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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64a5ffb35c2d8fdfbc91881be747cdf0882548d2e924aa04846f333e23a73487
4
- data.tar.gz: 17a825bf14afce060db1589fc6cb13986e0e7857a1d28622b99f1125d83de484
3
+ metadata.gz: dac47b89af1ba7edf042a4fadccd34541f9d5911398fa083e503171df18fe387
4
+ data.tar.gz: 659e1e6e40f34404ab9d31c8a106792051e8f255e7195b806189124b63d661a9
5
5
  SHA512:
6
- metadata.gz: c499a3d6b07424ef0d696df9ae842eabc81ef6265aa251b3e32f22c20c1ab70be30e1a9df56351cbd182f7d11bc05e536726429e53a1adc57ce2a5729df37043
7
- data.tar.gz: d1212a4befda0c26dee61f60de0a74c4a1d729b37806eccf99198d52045dbbdd6d43c493eaf33ebf0635892d9eae9b6773dd349e9bc40d031d5863a36b949b30
6
+ metadata.gz: b6a72df6cb9b0846584044cb6f480003f50452c170f54f14aff7b1a53b4801c2824d1acfb4e5f0a2e2e3d16a10631dad64e4f57be5d76ee3a9b567e83b0ecf34
7
+ data.tar.gz: 2b447543c35849039cdf37b2a2bd78dbe10b57be8fee85468059c1bcb503ef8ce1fc9aace832d07c148d22dd0892f2931e6413ed67c54767ce20e341d525953c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,60 @@
1
1
  # Changelog
2
2
 
3
+ ## Unreleased
4
+
5
+ ## 0.5.0 — 2026-09-19
6
+
7
+ - Configure automatic pairs and selection surrounding globally or per language without affecting paste, completion, or Vim insertion.
8
+
9
+ - Add command-palette actions for cursors at every selected line start or end and selections for every regular-expression match.
10
+
11
+ - Add rectangular Alt-drag selection and Ctrl-Alt-Up/Down cursor insertion across wrapped Unicode text.
12
+
13
+ - Track shell commands and working directories through Tarazed OSC 133/7 integration, fold output, show exit status, and navigate command boundaries or failed commands.
14
+ - Split the terminal panel horizontally or vertically, restore its layout and profiles, and inject editor integration variables.
15
+ - Add `--wait` for blocking editor invocations such as `EDITOR="canopus --wait"`.
16
+ - Periodically save bounded private snapshots of dirty buffers and offer valid crash recovery on the next startup.
17
+ - Require Zaniah 0.5.2 so equal-position inline overlays preserve source order on every platform.
18
+ - Delegate language-server protocol transport and lifecycle handling to Sadr.
19
+ - Delegate terminal emulation and POSIX/Windows PTY handling to Tarazed; the editor UI is unchanged.
20
+ - Delegate project walking and content search to Alkaid while retaining Canopus's search and replace UI.
21
+ - Show language-server diagnostics as severity-colored wave underlines and optional line-end messages.
22
+ - Collect LSP, task, and test diagnostics in one bounded registry with a filterable Problems panel and status counts.
23
+ - Run opt-in formatting and configured source actions before saving without letting language-server failures block the write.
24
+ - Route each language through ordered language servers, aggregate completion, diagnostics, and code actions, and restart individual servers.
25
+ - Search symbols from every active routed language server with Cmd-T/Ctrl-T and fall back to bounded Alkaid project search.
26
+ - Load bounded JSONC debug configurations, expand explicit launch variables, and resolve configured adapters.
27
+ - Persist bounded conditional breakpoints with coalesced writes and keep their lines aligned through edits, undo, and redo.
28
+ - Toggle breakpoints from the gutter and edit conditions, hit counts, log messages, and enabled state from its context menu.
29
+ - Start Megrez-backed debug sessions, configure enabled breakpoints, and highlight safe workspace stop locations.
30
+ - Browse stack frames, lazily expand fresh variable paths, reevaluate watches, and list breakpoints in the Debug panel.
31
+ - Evaluate selected-frame REPL and hover expressions and show bounded, ordered adapter output in the Debug Console.
32
+ - Run bounded JSONC project tasks through Tarazed PTYs in interactive, color-preserving Output tabs.
33
+ - Publish bounded single-line, multi-line, and watch task problem matches through the shared diagnostics registry.
34
+ - Keep regex-backed task diagnostics responsive on Ruby 3.1 with one deferred complete-line retry before fail-closed disabling.
35
+ - Discover bounded Minitest and RSpec declarations with Alkaid and Prism and browse them in the Tests panel.
36
+ - Run discovered tests from the gutter, display bounded results, and publish navigable failure diagnostics.
37
+ - Preserve registration order for equal-priority decorations across Ruby versions and platforms.
38
+ - Show cached, viewport-scoped language-server inlay hints inline with clickable label locations.
39
+ - Show cached language-server code lenses above source lines and resolve them only when visible.
40
+ - Highlight language-server read, write, and text occurrences for each visible editor caret.
41
+ - Prefer language-server folding ranges with asynchronous Antares structure fallback.
42
+ - Expand and shrink multiple selections from language-server ranges or asynchronous Antares structure data.
43
+ - Validate rename targets asynchronously before opening the dialog when the language server supports preparation.
44
+ - Underline and safely open language-server document links, resolving targets only when clicked.
45
+ - Turn validated language-server linked ranges into multiple selections from the command palette, with a bounded HTML/XML tag fallback.
46
+ - Browse call and type hierarchies in a lazily loaded side panel.
47
+ - Color nested bracket pairs from Antares structure data and draw display-aware active indentation guides.
48
+ - Render configurable space, tab, and ideographic-space markers without changing display coordinates.
49
+ - Keep the active declaration chain visible with cached LSP symbols and an Antares fallback.
50
+ - Navigate files and the cached declaration hierarchy from editor breadcrumbs.
51
+ - Add an opt-in GUI minimap with shared, edit-aware line textures and Git, search, and diagnostic overview marks.
52
+ - Route LSP, snippet, and extension completion through a bounded provider registry with stable fuzzy ranking.
53
+ - Stage Git files, hunks, and lines and create or amend commits from the Source Control panel.
54
+ - Compare Git changes and revisions inline or side by side, with word highlights and per-file history.
55
+ - Resolve text merge regions in base/ours/theirs panes, stage the completed file atomically, and advance to the next conflict.
56
+ - Browse and search bounded commit graphs, run cancellable authenticated remote transfers, and show cached inline blame on clean or edited buffers.
57
+
3
58
  ## 0.4.0 — 2026-09-15
