canopus 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +55 -0
  3. data/README.md +191 -19
  4. data/assets/keymaps/emacs.jsonc +5 -0
  5. data/assets/keymaps/jetbrains.jsonc +5 -0
  6. data/assets/keymaps/sublime.jsonc +5 -0
  7. data/assets/keymaps/vscode.jsonc +5 -0
  8. data/docs/debugging.md +143 -0
  9. data/docs/distribution.md +40 -9
  10. data/docs/lsp.md +131 -0
  11. data/docs/performance.md +18 -0
  12. data/docs/providers.md +36 -0
  13. data/docs/release-log.md +12 -0
  14. data/docs/tasks.md +64 -0
  15. data/docs/testing.md +49 -0
  16. data/docs/vim.md +3 -0
  17. data/exe/canopus +4 -1
  18. data/lib/canopus/buffer.rb +291 -50
  19. data/lib/canopus/cli.rb +5 -2
  20. data/lib/canopus/command.rb +13 -4
  21. data/lib/canopus/controller.rb +183 -40
  22. data/lib/canopus/debug/breakpoints.rb +550 -0
  23. data/lib/canopus/debug/configuration.rb +291 -0
  24. data/lib/canopus/debug/console.rb +243 -0
  25. data/lib/canopus/debug/panel.rb +487 -0
  26. data/lib/canopus/debug/session.rb +354 -0
  27. data/lib/canopus/decoration.rb +4 -2
  28. data/lib/canopus/denebola_compat.rb +27 -0
  29. data/lib/canopus/diagnostics.rb +173 -0
  30. data/lib/canopus/display_map/overlay_map.rb +6 -2
  31. data/lib/canopus/editor/snippet_expandable.rb +3 -2
  32. data/lib/canopus/editor.rb +122 -31
  33. data/lib/canopus/git/state.rb +100 -0
  34. data/lib/canopus/language/background_analysis.rb +93 -14
  35. data/lib/canopus/language/document.rb +70 -34
  36. data/lib/canopus/language/symbol.rb +1 -0
  37. data/lib/canopus/language/syntax_worker.rb +61 -9
  38. data/lib/canopus/language.rb +3 -0
  39. data/lib/canopus/minimap.rb +201 -0
  40. data/lib/canopus/patch.rb +3 -1
  41. data/lib/canopus/plugins/api.rb +4 -2
  42. data/lib/canopus/plugins/isolated_runtime.rb +64 -7
  43. data/lib/canopus/plugins/registry.rb +114 -3
  44. data/lib/canopus/plugins.rb +8 -7
  45. data/lib/canopus/project.rb +15 -6
  46. data/lib/canopus/provider.rb +192 -0
  47. data/lib/canopus/regexp_compat.rb +36 -4
  48. data/lib/canopus/selection.rb +12 -0
  49. data/lib/canopus/settings/schema.rb +201 -0
  50. data/lib/canopus/settings.rb +328 -49
  51. data/lib/canopus/task/configuration.rb +356 -0
  52. data/lib/canopus/task/problem_matcher.rb +264 -0
  53. data/lib/canopus/task/runner.rb +314 -0
  54. data/lib/canopus/test_runner/bounded_ignore.rb +144 -0
  55. data/lib/canopus/test_runner/discovery.rb +97 -0
  56. data/lib/canopus/test_runner/execution.rb +194 -0
  57. data/lib/canopus/test_runner/minitest.rb +116 -0
  58. data/lib/canopus/test_runner/rspec.rb +103 -0
  59. data/lib/canopus/test_runner/safe_walker.rb +37 -0
  60. data/lib/canopus/test_runner.rb +54 -0
  61. data/lib/canopus/theme/import.rb +131 -0
  62. data/lib/canopus/theme.rb +28 -4
  63. data/lib/canopus/version.rb +1 -1
  64. data/lib/canopus/vim/motionable.rb +1 -1
  65. data/lib/canopus/vim.rb +10 -16
  66. data/lib/canopus/workspace/auto_savable.rb +83 -0
  67. data/lib/canopus/workspace/debug_aware.rb +600 -0
  68. data/lib/canopus/workspace/edit/plan.rb +2 -2
  69. data/lib/canopus/workspace/editor_configurable.rb +113 -0
  70. data/lib/canopus/workspace/file_change_aware.rb +11 -3
  71. data/lib/canopus/workspace/git_aware.rb +80 -34
  72. data/lib/canopus/workspace/git_blame.rb +175 -0
  73. data/lib/canopus/workspace/git_conflict_resolution.rb +410 -0
  74. data/lib/canopus/workspace/git_diff_view.rb +641 -0
  75. data/lib/canopus/workspace/git_history.rb +171 -0
  76. data/lib/canopus/workspace/git_remote.rb +267 -0
  77. data/lib/canopus/workspace/git_staging.rb +583 -0
  78. data/lib/canopus/workspace/hierarchy_aware.rb +477 -0
  79. data/lib/canopus/workspace/keymap_aware.rb +66 -0
  80. data/lib/canopus/workspace/language_aware.rb +3721 -135
  81. data/lib/canopus/workspace/language_server_configurable.rb +287 -71
  82. data/lib/canopus/workspace/persistent_undo.rb +169 -0
  83. data/lib/canopus/workspace/problems_aware.rb +131 -0
  84. data/lib/canopus/workspace/project_searchable.rb +88 -11
  85. data/lib/canopus/workspace/project_tree_editable.rb +3 -1
  86. data/lib/canopus/workspace/recoverable.rb +204 -0
  87. data/lib/canopus/workspace/session_persistable.rb +85 -13
  88. data/lib/canopus/workspace/settings_aware.rb +76 -2
  89. data/lib/canopus/workspace/task_aware.rb +194 -0
  90. data/lib/canopus/workspace/test_aware.rb +394 -0
  91. data/lib/canopus/workspace/trust.rb +73 -0
  92. data/lib/canopus/workspace/view/terminal_presentable.rb +298 -47
  93. data/lib/canopus/workspace/view.rb +399 -74
  94. data/lib/canopus/workspace.rb +688 -44
  95. data/lib/canopus.rb +20 -2
  96. data/sig/canopus.rbs +138 -31
  97. data/sig/controller.rbs +10 -3
  98. data/sig/debug.rbs +121 -0
  99. data/sig/decoration.rbs +12 -2
  100. data/sig/diagnostics.rbs +26 -0
  101. data/sig/minimap.rbs +20 -0
  102. data/sig/provider.rbs +29 -0
  103. data/sig/services.rbs +1 -16
  104. data/sig/task.rbs +92 -0
  105. data/sig/test_runner.rbs +109 -0
  106. data/sig/trust.rbs +17 -0
  107. data/sig/workspace_edits.rbs +2 -2
  108. data/sig/workspace_services.rbs +234 -2
  109. data/tools/check_dependencies.rb +21 -2
  110. data/tools/package.rb +172 -14
  111. data/tools/package_signature_test.rb +33 -0
  112. data/tools/package_test.rb +29 -0
  113. data/tools/sign_package.rb +123 -0
  114. data/tools/update.rb +189 -0
  115. data/tools/update_test.rb +71 -0
  116. metadata +206 -31
  117. data/lib/canopus/lsp/client.rb +0 -307
  118. data/lib/canopus/lsp/error.rb +0 -7
  119. data/lib/canopus/lsp/future/subscription.rb +0 -9
  120. data/lib/canopus/lsp/future.rb +0 -87
  121. data/lib/canopus/lsp/protocol.rb +0 -83
  122. data/lib/canopus/lsp/server_error.rb +0 -13
  123. data/lib/canopus/lsp/timeout.rb +0 -7
  124. data/lib/canopus/lsp/transport.rb +0 -123
  125. data/lib/canopus/lsp.rb +0 -19
  126. data/lib/canopus/project/search.rb +0 -164
  127. data/lib/canopus/project/search_worker/cancelled.rb +0 -3
  128. data/lib/canopus/project/search_worker/runner.rb +0 -9
  129. data/lib/canopus/project/search_worker.rb +0 -108
  130. data/lib/canopus/terminal/cell.rb +0 -7
  131. data/lib/canopus/terminal/grid.rb +0 -321
  132. data/lib/canopus/terminal/pty.rb +0 -178
  133. data/lib/canopus/terminal/scrollback.rb +0 -38
  134. data/lib/canopus/terminal/vt.rb +0 -398
  135. data/lib/canopus/terminal.rb +0 -13
  136. data/sig/lsp.rbs +0 -99
  137. data/sig/terminal.rbs +0 -130
