From e6eb3d22bb39515899c0178c5245f3b9a6834c07 Mon Sep 17 00:00:00 2001 From: Damien Date: Tue, 26 May 2026 19:28:12 +1000 Subject: [PATCH 1/7] New files added, some updated --- README.md | 8 +- _sidebar.md | 4 +- develop-dotnet-plugins.md | 8 +- executable-develop-plugins.md | 365 ++++++++++++++++++++++++++++++++++ faq.md | 111 +++++++++++ installation.md | 4 + keyboard-shortcuts.md | 58 ++++++ plugin-dev.md | 175 ++++++++++++++-- plugin-explorer.md | 13 ++ quickstart.md | 86 ++++++++ usage-tips.md | 17 +- 11 files changed, 815 insertions(+), 34 deletions(-) create mode 100644 executable-develop-plugins.md create mode 100644 faq.md create mode 100644 keyboard-shortcuts.md create mode 100644 quickstart.md diff --git a/README.md b/README.md index d77cdf5..27936e4 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,9 @@ ## Welcome -If you have just started using Flow, this documentation should help familiarise you with how to get to the settings to customise Flow to your liking, show you some usage tips to use Flow more effectively, as well as provide more detailed documentation for plugin authors. +If you have just started using Flow, this documentation should get you started and help familiarise you with settings and customisation. + +Start with the [**Quick Start**](/quickstart.md) guide for your first steps, and the dive into more detail from there. Any issues, check out the [**Support**](/support.md) page to see where you can go to get help. Browse the many community created [**Plugins**](/plugins.md) to extend Flow to do just about anything. + +And if you find a use case not covered, and are feeling creative, learn about [**Plugin Development**](/plugin-dev.md) and create your own! + +Flow Launcher is created and maintained as an open source project by a world-wide team of productivity passionate volunteers. We hope you enjoy using it as much as we enjoy creating it. diff --git a/_sidebar.md b/_sidebar.md index 10c46f3..4f32987 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -1,15 +1,17 @@ - [**Introduction**](/README.md) - [**Installation**](/installation.md) +- [**Quick Start**](/quickstart.md) - [**Settings**](/settings.md) - [**File Manager**](/filemanager.md) - [**Usage Tips**](/usage-tips.md) - [**Support**](/support.md) +- [**Frequently Asked Questions**](/faq.md) - [**Plugin Store**](https://www.flowlauncher.com/plugins/) - [**Explorer Plugin**](/plugin-explorer.md) - [**Bookmark Plugin**](/plugin-bookmark.md) - [**Plugin Development**](/plugin-dev.md) - [**plugin.json**](/plugin.json.md) - - Dotnet Plugins + - .NET Plugins - [**Development Guide**](/develop-dotnet-plugins.md) - [**API Reference**](/API-Reference/Flow.Launcher.Plugin.md) - Python Plugins diff --git a/develop-dotnet-plugins.md b/develop-dotnet-plugins.md index 1f8496f..3892a20 100644 --- a/develop-dotnet-plugins.md +++ b/develop-dotnet-plugins.md @@ -1,17 +1,17 @@ Flow is written in C#, so plugins written in .NET platform can directly communicate with Flow without extra protocols. -## Initialization +## Initialisation For C# Plugins, We recommend you use the [dotnet template](https://github.com/Flow-Launcher/dotnet-template) to generate a plugin template. -To be recognized as a Flow DotNet plugin, the directory needs to have at least two files +To be recognized as a Flow .NET plugin, the directory needs to have at least two files 1. [`plugin.json`](/plugin.json.md) -2. A Dotnet Assembly that implements **[IPlugin](/API-Reference/Flow.Launcher.Plugin/IPlugin.md)** or **[IAsyncPlugin](/API-Reference/Flow.Launcher.Plugin/IAsyncPlugin.md)** (remember to reference [Flow.Launcher.Plugin](https://www.nuget.org/packages/Flow.Launcher.Plugin/) by Nuget). The plugin template will add the reference and create a `Main.cs` that implements `IPlugin`. +2. A .NET Assembly that implements **[IPlugin](/API-Reference/Flow.Launcher.Plugin/IPlugin.md)** or **[IAsyncPlugin](/API-Reference/Flow.Launcher.Plugin/IAsyncPlugin.md)** (remember to reference [Flow.Launcher.Plugin](https://www.nuget.org/packages/Flow.Launcher.Plugin/) by Nuget). The plugin template will add the reference and create a `Main.cs` that implements `IPlugin`. Find our API Reference [here](/API-Reference/Flow.Launcher.Plugin.md) -A sample CSharp Plugin [here](https://github.com/Flow-Launcher/plugin-samples) +A sample C# Plugin [here](https://github.com/Flow-Launcher/plugin-samples) ## IPlugin/IAsyncPlugin diff --git a/executable-develop-plugins.md b/executable-develop-plugins.md new file mode 100644 index 0000000..6c6b325 --- /dev/null +++ b/executable-develop-plugins.md @@ -0,0 +1,365 @@ +# Executable Plugins + +Executable plugins let you build a Flow Launcher plugin in **any language that can produce a binary** — Go, Rust, C, compiled TypeScript, Zig, or anything else. Flow treats the executable as a subprocess and communicates with it over JSON-RPC via stdin/stdout. + +This is a good choice when you want: +- Minimal startup latency (no interpreter to boot) +- A single binary with no runtime dependency +- A language not otherwise supported + +--- + +## How it works + +When a user triggers your plugin, Flow: + +1. Launches your executable as a subprocess (once, on startup) +2. Sends a JSON-RPC request to the process's **stdin** +3. Reads the JSON-RPC response from the process's **stdout** +4. Renders the returned results + +Your process stays alive for the lifetime of the Flow session. It must read from stdin in a loop and write responses to stdout. + +> **Important:** Only write JSON-RPC responses to stdout. Any debug output must go to **stderr** or a log file, or Flow will fail to parse it. + +--- + +## plugin.json for an executable plugin + +Set `"Language": "executable"` and point `"ExecuteFileName"` at your binary: + +```json +{ + "ID": "your-unique-guid-here", + "ActionKeyword": "ex", + "Name": "My Executable Plugin", + "Description": "Does something fast", + "Author": "Your Name", + "Version": "1.0.0", + "Language": "executable", + "Website": "https://github.com/you/your-plugin", + "IcoPath": "Images/icon.png", + "ExecuteFileName": "my-plugin.exe" +} +``` + +--- + +## JSON-RPC protocol + +Flow sends newline-delimited JSON to your process. Each message has a `method` and a `parameters` array. + +### Methods Flow will call + +#### `initialize` + +Called once when Flow starts. Use this to perform any startup work. + +**Request:** +```json +{"method": "initialize", "parameters": [{"currentPluginMetadata": {...}}]} +``` + +**Response:** An empty result is acceptable. +```json +{"result": []} +``` + +--- + +#### `query` + +Called each time the user types in the search bar (after the action keyword, if any). + +**Request:** +```json +{"method": "query", "parameters": ["search text"]} +``` + +**Response:** A list of result objects. +```json +{ + "result": [ + { + "Title": "First result", + "SubTitle": "Subtitle text", + "IcoPath": "Images/icon.png", + "Score": 100, + "JsonRPCAction": { + "method": "openUrl", + "parameters": ["https://example.com"], + "dontHideAfterAction": false + } + } + ] +} +``` + +--- + +#### `context_menu` + +Called when the user opens the context menu on a result (right-arrow or right-click). Return a list of additional actions. + +**Request:** +```json +{"method": "context_menu", "parameters": [{"Title": "First result", ...}]} +``` + +**Response:** Same format as `query`. + +--- + +### Result fields + +| Field | Type | Description | +|---|---|---| +| `Title` | string | Main result text (required) | +| `SubTitle` | string | Secondary line below the title | +| `IcoPath` | string | Relative path to icon file, or a data URI | +| `Score` | int | Sort weight — higher is ranked higher | +| `JsonRPCAction` | object | Action to perform when the user selects this result | +| `ContextData` | any | Arbitrary data passed back to your plugin in `context_menu` | +| `TitleHighlightData` | int[] | Character positions to bold in the title | + +--- + +### Built-in actions (JsonRPCAction.method) + +These are handled by Flow directly — you don't need to implement them yourself: + +| method | parameters | Effect | +|---|---|---| +| `Flow.Launcher.OpenUrl` | `[url]` | Opens a URL in the default browser | +| `Flow.Launcher.OpenDirectory` | `[path]` | Opens a folder in Explorer | +| `Flow.Launcher.OpenFile` | `[path]` | Opens a file with its default app | +| `Flow.Launcher.CopyToClipboard` | `[text]` | Copies text to the clipboard | +| `Flow.Launcher.ShellRun` | `[command]` | Runs a shell command | + +For custom actions (ones you implement yourself), use any method name not prefixed with `Flow.Launcher.`. Flow will send it back to your process as a new method call. + +--- + +## Minimal example in Go + +Here's a complete working plugin in Go that returns a single result for any query: + +```go +package main + +import ( + "bufio" + "encoding/json" + "fmt" + "os" + "strings" +) + +type Request struct { + Method string `json:"method"` + Parameters []json.RawMessage `json:"parameters"` +} + +type Action struct { + Method string `json:"method"` + Parameters []string `json:"parameters"` + DontHideAfterAction bool `json:"dontHideAfterAction"` +} + +type Result struct { + Title string `json:"Title"` + SubTitle string `json:"SubTitle"` + IcoPath string `json:"IcoPath"` + Score int `json:"Score"` + JsonRPCAction Action `json:"JsonRPCAction"` +} + +type Response struct { + Result []Result `json:"result"` +} + +func handleQuery(query string) Response { + return Response{ + Result: []Result{ + { + Title: fmt.Sprintf("You searched: %s", query), + SubTitle: "Press Enter to open example.com", + IcoPath: "Images/icon.png", + Score: 100, + JsonRPCAction: Action{ + Method: "Flow.Launcher.OpenUrl", + Parameters: []string{"https://example.com"}, + }, + }, + }, + } +} + +func main() { + scanner := bufio.NewScanner(os.Stdin) + for scanner.Scan() { + line := strings.TrimSpace(scanner.Text()) + if line == "" { + continue + } + + var req Request + if err := json.Unmarshal([]byte(line), &req); err != nil { + continue + } + + var resp Response + + switch req.Method { + case "query": + var params []string + json.Unmarshal(req.Parameters[0], ¶ms) + query := "" + if len(params) > 0 { + query = params[0] + } + resp = handleQuery(query) + + case "initialize", "context_menu": + resp = Response{Result: []Result{}} + } + + out, _ := json.Marshal(resp) + fmt.Println(string(out)) + } +} +``` + +Build with `go build -o my-plugin.exe .` and place the binary in your plugin folder. + +--- + +## Minimal example in Rust + +```rust +use std::io::{self, BufRead, Write}; +use serde::{Deserialize, Serialize}; +use serde_json::Value; + +#[derive(Deserialize)] +struct Request { + method: String, + parameters: Vec, +} + +#[derive(Serialize)] +struct Action { + method: String, + parameters: Vec, + #[serde(rename = "dontHideAfterAction")] + dont_hide: bool, +} + +#[derive(Serialize)] +struct Result { + #[serde(rename = "Title")] + title: String, + #[serde(rename = "SubTitle")] + subtitle: String, + #[serde(rename = "IcoPath")] + ico_path: String, + #[serde(rename = "Score")] + score: i32, + #[serde(rename = "JsonRPCAction")] + action: Action, +} + +#[derive(Serialize)] +struct Response { + result: Vec, +} + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + let mut out = stdout.lock(); + + for line in stdin.lock().lines() { + let line = line.unwrap(); + if line.trim().is_empty() { continue; } + + let req: Request = match serde_json::from_str(&line) { + Ok(r) => r, + Err(_) => continue, + }; + + let resp = match req.method.as_str() { + "query" => { + let query = req.parameters.get(0) + .and_then(|v| v.as_str()) + .unwrap_or(""); + Response { + result: vec![Result { + title: format!("You searched: {}", query), + subtitle: "Press Enter to open example.com".into(), + ico_path: "Images/icon.png".into(), + score: 100, + action: Action { + method: "Flow.Launcher.OpenUrl".into(), + parameters: vec!["https://example.com".into()], + dont_hide: false, + }, + }], + } + } + _ => Response { result: vec![] }, + }; + + let json = serde_json::to_string(&resp).unwrap(); + writeln!(out, "{}", json).unwrap(); + out.flush().unwrap(); + } +} +``` + +--- + +## Folder structure + +``` +MyPlugin/ +├── plugin.json +├── my-plugin.exe ← your compiled binary +└── Images/ + └── icon.png +``` + +--- + +## Installing for development + +Copy your plugin folder to: +``` +%APPDATA%\FlowLauncher\Plugins\MyPlugin\ +``` + +Then restart Flow or press `F5` / type `reload plugin data` to load it. + +--- + +## Debugging + +Since you can't attach a debugger easily, logging to a file is the most practical approach: + +```go +// Go example +logFile, _ := os.OpenFile("plugin.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) +log.SetOutput(logFile) +log.Printf("Query received: %s", query) +``` + +You can also view Flow's own logs by typing `open log location` in Flow. + +--- + +## Publishing + +See the [Publishing guide](port-plugins.md) for instructions on releasing to the Plugin Store, including the required GitHub Actions workflow for automated builds. + +**SECURITY NOTE** +New binary plugin submissions will only be accepted to the Plugin Store after the source code and GitHub CI action have been reviewed and verified. Users will be warned in other parts of Flow documentation that binary plugins represent the greatest security risk as they are one step removed from direct source code. \ No newline at end of file diff --git a/faq.md b/faq.md new file mode 100644 index 0000000..d8ff5a8 --- /dev/null +++ b/faq.md @@ -0,0 +1,111 @@ +# FAQ & Troubleshooting + +Answers to common questions for both **Flow users** and **plugin developers**. + +--- + +## For users + +### Flow won't open when I press the hotkey + +- Check that Flow is running — look for its icon in the system tray +- Another application may have claimed the same hotkey. Try changing it in **Settings → General → Hotkey** +- If you're in a game, Flow's hotkey detection may be suppressed. Press `Ctrl + F12` in the search window to toggle game mode on/off + +### A plugin isn't showing results + +1. Open Settings → Plugins and find the plugin +2. Check its **Action Keyword** — if it has a dedicated keyword (not `*`), you must type that keyword first +3. Make sure the plugin is **enabled** (toggle is on) +4. Try pressing `F5` or typing `reload plugin data` to reload all plugins +5. Check if the plugin requires setup (an API key, a file path, etc.) in its settings tab + +### Flow is slow to open or results are slow to appear + +- Some plugins do network calls or heavy file I/O on every query. Identify which ones by temporarily disabling plugins one at a time +- Check if **Everything** search is running — Flow's file search can slow down if Everything isn't active. Look for a warning result in Flow when you search +- Reduce the number of global (`*`) keyword plugins — they all run on every query + +### My newly installed app doesn't appear in results + +Flow's app index refreshes automatically, but you can force it by: +- Pressing `F5` in the query window, or +- Typing `reload plugin data` + +### How do I back up my settings? + +Type `flow user data` in Flow to open your UserData folder. Copy the entire folder to back up your settings, themes, installed plugins, and history. + +To restore: exit Flow, replace the UserData folder with your backup, then restart Flow. + +### Flow shows up in the wrong place on screen / is too small or large + +If you've moved between monitors with different resolutions, the window position may be saved offscreen. Open `%APPDATA%\FlowLauncher\Settings\Settings.json` and reset `SettingWindowTop`, `SettingWindowLeft`, `SettingWindowWidth`, and `SettingWindowHeight`. + +Sensible defaults for 1080p: `top: 0, left: 0, width: 1000, height: 700`. + +### Windows says Flow is unsafe to run + +This is a SmartScreen warning, not an indication that Flow is harmful. It appears because Flow hasn't accumulated enough download volume for Microsoft to automatically trust it. As long as you downloaded from [flowlauncher.com](https://flowlauncher.com) or the [official GitHub repo](https://github.com/Flow-Launcher/Flow.Launcher), it is safe. Click "More info" → "Run anyway". + +Similarly, antivirus false positives can occur. If you've confirmed you downloaded from an official source, submit a false-positive report to your AV vendor. + +--- + +## For plugin developers + +### My plugin doesn't appear in Flow after installing it + +- Confirm the plugin folder is in `%APPDATA%\FlowLauncher\Plugins\` +- Check that `plugin.json` exists in the root of the plugin folder and is valid JSON +- Check that the `Language` field in `plugin.json` exactly matches one of: `csharp`, `fsharp`, `python`, `nodejs`, `executable` +- Restart Flow or type `reload plugin data` +- Check Flow's logs: type `open log location` in Flow and look for errors related to your plugin name + +### Flow shows my plugin in the list but returns no results + +For JSON-RPC plugins (Python, Node, Executable): +- Check that your process is actually writing to **stdout** (not stderr) +- Make sure each response is a single line of JSON followed by a newline — Flow reads line by line +- Test your process manually: run it, type a JSON-RPC request into stdin, and verify the stdout output looks correct +- Confirm you're not accidentally mixing debug output into stdout + +For .NET plugins: +- Confirm your class implements `IAsyncPlugin` (or `IPlugin`) +- Check the Flow logs for assembly load errors + +### My plugin crashes on startup + +Check Flow's logs (`open log location`). Common causes: +- Missing runtime (Python not installed, Node not installed) +- A dependency import failing — check that all libraries in `lib/` are correctly bundled +- A syntax error in your entry point file + +### Query is called but results don't appear in Flow + +- Check that your `result` array is non-empty and correctly structured +- Confirm `Title` (capital T) is present on each result — it's required +- Verify `IcoPath` points to a file that actually exists relative to your plugin folder, or use a valid data URI + +### How do I access settings in my plugin? + +See the [plugin settings guide](json-rpc-settings.md). Define settings in `SettingsTemplate.yaml` and they'll appear in Flow's Settings UI. Read them at runtime via the public API or from the settings JSON directly. + +### How do I test my plugin without reinstalling it each time? + +Develop directly inside `%APPDATA%\FlowLauncher\Plugins\YourPlugin\` and use `reload plugin data` (or `F5`) to reload without restarting Flow. For .NET plugins you'll need to restart Flow to pick up recompiled DLLs. + +### How do I view logs from my plugin? + +Type `open log location` in Flow to open the logs folder. Each plugin gets its own log entries. You can also write your own log file from within your plugin code. + +### My plugin works locally but fails after publishing + +Common causes: +- Bundled dependencies are missing in the release archive — confirm your build/release workflow includes everything in `lib/` +- The release ZIP doesn't have the plugin folder at the root level — the structure should be `PluginName/plugin.json`, not `plugin.json` at the archive root +- `ExecuteFileName` in `plugin.json` doesn't match the actual filename in the release + +### What's the difference between IPlugin and IAsyncPlugin? + +`IAsyncPlugin` is preferred. It allows your `Query` method to be `async`, which is important if you make network requests or do any I/O — doing blocking work in `IPlugin.Query` will freeze Flow's UI while your query runs. diff --git a/installation.md b/installation.md index 849ef8d..8ebae0a 100644 --- a/installation.md +++ b/installation.md @@ -2,6 +2,10 @@ Flow Launcher can be installed several ways, including Windows package managers Winget, Scoop, and Chocolatey. The most popular method is to download the installer file from the main Flow Launcher website. This downloads the latest release package from the Flow Launcher GitHub repository (repo). +#### Minimum Requirement + +Note that as of Flow version 2.0, Windows 10 is the minimum requirement. + #### Security When installing Flow Launcher, you will get the Microsoft Defender SmartScreen installer window warning: diff --git a/keyboard-shortcuts.md b/keyboard-shortcuts.md new file mode 100644 index 0000000..f034c65 --- /dev/null +++ b/keyboard-shortcuts.md @@ -0,0 +1,58 @@ +# Keyboard Shortcuts + +A complete reference for keyboard shortcuts in Flow Launcher. + +--- + +## Global + +| Shortcut | Action | +|---|---| +| `Alt + Space` | Open Flow (default — customisable in Settings → General) | +| `Ctrl + F12` | Toggle game mode (suppresses hotkey activation) | + +--- + +## In the search window + +| Shortcut | Action | +|---|---| +| `↑` / `↓` | Move between results | +| `Enter` | Run the selected result's default action | +| `Ctrl + Enter` | (Explorer results) Open the containing folder in File Explorer | +| `Ctrl + Shift + Enter` | Run the selected result as Administrator | +| `→` or `Shift + Enter` | Open the context menu for the selected result | +| `Tab` | Autocomplete (where supported by the plugin) | +| `Esc` | Close Flow | +| `F5` | Reload all plugin data | +| `Ctrl + R` | Toggle result ordering between relevance and most-recently-used | +| `Ctrl + O` | (Explorer results) Open in Explorer | + +--- + +## Context menu + +| Shortcut | Action | +|---|---| +| `↑` / `↓` | Move between context menu actions | +| `Enter` | Run the selected context action | +| `Esc` | Close the context menu and return to results | + +--- + +## Plugin Manager (in the search bar) + +These are typed commands rather than keyboard shortcuts, but included here for discoverability: + +| Command | Action | +|---|---| +| `pm install ` | Install a plugin from the store | +| `pm uninstall ` | Uninstall a plugin | +| `pm update ` | Update a specific plugin | + +--- + +## Tips + +- Typing **`?`** shows all currently active action keywords. Narrow them by typing the first character or two of the keyword you're looking for. +- Most shortcuts can't be customised individually — only the global activation hotkey is user-configurable. diff --git a/plugin-dev.md b/plugin-dev.md index 82f75e1..f9ef48f 100644 --- a/plugin-dev.md +++ b/plugin-dev.md @@ -1,20 +1,155 @@ -# Get Started - -Welcome to the comprehensive guide to plugin development in Flow Launcher. - -## Types of plugin implementation - -While Flow Launcher is written in C#, plugins can be written natively or in other languages. - -### Natively (no integration needed) - -- [**C# (.NET framework)**](/develop-dotnet-plugins.md) - -### Using JSON-RPC - -For other languages, Flow launcher communicates with the plugin via [JSON-RPC](/json-rpc.md). - -Currently supported languages are: - -- [**Python**](/py-develop-plugins.md) -- [**JavaScript / TypeScript (NodeJS)**](/nodejs-develop-plugins.md) +# Plugin Development — Overview + +> This page is your starting point for building Flow Launcher plugins. It explains how plugins work, helps you choose a language, and points you to the right guide. + +--- + +## What is a plugin? + +A Flow Launcher plugin is a program that receives a search query and returns a list of results. Each result has a title, subtitle, icon, and an action to run when the user presses Enter. + +That's it at its core — but plugins can also: +- Provide context menu actions (secondary actions on a result) +- Store and load settings that appear in Flow's Settings UI +- Call back into Flow's API (copy to clipboard, open URLs, show notifications, etc.) +- Run initialisation and cleanup logic on startup/shutdown + +--- + +## How Flow calls your plugin + +Every time the user types in the search bar, Flow calls your plugin's `query` method with the current search string. Your plugin returns results. Flow renders them. + +``` +User types query + │ + ▼ +Flow Launcher + │ calls query("search text") + ▼ +Your Plugin + │ returns list of Results + ▼ +Flow Launcher renders results + │ + ▼ +User selects a result → Flow calls your action +``` + +For .NET plugins this is a direct in-process method call. For all other languages, this communication happens over **JSON-RPC** — a lightweight protocol where Flow sends JSON to your process's stdin, and your process writes JSON to stdout. + +--- + +## Choosing a language + +| Language | Integration | Performance | API access | Best for | +|---|---|---|---|---| +| **C# / F# (.NET)** | In-process | Fastest | Full | Anything. The most capable option. | +| **Python** | JSON-RPC (subprocess) | Good | Core API | Scripting, data tasks, rapid prototyping | +| **JavaScript / TypeScript** | JSON-RPC (Node.js) | Good | Core API | Web API calls, JS-native tooling | +| **Executable** (any language) | JSON-RPC (subprocess) | Fastest for scripts | Core API | Go, Rust, compiled TypeScript, or any binary | + +**Not sure?** Use this decision guide: + +- You know C# or F# → **C# / F#** (most powerful, full API access) +- You want the fastest path to a working plugin → **Python** (simplest JSON-RPC setup, good library ecosystem) +- Your plugin makes a lot of web API calls → **JavaScript / TypeScript** (async-native, fetch built-in) +- You want minimal startup time and no runtime dependency → **Executable** (ship a single binary) + +--- + +## The plugin.json file + +Every plugin, regardless of language, requires a `plugin.json` file in its root directory. This is how Flow discovers and identifies your plugin. + +```json +{ + "ID": "a unique GUID, e.g. 2f4e384e-76ce-45c3-aea2-b16f5e5c328f", + "ActionKeyword": "kw", + "Name": "My Plugin", + "Description": "What it does, briefly", + "Author": "Your Name", + "Version": "1.0.0", + "Language": "python", + "Website": "https://github.com/you/your-plugin", + "IcoPath": "Images/icon.png", + "ExecuteFileName": "main.py" +} +``` + +See the [plugin.json reference](plugin.json.md) for all available fields. + +--- + +## What a result looks like + +Whether you're writing C#, Python, or JavaScript, you return the same conceptual structure: + +```json +{ + "Title": "Main text shown in the result", + "SubTitle": "Secondary line below the title", + "IcoPath": "Images/icon.png", + "Score": 50, + "JsonRPCAction": { + "method": "openUrl", + "parameters": ["https://example.com"] + } +} +``` + +- **Title / SubTitle** — what the user sees +- **IcoPath** — path to an icon (relative to your plugin folder) +- **Score** — influences result ordering (higher = ranked higher) +- **JsonRPCAction** — what happens when the user selects this result + +--- + +## Plugin folder structure + +All plugins share this general layout: + +``` +MyPlugin/ +├── plugin.json ← required: plugin metadata +├── main.py ← your entry point (language-dependent name) +├── SettingsTemplate.yaml ← optional: defines settings shown in Flow's UI +├── Images/ +│ └── icon.png ← plugin icon +└── lib/ ← optional: bundled dependencies +``` + +--- + +## Development guides by language + +Pick your language and follow the step-by-step guide: + +### .NET (C# or F#) +- [Develop a .NET plugin](develop-dotnet-plugins.md) + +### Python +- [1. Set up your project](py-setup-project.md) +- [2. Write your plugin code](py-write-code.md) +- [3. Release your plugin](py-release-project.md) +- [Reference](py-plugin-references.md) + +### JavaScript / TypeScript (Node.js) +- [1. Set up your project](nodejs-setup-project.md) +- [2. Write your plugin code](nodejs-write-code.md) +- [3. Release your plugin](nodejs-release-project.md) +- [Reference](nodejs-plugin-references.md) + +### Executable (Go, Rust, or any compiled language) +- [Develop an executable plugin](executable-develop-plugins.md) ← new + +--- + +## Shared references + +- [plugin.json field reference](plugin.json.md) +- [JSON-RPC protocol reference](json-rpc.md) +- [Plugin settings (SettingsTemplate)](json-rpc-settings.md) +- [.NET API Reference](API-Reference/Flow.Launcher.Plugin.md) +- [Testing your plugin](testing.md) +- [Publishing to the Plugin Store](port-plugins.md) diff --git a/plugin-explorer.md b/plugin-explorer.md index 2001a0d..7a67b53 100644 --- a/plugin-explorer.md +++ b/plugin-explorer.md @@ -33,6 +33,19 @@ and then choose the *Open With Editor* option - *Search full path* : use the Everything option to search the full path and not just the filename. Equivalent to the `path:` modifier within Everything. - *Sort Option* : dropdown list to show how the search results are sorted. - *Everything Path* : If you have Everything installed, Flow Launcher will try and find the installation to use, but if you are having issues, or it is installed in a non-standard directory, you can specify it explicitly here. + +**NOTE** +If you let Flow download Everything for you, it will use the latest stable release on the 1.4 branch. If you want to use the Everything 1.5 alpha branch you will need to do the following: + +Completely exit out of Everything (right click the Everything system tray icon and click Exit) +Open your Everything-1.5a.ini file in the same location as your Everything64.exe +Add the following line to the end of the file: +alpha_instance=0 +Save changes and restart Everything. +Everything will no longer use an instance name for window classes (IPC) +Everything will continue to use the 1.5a instance name for settings, data and the Everything Service. +(source - https://github.com/Flow-Launcher/Flow.Launcher/issues/1716) + #### Customised Action Keywords tab ---- ![Customise Action Keywords tab](/assets/explorer_3.png) diff --git a/quickstart.md b/quickstart.md new file mode 100644 index 0000000..2694b30 --- /dev/null +++ b/quickstart.md @@ -0,0 +1,86 @@ +# Quick Start Guide + +**New to Flow Launcher?** This page gets you productive in 5 minutes. + +Flow Launcher is a keyboard-driven launcher for Windows. Press a hotkey, type something, press Enter. That's the core loop — but there's a lot of power underneath once you know where to look. + +## Step 1 — Open Flow + +By default, Flow is triggered with `Alt + Space`. You can change this under **Settings → General → Hotkey**. + +> **Tip:** If Flow doesn't open, check your system tray — look for the Flow icon. Right-click it to access Settings. + +## Step 2 — Search for anything + +Just start typing. Flow searches across: + +- **Applications** — type `chr` to launch Chrome, `vs` for Visual Studio Code, etc. +- **Files and folders** — type part of a filename and Flow finds it +- **Calculator** — type `14 * 3` and see the result immediately +- **Web searches** — type `g cats` to search Google for "cats" (or whichever search engine you've configured) +- **System commands** — type `shutdown`, `lock`, `restart`, or `sleep` + +## Step 3 — Understand action keywords + +Some plugins only activate when you type a specific **action keyword** first. This keeps results focused and prevents clutter. + +For example: +- `g ` → Google search +- `wt` → open Windows Terminal +- `fd ` → file search via Everything + +To see all currently active keywords, type **`?`** in the search bar. Refine by typing the first letter or two of the keyword you're looking for. + +> **Global vs. dedicated keywords:** Plugins set to the `*` keyword respond to every query. Plugins with a dedicated keyword (like `g`) only respond when you type that prefix. You can customise keywords per-plugin in **Settings → Plugins**. + +## Step 4 — Use the context menu + +Every result has a **context menu** with additional actions specific to that plugin. + +To open it: +- Press **→** (right arrow) on a highlighted result, or +- **Right-click** a result with your mouse + +For example, a file result might offer: *Open containing folder*, *Copy path*, *Run as administrator*. + +## Step 5 — Customise your settings + +Open Settings by: +- Typing `settings` in Flow, or +- Typing **`flow user data`** to open your config folder directly + +Key things to configure early: + +| Setting | Where to find it | +|---|---| +| Change the hotkey | General → Hotkey | +| Change the theme | Appearance → Theme | +| Add or remove plugins | Plugins tab | +| Set a plugin's action keyword | Plugins → [plugin name] → Action Keyword | +| Prioritise a plugin's results | Plugins → [plugin name] → Priority | + +## Useful things you might not discover on your own + +**Fuzzy and acronym matching** — You don't need to type the full name of an app. `gkp` matches *GitKraken Preview*, `acr` matches *Acrobat Reader DC*, and `code` or `visual` both match *Visual Studio Code*. + +**Run as administrator** — Highlight any result and press `Ctrl + Shift + Enter` to run it as admin. + +**Open folder instead of navigating into it** — In Explorer results, press `Ctrl + Enter` to open the folder directly in File Explorer. + +**Reload plugins** — Press `F5` in the query window, or type `reload plugin data`, to refresh all plugin data (useful after installing new apps or bookmarks). + +**Plugin Manager** — Install, uninstall, or update plugins without leaving Flow. Type: +- `pm install ` +- `pm uninstall ` +- `pm update ` + +**Portable mode** — Flow is self-contained and can run from a USB drive or cloud folder (like Dropbox). Type `flow user data` to see where your settings are stored. + +**Back up your settings** — Copy the `UserData` folder (found via `flow user data`) to back up everything: settings, plugins, themes, and history. + +## Next steps + +- Browse the [Plugin Store](plugins.md) to extend Flow +- Read [Usage Tips](usage-tips.md) for power-user tricks +- Explore [Settings](settings.md) for full configuration reference +- Build your own plugin → [Plugin Development](plugin-dev.md) diff --git a/usage-tips.md b/usage-tips.md index ea7ca82..3ebe2cf 100644 --- a/usage-tips.md +++ b/usage-tips.md @@ -1,26 +1,27 @@ ### Usage Tips #### Installation -- Flow is published as a self-contained app, this means on Windows machines (7 and up) Flow can run straight away without needing to install .NET runtime and framework. Coupled with portable mode, it can be stored on Dropbox or cloud storage provider and run on any Windows machines. The slight drawback is that the installed package size is slightly bigger at around 250 MB because it needs to bundle the required .NET components together. +- Flow is published as a self-contained app, this means Flow can run straight away without needing to install .NET runtime and framework. Coupled with portable mode, it can be stored on Dropbox or another cloud storage provider and run. The trade off is that the installed package size is slightly bigger at around 250 MB because it needs to bundle the required .NET components together. + #### Searching - Search for items using: - Acronyms e.g. `gk` or `gp` for GitKraken Preview. - Fuzzy e.g. `acr` or `rea` for Acrobat Reader DC. - Single word e.g. `code` or `visual` for Visual Studio Code. -- Right-click with the mouse, or press right-arrow on the keyboard, on a result to access the context menu for additional actions. The context menu is specific to the plugin providing the result +- Right-click with the mouse, or press right-arrow on the keyboard, on a result to access the context menu for additional actions. The context menu is specific to the plugin providing the result. #### Plugins - Typing `?` in the search bar will show you the keywords currently active. This can be refined by typing the first letter or two of the keywords you are after. -- The plugin results order can be prioritised. This can be done by going to the plugin's settings page. Under the plugin's title and the description, click the number next to 'Priority'; this is where you can assign weight to the plugin's result. The higher the weight is, the higher the selected plugin's results will be in Flow's result list. +- The plugin results order can be prioritised. This can be done by going to the plugin's settings page and under the plugin's title and the description, click the number next to 'Priority'; this is where you can assign weight to the plugin's result. The higher the weight is, the higher the selected plugin's results will be in Flow's result list. - Press `F5` while in the query window or type `reload plugin data` to reload all plugin data. - Both Program and Bookmarks plugin will automatically detect new changes, so your newly installed apps or bookmarks will be available soon after they are added. -- If your plugin is not triggering, open Flow's settings, navigate to the Plugins tab, and check if the plugin is set to a specific action keyword. Note that sometimes a dedicated keyword is used to limit the number of results and avoid cluttering the list.. +- If your plugin is not triggering, open Flow's settings, navigate to the Plugins tab, and check if the plugin is set to a specific action keyword. Note that sometimes a dedicated keyword is used to limit the number of results and avoid cluttering the list. - For Explorer plugin results, you can press `Ctrl + Enter` to open the folder directly instead of navigating into the folder. -- You can save your frequently used or favourite files/folder locations via Explorer plugin. Navigate to the file/location you want to save, then go to the context menu and select `Add to Quick Access`. It will be particularly handy if you have set a custom action keyword instead of the default '*', which when used will display your list of saved Quick Access files and folders. You can change the default action keyword via the plugin's settings page. -- Press ctrl + enter/click on a Shell plugin command will run it directly as admin. +- You can save your frequently used or favourite files/folder locations via Explorer plugin. Navigate to the file/location you want to save, then go to the context menu and select `Add to Quick Access`. It is particularly handy if you have set a custom action keyword instead of the default '*', which when used will display your list of saved Quick Access files and folders. You can change the default action keyword via the plugin's settings page. +- Press `Ctrl + Enter/Click` on a Shell plugin command to run it directly as an Administrator. - In the plugins download list, you can press ctrl + enter/click to open the plugin's url. -- Explorer's Search action keyword combines both Path and Index search, so you can use it without worrying about which action keyword to use for what, put in what you need to search for. Path (searches a specific path) and Index (search a file or folder name) search allows users to do just their specific searches and are disabled by default. -- Whilst in the query window and searching inside a directory, pressing `Ctrl + Backspace` will go back up one level in the directory tree. +- Explorer's Search action keyword combines both Path and Index search, so you can use it without worrying about which action keyword to use for what, just enter what you need to search for. Path (searches a specific path) and Index (search a file or folder name) search allows users to do just their specific searches and are disabled by default. +- Whilst in the query window and searching inside a directory, pressing `Ctrl + Backspace` to go back up one level in the directory tree. #### Settings - Flow's settings including installed plugins are located at: From 655fab2de2a85d2dc434f7974c1a2a745869603d Mon Sep 17 00:00:00 2001 From: Damien Date: Tue, 26 May 2026 20:55:08 +1000 Subject: [PATCH 2/7] Update to kb shortcuts --- keyboard-shortcuts.md | 1 - 1 file changed, 1 deletion(-) diff --git a/keyboard-shortcuts.md b/keyboard-shortcuts.md index f034c65..ed5e47b 100644 --- a/keyboard-shortcuts.md +++ b/keyboard-shortcuts.md @@ -26,7 +26,6 @@ A complete reference for keyboard shortcuts in Flow Launcher. | `Esc` | Close Flow | | `F5` | Reload all plugin data | | `Ctrl + R` | Toggle result ordering between relevance and most-recently-used | -| `Ctrl + O` | (Explorer results) Open in Explorer | --- From a5ef2870223cbc3315d9f5f4047b112bcb49268c Mon Sep 17 00:00:00 2001 From: Damien Date: Tue, 26 May 2026 21:29:31 +1000 Subject: [PATCH 3/7] Update _sidebar.md Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- _sidebar.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_sidebar.md b/_sidebar.md index 4f32987..f64518f 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -1,6 +1,7 @@ - [**Introduction**](/README.md) - [**Installation**](/installation.md) - [**Quick Start**](/quickstart.md) +- [**Keyboard Shortcuts**](/keyboard-shortcuts.md) - [**Settings**](/settings.md) - [**File Manager**](/filemanager.md) - [**Usage Tips**](/usage-tips.md) From 17b5f31021d07b03a382a2a4b4a5254ca6b4ce41 Mon Sep 17 00:00:00 2001 From: Damien Date: Tue, 26 May 2026 21:50:15 +1000 Subject: [PATCH 4/7] CodeRabbit suggested fixes --- README.md | 4 ++-- _sidebar.md | 1 + develop-dotnet-plugins.md | 4 ++-- executable-develop-plugins.md | 4 ++-- installation.md | 2 +- plugin-dev.md | 4 ++-- plugin-explorer.md | 2 +- usage-tips.md | 4 ++-- 8 files changed, 13 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 27936e4..92afd44 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ If you have just started using Flow, this documentation should get you started and help familiarise you with settings and customisation. -Start with the [**Quick Start**](/quickstart.md) guide for your first steps, and the dive into more detail from there. Any issues, check out the [**Support**](/support.md) page to see where you can go to get help. Browse the many community created [**Plugins**](/plugins.md) to extend Flow to do just about anything. +Start with the [**Quick Start**](/quickstart.md) guide for your first steps, and the dive into more detail from there. Any issues, check out the [**Support**](/support.md) page to see where you can go to get help. Browse the many community-created [**Plugins**](/plugins.md) to extend Flow to do just about anything. And if you find a use case not covered, and are feeling creative, learn about [**Plugin Development**](/plugin-dev.md) and create your own! -Flow Launcher is created and maintained as an open source project by a world-wide team of productivity passionate volunteers. We hope you enjoy using it as much as we enjoy creating it. +Flow Launcher is created and maintained as an open source project by a worldwide team of productivity-passionate volunteers. We hope you enjoy using it as much as we enjoy creating it. diff --git a/_sidebar.md b/_sidebar.md index 4f32987..9ac7238 100644 --- a/_sidebar.md +++ b/_sidebar.md @@ -1,6 +1,7 @@ - [**Introduction**](/README.md) - [**Installation**](/installation.md) - [**Quick Start**](/quickstart.md) +- [**Keyboard Shortcuts**](/keyboard-shortcuts.md) - [**Settings**](/settings.md) - [**File Manager**](/filemanager.md) - [**Usage Tips**](/usage-tips.md) diff --git a/develop-dotnet-plugins.md b/develop-dotnet-plugins.md index 3892a20..6b50fdf 100644 --- a/develop-dotnet-plugins.md +++ b/develop-dotnet-plugins.md @@ -8,10 +8,10 @@ To be recognized as a Flow .NET plugin, the directory needs to have at least two 1. [`plugin.json`](/plugin.json.md) 2. A .NET Assembly that implements **[IPlugin](/API-Reference/Flow.Launcher.Plugin/IPlugin.md)** or **[IAsyncPlugin](/API-Reference/Flow.Launcher.Plugin/IAsyncPlugin.md)** (remember to reference [Flow.Launcher.Plugin](https://www.nuget.org/packages/Flow.Launcher.Plugin/) by Nuget). The plugin template will add the reference and create a `Main.cs` that implements `IPlugin`. -Find our API Reference [here](/API-Reference/Flow.Launcher.Plugin.md) +Find the [Flow Launcher Plugin API Reference](/API-Reference/Flow.Launcher.Plugin.md) -A sample C# Plugin [here](https://github.com/Flow-Launcher/plugin-samples) +See the [Flow Launcher C# plugin samples](https://github.com/Flow-Launcher/plugin-samples). ## IPlugin/IAsyncPlugin diff --git a/executable-develop-plugins.md b/executable-develop-plugins.md index 6c6b325..e40c878 100644 --- a/executable-develop-plugins.md +++ b/executable-develop-plugins.md @@ -321,7 +321,7 @@ fn main() { ## Folder structure -``` +```text MyPlugin/ ├── plugin.json ├── my-plugin.exe ← your compiled binary @@ -334,7 +334,7 @@ MyPlugin/ ## Installing for development Copy your plugin folder to: -``` +```powershell %APPDATA%\FlowLauncher\Plugins\MyPlugin\ ``` diff --git a/installation.md b/installation.md index 8ebae0a..b532d3e 100644 --- a/installation.md +++ b/installation.md @@ -4,7 +4,7 @@ Flow Launcher can be installed several ways, including Windows package managers #### Minimum Requirement -Note that as of Flow version 2.0, Windows 10 is the minimum requirement. +Note that as of Flow version 2.0+, Windows 10 is the minimum requirement. #### Security diff --git a/plugin-dev.md b/plugin-dev.md index f9ef48f..f17102a 100644 --- a/plugin-dev.md +++ b/plugin-dev.md @@ -20,7 +20,7 @@ That's it at its core — but plugins can also: Every time the user types in the search bar, Flow calls your plugin's `query` method with the current search string. Your plugin returns results. Flow renders them. -``` +```text User types query │ ▼ @@ -109,7 +109,7 @@ Whether you're writing C#, Python, or JavaScript, you return the same conceptual All plugins share this general layout: -``` +```text MyPlugin/ ├── plugin.json ← required: plugin metadata ├── main.py ← your entry point (language-dependent name) diff --git a/plugin-explorer.md b/plugin-explorer.md index 7a67b53..6f396be 100644 --- a/plugin-explorer.md +++ b/plugin-explorer.md @@ -37,7 +37,7 @@ and then choose the *Open With Editor* option **NOTE** If you let Flow download Everything for you, it will use the latest stable release on the 1.4 branch. If you want to use the Everything 1.5 alpha branch you will need to do the following: -Completely exit out of Everything (right click the Everything system tray icon and click Exit) +Completely exit out of Everything (right-click the Everything system tray icon and click Exit) Open your Everything-1.5a.ini file in the same location as your Everything64.exe Add the following line to the end of the file: alpha_instance=0 diff --git a/usage-tips.md b/usage-tips.md index 3ebe2cf..49038a9 100644 --- a/usage-tips.md +++ b/usage-tips.md @@ -1,7 +1,7 @@ ### Usage Tips #### Installation -- Flow is published as a self-contained app, this means Flow can run straight away without needing to install .NET runtime and framework. Coupled with portable mode, it can be stored on Dropbox or another cloud storage provider and run. The trade off is that the installed package size is slightly bigger at around 250 MB because it needs to bundle the required .NET components together. +- Flow is published as a self-contained app, which means it can run straight away without needing to install .NET runtime and framework. Coupled with portable mode, it can be stored on Dropbox or another cloud storage provider and run. The trade-off is that the installed package size is slightly bigger (around 250 MB) because it bundles the required .NET components together. #### Searching - Search for items using: @@ -21,7 +21,7 @@ - Press `Ctrl + Enter/Click` on a Shell plugin command to run it directly as an Administrator. - In the plugins download list, you can press ctrl + enter/click to open the plugin's url. - Explorer's Search action keyword combines both Path and Index search, so you can use it without worrying about which action keyword to use for what, just enter what you need to search for. Path (searches a specific path) and Index (search a file or folder name) search allows users to do just their specific searches and are disabled by default. -- Whilst in the query window and searching inside a directory, pressing `Ctrl + Backspace` to go back up one level in the directory tree. +- Whilst in the query window and searching inside a directory, press `Ctrl + Backspace` to go back one level in the directory tree. #### Settings - Flow's settings including installed plugins are located at: From 12a409c1854a0069e2ceb62cad39468416dd5b29 Mon Sep 17 00:00:00 2001 From: Damien Date: Wed, 27 May 2026 12:14:28 +1000 Subject: [PATCH 5/7] restructure and updates based on first round of team feedback --- ...lugins.md => develop-executable-plugins.md | 4 +- develop-nodejs-plugins.md | 163 +++++++++++ develop-python-plugins.md | 262 ++++++++++++++++++ faq.md | 5 +- keyboard-shortcuts.md | 6 +- nodejs-develop-plugins.md | 17 -- nodejs-plugin-references.md | 6 - nodejs-release-project.md | 2 - nodejs-setup-project.md | 62 ----- nodejs-write-code.md | 69 ----- plugin-dev.md | 15 +- plugin-explorer.md | 2 +- py-develop-plugins.md | 83 ------ py-plugin-references.md | 8 - py-release-project.md | 2 - py-setup-project.md | 70 ----- py-write-code.md | 87 ------ quickstart.md | 8 +- 18 files changed, 443 insertions(+), 428 deletions(-) rename executable-develop-plugins.md => develop-executable-plugins.md (97%) create mode 100644 develop-nodejs-plugins.md create mode 100644 develop-python-plugins.md delete mode 100644 nodejs-develop-plugins.md delete mode 100644 nodejs-plugin-references.md delete mode 100644 nodejs-release-project.md delete mode 100644 nodejs-setup-project.md delete mode 100644 nodejs-write-code.md delete mode 100644 py-develop-plugins.md delete mode 100644 py-plugin-references.md delete mode 100644 py-release-project.md delete mode 100644 py-setup-project.md delete mode 100644 py-write-code.md diff --git a/executable-develop-plugins.md b/develop-executable-plugins.md similarity index 97% rename from executable-develop-plugins.md rename to develop-executable-plugins.md index e40c878..1a15abc 100644 --- a/executable-develop-plugins.md +++ b/develop-executable-plugins.md @@ -13,12 +13,12 @@ This is a good choice when you want: When a user triggers your plugin, Flow: -1. Launches your executable as a subprocess (once, on startup) +1. Launches your executable as a subprocess 2. Sends a JSON-RPC request to the process's **stdin** 3. Reads the JSON-RPC response from the process's **stdout** 4. Renders the returned results -Your process stays alive for the lifetime of the Flow session. It must read from stdin in a loop and write responses to stdout. +Your process stays alive for the lifetime of the Flow session with JsonRPC v2 (for v1 it runs when called and then exits). It must read from stdin in a loop and write responses to stdout. > **Important:** Only write JSON-RPC responses to stdout. Any debug output must go to **stderr** or a log file, or Flow will fail to parse it. diff --git a/develop-nodejs-plugins.md b/develop-nodejs-plugins.md new file mode 100644 index 0000000..6a968f1 --- /dev/null +++ b/develop-nodejs-plugins.md @@ -0,0 +1,163 @@ +As the language of the internet, Javascript can be used to write Flow plugins. + +## About Flow's TypeScript/JavaScript plugins + +Plugins written in TypeScript/JavaScript use the [JSON-RPC](https://flow-launcher.github.io/docs/#/json-rpc) protocol to communicate with Flow via JSON structured calls. + +Although not a hard requirement, this guide will use Node.js to run the TypeScript/JavaScript. We will refer to TypeScript/JavaScript plugin as Node.js plugin from here on. + +When building a Node.js plugin, there are several things to be mindful of: + +* The most important thing is we do not expect users to have to manually install the dependencies via npm because we aim to provide a seamless experience for them. This can be achieved by adding the following three things to your project: + 1. Add a GitHub workflow — use a GitHub workflow that will install all your plugin's dependencies including the modules inside a folder called `node_modules`. + 2. Publish all as a zip — zip up your project including a lib directory that contains the modules and publish it to GitHub Releases page. + 3. Point your module path to the node_modules directory — reference all the modules to that directory. + +* Users can use their system-installed Node.js with Flow Launcher, but in most circumstances, they will most likely be using Flow Launcher's download of [Node.js](https://nodejs.org/dist/v16.18.0/node-v16.18.0-win-x64.zip). This download of portable Node.js version is isolated from the user's system and can be simply removed. + +### Simple Example +Have a look at this simple example plugin [here](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS), notice it has a folder called `.github/workflows` and a file called `Publish Release.yml`. This is the workflow file that GitHub Workflow uses to run the CI/CD for the project. Moving out of that folder, you can go into the [main.js](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS/blob/main/main.js) file; this is the entry file for your plugin. + +## Add GitHub workflow +The workflow [file](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS/blob/main/.github/workflows/Publish%20Release.yml) will help build and deploy your project, it does the following things: +1. `workflow_dispatch:` gives you the option to manually run your workflow from the Actions section of your project + +2. On pushes to main, it will kick off the workflow but ignore the push if it's only changes made to the workflow file. + +```yml +push: + branches: [ main ] + paths-ignore: + - .github/workflows/* +``` + +3. It specifies the Node.js version that will be used for building your project: + +```yml +- name: Set up Node.Js + uses: actions/setup-node@v2 + with: + node-version: '17.3.0' +``` + +4. The project's release version is obtained from your plugin.json automatically by the CI, so when built, it will be appended to the zip file later: + +```yml +- name: get version + id: version + uses: notiz-dev/github-action-json-property@release + with: + path: 'plugin.json' + prop_path: 'Version' +``` + +5. The **Install dependencies** section is where you will do most of your CI work. It will run `npm install`, which will output all the dependencies specified in package.json into the 'node_modules' directory. The workflow will then zip them up along with your project using `zip -r Flow.Launcher.Plugin.HelloWorldNodeJS.zip . -x '*.git*'`, where you replace this `Flow.Launcher.Plugin.HelloWorldNodeJS` with the name of your plugin. + +```yml +- name: Install dependencies + run: | + npm install + zip -r Flow.Launcher.Plugin.HelloWorldNodeJS.zip . -x '*.git*' +``` + +### Publish as zip +The final step to the workflow file is this **Publish** section, which will publish the zip file you generated, upload to GitHub Releases page and tag with the version generated from the previous step from your plugin.json file. Remember again to replace `Flow.Launcher.Plugin.HelloWorldNodeJS` with the name of your plugin. + +```yml +- name: Publish + uses: softprops/action-gh-release@v1 + with: + files: 'Flow.Launcher.Plugin.HelloWorldNodeJS.zip' + tag_name: "v${{steps.version.outputs.prop}}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +``` + +Feel free to also have a read of this [blog post](https://blog.ipswitch.com/how-to-build-your-first-github-actions-workflow) which does a simple explanation of how to use GitHub Actions Workflow. + +### Use node_modules directory +Once the `node_modules` folder is included in your zip release, it can then be used without needing the user to manually npm install the plugin's dependencies. You just have to tell the plugin during runtime to find those modules in your local node_modules directory. Do this by using this exact copy of the following code block in your [main.js](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS/blob/main/main.js): +```javascript +const open = require('./node_modules/open'); +``` + +## Start with a branch +Since we have created a CI for your plugin in the [previous step](https://flow-launcher.github.io/docs/#/nodejs-setup-project), which includes creating a release when you push/merge to the 'main' branch, it is then necessary to create another git branch separate to your 'main' branch so you can continue to work on your plugin with git commits and pushes without creating a new release each time. + +It is a good practice that you create a branch for each of the new feature/fixes you are releasing for your plugin, if you are not sure how to do so then follow this [video tutorial](https://www.gitkraken.com/learn/git/problems/create-git-branch). Once you have fully finished developing your plugin with your new branch, then you can merge it into the 'main' branch, which will consequently create a new release for your plugin with a version from your `plugin.json`. + +### main.js +your main.js should look something like below: +```js +const open = require('./node_modules/open'); + +const { method, parameters, settings } = JSON.parse(process.argv[2]); + +if (method === "query") { + console.log(JSON.stringify( + { + "result": [{ + "Title": "Hello World Typescript", + "Subtitle": "Showing your query parameters: " + parameters + ". Click to open Flow's website", + "JsonRPCAction": { + "method": "do_something_for_query", + "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher"] + }, + "IcoPath": "Images\\app.png", + "score" : 0 + }] + } + )); +} + +if (method === "do_something_for_query") { + url = parameters[0]; + do_something_for_query(url); +} + +function do_something_for_query(url) { + open(url); +} +``` + +
+ +### Query entry point +**if (method === "query")** + +This if statement captures the args passed via JSON-RPC defined as `const { method, parameters } = JSON.parse(process.argv[2])`, so if `method` is `'query'` then the console.log's code block will be run. As the `result` property is an array, you can also specify a single or multiple results. + +### Assigning an action to your results +**JsonRPCAction** + +This is where you specify the method that will be executed when the user selects on the result. +In this example, if the user selects the result, the `do_something_for_query` method will be called with the url parameter which opens the Flow Launcher GitHub repo. + +### node.bat +The [node.bat](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS/blob/main/node.bat) file is the entry Flow uses to call main.js, it will set the working directory to the plugin's own location before calling main.js with node. +``` +@echo off +SET plugin_dir=%~dp0% +node "%plugin_dir%/main.js" %* +``` + +### Result score +The `score` field provides the ability to assign a weight to your score; the higher the score is, the higher the result from the plugin would show in flow's result list. The range in which you assign the score is usually between 0–100. You can keep it as 0 if your plugin generally uses an action keyword to trigger, but if you are using a global action keyword - `*` then the average weight for a plugin would be 50. Additionally, users can tweak the score via Flow's plugin setting as well. + +### Your plugin.json +You will also need to, if not yet already, create a plugin.json file that will instruct Flow on how to load your plugin. + +This file should be placed in the top level folder. + +To revisit what to include in your plugin.json, visit [here](/plugin.json.md) + +## Release your plugin to Flow's Plugin Store + +When you are ready to release your plugin for people to enjoy, head over to Flow's [plugin repo](https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest) and follow the instructions there in the readme. + +## Good references to follow + +Here are some plugins that could help you build out your own or serve as a reference point: +- Plugin Template https://github.com/Joehoel/flow-launcher-plugin-template-node +- Discord Timestamps https://github.com/Jessuhh/discord-timestamps-flowlauncher-plugin +- NPM Search https://github.com/gabrielcarloto/flow-search-npm \ No newline at end of file diff --git a/develop-python-plugins.md b/develop-python-plugins.md new file mode 100644 index 0000000..cc00129 --- /dev/null +++ b/develop-python-plugins.md @@ -0,0 +1,262 @@ +Python is a common language allowing for rapid prototyping without the need for compilation. + +## About Flow's Python plugins + +Python plugins use the [JSON-RPC](https://flow-launcher.github.io/docs/#/json-rpc) protocol to communicate with Flow via JSON structured calls. + +When building a Python plugins, there are several things to be mindful of: + +* The most important thing is we do not expect users to have to manually install the dependencies in requirements.txt because we aim to provide a seamless experience for them. This can be achieved by adding the following three things to your project: + 1. Add a GitHub workflow — use a GitHub workflow that will install all your plugin's dependencies including the Python flowlauncher module to a folder called Lib inside your plugin. + 2. Publish all as a zip — zip up your project including a lib directory that contains the modules and publish it to GitHub Releases page. + 3. Point your module imports to the lib directory — reference all the modules to that directory where they are first imported. + +* Users can use their own system-installed Python with Flow Launcher, but in most circumstances they will most likely be using Flow Launcher's download of [Embedded Python](https://docs.python.org/3/using/windows.html#the-embeddable-package). This download is isolated from the users system and does not prepend the scripts run directory to the system `PATH`.[ref](https://bugs.python.org/issue28245) If you need to import external files please follow the example below. + +* It should also be noted that external libraries that include compiled code can pose compatibility issues with different versions of Python. This is because the compiled code is platform-specific and tied to a specific version of Python. If you *must* use an external library with compiled code, you may look at alternative packaging methods such as [nuitka](http://nuitka.net/), or [pyinstaller](https://pyinstaller.org/en/stable/). + +### Simple Example +Have a look at this simple example plugin [here](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython), notice it has a folder called `.github/workflows` and a file called 'Publish Release.yml'. This is the workflow file that GitHub Workflow uses to run the CI/CD for the project. + +Moving out of that folder, you can go into the [main.py](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython/blob/main/main.py) file; this is the entry file for your plugin. Notice it has this code block: +```python +import sys +from pathlib import Path + +plugindir = Path.absolute(Path(__file__).parent) +paths = (".", "lib", "plugin") +sys.path = [str(plugindir / p) for p in paths] + sys.path +``` + +Now that we've added our `lib` folder to `sys.path`, we can now import our external libraries like so: +```python +from flowlauncher import FlowLauncher #external library +import webbrowser #Not external +``` + +We inherit from the FlowLauncher class provided by the FlowLauncher library we imported. This will allow our plugin to communicate with FlowLauncher. + +```python +class HelloWorld(FlowLauncher): +``` + +When a user activates our plugin, we can retrieve their query by providing a `query` method. Flow Launcher provides the argument `query` with the users text. + +To send a response back, we need to return a list of dictionaries as shown below. The `JsonRPCAction` dict allows you to provide a method that will be called by Flow Launcher with the parameters you provided. This method *must* be part of your plugin class. + +```python + def query(self, query): + return [ + { + "Title": "Hello World, this is where title goes. {}".format(('Your query is: ' + query , query)[query == '']), + "SubTitle": "This is where your subtitle goes, press enter to open Flow's url", + "IcoPath": "Images/app.png", + "ContextData": ["foo", "bar"] + "JsonRPCAction": { + "method": "open_url", + "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher"] + } + } + ] +``` + +This method will be called when a user selects our result: + +```python + def open_url(self, url): + webbrowser.open(url) +``` + +The context menu is activated when the user uses Shift+Enter or right-clicks on a result. The context menu is similar to the `query` method except it does not receive a `query` argument but a `data` argument with a list of values from the result selected. + +```python + def context_menu(self, data): + return [ + { + "Title": "Hello World Python's Context menu", + "SubTitle": "Press enter to open Flow the plugin's repo in GitHub", + "IcoPath": "Images/app.png", + "JsonRPCAction": { + "method": "open_url", + "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython"] + } + } + ] +``` + + +## Project setup + +### 1. Add GitHub workflow +The workflow [file](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython/blob/main/.github/workflows/Publish%20Release.yml) will help build and deploy your project, it does the following things: +1. `workflow_dispatch:` gives you the option to manually run your workflow from the Actions section of your project + +2. On pushes to main, it will kick off the workflow but ignore the push if it's only changes made to the workflow file. + +```yml +push: + branches: [ main ] + paths-ignore: + - .github/workflows/* +``` + +3. It specifies the python version that will be used for building your project: + +```yml + env: + python_ver: 3.11 +``` + +4. The project's release version is obtained from your plugin.json automatically by the CI, so when built, it will be appended to the zip file later: + +```yml +- name: get version + id: version + uses: notiz-dev/github-action-json-property@release + with: + path: 'plugin.json' + prop_path: 'Version' +``` + +5. The **Install dependencies** section is where you will do most of your CI work. Notice it installs the requirements.txt and outputs it with the `-t` parameter to the `./lib` folder. This tells pip to dump all the installed modules to the local lib folder which you will zip up along with your project using the `zip -r Flow.Launcher.Plugin.HelloWorldPython.zip . -x '*.git*'`, where you replace this `Flow.Launcher.Plugin.HelloWorldPython` with the name of your plugin. + + You can also add additional steps here to unpack/install any additional dependencies your plugin requires, for example, compiling additional translation files like [this](https://github.com/deefrawley/Flow.Launcher.Plugin.Currency/blob/23770ee929af059b1b1b7f9b5f3327b692ac9587/.github/workflows/Publish%20Release.yml#L34) + +```yml +- name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r ./requirements.txt -t ./lib + zip -r Flow.Launcher.Plugin.HelloWorldPython.zip . -x '*.git*' +``` + +### 2. Publish as zip +The final step to the workflow file is this **Publish** section, which will publish the zip file you generated, upload to GitHub Releases page and tag with the version generated from the previous step from your plugin.json file. Remember again to replace `Flow.Launcher.Plugin.HelloWorldPython` with the name of your plugin. +```yml +- name: Publish + if: success() + uses: softprops/action-gh-release@v1 + with: + files: 'Flow.Launcher.Plugin.HelloWorldPython.zip' + tag_name: "v${{steps.version.outputs.prop}}" + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +``` + +Feel free to also have a read of this [blog post](https://blog.ipswitch.com/how-to-build-your-first-github-actions-workflow) which does a simple explanation of how to use GitHub Actions Workflow. + +### 3. Use lib directory +Once the lib folder is included in your zip release, it can then be used without needing the user to manually pip install. You just have to tell during runtime to find those modules in your local lib folder. Do this by using this exact copy of the following code block: +```python +import sys +from pathlib import Path + +plugindir = Path.absolute(Path(__file__).parent) +paths = (".", "lib", "plugin") +sys.path = [str(plugindir / p) for p in paths] + sys.path + +``` +Add the above code into your init file at the top, usually this is the [main.py](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython/blob/main/main.py) file. This block of code appends the path of your lib and plugin directories on the user's machine to `sys.path`. `sys.path` is a built-in variable within the sys module, which contains a list of directories that the Python interpreter will search in for the required module. Effectively, we are telling the interpreter if the required modules in your plugin are not found among its built-in modules then look through the list of directories defined by `sys.path`, which should have all the modules installed by your GitHub workflow in the 'lib' folder. + +## Write the code + +### 1. Start with a branch +Since we have created a CI for your plugin in the [previous step](/py-setup-project.md), which includes creating a release when you push/merge to the 'main' branch, it is then necessary to create another git branch separate to your `main` branch, so you can continue to work on your plugin with git commits and pushes without creating a new release each time. + +It is a good practice that you create a branch for each of the new feature/fixes you are releasing for your plugin, if you are not sure how to do so, then follow this [video tutorial](https://www.gitkraken.com/learn/git/problems/create-git-branch). Once you have fully finished developing your plugin with your new branch, then you can merge it into the 'main' branch, which will consequently create a new release for your plugin with a version from your `plugin.json`. + +### 2. main.py +your `main.py` should look something like below: + +```python +import sys,os +parent_folder_path = os.path.abspath(os.path.dirname(__file__)) +sys.path.append(parent_folder_path) +sys.path.append(os.path.join(parent_folder_path, 'lib')) +sys.path.append(os.path.join(parent_folder_path, 'plugin')) + +from flowlauncher import FlowLauncher +import webbrowser + + +class HelloWorld(FlowLauncher): + + def query(self, query): + return [ + { + "title": "Hello World, this is where title goes. {}".format(('Your query is: ' + query , query)[query == '']), + "subTitle": "This is where your subtitle goes, press enter to open Flow's url", + "icoPath": "Images/app.png", + "jsonRPCAction": { + "method": "open_url", + "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher"] + }, + "score": 0 + } + ] + + def context_menu(self, data): + return [ + { + "title": "Hello World Python's Context menu", + "subTitle": "Press enter to open Flow the plugin's repo in GitHub", + "icoPath": "Images/app.png", # related path to the image + "jsonRPCAction": { + "method": "open_url", + "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython"] + }, + "score" : 0 + } + ] + + def open_url(self, url): + webbrowser.open(url) + +if __name__ == "__main__": + HelloWorld() + +``` + +
+ +### 3. Query entry point +**def query(self, query):** + +This is the main entry to your plugin, and the return block will be a list of the results that your plugin returns, which could be a single or many results. + +### 4. Assigning an action to your results +**JsonRPCAction** + +This is where you specify the method that will be executed when the user selects on the result. +In this example, if the user selects the result, the `open_url` method will be called with the url parameter that opens the Flow Launcher GitHub repo. + +### 5. Create an additional context menu +**def context_menu(self, data):** + +This method creates a context menu for your results, where the user can carry out additional tasks when they go to the context menu via pressing `Shift + Enter`. A context menu could be helpful if you want some tasks specific to your returned results. For example, the Explorer plugin would return a list of file results, and when going to the context menu of one of the result users can select to copy the file. + +To attach a method to your context menu result, do the same as for normal results where you define a JsonRPCAction item with the method and parameters you want to call and pass through. In this case, the context menu will simply open the HelloWorldPython plugin's GitHub repo. + +### 6 Result score +The `score` field provides the ability to assign a weight to your score; the higher the score is, the higher the result from the plugin would show in flow's result list. The range in which you assign the score is usually between 0–100. You can keep it as 0 if your plugin generally uses an action keyword to trigger, but if you are using a global action keyword (`*`) then the average weight for a plugin would be 50. Additionally, users can tweak the score via Flow's plugin setting as well. + +### 7. Your plugin.json + +You will also need to, if not yet already, create a plugin.json file that will instruct Flow on how to load your plugin. + +This file should be placed in the top level folder. + +To revisit what to include in your plugin.json, visit [here](/plugin.json.md) + +## Release your plugin to Flow's Plugin Store + +When you are ready to release your plugin for people to enjoy, head over to Flow's [plugin repo](https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest) and follow the instructions there in the readme. + +## Good references to follow + +Here are some plugins that could help you build out your own or serve as a reference point: +- IsPrime https://github.com/lvonkacsoh/Flow.Launcher.Plugin.IsPrime +- RollDice https://github.com/lvonkacsoh/Flow.Launcher.RollDice +- FancyEmoji https://github.com/Ma-ve/Flow.Launcher.Plugin.FancyEmoji +- Steam Search https://github.com/Garulf/Steam-Search +- Currency Converter https://github.com/deefrawley/Flow.Launcher.Plugin.Currency diff --git a/faq.md b/faq.md index d8ff5a8..2d100a0 100644 --- a/faq.md +++ b/faq.md @@ -89,7 +89,10 @@ Check Flow's logs (`open log location`). Common causes: ### How do I access settings in my plugin? -See the [plugin settings guide](json-rpc-settings.md). Define settings in `SettingsTemplate.yaml` and they'll appear in Flow's Settings UI. Read them at runtime via the public API or from the settings JSON directly. +It depends on your plugin type: + +- **JSON-RPC plugins** (Python, Node.js, and similar): see the [plugin settings guide](json-rpc-settings.md). Define settings in `SettingsTemplate.yaml` and they'll appear in Flow's Settings UI. Read them at runtime from the settings object or settings JSON. +- **C# (.NET) plugins**: implement [ISettingProvider](/API-Reference/Flow.Launcher.Plugin/ISettingProvider.md) to return a custom settings panel from `CreateSettingPanel()`. Your plugin can store its options in a serializable settings model that Flow persists and loads at runtime. ### How do I test my plugin without reinstalling it each time? diff --git a/keyboard-shortcuts.md b/keyboard-shortcuts.md index ed5e47b..21f0906 100644 --- a/keyboard-shortcuts.md +++ b/keyboard-shortcuts.md @@ -17,15 +17,13 @@ A complete reference for keyboard shortcuts in Flow Launcher. | Shortcut | Action | |---|---| -| `↑` / `↓` | Move between results | +| `↑` / `↓` and `Tab` | Move between results | | `Enter` | Run the selected result's default action | | `Ctrl + Enter` | (Explorer results) Open the containing folder in File Explorer | | `Ctrl + Shift + Enter` | Run the selected result as Administrator | | `→` or `Shift + Enter` | Open the context menu for the selected result | -| `Tab` | Autocomplete (where supported by the plugin) | -| `Esc` | Close Flow | +| `Esc` | Hide Flow search box | | `F5` | Reload all plugin data | -| `Ctrl + R` | Toggle result ordering between relevance and most-recently-used | --- diff --git a/nodejs-develop-plugins.md b/nodejs-develop-plugins.md deleted file mode 100644 index 24211d1..0000000 --- a/nodejs-develop-plugins.md +++ /dev/null @@ -1,17 +0,0 @@ -### About Flow's TypeScript/JavaScript plugins - -Plugins written in TypeScript/JavaScript use the [JSON-RPC](https://flow-launcher.github.io/docs/#/json-rpc) protocol to communicate with Flow via JSON structured calls. - -Although not a hard requirement, this guide will use Node.js to run the TypeScript/JavaScript. We will refer to TypeScript/JavaScript plugin as Node.js plugin from here on. - -When building a Node.js plugin, there are several things to be mindful of: - -* The most important thing is we do not expect users to have to manually install the dependencies via npm because we aim to provide a seamless experience for them. This can be achieved by adding the following three things to your project: - 1. Add a GitHub workflow — use a GitHub workflow that will install all your plugin's dependencies including the modules inside a folder called `node_modules`. - 2. Publish all as a zip — zip up your project including a lib directory that contains the modules and publish it to GitHub Releases page. - 3. Point your module path to the node_modules directory — reference all the modules to that directory. - -* Users can use their system-installed Node.js with Flow Launcher, but in most circumstances, they will most likely be using Flow Launcher's download of [Node.js](https://nodejs.org/dist/v16.18.0/node-v16.18.0-win-x64.zip). This download of portable Node.js version is isolated from the user's system and can be simply removed. - -### Simple Example -Have a look at this simple example plugin [here](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS), notice it has a folder called `.github/workflows` and a file called `Publish Release.yml`. This is the workflow file that GitHub Workflow uses to run the CI/CD for the project. Moving out of that folder, you can go into the [main.js](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS/blob/main/main.js) file; this is the entry file for your plugin. diff --git a/nodejs-plugin-references.md b/nodejs-plugin-references.md deleted file mode 100644 index eca2608..0000000 --- a/nodejs-plugin-references.md +++ /dev/null @@ -1,6 +0,0 @@ -### Good references to follow - -Here are some plugins that could help you build out your own or serve as a reference point: -- Plugin Template https://github.com/Joehoel/flow-launcher-plugin-template-node -- Discord Timestamps https://github.com/Jessuhh/discord-timestamps-flowlauncher-plugin -- NPM Search https://github.com/gabrielcarloto/flow-search-npm diff --git a/nodejs-release-project.md b/nodejs-release-project.md deleted file mode 100644 index 9b7bee5..0000000 --- a/nodejs-release-project.md +++ /dev/null @@ -1,2 +0,0 @@ -### Release your plugin to Flow's Plugin Store -When you are ready to release your plugin for people to enjoy, head over to Flow's [plugin repo](https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest) and follow the instructions there in the readme. diff --git a/nodejs-setup-project.md b/nodejs-setup-project.md deleted file mode 100644 index cf3e41d..0000000 --- a/nodejs-setup-project.md +++ /dev/null @@ -1,62 +0,0 @@ -### 1. Add GitHub workflow -The workflow [file](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS/blob/main/.github/workflows/Publish%20Release.yml) will help build and deploy your project, it does the following things: -1. `workflow_dispatch:` gives you the option to manually run your workflow from the Actions section of your project - -2. On pushes to main, it will kick off the workflow but ignore the push if it's only changes made to the workflow file. - -```yml -push: - branches: [ main ] - paths-ignore: - - .github/workflows/* -``` - -3. It specifies the Node.js version that will be used for building your project: - -```yml -- name: Set up Node.Js - uses: actions/setup-node@v2 - with: - node-version: '17.3.0' -``` - -4. The project's release version is obtained from your plugin.json automatically by the CI, so when built, it will be appended to the zip file later: - -```yml -- name: get version - id: version - uses: notiz-dev/github-action-json-property@release - with: - path: 'plugin.json' - prop_path: 'Version' -``` - -5. The **Install dependencies** section is where you will do most of your CI work. It will run `npm install`, which will output all the dependencies specified in package.json into the 'node_modules' directory. The workflow will then zip them up along with your project using `zip -r Flow.Launcher.Plugin.HelloWorldNodeJS.zip . -x '*.git*'`, where you replace this `Flow.Launcher.Plugin.HelloWorldNodeJS` with the name of your plugin. - -```yml -- name: Install dependencies - run: | - npm install - zip -r Flow.Launcher.Plugin.HelloWorldNodeJS.zip . -x '*.git*' -``` - -### 2. Publish as zip -The final step to the workflow file is this **Publish** section, which will publish the zip file you generated, upload to GitHub Releases page and tag with the version generated from the previous step from your plugin.json file. Remember again to replace `Flow.Launcher.Plugin.HelloWorldNodeJS` with the name of your plugin. - -```yml -- name: Publish - uses: softprops/action-gh-release@v1 - with: - files: 'Flow.Launcher.Plugin.HelloWorldNodeJS.zip' - tag_name: "v${{steps.version.outputs.prop}}" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -``` - -Feel free to also have a read of this [blog post](https://blog.ipswitch.com/how-to-build-your-first-github-actions-workflow) which does a simple explanation of how to use GitHub Actions Workflow. - -### 3. Use node_modules directory -Once the `node_modules` folder is included in your zip release, it can then be used without needing the user to manually npm install the plugin's dependencies. You just have to tell the plugin during runtime to find those modules in your local node_modules directory. Do this by using this exact copy of the following code block in your [main.js](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS/blob/main/main.js): -```javascript -const open = require('./node_modules/open'); -``` diff --git a/nodejs-write-code.md b/nodejs-write-code.md deleted file mode 100644 index 336e68b..0000000 --- a/nodejs-write-code.md +++ /dev/null @@ -1,69 +0,0 @@ -### 1. Start with a branch -Since we have created a CI for your plugin in the [previous step](https://flow-launcher.github.io/docs/#/nodejs-setup-project), which includes creating a release when you push/merge to the 'main' branch, it is then necessary to create another git branch separate to your 'main' branch so you can continue to work on your plugin with git commits and pushes without creating a new release each time. - -It is a good practice that you create a branch for each of the new feature/fixes you are releasing for your plugin, if you are not sure how to do so then follow this [video tutorial](https://www.gitkraken.com/learn/git/problems/create-git-branch). Once you have fully finished developing your plugin with your new branch, then you can merge it into the 'main' branch, which will consequently create a new release for your plugin with a version from your `plugin.json`. - -### 2. main.js -your main.js should look something like below: -```js -const open = require('./node_modules/open'); - -const { method, parameters, settings } = JSON.parse(process.argv[2]); - -if (method === "query") { - console.log(JSON.stringify( - { - "result": [{ - "Title": "Hello World Typescript", - "Subtitle": "Showing your query parameters: " + parameters + ". Click to open Flow's website", - "JsonRPCAction": { - "method": "do_something_for_query", - "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher"] - }, - "IcoPath": "Images\\app.png", - "score" : 0 - }] - } - )); -} - -if (method === "do_something_for_query") { - url = parameters[0]; - do_something_for_query(url); -} - -function do_something_for_query(url) { - open(url); -} -``` - -
- -### 3. Query entry point -**if (method === "query")** - -This if statement captures the args passed via JSON-RPC defined as `const { method, parameters } = JSON.parse(process.argv[2])`, so if `method` is `'query'` then the console.log's code block will be run. As the `result` property is an array, you can also specify a single or multiple results. - -### 4. Assigning an action to your results -**JsonRPCAction** - -This is where you specify the method that will be executed when the user selects on the result. -In this example, if the user selects the result, the `do_something_for_query` method will be called with the url parameter which opens the Flow Launcher GitHub repo. - -### 5. node.bat -The [node.bat](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldNodeJS/blob/main/node.bat) file is the entry Flow uses to call main.js, it will set the working directory to the plugin's own location before calling main.js with node. -``` -@echo off -SET plugin_dir=%~dp0% -node "%plugin_dir%/main.js" %* -``` - -### 6 Result score -The `score` field provides the ability to assign a weight to your score; the higher the score is, the higher the result from the plugin would show in flow's result list. The range in which you assign the score is usually between 0–100. You can keep it as 0 if your plugin generally uses an action keyword to trigger, but if you are using a global action keyword - `*` then the average weight for a plugin would be 50. Additionally, users can tweak the score via Flow's plugin setting as well. - -### 7. Your plugin.json -You will also need to, if not yet already, create a plugin.json file that will instruct Flow on how to load your plugin. - -This file should be placed in the top level folder. - -To revisit what to include in your plugin.json, visit [here](/plugin.json.md) diff --git a/plugin-dev.md b/plugin-dev.md index f17102a..4aea924 100644 --- a/plugin-dev.md +++ b/plugin-dev.md @@ -47,7 +47,7 @@ For .NET plugins this is a direct in-process method call. For all other language | **C# / F# (.NET)** | In-process | Fastest | Full | Anything. The most capable option. | | **Python** | JSON-RPC (subprocess) | Good | Core API | Scripting, data tasks, rapid prototyping | | **JavaScript / TypeScript** | JSON-RPC (Node.js) | Good | Core API | Web API calls, JS-native tooling | -| **Executable** (any language) | JSON-RPC (subprocess) | Fastest for scripts | Core API | Go, Rust, compiled TypeScript, or any binary | +| **Executable** (any language) | JSON-RPC (subprocess) | Faster than scripted languages | Core API | Go, Rust, compiled TypeScript, or any binary | **Not sure?** Use this decision guide: @@ -129,19 +129,14 @@ Pick your language and follow the step-by-step guide: - [Develop a .NET plugin](develop-dotnet-plugins.md) ### Python -- [1. Set up your project](py-setup-project.md) -- [2. Write your plugin code](py-write-code.md) -- [3. Release your plugin](py-release-project.md) -- [Reference](py-plugin-references.md) +- [Develop a Python plugin](develop-python-plugins.md) + ### JavaScript / TypeScript (Node.js) -- [1. Set up your project](nodejs-setup-project.md) -- [2. Write your plugin code](nodejs-write-code.md) -- [3. Release your plugin](nodejs-release-project.md) -- [Reference](nodejs-plugin-references.md) +- [Develop a Nodejs plugin](develop-nodejs-plugins.md) ### Executable (Go, Rust, or any compiled language) -- [Develop an executable plugin](executable-develop-plugins.md) ← new +- [Develop an executable plugin](develop-executable-plugins.md) ← new --- diff --git a/plugin-explorer.md b/plugin-explorer.md index 6f396be..fe93cc1 100644 --- a/plugin-explorer.md +++ b/plugin-explorer.md @@ -1,6 +1,6 @@ ## Explorer Plugin -The Explorer plugin is a default plugin that installs with Flow Launcher. Previously there was an Explorer Plugin and an Everything Plugin, but these were merged, and you can now choose which search engine will search for what through Flow. If you don't already have the Everything search tool from Voidtools installed, Flow will automatically download and install it if you choose it as your search index engine. To trigger automatic install, fire a search and click the "Warning: Everything is not running" result. Flow Launcher currently only supports v1.4.x of Everything and not the 1.5 alpha branch. (For 1.5 alpha support, please refer to [this](https://github.com/Flow-Launcher/Flow.Launcher/issues/1716) link) +The Explorer plugin is a default plugin that installs with Flow Launcher and is used to search for files and folders on your filesystem. You can now choose which search engine will search for what type of item through Flow. You can use the built-in Windows Search Index which is default and is part of the Windows operating system or you can use a popular third party tool called Everything from the company Voidtools. Everything tends to be a faster search and offers more search options than Windows Index however you do need to download and install it to use it. If you don't already have the Everything search tool from Voidtools installed, Flow will automatically download and install it if you choose it as your search index engine. To trigger automatic install, fire a search and click the "Warning: Everything is not running" result. Here is how to configure this plugin: diff --git a/py-develop-plugins.md b/py-develop-plugins.md deleted file mode 100644 index a4e8145..0000000 --- a/py-develop-plugins.md +++ /dev/null @@ -1,83 +0,0 @@ -### About Flow's Python plugins - -Python plugins use the [JSON-RPC](https://flow-launcher.github.io/docs/#/json-rpc) protocol to communicate with Flow via JSON structured calls. - -When building a Python plugins, there are several things to be mindful of: - -* The most important thing is we do not expect users to have to manually install the dependencies in requirements.txt because we aim to provide a seamless experience for them. This can be achieved by adding the following three things to your project: - 1. Add a GitHub workflow — use a GitHub workflow that will install all your plugin's dependencies including the Python flowlauncher module to a folder called Lib inside your plugin. - 2. Publish all as a zip — zip up your project including a lib directory that contains the modules and publish it to GitHub Releases page. - 3. Point your module imports to the lib directory — reference all the modules to that directory where they are first imported. - -* Users can use their own system-installed Python with Flow Launcher, but in most circumstances they will most likely be using Flow Launcher's download of [Embedded Python](https://docs.python.org/3/using/windows.html#the-embeddable-package). This download is isolated from the users system and does not prepend the scripts run directory to the system `PATH`.[ref](https://bugs.python.org/issue28245) If you need to import external files please follow the example below. - -* It should also be noted that external libraries that include compiled code can pose compatibility issues with different versions of Python. This is because the compiled code is platform-specific and tied to a specific version of Python. If you *must* use an external library with compiled code, you may look at alternative packaging methods such as [nuitka](http://nuitka.net/), or [pyinstaller](https://pyinstaller.org/en/stable/). - -### Simple Example -Have a look at this simple example plugin [here](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython), notice it has a folder called `.github/workflows` and a file called 'Publish Release.yml'. This is the workflow file that GitHub Workflow uses to run the CI/CD for the project. - -Moving out of that folder, you can go into the [main.py](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython/blob/main/main.py) file; this is the entry file for your plugin. Notice it has this code block: -```python -import sys -from pathlib import Path - -plugindir = Path.absolute(Path(__file__).parent) -paths = (".", "lib", "plugin") -sys.path = [str(plugindir / p) for p in paths] + sys.path -``` - -Now that we've added our `lib` folder to `sys.path`, we can now import our external libraries like so: -```python -from flowlauncher import FlowLauncher #external library -import webbrowser #Not external -``` - -We inherit from the FlowLauncher class provided by the FlowLauncher library we imported. This will allow our plugin to communicate with FlowLauncher. - -```python -class HelloWorld(FlowLauncher): -``` - -When a user activates our plugin, we can retrieve their query by providing a `query` method. Flow Launcher provides the argument `query` with the users text. - -To send a response back, we need to return a list of dictionaries as shown below. The `JsonRPCAction` dict allows you to provide a method that will be called by Flow Launcher with the parameters you provided. This method *must* be part of your plugin class. - -```python - def query(self, query): - return [ - { - "Title": "Hello World, this is where title goes. {}".format(('Your query is: ' + query , query)[query == '']), - "SubTitle": "This is where your subtitle goes, press enter to open Flow's url", - "IcoPath": "Images/app.png", - "ContextData": ["foo", "bar"] - "JsonRPCAction": { - "method": "open_url", - "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher"] - } - } - ] -``` - -This method will be called when a user selects our result: - -```python - def open_url(self, url): - webbrowser.open(url) -``` - -The context menu is activated when the user uses Shift+Enter or right-clicks on a result. The context menu is similar to the `query` method except it does not receive a `query` argument but a `data` argument with a list of values from the result selected. - -```python - def context_menu(self, data): - return [ - { - "Title": "Hello World Python's Context menu", - "SubTitle": "Press enter to open Flow the plugin's repo in GitHub", - "IcoPath": "Images/app.png", - "JsonRPCAction": { - "method": "open_url", - "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython"] - } - } - ] -``` diff --git a/py-plugin-references.md b/py-plugin-references.md deleted file mode 100644 index 98187bd..0000000 --- a/py-plugin-references.md +++ /dev/null @@ -1,8 +0,0 @@ -### Good references to follow - -Here are some plugins that could help you build out your own or serve as a reference point: -- IsPrime https://github.com/lvonkacsoh/Flow.Launcher.Plugin.IsPrime -- RollDice https://github.com/lvonkacsoh/Flow.Launcher.RollDice -- FancyEmoji https://github.com/Ma-ve/Flow.Launcher.Plugin.FancyEmoji -- Steam Search https://github.com/Garulf/Steam-Search -- Currency Converter https://github.com/deefrawley/Flow.Launcher.Plugin.Currency diff --git a/py-release-project.md b/py-release-project.md deleted file mode 100644 index 334d38d..0000000 --- a/py-release-project.md +++ /dev/null @@ -1,2 +0,0 @@ -### Release your plugin to Flow's Plugin Store -When you are ready to release your plugin for people to enjoy, head over to Flow's [plugin repo](https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest) and follow the instructions there in the readme. diff --git a/py-setup-project.md b/py-setup-project.md deleted file mode 100644 index 90aeda9..0000000 --- a/py-setup-project.md +++ /dev/null @@ -1,70 +0,0 @@ -### 1. Add GitHub workflow -The workflow [file](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython/blob/main/.github/workflows/Publish%20Release.yml) will help build and deploy your project, it does the following things: -1. `workflow_dispatch:` gives you the option to manually run your workflow from the Actions section of your project - -2. On pushes to main, it will kick off the workflow but ignore the push if it's only changes made to the workflow file. - -```yml -push: - branches: [ main ] - paths-ignore: - - .github/workflows/* -``` - -3. It specifies the python version that will be used for building your project: - -```yml - env: - python_ver: 3.11 -``` - -4. The project's release version is obtained from your plugin.json automatically by the CI, so when built, it will be appended to the zip file later: - -```yml -- name: get version - id: version - uses: notiz-dev/github-action-json-property@release - with: - path: 'plugin.json' - prop_path: 'Version' -``` - -5. The **Install dependencies** section is where you will do most of your CI work. Notice it installs the requirements.txt and outputs it with the `-t` parameter to the `./lib` folder. This tells pip to dump all the installed modules to the local lib folder which you will zip up along with your project using the `zip -r Flow.Launcher.Plugin.HelloWorldPython.zip . -x '*.git*'`, where you replace this `Flow.Launcher.Plugin.HelloWorldPython` with the name of your plugin. - - You can also add additional steps here to unpack/install any additional dependencies your plugin requires, for example, compiling additional translation files like [this](https://github.com/deefrawley/Flow.Launcher.Plugin.Currency/blob/23770ee929af059b1b1b7f9b5f3327b692ac9587/.github/workflows/Publish%20Release.yml#L34) - -```yml -- name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r ./requirements.txt -t ./lib - zip -r Flow.Launcher.Plugin.HelloWorldPython.zip . -x '*.git*' -``` - -### 2. Publish as zip -The final step to the workflow file is this **Publish** section, which will publish the zip file you generated, upload to GitHub Releases page and tag with the version generated from the previous step from your plugin.json file. Remember again to replace `Flow.Launcher.Plugin.HelloWorldPython` with the name of your plugin. -```yml -- name: Publish - if: success() - uses: softprops/action-gh-release@v1 - with: - files: 'Flow.Launcher.Plugin.HelloWorldPython.zip' - tag_name: "v${{steps.version.outputs.prop}}" - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} -``` - -Feel free to also have a read of this [blog post](https://blog.ipswitch.com/how-to-build-your-first-github-actions-workflow) which does a simple explanation of how to use GitHub Actions Workflow. - -### 3. Use lib directory -Once the lib folder is included in your zip release, it can then be used without needing the user to manually pip install. You just have to tell during runtime to find those modules in your local lib folder. Do this by using this exact copy of the following code block: -```python -import sys -from pathlib import Path - -plugindir = Path.absolute(Path(__file__).parent) -paths = (".", "lib", "plugin") -sys.path = [str(plugindir / p) for p in paths] + sys.path - -``` -Add the above code into your init file at the top, usually this is the [main.py](https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython/blob/main/main.py) file. This block of code appends the path of your lib and plugin directories on the user's machine to `sys.path`. `sys.path` is a built-in variable within the sys module, which contains a list of directories that the Python interpreter will search in for the required module. Effectively, we are telling the interpreter if the required modules in your plugin are not found among its built-in modules then look through the list of directories defined by `sys.path`, which should have all the modules installed by your GitHub workflow in the 'lib' folder. diff --git a/py-write-code.md b/py-write-code.md deleted file mode 100644 index ee861b6..0000000 --- a/py-write-code.md +++ /dev/null @@ -1,87 +0,0 @@ -### 1. Start with a branch -Since we have created a CI for your plugin in the [previous step](/py-setup-project.md), which includes creating a release when you push/merge to the 'main' branch, it is then necessary to create another git branch separate to your `main` branch, so you can continue to work on your plugin with git commits and pushes without creating a new release each time. - -It is a good practice that you create a branch for each of the new feature/fixes you are releasing for your plugin, if you are not sure how to do so, then follow this [video tutorial](https://www.gitkraken.com/learn/git/problems/create-git-branch). Once you have fully finished developing your plugin with your new branch, then you can merge it into the 'main' branch, which will consequently create a new release for your plugin with a version from your `plugin.json`. - -### 2. main.py -your `main.py` should look something like below: - -```python -import sys,os -parent_folder_path = os.path.abspath(os.path.dirname(__file__)) -sys.path.append(parent_folder_path) -sys.path.append(os.path.join(parent_folder_path, 'lib')) -sys.path.append(os.path.join(parent_folder_path, 'plugin')) - -from flowlauncher import FlowLauncher -import webbrowser - - -class HelloWorld(FlowLauncher): - - def query(self, query): - return [ - { - "title": "Hello World, this is where title goes. {}".format(('Your query is: ' + query , query)[query == '']), - "subTitle": "This is where your subtitle goes, press enter to open Flow's url", - "icoPath": "Images/app.png", - "jsonRPCAction": { - "method": "open_url", - "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher"] - }, - "score": 0 - } - ] - - def context_menu(self, data): - return [ - { - "title": "Hello World Python's Context menu", - "subTitle": "Press enter to open Flow the plugin's repo in GitHub", - "icoPath": "Images/app.png", # related path to the image - "jsonRPCAction": { - "method": "open_url", - "parameters": ["https://github.com/Flow-Launcher/Flow.Launcher.Plugin.HelloWorldPython"] - }, - "score" : 0 - } - ] - - def open_url(self, url): - webbrowser.open(url) - -if __name__ == "__main__": - HelloWorld() - -``` - -
- -### 3. Query entry point -**def query(self, query):** - -This is the main entry to your plugin, and the return block will be a list of the results that your plugin returns, which could be a single or many results. - -### 4. Assigning an action to your results -**JsonRPCAction** - -This is where you specify the method that will be executed when the user selects on the result. -In this example, if the user selects the result, the `open_url` method will be called with the url parameter that opens the Flow Launcher GitHub repo. - -### 5. Create an additional context menu -**def context_menu(self, data):** - -This method creates a context menu for your results, where the user can carry out additional tasks when they go to the context menu via pressing `Shift + Enter`. A context menu could be helpful if you want some tasks specific to your returned results. For example, the Explorer plugin would return a list of file results, and when going to the context menu of one of the result users can select to copy the file. - -To attach a method to your context menu result, do the same as for normal results where you define a JsonRPCAction item with the method and parameters you want to call and pass through. In this case, the context menu will simply open the HelloWorldPython plugin's GitHub repo. - -### 6 Result score -The `score` field provides the ability to assign a weight to your score; the higher the score is, the higher the result from the plugin would show in flow's result list. The range in which you assign the score is usually between 0–100. You can keep it as 0 if your plugin generally uses an action keyword to trigger, but if you are using a global action keyword (`*`) then the average weight for a plugin would be 50. Additionally, users can tweak the score via Flow's plugin setting as well. - -### 7. Your plugin.json - -You will also need to, if not yet already, create a plugin.json file that will instruct Flow on how to load your plugin. - -This file should be placed in the top level folder. - -To revisit what to include in your plugin.json, visit [here](/plugin.json.md) diff --git a/quickstart.md b/quickstart.md index 2694b30..9065eca 100644 --- a/quickstart.md +++ b/quickstart.md @@ -55,7 +55,7 @@ Key things to configure early: |---|---| | Change the hotkey | General → Hotkey | | Change the theme | Appearance → Theme | -| Add or remove plugins | Plugins tab | +| Add or remove plugins | Plugin Store tab | | Set a plugin's action keyword | Plugins → [plugin name] → Action Keyword | | Prioritise a plugin's results | Plugins → [plugin name] → Priority | @@ -74,13 +74,13 @@ Key things to configure early: - `pm uninstall ` - `pm update ` -**Portable mode** — Flow is self-contained and can run from a USB drive or cloud folder (like Dropbox). Type `flow user data` to see where your settings are stored. +**Portable mode** — Flow is self-contained and can run from a USB drive or cloud folder (like Dropbox). Type `Flow Launcher UserData Folder` to see where your settings are stored. -**Back up your settings** — Copy the `UserData` folder (found via `flow user data`) to back up everything: settings, plugins, themes, and history. +**Back up your settings** — Copy the `UserData` folder (found via `Flow Launcher UserData Folder`) to back up everything: settings, plugins, themes, and history. ## Next steps - Browse the [Plugin Store](plugins.md) to extend Flow - Read [Usage Tips](usage-tips.md) for power-user tricks -- Explore [Settings](settings.md) for full configuration reference +- Explore [Settings](settings.md) - Build your own plugin → [Plugin Development](plugin-dev.md) From ce6f9fa08070dc59bb5686febfba6a2b7018c665 Mon Sep 17 00:00:00 2001 From: Damien Date: Thu, 28 May 2026 11:21:58 +1000 Subject: [PATCH 6/7] expanded keyboard shortcuts to include those in the repo README --- keyboard-shortcuts.md | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/keyboard-shortcuts.md b/keyboard-shortcuts.md index 21f0906..b746327 100644 --- a/keyboard-shortcuts.md +++ b/keyboard-shortcuts.md @@ -17,13 +17,27 @@ A complete reference for keyboard shortcuts in Flow Launcher. | Shortcut | Action | |---|---| -| `↑` / `↓` and `Tab` | Move between results | +| `Alt + Space` | Open the search window (default and configurable) | +| `↑` / `↓`, `Tab`, `Shift + Tab` | Move between results | | `Enter` | Run the selected result's default action | -| `Ctrl + Enter` | (Explorer results) Open the containing folder in File Explorer | +| `Ctrl + Enter` | Open the containing folder for explorer results | | `Ctrl + Shift + Enter` | Run the selected result as Administrator | -| `→` or `Shift + Enter` | Open the context menu for the selected result | -| `Esc` | Hide Flow search box | +| `←` / `→` | Back to result / open the context menu | +| `Ctrl + O`, `Shift + Enter` | Open the context menu for the selected result | +| `Ctrl + Tab` | Autocomplete | +| `F1` | Toggle the Preview Panel | +| `Esc` | Back to results / hide the search window | +| `Ctrl + C` | Copy the selected folder or file | +| `Ctrl + Shift + C` | Copy the selected folder or file path | +| `Ctrl + I` | Open Flow settings | +| `Ctrl + R` | Run the current query again and refresh results | | `F5` | Reload all plugin data | +| `Ctrl + F12` | Toggle Game Mode while in the search window | +| `Ctrl + +`, `Ctrl + -` | Adjust the maximum results shown | +| `Ctrl + [` / `Ctrl + ]` | Adjust the search window width | +| `Ctrl + H` | Open search history | +| `Ctrl + Backspace` | Go back to the previous directory | +| `PageUp` / `PageDown` | Move to the previous or next page | --- @@ -33,7 +47,7 @@ A complete reference for keyboard shortcuts in Flow Launcher. |---|---| | `↑` / `↓` | Move between context menu actions | | `Enter` | Run the selected context action | -| `Esc` | Close the context menu and return to results | +| `Esc` or `←` | Close the context menu and return to results | --- From d7b88fcf7111160e331d95409b0583fdbd2114af Mon Sep 17 00:00:00 2001 From: Damien Date: Fri, 29 May 2026 13:53:37 +1000 Subject: [PATCH 7/7] General plugin dev additions --- plugin-dev.md | 53 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 11 deletions(-) diff --git a/plugin-dev.md b/plugin-dev.md index 4aea924..438608e 100644 --- a/plugin-dev.md +++ b/plugin-dev.md @@ -16,6 +16,28 @@ That's it at its core — but plugins can also: --- +## Before starting work on a Plugin + +Before you start, check the Plugin Store for similar plugins. If one exists, consider reaching out to its author about extending it together—this gets features to users faster and maintains plugin quality. Only create a new plugin if the author doesn't respond, declines, or if your idea requires vastly different features, performance, or architecture. + +--- + +## Plugin Store policy + +Plugins that facilitate or contain any of the following will not be allowed: + +- Malicious code +- Piracy +- Deceptive use +- Inappropriate content +- Illegal activities +- Impersonation +- Abuse +- Fraud +- Spam + +--- + ## How Flow calls your plugin Every time the user types in the search bar, Flow calls your plugin's `query` method with the current search string. Your plugin returns results. Flow renders them. @@ -83,7 +105,13 @@ See the [plugin.json reference](plugin.json.md) for all available fields. ## What a result looks like -Whether you're writing C#, Python, or JavaScript, you return the same conceptual structure: +All plugins return a list of Result objects after a query. + +Each Result represents one row in Flow Launcher and controls: +- How that row looks +- How the user can interact with it + +It has many properties, but these are the core ones: ```json { @@ -107,17 +135,14 @@ Whether you're writing C#, Python, or JavaScript, you return the same conceptual ## Plugin folder structure -All plugins share this general layout: +Plugin structure varies by language, so the best way to get started is to use a template or sample: -```text -MyPlugin/ -├── plugin.json ← required: plugin metadata -├── main.py ← your entry point (language-dependent name) -├── SettingsTemplate.yaml ← optional: defines settings shown in Flow's UI -├── Images/ -│ └── icon.png ← plugin icon -└── lib/ ← optional: bundled dependencies -``` +- **.NET**: Use `dotnet new flow-plugin` to scaffold from a template +- **Other languages**: Check the [plugin samples](plugins.md) for real examples + +Every plugin needs a **plugin.json** file. This file tells Flow how to load your plugin and must specify, details can be found above. + +Beyond these essentials, you have flexibility in how you organize your code. See the language-specific development guides for examples. --- @@ -140,6 +165,12 @@ Pick your language and follow the step-by-step guide: --- +## Releasing your Plugin to the Plugin Store + +When you are ready to release your plugin for people to enjoy, head over to Flow's [plugin repo](https://github.com/Flow-Launcher/Flow.Launcher.PluginsManifest) and follow the instructions there in the readme. Note that each new submission needs to be reviewed and approved before it is available to all Flow users in the Plugin Store. This is done on a volunteer basis by the Flow Launcher Team so may take some time after initial submission. If it has taken a week or two, you can jump into the Flow Discord (https://discord.gg/n3vANeaxty) and let the team know the submission has been there for a while and we are sure a friendly team member will escalate the review. We appreciate the effort Plugin authors put in to extending the functionality of Flow Launcher and we will do our best to ensure Plugin submissions are reviewed in a timely manner. + +--- + ## Shared references - [plugin.json field reference](plugin.json.md)