4
59
 
5
60
  - Route commands and keybindings through one context-aware command registry.
data/README.md CHANGED
@@ -33,9 +33,25 @@ installable.
33
33
 
34
34
  - Native GPU windows on macOS, Linux, and Windows, plus TUI and headless modes
35
35
  - Persistent buffers, tabs, splits, sessions, and explicit save-conflict handling
36
- - LSP completion, diagnostics, hover, symbols, formatting, rename, and code actions
37
- - Resizable integrated terminal with multiple tabs, scrollback, selection, colors, and clickable links
38
- - Git diff, blame, hunk reversal, and branch switching
36
+ - LSP completion, diagnostics, hover, document and workspace symbols, formatting, prevalidated rename, and code actions
37
+ - Bounded debug console output, stopped-frame REPL evaluation, and safe identifier hover evaluation
38
+ - Filterable Problems tree for LSP, task, and test diagnostics, with error and warning status counts
39
+ - Automatic read, write, and text highlights for the symbol at each visible editor's caret
40
+ - Clickable LSP document links with on-demand resolution and safe HTTP or local-file navigation
41
+ - LSP folding ranges with an asynchronous Antares fallback
42
+ - LSP-aware selection expansion with an asynchronous Antares fallback
43
+ - LSP linked-range selection for starting a multi-cursor edit from the command palette
44
+ - Rectangular selection with Alt-drag and vertical cursor insertion
45
+ - Multi-cursor expansion to selected line starts, line ends, or every regular-expression match
46
+ - Lazy call and type hierarchy trees with bidirectional navigation
47
+ - Menkar-based encoding detection, newline display and conversion, and encoding-aware saves
48
+ - Ranked, extensible completion and inline-completion provider registry
49
+ - Viewport-scoped LSP inlay hints with clickable label locations
50
+ - Nested bracket colors and active indentation guides backed by Antares structure analysis
51
+ - Optional GPU minimap with shared line textures, viewport navigation, and overview markers
52
+ - Resizable integrated terminal with tabs, horizontal/vertical splits, profiles, scrollback, OSC 133 command history, colors, and clickable links
53
+ - Bounded JSONC project tasks with color-preserving, interactive Output tabs
54
+ - Git diff and staging, searchable commit graphs, cancellable fetch/pull/push, inline blame, and branch switching
39
55
  - Editable project-wide search results and safe project file operations
40
56
  - Optional Vim-compatible modes, motions, operators, registers, macros, and Ex commands
41
57
  - Layered JSONC settings, keymaps, themes, snippets, and trusted Ruby plugins
@@ -75,6 +91,9 @@ canopus --tui --project .
75
91
  canopus --headless /tmp/canopus.png README.md
