v3.0.0 — major merge: deep links, sibling commands, autoactions, defaults overhaul#79
Open
noahcoad wants to merge 24 commits into
Open
v3.0.0 — major merge: deep links, sibling commands, autoactions, defaults overhaul#79noahcoad wants to merge 24 commits into
noahcoad wants to merge 24 commits into
Conversation
Adds test_open_url.py with mocked sublime/sublime_plugin so tests run in plain Python. Imports open_url as a package to support its 'from .url' relative import. Phase 0 ships v1-surface coverage immediately: - TestMergeSettings: User defaults + project override + missing data - TestMatchOpeners: pattern AND os filter combinations - TestGenerateUrls: search_paths × prefixes × suffixes combinatorics - TestPrepareArgs: cwd substitution + commands string/array branches - TestRemoveTrailingDelimiters, TestResolveAliases, TestPrependScheme v2-symbol test classes (TestFindLocSep, TestParseFileLocation, TestFindSelection, etc.) are skip-decorated until Phase 1+ lands the helpers they reference. test_cases.yaml ported verbatim from v2; consumed by table-driven tests once Phase 1 un-skips them. pre-push hook now runs the test suite. .gitignore picks up __pycache__/ and .pytest_cache/.
…start scan Adds module-level helpers strip_file_scheme, find_loc_sep, parse_file_location. Threads deep-link locations (file:42, file:"text", file:/regex/) through file_action -> file_done -> open_file_at_location, which uses sublime.ENCODED_POSITION for line numbers and registers a load callback for search/regex navigation. OpenUrlCommand.run gains: - multi-line region handling (single non-empty selection across multiple non-empty lines opens each line as a separate URL) - line-start scan heuristic (cursor at column 0 with non-resolvable text scans rightward via _scan_line_for_url for the first resolvable token) - per-url strip_file_scheme + os.path.expandvars before handle() OpenUrlCommand.handle now also retries each candidate url as path:location when the bare resolution misses, so 'foo.py:42' resolves to foo.py and opens at line 42. Behavior unification: show_menu=False on a path:location now navigates to the location instead of just opening the file at the top. New setting: deep_link_line_number_only (default false) restricts deep links to numeric line markers, dropping :"text" and :/regex/ forms. Tests: 87/87 pass. New classes TestFindLocSep (17), TestParseFileLocation (13), TestStripFileScheme (9), TestIsResolvable (13), TestScanLineForUrl (8) plus YAML-driven cases. TestFindSelection / TestSelectionMethod stay skipped until Phase 2.
Adds four new TextCommand classes plus shared helpers:
- find_selection() / selection() on OpenUrlCommand: smarter expansion that
handles enclosing quotes/backticks and deep-link tokens
(path:42, path:"text", path:/regex/), distinct from get_selection's
simpler delimiter-based expansion which still feeds the resolution path.
- apply_path_transform() module helper: shells out a {path} template,
returning (new_path, error) — used by both Copy commands.
SelectUrlCommand expands the cursor to a URL/path region and copies it.
CopyDeepLinkCommand emits file:line / file:"text" / file:/regex/ depending
on selection state and current line content; honors copy_path_transform
and deep_link_line_number_only.
CopyTransformedPathCommand pipes the file path through the same transform
and only is_visible() in the palette when configured.
PasteRelativePathCommand picks the shortest of relative / tilde / absolute
forms, resolves symlinks on both sides, preserves any deep-link suffix on
clipboard text, and auto-wraps in backticks for markdown views.
Palette gains four "Open URL: ..." entries. Default keymaps gain four
new bindings on each platform, all gated by the existing
disable_default_key_bindings setting:
macOS: ctrl+shift+u, ctrl+alt+shift+u, ctrl+alt+v, ctrl+alt+shift+c
Lin/Win: ctrl+alt+shift+u, ctrl+alt+shift+d, ctrl+alt+v, ctrl+alt+shift+c
The ctrl+alt+shift+c choice resolves the v1 ctrl+alt+u collision by giving
copy_transformed_path its own home rather than overloading the open_url key.
Settings additions: copy_path_transform (string, default ""),
paste_relative_path_markdown_backticks (bool, default true).
Tests: 121/121 pass. New classes TestFindSelection (22), TestSelectionMethod (2),
TestApplyPathTransform (3), TestCopyTransformedPathVisibility (2),
TestCopyDeepLinkBuildsLink (4).
Adds three additive opener-schema extensions in v1's *_custom_commands lists:
terminal: bool — wrap the command in xterm/cmd.exe
pause: bool — read -p prompt after exit (paired with terminal)
pre_command: str — prepended to commands (replaces v2's openwith/app)
Adds new top-level autoactions setting: list of regex/extension matchers
that pre-select an opener label and either auto-invoke it or pre-highlight
it in the menu. Schema:
{ os?, pattern? | endswith?, label, action: 'auto'|'menu' }
Reserves four sentinel command names dispatched in-process instead of
spawning a subprocess (BUILTIN_COMMANDS frozenset):
edit_in_sublime — open via Sublime (with deep-link if present)
open_in_new_window — sublime.executable_path -n <path>
system_open — open / xdg-open / cmd start
add_to_project — append folder to window.project_data()
A user opener of { 'commands': 'add_to_project' } now works directly.
Wires select_default_opener() into file_action and folder_action: when
autoactions match, the opener is invoked immediately (action=auto) or the
quick panel opens with that opener pre-highlighted (action=menu). The
file menu's pseudo 'edit' entry is index 0; user openers shift to 1..n.
Existing user configs with no new fields and empty autoactions retain
identical behavior (regression covered by
test_existing_opener_without_new_fields_unchanged).
Tests: 138/138 pass. New classes TestSelectDefaultOpener (8) and
TestPrepareArgsBuiltinAndExtras (9).
Adds browser_search setting (string with {query} placeholder). Used by
modify_or_search_action with this precedence:
- web_searchers empty AND browser_search set
-> open browser_search directly, no panel
- web_searchers non-empty
-> show modify-or-search panel; if browser_search is also set, it
appears as the last entry labeled "search ({term})"
Existing v1 default has web_searchers populated and browser_search empty,
so existing users see no behavior change.
New helper _resolve_browser_search(term, template, encoding) handles
{query} substitution with URL-encoded text.
Tests: 144/144 pass. New classes TestResolveBrowserSearch (2),
TestModifyOrSearchAction (4).
Rewrites the shipped open_url.sublime-settings so a fresh install behaves like the v2 fork: rich file/folder menus driven by sentinel commands and sensible autoactions for common file extensions. Default file_custom_commands now: edit, run, reveal, open in new window, system open. Default folder_custom_commands: open in new window, reveal, add to project. Default autoactions auto-edit .txt/.md/.log/.config/ .sublime-settings/.sublime-project, auto-run Windows .exe/.com, and open the menu pre-highlighting 'run' for Windows .bat/.cmd. Default browser_search points at Google. Every existing setting key is preserved with a value (no removals). User-folder and project-level settings continue to win over these defaults via merge_settings, so existing customizations are unaffected (regression covered by TestUserOverrideReplacesDefaults). Adds messages/3.0.0.md describing the migration and how to revert defaults; registered in messages.json. New version: 3.0.0. Tests: 156/156 pass. New classes TestDefaultSettings (8), TestDefaultAutoactionsBehavior (3), TestUserOverrideReplacesDefaults (1). Test harness now imports 're' at module scope to support the JSONC parser used to validate the shipped settings file.
…lette entry Settings (and key bindings) are now reachable via the standard Sublime Preferences menu instead of via the command palette.
Open URL (Skip Menu) -> Open URL: Skip Menu Open URL (Use Input) -> Open URL: Use Input
The previous implementation called the GUI binary at executable_path() with -n. On macOS this works visually but doesn't fully load the folder through Sublime's project machinery, so on_load_project_async listeners (e.g. AutoOpenNotes) fire inconsistently or not at all. Ports v2's mechanism: rewrite executable_path() to the bundled .app/Contents/SharedSupport/bin/subl. This dispatches through the running ST instance with full project event ordering, so listeners see folders set before they inspect the window. Avoids both: - GUI-binary inconsistency - shelling out to PATH 'subl' (could be a different ST build) For files, also passes the parent dir as a project root so the file opens as a tab in a window with that folder loaded. Drops -n; relies on subl's default (new window when not focused on that folder) which matches v2's user-tested behavior.
file_action() prepends a synthetic 'edit' entry to whatever file_custom_commands defines, so including an explicit 'edit' in defaults made it appear twice in the quick panel. The synthetic entry calls open_file_at_location which honors deep-link suffixes, matching the behavior the explicit entry's edit_in_sublime sentinel provided.
Previously the cursor-expansion path called get_selection, which uses the user-configurable 'delimiters' setting to find token boundaries. Default delimiters include '*' '<' '>' ',' which are valid characters inside deep-link regex/search suffixes like /file.txt:/^\\s*http/. get_selection terminated at the first '*' so the deep-link tokens were truncated and never resolved. find_selection (introduced in Phase 2 for SelectUrlCommand) is the deep-link-aware expansion: hardcoded terminator set, recognizes :42 / :\"text\" / :/regex/ tokens, handles enclosing quotes. v2 used this expansion universally; we now do the same. Also strip enclosing quotes/backticks and unescape '\\ ' before handing off to handle(), matching v2 (so 'hello\\ world.txt' resolves correctly). Adds regression to TestFindSelection plus 5 YAML cases covering regex suffixes containing *, <, >, comma.
Copy Deep Link now emits 'path:LINE:/regex/' or 'path:LINE:"text"' so the
line number anchors the location even when the regex/search pattern is
ambiguous. Navigation behavior:
- legacy ':42' -> jump to line 42 via ENCODED_POSITION (unchanged)
- legacy ':/regex/' -> first regex match in the file (unchanged)
- legacy ':"text"' -> first case-insensitive match (unchanged)
- new ':N:/regex/' -> regex match closest to line N; if no match,
fall back to line N
- new ':N:"text"' -> search match closest to line N; same fallback
Implementation:
- New module helper split_path_and_loc_suffix peels the combined form for
paste-relative-path's opaque-suffix use case.
- parse_file_location returns 'line: int|None' on regex/search dicts.
- _navigate_in_view collects all matches, picks nearest-by-row when a
hint is present, falls back to the line itself when nothing matches.
- find_loc_sep / split_path_and_loc_suffix detect the combined form by
recognizing path[...:N] before the outer suffix.
Tests: 170/170 pass. Added TestNavigateInView (3 cases), 5 new
TestParseFileLocation cases covering each form, plus updated
TestCopyDeepLinkBuildsLink for the new emit format and a new test
asserting the legacy line-number-only emit path is unchanged.
…forms
Adds a new location type:
path:123-320 -> select all text from line 123 through line 320 inclusive
parse_file_location returns {type: 'range', start, end} for this form.
open_file_at_location opens the file via ENCODED_POSITION (landing at the
first line) then expands the selection to span the full range once the
view finishes loading.
README gets a new 'Deep Links' section laying out all six forms with a
table of examples, plus what Copy Deep Link emits and how Paste Relative
Path preserves suffixes.
Tests: 175/175 pass. Added 4 TestParseFileLocation cases covering simple
ranges, degenerate single-line ranges, absolute paths, and the
non-matching 'foo:8080-bar' case. New TestNavigateInView case verifies
the actual selected region spans the requested rows.
…ns, transforms Adds first-class coverage for everything that landed in the v2->v1 merge: - Commands table with platform-specific keybindings for all five commands - Per-command sections (Skip Menu, Use Input, Copy Deep Link, Copy Transformed Path, Paste Relative Path) - Custom command schema with the new opener fields (terminal, pause, pre_command) and the four built-in sentinels - autoactions section with shipped defaults - browser_search alongside web_searchers - Settings reference table covering every key in the shipped settings - Project-specific settings still documented; project replaces (no merge) - Disable default key bindings note covers all five bindings now The original Deep Links section is kept; it already matched v3 behavior.
Black hardcodes 4-space indentation with no escape hatch, so we drop it. The remaining toolchain (flake8 + isort + pyright + the test suite) is enough to keep the codebase consistent without bikeshedding indentation. Configuration changes: - pre-push: remove the 'black --check .' line - .flake8: ignore W191 (tab indentation), E101 (mixed leading whitespace), and E128 (continuation under-indent — meaningless with tabs) - pyproject.toml: drop [tool.black]; add [tool.isort] indent = '\t' so isort rewrites import blocks with tabs when needed - pyrightconfig.json: untouched (pyright is whitespace-agnostic) Code changes: - open_url.py, url.py, test_open_url.py: leading groups of 4 spaces are now tabs. No content changes; the diff is whitespace-only. - 175/175 tests still pass.
open_url.py and url.py: 31 hand-written docstrings covering helpers, TextCommand entry points, and internal methods. Each focuses on intent or non-obvious behavior; nothing redundant with the function name alone. test_open_url.py: 224 single-line docstrings. test_* methods get a humanized version of the function name. Helpers (setUp, _make_cmd, fake_run, MockView methods, etc.) get a small lookup-table description. Tests: 175/175 still pass.
…v1 behavior) Phase 4 introduced browser_search as a parallel search mechanism alongside v1's web_searchers. With both shipped non-empty by default, the panel showed three entries — modify path, google search, search — the latter two both pointing at Google. Reverts to v1's panel-only behavior: - Drop the browser_search setting from the schema and the shipped defaults. - Restore modify_or_search_action / modify_or_search_done to v1's simpler signatures: panel always shows, populated from web_searchers. - Default web_searchers continues to ship one Google entry. Users can empty the list (no engines, only modify-path), add more entries, or remove the default — config remains the single lever. Tests: 173/173 pass (was 175; removed 2 browser_search-specific tests, added regression test asserting browser_search is gone from defaults and the v1 panel shape is preserved). README and messages/3.0.0.md updated to drop browser_search references.
The modify-path entry now matches the visual style of web_searchers
('label (term)') and appears at the bottom of the panel where
'last-resort' actions belong, instead of stealing the default
quick-panel selection.
Shorter label fits better in the action menu and matches the visual weight of neighbors like 'reveal' and 'edit'. Also updated docs and the matching test assertions.
'run' and 'system open' were both wired to the same sentinel
('system_open') so they did literally identical things on every
platform. Removed 'run'. The shipped autoactions for .exe/.com/.bat/
.cmd on Windows now reference 'system open' instead.
These markers were useful during the merge but became noise once it landed. Replaces them with descriptive section headers and renames test_*_match_v2_feel methods to plain test_default_*_menu_labels.
The Open URL command also responds to alt+double-click via the bundled Default.sublime-mousemap; surfacing it in the keybindings table.
Quick orientation header listing the registered Sublime commands, key module entry points, the settings file location, and the reserved sentinel command names.
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.
Major merge that unifies the long-divergent
select-url-oldfeature set intomasterwhile preserving v1 architecture and config style. Replaces #78 (closed when the branch was renamed frommerge-v2-into-v1tomajor-merge).What lands
path:LINE,path:START-END,path:"text",path:/regex/, plus combinedpath:LINE:/regex/andpath:LINE:"text"for unambiguous navigation.disable_default_key_bindings.*_custom_commandsentries.edit_in_sublime,open_in_new_window,system_open,add_to_projectdispatched in-process;open_in_new_windowuses the bundled macOSsublso project-load events fire reliably.terminal,pause,pre_command.file://URIs (incl.file:///,file://localhost/, percent-encoded) recognized as local paths.pre-push..txt/.md/.exe/etc.Compatibility
No setting key is removed. User-folder
open_url.sublime-settingsand project-level["settings"]["open_url"]continue to win over defaults viamerge_settings(regression covered byTestUserOverrideReplacesDefaults).Tests
174/174 pass via
python3 test_open_url.py.🤖 Generated with Claude Code