canopus 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/README.md +191 -19
  4. data/assets/keymaps/emacs.jsonc +5 -0
  5. data/assets/keymaps/jetbrains.jsonc +5 -0
  6. data/assets/keymaps/sublime.jsonc +5 -0
  7. data/assets/keymaps/vscode.jsonc +5 -0
  8. data/docs/debugging.md +143 -0
  9. data/docs/distribution.md +40 -9
  10. data/docs/lsp.md +131 -0
  11. data/docs/performance.md +18 -0
  12. data/docs/providers.md +36 -0
  13. data/docs/release-log.md +12 -0
  14. data/docs/tasks.md +64 -0
  15. data/docs/testing.md +49 -0
  16. data/docs/vim.md +3 -0
  17. data/exe/canopus +4 -1
  18. data/lib/canopus/buffer.rb +291 -50
  19. data/lib/canopus/cli.rb +5 -2
  20. data/lib/canopus/command.rb +13 -4
  21. data/lib/canopus/controller.rb +183 -40
  22. data/lib/canopus/debug/breakpoints.rb +550 -0
  23. data/lib/canopus/debug/configuration.rb +291 -0
  24. data/lib/canopus/debug/console.rb +243 -0
  25. data/lib/canopus/debug/panel.rb +487 -0
  26. data/lib/canopus/debug/session.rb +354 -0
  27. data/lib/canopus/decoration.rb +4 -2
  28. data/lib/canopus/denebola_compat.rb +27 -0
  29. data/lib/canopus/diagnostics.rb +173 -0
  30. data/lib/canopus/display_map/overlay_map.rb +6 -2
  31. data/lib/canopus/editor/snippet_expandable.rb +3 -2
  32. data/lib/canopus/editor.rb +122 -31
  33. data/lib/canopus/git/state.rb +100 -0
  34. data/lib/canopus/language/background_analysis.rb +93 -14
  35. data/lib/canopus/language/document.rb +70 -34
  36. data/lib/canopus/language/symbol.rb +1 -0
  37. data/lib/canopus/language/syntax_worker.rb +61 -9
  38. data/lib/canopus/language.rb +3 -0
  39. data/lib/canopus/minimap.rb +201 -0
  40. data/lib/canopus/patch.rb +3 -1
  41. data/lib/canopus/plugins/api.rb +4 -2
  42. data/lib/canopus/plugins/isolated_runtime.rb +64 -7
  43. data/lib/canopus/plugins/registry.rb +114 -3
  44. data/lib/canopus/plugins.rb +8 -7
  45. data/lib/canopus/project.rb +15 -6
  46. data/lib/canopus/provider.rb +192 -0
  47. data/lib/canopus/regexp_compat.rb +36 -4
  48. data/lib/canopus/selection.rb +12 -0
  49. data/lib/canopus/settings/schema.rb +201 -0
  50. data/lib/canopus/settings.rb +328 -49
  51. data/lib/canopus/task/configuration.rb +356 -0
  52. data/lib/canopus/task/problem_matcher.rb +264 -0
  53. data/lib/canopus/task/runner.rb +314 -0
  54. data/lib/canopus/test_runner/bounded_ignore.rb +144 -0
  55. data/lib/canopus/test_runner/discovery.rb +97 -0
  56. data/lib/canopus/test_runner/execution.rb +194 -0
  57. data/lib/canopus/test_runner/minitest.rb +116 -0
  58. data/lib/canopus/test_runner/rspec.rb +103 -0
  59. data/lib/canopus/test_runner/safe_walker.rb +37 -0
  60. data/lib/canopus/test_runner.rb +54 -0
  61. data/lib/canopus/theme/import.rb +131 -0
  62. data/lib/canopus/theme.rb +28 -4
  63. data/lib/canopus/version.rb +1 -1
  64. data/lib/canopus/vim/motionable.rb +1 -1
  65. data/lib/canopus/vim.rb +10 -16
  66. data/lib/canopus/workspace/auto_savable.rb +83 -0
  67. data/lib/canopus/workspace/debug_aware.rb +600 -0
  68. data/lib/canopus/workspace/edit/plan.rb +2 -2
  69. data/lib/canopus/workspace/editor_configurable.rb +113 -0
  70. data/lib/canopus/workspace/file_change_aware.rb +11 -3
  71. data/lib/canopus/workspace/git_aware.rb +80 -34
  72. data/lib/canopus/workspace/git_blame.rb +175 -0
  73. data/lib/canopus/workspace/git_conflict_resolution.rb +410 -0
  74. data/lib/canopus/workspace/git_diff_view.rb +641 -0
  75. data/lib/canopus/workspace/git_history.rb +171 -0
  76. data/lib/canopus/workspace/git_remote.rb +267 -0
  77. data/lib/canopus/workspace/git_staging.rb +583 -0
  78. data/lib/canopus/workspace/hierarchy_aware.rb +477 -0
  79. data/lib/canopus/workspace/keymap_aware.rb +66 -0
  80. data/lib/canopus/workspace/language_aware.rb +3721 -135
  81. data/lib/canopus/workspace/language_server_configurable.rb +287 -71
  82. data/lib/canopus/workspace/persistent_undo.rb +169 -0
  83. data/lib/canopus/workspace/problems_aware.rb +131 -0
  84. data/lib/canopus/workspace/project_searchable.rb +88 -11
  85. data/lib/canopus/workspace/project_tree_editable.rb +3 -1
  86. data/lib/canopus/workspace/recoverable.rb +204 -0
  87. data/lib/canopus/workspace/session_persistable.rb +85 -13
  88. data/lib/canopus/workspace/settings_aware.rb +76 -2
  89. data/lib/canopus/workspace/task_aware.rb +194 -0
  90. data/lib/canopus/workspace/test_aware.rb +394 -0
  91. data/lib/canopus/workspace/trust.rb +73 -0
  92. data/lib/canopus/workspace/view/terminal_presentable.rb +298 -47
  93. data/lib/canopus/workspace/view.rb +399 -74
  94. data/lib/canopus/workspace.rb +688 -44
  95. data/lib/canopus.rb +20 -2
  96. data/sig/canopus.rbs +138 -31
  97. data/sig/controller.rbs +10 -3
  98. data/sig/debug.rbs +121 -0
  99. data/sig/decoration.rbs +12 -2
  100. data/sig/diagnostics.rbs +26 -0
  101. data/sig/minimap.rbs +20 -0
  102. data/sig/provider.rbs +29 -0
  103. data/sig/services.rbs +1 -16
  104. data/sig/task.rbs +92 -0
  105. data/sig/test_runner.rbs +109 -0
  106. data/sig/trust.rbs +17 -0
  107. data/sig/workspace_edits.rbs +2 -2
  108. data/sig/workspace_services.rbs +234 -2
  109. data/tools/check_dependencies.rb +21 -2
  110. data/tools/package.rb +172 -14
  111. data/tools/package_signature_test.rb +33 -0
  112. data/tools/package_test.rb +29 -0
  113. data/tools/sign_package.rb +123 -0
  114. data/tools/update.rb +189 -0
  115. data/tools/update_test.rb +71 -0
  116. metadata +206 -31
  117. data/lib/canopus/lsp/client.rb +0 -307
  118. data/lib/canopus/lsp/error.rb +0 -7
  119. data/lib/canopus/lsp/future/subscription.rb +0 -9
  120. data/lib/canopus/lsp/future.rb +0 -87
  121. data/lib/canopus/lsp/protocol.rb +0 -83
  122. data/lib/canopus/lsp/server_error.rb +0 -13
  123. data/lib/canopus/lsp/timeout.rb +0 -7
  124. data/lib/canopus/lsp/transport.rb +0 -123
  125. data/lib/canopus/lsp.rb +0 -19
  126. data/lib/canopus/project/search.rb +0 -164
  127. data/lib/canopus/project/search_worker/cancelled.rb +0 -3
  128. data/lib/canopus/project/search_worker/runner.rb +0 -9
  129. data/lib/canopus/project/search_worker.rb +0 -108
  130. data/lib/canopus/terminal/cell.rb +0 -7
  131. data/lib/canopus/terminal/grid.rb +0 -321
  132. data/lib/canopus/terminal/pty.rb +0 -178
  133. data/lib/canopus/terminal/scrollback.rb +0 -38
  134. data/lib/canopus/terminal/vt.rb +0 -398
  135. data/lib/canopus/terminal.rb +0 -13
  136. data/sig/lsp.rbs +0 -99
  137. data/sig/terminal.rbs +0 -130
