textbringer 17 → 19

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 (82) hide show
  1. checksums.yaml +4 -4
  2. data/exe/txtb +1 -1
  3. data/lib/textbringer/buffer.rb +37 -3
  4. data/lib/textbringer/commands/buffers.rb +4 -2
  5. data/lib/textbringer/commands/clipboard.rb +21 -6
  6. data/lib/textbringer/commands/completion.rb +133 -0
  7. data/lib/textbringer/commands/ctags.rb +1 -1
  8. data/lib/textbringer/commands/files.rb +11 -1
  9. data/lib/textbringer/commands/help.rb +1 -1
  10. data/lib/textbringer/commands/isearch.rb +4 -10
  11. data/lib/textbringer/commands/ispell.rb +0 -2
  12. data/lib/textbringer/commands/lsp.rb +389 -0
  13. data/lib/textbringer/commands/misc.rb +2 -1
  14. data/lib/textbringer/commands.rb +7 -3
  15. data/lib/textbringer/completion_popup.rb +188 -0
  16. data/lib/textbringer/faces/basic.rb +3 -1
  17. data/lib/textbringer/faces/completion.rb +4 -0
  18. data/lib/textbringer/floating_window.rb +327 -0
  19. data/lib/textbringer/input_methods/skk_input_method.rb +751 -0
  20. data/lib/textbringer/lsp/client.rb +568 -0
  21. data/lib/textbringer/lsp/server_registry.rb +138 -0
  22. data/lib/textbringer/mode.rb +3 -1
  23. data/lib/textbringer/modes/programming_mode.rb +17 -8
  24. data/lib/textbringer/modes/transient_mark_mode.rb +9 -2
  25. data/lib/textbringer/utils.rb +14 -10
  26. data/lib/textbringer/version.rb +1 -1
  27. data/lib/textbringer/window.rb +116 -19
  28. data/lib/textbringer.rb +7 -0
  29. data/sig/lib/textbringer/buffer.rbs +483 -0
  30. data/sig/lib/textbringer/color.rbs +9 -0
  31. data/sig/lib/textbringer/commands/buffers.rbs +93 -0
  32. data/sig/lib/textbringer/commands/clipboard.rbs +17 -0
  33. data/sig/lib/textbringer/commands/completion.rbs +20 -0
  34. data/sig/lib/textbringer/commands/ctags.rbs +11 -0
  35. data/sig/lib/textbringer/commands/dabbrev.rbs +4 -0
  36. data/sig/lib/textbringer/commands/files.rbs +29 -0
  37. data/sig/lib/textbringer/commands/fill.rbs +5 -0
  38. data/sig/lib/textbringer/commands/help.rbs +28 -0
  39. data/sig/lib/textbringer/commands/input_method.rbs +6 -0
  40. data/sig/lib/textbringer/commands/isearch.rbs +38 -0
  41. data/sig/lib/textbringer/commands/ispell.rbs +39 -0
  42. data/sig/lib/textbringer/commands/keyboard_macro.rbs +25 -0
  43. data/sig/lib/textbringer/commands/lsp.rbs +8 -0
  44. data/sig/lib/textbringer/commands/misc.rbs +74 -0
  45. data/sig/lib/textbringer/commands/rectangle.rbs +19 -0
  46. data/sig/lib/textbringer/commands/register.rbs +31 -0
  47. data/sig/lib/textbringer/commands/replace.rbs +17 -0
  48. data/sig/lib/textbringer/commands/server.rbs +31 -0
  49. data/sig/lib/textbringer/commands/ucs_normalize.rbs +9 -0
  50. data/sig/lib/textbringer/commands/windows.rbs +45 -0
  51. data/sig/lib/textbringer/commands.rbs +21 -0
  52. data/sig/lib/textbringer/completion_popup.rbs +40 -0
  53. data/sig/lib/textbringer/controller.rbs +58 -0
  54. data/sig/lib/textbringer/default_output.rbs +7 -0
  55. data/sig/lib/textbringer/errors.rbs +3 -0
  56. data/sig/lib/textbringer/face.rbs +19 -0
  57. data/sig/lib/textbringer/floating_window.rbs +42 -0
  58. data/sig/lib/textbringer/global_minor_mode.rbs +7 -0
  59. data/sig/lib/textbringer/input_method.rbs +28 -0
  60. data/sig/lib/textbringer/input_methods/hangul_input_method.rbs +12 -0
  61. data/sig/lib/textbringer/input_methods/hiragana_input_method.rbs +12 -0
  62. data/sig/lib/textbringer/input_methods/t_code_input_method.rbs +49 -0
  63. data/sig/lib/textbringer/keymap.rbs +33 -0
  64. data/sig/lib/textbringer/lsp/client.rbs +21 -0
  65. data/sig/lib/textbringer/lsp/server_registry.rbs +23 -0
  66. data/sig/lib/textbringer/minor_mode.rbs +12 -0
  67. data/sig/lib/textbringer/mode.rbs +70 -0
  68. data/sig/lib/textbringer/modes/backtrace_mode.rbs +8 -0
  69. data/sig/lib/textbringer/modes/buffer_list_mode.rbs +5 -0
  70. data/sig/lib/textbringer/modes/c_mode.rbs +21 -0
  71. data/sig/lib/textbringer/modes/completion_list_mode.rbs +5 -0
  72. data/sig/lib/textbringer/modes/fundamental_mode.rbs +3 -0
  73. data/sig/lib/textbringer/modes/help_mode.rbs +7 -0
  74. data/sig/lib/textbringer/modes/overwrite_mode.rbs +15 -0
  75. data/sig/lib/textbringer/modes/programming_mode.rbs +14 -0
  76. data/sig/lib/textbringer/modes/ruby_mode.rbs +57 -0
  77. data/sig/lib/textbringer/plugin.rbs +3 -0
  78. data/sig/lib/textbringer/ring.rbs +36 -0
  79. data/sig/lib/textbringer/utils.rbs +95 -0
  80. data/sig/lib/textbringer/window.rbs +183 -0
  81. data/textbringer.gemspec +1 -0
  82. metadata +76 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afebafd9a22024be2bc3c4c5c2140ac9ad3b7fa7a1efc25e0ae9bf4d38c3da10