data/lib/canopus/theme.rb CHANGED
@@ -8,10 +8,19 @@ module Canopus
8
8
  "Literal.String" => "#356224", "Literal.Number" => "#854b16", "Operator" => "#375780", "Generic.Heading" => "#795500", "Error" => "#aa2438"}.freeze
9
9
  DARK = {background: "#161b22", foreground: "#d6dde6", panel: "#10151c", border: "#2c3644",
10
10
  active_tab: "#222d3b", muted: "#728399", accent: "#e9a661", selection: "#34547799",
11
- cursor: "#f4e4c1", current_line: "#ffffff06", error: "#f97583", status: "#202a36"}.freeze
11
+ cursor: "#f4e4c1", current_line: "#ffffff06", error: "#f97583", status: "#202a36",
12
+ :"diagnostic.error" => "#f97583", :"diagnostic.warning" => "#e3b341",
13
+ :"diagnostic.information" => "#58a6ff", :"diagnostic.hint" => "#8b949e",
14
+ :"bracket.1" => "#ffd866", :"bracket.2" => "#ab9df2", :"bracket.3" => "#78dce8",
15
+ :"bracket.4" => "#a9dc76", :"bracket.5" => "#fc9867", :"bracket.6" => "#ff6188",
16
+ :"indent.guide" => "#394657", :"indent.guide.active" => "#7c91aa"}.freeze
12
17
  LIGHT = DARK.merge(background: "#faf8f3", foreground: "#293440", panel: "#eeece6", border: "#cecac1",
13
18
  active_tab: "#fff", muted: "#6d7780", selection: "#93bdd477", current_line: "#00000006",
14
- cursor: "#34465a", status: "#e3e2dc").freeze
19
+ cursor: "#34465a", status: "#e3e2dc", :"diagnostic.error" => "#aa2438",
20
+ :"diagnostic.warning" => "#8a6116", :"diagnostic.information" => "#0969da",
21
+ :"diagnostic.hint" => "#57606a", :"bracket.1" => "#8a5a00", :"bracket.2" => "#6f42c1",
22
+ :"bracket.3" => "#096b7a", :"bracket.4" => "#3f6f20", :"bracket.5" => "#a34318",
23
+ :"bracket.6" => "#b42355", :"indent.guide" => "#c4c9cf", :"indent.guide.active" => "#73808c").freeze
15
24
  attr_reader :colors, :syntax, :name