data/docs/lsp.md CHANGED
@@ -21,11 +21,142 @@ An absent or `null` entry auto-detects the language's default executable; it doe
21
21
  not disable the server. If no executable is found, Canopus leaves that language
22
22
  without a server. Invalid settings keep the previous working connection.
23
23
 
24
+ Configure multiple ordered servers with option objects and explicit feature
25
+ routing. The first matching server handles single-result features such as
26
+ formatting and definition; completion, diagnostics, and code actions are merged
27
+ from every matching server:
28
+
29
+ ```json
30
+ {
31
+ "language_servers": {
32
+ "ruby": [
33
+ {"command": ["ruby-lsp"], "features": ["completion", "definition", "hover", "formatting"]},
34
+ {"command": ["rubocop", "--lsp"], "features": ["diagnostics", "codeAction"]}
35
+ ]
36
+ }
37
+ }
38
+ ```
39
+
40
+ Omit `features` to route from negotiated server capabilities. The legacy
41
+ argument array (`"ruby": ["ruby-lsp"]`) remains a single-server command. The
42
+ status bar shows each connection, and `language.restart_server` restarts one
43
+ selected server without disturbing the others.
44
+
24
45
  Changes to the command, environment, or initialization options restart the
25
46
  connection and reopen its documents. A configuration-only change sends