4
- data.tar.gz: 53841ecd93d7b63e9d33a07d39721f90bf0d39e6803406287518601d67d4a59c
3
+ metadata.gz: 9aa0a319cdc7f8e965d906b1059a76083730240463a3ed33a4cb79214d2762b6
4
+ data.tar.gz: 3993baf2bf25459b7ec201b112d98c05aa96eaac68e77510b013cfd2d3cf69c8
5
5
  SHA512:
6
- metadata.gz: 469ef80d72998003e1d5ca9e6c499b70debc5d1c2c09b43b9b79311e94ce15c22adbd766bf31cafaa20a5ac11a19c8b12d9c8392d166cec5a617305c4a50e43f
7
- data.tar.gz: 6908288f0debd4001c131327071962fda1392ff0310f26fc72b9f0391b01e281b22824c78e78d2be69cd89b5fc768c7239d116bd35699d1483c4fa944aae76be
6
+ metadata.gz: cb57afbe902f32238deab1589433564632fcea16b43351faebf530262deafb50d36719180a120e9496206ed99eaebc56f7c7506c190cb75abfaf104b00aecea1
7
+ data.tar.gz: 633f52c2fc1b4012b0e02ad06fba07d1cde388f1949ad06189a2b1354ab4952d9ae2c68898f8e4de899f58b9b800579f77212a3db6569340371d700fa3a3d12d
data/exe/txtb CHANGED
@@ -27,11 +27,11 @@ end
27
27
  Controller.current = Controller.new
28
28
  begin
29
29
  Window.start do
30
+ load_user_config("~/.textbringer/init.rb")
30
31
  $stdout = DefaultOutput.new
31
32
  begin
32
33
  transient_mark_mode(true)
33
34
  Window.echo_area.clear_message
34
- load_user_config("~/.textbringer/init.rb")
35
35
  Plugin.load_plugins
36
36
  load_user_config("~/.textbringer.rb")
37
37
  ruby_mode
@@ -10,7 +10,7 @@ module Textbringer
10
10
 
