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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +55 -0
- data/README.md +191 -19
- data/assets/keymaps/emacs.jsonc +5 -0
- data/assets/keymaps/jetbrains.jsonc +5 -0
- data/assets/keymaps/sublime.jsonc +5 -0
- data/assets/keymaps/vscode.jsonc +5 -0
- data/docs/debugging.md +143 -0
- data/docs/distribution.md +40 -9
- data/docs/lsp.md +131 -0
- data/docs/performance.md +18 -0
- data/docs/providers.md +36 -0
- data/docs/release-log.md +12 -0
- data/docs/tasks.md +64 -0
- data/docs/testing.md +49 -0
- data/docs/vim.md +3 -0
- data/exe/canopus +4 -1
- data/lib/canopus/buffer.rb +291 -50
- data/lib/canopus/cli.rb +5 -2
- data/lib/canopus/command.rb +13 -4
- data/lib/canopus/controller.rb +183 -40
- data/lib/canopus/debug/breakpoints.rb +550 -0
- data/lib/canopus/debug/configuration.rb +291 -0
- data/lib/canopus/debug/console.rb +243 -0
- data/lib/canopus/debug/panel.rb +487 -0
- data/lib/canopus/debug/session.rb +354 -0
- data/lib/canopus/decoration.rb +4 -2
- data/lib/canopus/denebola_compat.rb +27 -0
- data/lib/canopus/diagnostics.rb +173 -0
- data/lib/canopus/display_map/overlay_map.rb +6 -2
- data/lib/canopus/editor/snippet_expandable.rb +3 -2
- data/lib/canopus/editor.rb +122 -31
- data/lib/canopus/git/state.rb +100 -0
- data/lib/canopus/language/background_analysis.rb +93 -14
- data/lib/canopus/language/document.rb +70 -34
- data/lib/canopus/language/symbol.rb +1 -0
- data/lib/canopus/language/syntax_worker.rb +61 -9
- data/lib/canopus/language.rb +3 -0
- data/lib/canopus/minimap.rb +201 -0
- data/lib/canopus/patch.rb +3 -1
- data/lib/canopus/plugins/api.rb +4 -2
- data/lib/canopus/plugins/isolated_runtime.rb +64 -7
- data/lib/canopus/plugins/registry.rb +114 -3
- data/lib/canopus/plugins.rb +8 -7
- data/lib/canopus/project.rb +15 -6
- data/lib/canopus/provider.rb +192 -0
- data/lib/canopus/regexp_compat.rb +36 -4
- data/lib/canopus/selection.rb +12 -0
- data/lib/canopus/settings/schema.rb +201 -0
- data/lib/canopus/settings.rb +328 -49
- data/lib/canopus/task/configuration.rb +356 -0
- data/lib/canopus/task/problem_matcher.rb +264 -0
- data/lib/canopus/task/runner.rb +314 -0
- data/lib/canopus/test_runner/bounded_ignore.rb +144 -0
- data/lib/canopus/test_runner/discovery.rb +97 -0
- data/lib/canopus/test_runner/execution.rb +194 -0
- data/lib/canopus/test_runner/minitest.rb +116 -0
- data/lib/canopus/test_runner/rspec.rb +103 -0
- data/lib/canopus/test_runner/safe_walker.rb +37 -0
- data/lib/canopus/test_runner.rb +54 -0
- data/lib/canopus/theme/import.rb +131 -0
- data/lib/canopus/theme.rb +28 -4
- data/lib/canopus/version.rb +1 -1
- data/lib/canopus/vim/motionable.rb +1 -1
- data/lib/canopus/vim.rb +10 -16
- data/lib/canopus/workspace/auto_savable.rb +83 -0
- data/lib/canopus/workspace/debug_aware.rb +600 -0
- data/lib/canopus/workspace/edit/plan.rb +2 -2
- data/lib/canopus/workspace/editor_configurable.rb +113 -0
- data/lib/canopus/workspace/file_change_aware.rb +11 -3
- data/lib/canopus/workspace/git_aware.rb +80 -34
- data/lib/canopus/workspace/git_blame.rb +175 -0
- data/lib/canopus/workspace/git_conflict_resolution.rb +410 -0
- data/lib/canopus/workspace/git_diff_view.rb +641 -0
- data/lib/canopus/workspace/git_history.rb +171 -0
- data/lib/canopus/workspace/git_remote.rb +267 -0
- data/lib/canopus/workspace/git_staging.rb +583 -0
- data/lib/canopus/workspace/hierarchy_aware.rb +477 -0
- data/lib/canopus/workspace/keymap_aware.rb +66 -0
- data/lib/canopus/workspace/language_aware.rb +3721 -135
- data/lib/canopus/workspace/language_server_configurable.rb +287 -71
- data/lib/canopus/workspace/persistent_undo.rb +169 -0
- data/lib/canopus/workspace/problems_aware.rb +131 -0
- data/lib/canopus/workspace/project_searchable.rb +88 -11
- data/lib/canopus/workspace/project_tree_editable.rb +3 -1
- data/lib/canopus/workspace/recoverable.rb +204 -0
- data/lib/canopus/workspace/session_persistable.rb +85 -13
- data/lib/canopus/workspace/settings_aware.rb +76 -2
- data/lib/canopus/workspace/task_aware.rb +194 -0
- data/lib/canopus/workspace/test_aware.rb +394 -0
- data/lib/canopus/workspace/trust.rb +73 -0
- data/lib/canopus/workspace/view/terminal_presentable.rb +298 -47
- data/lib/canopus/workspace/view.rb +399 -74
- data/lib/canopus/workspace.rb +688 -44
- data/lib/canopus.rb +20 -2
- data/sig/canopus.rbs +138 -31
- data/sig/controller.rbs +10 -3
- data/sig/debug.rbs +121 -0
- data/sig/decoration.rbs +12 -2
- data/sig/diagnostics.rbs +26 -0
- data/sig/minimap.rbs +20 -0
- data/sig/provider.rbs +29 -0
- data/sig/services.rbs +1 -16
- data/sig/task.rbs +92 -0
- data/sig/test_runner.rbs +109 -0
- data/sig/trust.rbs +17 -0
- data/sig/workspace_edits.rbs +2 -2
- data/sig/workspace_services.rbs +234 -2
- data/tools/check_dependencies.rb +21 -2
- data/tools/package.rb +172 -14
- data/tools/package_signature_test.rb +33 -0
- data/tools/package_test.rb +29 -0
- data/tools/sign_package.rb +123 -0
- data/tools/update.rb +189 -0
- data/tools/update_test.rb +71 -0
- metadata +206 -31
- data/lib/canopus/lsp/client.rb +0 -307
- data/lib/canopus/lsp/error.rb +0 -7
- data/lib/canopus/lsp/future/subscription.rb +0 -9
- data/lib/canopus/lsp/future.rb +0 -87
- data/lib/canopus/lsp/protocol.rb +0 -83
- data/lib/canopus/lsp/server_error.rb +0 -13
- data/lib/canopus/lsp/timeout.rb +0 -7
- data/lib/canopus/lsp/transport.rb +0 -123
- data/lib/canopus/lsp.rb +0 -19
- data/lib/canopus/project/search.rb +0 -164
- data/lib/canopus/project/search_worker/cancelled.rb +0 -3
- data/lib/canopus/project/search_worker/runner.rb +0 -9
- data/lib/canopus/project/search_worker.rb +0 -108
- data/lib/canopus/terminal/cell.rb +0 -7
- data/lib/canopus/terminal/grid.rb +0 -321
- data/lib/canopus/terminal/pty.rb +0 -178
- data/lib/canopus/terminal/scrollback.rb +0 -38
- data/lib/canopus/terminal/vt.rb +0 -398
- data/lib/canopus/terminal.rb +0 -13
- data/sig/lsp.rbs +0 -99
- data/sig/terminal.rbs +0 -130
data/lib/canopus/controller.rb
CHANGED
|
@@ -8,10 +8,19 @@ module Canopus
|
|
|
8
8
|
def initialize(workspace, window)
|
|
9
9
|
@workspace, @window, @view = workspace, window, Workspace::View.new(workspace)
|
|
10
10
|
workspace.window = window
|
|
11
|
-
workspace.register_action("terminal.copy", condition: "Terminal") { terminal_copy }
|
|
12
|
-
workspace.register_action("terminal.paste", condition: "Terminal") do
|
|
11
|
+
workspace.register_action("terminal.copy", condition: "Terminal || TaskOutput") { terminal_copy }
|
|
12
|
+
workspace.register_action("terminal.paste", condition: "Terminal || TaskOutput") do
|
|
13
13
|
terminal_paste(@window.respond_to?(:clipboard) ? @window.clipboard.to_s : @clipboard)
|
|
14
14
|
end
|
|
15
|
+
workspace.register_action("terminal.command.previous", description: "Go to Previous Terminal Command", condition: "Terminal") do
|
|
16
|
+
@view.terminal_command(:previous)
|
|
17
|
+
end
|
|
18
|
+
workspace.register_action("terminal.command.next", description: "Go to Next Terminal Command", condition: "Terminal") do
|
|
19
|
+
@view.terminal_command(:next)
|
|
20
|
+
end
|
|
21
|
+
workspace.register_action("terminal.command.toggle_fold", description: "Toggle Terminal Command Output", condition: "Terminal") do
|
|
22
|
+
@view.terminal_toggle_command
|
|
23
|
+
end
|
|
15
24
|
reload_keymap
|
|
16
25
|
window.draw { workspace.drain; @view }
|
|
17
26
|
window.on_input { |event| input(event) }
|
|
@@ -19,20 +28,30 @@ module Canopus
|
|
|
19
28
|
window.on_appearance { |_| workspace.apply_settings if workspace.settings["theme"] == "auto" } if window.respond_to?(:on_appearance)
|
|
20
29
|
window.on_tick do
|
|
21
30
|
workspace.drain_terminals
|
|
31
|
+
workspace.drain_task_outputs
|
|
22
32
|
workspace.drain
|
|
23
33
|
workspace.poll_changes
|
|
24
34
|
workspace.poll_settings
|
|
35
|
+
workspace.poll_auto_save
|
|
36
|
+
workspace.poll_recovery
|
|
25
37
|
reload_keymap
|
|
26
38
|
workspace.poll_git_changes
|
|
27
39
|
poll_display_maps
|
|
28
40
|
poll_language_documents
|
|
29
41
|
poll_scroll
|
|
30
42
|
window.request_frame if @view.tick
|
|
43
|
+
window.close if wait_complete?
|
|
31
44
|
end
|
|
32
|
-
@clipboard, @terminal_focus = "",
|
|
45
|
+
@clipboard, @terminal_focus = "", nil
|
|
33
46
|
workspace.new_buffer unless workspace.editor
|
|
34
47
|
end
|
|
48
|
+
def wait_for(paths)
|
|
49
|
+
@wait_paths = paths.map { |path| @workspace.canonical_path(path) }.uniq
|
|
50
|
+
end
|
|
35
51
|
def input(event)
|
|
52
|
+
return if focused_ui_widget? &&
|
|
53
|
+
[Zaniah::Input::KeyDown, Zaniah::Input::TextInput, Zaniah::Input::Composition].any? { |type| event.is_a?(type) }
|
|
54
|
+
|
|
36
55
|
case event
|
|
37
56
|
when Zaniah::Input::KeyUp, Zaniah::Input::MouseDown, Zaniah::Input::FileDrop
|
|
38
57
|
@suppress_key_text = false
|
|
@@ -55,7 +74,7 @@ module Canopus
|
|
|
55
74
|
when Zaniah::Input::TextInput
|
|
56
75
|
input_text(event.text)
|
|
57
76
|
when Zaniah::Input::Composition
|
|
58
|
-
if
|
|
77
|
+
if focused_terminal
|
|
59
78
|
@workspace.terminal_composition = event
|
|
60
79
|
else
|
|
61
80
|
@workspace.new_buffer unless @workspace.editor
|
|
@@ -67,18 +86,41 @@ module Canopus
|
|
|
67
86
|
mouse_down(event)
|
|
68
87
|
when Zaniah::Input::MouseMove
|
|
69
88
|
mouse_move(event) if @drag
|
|
89
|
+
if @minimap_drag
|
|
90
|
+
pane, editor = @minimap_drag
|
|
91
|
+
@view.minimap_scroll(editor, event.position) if @workspace.panes.include?(pane) && pane.editors.include?(editor)
|
|
92
|
+
end
|
|
70
93
|
resize_drag(event.position) if @resize_drag
|
|
71
94
|
scroll_drag(event.position) if @scroll_drag
|
|
72
95
|
if @terminal_drag
|
|
73
96
|
@terminal_drag == :selection ? @view.terminal_select(event.position, extend: true) : terminal_mouse(event, :move)
|
|
74
|
-
elsif !(@drag || @resize_drag || @scroll_drag || @drag_file || @drag_tab)
|
|
75
|
-
|
|
76
|
-
|
|
97
|
+
elsif !(@drag || @resize_drag || @scroll_drag || @drag_file || @drag_tab)
|
|
98
|
+
hit = @view.hit(event.position)
|
|
99
|
+
target = hit&.first
|
|
100
|
+
terminal = if target == :terminal
|
|
101
|
+
hit[1] if @workspace.terminal_visible
|
|
102
|
+
elsif target == :terminal_command
|
|
103
|
+
hit[2] if @workspace.terminal_visible
|
|
104
|
+
elsif target == :task_output
|
|
105
|
+
@workspace.task_terminal if @workspace.task_output_visible
|
|
106
|
+
end
|
|
107
|
+
@view.focus_terminal(terminal) if terminal
|
|
108
|
+
terminal_mouse(event, :move, terminal: terminal) if terminal&.vt&.modes&.[](1003)
|
|
109
|
+
end
|
|
110
|
+
unless @drag || @resize_drag || @scroll_drag || @minimap_drag || @drag_file || @drag_tab || @terminal_drag
|
|
111
|
+
target = @view.hit(event.position)
|
|
112
|
+
if target&.first == :editor
|
|
113
|
+
current = target.last
|
|
114
|
+
@workspace.debug_hover(current, @view.offset_at(current, event.position))
|
|
115
|
+
else
|
|
116
|
+
@workspace.debug_hover(nil, nil)
|
|
117
|
+
end
|
|
77
118
|
end
|
|
78
119
|
when Zaniah::Input::MouseUp
|
|
79
|
-
@workspace.flush_terminal_resize if @resize_drag
|
|
120
|
+
@workspace.flush_terminal_resize if @resize_drag
|
|
80
121
|
@resize_drag = nil
|
|
81
122
|
@scroll_drag = nil
|
|
123
|
+
@minimap_drag = nil
|
|
82
124
|
if @drag_file
|
|
83
125
|
path, origin = @drag_file
|
|
84
126
|
target = @view.hit(event.position)
|
|
@@ -122,12 +164,13 @@ module Canopus
|
|
|
122
164
|
end
|
|
123
165
|
def input_text(text)
|
|
124
166
|
if @workspace.palette
|
|
125
|
-
return if [:workspace_edit, :confirm_close, :confirm_tab_close, :confirm_terminal_close, :confirm_terminal_paste, :trash_file
|
|
167
|
+
return if [:workspace_edit, :confirm_close, :confirm_tab_close, :confirm_terminal_close, :confirm_terminal_paste, :trash_file, :recovery,
|
|
168
|
+
:breakpoint_actions].include?(@workspace.palette[:kind])
|
|
126
169
|
@workspace.palette[:query] << text
|
|
127
170
|
@workspace.update_palette
|
|
128
|
-
elsif
|
|
171
|
+
elsif (terminal = focused_terminal)
|
|
129
172
|
@workspace.terminal_composition = nil
|
|
130
|
-
|
|
173
|
+
terminal.write(text)
|
|
131
174
|
else
|
|
132
175
|
@workspace.new_buffer unless @workspace.editor
|
|
133
176
|
if @workspace.settings["vim_mode"]
|
|
@@ -144,15 +187,16 @@ module Canopus
|
|
|
144
187
|
stroke = Zaniah::Input::Keystroke.normalize(stroke)
|
|
145
188
|
return palette_key(stroke) if @workspace.palette
|
|
146
189
|
return if @composing && (stroke.split("-") & %w[ctrl cmd]).empty?
|
|
147
|
-
if stroke == "cmd-q" || stroke == "ctrl-q" && !
|
|
190
|
+
if stroke == "cmd-q" || stroke == "ctrl-q" && !focused_terminal
|
|
148
191
|
return @window.close
|
|
149
192
|
end
|
|
150
|
-
if
|
|
151
|
-
if stroke == "enter" &&
|
|
193
|
+
if (terminal = focused_terminal)
|
|
194
|
+
if terminal_focused? && stroke == "enter" && terminal.respond_to?(:alive?) && !terminal.alive?
|
|
152
195
|
return @workspace.restart_terminal
|
|
153
196
|
end
|
|
154
197
|
mode = @workspace.settings["vim_mode"] && @workspace.editor ? @workspace.vim.mode.to_s : false
|
|
155
|
-
context = @workspace.command_context(terminal:
|
|
198
|
+
context = @workspace.command_context(terminal: terminal_focused?,
|
|
199
|
+
task_output: @terminal_focus == :task_output).merge("Editor" => false, "vim_mode" => mode)
|
|
156
200
|
action = @keymap.dispatch(stroke, context: context)
|
|
157
201
|
if action && action != :pending
|
|
158
202
|
@drag_terminal_tab = nil if action == "terminal.close"
|
|
@@ -166,7 +210,7 @@ module Canopus
|
|
|
166
210
|
name = parts.pop
|
|
167
211
|
return if (name.length == 1 || name == "space") && (parts & %w[ctrl alt cmd]).empty?
|
|
168
212
|
name = {"esc" => "escape", "pageup" => "page_up", "pagedown" => "page_down", "space" => " "}.fetch(name, name)
|
|
169
|
-
return
|
|
213
|
+
return terminal.key(name, control: parts.include?("ctrl"), alt: parts.include?("alt"), shift: parts.include?("shift"))
|
|
170
214
|
end
|
|
171
215
|
return @workspace.settings_completions if stroke == "ctrl-space" && @workspace.editor && @workspace.settings_document?(@workspace.editor.buffer)
|
|
172
216
|
mode = @workspace.settings["vim_mode"] && @workspace.editor ? @workspace.vim.mode.to_s : false
|
|
@@ -225,20 +269,37 @@ module Canopus
|
|
|
225
269
|
candidates = visible + (inactive.empty? ? [] : [inactive[@language_poll_index % inactive.length]])
|
|
226
270
|
candidates.each do |editor|
|
|
227
271
|
document = editor.language_document
|
|
272
|
+
sticky = false
|
|
228
273
|
if visible.include?(editor)
|
|
274
|
+
@workspace.request_document_highlights(editor)
|
|
275
|
+
@workspace.request_document_links(editor)
|
|
229
276
|
map = editor.display_map
|
|
230
277
|
first = editor.scroll_y.floor.clamp(0, map.row_count - 1)
|
|
231
278
|
last = [first + editor.viewport_rows, first + 255, map.row_count - 1].min
|
|
279
|
+
sticky = @workspace.sticky_scroll_enabled?(editor)
|
|
280
|
+
symbols = sticky || @workspace.breadcrumbs_enabled?(editor)
|
|
232
281
|
cached = @language_viewports[editor]
|
|
233
282
|
# The persistent display tree changes on edits, folds, blocks and
|
|
234
283
|
# completed wrap batches. Idle polls need not walk every visible row.
|
|
235
284
|
unless cached && cached[0].equal?(document) && cached[1].equal?(map.tree) &&
|
|
236
|
-
cached[2] == editor.buffer.version && cached[3] == first && cached[4] == last
|
|
237
|
-
|
|
238
|
-
|
|
285
|
+
cached[2] == editor.buffer.version && cached[3] == first && cached[4] == last && cached[7] == symbols
|
|
286
|
+
rows = (first..last).map { |row| map.source_row(row) }.uniq.sort
|
|
287
|
+
document.request(rows: rows, syntax: symbols)
|
|
288
|
+
inlay_ranges = @workspace.visible_inlay_hint_ranges(editor, first...(last + 1))
|
|
289
|
+
lens_ranges = @workspace.visible_code_lens_ranges(editor, first...(last + 1))
|
|
290
|
+
cached = @language_viewports[editor] = [document, map.tree, editor.buffer.version, first, last, inlay_ranges, lens_ranges, symbols]
|
|
291
|
+
end
|
|
292
|
+
cached[5].each do |rows|
|
|
293
|
+
@workspace.request_inlay_hints(editor, rows, start: true)
|
|
239
294
|
end
|
|
295
|
+
cached[6].each do |rows|
|
|
296
|
+
@workspace.request_code_lenses(editor, rows, start: true)
|
|
297
|
+
end
|
|
298
|
+
@workspace.request_sticky_symbols(editor) if symbols
|
|
240
299
|
end
|
|
241
300
|
changed = document.poll
|
|
301
|
+
@workspace.refresh_sticky_fallback(editor, document) if visible.include?(editor) && symbols && document.syntax_ready?
|
|
302
|
+
@workspace.invalidate_brackets(editor.buffer) if changed
|
|
242
303
|
@workspace.language_ready(editor, document)
|
|
243
304
|
@window.request_frame if changed
|
|
244
305
|
rescue StandardError => error
|
|
@@ -300,6 +361,17 @@ module Canopus
|
|
|
300
361
|
end
|
|
301
362
|
|
|
302
363
|
private
|
|
364
|
+
def wait_complete?
|
|
365
|
+
return false unless @wait_paths
|
|
366
|
+
return false if @wait_paths.any? do |path|
|
|
367
|
+
@workspace.panes.any? { |pane| pane.editors.any? { |editor| editor.buffer.path == path } }
|
|
368
|
+
end
|
|
369
|
+
@wait_paths = nil
|
|
370
|
+
true
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
def focused_ui_widget? = !@window.dispatcher.focused.nil?
|
|
374
|
+
|
|
303
375
|
def reload_keymap
|
|
304
376
|
language = @workspace.editor&.language_document&.definition&.name
|
|
305
377
|
groups = @workspace.settings["languages"].dig(language, "keymap") || @workspace.settings["keymap"]
|
|
@@ -324,7 +396,7 @@ module Canopus
|
|
|
324
396
|
end
|
|
325
397
|
def palette_input(event)
|
|
326
398
|
return false unless @workspace.palette
|
|
327
|
-
@drag = @resize_drag = @scroll_drag = @terminal_drag = @drag_file = @drag_tab = @drag_terminal_tab = nil
|
|
399
|
+
@drag = @resize_drag = @scroll_drag = @minimap_drag = @terminal_drag = @drag_file = @drag_tab = @drag_terminal_tab = nil
|
|
328
400
|
case event
|
|
329
401
|
when Zaniah::Input::KeyDown then key(event.keystroke)
|
|
330
402
|
when Zaniah::Input::TextInput then input_text(event.text)
|
|
@@ -337,7 +409,7 @@ module Canopus
|
|
|
337
409
|
editor = @workspace.editor
|
|
338
410
|
if operation == "v"
|
|
339
411
|
value = @window.respond_to?(:clipboard) ? @window.clipboard : @clipboard
|
|
340
|
-
editor.insert_text(value.to_s, auto_indent: false)
|
|
412
|
+
editor.insert_text(value.to_s, auto_indent: false, pair: false)
|
|
341
413
|
else
|
|
342
414
|
value = editor.selections.map { |selection| editor.buffer.rope.byteslice(selection.range).to_s }.join("\n")
|
|
343
415
|
@clipboard = value
|
|
@@ -370,7 +442,8 @@ module Canopus
|
|
|
370
442
|
palette[:details_scroll] = (palette.fetch(:details_scroll, 0) + (stroke == "pageup" ? -step : step)).clamp(0, maximum)
|
|
371
443
|
end
|
|
372
444
|
when "backspace"
|
|
373
|
-
return if [:workspace_edit, :confirm_close, :confirm_tab_close, :confirm_terminal_close, :confirm_terminal_paste, :trash_file
|
|
445
|
+
return if [:workspace_edit, :confirm_close, :confirm_tab_close, :confirm_terminal_close, :confirm_terminal_paste, :trash_file, :recovery,
|
|
446
|
+
:breakpoint_actions].include?(palette[:kind])
|
|
374
447
|
palette[:query] = palette[:query].grapheme_clusters[0...-1].join
|
|
375
448
|
@workspace.update_palette
|
|
376
449
|
when "enter"
|
|
@@ -391,6 +464,8 @@ module Canopus
|
|
|
391
464
|
elsif result["failureReason"] != "User cancelled"
|
|
392
465
|
@workspace.message = result["failureReason"].to_s
|
|
393
466
|
end
|
|
467
|
+
elsif palette[:kind] == :recovery
|
|
468
|
+
@workspace.resolve_recovery(palette[:index].zero? ? :restore : :discard)
|
|
394
469
|
elsif palette[:kind] == :confirm_close
|
|
395
470
|
case palette[:index]
|
|
396
471
|
when 0
|
|
@@ -410,11 +485,15 @@ module Canopus
|
|
|
410
485
|
@workspace.close_terminal(index) if palette[:index].zero? && index
|
|
411
486
|
elsif palette[:kind] == :confirm_terminal_paste
|
|
412
487
|
value = palette[:text]
|
|
488
|
+
terminal = palette[:terminal]
|
|
413
489
|
@workspace.palette = nil
|
|
414
|
-
|
|
490
|
+
terminal&.paste(value) if palette[:index].zero?
|
|
415
491
|
elsif palette[:kind] == :terminal_rename
|
|
416
492
|
@workspace.rename_terminal(palette[:query])
|
|
417
493
|
@workspace.palette = nil
|
|
494
|
+
elsif palette[:kind] == :terminal_commands
|
|
495
|
+
command = @workspace.palette_accept
|
|
496
|
+
@workspace.message = "Command output is no longer in scrollback" if command && !@view.terminal_command_jump(command)
|
|
418
497
|
else
|
|
419
498
|
@workspace.palette_accept
|
|
420
499
|
end
|
|
@@ -423,6 +502,7 @@ module Canopus
|
|
|
423
502
|
def mouse_down(event)
|
|
424
503
|
action = @view.hit(event.position)
|
|
425
504
|
return unless action
|
|
505
|
+
@window.dispatcher.focus(nil)
|
|
426
506
|
kind, *args = action
|
|
427
507
|
return if @workspace.palette && (kind != :palette || event.button != :left)
|
|
428
508
|
if [:file, :directory].include?(kind)
|
|
@@ -434,16 +514,34 @@ module Canopus
|
|
|
434
514
|
return
|
|
435
515
|
end
|
|
436
516
|
end
|
|
437
|
-
@terminal_focus = [:terminal, :terminal_tab, :terminal_close].include?(kind)
|
|
517
|
+
@terminal_focus = if [:terminal, :terminal_command, :terminal_tab, :terminal_close].include?(kind)
|
|
518
|
+
:terminal
|
|
519
|
+
elsif [:task_output, :task_output_tab, :task_output_close].include?(kind)
|
|
520
|
+
:task_output
|
|
521
|
+
end
|
|
522
|
+
if kind == :terminal || kind == :terminal_command
|
|
523
|
+
current = kind == :terminal ? args.first : args[1]
|
|
524
|
+
if current && (index = @workspace.terminals.index(current))
|
|
525
|
+
@workspace.activate_terminal(index)
|
|
526
|
+
@view.focus_terminal(current)
|
|
527
|
+
end
|
|
528
|
+
elsif kind == :task_output && args.first
|
|
529
|
+
@view.focus_terminal(args.first)
|
|
530
|
+
end
|
|
438
531
|
case kind
|
|
439
|
-
when :decoration
|
|
440
|
-
|
|
532
|
+
when :decoration, :context_decoration
|
|
533
|
+
if event.button == :left
|
|
534
|
+
args[0].call(args[1], args[2])
|
|
535
|
+
elsif event.button == :right && args[0].respond_to?(:right_click)
|
|
536
|
+
args[0].right_click(args[1], args[2])
|
|
537
|
+
end
|
|
441
538
|
when :git_hunk then @workspace.toggle_git_hunk(args[0], row: args[1]) if event.button == :left
|
|
442
539
|
when :hover_link
|
|
443
540
|
return unless event.button == :left
|
|
444
541
|
uri = URI.parse(args.first)
|
|
445
542
|
@window.open_url(uri.to_s) if %w[http https].include?(uri.scheme) && uri.host && @window.respond_to?(:open_url)
|
|
446
543
|
when :dismiss_notification then @workspace.dismiss_notification(args.first)
|
|
544
|
+
when :buffer_format then @workspace.show_encoding_actions(args.first) if event.button == :left
|
|
447
545
|
when :pane then @workspace.focus(args.first)
|
|
448
546
|
when :split_resize, :dock_resize then @resize_drag = action
|
|
449
547
|
when :scrollbar
|
|
@@ -454,9 +552,15 @@ module Canopus
|
|
|
454
552
|
grab = coordinate.between?(start, start + length) ? coordinate - start : length / 2.0
|
|
455
553
|
@scroll_drag = [editor, direction, track, thumb, maximum, grab]
|
|
456
554
|
scroll_drag(event.position)
|
|
457
|
-
when :
|
|
555
|
+
when :minimap
|
|
556
|
+
pane, editor = args
|
|
557
|
+
if event.button == :left && pane.active.equal?(editor) && @view.minimap_scroll(editor, event.position)
|
|
558
|
+
@workspace.focus(pane)
|
|
559
|
+
@minimap_drag = [pane, editor]
|
|
560
|
+
end
|
|
561
|
+
when :terminal, :task_output
|
|
458
562
|
return if event.button == :left && @view.terminal_open_link(event.position, modifiers: event.modifiers)
|
|
459
|
-
tracking = [1000, 1002, 1003].any? { |mode|
|
|
563
|
+
tracking = [1000, 1002, 1003].any? { |mode| focused_terminal.vt.modes[mode] }
|
|
460
564
|
if tracking && !event.modifiers.map(&:to_s).include?("shift")
|
|
461
565
|
@terminal_drag = event.button
|
|
462
566
|
terminal_mouse(event, :press)
|
|
@@ -464,11 +568,20 @@ module Canopus
|
|
|
464
568
|
@terminal_drag = :selection
|
|
465
569
|
@view.terminal_select(event.position)
|
|
466
570
|
end
|
|
571
|
+
when :terminal_command
|
|
572
|
+
@view.terminal_toggle_command(args.first) if event.button == :left
|
|
467
573
|
when :terminal_tab
|
|
468
574
|
@workspace.activate_terminal(args.first)
|
|
469
575
|
@drag_terminal_tab = [args.first, event.position] if event.button == :left
|
|
470
576
|
when :terminal_close
|
|
471
577
|
@workspace.request_terminal_close(args.first) if event.button == :left
|
|
578
|
+
when :task_output_tab
|
|
579
|
+
@workspace.activate_task_output(args.first)
|
|
580
|
+
when :task_output_close
|
|
581
|
+
output = @workspace.task_outputs[args.first]
|
|
582
|
+
if event.button == :left && output
|
|
583
|
+
@workspace.task_runner.running?(output) ? @workspace.stop_task(output) : @workspace.close_task_output(args.first)
|
|
584
|
+
end
|
|
472
585
|
when :file then @workspace.open(args.first)
|
|
473
586
|
when :directory then @workspace.project_tree.toggle(args.first)
|
|
474
587
|
when :tab
|
|
@@ -495,7 +608,19 @@ module Canopus
|
|
|
495
608
|
editor.move(:line_start)
|
|
496
609
|
editor.move(:down, extend: true)
|
|
497
610
|
end
|
|
498
|
-
|
|
611
|
+
rectangle = modifiers.include?("alt") && event.click_count == 1
|
|
612
|
+
@drag = [editor, rectangle ? anchor : editor.primary.anchor, event.position, rectangle]
|
|
613
|
+
when :sticky
|
|
614
|
+
pane, editor, offset, version, generation = args
|
|
615
|
+
if event.button == :left && editor.buffer.version == version &&
|
|
616
|
+
@workspace.document_symbol_generation(editor) == generation && pane.editors.include?(editor)
|
|
617
|
+
@workspace.activate_tab(pane, editor)
|
|
618
|
+
editor.select(offset)
|
|
619
|
+
editor.reveal_cursor
|
|
620
|
+
end
|
|
621
|
+
when :breadcrumb
|
|
622
|
+
pane, editor, item, context = args
|
|
623
|
+
@workspace.show_breadcrumb_menu(pane, editor, item, context) if event.button == :left
|
|
499
624
|
when :palette
|
|
500
625
|
@workspace.palette[:index] = args.first
|
|
501
626
|
palette_key("enter")
|
|
@@ -510,8 +635,13 @@ module Canopus
|
|
|
510
635
|
cancel_scroll
|
|
511
636
|
raise ArgumentError, "scroll deltas must be finite" unless [event.delta.x, event.delta.y].all? { |value| value.is_a?(Numeric) && value.finite? }
|
|
512
637
|
action = @view.hit(event.position)
|
|
513
|
-
if [:editor, :scrollbar].include?(action&.first)
|
|
514
|
-
editor = action.first
|
|
638
|
+
if [:editor, :scrollbar, :sticky, :breadcrumb, :minimap].include?(action&.first)
|
|
639
|
+
editor = case action.first
|
|
640
|
+
when :editor then action.last
|
|
641
|
+
when :sticky, :breadcrumb then action[2]
|
|
642
|
+
when :minimap then action[2]
|
|
643
|
+
else action[1]
|
|
644
|
+
end
|
|
515
645
|
editor.scroll(dx: event.delta.x, dy: event.delta.y / 20.0)
|
|
516
646
|
# Cocoa already supplies native momentum deltas (numeric NSEvent phase).
|
|
517
647
|
# Other backends get a bounded decaying tail; zero friction disables it.
|
|
@@ -520,10 +650,14 @@ module Canopus
|
|
|
520
650
|
end
|
|
521
651
|
elsif [:file, :directory].include?(action&.first)
|
|
522
652
|
@view.project_scroll(event.delta.y / 24.0)
|
|
523
|
-
elsif action&.first
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
653
|
+
elsif [:terminal, :terminal_command, :task_output].include?(action&.first)
|
|
654
|
+
terminal = action.first == :terminal_command ? action[2] : action[1]
|
|
655
|
+
terminal ||= action.first == :task_output ? @workspace.task_terminal : @workspace.terminal
|
|
656
|
+
@view.focus_terminal(terminal)
|
|
657
|
+
if [1000, 1002, 1003].any? { |mode| terminal.vt.modes[mode] }
|
|
658
|
+
if (position = @view.terminal_point(event.position))
|
|
659
|
+
terminal.mouse(button: event.delta.y.positive? ? :wheel_down : :wheel_up, column: position[0], row: position[1])
|
|
660
|
+
end
|
|
527
661
|
else
|
|
528
662
|
@view.terminal_scroll(event.delta.y / 20.0)
|
|
529
663
|
end
|
|
@@ -539,25 +673,34 @@ module Canopus
|
|
|
539
673
|
editor.scroll(dx: fraction.clamp(0, 1) * maximum - editor.scroll_x)
|
|
540
674
|
end
|
|
541
675
|
end
|
|
542
|
-
def terminal_mouse(event, action)
|
|
543
|
-
|
|
676
|
+
def terminal_mouse(event, action, terminal: focused_terminal)
|
|
677
|
+
return unless terminal
|
|
678
|
+
position = @view.terminal_point(event.position)
|
|
679
|
+
return unless position
|
|
680
|
+
column, row = position
|
|
544
681
|
modifiers = event.modifiers.map(&:to_s)
|
|
545
|
-
|
|
682
|
+
terminal.mouse(button: @terminal_drag, column: column, row: row, action: action,
|
|
546
683
|
shift: modifiers.include?("shift"), alt: modifiers.include?("alt"), control: modifiers.include?("ctrl"))
|
|
547
684
|
end
|
|
548
685
|
|
|
549
686
|
def terminal_paste(text)
|
|
550
687
|
if @workspace.settings["terminal"]["confirm_multiline_paste"] && text.match?(/[\r\n].*[\r\n]?/m)
|
|
551
688
|
@workspace.palette = {kind: :confirm_terminal_paste, query: "Paste multiple lines into the terminal?", index: 1,
|
|
552
|
-
matches: ["Paste", "Cancel"], text: text}
|
|
689
|
+
matches: ["Paste", "Cancel"], text: text, terminal: focused_terminal}
|
|
553
690
|
else
|
|
554
|
-
|
|
691
|
+
focused_terminal&.paste(text)
|
|
555
692
|
end
|
|
556
693
|
end
|
|
557
694
|
def terminal_copy
|
|
558
695
|
@clipboard = @view.terminal_selected_text
|
|
559
696
|
@window.clipboard = @clipboard if @window.respond_to?(:clipboard=)
|
|
560
697
|
end
|
|
698
|
+
def focused_terminal
|
|
699
|
+
return @workspace.terminal if terminal_focused? && @workspace.terminal_visible
|
|
700
|
+
return @workspace.task_terminal if @terminal_focus == :task_output && @workspace.task_output_visible
|
|
701
|
+
nil
|
|
702
|
+
end
|
|
703
|
+
def terminal_focused? = @terminal_focus == :terminal || @terminal_focus == true
|
|
561
704
|
def resize_drag(point)
|
|
562
705
|
kind, target, bounds = @resize_drag
|
|
563
706
|
if kind == :split_resize
|