26
47
  `workspace/didChangeConfiguration` without restarting. Resource-changing server
27
48
  requests require confirmation as described in [workspace edits](workspace_edits.md).
28
49
 
50
+ Save-time actions are opt-in and run before the file write. Formatting runs
51
+ first, followed by the first enabled action returned for each configured kind:
52
+
53
+ ```json
54
+ {
55
+ "format_on_save": true,
56
+ "code_actions_on_save": ["source.organizeImports", "source.fixAll"],
57
+ "format_on_save_timeout": 2000
58
+ }
59
+ ```
60
+
61
+ The timeout covers the complete sequence. A timeout, stale or invalid edit, or
62
+ server failure is reported without preventing the save; edits to the saved
63
+ document accepted before a later failure remain grouped as one undo step.
64
+ Server edits use the normal version-checked workspace-edit path. Resource
65
+ operations are rejected during an automatic save action. An untitled document
66
+ establishes its URI on the first Save As, so its save-time actions begin with
67
+ the next save.
68
+
69
+ Published diagnostics are shown as severity-colored wave underlines. The most
70
+ severe message on each line is also shown at line end by default. Configure this
71
+ with `diagnostics.inline`, `diagnostics.inline_max_length`, and the minimum
72
+ `diagnostics.severity` (`error`, `warning`, `information`, or `hint`).
73
+
74
+ The Problems panel groups validated local-file diagnostics by file and also
75
+ accepts task and test sources through the diagnostics registry. Selecting a
76
+ problem opens its exact source position. `problems.filter` filters the tree by
77
+ free text and optional terms such as `severity:warning` and `source:task`; the
78
+ status bar shows current error and warning totals.
79
+
80
+ Task and test integrations publish the same validated LSP-shaped records with
81
+ `workspace.diagnostics.publish(:task, uri, diagnostics)` or `:test`. Publishing
82
+ an empty array removes that source's records for the URI.
83
+
84
+ Inlay hints are fetched for the visible source lines plus 50 lines of context and
85
+ shown inline. Label parts with a server-provided location are clickable. Configure
86
+ type and parameter-name hints, or their display limit, with `inlay_hints.types`,
87
+ `inlay_hints.parameter_names`, and `inlay_hints.max_length`; set
88
+ `inlay_hints.enabled` to `false` to disable requests.
89
+
90
+ Code lenses are cached for each document version and shown above their source
91
+ line. Unresolved lenses are resolved only as they enter the viewport; click a
92
+ lens to execute its server command. Set `code_lens.enabled` to `false` to
93
+ disable requests and hide cached lenses.
94
+
95
+ When supported, `textDocument/documentHighlight` automatically marks reads,
96
+ writes, and textual occurrences at each visible editor's caret. Results are
97
+ kept per split and caret, and are discarded when the caret or document changes,
98
+ the tab closes, or the language server is replaced.
99
+
100
+ `textDocument/documentLink` results are underlined and clickable in each visible
101
+ editor. Links without a target are resolved only when clicked. Canopus opens
102
+ HTTP(S) targets through the platform and local `file` targets in an editor;
103
+ remote file URIs and executable or custom URI schemes are rejected. Cached links
104
+ and pending resolutions are discarded after edits, hidden tabs, document close,
105
+ settings changes, or server replacement.
106
+
107
+ `editor.fold` prefers cached `textDocument/foldingRange` results and folds the
108
+ smallest range containing the caret's source line. Servers without folding
109
+ support, null or failed responses, and unconfigured languages fall back to
110
+ asynchronous Antares structure analysis; the UI thread never waits for either
111
+ source.
112
+
113
+ `Alt-Up` expands every selection through its nested
114
+ `textDocument/selectionRange` chain and `Alt-Down` restores the exact previous
115
+ selection. Unsupported, null, failed, or invalid responses fall back to
116
+ asynchronous Antares structure analysis. Move-line shortcuts use
117
+ `Alt-Shift-Up` and `Alt-Shift-Down`.
118
+
119
+ `F2` asks servers advertising rename preparation to validate the exact document
120
+ version and caret before opening the rename dialog. The prepared range,
121
+ placeholder, or client-side identifier pre-fills the dialog; edits, caret moves,
122
+ hidden tabs, server replacement, and settings reload cancel the snapshot. Servers
123
+ without preparation support, and unconfigured languages, keep the regular rename
124
+ dialog.
125
+
126
+ Run `language.linked_editing` from the command palette to request
127
+ `textDocument/linkedEditingRange`. Canopus maps the current primary selection's
128
+ relative anchor and caret to every validated, non-overlapping linked range and
129
+ creates multiple selections. The request is cancelled when the selection,
130
+ document, visible tab, settings, or server changes. Continuous linked editing
131
+ is intentionally left to the editor's normal multi-selection behavior. If no
132
+ server is available, or the server does not support the request, returns null,
133
+ fails, or times out, HTML and XML use a bounded fallback for unambiguous matching
134
+ opening and closing tag names. HTML names are ASCII case-insensitive; XML names
135
+ are exact and may contain Unicode. Self-closing and HTML void elements are not
136
+ linked.
137
+
138
+ Run `language.call_hierarchy` or `language.type_hierarchy` from the command
139
+ palette to prepare a hierarchy at the caret. If the server returns more than
140
+ one root, choose one from the palette. The right-side Hierarchy panel loads
141
+ incoming and outgoing calls, or supertypes and subtypes, only as branches are
142
+ expanded. Selecting an item opens its local file and source range; remote file
143
+ URIs are rejected.
144
+
145
+ Press Cmd-T on macOS or Ctrl-T elsewhere, or run
146
+ `language.workspace_symbols`, and enter a query. Canopus requests
147
+ `workspace/symbol` from every active server routed to `workspaceSymbol` under
148
+ one ten-second deadline, keeps configuration order while removing duplicate
149
+ results, and uses Spica to refine the returned locations. Selecting a result
150
+ opens its local file and range. If no routed server is running, or every routed
151
+ provider fails, a background Alkaid content search supplies bounded local-file
152
+ matches using the project's ignore rules. Queries are limited to 256 bytes and
153
+ results to 10,000 entries.
154
+
155
+ Sticky scroll prefers `textDocument/documentSymbol` when the server advertises
156
+ it and uses cached Antares structure regions otherwise. Requests and normalized
157
+ symbol trees are tied to the current buffer version and discarded after edits,
158
+ document close, or server retirement; painting never waits for either source.
159
+
29
160
  Editor positions use UTF-8 byte offsets internally and are converted to LSP