11
11
  attr_accessor :mode, :keymap
12
12
  attr_reader :name, :file_name, :file_encoding, :file_format, :point, :marks
13
- attr_reader :current_line, :current_column, :visible_mark, :mark_active
13
+ attr_reader :current_line, :current_column, :visible_mark, :isearch_mark, :mark_active
14
14
  attr_reader :last_match
15
15
  attr_reader :input_method
16
16
 
@@ -254,6 +254,7 @@ module Textbringer
254
254
  @save_point_level = 0
255
255
  @match_offsets = []
256
256
  @visible_mark = nil
257
+ @isearch_mark = nil
257
258
  @mark_active = false
258
259
  @read_only = read_only
259
260
  @callbacks = {}
@@ -276,11 +277,15 @@ module Textbringer
276
277
  end
277
278
 
278
279
  def file_name=(file_name)
280
+ old_file_name = @file_name
279
281
  @file_name = file_name
280
282
  basename = File.basename(file_name)
281
283
  if /\A#{Regexp.quote(basename)}(<\d+>)?\z/ !~ name
282
284
  self.name = basename
283
285
  end
286
+ if old_file_name != file_name && current?
287
+ Utils.run_hooks(:after_set_visited_file_name_hook, old_file_name)
288
+ end
284
289
  end
285
290
 
286
291
  def file_encoding=(enc)
@@ -342,7 +347,7 @@ module Textbringer
342
347
  end
343
348
 
344
349
  def on_killed(&callback)
345
- add_callback(:killed, callback)
350
+ on(:killed, &callback)
346
351
  end
347
352
 
348
353
  def current?
@@ -366,7 +371,7 @@ module Textbringer
366
371
  end
367
372
 
368
373
  def on_modified(&callback)
369
- add_callback(:modified, callback)
374
+ on(:modified, &callback)
370
375
  end
371
376
 
372
377
  def [](name)
@@ -609,6 +614,7 @@ module Textbringer
609
614
  end
610
615
  self.modified = true
611
616
  @goal_column = nil
617
+ Utils.run_hooks(:after_change_functions, pos, @point, "") unless @undoing || !current?
612
618
  self
613
619
  end
614
620
 
@@ -650,6 +656,7 @@ module Textbringer
650
656
  end
651
657
  push_undo(DeleteAction.new(self, s, s, str))
652
658
  self.modified = true
659
+ Utils.run_hooks(:after_change_functions, s, s, str) unless @undoing || !current?
653
660
  elsif n < 0
654
661
  str = substring(pos, s)
655
662
  update_line_and_column(@point, pos)
@@ -665,6 +672,7 @@ module Textbringer
665
672
  @point = @gap_start = pos
666
673
  push_undo(DeleteAction.new(self, s, pos, str))
667
674
  self.modified = true
675
+ Utils.run_hooks(:after_change_functions, pos, pos, str) unless @undoing || !current?
668
676
  end
669
677
  @goal_column = nil
670
678
  end
@@ -948,6 +956,18 @@ module Textbringer
948
956
  end
949
957
  end
950
958
 
959
+ def set_isearch_mark(pos = @point)
960
+ @isearch_mark ||= new_mark
961
+ @isearch_mark.location = pos
962
+ end
963
+
964
+ def delete_isearch_mark
965
+ if @isearch_mark
966
+ @isearch_mark.delete
967
+ @isearch_mark = nil
968
+ end
969
+ end
970
+
951
971
  def activate_mark
952
972
  @mark_active = true
953
973
  set_visible_mark(@mark.location) if @mark
@@ -1007,6 +1027,7 @@ module Textbringer
1007
1027
  end
1008
1028
  push_undo(DeleteAction.new(self, old_pos, s, str))
1009
1029
  self.modified = true
1030
+ Utils.run_hooks(:after_change_functions, s, s, str) unless @undoing || !current?
1010
1031
  end
1011
1032
  end
1012
1033
 
@@ -1477,6 +1498,19 @@ module Textbringer
1477
1498
  end
1478
1499
  end
1479
1500
 
