feat: add Launcher class with V1/V2 protocol support#19
Open
Garulf wants to merge 3 commits into
Open
Conversation
- Add Launcher ABC with program directory detection (env var → roaming AppData → local AppData → portable walk-up), Icons class access via launcher.icons.<name>, and Api class access via launcher.api.* - Add FlowLauncherV1: wraps JsonRPCClient, preserves existing one-shot argv[1] protocol behaviour exactly - Add FlowLauncherV2: persistent JSON-RPC 2.0 loop over stdin/stdout with newline framing, id echoing, lifecycle method handling (initialize, reload_data, close), and transparent query param normalisation so plugin methods still receive plain strings - Plugin accepts optional launcher= param; auto-detects V1/V2 from plugin.json Language field (python_v2 → V2, else V1) with FileNotFoundError fallback to V1 for test environments - Plugin.run() delegates to launcher; Plugin.settings delegates to launcher; Plugin.launcher property exposes the launcher instance - Add Icons class to icons.py with __getattr__ for flexible icon access - Add Api class to api.py wrapping existing module functions as statics - Export FlowLauncherV1, FlowLauncherV2 from pyflowlauncher - 21 new tests in tests/test_launcher.py; update test_settings to use launcher injection instead of patching removed _client attribute
- FlowLauncherV1: remove settings property override that re-parsed sys.argv[1] on every access; base Launcher.settings (returns self._settings) is now used, set once by run() - FlowLauncherV2._send_response: send empty ack when result is None so Flow Launcher is not left waiting for a response that never comes - FlowLauncherV2.run: fix null search value passthrough — use `or` instead of dict.get default so null values fall through to trimmedQuery - Plugin._detect_launcher: guard against manifest.language being None with `(language or '').lower()` to avoid AttributeError on null field - Plugin: re-add JsonRPCRequest import removed by previous refactor; used in Plugin.action() return annotation - Icons.__getattr__: raise AttributeError for dunder attribute names so copy/pickle protocols work correctly
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LauncherABC that owns FlowLauncher communication, program directory detection, icons, and API access — decoupling I/O protocol fromPluginFlowLauncherV1preserves the existing one-shotsys.argv[1]protocol with zero breaking changesFlowLauncherV2implements a persistent JSON-RPC 2.0 loop over stdin/stdout (newline-delimited), withidechoing, lifecycle method handling (initialize,reload_data,close), and transparent query param normalisationPluginauto-detects V1 vs V2 fromplugin.json'sLanguagefield — existing plugins need no changes; V2 plugins just setLanguage: "Python_v2"plugin.launcher.api.change_query(...)andplugin.launcher.icons.adminnow availableFlowLauncherV1/FlowLauncherV2exported frompyflowlauncherfor explicit injectionUsage
Test plan
python3 -m pytest tests/ -q)Plugin()with noplugin.jsonfalls back toFlowLauncherV1Plugin()withLanguage: "Python_v2"inplugin.jsonselectsFlowLauncherV2