30
161
  UTF-16 positions. Servers selecting another position encoding are rejected.
31
162
  Messages are limited to 32 MiB, crashes fail pending requests, and a connection
data/docs/performance.md CHANGED
@@ -29,8 +29,17 @@ private directory with appropriate ACLs.
29
29
 
30
30
  Developers can produce current, reproducible measurements with:
31
31
 
32
+ ```sh
33
+ BUDGET=1 ruby bench/require.rb
34
+ ```
35
+
36
+ The require-only budget is 300 ms in a fresh Ruby process. It covers the
37
+ library load, not window creation or the first rendered frame; those remain
38
+ measured by the startup benchmark below.
39
+
32
40
  ```sh
33
41
  ruby --yjit bench/frame_profile.rb --frames 120 --output /tmp/frames.json
42
+ ruby --yjit bench/minimap.rb
34
43
  ruby bench/startup.rb --runs 3
35
44
  ruby --yjit tools/native_check.rb --idle /tmp/native-check.png
36
45
  ```
@@ -38,3 +47,12 @@ ruby --yjit tools/native_check.rb --idle /tmp/native-check.png
38
47
  Compare results only when the platform, renderer, viewport, Ruby/JIT mode,
39
48
  warmup, and diagnostic options match. Headless software rendering is a regression