1501
+ def pos_to_line_and_column(pos)
1502
+ return [1, 1] if pos == 0
1503
+ text_before = substring(0, pos)
1504
+ line = text_before.count("\n") + 1
1505
+ last_newline = text_before.rindex("\n")
1506
+ column = if last_newline
1507
+ text_before.size - last_newline
1508
+ else
1509
+ text_before.size + 1
1510
+ end
1511
+ [line, column]
1512
+ end
1513
+
1480
1514
  private
1481
1515
 
1482
1516
  def set_contents(s, enc)
@@ -96,7 +96,8 @@ module Textbringer
96
96
  buffer = Buffer.current
97
97
  buffer.exchange_point_and_mark
98
98
  # Activate mark if transient mark mode is enabled
99
- if TransientMarkMode.enabled?
99
+ if TransientMarkMode.enabled? &&
100
+ Controller.current.this_command == :exchange_point_and_mark
100
101
  buffer.activate_mark
101
102
  end
102
103
  end
@@ -153,7 +154,8 @@ module Textbringer
153
154
  else
154
155
  buffer.push_mark
155
156
  # Activate mark if transient mark mode is enabled
156
- if TransientMarkMode.enabled?
157
+ if TransientMarkMode.enabled? &&
158
+ Controller.current.this_command == :set_mark_command
157
159
  buffer.activate_mark
158
160
  end
159
161
  message("Mark set")
@@ -29,23 +29,38 @@ module Textbringer
29
29
  Copy the region to the kill ring and the clipboard, and delete
30
30
  the region.
31
31
  EOD
32
- kill_region
33
- Clipboard.copy(KILL_RING.current)
32
+ begin
33
+ kill_region
34
+ Clipboard.copy(KILL_RING.current)
35
+ rescue ReadOnlyError
36
+ Clipboard.copy(KILL_RING.current)
37
+ raise
38
+ end
34
39
  end
35
40
 
36
41
  define_command(:clipboard_kill_line, doc: <<~EOD) do
37
42
  Kill the rest of the current line, and copy the killed text to
38
43
  the clipboard.
39
44
  EOD
40
- kill_line
41
- Clipboard.copy(KILL_RING.current)
45
+ begin
46
+ kill_line
47
+ Clipboard.copy(KILL_RING.current)
48
+ rescue ReadOnlyError
49
+ Clipboard.copy(KILL_RING.current)
50
+ raise
51
+ end
42
52
  end
43
53
 
44
54
  define_command(:clipboard_kill_word, doc: <<~EOD) do
45
55
  Kill a word, and copy the word to the clipboard.
46
56
  EOD
47
- kill_word
48
- Clipboard.copy(KILL_RING.current)
57
+ begin
58
+ kill_word
59
+ Clipboard.copy(KILL_RING.current)
60
+ rescue ReadOnlyError
61
+ Clipboard.copy(KILL_RING.current)
62
+ raise
63
+ end
49
64
  end
50
65
 
51
66
  define_command(:clipboard_yank, doc: <<~EOD) do