76
92
  ```
77
93
 
94
+ Use `EDITOR="canopus --wait"` when a caller such as Git must wait until every
95
+ requested file tab is closed.
96
+
78
97
  Run `canopus --help` for session, settings, replay, backend, profiling, and
79
98
  plugin options.
80
99
 
@@ -83,19 +102,45 @@ plugin options.
83
102
  | Action | macOS | Linux / Windows |
84
103
  | --- | --- | --- |
85
104
  | File finder / commands | Cmd-P / Cmd-Shift-P | Ctrl-P / Ctrl-Shift-P |
105
+ | Workspace symbols | Cmd-T | Ctrl-T |
86
106
  | Save / undo / redo | Cmd-S / Cmd-Z / Cmd-Shift-Z | Ctrl-S / Ctrl-Z / Ctrl-Shift-Z |
87
107
  | Find / project search | Cmd-F / Cmd-Shift-F | Ctrl-F / Ctrl-Shift-F |
88
108
  | Replace / next occurrence | Cmd-Alt-F / Cmd-D | Ctrl-H / Ctrl-D |
89
- | All occurrences / move lines | Cmd-Shift-L / Alt-Up or Down | Ctrl-Shift-L / Alt-Up or Down |
90
- | Completion / definition | Ctrl-Space / F12 | Ctrl-Space / F12 |
109
+ | All occurrences / expand or shrink selection | Cmd-Shift-L / Alt-Up or Down | Ctrl-Shift-L / Alt-Up or Down |
110
+ | Add cursor above / below | Ctrl-Alt-Up or Down | Ctrl-Alt-Up or Down |
111
+ | Line-start, line-end, or regex cursors | Command palette | Command palette |
112
+ | Move lines | Alt-Shift-Up or Down | Alt-Shift-Up or Down |
113
+ | Completion / definition / rename | Ctrl-Space / F12 / F2 | Ctrl-Space / F12 / F2 |
91
114
  | Split / terminal | Cmd-Backslash / Ctrl-Backtick | Ctrl-Backslash / Ctrl-Backtick |
92
115
  | Close / reopen tab | Cmd-W / Cmd-Shift-T | Ctrl-W / Ctrl-Shift-T |
93
116
  | New terminal tab | Ctrl-Shift-Backtick | Ctrl-Shift-Backtick |
94
117
  | Next / previous terminal | Ctrl-Shift-] / Ctrl-Shift-[ | Ctrl-Shift-] / Ctrl-Shift-[ |
95
-
96
- The command palette also exposes Git operations, language actions, project file
97
- operations, settings, themes, docks, and Vim mode. Project deletion moves files
98
- to `.canopus/trash` instead of deleting them immediately.
118
+ | Previous / next terminal command | Ctrl-Shift-Up / Ctrl-Shift-Down | Ctrl-Shift-Up / Ctrl-Shift-Down |
119
+ | Run task | Cmd-Shift-B | Ctrl-Shift-B |
120
+
121
+ The command palette also exposes Git operations, language actions (including
122
+ `language.linked_editing`, `language.call_hierarchy`, and
123
+ `language.type_hierarchy`), project file operations, settings, themes, docks,
124
+ Vim mode, `git.history`, `git.fetch`, `git.pull`, `git.push`,
125
+ `terminal.commands`, `terminal.commands.failed`, `terminal.command.toggle_fold`,
126
+ `terminal.split_right`, `terminal.split_down`,
127
+ `panel.problems`, and
128
+ `problems.filter`. The problem filter accepts
129
+ free text plus optional `severity:error` and `source:lsp` terms (`warning`,
130
+ `information`, `hint`, `task`, and `test` are also accepted). Project deletion
131
+ moves files to `.canopus/trash` instead of deleting them immediately.
132
+
133
+ `language.linked_editing` selects matching HTML or XML opening and closing tag
134
+ names when no language server can provide linked ranges. Editing either selected
135
+ name updates both through the editor's normal multi-selection and undo behavior.
136
+
137
+ Bash, zsh, and fish terminals automatically load Tarazed shell integration
138
+ for command boundaries, collapsible output, exit status, and OSC 7
139
+ working-directory tracking. Click a command status badge to fold its output.
140
+ Set `terminal.shell_integration` to `false` to leave the shell untouched.
141
+ New terminals inherit the active terminal's OSC 7 working directory. Profiles
142
+ accept `command` (or `path` plus `args`) and `env`; Canopus always sets
143
+ `CANOPUS=1` and `EDITOR="canopus --wait"` after merging profile variables.
99
144
 
100
145
  ## Configuration
101
146
 
@@ -103,14 +148,44 @@ Run `settings.open` from the command palette to edit project settings. User
103
148
  settings live at `$XDG_CONFIG_HOME/canopus/settings.jsonc` or
104
149
  `~/.config/canopus/settings.jsonc`.
105
150
 
151
+ When enabled (the default), `.editorconfig` is read per file between user and
152
+ project settings. `indent_style`, `indent_size`, `tab_width`,
153
+ `trim_trailing_whitespace`, `insert_final_newline`, and `max_line_length` are
154
+ supported. Set `editorconfig` to `false` to disable it. Project settings keep
155
+ precedence over `.editorconfig`; malformed, oversized, or symlinked config
156
+ files are ignored.
157
+
106
158
  ```jsonc