40
49
  check, not a hardware-GPU performance result.
50
+
51
+ Bracket colors and indentation guides are requested and cached by visible source
52
+ rows. Structural analysis stays in the bounded language worker; files on the
53
+ large read-only path skip these decorations instead of scanning on the UI thread.
54
+
55
+ `bench/minimap.rb` renders a 10,000-line file through the real headless renderer.
56
+ It asserts the per-frame cold-generation bound, texture reuse while scrolling,
57
+ one-row regeneration after an edit, and warm p95 against a same-run minimap-off
58
+ baseline. Compare raw timings only on the same Ruby, font, scale factor, and renderer.
data/docs/providers.md ADDED
@@ -0,0 +1,36 @@
1
+ # Completion providers
2
+
3
+ `workspace.providers` combines completion sources without coupling the editor to
4
+ a particular language server. Canopus registers LSP completion itself; plugins
5
+ and embedders can add sources with `register_completion`:
6
+
7
+ ```ruby
8
+ workspace.providers.register_completion(:project_terms, priority: 20) do |buffer, offset, context|
9
+ [Canopus::Provider::Completion.new(
10
+ "ProjectName", "ProjectName", :constant, "Project term", nil,
11
+ nil, nil, [], :project_terms
12
+ )]
13
+ end
14
+ ```
15
+
16
+ The block runs away from the UI thread and receives the current buffer, UTF-8
17
+ byte offset, and a context hash whose `:query` is the word prefix. It returns an
18
+ array of `Completion` records, or an awaitable with `await(timeout:)`. Results
19
+ are fuzzy-ranked with Spica; higher source priority is the stable tie-break. Duplicate
20
+ label/insertion pairs keep the higher-ranked source. Invalid, oversized, or
21
+ failed sources are omitted without hiding results from healthy sources. All
22
+ sources share a ten-second completion deadline, rather than multiplying that
23
+ deadline by the number of registered providers.
24
+
25
+ Use source `:snippet` (or kind `:snippet`) when `insert_text` contains LSP/
26
+ TextMate snippet syntax. Additional edits are `[Range, String]` pairs and are
27
+ preflighted with the main insertion before editing.
28
+
29
+ Ghost-text integrations can register a block with
30
+ `register_inline_completion(source)`. `inline_completion(buffer, offset)` uses
31
+ the first registered provider that returns a valid non-nil string. Canopus only
32
+ provides this boundary today; AI, word, and path providers belong to their
33
+ respective later features or plugins.
34
+
35
+ At most 64 providers of each kind, 10,000 combined completion records, 1,000
36
+ additional edits per record, and 64 KiB per string are accepted.
data/docs/release-log.md CHANGED
@@ -2,4 +2,16 @@
2
2
 
3
3
  | Date | Repository | Version | Canopus follow-up | Reason |
4
4
  | --- | --- | --- | --- | --- |
5
+ | 2026-09-18 | kochab | 0.2.0 | 2026-09-18 | Settings schema metadata and safe layer merge API |
6
+ | 2026-09-18 | tarazed | 0.2.4 | 2026-09-18 | Explicit command-history clearing for terminal consumers |
7
+ | 2026-09-18 | tarazed | 0.2.3 | 2026-09-18 | Shell executable detection for argument-bearing and Windows commands |
8
+ | 2026-09-17 | thuban | 0.6.0 | 2026-09-17 | Transactional merge-conflict snapshots and resolution |
9
+ | 2026-09-17 | thuban | 0.5.0 | 2026-09-17 | Atomic partial staging and managed Git transfers |
10
+ | 2026-09-17 | thuban | 0.4.1 | 2026-09-17 | Lazy remote provider loading for headless startup |
11
+ | 2026-09-17 | tarazed | 0.2.2 | 2026-09-17 | Drain final Windows ConPTY output after process exit |
12
+ | 2026-09-16 | megrez | 0.1.1 | 2026-09-16 | Debug Adapter Protocol session lifecycle |
13
+ | 2026-09-16 | antares | 0.2.1 | 2026-09-16 | CRLF-safe selection range columns |
14
+ | 2026-09-16 | denebola | 0.2.1 | 2026-09-16 | Deterministic same-offset edit and anchor mapping |
15
+ | 2026-09-15 | thuban | 0.4.0 | 2026-09-17 | Git write, commit, history, stash, and remote APIs |
16
+ | 2026-09-15 | porrima | 0.2.0 | 2026-09-17 | Structured three-way merge conflict resolution |
5
17
  | 2026-09-14 | thuban | 0.2.0 | 2026-09-14 | Public `IgnoreMatcher` API |