@@ -0,0 +1,133 @@
1
+ module Textbringer
2
+ module Commands
3
+ define_keymap :COMPLETION_POPUP_MAP
4
+
5
+ # Navigation keys
6
+ COMPLETION_POPUP_MAP.define_key("\C-n", :completion_popup_next)
7
+ COMPLETION_POPUP_MAP.define_key(:down, :completion_popup_next)
8
+ COMPLETION_POPUP_MAP.define_key("\C-p", :completion_popup_previous)
9
+ COMPLETION_POPUP_MAP.define_key(:up, :completion_popup_previous)
10
+
11
+ # Accept keys
12
+ COMPLETION_POPUP_MAP.define_key("\C-m", :completion_popup_accept) # RET
13
+ COMPLETION_POPUP_MAP.define_key("\t", :completion_popup_accept) # Tab
14
+
15
+ # Cancel keys
16
+ COMPLETION_POPUP_MAP.define_key("\C-g", :completion_popup_cancel)
17
+
18
+ # Handle undefined keys - close popup and forward the key
19
+ COMPLETION_POPUP_MAP.handle_undefined_key do |key|
20
+ :completion_popup_self_insert_and_close
21
+ end
22
+
23
+ COMPLETION_POPUP_STATUS = {
24
+ active: false,
25
+ start_point: nil
26
+ }
27
+
28
+ def self.completion_popup_mode_active?
29
+ COMPLETION_POPUP_STATUS[:active]
30
+ end
31
+
32
+ define_command(:completion_popup_next,
33
+ doc: "Select next completion candidate.") do
34
+ CompletionPopup.instance.select_next
35
+ end
36
+
37
+ define_command(:completion_popup_previous,
38
+ doc: "Select previous completion candidate.") do
39
+ CompletionPopup.instance.select_previous
40
+ end
41
+
42
+ define_command(:completion_popup_accept,
43
+ doc: "Accept the selected completion.") do
44
+ popup = CompletionPopup.instance
45
+ item = popup.accept
46
+ if item
47
+ insert_completion(item)
48
+ end
49
+ completion_popup_done
50
+ end
51
+
52
+ define_command(:completion_popup_cancel,
53
+ doc: "Cancel completion popup.") do
54
+ CompletionPopup.instance.cancel
55
+ completion_popup_done
56
+ end
57
+
58
+ define_command(:completion_popup_self_insert_and_close,
59
+ doc: "Close popup and process the key.") do
60
+ CompletionPopup.instance.close
61
+ completion_popup_done
62
+ # Execute the command for the key that closed the popup
63
+ key = Controller.current.last_key
64
+ buffer = Buffer.current
65
+ cmd = buffer&.keymap&.lookup([key]) || GLOBAL_MAP.lookup([key])
66
+ if cmd.is_a?(Symbol)
67
+ send(cmd)
68
+ elsif cmd.respond_to?(:call)
69
+ cmd.call
70
+ end
71
+ end
72
+
73
+ def completion_popup_start(items:, start_point:, prefix: "")
74
+ return if items.empty?
75
+
76
+ CompletionPopup.instance.show(
77
+ items: items,
78
+ start_point: start_point,
79
+ prefix: prefix
80
+ )
81
+
82
+ COMPLETION_POPUP_STATUS[:active] = true
83
+ COMPLETION_POPUP_STATUS[:start_point] = start_point
84
+
85
+ Controller.current.overriding_map = COMPLETION_POPUP_MAP
86
+ add_hook(:pre_command_hook, :completion_popup_pre_command_hook)
87
+ end
88
+
89
+ def completion_popup_done
90
+ COMPLETION_POPUP_STATUS[:active] = false
91
+ COMPLETION_POPUP_STATUS[:start_point] = nil
92
+ Controller.current.overriding_map = nil
93
+ remove_hook(:pre_command_hook, :completion_popup_pre_command_hook)
94
+ end
95
+
96
+ def completion_popup_pre_command_hook
97
+ # Close popup if command is not a completion popup command
98
+ if /\Acompletion_popup_/ !~ Controller.current.this_command.to_s
99
+ CompletionPopup.instance.close
100
+ completion_popup_done
101
+ end
102
+ end
103
+
104
+ def insert_completion(item)
105
+ buffer = Buffer.current
106
+ start_point = COMPLETION_POPUP_STATUS[:start_point]
107
+ return unless start_point
108
+
109
+ insert_text = item[:insert_text] || item[:label]
110
+ return unless insert_text
111
+
112
+ # The server may return an insert_text that covers more than the typed
113
+ # symbol prefix (e.g. "Textbringer::Buffer" when the symbol pattern only
114
+ # backed up to "Buf"). Find the longest prefix of insert_text that is a
115
+ # suffix of the buffer text ending at point, and use that as the
116
+ # replacement range.
117
+ look_back = [buffer.point, insert_text.length].min
118
+ actual_start = start_point
119
+ if look_back > 0
120
+ text_before_point = buffer.substring(buffer.point - look_back, buffer.point)
121
+ look_back.downto(1) do |n|
122
+ if text_before_point.end_with?(insert_text[0, n])
123
+ actual_start = buffer.point - n
124
+ break
125
+ end
126
+ end
127
+ end
128
+
129
+ buffer.delete_region(actual_start, buffer.point)
130
+ buffer.insert(insert_text)
131
+ end
132
+ end
133
+ end
@@ -76,7 +76,7 @@ module Textbringer
76
76
  if CTAGS[:path] != path || CTAGS[:tags_mtime] != mtime
