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
|
@@ -18,6 +18,13 @@ module Canopus
|
|
|
18
18
|
raise Error, "Open a settings document first" unless settings_document?(editor.buffer)
|
|
19
19
|
self.palette = {kind: :settings_keys, query: +"", index: 0, matches: Settings::DEFAULTS.keys}
|
|
20
20
|
end
|
|
21
|
+
def settings_browse(changed_only: false)
|
|
22
|
+
fields = settings_gui_fields(changed_only: changed_only)
|
|
23
|
+
labels = fields.map { |field| "#{field[:path].join(".")} = #{JSON.generate(field[:value])}" }
|
|
24
|
+
self.palette = {kind: :settings_gui, query: +"", index: 0, matches: labels, fields: fields,
|
|
25
|
+
settings_file: settings_path, changed_only: changed_only}
|
|
26
|
+
end
|
|
27
|
+
def settings_gui(changed_only: false) = settings_browse(changed_only: changed_only)
|
|
21
28
|
def settings_document?(buffer)
|
|
22
29
|
buffer.path && (buffer.path == settings_path || @settings.paths.any? { |path| File.expand_path(path) == buffer.path })
|
|
23
30
|
end
|
|
@@ -31,6 +38,9 @@ module Canopus
|
|
|
31
38
|
system
|
|
32
39
|
end
|
|
33
40
|
def apply_settings
|
|
41
|
+
reset_auto_save
|
|
42
|
+
cancel_workspace_symbol_search
|
|
43
|
+
self.palette = nil if @palette&.dig(:kind) == :workspace_symbol_results
|
|
34
44
|
servers = language_server_settings_plan
|
|
35
45
|
clear_vim_states unless @settings["vim_mode"]
|
|
36
46
|
name = @settings["theme"]
|
|
@@ -53,6 +63,18 @@ module Canopus
|
|
|
53
63
|
end
|
|
54
64
|
@applied_font_family = @settings["font_family"]
|
|
55
65
|
@applied_icon_theme = @settings["icon_theme"]
|
|
66
|
+
invalidate_diagnostics
|
|
67
|
+
invalidate_document_highlights
|
|
68
|
+
invalidate_document_links
|
|
69
|
+
invalidate_folding_ranges
|
|
70
|
+
invalidate_selection_ranges
|
|
71
|
+
invalidate_hierarchy
|
|
72
|
+
invalidate_prepare_rename
|
|
73
|
+
invalidate_linked_editing_ranges
|
|
74
|
+
invalidate_inlay_hints
|
|
75
|
+
invalidate_code_lenses
|
|
76
|
+
invalidate_brackets
|
|
77
|
+
@decorations.invalidate(:blame)
|
|
56
78
|
reload_language_servers(servers)
|
|
57
79
|
@window&.request_frame
|
|
58
80
|
end
|
|
@@ -70,20 +92,72 @@ module Canopus
|
|
|
70
92
|
initial = !defined?(@settings_state)
|
|
71
93
|
@settings_state = state
|
|
72
94
|
return if initial && !force
|
|
95
|
+
previous_paths = @settings.paths
|
|
73
96
|
replacement = @settings.reload
|
|
74
97
|
old, @settings = @settings, replacement
|
|
98
|
+
publish_settings_diagnostics(previous_paths | @settings.paths)
|
|
75
99
|
apply_settings
|
|
76
|
-
|
|
100
|
+
errors = @settings.paths.filter_map { |path| Settings.file_diagnostics(path)&.last }.flatten
|
|
101
|
+
@message = errors.empty? ? "Settings reloaded" : "Settings unchanged: #{errors.first.message}"
|
|
77
102
|
rescue StandardError => error
|
|
78
103
|
@settings = old if old
|
|
104
|
+
publish_settings_diagnostics(@settings.paths) if @settings
|
|
79
105
|
@message = "Settings unchanged: #{error.message}"
|
|
80
106
|
end
|
|
81
107
|
|
|
82
108
|
private
|
|
109
|
+
|
|
110
|
+
def settings_gui_fields(changed_only: false)
|
|
111
|
+
defaults = Settings::SCHEMA_MODEL.defaults
|
|
112
|
+
Settings::SCHEMA_MODEL.fields.filter_map do |field|
|
|
113
|
+
path = field.path
|
|
114
|
+
next unless path.all? { |part| part.is_a?(String) && part != "*" }
|
|
115
|
+
|
|
116
|
+
value = path.reduce(@settings.values) { |current, key| current.is_a?(Hash) ? current[key] : nil }
|
|
117
|
+
default = path.reduce(defaults) { |current, key| current.is_a?(Hash) ? current[key] : nil }
|
|
118
|
+
next if changed_only && value == default
|
|
119
|
+
|
|
120
|
+
{path: path, value: value, default: default, description: field.description}.freeze
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def publish_settings_diagnostics(paths)
|
|
125
|
+
paths.uniq.each do |path|
|
|
126
|
+
uri = Sadr::Protocol.uri(File.expand_path(path))
|
|
127
|
+
@diagnostics.publish(:settings, uri, settings_diagnostics(path))
|
|
128
|
+
rescue StandardError
|
|
129
|
+
@diagnostics.publish(:settings, uri, [], notify: false) rescue nil
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
def settings_diagnostics(path)
|
|
134
|
+
parsed = Settings.file_diagnostics(path)
|
|
135
|
+
return [] unless parsed
|
|
136
|
+
|
|
137
|
+
document, diagnostics = parsed
|
|
138
|
+
diagnostics.filter_map do |diagnostic|
|
|
139
|
+
range = diagnostic.range
|
|
140
|
+
start_position = document.utf16_position_at(range&.begin || 0)
|
|
141
|
+
end_position = document.utf16_position_at(range&.end || range&.begin || 0)
|
|
142
|
+
{
|
|
143
|
+
"range" => {
|
|
144
|
+
"start" => {"line" => start_position[0], "character" => start_position[1]},
|
|
145
|
+
"end" => {"line" => end_position[0], "character" => end_position[1]}
|
|
146
|
+
},
|
|
147
|
+
"severity" => Diagnostics::SEVERITIES.fetch(diagnostic.severity, 2),
|
|
148
|
+
"message" => diagnostic.message.to_s,
|
|
149
|
+
"source" => "settings"
|
|
150
|
+
}
|
|
151
|
+
rescue EncodingError, RangeError
|
|
152
|
+
nil
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
83
156
|
def apply_editor_settings(current)
|
|
84
|
-
values =
|
|
157
|
+
values = settings_for_editor(current)
|
|
85
158
|
current.tab_size = values["tab_size"]
|
|
86
159
|
current.use_tabs = values["use_tabs"]
|
|
160
|
+
current.closing_pairs = values["auto_pairs"].to_h.freeze
|
|
87
161
|
current.display_map.tab_size = current.tab_size
|
|
88
162
|
current.display_map.wrap_width = values["soft_wrap"] ? 100 : nil unless current.buffer.read_only
|
|
89
163
|
end
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Canopus
|
|
4
|
+
class Workspace
|
|
5
|
+
module TaskAware
|
|
6
|
+
attr_reader :task_runner
|
|
7
|
+
|
|
8
|
+
def initialize_tasks
|
|
9
|
+
options = @settings["terminal"]
|
|
10
|
+
@task_runner = Task::Runner.new(scrollback: options["scrollback_lines"],
|
|
11
|
+
queue_limit_bytes: options["queue_limit_bytes"], report: ->(error) { post { notify("Cannot close task: #{error.message}") } })
|
|
12
|
+
@task_matchers, @task_finished, @task_diagnostic_snapshot = {}, {}, {}.freeze
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def task_outputs = @task_runner.entries
|
|
16
|
+
def task_output = @task_runner.active
|
|
17
|
+
def task_terminal = @task_runner.terminal
|
|
18
|
+
def task_output_visible = @panels.visible?("output") && @docks[:bottom][:visible]
|
|
19
|
+
|
|
20
|
+
def show_tasks
|
|
21
|
+
configuration = Task::Configuration.new(root: @root)
|
|
22
|
+
if configuration.tasks.empty?
|
|
23
|
+
self.message = "No tasks configured in .canopus/tasks.jsonc"
|
|
24
|
+
return false
|
|
25
|
+
end
|
|
26
|
+
self.palette = {kind: :tasks, query: +"", index: 0,
|
|
27
|
+
matches: configuration.tasks.map { |task| task.fetch("label") },
|
|
28
|
+
items: configuration.tasks, task_configuration: configuration}
|
|
29
|
+
update_palette
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def run_task(task)
|
|
33
|
+
configuration = Task::Configuration.new(root: @root)
|
|
34
|
+
source = task.is_a?(String) ? task : configuration.tasks.find { |candidate| candidate == task }
|
|
35
|
+
resolved = configuration.resolve(source, **task_context)
|
|
36
|
+
matcher = resolved["problem_matcher"] && configuration.problem_matcher(resolved["problem_matcher"])
|
|
37
|
+
raise Error, "unknown problem matcher: #{resolved['problem_matcher']}" if resolved["problem_matcher"] && !matcher
|
|
38
|
+
start_task(resolved, matcher)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def accept_task_palette
|
|
42
|
+
state = @palette
|
|
43
|
+
index = state[:indices] ? state[:indices][state[:index]] : state[:index]
|
|
44
|
+
source = index && state[:items][index]
|
|
45
|
+
configuration = state[:task_configuration]
|
|
46
|
+
self.palette = nil
|
|
47
|
+
return unless source && configuration
|
|
48
|
+
|
|
49
|
+
resolved = configuration.resolve(source, **task_context)
|
|
50
|
+
matcher = resolved["problem_matcher"] && configuration.problem_matcher(resolved["problem_matcher"])
|
|
51
|
+
raise Error, "unknown problem matcher: #{resolved['problem_matcher']}" if resolved["problem_matcher"] && !matcher
|
|
52
|
+
start_task(resolved, matcher)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def show_task_output(output = task_output)
|
|
56
|
+
if output && (index = task_outputs.index { |entry| entry.equal?(output) })
|
|
57
|
+
@task_runner.activate(index)
|
|
58
|
+
end
|
|
59
|
+
@panels.hide("terminal") if @panels.visible?("terminal")
|
|
60
|
+
@panels.hide("debug_console") if @panels.visible?("debug_console")
|
|
61
|
+
@panels.show("output")
|
|
62
|
+
@window&.request_frame
|
|
63
|
+
output
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def toggle_task_output
|
|
67
|
+
task_output_visible ? @panels.hide("output") : show_task_output
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def activate_task_output(index)
|
|
71
|
+
output = @task_runner.activate(index)
|
|
72
|
+
@window&.request_frame
|
|
73
|
+
output
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def close_task_output(index = @task_runner.active_index)
|
|
77
|
+
output = @task_runner.remove(index)
|
|
78
|
+
forget_task_output(output) if output
|
|
79
|
+
@panels.hide("output") if task_outputs.empty?
|
|
80
|
+
@window&.request_frame
|
|
81
|
+
output
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def stop_task(output = task_output)
|
|
85
|
+
stopped = @task_runner.stop(output)
|
|
86
|
+
cancel_test_output(output) if stopped
|
|
87
|
+
self.message = "No running task selected" unless stopped
|
|
88
|
+
@window&.request_frame
|
|
89
|
+
stopped
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def drain_task_outputs
|
|
93
|
+
changed = @task_runner.drain(max_bytes: @settings["terminal"]["max_bytes_per_frame"]) do |output, data, seconds|
|
|
94
|
+
capture_test_output(output, data)
|
|
95
|
+
matcher = @task_matchers[output.id]
|
|
96
|
+
matcher&.feed(data.to_s, max_seconds: seconds)
|
|
97
|
+
!matcher || !matcher.pending?
|
|
98
|
+
end
|
|
99
|
+
@task_runner.completed.each do |output|
|
|
100
|
+
unless @task_finished[output.id]
|
|
101
|
+
@task_finished[output.id] = true
|
|
102
|
+
@task_matchers[output.id]&.finish
|
|
103
|
+
complete_test_output(output)
|
|
104
|
+
end
|
|
105
|
+
next unless output.presentation.fetch("reveal") == "silent"
|
|
106
|
+
status = output.terminal.status if output.terminal.respond_to?(:status)
|
|
107
|
+
show_task_output(output) if status && !status.success?
|
|
108
|
+
end
|
|
109
|
+
@window&.request_frame if changed || @task_runner.pending?
|
|
110
|
+
changed
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def resize_task_output(columns, rows) = @task_runner.resize(columns, rows)
|
|
114
|
+
|
|
115
|
+
def task_output_title(output)
|
|
116
|
+
suffix = @task_runner.running?(output) ? " ●" : ""
|
|
117
|
+
"#{output.label}#{suffix}"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def close_tasks
|
|
121
|
+
@task_runner.close
|
|
122
|
+
ensure
|
|
123
|
+
@task_matchers.clear
|
|
124
|
+
@task_finished.clear
|
|
125
|
+
publish_task_diagnostics
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
private
|
|
129
|
+
|
|
130
|
+
def start_task(task, matcher)
|
|
131
|
+
output = @task_runner.run(task)
|
|
132
|
+
cleanup_stale_task_outputs
|
|
133
|
+
if matcher
|
|
134
|
+
@task_matchers[output.id] = Task::ProblemMatcher.new(matcher, root: @root) { publish_task_diagnostics }
|
|
135
|
+
end
|
|
136
|
+
show_task_output(output) if output.presentation.fetch("reveal") == "always"
|
|
137
|
+
@window&.request_frame
|
|
138
|
+
output
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def cleanup_stale_task_outputs
|
|
142
|
+
ids = task_outputs.map(&:id)
|
|
143
|
+
(@task_matchers.keys | @task_finished.keys).each do |id|
|
|
144
|
+
next if ids.include?(id)
|
|
145
|
+
@task_matchers.delete(id)
|
|
146
|
+
@task_finished.delete(id)
|
|
147
|
+
end
|
|
148
|
+
publish_task_diagnostics
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def forget_task_output(output)
|
|
152
|
+
forget_test_output(output)
|
|
153
|
+
@task_matchers.delete(output.id)
|
|
154
|
+
@task_finished.delete(output.id)
|
|
155
|
+
publish_task_diagnostics
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def publish_task_diagnostics
|
|
159
|
+
grouped = @task_matchers.values.each_with_object(Hash.new { |hash, uri| hash[uri] = [] }) do |matcher, result|
|
|
160
|
+
matcher.diagnostics.each { |uri, values| result[uri].concat(values) }
|
|
161
|
+
end
|
|
162
|
+
snapshot = grouped.to_h do |uri, values|
|
|
163
|
+
[uri, values.first(Diagnostics::PUBLICATION_LIMIT).freeze]
|
|
164
|
+
end
|
|
165
|
+
snapshot.freeze
|
|
166
|
+
changed = (@task_diagnostic_snapshot.keys | snapshot.keys).select do |uri|
|
|
167
|
+
@task_diagnostic_snapshot[uri] != snapshot[uri]
|
|
168
|
+
end
|
|
169
|
+
return false if changed.empty?
|
|
170
|
+
|
|
171
|
+
changed.each do |uri|
|
|
172
|
+
@diagnostics.publish(:task, uri, snapshot.fetch(uri, []), notify: false)
|
|
173
|
+
end
|
|
174
|
+
@task_diagnostic_snapshot = snapshot
|
|
175
|
+
changed.freeze
|
|
176
|
+
@window ? post { diagnostics_changed(changed) } : diagnostics_changed(changed)
|
|
177
|
+
true
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def task_context
|
|
181
|
+
current = editor
|
|
182
|
+
file = current&.buffer&.path
|
|
183
|
+
line_number = current && current.buffer.rope.point_at(current.primary.head).row + 1
|
|
184
|
+
selected_text = nil
|
|
185
|
+
if current && !current.primary.empty?
|
|
186
|
+
range = current.primary.range
|
|
187
|
+
raise Error, "selectedText exceeds 1 MiB" if range.size > Task::Configuration::MAX_EXPANDED_BYTES
|
|
188
|
+
selected_text = current.buffer.rope.byteslice(range).to_s
|
|
189
|
+
end
|
|
190
|
+
{file: file, line_number: line_number, selected_text: selected_text}
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|