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/keymap_manager.rb
CHANGED
|
@@ -14,7 +14,7 @@ module RuVim
|
|
|
14
14
|
|
|
15
15
|
def bind(mode, seq, id, argv: [], kwargs: {}, bang: false)
|
|
16
16
|
tokens = normalize_seq(seq)
|
|
17
|
-
@mode_maps[mode
|
|
17
|
+
@mode_maps[mode][tokens] = build_invocation(id, argv:, kwargs:, bang:, tokens:)
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
def bind_global(seq, id, argv: [], kwargs: {}, bang: false)
|
|
@@ -29,20 +29,20 @@ module RuVim
|
|
|
29
29
|
|
|
30
30
|
def bind_filetype(filetype, seq, id, mode: :normal, argv: [], kwargs: {}, bang: false)
|
|
31
31
|
tokens = normalize_seq(seq)
|
|
32
|
-
@filetype_maps[filetype.to_s][mode
|
|
32
|
+
@filetype_maps[filetype.to_s][mode][tokens] = build_invocation(id, argv:, kwargs:, bang:, tokens:)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def resolve(mode, pending_tokens)
|
|
36
|
-
resolve_layers([@mode_maps[mode
|
|
36
|
+
resolve_layers([@mode_maps[mode]], pending_tokens)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def resolve_with_context(mode, pending_tokens, editor:)
|
|
40
40
|
buffer = editor.current_buffer
|
|
41
41
|
filetype = detect_filetype(buffer)
|
|
42
42
|
layers = []
|
|
43
|
-
layers << @filetype_maps[filetype][mode
|
|
43
|
+
layers << @filetype_maps[filetype][mode] if filetype && @filetype_maps.key?(filetype)
|
|
44
44
|
layers << @buffer_maps[buffer.id] if @buffer_maps.key?(buffer.id)
|
|
45
|
-
layers << @mode_maps[mode
|
|
45
|
+
layers << @mode_maps[mode]
|
|
46
46
|
layers << @global_map
|
|
47
47
|
resolve_layers(layers, pending_tokens)
|
|
48
48
|
end
|
|
@@ -135,7 +135,7 @@ module RuVim
|
|
|
135
135
|
def normalized_mode_filter(mode)
|
|
136
136
|
return nil if mode.nil?
|
|
137
137
|
|
|
138
|
-
ary = Array(mode).compact
|
|
138
|
+
ary = Array(mode).compact
|
|
139
139
|
ary.empty? ? nil : ary
|
|
140
140
|
end
|
|
141
141
|
|
|
@@ -153,7 +153,7 @@ module RuVim
|
|
|
153
153
|
operator_pending: 5,
|
|
154
154
|
command_line: 6
|
|
155
155
|
}
|
|
156
|
-
[order.fetch(mode
|
|
156
|
+
[order.fetch(mode, 99), mode.to_s]
|
|
157
157
|
end
|
|
158
158
|
|
|
159
159
|
def detect_filetype(buffer)
|
data/lib/ruvim/lang/base.rb
CHANGED
|
@@ -21,5 +21,10 @@ module RuVim
|
|
|
21
21
|
# no-op
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
|
+
|
|
25
|
+
# Non-highlighted filetypes (extension-only detection)
|
|
26
|
+
Registry.register("text", mod: Base, extensions: %w[.txt])
|
|
27
|
+
Registry.register("css", mod: Base, extensions: %w[.css])
|
|
28
|
+
Registry.register("erlang", mod: Base, extensions: %w[.erl])
|
|
24
29
|
end
|
|
25
30
|
end
|
data/lib/ruvim/lang/c.rb
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
5
|
+
module RuVim
|
|
6
|
+
module Lang
|
|
7
|
+
module C
|
|
8
|
+
KEYWORDS = %w[
|
|
9
|
+
if else for while return struct enum typedef switch case break
|
|
10
|
+
continue do static const extern unsigned signed sizeof union
|
|
11
|
+
goto default volatile register inline restrict
|
|
12
|
+
].freeze
|
|
13
|
+
|
|
14
|
+
TYPES = %w[
|
|
15
|
+
int char float double long short void size_t
|
|
16
|
+
uint8_t uint16_t uint32_t uint64_t
|
|
17
|
+
int8_t int16_t int32_t int64_t
|
|
18
|
+
ssize_t ptrdiff_t intptr_t uintptr_t
|
|
19
|
+
bool FILE
|
|
20
|
+
].freeze
|
|
21
|
+
|
|
22
|
+
ALL_KEYWORDS = (KEYWORDS + TYPES).uniq.freeze
|
|
23
|
+
|
|
24
|
+
KEYWORD_RE = /\b(?:#{ALL_KEYWORDS.join("|")})\b/
|
|
25
|
+
STRING_RE = /"(?:\\.|[^"\\])*"/
|
|
26
|
+
CHAR_RE = /'(?:\\.|[^'\\])'/
|
|
27
|
+
NUMBER_RE = /\b(?:0[xX][0-9a-fA-F]+|0[bB][01]+|\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)[fFlLuU]*\b/
|
|
28
|
+
LINE_COMMENT_RE = %r{//.*}
|
|
29
|
+
BLOCK_COMMENT_RE = %r{/\*.*?\*/}
|
|
30
|
+
PREPROCESSOR_RE = /\A\s*#\s*\w+.*/
|
|
31
|
+
CONSTANT_RE = /\b[A-Z][A-Z0-9_]{1,}\b/
|
|
32
|
+
|
|
33
|
+
INDENT_OPEN_RE = /\{\s*$/
|
|
34
|
+
INDENT_CLOSE_RE = /\A\s*\}/
|
|
35
|
+
CASE_RE = /\A\s*(?:case\b.*:|default\s*:)/
|
|
36
|
+
|
|
37
|
+
DEDENT_TRIGGERS = {
|
|
38
|
+
"}" => /\A(\s*)\}/
|
|
39
|
+
}.freeze
|
|
40
|
+
|
|
41
|
+
module_function
|
|
42
|
+
|
|
43
|
+
def calculate_indent(lines, target_row, shiftwidth)
|
|
44
|
+
depth = 0
|
|
45
|
+
(0...target_row).each do |row|
|
|
46
|
+
line = lines[row].to_s
|
|
47
|
+
line.each_char do |ch|
|
|
48
|
+
case ch
|
|
49
|
+
when "{" then depth += 1
|
|
50
|
+
when "}" then depth -= 1
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
target_line = lines[target_row].to_s.lstrip
|
|
56
|
+
depth -= 1 if target_line.match?(INDENT_CLOSE_RE)
|
|
57
|
+
depth -= 1 if target_line.match?(CASE_RE) && depth > 0
|
|
58
|
+
depth = 0 if depth < 0
|
|
59
|
+
depth * shiftwidth
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def indent_trigger?(line)
|
|
63
|
+
line.to_s.rstrip.match?(INDENT_OPEN_RE)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def dedent_trigger(char)
|
|
67
|
+
DEDENT_TRIGGERS[char]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def on_save(ctx, path)
|
|
71
|
+
return unless path && File.exist?(path)
|
|
72
|
+
return if ctx.editor.respond_to?(:restricted_mode?) && ctx.editor.restricted_mode?
|
|
73
|
+
|
|
74
|
+
gcc = ENV["CC"] || "gcc"
|
|
75
|
+
begin
|
|
76
|
+
output, status = Open3.capture2e(gcc, "-fsyntax-only", "-Wall", path)
|
|
77
|
+
rescue Errno::ENOENT
|
|
78
|
+
return
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if !status.success?
|
|
82
|
+
buffer_id = ctx.buffer.id
|
|
83
|
+
items = output.lines.filter_map { |line|
|
|
84
|
+
if line =~ /\A.+?:(\d+):\d+:/
|
|
85
|
+
{ buffer_id: buffer_id, row: $1.to_i - 1, col: 0, text: line.strip }
|
|
86
|
+
end
|
|
87
|
+
}
|
|
88
|
+
items = [{ buffer_id: buffer_id, row: 0, col: 0, text: output.strip }] if items.empty?
|
|
89
|
+
ctx.editor.set_quickfix_list(items)
|
|
90
|
+
first = output.lines.first.to_s.strip
|
|
91
|
+
hint = items.size > 1 ? " (Q to see all, #{items.size} total)" : ""
|
|
92
|
+
ctx.editor.echo_error("#{first}#{hint}")
|
|
93
|
+
else
|
|
94
|
+
ctx.editor.set_quickfix_list([])
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def color_columns(text)
|
|
99
|
+
cols = {}
|
|
100
|
+
Highlighter.apply_regex(cols, text, CHAR_RE, Highlighter::STRING_COLOR)
|
|
101
|
+
Highlighter.apply_regex(cols, text, STRING_RE, Highlighter::STRING_COLOR)
|
|
102
|
+
Highlighter.apply_regex(cols, text, KEYWORD_RE, Highlighter::KEYWORD_COLOR)
|
|
103
|
+
Highlighter.apply_regex(cols, text, NUMBER_RE, Highlighter::NUMBER_COLOR)
|
|
104
|
+
Highlighter.apply_regex(cols, text, CONSTANT_RE, Highlighter::CONSTANT_COLOR)
|
|
105
|
+
Highlighter.apply_regex(cols, text, PREPROCESSOR_RE, "\e[35m")
|
|
106
|
+
Highlighter.apply_regex(cols, text, BLOCK_COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
107
|
+
Highlighter.apply_regex(cols, text, LINE_COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
108
|
+
cols
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
Registry.register("c", mod: C,
|
|
113
|
+
extensions: %w[.c .h],
|
|
114
|
+
runprg: "gcc -Wall -o /tmp/a.out % && /tmp/a.out")
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "open3"
|
|
4
|
+
|
|
5
|
+
module RuVim
|
|
6
|
+
module Lang
|
|
7
|
+
module Cpp
|
|
8
|
+
CPP_KEYWORDS = %w[
|
|
9
|
+
class namespace template typename virtual override final
|
|
10
|
+
public private protected friend
|
|
11
|
+
new delete dynamic_cast static_cast reinterpret_cast const_cast
|
|
12
|
+
try catch throw noexcept
|
|
13
|
+
using auto decltype nullptr constexpr consteval constinit
|
|
14
|
+
concept requires co_await co_return co_yield
|
|
15
|
+
mutable explicit export
|
|
16
|
+
].freeze
|
|
17
|
+
|
|
18
|
+
CPP_TYPES = %w[
|
|
19
|
+
string vector map set list deque array
|
|
20
|
+
shared_ptr unique_ptr weak_ptr
|
|
21
|
+
string_view optional variant any
|
|
22
|
+
wchar_t char8_t char16_t char32_t
|
|
23
|
+
].freeze
|
|
24
|
+
|
|
25
|
+
ALL_KEYWORDS = (C::ALL_KEYWORDS + CPP_KEYWORDS + CPP_TYPES).uniq.freeze
|
|
26
|
+
|
|
27
|
+
KEYWORD_RE = /\b(?:#{ALL_KEYWORDS.join("|")})\b/
|
|
28
|
+
|
|
29
|
+
ACCESS_RE = /\A\s*(?:public|private|protected)\s*:/
|
|
30
|
+
|
|
31
|
+
module_function
|
|
32
|
+
|
|
33
|
+
def calculate_indent(lines, target_row, shiftwidth)
|
|
34
|
+
depth = 0
|
|
35
|
+
(0...target_row).each do |row|
|
|
36
|
+
line = lines[row].to_s
|
|
37
|
+
line.each_char do |ch|
|
|
38
|
+
case ch
|
|
39
|
+
when "{" then depth += 1
|
|
40
|
+
when "}" then depth -= 1
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
target_line = lines[target_row].to_s.lstrip
|
|
46
|
+
depth -= 1 if target_line.match?(C::INDENT_CLOSE_RE)
|
|
47
|
+
depth -= 1 if target_line.match?(C::CASE_RE) && depth > 0
|
|
48
|
+
depth -= 1 if target_line.match?(ACCESS_RE) && depth > 0
|
|
49
|
+
depth = 0 if depth < 0
|
|
50
|
+
depth * shiftwidth
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def indent_trigger?(line)
|
|
54
|
+
C.indent_trigger?(line)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def dedent_trigger(char)
|
|
58
|
+
C.dedent_trigger(char)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def on_save(ctx, path)
|
|
62
|
+
return unless path && File.exist?(path)
|
|
63
|
+
return if ctx.editor.respond_to?(:restricted_mode?) && ctx.editor.restricted_mode?
|
|
64
|
+
|
|
65
|
+
compiler = ENV["CXX"] || "g++"
|
|
66
|
+
begin
|
|
67
|
+
output, status = Open3.capture2e(compiler, "-fsyntax-only", "-Wall", path)
|
|
68
|
+
rescue Errno::ENOENT
|
|
69
|
+
return
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
if !status.success?
|
|
73
|
+
buffer_id = ctx.buffer.id
|
|
74
|
+
items = output.lines.filter_map { |line|
|
|
75
|
+
if line =~ /\A.+?:(\d+):\d+:/
|
|
76
|
+
{ buffer_id: buffer_id, row: $1.to_i - 1, col: 0, text: line.strip }
|
|
77
|
+
end
|
|
78
|
+
}
|
|
79
|
+
items = [{ buffer_id: buffer_id, row: 0, col: 0, text: output.strip }] if items.empty?
|
|
80
|
+
ctx.editor.set_quickfix_list(items)
|
|
81
|
+
first = output.lines.first.to_s.strip
|
|
82
|
+
hint = items.size > 1 ? " (Q to see all, #{items.size} total)" : ""
|
|
83
|
+
ctx.editor.echo_error("#{first}#{hint}")
|
|
84
|
+
else
|
|
85
|
+
ctx.editor.set_quickfix_list([])
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def color_columns(text)
|
|
90
|
+
cols = {}
|
|
91
|
+
Highlighter.apply_regex(cols, text, C::CHAR_RE, Highlighter::STRING_COLOR)
|
|
92
|
+
Highlighter.apply_regex(cols, text, C::STRING_RE, Highlighter::STRING_COLOR)
|
|
93
|
+
Highlighter.apply_regex(cols, text, KEYWORD_RE, Highlighter::KEYWORD_COLOR)
|
|
94
|
+
Highlighter.apply_regex(cols, text, C::NUMBER_RE, Highlighter::NUMBER_COLOR)
|
|
95
|
+
Highlighter.apply_regex(cols, text, C::CONSTANT_RE, Highlighter::CONSTANT_COLOR)
|
|
96
|
+
Highlighter.apply_regex(cols, text, C::PREPROCESSOR_RE, "\e[35m")
|
|
97
|
+
Highlighter.apply_regex(cols, text, C::BLOCK_COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
98
|
+
Highlighter.apply_regex(cols, text, C::LINE_COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
99
|
+
cols
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
Registry.register("cpp", mod: Cpp,
|
|
104
|
+
extensions: %w[.cpp .cc .cxx .hpp],
|
|
105
|
+
runprg: "g++ -Wall -o /tmp/a.out % && /tmp/a.out")
|
|
106
|
+
end
|
|
107
|
+
end
|
data/lib/ruvim/lang/csv.rb
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
module RuVim
|
|
4
4
|
module Lang
|
|
5
|
+
Registry.register("csv", mod: Base,
|
|
6
|
+
extensions: %w[.csv])
|
|
7
|
+
|
|
5
8
|
module Csv
|
|
6
9
|
module_function
|
|
7
10
|
|
|
@@ -14,5 +17,5 @@ module RuVim
|
|
|
14
17
|
end
|
|
15
18
|
end
|
|
16
19
|
|
|
17
|
-
RichView.register(
|
|
20
|
+
RichView.register(:csv, RichView::TableRenderer, detector: Lang::Csv.method(:detect?))
|
|
18
21
|
end
|
data/lib/ruvim/lang/diff.rb
CHANGED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuVim
|
|
4
|
+
module Lang
|
|
5
|
+
module Dockerfile
|
|
6
|
+
INSTRUCTIONS = %w[
|
|
7
|
+
FROM AS RUN CMD EXPOSE ENV ADD COPY ENTRYPOINT VOLUME
|
|
8
|
+
USER WORKDIR ARG ONBUILD STOPSIGNAL HEALTHCHECK SHELL LABEL MAINTAINER
|
|
9
|
+
].freeze
|
|
10
|
+
|
|
11
|
+
INSTRUCTION_RE = /\A\s*(?:#{INSTRUCTIONS.join("|")})\b/i
|
|
12
|
+
STRING_DOUBLE_RE = /"(?:\\.|[^"\\])*"/
|
|
13
|
+
STRING_SINGLE_RE = /'(?:\\.|[^'\\])*'/
|
|
14
|
+
VARIABLE_RE = /\$\{?[\w]+\}?/
|
|
15
|
+
COMMENT_RE = /\A\s*#.*/
|
|
16
|
+
FLAG_RE = /--[\w\-]+=?/
|
|
17
|
+
|
|
18
|
+
module_function
|
|
19
|
+
|
|
20
|
+
def color_columns(text)
|
|
21
|
+
cols = {}
|
|
22
|
+
Highlighter.apply_regex(cols, text, INSTRUCTION_RE, Highlighter::KEYWORD_COLOR)
|
|
23
|
+
Highlighter.apply_regex(cols, text, FLAG_RE, Highlighter::CONSTANT_COLOR)
|
|
24
|
+
Highlighter.apply_regex(cols, text, STRING_DOUBLE_RE, Highlighter::STRING_COLOR)
|
|
25
|
+
Highlighter.apply_regex(cols, text, STRING_SINGLE_RE, Highlighter::STRING_COLOR)
|
|
26
|
+
Highlighter.apply_regex(cols, text, VARIABLE_RE, Highlighter::VARIABLE_COLOR)
|
|
27
|
+
Highlighter.apply_regex(cols, text, COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
28
|
+
cols
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
Registry.register("dockerfile", mod: Dockerfile,
|
|
33
|
+
basenames: %w[Dockerfile],
|
|
34
|
+
basename_prefix: "Dockerfile")
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuVim
|
|
4
|
+
module Lang
|
|
5
|
+
module Elixir
|
|
6
|
+
KEYWORDS = %w[
|
|
7
|
+
def defp defmodule defmacro defmacrop defstruct defprotocol defimpl
|
|
8
|
+
defguard defguardp defdelegate defoverridable defexception
|
|
9
|
+
do end fn if else unless cond case when with for receive after
|
|
10
|
+
raise rescue try catch throw
|
|
11
|
+
import use alias require
|
|
12
|
+
and or not in
|
|
13
|
+
true false nil
|
|
14
|
+
quote unquote
|
|
15
|
+
].freeze
|
|
16
|
+
|
|
17
|
+
KEYWORD_RE = /\b(?:#{KEYWORDS.join("|")})\b/
|
|
18
|
+
STRING_DOUBLE_RE = /"(?:\\.|[^"\\])*"/
|
|
19
|
+
STRING_SINGLE_RE = /'(?:\\.|[^'\\])*'/
|
|
20
|
+
HEREDOC_RE = /"""/
|
|
21
|
+
SIGIL_RE = /~[a-zA-Z](?:\(.*?\)|\[.*?\]|\{.*?\}|<.*?>|\/.*?\/|".*?"|\|.*?\|)/
|
|
22
|
+
ATOM_RE = /:\w+|:"(?:\\.|[^"\\])*"/
|
|
23
|
+
MODULE_RE = /\b[A-Z]\w*(?:\.[A-Z]\w*)*/
|
|
24
|
+
NUMBER_RE = /\b(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:\.[\d_]+)?(?:[eE][+-]?\d+)?)\b/
|
|
25
|
+
COMMENT_RE = /#.*/
|
|
26
|
+
VARIABLE_RE = /@\w+/
|
|
27
|
+
|
|
28
|
+
INDENT_OPEN_RE = /\b(?:do|fn)\s*(?:->)?\s*$/
|
|
29
|
+
INDENT_CLOSE_RE = /\A\s*end\b/
|
|
30
|
+
INDENT_MID_RE = /\A\s*(?:else|rescue|catch|after)\b/
|
|
31
|
+
|
|
32
|
+
DEDENT_TRIGGERS = {
|
|
33
|
+
"d" => /\A(\s*)end\z/,
|
|
34
|
+
"e" => /\A(\s*)(?:else|rescue)\z/,
|
|
35
|
+
"h" => /\A(\s*)catch\z/,
|
|
36
|
+
"r" => /\A(\s*)after\z/
|
|
37
|
+
}.freeze
|
|
38
|
+
|
|
39
|
+
module_function
|
|
40
|
+
|
|
41
|
+
def calculate_indent(lines, target_row, shiftwidth)
|
|
42
|
+
depth = 0
|
|
43
|
+
(0...target_row).each do |row|
|
|
44
|
+
line = lines[row].to_s.strip
|
|
45
|
+
next if line.empty? || line.start_with?("#")
|
|
46
|
+
|
|
47
|
+
depth += 1 if line.match?(/\b(?:do|fn)\b/) || line.match?(/->$/)
|
|
48
|
+
depth -= 1 if line.match?(/\Aend\b/)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
target_line = lines[target_row].to_s.strip
|
|
52
|
+
depth -= 1 if target_line.match?(INDENT_CLOSE_RE) || target_line.match?(INDENT_MID_RE)
|
|
53
|
+
depth = 0 if depth < 0
|
|
54
|
+
depth * shiftwidth
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def indent_trigger?(line)
|
|
58
|
+
line.to_s.rstrip.match?(INDENT_OPEN_RE)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def dedent_trigger(char)
|
|
62
|
+
DEDENT_TRIGGERS[char]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def color_columns(text)
|
|
66
|
+
cols = {}
|
|
67
|
+
Highlighter.apply_regex(cols, text, STRING_DOUBLE_RE, Highlighter::STRING_COLOR)
|
|
68
|
+
Highlighter.apply_regex(cols, text, STRING_SINGLE_RE, Highlighter::STRING_COLOR)
|
|
69
|
+
Highlighter.apply_regex(cols, text, ATOM_RE, Highlighter::CONSTANT_COLOR)
|
|
70
|
+
Highlighter.apply_regex(cols, text, KEYWORD_RE, Highlighter::KEYWORD_COLOR)
|
|
71
|
+
Highlighter.apply_regex(cols, text, MODULE_RE, Highlighter::CONSTANT_COLOR)
|
|
72
|
+
Highlighter.apply_regex(cols, text, VARIABLE_RE, Highlighter::VARIABLE_COLOR)
|
|
73
|
+
Highlighter.apply_regex(cols, text, NUMBER_RE, Highlighter::NUMBER_COLOR)
|
|
74
|
+
Highlighter.apply_regex(cols, text, SIGIL_RE, Highlighter::STRING_COLOR)
|
|
75
|
+
Highlighter.apply_regex(cols, text, COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
76
|
+
cols
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
Registry.register("elixir", mod: Elixir,
|
|
81
|
+
extensions: %w[.ex .exs],
|
|
82
|
+
shebangs: %w[elixir iex],
|
|
83
|
+
runprg: "elixir %")
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuVim
|
|
4
|
+
module Lang
|
|
5
|
+
module Erb
|
|
6
|
+
ERB_COMMENT_RE = /<%#.*?%>/
|
|
7
|
+
ERB_TAG_RE = /<%[=\-]?|[-%]?%>/
|
|
8
|
+
|
|
9
|
+
module_function
|
|
10
|
+
|
|
11
|
+
def color_columns(text)
|
|
12
|
+
cols = {}
|
|
13
|
+
|
|
14
|
+
# First apply HTML highlighting as base
|
|
15
|
+
Html.color_columns(text).each { |k, v| cols[k] = v }
|
|
16
|
+
|
|
17
|
+
# ERB delimiters (<%= %> <% %> <%- -%>)
|
|
18
|
+
Highlighter.apply_regex(cols, text, ERB_TAG_RE, "\e[35m", override: true)
|
|
19
|
+
|
|
20
|
+
# ERB comment tags override everything (including delimiters)
|
|
21
|
+
Highlighter.apply_regex(cols, text, ERB_COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
22
|
+
|
|
23
|
+
cols
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Registry.register("erb", mod: Erb,
|
|
28
|
+
extensions: %w[.erb])
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuVim
|
|
4
|
+
module Lang
|
|
5
|
+
module Go
|
|
6
|
+
KEYWORDS = %w[
|
|
7
|
+
break case chan const continue default defer else fallthrough
|
|
8
|
+
for func go goto if import interface map package range return
|
|
9
|
+
select struct switch type var
|
|
10
|
+
true false nil iota
|
|
11
|
+
].freeze
|
|
12
|
+
|
|
13
|
+
TYPES = %w[
|
|
14
|
+
bool byte complex64 complex128 error float32 float64
|
|
15
|
+
int int8 int16 int32 int64 rune string
|
|
16
|
+
uint uint8 uint16 uint32 uint64 uintptr any comparable
|
|
17
|
+
].freeze
|
|
18
|
+
|
|
19
|
+
ALL_KEYWORDS = (KEYWORDS + TYPES).uniq.freeze
|
|
20
|
+
|
|
21
|
+
KEYWORD_RE = /\b(?:#{ALL_KEYWORDS.join("|")})\b/
|
|
22
|
+
STRING_DOUBLE_RE = /"(?:\\.|[^"\\])*"/
|
|
23
|
+
STRING_RAW_RE = /`[^`]*`/
|
|
24
|
+
CHAR_RE = /'(?:\\.|[^'\\])'/
|
|
25
|
+
NUMBER_RE = /\b(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:\.[\d_]+)?(?:[eE][+-]?\d+)?i?)\b/
|
|
26
|
+
LINE_COMMENT_RE = %r{//.*}
|
|
27
|
+
BLOCK_COMMENT_RE = %r{/\*.*?\*/}
|
|
28
|
+
CONSTANT_RE = /\b[A-Z][A-Z0-9_]{1,}\b/
|
|
29
|
+
|
|
30
|
+
INDENT_OPEN_RE = /\{\s*(?:\/\/.*)?$/
|
|
31
|
+
INDENT_CLOSE_RE = /\A\s*\}/
|
|
32
|
+
|
|
33
|
+
DEDENT_TRIGGERS = {
|
|
34
|
+
"}" => /\A(\s*)\}/
|
|
35
|
+
}.freeze
|
|
36
|
+
|
|
37
|
+
module_function
|
|
38
|
+
|
|
39
|
+
def calculate_indent(lines, target_row, shiftwidth)
|
|
40
|
+
depth = 0
|
|
41
|
+
(0...target_row).each do |row|
|
|
42
|
+
line = lines[row].to_s
|
|
43
|
+
line.each_char do |ch|
|
|
44
|
+
case ch
|
|
45
|
+
when "{" then depth += 1
|
|
46
|
+
when "}" then depth -= 1
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
target_line = lines[target_row].to_s.lstrip
|
|
52
|
+
depth -= 1 if target_line.match?(INDENT_CLOSE_RE)
|
|
53
|
+
depth = 0 if depth < 0
|
|
54
|
+
depth * shiftwidth
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def indent_trigger?(line)
|
|
58
|
+
line.to_s.rstrip.match?(INDENT_OPEN_RE)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def dedent_trigger(char)
|
|
62
|
+
DEDENT_TRIGGERS[char]
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def color_columns(text)
|
|
66
|
+
cols = {}
|
|
67
|
+
Highlighter.apply_regex(cols, text, CHAR_RE, Highlighter::STRING_COLOR)
|
|
68
|
+
Highlighter.apply_regex(cols, text, STRING_DOUBLE_RE, Highlighter::STRING_COLOR)
|
|
69
|
+
Highlighter.apply_regex(cols, text, STRING_RAW_RE, Highlighter::STRING_COLOR)
|
|
70
|
+
Highlighter.apply_regex(cols, text, KEYWORD_RE, Highlighter::KEYWORD_COLOR)
|
|
71
|
+
Highlighter.apply_regex(cols, text, NUMBER_RE, Highlighter::NUMBER_COLOR)
|
|
72
|
+
Highlighter.apply_regex(cols, text, CONSTANT_RE, Highlighter::CONSTANT_COLOR)
|
|
73
|
+
Highlighter.apply_regex(cols, text, BLOCK_COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
74
|
+
Highlighter.apply_regex(cols, text, LINE_COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
75
|
+
cols
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
Registry.register("go", mod: Go,
|
|
80
|
+
extensions: %w[.go],
|
|
81
|
+
runprg: "go run %")
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuVim
|
|
4
|
+
module Lang
|
|
5
|
+
module Html
|
|
6
|
+
TAG_RE = /<\/?[\w\-]+/
|
|
7
|
+
TAG_CLOSE_RE = /\/?>/
|
|
8
|
+
ATTR_NAME_RE = /\b[\w\-]+(?==)/
|
|
9
|
+
STRING_DOUBLE_RE = /"(?:[^"\\]|\\.)*"/
|
|
10
|
+
STRING_SINGLE_RE = /'(?:[^'\\]|\\.)*'/
|
|
11
|
+
COMMENT_RE = /<!--.*?-->/
|
|
12
|
+
DOCTYPE_RE = /<!DOCTYPE\b[^>]*/i
|
|
13
|
+
ENTITY_RE = /&\w+;|&#\d+;|&#x[\da-fA-F]+;/
|
|
14
|
+
|
|
15
|
+
module_function
|
|
16
|
+
|
|
17
|
+
def color_columns(text)
|
|
18
|
+
cols = {}
|
|
19
|
+
Highlighter.apply_regex(cols, text, TAG_RE, Highlighter::KEYWORD_COLOR)
|
|
20
|
+
Highlighter.apply_regex(cols, text, TAG_CLOSE_RE, Highlighter::KEYWORD_COLOR)
|
|
21
|
+
Highlighter.apply_regex(cols, text, DOCTYPE_RE, "\e[35m")
|
|
22
|
+
Highlighter.apply_regex(cols, text, ATTR_NAME_RE, Highlighter::VARIABLE_COLOR)
|
|
23
|
+
Highlighter.apply_regex(cols, text, STRING_DOUBLE_RE, Highlighter::STRING_COLOR)
|
|
24
|
+
Highlighter.apply_regex(cols, text, STRING_SINGLE_RE, Highlighter::STRING_COLOR)
|
|
25
|
+
Highlighter.apply_regex(cols, text, ENTITY_RE, Highlighter::CONSTANT_COLOR)
|
|
26
|
+
Highlighter.apply_regex(cols, text, COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
27
|
+
cols
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
Registry.register("html", mod: Html,
|
|
32
|
+
extensions: %w[.html .htm .xml])
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RuVim
|
|
4
|
+
module Lang
|
|
5
|
+
module Javascript
|
|
6
|
+
KEYWORDS = %w[
|
|
7
|
+
async await break case catch class const continue debugger default
|
|
8
|
+
delete do else export extends finally for from function if import
|
|
9
|
+
in instanceof let new of return static super switch this throw
|
|
10
|
+
try typeof var void while with yield
|
|
11
|
+
true false null undefined NaN Infinity
|
|
12
|
+
].freeze
|
|
13
|
+
|
|
14
|
+
KEYWORD_RE = /\b(?:#{KEYWORDS.join("|")})\b/
|
|
15
|
+
STRING_DOUBLE_RE = /"(?:\\.|[^"\\])*"/
|
|
16
|
+
STRING_SINGLE_RE = /'(?:\\.|[^'\\])*'/
|
|
17
|
+
TEMPLATE_RE = /`(?:\\.|[^`\\])*`/
|
|
18
|
+
NUMBER_RE = /\b(?:0[xXoObB][\da-fA-F_]+|\d[\d_]*(?:\.[\d_]+)?(?:[eE][+-]?\d+)?n?)\b/
|
|
19
|
+
LINE_COMMENT_RE = %r{//.*}
|
|
20
|
+
BLOCK_COMMENT_RE = %r{/\*.*?\*/}
|
|
21
|
+
CONSTANT_RE = /\b[A-Z][A-Z0-9_]{1,}\b/
|
|
22
|
+
REGEX_RE = %r{/(?:\\.|[^/\\])+/[gimsuvy]*}
|
|
23
|
+
|
|
24
|
+
INDENT_OPEN_RE = /[{(\[]\s*(?:\/\/.*)?$/
|
|
25
|
+
INDENT_CLOSE_RE = /\A\s*[}\])]/
|
|
26
|
+
|
|
27
|
+
DEDENT_TRIGGERS = {
|
|
28
|
+
"}" => /\A(\s*)\}/,
|
|
29
|
+
"]" => /\A(\s*)\]/,
|
|
30
|
+
")" => /\A(\s*)\)/
|
|
31
|
+
}.freeze
|
|
32
|
+
|
|
33
|
+
module_function
|
|
34
|
+
|
|
35
|
+
def calculate_indent(lines, target_row, shiftwidth)
|
|
36
|
+
depth = 0
|
|
37
|
+
(0...target_row).each do |row|
|
|
38
|
+
line = lines[row].to_s
|
|
39
|
+
line.each_char do |ch|
|
|
40
|
+
case ch
|
|
41
|
+
when "{", "[", "(" then depth += 1
|
|
42
|
+
when "}", "]", ")" then depth -= 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
target_line = lines[target_row].to_s.lstrip
|
|
48
|
+
depth -= 1 if target_line.match?(INDENT_CLOSE_RE)
|
|
49
|
+
depth = 0 if depth < 0
|
|
50
|
+
depth * shiftwidth
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def indent_trigger?(line)
|
|
54
|
+
line.to_s.rstrip.match?(INDENT_OPEN_RE)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def dedent_trigger(char)
|
|
58
|
+
DEDENT_TRIGGERS[char]
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def color_columns(text)
|
|
62
|
+
cols = {}
|
|
63
|
+
Highlighter.apply_regex(cols, text, STRING_SINGLE_RE, Highlighter::STRING_COLOR)
|
|
64
|
+
Highlighter.apply_regex(cols, text, STRING_DOUBLE_RE, Highlighter::STRING_COLOR)
|
|
65
|
+
Highlighter.apply_regex(cols, text, TEMPLATE_RE, Highlighter::STRING_COLOR)
|
|
66
|
+
Highlighter.apply_regex(cols, text, KEYWORD_RE, Highlighter::KEYWORD_COLOR)
|
|
67
|
+
Highlighter.apply_regex(cols, text, NUMBER_RE, Highlighter::NUMBER_COLOR)
|
|
68
|
+
Highlighter.apply_regex(cols, text, CONSTANT_RE, Highlighter::CONSTANT_COLOR)
|
|
69
|
+
Highlighter.apply_regex(cols, text, BLOCK_COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
70
|
+
Highlighter.apply_regex(cols, text, LINE_COMMENT_RE, Highlighter::COMMENT_COLOR, override: true)
|
|
71
|
+
cols
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
Registry.register("javascript", mod: Javascript,
|
|
76
|
+
extensions: %w[.js .mjs .cjs],
|
|
77
|
+
aliases: %w[javascriptreact],
|
|
78
|
+
shebangs: %w[node nodejs deno],
|
|
79
|
+
runprg: "node %")
|
|
80
|
+
Registry.register("javascriptreact", mod: Javascript,
|
|
81
|
+
extensions: %w[.jsx])
|
|
82
|
+
end
|
|
83
|
+
end
|