16
25
  def initialize(name: "Canopus Dark", colors: {}, syntax: {})
17
26
  @name, @syntax = name, syntax
@@ -29,13 +38,28 @@ module Canopus
29
38
  key ? @token_mapping[key] : self[:foreground]
30
39
  end
31
40
  end
32
- def self.load(path)
41
+ def self.load(path, warnings: nil)
42
+ if File.extname(path).downcase == ".tmtheme"
43
+ require_relative "theme/import"
44
+ return Import.load(path, warnings: warnings)
45
+ end
46
+
33
47
  data = Kochab.parse(File.read(path), strict: false).value
48
+ if data.is_a?(Hash) && (data.key?("colors") || data.key?("tokenColors"))
49
+ require_relative "theme/import"
50
+ return Import.vscode(data, warnings: warnings)
51
+ end
52
+
34
53
  theme = data.fetch("themes", [data]).first
35
54
  style = theme.fetch("style", {})
36
55
  map = {"editor.background" => :background, "editor.foreground" => :foreground,
37
56
  "panel.background" => :panel, "border" => :border, "text.muted" => :muted,
38
- "status_bar.background" => :status, "editor.active_line.background" => :current_line}
57
+ "status_bar.background" => :status, "editor.active_line.background" => :current_line,
58
+ "diagnostic.error" => :"diagnostic.error", "diagnostic.warning" => :"diagnostic.warning",
59
+ "diagnostic.information" => :"diagnostic.information", "diagnostic.hint" => :"diagnostic.hint",
60
+ "bracket.1" => :"bracket.1", "bracket.2" => :"bracket.2", "bracket.3" => :"bracket.3",
61
+ "bracket.4" => :"bracket.4", "bracket.5" => :"bracket.5", "bracket.6" => :"bracket.6",
62
+ "indent.guide" => :"indent.guide", "indent.guide.active" => :"indent.guide.active"}
39
63
  colors = style.each_with_object({}) { |(key, value), result| result[map[key]] = value if map[key] }
40
64
  new(name: theme.fetch("name", "Imported"), colors: colors, syntax: style.fetch("syntax", {}))
41
65
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Canopus
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
@@ -259,7 +259,7 @@ module Canopus
259
259
 
260
260
  def cell_width(character, column)
261
261
  return @editor.tab_size - column % @editor.tab_size if character == "\t"
262
- defined?(Terminal::Grid) ? [Terminal::Grid.width(character), 1].max : 1
262
+ [Tarazed::Grid.width(character), 1].max
263
263
  end
264
264
 
265
265
  def block_columns
data/lib/canopus/vim.rb CHANGED
@@ -209,24 +209,18 @@ module Canopus
209
209
  end
210
210
  when "delete" then @editor.delete_forward
211
211
  when "left", "right", "up", "down" then @editor.move(key.to_sym)
