ruvim 0.4.0 → 0.6.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/AGENTS.md +53 -4
- data/README.md +15 -6
- data/Rakefile +7 -0
- data/benchmark/cext_compare.rb +165 -0
- data/benchmark/chunked_load.rb +256 -0
- data/benchmark/file_load.rb +140 -0
- data/benchmark/hotspots.rb +178 -0
- data/docs/binding.md +3 -2
- data/docs/command.md +81 -9
- data/docs/done.md +23 -0
- data/docs/spec.md +105 -19
- data/docs/todo.md +9 -0
- data/docs/tutorial.md +9 -1
- data/docs/vim_diff.md +13 -0
- data/ext/ruvim/extconf.rb +5 -0
- data/ext/ruvim/ruvim_ext.c +519 -0
- data/lib/ruvim/app.rb +217 -2778
- data/lib/ruvim/browser.rb +104 -0
- data/lib/ruvim/buffer.rb +39 -28
- data/lib/ruvim/command_invocation.rb +2 -2
- data/lib/ruvim/completion_manager.rb +708 -0
- data/lib/ruvim/dispatcher.rb +14 -8
- data/lib/ruvim/display_width.rb +91 -45
- data/lib/ruvim/editor.rb +64 -81
- data/lib/ruvim/ex_command_registry.rb +3 -1
- data/lib/ruvim/gh/link.rb +207 -0
- data/lib/ruvim/git/blame.rb +16 -6
- data/lib/ruvim/git/branch.rb +20 -5
- data/lib/ruvim/git/grep.rb +107 -0
- data/lib/ruvim/git/handler.rb +42 -1
- data/lib/ruvim/global_commands.rb +175 -35
- data/lib/ruvim/highlighter.rb +4 -13
- data/lib/ruvim/key_handler.rb +1510 -0
- data/lib/ruvim/keymap_manager.rb +7 -7
- data/lib/ruvim/lang/base.rb +5 -0
- data/lib/ruvim/lang/c.rb +116 -0
- data/lib/ruvim/lang/cpp.rb +107 -0
- data/lib/ruvim/lang/csv.rb +4 -1
- data/lib/ruvim/lang/diff.rb +2 -0
- data/lib/ruvim/lang/dockerfile.rb +36 -0
- data/lib/ruvim/lang/elixir.rb +85 -0
- data/lib/ruvim/lang/erb.rb +30 -0
- data/lib/ruvim/lang/go.rb +83 -0
- data/lib/ruvim/lang/html.rb +34 -0
- data/lib/ruvim/lang/javascript.rb +83 -0
- data/lib/ruvim/lang/json.rb +6 -0
- data/lib/ruvim/lang/lua.rb +76 -0
- data/lib/ruvim/lang/makefile.rb +36 -0
- data/lib/ruvim/lang/markdown.rb +3 -4
- data/lib/ruvim/lang/ocaml.rb +77 -0
- data/lib/ruvim/lang/perl.rb +91 -0
- data/lib/ruvim/lang/python.rb +85 -0
- data/lib/ruvim/lang/registry.rb +102 -0
- data/lib/ruvim/lang/ruby.rb +7 -0
- data/lib/ruvim/lang/rust.rb +95 -0
- data/lib/ruvim/lang/scheme.rb +5 -0
- data/lib/ruvim/lang/sh.rb +76 -0
- data/lib/ruvim/lang/sql.rb +52 -0
- data/lib/ruvim/lang/toml.rb +36 -0
- data/lib/ruvim/lang/tsv.rb +4 -1
- data/lib/ruvim/lang/typescript.rb +53 -0
- data/lib/ruvim/lang/yaml.rb +62 -0
- data/lib/ruvim/rich_view/table_renderer.rb +3 -3
- data/lib/ruvim/rich_view.rb +14 -7
- data/lib/ruvim/screen.rb +126 -72
- data/lib/ruvim/stream/file_load.rb +85 -0
- data/lib/ruvim/stream/follow.rb +40 -0
- data/lib/ruvim/stream/git.rb +43 -0
- data/lib/ruvim/stream/run.rb +74 -0
- data/lib/ruvim/stream/stdin.rb +55 -0
- data/lib/ruvim/stream.rb +35 -0
- data/lib/ruvim/stream_mixer.rb +394 -0
- data/lib/ruvim/terminal.rb +18 -4
- data/lib/ruvim/text_metrics.rb +84 -65
- data/lib/ruvim/version.rb +1 -1
- data/lib/ruvim/window.rb +5 -5
- data/lib/ruvim.rb +23 -6
- data/test/app_command_test.rb +382 -0
- data/test/app_completion_test.rb +43 -19
- data/test/app_dot_repeat_test.rb +27 -3
- data/test/app_ex_command_test.rb +154 -0
- data/test/app_motion_test.rb +13 -12
- data/test/app_register_test.rb +2 -1
- data/test/app_scenario_test.rb +15 -10
- data/test/app_startup_test.rb +70 -27
- data/test/app_text_object_test.rb +2 -1
- data/test/app_unicode_behavior_test.rb +3 -2
- data/test/browser_test.rb +88 -0
- data/test/buffer_test.rb +24 -0
- data/test/cli_test.rb +63 -0
- data/test/command_invocation_test.rb +33 -0
- data/test/config_dsl_test.rb +47 -0
- data/test/dispatcher_test.rb +74 -4
- data/test/ex_command_registry_test.rb +106 -0
- data/test/follow_test.rb +20 -21
- data/test/gh_link_test.rb +141 -0
- data/test/git_blame_test.rb +96 -17
- data/test/git_grep_test.rb +64 -0
- data/test/highlighter_test.rb +125 -0
- data/test/indent_test.rb +137 -0
- data/test/input_screen_integration_test.rb +1 -1
- data/test/keyword_chars_test.rb +85 -0
- data/test/lang_test.rb +634 -0
- data/test/markdown_renderer_test.rb +5 -5
- data/test/on_save_hook_test.rb +12 -8
- data/test/render_snapshot_test.rb +78 -0
- data/test/rich_view_test.rb +42 -42
- data/test/run_command_test.rb +307 -0
- data/test/screen_test.rb +68 -5
- data/test/stream_test.rb +165 -0
- data/test/window_test.rb +59 -0
- metadata +52 -2
data/lib/ruvim/dispatcher.rb
CHANGED
|
@@ -21,9 +21,9 @@ module RuVim
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def dispatch_ex(editor, line)
|
|
24
|
-
raw = line.
|
|
24
|
+
raw = line.strip
|
|
25
25
|
if raw.start_with?("!")
|
|
26
|
-
command = raw[1..].
|
|
26
|
+
command = raw[1..].strip
|
|
27
27
|
invocation = CommandInvocation.new(id: "__shell__", argv: [command])
|
|
28
28
|
ctx = Context.new(editor:, invocation:)
|
|
29
29
|
@command_host.ex_shell(ctx, command:)
|
|
@@ -52,15 +52,21 @@ module RuVim
|
|
|
52
52
|
return if parsed.nil?
|
|
53
53
|
|
|
54
54
|
spec = @ex_registry.fetch(parsed.name)
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
argv = parsed.argv
|
|
56
|
+
if spec.raw_args
|
|
57
|
+
# Re-extract raw text after command name (preserving shell quoting)
|
|
58
|
+
raw_rest = rest.strip.sub(/\A\S+\s*/, "")
|
|
59
|
+
argv = raw_rest.empty? ? [] : [raw_rest]
|
|
60
|
+
end
|
|
61
|
+
validate_ex_args!(spec, argv, parsed.bang)
|
|
62
|
+
invocation = CommandInvocation.new(id: spec.name, argv: argv, bang: parsed.bang)
|
|
57
63
|
ctx = Context.new(editor:, invocation:)
|
|
58
64
|
range_kwargs = {}
|
|
59
65
|
if range_result
|
|
60
66
|
range_kwargs[:range_start] = range_result[:range_start]
|
|
61
67
|
range_kwargs[:range_end] = range_result[:range_end]
|
|
62
68
|
end
|
|
63
|
-
@command_host.call(spec.call, ctx, argv:
|
|
69
|
+
@command_host.call(spec.call, ctx, argv: argv, bang: parsed.bang, count: 1, kwargs: range_kwargs)
|
|
64
70
|
rescue StandardError => e
|
|
65
71
|
editor.echo_error("Error: #{e.message}")
|
|
66
72
|
ensure
|
|
@@ -68,7 +74,7 @@ module RuVim
|
|
|
68
74
|
end
|
|
69
75
|
|
|
70
76
|
def parse_ex(line)
|
|
71
|
-
raw = line.
|
|
77
|
+
raw = line.strip
|
|
72
78
|
return nil if raw.empty?
|
|
73
79
|
|
|
74
80
|
tokens = Shellwords.shellsplit(raw)
|
|
@@ -85,7 +91,7 @@ module RuVim
|
|
|
85
91
|
# Parse a substitute command: s/pat/repl/flags
|
|
86
92
|
# Returns {pattern:, replacement:, flags_str:} or nil
|
|
87
93
|
def parse_substitute(line)
|
|
88
|
-
raw = line.
|
|
94
|
+
raw = line.strip
|
|
89
95
|
return nil unless raw.match?(/\As[^a-zA-Z]/)
|
|
90
96
|
return nil if raw.length < 2
|
|
91
97
|
|
|
@@ -189,7 +195,7 @@ module RuVim
|
|
|
189
195
|
# Parse a range from the beginning of raw.
|
|
190
196
|
# Returns {range_start:, range_end:, rest:} or nil.
|
|
191
197
|
def parse_range(raw, editor)
|
|
192
|
-
str = raw
|
|
198
|
+
str = raw
|
|
193
199
|
return nil if str.empty?
|
|
194
200
|
|
|
195
201
|
# % = whole file
|
data/lib/ruvim/display_width.rb
CHANGED
|
@@ -1,24 +1,103 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Try loading the C extension (built by rake compile)
|
|
4
|
+
begin
|
|
5
|
+
require_relative "ruvim_ext"
|
|
6
|
+
rescue LoadError
|
|
7
|
+
# C extension not available — pure Ruby fallback below
|
|
8
|
+
end
|
|
9
|
+
|
|
3
10
|
module RuVim
|
|
4
11
|
module DisplayWidth
|
|
5
12
|
module_function
|
|
6
13
|
|
|
7
|
-
|
|
8
|
-
|
|
14
|
+
if defined?(RuVim::DisplayWidthExt)
|
|
15
|
+
# ---- C extension paths ----
|
|
16
|
+
|
|
17
|
+
def cell_width(ch, col: 0, tabstop: 2)
|
|
18
|
+
sync_ambiguous_width
|
|
19
|
+
DisplayWidthExt.cell_width(ch, col:, tabstop:)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def display_width(str, tabstop: 2, start_col: 0)
|
|
23
|
+
sync_ambiguous_width
|
|
24
|
+
DisplayWidthExt.display_width(str, tabstop:, start_col:)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def expand_tabs(str, tabstop: 2, start_col: 0)
|
|
28
|
+
sync_ambiguous_width
|
|
29
|
+
DisplayWidthExt.expand_tabs(str, tabstop:, start_col:)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def ambiguous_width
|
|
33
|
+
sync_ambiguous_width
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def sync_ambiguous_width
|
|
37
|
+
env = ::ENV["RUVIM_AMBIGUOUS_WIDTH"]
|
|
38
|
+
if !defined?(@ambiguous_width_cached) || @ambiguous_width_env != env
|
|
39
|
+
@ambiguous_width_env = env
|
|
40
|
+
@ambiguous_width_cached = (env == "2" ? 2 : 1)
|
|
41
|
+
DisplayWidthExt.set_ambiguous_width(@ambiguous_width_cached)
|
|
42
|
+
end
|
|
43
|
+
@ambiguous_width_cached
|
|
44
|
+
end
|
|
45
|
+
else
|
|
46
|
+
# ---- Pure Ruby fallback ----
|
|
47
|
+
|
|
48
|
+
def cell_width(ch, col: 0, tabstop: 2)
|
|
49
|
+
return 1 if ch.nil? || ch.empty?
|
|
50
|
+
|
|
51
|
+
if ch == "\t"
|
|
52
|
+
width = tabstop - (col % tabstop)
|
|
53
|
+
return width.zero? ? tabstop : width
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Fast path: byte length 1 means ASCII — always width 1
|
|
57
|
+
return 1 if ch.bytesize == 1
|
|
58
|
+
|
|
59
|
+
code = ch.ord
|
|
60
|
+
return cached_codepoint_width(code) if codepoint_cacheable?(code)
|
|
9
61
|
|
|
10
|
-
|
|
11
|
-
width = tabstop - (col % tabstop)
|
|
12
|
-
return width.zero? ? tabstop : width
|
|
62
|
+
uncached_codepoint_width(code)
|
|
13
63
|
end
|
|
14
64
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
65
|
+
def display_width(str, tabstop: 2, start_col: 0)
|
|
66
|
+
col = start_col
|
|
67
|
+
str.to_s.each_char { |ch| col += cell_width(ch, col:, tabstop:) }
|
|
68
|
+
col - start_col
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def expand_tabs(str, tabstop: 2, start_col: 0)
|
|
72
|
+
col = start_col
|
|
73
|
+
out = +""
|
|
74
|
+
str.to_s.each_char do |ch|
|
|
75
|
+
if ch == "\t"
|
|
76
|
+
n = cell_width(ch, col:, tabstop:)
|
|
77
|
+
out << (" " * n)
|
|
78
|
+
col += n
|
|
79
|
+
else
|
|
80
|
+
out << ch
|
|
81
|
+
col += cell_width(ch, col:, tabstop:)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
out
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def ambiguous_width
|
|
88
|
+
env = ::ENV["RUVIM_AMBIGUOUS_WIDTH"]
|
|
89
|
+
if !defined?(@ambiguous_width_cached) || @ambiguous_width_env != env
|
|
90
|
+
@ambiguous_width_env = env
|
|
91
|
+
@ambiguous_width_cached = (env == "2" ? 2 : 1)
|
|
92
|
+
@codepoint_width_cache = {}
|
|
93
|
+
end
|
|
18
94
|
|
|
19
|
-
|
|
95
|
+
@ambiguous_width_cached
|
|
96
|
+
end
|
|
20
97
|
end
|
|
21
98
|
|
|
99
|
+
# Shared helpers (used by pure Ruby path; kept available for tests)
|
|
100
|
+
|
|
22
101
|
def codepoint_cacheable?(code)
|
|
23
102
|
!code.nil? && !code.zero?
|
|
24
103
|
end
|
|
@@ -43,28 +122,6 @@ module RuVim
|
|
|
43
122
|
1
|
|
44
123
|
end
|
|
45
124
|
|
|
46
|
-
def display_width(str, tabstop: 2, start_col: 0)
|
|
47
|
-
col = start_col
|
|
48
|
-
str.to_s.each_char { |ch| col += cell_width(ch, col:, tabstop:) }
|
|
49
|
-
col - start_col
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def expand_tabs(str, tabstop: 2, start_col: 0)
|
|
53
|
-
col = start_col
|
|
54
|
-
out = +""
|
|
55
|
-
str.to_s.each_char do |ch|
|
|
56
|
-
if ch == "\t"
|
|
57
|
-
n = cell_width(ch, col:, tabstop:)
|
|
58
|
-
out << (" " * n)
|
|
59
|
-
col += n
|
|
60
|
-
else
|
|
61
|
-
out << ch
|
|
62
|
-
col += cell_width(ch, col:, tabstop:)
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
out
|
|
66
|
-
end
|
|
67
|
-
|
|
68
125
|
def combining_mark?(code)
|
|
69
126
|
(0x0300..0x036F).cover?(code) ||
|
|
70
127
|
(0x1AB0..0x1AFF).cover?(code) ||
|
|
@@ -74,9 +131,9 @@ module RuVim
|
|
|
74
131
|
end
|
|
75
132
|
|
|
76
133
|
def zero_width_codepoint?(code)
|
|
77
|
-
(0x200D..0x200D).cover?(code) ||
|
|
78
|
-
(0xFE00..0xFE0F).cover?(code) ||
|
|
79
|
-
(0xE0100..0xE01EF).cover?(code)
|
|
134
|
+
(0x200D..0x200D).cover?(code) ||
|
|
135
|
+
(0xFE00..0xFE0F).cover?(code) ||
|
|
136
|
+
(0xE0100..0xE01EF).cover?(code)
|
|
80
137
|
end
|
|
81
138
|
|
|
82
139
|
def wide_codepoint?(code)
|
|
@@ -121,16 +178,5 @@ module RuVim
|
|
|
121
178
|
(0x2460..0x24E9).cover?(code) ||
|
|
122
179
|
(0x2500..0x257F).cover?(code)
|
|
123
180
|
end
|
|
124
|
-
|
|
125
|
-
def ambiguous_width
|
|
126
|
-
env = ::ENV["RUVIM_AMBIGUOUS_WIDTH"]
|
|
127
|
-
if !defined?(@ambiguous_width_cached) || @ambiguous_width_env != env
|
|
128
|
-
@ambiguous_width_env = env
|
|
129
|
-
@ambiguous_width_cached = (env == "2" ? 2 : 1)
|
|
130
|
-
@codepoint_width_cache = {}
|
|
131
|
-
end
|
|
132
|
-
|
|
133
|
-
@ambiguous_width_cached
|
|
134
|
-
end
|
|
135
181
|
end
|
|
136
182
|
end
|
data/lib/ruvim/editor.rb
CHANGED
|
@@ -54,24 +54,12 @@ module RuVim
|
|
|
54
54
|
"filetype" => { default_scope: :buffer, type: :string, default: nil },
|
|
55
55
|
"onsavehook" => { default_scope: :buffer, type: :bool, default: true },
|
|
56
56
|
"grepprg" => { default_scope: :global, type: :string, default: "grep -nH" },
|
|
57
|
-
"grepformat" => { default_scope: :global, type: :string, default: "%f:%l:%m" }
|
|
57
|
+
"grepformat" => { default_scope: :global, type: :string, default: "%f:%l:%m" },
|
|
58
|
+
"runprg" => { default_scope: :buffer, type: :string, default: nil }
|
|
58
59
|
}.freeze
|
|
59
|
-
SHEBANG_FILETYPE_RULES = [
|
|
60
|
-
[/\Aruby(?:\d+(?:\.\d+)*)?\z/, "ruby"],
|
|
61
|
-
[/\Apython(?:\d+(?:\.\d+)*)?\z/, "python"],
|
|
62
|
-
["node", "javascript"],
|
|
63
|
-
["nodejs", "javascript"],
|
|
64
|
-
["deno", "javascript"],
|
|
65
|
-
["bash", "sh"],
|
|
66
|
-
["sh", "sh"],
|
|
67
|
-
["zsh", "sh"],
|
|
68
|
-
["ksh", "sh"],
|
|
69
|
-
["dash", "sh"],
|
|
70
|
-
[/\Aperl(?:\d+(?:\.\d+)*)?\z/, "perl"]
|
|
71
|
-
].freeze
|
|
72
60
|
|
|
73
61
|
attr_reader :buffers, :windows, :layout_tree
|
|
74
|
-
attr_accessor :current_window_id, :mode, :message, :pending_count, :alternate_buffer_id, :restricted_mode, :current_window_view_height_hint, :
|
|
62
|
+
attr_accessor :current_window_id, :mode, :message, :pending_count, :alternate_buffer_id, :restricted_mode, :current_window_view_height_hint, :open_path_handler, :keymap_manager, :app_action_handler, :git_stream_handler, :git_stream_stop_handler, :shell_executor, :run_stream_handler
|
|
75
63
|
|
|
76
64
|
def initialize
|
|
77
65
|
@buffers = {}
|
|
@@ -93,7 +81,6 @@ module RuVim
|
|
|
93
81
|
@restricted_mode = false
|
|
94
82
|
@current_window_view_height_hint = 1
|
|
95
83
|
@running = true
|
|
96
|
-
@stdin_stream_stop_handler = nil
|
|
97
84
|
@open_path_handler = nil
|
|
98
85
|
@keymap_manager = nil
|
|
99
86
|
@app_action_handler = nil
|
|
@@ -117,6 +104,8 @@ module RuVim
|
|
|
117
104
|
@arglist = []
|
|
118
105
|
@arglist_index = 0
|
|
119
106
|
@hit_enter_lines = nil
|
|
107
|
+
@run_history = {} # buffer_id => last run command (unexpanded)
|
|
108
|
+
@run_output_buffer_id = nil
|
|
120
109
|
end
|
|
121
110
|
|
|
122
111
|
def running?
|
|
@@ -131,6 +120,18 @@ module RuVim
|
|
|
131
120
|
@running = false
|
|
132
121
|
end
|
|
133
122
|
|
|
123
|
+
def run_history
|
|
124
|
+
@run_history
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def run_output_buffer_id
|
|
128
|
+
@run_output_buffer_id
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def run_output_buffer_id=(id)
|
|
132
|
+
@run_output_buffer_id = id
|
|
133
|
+
end
|
|
134
|
+
|
|
134
135
|
def command_line
|
|
135
136
|
@command_line
|
|
136
137
|
end
|
|
@@ -152,7 +153,7 @@ module RuVim
|
|
|
152
153
|
end
|
|
153
154
|
|
|
154
155
|
def set_last_search(pattern:, direction:)
|
|
155
|
-
@last_search = { pattern: pattern
|
|
156
|
+
@last_search = { pattern: pattern, direction: direction }
|
|
156
157
|
@hlsearch_suppressed = false
|
|
157
158
|
end
|
|
158
159
|
|
|
@@ -165,7 +166,7 @@ module RuVim
|
|
|
165
166
|
end
|
|
166
167
|
|
|
167
168
|
def set_last_find(char:, direction:, till:)
|
|
168
|
-
@last_find = { char: char
|
|
169
|
+
@last_find = { char: char, direction: direction, till: !!till }
|
|
169
170
|
end
|
|
170
171
|
|
|
171
172
|
def current_window
|
|
@@ -176,19 +177,18 @@ module RuVim
|
|
|
176
177
|
@buffers.fetch(current_window.buffer_id)
|
|
177
178
|
end
|
|
178
179
|
|
|
179
|
-
def
|
|
180
|
-
handler =
|
|
180
|
+
def stream_stop_or_cancel!
|
|
181
|
+
handler = current_buffer&.stream&.stop_handler
|
|
181
182
|
return false unless handler
|
|
182
183
|
|
|
183
184
|
handler.call
|
|
184
|
-
true
|
|
185
185
|
end
|
|
186
186
|
|
|
187
187
|
def invoke_app_action(name, **kwargs)
|
|
188
188
|
handler = @app_action_handler
|
|
189
189
|
return false unless handler
|
|
190
190
|
|
|
191
|
-
handler.call(name
|
|
191
|
+
handler.call(name, **kwargs)
|
|
192
192
|
true
|
|
193
193
|
end
|
|
194
194
|
|
|
@@ -213,7 +213,7 @@ module RuVim
|
|
|
213
213
|
|
|
214
214
|
def get_option(name, scope: :effective, window: current_window, buffer: current_buffer)
|
|
215
215
|
key = name.to_s
|
|
216
|
-
case scope
|
|
216
|
+
case scope
|
|
217
217
|
when :global
|
|
218
218
|
@global_options[key]
|
|
219
219
|
when :buffer
|
|
@@ -228,7 +228,7 @@ module RuVim
|
|
|
228
228
|
def set_option(name, value, scope: :auto, window: current_window, buffer: current_buffer)
|
|
229
229
|
key = name.to_s
|
|
230
230
|
value = coerce_option_value(key, value)
|
|
231
|
-
actual_scope = (scope
|
|
231
|
+
actual_scope = (scope == :auto ? option_default_scope(key) : scope)
|
|
232
232
|
case actual_scope
|
|
233
233
|
when :global
|
|
234
234
|
@global_options[key] = value
|
|
@@ -262,34 +262,13 @@ module RuVim
|
|
|
262
262
|
return nil if p.empty?
|
|
263
263
|
|
|
264
264
|
base = File.basename(p)
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
".js" => "javascript",
|
|
273
|
-
".mjs" => "javascript",
|
|
274
|
-
".cjs" => "javascript",
|
|
275
|
-
".ts" => "typescript",
|
|
276
|
-
".tsx" => "typescriptreact",
|
|
277
|
-
".jsx" => "javascriptreact",
|
|
278
|
-
".json" => "json",
|
|
279
|
-
".jsonl" => "jsonl",
|
|
280
|
-
".yml" => "yaml",
|
|
281
|
-
".yaml" => "yaml",
|
|
282
|
-
".md" => "markdown",
|
|
283
|
-
".txt" => "text",
|
|
284
|
-
".html" => "html",
|
|
285
|
-
".css" => "css",
|
|
286
|
-
".sh" => "sh",
|
|
287
|
-
".tsv" => "tsv",
|
|
288
|
-
".csv" => "csv",
|
|
289
|
-
".scm" => "scheme",
|
|
290
|
-
".ss" => "scheme",
|
|
291
|
-
".sld" => "scheme"
|
|
292
|
-
}[File.extname(base).downcase]
|
|
265
|
+
|
|
266
|
+
# Basename-based detection (exact match, then prefix)
|
|
267
|
+
base_ft = Lang::Registry.detect_by_basename(base)
|
|
268
|
+
return base_ft if base_ft
|
|
269
|
+
|
|
270
|
+
# Extension-based detection
|
|
271
|
+
ext_ft = Lang::Registry.detect_by_extension(File.extname(base))
|
|
293
272
|
return ext_ft if ext_ft
|
|
294
273
|
|
|
295
274
|
detect_filetype_from_shebang(p)
|
|
@@ -301,9 +280,9 @@ module RuVim
|
|
|
301
280
|
|
|
302
281
|
def set_register(name = "\"", text:, type: :charwise)
|
|
303
282
|
key = name.to_s
|
|
304
|
-
return { text: text
|
|
283
|
+
return { text: text, type: type } if key == "_"
|
|
305
284
|
|
|
306
|
-
payload = write_register_payload(key, text: text
|
|
285
|
+
payload = write_register_payload(key, text: text, type: type)
|
|
307
286
|
write_clipboard_register(key, payload)
|
|
308
287
|
if key == "\""
|
|
309
288
|
if (default_clip = clipboard_default_register_key)
|
|
@@ -316,14 +295,14 @@ module RuVim
|
|
|
316
295
|
end
|
|
317
296
|
|
|
318
297
|
def store_operator_register(name = "\"", text:, type:, kind:)
|
|
319
|
-
key = (name || "\"")
|
|
320
|
-
payload = { text: text
|
|
298
|
+
key = (name || "\"")
|
|
299
|
+
payload = { text: text, type: type }
|
|
321
300
|
return payload if key == "_"
|
|
322
301
|
|
|
323
302
|
written = set_register(key, text: payload[:text], type: payload[:type])
|
|
324
303
|
op_payload = dup_register_payload(written)
|
|
325
304
|
|
|
326
|
-
case kind
|
|
305
|
+
case kind
|
|
327
306
|
when :yank
|
|
328
307
|
@registers["0"] = dup_register_payload(op_payload)
|
|
329
308
|
when :delete, :change
|
|
@@ -485,9 +464,9 @@ module RuVim
|
|
|
485
464
|
end
|
|
486
465
|
|
|
487
466
|
def enter_visual(mode)
|
|
488
|
-
@mode = mode
|
|
467
|
+
@mode = mode
|
|
489
468
|
@visual_state = {
|
|
490
|
-
mode: mode
|
|
469
|
+
mode: mode,
|
|
491
470
|
anchor_y: current_window.cursor_y,
|
|
492
471
|
anchor_x: current_window.cursor_x
|
|
493
472
|
}
|
|
@@ -645,10 +624,10 @@ module RuVim
|
|
|
645
624
|
win.row_offset = src.row_offset
|
|
646
625
|
win.col_offset = src.col_offset
|
|
647
626
|
|
|
648
|
-
split_type = (layout
|
|
627
|
+
split_type = (layout == :vertical ? :vsplit : :hsplit)
|
|
649
628
|
new_leaf = { type: :window, id: win.id }
|
|
650
629
|
|
|
651
|
-
@layout_tree = tree_split_leaf(@layout_tree, src.id, split_type, new_leaf, place
|
|
630
|
+
@layout_tree = tree_split_leaf(@layout_tree, src.id, split_type, new_leaf, place)
|
|
652
631
|
|
|
653
632
|
@current_window_id = win.id
|
|
654
633
|
save_current_tabpage_state! unless @suspend_tab_autosave
|
|
@@ -849,8 +828,7 @@ module RuVim
|
|
|
849
828
|
end
|
|
850
829
|
|
|
851
830
|
def delete_buffer(buffer_id)
|
|
852
|
-
|
|
853
|
-
buffer = @buffers[id]
|
|
831
|
+
buffer = @buffers[buffer_id]
|
|
854
832
|
return nil unless buffer
|
|
855
833
|
|
|
856
834
|
if @buffers.length <= 1
|
|
@@ -863,13 +841,13 @@ module RuVim
|
|
|
863
841
|
if replacement
|
|
864
842
|
replacement.id
|
|
865
843
|
else
|
|
866
|
-
candidates = @buffers.keys.reject { |bid| bid ==
|
|
844
|
+
candidates = @buffers.keys.reject { |bid| bid == buffer_id }
|
|
867
845
|
alt = @alternate_buffer_id
|
|
868
|
-
(alt && alt !=
|
|
846
|
+
(alt && alt != buffer_id && @buffers.key?(alt)) ? alt : candidates.first
|
|
869
847
|
end
|
|
870
848
|
|
|
871
849
|
@windows.each_value do |win|
|
|
872
|
-
next unless win.buffer_id ==
|
|
850
|
+
next unless win.buffer_id == buffer_id
|
|
873
851
|
next unless fallback_id
|
|
874
852
|
|
|
875
853
|
win.buffer_id = fallback_id
|
|
@@ -879,9 +857,9 @@ module RuVim
|
|
|
879
857
|
win.col_offset = 0
|
|
880
858
|
end
|
|
881
859
|
|
|
882
|
-
@buffers.delete(
|
|
883
|
-
@local_marks.delete(
|
|
884
|
-
@alternate_buffer_id = nil if @alternate_buffer_id ==
|
|
860
|
+
@buffers.delete(buffer_id)
|
|
861
|
+
@local_marks.delete(buffer_id)
|
|
862
|
+
@alternate_buffer_id = nil if @alternate_buffer_id == buffer_id
|
|
885
863
|
save_current_tabpage_state! unless @suspend_tab_autosave
|
|
886
864
|
ensure_bootstrap_buffer! if @buffers.empty?
|
|
887
865
|
true
|
|
@@ -1023,11 +1001,10 @@ module RuVim
|
|
|
1023
1001
|
end
|
|
1024
1002
|
|
|
1025
1003
|
def find_window_ids_by_buffer_kind(kind)
|
|
1026
|
-
sym = kind.to_sym
|
|
1027
1004
|
window_order.select do |wid|
|
|
1028
1005
|
win = @windows[wid]
|
|
1029
1006
|
buf = win && @buffers[win.buffer_id]
|
|
1030
|
-
buf && buf.kind ==
|
|
1007
|
+
buf && buf.kind == kind
|
|
1031
1008
|
end
|
|
1032
1009
|
end
|
|
1033
1010
|
|
|
@@ -1165,15 +1142,24 @@ module RuVim
|
|
|
1165
1142
|
def assign_filetype(buffer, ft)
|
|
1166
1143
|
buffer.options["filetype"] = ft
|
|
1167
1144
|
buffer.lang_module = resolve_lang_module(ft)
|
|
1145
|
+
apply_filetype_defaults(buffer, ft)
|
|
1146
|
+
end
|
|
1147
|
+
|
|
1148
|
+
def apply_filetype_defaults(buffer, ft)
|
|
1149
|
+
unless buffer.options.key?("runprg")
|
|
1150
|
+
runprg = filetype_default_runprg(ft)
|
|
1151
|
+
buffer.options["runprg"] = runprg if runprg
|
|
1152
|
+
end
|
|
1153
|
+
end
|
|
1154
|
+
|
|
1155
|
+
def filetype_default_runprg(ft)
|
|
1156
|
+
Lang::Registry.runprg_for(ft)
|
|
1168
1157
|
end
|
|
1169
1158
|
|
|
1170
1159
|
private
|
|
1171
1160
|
|
|
1172
1161
|
def resolve_lang_module(ft)
|
|
1173
|
-
|
|
1174
|
-
when "ruby" then Lang::Ruby
|
|
1175
|
-
else Lang::Base
|
|
1176
|
-
end
|
|
1162
|
+
Lang::Registry.resolve_module(ft)
|
|
1177
1163
|
end
|
|
1178
1164
|
|
|
1179
1165
|
def detect_filetype_from_shebang(path)
|
|
@@ -1183,10 +1169,7 @@ module RuVim
|
|
|
1183
1169
|
cmd = shebang_command_name(line)
|
|
1184
1170
|
return nil if cmd.nil? || cmd.empty?
|
|
1185
1171
|
|
|
1186
|
-
|
|
1187
|
-
matcher.is_a?(Regexp) ? matcher.match?(cmd) : matcher.to_s == cmd
|
|
1188
|
-
end
|
|
1189
|
-
rule && rule[1]
|
|
1172
|
+
Lang::Registry.detect_by_shebang(cmd)
|
|
1190
1173
|
rescue StandardError
|
|
1191
1174
|
nil
|
|
1192
1175
|
end
|
|
@@ -1222,7 +1205,7 @@ module RuVim
|
|
|
1222
1205
|
prog = tokens[i].to_s
|
|
1223
1206
|
end
|
|
1224
1207
|
|
|
1225
|
-
File.basename(prog
|
|
1208
|
+
File.basename(prog)
|
|
1226
1209
|
end
|
|
1227
1210
|
|
|
1228
1211
|
def default_global_options
|
|
@@ -1277,7 +1260,7 @@ module RuVim
|
|
|
1277
1260
|
def dup_register_payload(payload)
|
|
1278
1261
|
return nil unless payload
|
|
1279
1262
|
|
|
1280
|
-
{ text: payload[:text].
|
|
1263
|
+
{ text: payload[:text].dup, type: payload[:type] }
|
|
1281
1264
|
end
|
|
1282
1265
|
|
|
1283
1266
|
def assign_detected_filetype(buffer)
|
|
@@ -9,6 +9,7 @@ module RuVim
|
|
|
9
9
|
:desc,
|
|
10
10
|
:nargs,
|
|
11
11
|
:bang,
|
|
12
|
+
:raw_args,
|
|
12
13
|
:source,
|
|
13
14
|
keyword_init: true
|
|
14
15
|
)
|
|
@@ -20,7 +21,7 @@ module RuVim
|
|
|
20
21
|
@lookup = {}
|
|
21
22
|
end
|
|
22
23
|
|
|
23
|
-
def register(name, call:, aliases: [], desc: "", nargs: :any, bang: false, source: :builtin)
|
|
24
|
+
def register(name, call:, aliases: [], desc: "", nargs: :any, bang: false, raw_args: false, source: :builtin)
|
|
24
25
|
canonical = name.to_s
|
|
25
26
|
if @specs.key?(canonical)
|
|
26
27
|
raise RuVim::CommandError, "Ex command already exists: #{canonical}"
|
|
@@ -32,6 +33,7 @@ module RuVim
|
|
|
32
33
|
desc: desc,
|
|
33
34
|
nargs: nargs,
|
|
34
35
|
bang: bang,
|
|
36
|
+
raw_args: raw_args,
|
|
35
37
|
source: source
|
|
36
38
|
)
|
|
37
39
|
|