107
159
  {
108
160
  "theme": "auto",
109
161
  "font_size": 14,
110
162
  "vim_mode": false,
111
163
  "use_tabs": false,
164
+ "auto_pairs": [["(", ")"], ["[", "]"], ["{", "}"], ["\"", "\""], ["'", "'"]],
165
+ "diagnostics": { "inline": true, "inline_max_length": 80, "severity": "warning" },
166
+ "inlay_hints": { "enabled": true, "parameter_names": true, "types": true, "max_length": 30 },
167
+ "code_lens": { "enabled": true },
168
+ "bracket_colorization": true,
169
+ "indent_guides": { "enabled": true, "active": true },
170
+ "render_whitespace": "boundary",
171
+ "render_ideographic_space": true,
172
+ "sticky_scroll": { "enabled": true, "max_lines": 5 },
173
+ "breadcrumbs": { "enabled": true },
174
+ "minimap": { "enabled": false, "width": 100, "show_diagnostics": true },
175
+ "auto_save": "off",
176
+ "auto_save_delay": 1000,
177
+ "persistent_undo": { "enabled": true, "max_entries": 1000, "expire_days": 30 },
178
+ "format_on_save": false,
179
+ "code_actions_on_save": [],
180
+ "format_on_save_timeout": 2000,
181
+ "git": { "inline_blame": "off", "autofetch": false, "autofetch_interval": 180 },
182
+ "recovery": { "enabled": true, "interval": 5000 },
112
183
  "tabs": { "activate_on_close": "history", "reopen_history_limit": 20 },
113
- "terminal": { "working_directory": "project", "scrollback_lines": 10000 },
184
+ "terminal": {
185
+ "working_directory": "project", "scrollback_lines": 10000, "shell_integration": true,
186
+ "profiles": { "bash": { "path": "/bin/bash", "args": ["--login"], "env": { "TERM_PROGRAM": "canopus" } } },
187
+ "default_profile": "bash"
188
+ },
114
189
  "dock": {
115
190
  "bottom": { "size": 280, "visible": false },
116
191
  "panels": { "terminal": { "size": 280, "visible": false } }
@@ -118,11 +193,52 @@ settings live at `$XDG_CONFIG_HOME/canopus/settings.jsonc` or
118
193
  "keymap": [
119
194
  { "context": "Editor && !vim_mode", "bindings": { "ctrl-k ctrl-s": "file.save" } }
120
195
  ],
121
- "languages": { "ruby": { "tab_size": 2 } },
122
- "language_servers": { "ruby": ["ruby-lsp"] }
196
+ "languages": { "ruby": { "tab_size": 2, "auto_pairs": [] } },
197
+ "language_servers": {
198
+ "ruby": [
199
+ { "command": ["ruby-lsp"], "features": ["completion", "definition", "hover", "formatting"] },
200
+ { "command": ["rubocop", "--lsp"], "features": ["diagnostics", "codeAction"] }
201
+ ]
202
+ },
203
+ "debug_adapters": {
204
+ "ruby": { "command": ["rdbg", "--open", "--stop-at-load"], "transport": "tcp" }
205
+ }
123
206
  }
124
207
  ```
125
208
 
209
+ A legacy argument array such as `"ruby": ["ruby-lsp"]` still configures one
210
+ server. With multiple servers, completion, diagnostics, and code actions are
211
+ merged; workspace symbols are collected from every matching active server;
212
+ other features use the first matching server in configuration order. Workspace
213
+ symbol search falls back to bounded project-content search when no usable
214
+ provider is active. Override `language.workspace_symbols` in `keymap` to change
215
+ its Cmd-T / Ctrl-T binding.
216
+
217
+ `render_whitespace` accepts `none`, `boundary`, `selection`, or `all`.
218
+ `boundary` hides only single spaces between non-whitespace characters. Tabs use
219
+ `→`, spaces use `·`, and ideographic spaces use `□`; the last remains visible
220
+ independently when `render_ideographic_space` is enabled.
221
+
222
+ `auto_pairs` replaces the opener/closer list for the current settings layer;
223
+ set it to `[]` globally or for one language to disable automatic pairing and
224
+ selection surrounding. Each opener and closer must be one Unicode grapheme.
225
+
226
+ Sticky scroll keeps the declarations containing the first visible source byte
227
+ above the editor body. It prefers cached LSP document symbols and falls back to
228
+ cached Antares structure regions; `sticky_scroll.enabled` and
229
+ `sticky_scroll.max_lines` can also be overridden per language.
230
+
231
+ Breadcrumbs show the project-relative file, containing type, and callable above
232
+ sticky scroll. Selecting an item opens its same-directory files or same-parent
233
+ symbols in the palette. `breadcrumbs.enabled` can be overridden per language.
234
+
235
+ The GUI-only minimap is disabled by default. When enabled, it reserves its
236
+ configured width only in panes wide enough to keep the editor usable, reuses
237
+ bounded low-resolution line textures across splits, and shows Git, search, and
238
+ optionally diagnostic overview marks. Click or drag it to center that source
239
+ position without moving the selection. All minimap options can be overridden
240
+ per language.
241
+
126
242
  Closing a dirty tab asks whether to save, discard, or cancel. Reopening restores
127
243
  the file, selections, position, and pane while Canopus is running; discarded
128
244
  unsaved changes are never restored. Dock and panel visibility and sizes are also
@@ -130,6 +246,24 @@ restored. Terminal session restoration, when enabled,
130
246
  starts fresh shells with the saved tab count and working directories and does
131
247
  not restore processes or scrollback.
132
248
 
249
+ Dirty buffers are also written every five seconds to private, atomically
250
+ replaced files under `.canopus/recovery/`. After an abnormal exit, the newest
251
+ valid snapshot is offered at startup; normal exit removes this run's snapshot.
252
+ Set `recovery.enabled` to `false` or change `recovery.interval` (milliseconds)
253
+ in settings. Recovery files contain local unsaved text, so disable the feature
254
+ for workspaces where even a mode-0600 local copy is unacceptable. Individual
255
+ buffers over 10 MiB and snapshots over 64 MiB are not retained.
256
+
257
+ Set `auto_save` to `after_delay` to save dirty named files after the debounce
258
+ interval in `auto_save_delay` milliseconds, or to `on_focus_change` to save a
259
+ file when switching away from it. Untitled, read-only, and conflicting files
260
+ are skipped or reported without forcing a write.
261
+
262
+ Persistent undo keeps up to `persistent_undo.max_entries` undo entries for
263
+ clean regular files under `.canopus/undo/`. Records are project- and file
264
+ identity-bound, expire after `expire_days`, and are ignored when corrupt or
265
+ when the file changes. Dirty buffers remain in recovery storage instead.
266
+
133
267
  Settings are layered from defaults through user, project, explicit `--settings`,
134
268
  and language overrides. Invalid saved settings leave the previous valid values
135
269
  active. Keymap groups extend defaults; later matching bindings win, and `null`
@@ -139,6 +273,33 @@ Language servers are separate programs and are auto-detected or configured by
139
273
  argument array. See [Language servers](docs/lsp.md) for configuration and
140
274
  restart behavior.
141
275
 
276
+ Debug launch definitions and the persistent, edit-aware breakpoint gutter
277
+ are described in [Debug configurations](docs/debugging.md). `debug.start`
278
+ selects and starts a configuration, and `debug.stop` ends the active session.
279
+ When execution stops, the Debug panel provides safe stack navigation, lazy
280
+ variables, per-stop watch evaluation (`debug.watch.add` /
281
+ `debug.watch.remove`), and the breakpoint list. Variable expansion is restored
282
+ by name path rather than adapter reference IDs.
283
+ `debug.console.evaluate` accepts REPL input for the selected frame and
284
+ `panel.debug_console` toggles ordered adapter output. Hovering a simple
285
+ local, instance, class, or global variable while stopped evaluates it in the
286
+ selected frame.
287
+ Breakpoint files use an atomic rename
288
+ for normal same-user workspace consistency; concurrent malicious workspace
289
+ mutation is outside that guarantee.
290
+
291
+ Project task definitions, variables, Output tabs, and reveal behavior are
292
+ described in [Tasks](docs/tasks.md). `task.run` opens the task picker,
293
+ `task.stop` stops the selected running Output tab, and `panel.output` toggles
294
+ the panel. Single-line, multi-line, and watch problem matchers publish task
295
+ output into the shared Problems panel and editor diagnostics.
296
+
297
+ The [Test explorer](docs/testing.md) discovers Minitest and RSpec declarations
298
+ with a bounded Alkaid walk and Prism AST inspection. `panel.test` opens the
299
+ tree and `test.refresh` rescans it. Gutter buttons run static tests in bounded
300
+ Task Output tabs and show running, passed, failed, or skipped state; selecting
301
+ a failed test opens its reported failure line.
302
+
142
303
  Plugins require explicit trust and permissions:
143
304
 
144
305
  ```sh
@@ -146,15 +307,19 @@ canopus --plugin examples/plugins/word_count.rb \
146
307
  --trust-plugins --grant read_buffer
147
308
  ```
148
309
 
149
- The default separate process contains plugin crashes and timeouts, but it is not
150
- an OS sandbox. Trusted Ruby code retains the invoking user's filesystem and
151
- network privileges.
310
+ The default separate process also requests Saiph's OS sandbox. Set
311
+ `plugins.sandbox` to `"required"` to reject plugins when the host has no
312
+ supported backend, or to `"off"` to retain the legacy process-only isolation.
313
+ The legacy `process` permission is accepted as an alias for `exec`.
152
314
 
153
315
  ## Documentation
154
316
 
155
317
  - [Language servers](docs/lsp.md)
318
+ - [Debug configurations](docs/debugging.md)
319
+ - [Test explorer](docs/testing.md)
156
320
  - [Vim mode](docs/vim.md)
157
321
  - [Snippets](docs/snippets.md)
322
+ - [Completion providers](docs/providers.md)
158
323
  - [Workspace edits](docs/workspace_edits.md)
159
324
  - [Packaging](docs/distribution.md)
160
325
  - [Profiling and local crash reports](docs/performance.md)
@@ -167,19 +332,26 @@ git clone https://github.com/noxdea/canopus.git
167
332
  cd canopus
168
333
  bundle install
169
334
  bundle exec rake test
170
- bundle exec rbs -I sig -r porrima -r thuban -r alhena -r antares -r denebola -r zaniah -r stringio -r strscan validate
335
+ bundle exec rbs -I sig -r kochab -r porrima -r thuban -r alhena -r antares -r denebola -r zaniah -r sadr -r saiph -r rexml -r megrez -r tarazed -r alkaid -r stringio -r strscan validate
171
336
  bundle exec ruby tools/check_dependencies.rb test/type/smoke.rb
172
337
  ```
173
338
 
339
+ Before component releases are available, use sibling checkouts with
340
+ `SADR_PATH=../sadr SAIPH_PATH=../saiph MEGREZ_PATH=../megrez MENKAR_PATH=../menkar TARAZED_PATH=../tarazed ALKAID_PATH=../alkaid ANTARES_PATH=../antares bundle install`.
341
+
174
342
  Run `bundle exec rake bench` for performance checks. Contributions can be
175
343
  submitted through [GitHub issues and pull requests](https://github.com/noxdea/canopus/issues).
176
344
 
177
345
  ## Limits
178
346
 
179
- - Files larger than 100 MiB use a read-only UTF-8 path without wrapping or folding.
180
- - Large-file UTF-16 and legacy encodings are unsupported.
347
+ - Files larger than 100 MiB use Denebola's read-only, UTF-8 `LazyRope` path with bounded page caching; wrapping and folding remain disabled.
348
+ - Persistent undo records are limited to 16 MiB per file and 256 MiB per project.
349
+ - Smaller text files use Menkar to detect UTF-8/16/32 and common legacy encodings; binary files are not opened as editable buffers.
350
+ - Mixed line endings are shown as `mixed` in the status bar and can be normalized to LF, CRLF, or CR from the encoding actions.
181
351
  - Git support targets SHA-1 repositories and does not implement every index or object extension.
182
- - Desktop packages are unsigned and do not bundle Ruby or automatic updates.
352
+ - The integrated terminal uses a POSIX PTY on macOS/Linux and ConPTY on 64-bit Windows.
353
+ - Desktop packages are unsigned and do not bundle Ruby or automatic updates;
354
+ signed updates are available as an explicit `tools/update.rb` operation.
183
355
 
184
356
  ## License
185
357
 
@@ -0,0 +1,5 @@
1
+ {
2
+ "keymap": [
3
+ {"context": "", "bindings": {"ctrl-x ctrl-f": "file.find", "alt-x": "command.palette", "ctrl-x ctrl-s": "file.save"}}
4
+ ]
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "keymap": [
3
+ {"context": "", "bindings": {"shift-shift": "command.palette", "ctrl-shift-n": "file.find", "shift-f6": "language.rename"}}
4
+ ]
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "keymap": [
3
+ {"context": "", "bindings": {"ctrl-p": "file.find", "ctrl-shift-p": "command.palette", "ctrl-r": "language.rename"}}
4
+ ]
5
+ }
@@ -0,0 +1,5 @@
1
+ {
2
+ "keymap": [
3
+ {"context": "", "bindings": {"ctrl-p": "file.find", "ctrl-shift-p": "command.palette", "f12": "language.definition"}}
4
+ ]
5
+ }
data/docs/debugging.md ADDED
@@ -0,0 +1,143 @@
1
+ # Debug configurations
2
+
3
+ Canopus reads project launch configurations from `.canopus/launch.jsonc`. The
4
+ file is JSON with comments and trailing commas, parsed by Kochab:
5
+
6
+ ```jsonc
7
+ {
8
+ "configurations": [{
9
+ "name": "Run tests",
10
+ "type": "ruby",
11
+ "request": "launch",
12
+ "program": "${workspaceFolder}/bin/rake",
13
+ "args": ["test"],
14
+ "cwd": "${workspaceFolder}"
15
+ }]
16
+ }
17
+ ```
18
+
19
+ The supported substitutions are `${workspaceFolder}`, `${file}`,
20
+ `${lineNumber}`, `${selectedText}`, and `${env:NAME}`. Substitution applies to
21
+ all string values, including `program`, `args`, and `cwd`. A requested value
22
+ must be available; unknown variables and missing environment entries are
23
+ reported as configuration errors. Text inserted from a selection or environment
24
+ entry is literal, so `${...}` inside that text is not expanded again. File,
25
+ program, and working-directory paths must remain inside the project root.
26
+ Adapter commands are accepted only as argument arrays, not as shell command
27
+ strings.
28
+
29
+ Adapters are selected by the configuration's `type` and configured as a global
30
+ setting. `languages.*.debug_adapters` is rejected; language selection happens
31
+ through each launch configuration's `type`:
32
+
33
+ ```jsonc
34
+ {
35
+ "debug_adapters": {
36
+ "ruby": {
37
+ "command": ["rdbg", "--open", "--stop-at-load"],
38
+ "transport": "tcp"
39
+ }
40
+ }
41
+ }
42
+ ```
43
+
44
+ `transport` is `stdio` or `tcp`. Adapter commands use the same substitutions.
45
+ At most 64 adapter types and 32 command arguments per adapter are accepted.
46
+ Adapter type names are at most 128 bytes, each command argument is at most
47
+ 4,096 bytes and contains no control characters, and the complete adapter
48
+ setting is at most 1 MiB. These byte limits are enforced at runtime in addition
49
+ to the JSON schema's character limits.
50
+
51
+ Canopus rejects oversized, deeply nested, or incorrectly typed configuration
52
+ data before it can start an adapter. Expansion is limited to 1 MiB across one
53
+ resolved launch or adapter, and captured environment data is limited to 1 MiB.
54
+ If a project has a `Rakefile` but no launch configuration, the configuration
55
+ loader offers a `Run tests` launch using `bin/rake test`. Debug sessions and
56
+ their user interface are implemented separately from configuration loading.
57
+
58
+ ## Breakpoints
59
+
60
+ The breakpoint registry stores project-relative paths, 1-based line numbers,
61
+ optional conditions, hit conditions, log messages, and enabled state in
62
+ `.canopus/breakpoints.json`. Version 1 files are loaded with breakpoints enabled
63
+ and are written as version 2 on the next change. The versioned file is
64
+ limited to 1 MiB and 10,000 entries. Paths must stay within the canonical
65
+ workspace root; paths through outside symlinks are rejected. Breakpoints for
66
+ files that are not currently open remain in the registry.
67
+
68
+ Attached buffers update breakpoint lines after committed edits. Inserting ten
69
+ lines before a breakpoint moves it down ten lines, deleting its complete source
70
+ line removes it, and undo or redo restores the corresponding registry state.
71
+ Tracked edits are coalesced and saved by one background writer; detach and
72
+ close flush pending changes and surface write failures. The registry's `error`
73
+ accessor exposes the latest background failure, and `flush` re-raises it.
74
+ Changes are written through a sibling temporary file followed by `fsync` and
75
+ an atomic rename.
76
+ This provides normal same-user workspace consistency; concurrent malicious
77
+ workspace mutation is outside its scope. Buffer attachment is an internal
78
+ lifecycle operation. Left-click the gutter to add or remove a breakpoint.
79
+ Right-click it to add or edit a condition, hit count, or log message, or to
80
+ enable, disable, and remove the breakpoint. Disabled breakpoints use the muted
81
+ gutter color; enabled breakpoints use the error color.
82
+
83
+ ## Sessions
84
+
85
+ Run `debug.start` from the command palette. If the project has more than one
86
+ launch configuration, Canopus opens a searchable configuration list. The
87
+ adapter is initialized before enabled breakpoints are sent; Canopus then
88
+ completes configuration and waits for the launch or attach response. Only one
89
+ session is active per workspace. `debug.stop` closes the protocol session and
90
+ its adapter process.
91
+
92
+ The Ruby TCP adapter example above supports launch configurations and is started
93
+ without a shell. Canopus assigns
94
+ it a loopback port, passes the resolved `program` and `args` to rdbg, and then
95
+ connects with Megrez. TCP attach is not supported; stdio adapters may implement
96
+ attach through their launch configuration. On a stop event, the first stack frame is opened only if
97
+ its canonical source path remains inside the workspace, and its line is
98
+ highlighted. Continued and terminated events clear that highlight. Adapter
99
+ startup and protocol failures are delivered through editor notifications.
100
+
101
+ ## Debug panel
102
+
103
+ The `debug` panel opens automatically when execution stops and is also
104
+ available through `panel.debug`. It shows the call stack, variables, watches,
105
+ and the persistent breakpoint list. Selecting a stack frame changes the
106
+ variable context and opens its source only when the canonical file remains
107
+ inside the workspace. Breakpoint rows use the same checked source-opening
108
+ path.
109
+
110
+ Variable children are requested only when their tree row is expanded. The
111
+ panel preserves expansion as scope and variable name paths (plus an ordinal
112
+ for duplicate sibling names); it never stores adapter `variablesReference`
113
+ values in tree state. On another stop or frame selection, Canopus resolves each
114
+ saved name path again from fresh scopes before requesting children. Pending
115
+ results from a continued, replaced, or closed session are discarded.
116
+
117
+ Use `debug.watch.add` and `debug.watch.remove` from the command palette to edit
118
+ the in-memory watch list. Watches are evaluated with DAP context `watch` for
119
+ the selected frame on every stop and whenever the selected stack frame
120
+ changes. Watch expressions are limited to 4 KiB and 100 entries. Panel
121
+ visibility and size use the existing `dock.panels.debug` setting and session
122
+ state; watch expressions themselves are not written to project files.
123
+
124
+ ## Debug console and hover
125
+
126
+ `debug.console.evaluate` opens the existing input palette and evaluates the
127
+ entered expression with DAP context `repl` in the selected stack frame.
128
+ `panel.debug_console` toggles the bottom panel. Adapter output events retain
129
+ their line breaks and arrival order and show bounded category and source-line
130
+ metadata when it is valid. Source metadata is display-only and never opens an
131
+ adapter-provided path. Finished sessions retain their history until the next
132
+ session starts.
133
+
134
+ While execution is stopped, hovering an ASCII local, instance, class, or
135
+ global variable evaluates it with context `hover`. Bare names are checked
136
+ against the selected frame's bounded DAP scopes first. Calls, members,
137
+ constants, string and comment tokens, names within a string interpolation
138
+ found in up to 256 cached rows or 4,096 tokens, indexing, operators, and names
139
+ longer than 256 bytes are not evaluated. Hover and REPL requests are cancelled
140
+ on continue, frame change, session replacement, termination, and close; late
141
+ results are discarded.
142
+ Console history is limited to 1,000 entries, individual adapter strings and
143
+ expressions to 4 KiB, and concurrent REPL requests to 16.
data/docs/distribution.md CHANGED
@@ -1,27 +1,58 @@
1
1
  # Packaging
2
2
 
3
3
  `tools/package.rb` creates a source-based macOS app, Linux launcher and desktop
4
- file, or Windows launcher and shortcut installer. The package includes Canopus
5
- sources and assets, but not Ruby, native binaries, or gem dependencies.
4
+ file, or Windows launcher and shortcut installer. By default the package
5
+ includes Canopus sources and assets but not Ruby or gem dependencies; a staged
6
+ relocatable Ruby can be included explicitly with `--ruby-root`.
6
7
 
7
8
  ```sh
8
9
  ruby tools/package.rb --platform mac --output /tmp/Canopus.app --ruby /path/to/ruby
9
10
  ruby tools/package.rb --platform linux --output /tmp/canopus-linux --ruby /usr/bin/ruby
10
11
  ruby tools/package.rb --platform windows --output /tmp/canopus-windows --ruby ruby.exe
12
+ ruby tools/package.rb --platform mac --output /tmp/Canopus-bundled.app --ruby-root /path/to/staged-ruby
11
13
  ruby tools/package_test.rb
12
14
  ```
13
15
 
14
- The output path must not exist and must be outside the source tree. Build for the
15
- Ruby executable available on the destination machine. Canopus requires CRuby
16
- 3.1 or newer and its runtime gems installed for that Ruby. The installed package
17
- does not require Bundler.
16
+ Packages can be signed after building with an RSA release key. The signer only
17
+ stores a public key fingerprint and a signature over `manifest.json`; the
18
+ private key stays outside the package and CI logs.
19
+
20
+ ```sh
21
+ ruby tools/sign_package.rb --package /tmp/canopus-linux --private-key release.pem
22
+ ruby tools/sign_package.rb --package /tmp/canopus-linux --verify --public-key release.pub
23
+ ```
24
+
25
+ Verification also checks every SHA-256 entry in the manifest. This is a
26
+ credential-free integrity check; macOS notarization and Windows Authenticode
27
+ still require platform credentials and are release-environment work.
28
+
29
+ The generated macOS app declares common text, Markdown, Ruby, JSON, and XML
30
+ document types. Linux packages include `Install.sh` and `Uninstall.sh` for a
31
+ per-user install under `~/.local/share/canopus` and register the desktop MIME
32
+ associations. Windows packages include `Install.ps1` and `Uninstall.ps1`,
33
+ which register a per-user `Canopus.Document` ProgID and OpenWith entries.
34
+
35
+ Updates are explicit: `tools/update.rb` accepts a signed JSON feed containing
36
+ the channel, platform, semver, HTTPS archive URL, size, SHA-256, and RSA
37
+ signature. It downloads into a same-filesystem staging directory, rejects
38
+ unsafe tar entries, verifies the archive hash, and atomically swaps the install
39
+ directory with rollback if activation fails.
40
+
41
+ The output path must not exist and must be outside the source tree. Without
42
+ `--ruby-root`, build for the Ruby executable available on the destination
43
+ machine. With `--ruby-root`, the directory must be a relocatable CRuby staging
44
+ root containing `bin/ruby` (or `bin/ruby.exe`); it is copied into the package's
45
+ `runtime/` directory and launchers use that relative executable. The staged root
46
+ must include Canopus's production gems and must not contain symlinks. The
47
+ installed package does not require Bundler.
18
48
 
19
49
  macOS's system Ruby is generally too old. Linux requires its Wayland/EGL/OpenGL
20
50
  or X11/GLX libraries, XKB, and `zenity` for file dialogs. Move a Linux package to
21
51
  its final location before installing its generated desktop file. On Windows, run
22
52
  `Create-Shortcut.ps1` from the package to create a shortcut.
23
53
 
24
- These packages are unsigned and do not bundle security updates for Ruby. Signing,
25
- notarization, automatic updates, and a relocatable Ruby runtime require separate
26
- platform-specific release work. See [ADR 005](adr/005-windows-runtime.md) for the
54
+ Every package includes `manifest.json` with SHA-256 entries for its files. These
55
+ packages are unsigned and do not bundle security updates for Ruby. Signing,
56
+ notarization, and automatic updates require separate platform-specific release
57
+ work. See [ADR 005](adr/005-windows-runtime.md) for the
27
58
  Windows/YJIT runtime decision.