212
- when "enter" then @editor.insert_text("\n")
213
- when "tab" then @editor.insert_text(@editor.use_tabs ? "\t" : " " * @editor.tab_size)
212
+ when "enter" then @editor.insert_text("\n", pair: false)
213
+ when "tab" then @editor.insert_text(@editor.use_tabs ? "\t" : " " * @editor.tab_size, pair: false)
214
214
  else
215
215
  return unless key.grapheme_clusters.length == 1
216
- auto_pairs = @editor.auto_pairs
217
- begin
218
- @editor.auto_pairs = false
219
- if @mode == :replace
220
- first = @editor.primary.head
221
- ending = horizontal(first, 1, insertion: true)
222
- original = @editor.buffer.rope.byteslice(first...ending).to_s
223
- @editor.select(first, ending)
224
- @replace_stack << [first, first + key.bytesize, original]
225
- end
226
- @editor.insert_text(key)
227
- ensure
228
- @editor.auto_pairs = auto_pairs
216
+ if @mode == :replace
217
+ first = @editor.primary.head
218
+ ending = horizontal(first, 1, insertion: true)
219
+ original = @editor.buffer.rope.byteslice(first...ending).to_s
220
+ @editor.select(first, ending)
221
+ @replace_stack << [first, first + key.bytesize, original]
229
222
  end
223
+ @editor.insert_text(key, pair: false)
230
224
  end
231
225
  end
232
226
 
@@ -243,7 +237,7 @@ module Canopus
243
237
  when "A" then @editor.select(line_end(row_at(cursor_position)))
244
238
  when "o"
245
239
  @editor.select(line_end(row_at(cursor_position)))
246
- @editor.insert_text("\n")
240
+ @editor.insert_text("\n", pair: false)
247
241
  when "O"
248
242
  row = row_at(cursor_position)
249
243
  indent = @editor.buffer.line(row)[/\A[ \t]*/]
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Canopus
4
+ module Workspace::AutoSavable
5
+ def poll_auto_save(now: Process.clock_gettime(Process::CLOCK_MONOTONIC))
6
+ return false if @closed
7
+ mode = @settings["auto_save"]
8
+ delay = @settings["auto_save_delay"]
9
+ current = editor&.buffer
10
+ config = [mode, delay]
11
+ if @auto_save_config != config
12
+ reset_auto_save
13
+ @auto_save_config = config
14
+ @auto_save_focus_buffer = current
15
+ return false unless mode == "after_delay"
16
+ end
17
+
18
+ case mode
19
+ when "on_focus_change"
20
+ previous, @auto_save_focus_buffer = @auto_save_focus_buffer, current
21
+ return false unless previous && !previous.equal?(current)
22
+ saved = false
23
+ auto_save_sources(previous).each { |buffer| saved = auto_save_buffer(buffer) || saved }
24
+ saved
25
+ when "after_delay"
26
+ buffers = auto_save_buffers
27
+ @auto_save_pending ||= {}.compare_by_identity
28
+ @auto_save_pending.delete_if { |buffer, _| !buffers.include?(buffer) }
29
+ attempted = false
30
+ buffers.each do |buffer|
31
+ unless auto_save_eligible?(buffer)
32
+ @auto_save_pending.delete(buffer)
33
+ next
34
+ end
35
+ version = buffer.version
36
+ state = @auto_save_pending[buffer]
37
+ if !state || state[0] != version
38
+ @auto_save_pending[buffer] = [version, now + delay / 1_000.0, false]
39
+ next
40
+ end
41
+ next if state[2] || now < state[1]
42
+ state[2] = true
43
+ attempted = auto_save_buffer(buffer) || attempted
44
+ end
45
+ attempted
46
+ else
47
+ reset_auto_save
48
+ @auto_save_config = config
49
+ @auto_save_focus_buffer = current
50
+ false
51
+ end
52
+ end
53
+
54
+ def reset_auto_save
55
+ @auto_save_pending&.clear
56
+ @auto_save_focus_buffer = nil
57
+ nil
58
+ end
59
+
60
+ private
61
+
62
+ def auto_save_buffers
63
+ @buffers.values.flat_map { |buffer| auto_save_sources(buffer) }.uniq
64
+ end
65
+
66
+ def auto_save_sources(buffer)
67
+ buffer.is_a?(MultiBuffer) ? buffer.excerpts.map(&:buffer).uniq : [buffer]
68
+ end
69
+
70
+ def auto_save_eligible?(buffer)
71
+ buffer.path && !buffer.read_only && buffer.dirty?
72
+ end
73
+
74
+ def auto_save_buffer(buffer)
75
+ return false unless auto_save_eligible?(buffer)
76
+ save_buffer(buffer)
77
+ true
78
+ rescue StandardError => error
79
+ notify("Auto-save failed: #{error.message}")
80
+ false
81
+ end
82
+ end
83
+ end