77
77
  CTAGS[:path] = path
78
78
  tags = Hash.new { |h, k| h[k] = [] }
79
- File.read(path).scan(/^(.*?)\t(.*?)\t(.*?)(?:;".*)?$/) do
79
+ File.binread(path).scan(/^(.*?)\t(.*?)\t(.*?)(?:;".*)?$/) do
80
80
  |name, file, addr|
81
81
  n = tags[name].count { |f,| f == file } + 1
82
82
  tags[name].push([file, addr, n])
@@ -45,6 +45,7 @@ module Textbringer
45
45
  if config.key?("tab_width")
46
46
  Buffer.current[:tab_width] = config["tab_width"].to_i
47
47
  end
48
+ run_hooks(:find_file_hook)
48
49
  end
49
50
 
50
51
  define_command(:revert_buffer, doc: <<~EOD) do
@@ -102,10 +103,19 @@ module Textbringer
102
103
  next
103
104
  end
104
105
  end
105
- Buffer.current.save(file_name)
106
+ set_visited_file_name(file_name)
107
+ Buffer.current.save
106
108
  message("Wrote #{Buffer.current.file_name}")
107
109
  end
108
110
 
111
+ define_command(:set_visited_file_name,
112
+ doc: "Change the file name of the current buffer.") do
113
+ |file_name = read_file_name("Set visited file name: ",
114
+ default: Buffer.current.file_name)|
115
+ file_name = File.expand_path(file_name)
116
+ Buffer.current.file_name = file_name
117
+ end
118
+
109
119
  define_command(:set_buffer_file_encoding,
110
120
  doc: "Set the file encoding of the current buffer.") do
111
121
  |enc = read_encoding("File encoding: ",
@@ -65,7 +65,7 @@ module Textbringer
65
65
  end
66
66
 
67
67
  def command_help(cmd)
68
- file, line = *cmd.block.source_location
68
+ file, line = *cmd.source_location
69
69
  s = format("%s:%d\n", file, line)
70
70
  s << "-" * (Window.columns - 2) + "\n"
71
71
  s << "#{cmd.name}"
@@ -77,10 +77,7 @@ module Textbringer
77
77
  end
78
78
 
79
79
  def isearch_done
80
- # Don't delete visible_mark if mark is active (transient mark mode)
81
- unless Buffer.current.mark_active?
82
- Buffer.current.delete_visible_mark
83
- end
80
+ Buffer.current.delete_isearch_mark
84
81
  Controller.current.overriding_map = nil
85
82
  remove_hook(:pre_command_hook, :isearch_pre_command_hook)
86
83
  ISEARCH_STATUS[:last_string] = ISEARCH_STATUS[:string]
@@ -94,7 +91,7 @@ module Textbringer
94
91
  end
95
92
 
96
93
  define_command(:isearch_abort, doc: "Abort incremental search.") do
97
- goto_char(Buffer.current[:isearch_start])
94
+ goto_char(ISEARCH_STATUS[:start])
98
95
  isearch_done
99
96
  raise Quit
100
97
  end
@@ -157,11 +154,8 @@ module Textbringer
157
154
  if Buffer.current != Buffer.minibuffer
158
155
  message(isearch_prompt + ISEARCH_STATUS[:string], log: false)
159
156
  end
160
- # Don't update visible_mark if mark is already active (transient mark mode)
161
- unless Buffer.current.mark_active?
162
- Buffer.current.set_visible_mark(forward ? match_beginning(0) :
163
- match_end(0))
164
- end
157
+ Buffer.current.set_isearch_mark(forward ? match_beginning(0) :
158
+ match_end(0))
165
159
  goto_char(forward ? match_end(0) : match_beginning(0))
166
160
  else
167
161
  if Buffer.current != Buffer.minibuffer
@@ -1,5 +1,3 @@
1
- # frozen_string_literal: true
2
-
3
1
  require "open3"
4
2
  require "uri"
5
3