data/docs/tasks.md ADDED
@@ -0,0 +1,64 @@
1
+ # Tasks
2
+
3
+ Project tasks live in `.canopus/tasks.jsonc`. Open **Run Task** from the command
4
+ palette or press Cmd-Shift-B on macOS / Ctrl-Shift-B on Linux and Windows.
5
+
6
+ ```jsonc
7
+ {
8
+ "problem_matchers": {
9
+ "ruby": {
10
+ "owner": "ruby",
11
+ "file_location": ["relative", "${workspaceFolder}"],
12
+ "pattern": {
13
+ "regexp": "^(.+):(\\d+):(?:(\\d+):)?\\s*(warning|error):\\s*(.+)$",
14
+ "file": 1, "line": 2, "column": 3, "severity": 4, "message": 5,
15
+ },
16
+ },
17
+ },
18
+ "tasks": [
19
+ {
20
+ "label": "rake test",
21
+ "command": ["bundle", "exec", "rake", "test"],
22
+ "cwd": "${workspaceFolder}",
23
+ "problem_matcher": "ruby",
24
+ "presentation": { "panel": "output", "reveal": "always" },
25
+ },
26
+ ],
27
+ }
28
+ ```
29
+
30
+ Commands are argument arrays and are passed directly to `Tarazed::PTY`; Canopus
31
+ does not interpolate a shell command string. Each task has one Output tab.
32
+ Running the same label again replaces its previous process and tab. Select a
33
+ tab and run **Stop Task** (Ctrl-C while its output is focused) to stop only that
34
+ task. Output supports terminal colors and interactive input.
35
+
36
+ The available variables are `${workspaceFolder}`, `${file}`,
37
+ `${lineNumber}`, `${selectedText}`, and `${env:NAME}`. Missing variables are
38
+ errors. `cwd` and file variables must stay inside the canonical workspace;
39
+ symlink escapes are rejected.
40
+
41
+ `presentation.panel` is currently `output`. `reveal` accepts `always` (show at
42
+ start), `silent` (show only after a failing exit), or `never`.
43
+
44
+ A problem matcher can use one `pattern` object or an array of up to eight
45
+ patterns for a multi-line diagnostic. Captures are 1-based and may specify
46
+ `file`, `line`, `column`, `end_line`, `end_column`, `severity`, and `message`;
47
+ `file`, `line`, and `message` are required across the sequence. Matching files
48
+ must already exist inside the canonical workspace. Matches are published with
49
+ source `task`, so they appear in editor diagnostics and the Problems panel.
50
+
51
+ Long-running tasks can add `background` with `begins_pattern`, `ends_pattern`,
52
+ and optional `active_on_start`. A begin match starts a fresh cycle and clears
53
+ the previous cycle's diagnostics; an end match pauses matching until the next
54
+ begin marker. `active_on_start` defaults to `false`.
55
+
56
+ Task files and expansion are limited to 1 MiB, 128 definitions, and 32 retained
57
+ Output tabs. Each PTY uses the configured terminal scrollback and queue limits,
58
+ and all output parsing remains frame-budgeted. Matcher lines and unfinished
59
+ input are limited to 64 KiB, each matcher retains at most 1,000 diagnostics,
60
+ and regular expressions use a timeout. A matcher that times out is disabled for
61
+ the rest of that task run while its already-published diagnostics are retained.
62
+ On Ruby 3.1, one timeout on a complete line is deferred to the next frame before
63
+ disabling, which avoids dropping a matcher after a transient scheduler delay;
64
+ an unterminated final line is disabled on its first timeout.
data/docs/testing.md ADDED
@@ -0,0 +1,49 @@
1
+ # Test explorer
2
+
3
+ Open the **Tests** panel with `panel.test`. Canopus discovers tests in the
4
+ background the first time the panel opens. Run `test.refresh` after changing
5
+ test declarations; filesystem changes also refresh an explorer that has
6
+ already been opened.
7
+
8
+ Discovery uses Alkaid's workspace walker and the same Git and project ignore
9
+ rules as project search. Ruby files in `test/`, ending in `_test.rb`, or named
10
+ `test_*.rb` use the Minitest adapter; files in `spec/` or ending in `_spec.rb`
11
+ use the RSpec adapter. An explicit `_test.rb` or `_spec.rb` suffix takes
12
+ precedence over a containing directory name.
13
+ Prism parses each candidate and adapters inspect its AST; comments, strings,
14
+ and syntactically invalid files are not treated as tests.
15
+
16
+ The Minitest adapter recognizes `test_` methods in classes, `test` blocks, and
17
+ Minitest spec-style `describe` / `context` groups with `it` or `specify`
18
+ examples. The RSpec adapter recognizes nested `describe`, `context`, and
19
+ `feature` groups plus their focused and skipped aliases, and `it`, `specify`,
20
+ `example`, and `scenario` examples. Test nodes retain only their framework,
21
+ workspace-relative path, static name, group path, source position, and bounded
22
+ framework selector.
23
+ Selecting a test opens its current source line after rechecking that the file
24
+ is still a regular file inside the canonical workspace. Each discovered test
25
+ also has a gutter button. The marker changes from run to running, passed,
26
+ failed, or skipped; clicking it starts that one static test through the shared
27
+ Task Output runner. Multiple declarations on one line run together.
28
+
29
+ Minitest runs use an exact suite/method filter. RSpec combines the discovered
30
+ source line with an exact full-description filter. Commands are fixed argument
31
+ arrays rather than shell strings. A regular workspace `Gemfile` is run with
32
+ `bundle exec`; inherited editor bundle state is
33
+ removed before the child starts. Output remains available in the bounded
34
+ Output panel and stopping or closing its tab cancels the run.
35
+
36
+ Failed runs publish a `test` diagnostic and retain a 256 KiB tail of output to
37
+ locate the test frame. Selecting a failed test, or its Problems entry, opens
38
+ that failure line. If no safe frame is present, Canopus falls back to the
39
+ discovered declaration.
40
+
41
+ Discovery does not follow symlinks. It scans at most 50,000 workspace files,
42
+ 2,000 candidate test files, and 10,000 tests, with a maximum traversal depth of
43
+ 64. Candidate files are limited to 1 MiB, names to 4 KiB, and adapter AST walks
44
+ to 100,000 nodes per file. Invalid UTF-8, NUL-containing, inaccessible,
45
+ oversized, and escaped paths are skipped. Refresh cancels stale work and keeps
46
+ at most one discovery worker active; closing the workspace cancels and joins
47
+ that worker.
48
+
49
+ Generating a debug launch remains a separate feature.
data/docs/vim.md CHANGED
@@ -22,3 +22,6 @@ Vimscript, arbitrary shell commands, and user mappings are not interpreted.
22
22
  Clipboard registers `+` and `*` are in-memory registers rather than OS clipboard
23
23
  integrations. Counts are capped at 10,000; macro playback allows 10 nested calls
24
24
  and 10,000 keys.
25
+
26
+ Insert and Replace modes follow Vim's literal insertion behavior and do not
27
+ apply the editor's `auto_pairs` setting.
data/exe/canopus CHANGED
@@ -13,7 +13,10 @@ unless RUBY_PLATFORM.match?(/mswin|mingw/) || RbConfig::CONFIG["YJIT_SUPPORT"] !
13
13
  exec(RbConfig.ruby, *flags, __FILE__, *ARGV)
14
14
  end
15
15
  ENV.delete("CANOPUS_YJIT_REEXEC")
16
- $LOAD_PATH.unshift(File.expand_path("../lib", __dir__))
16
+ canopus_root = File.expand_path("..", __dir__)
17
+ Gem::Specification.find_all_by_name("canopus")
18
+ .find { |specification| File.expand_path(specification.full_gem_path) == canopus_root }&.activate
19
+ $LOAD_PATH.unshift(File.join(canopus_root, "lib"))
17
20
  require "canopus"
18
21
  require "canopus/cli"
19
22
  exit Canopus::CLI.main(ARGV)