mui 0.1.0 → 0.3.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 (110) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +163 -0
  3. data/CHANGELOG.md +448 -0
  4. data/README.md +309 -6
  5. data/docs/_config.yml +56 -0
  6. data/docs/configuration.md +301 -0
  7. data/docs/getting-started.md +140 -0
  8. data/docs/index.md +55 -0
  9. data/docs/jobs.md +297 -0
  10. data/docs/keybindings.md +229 -0
  11. data/docs/plugins.md +285 -0
  12. data/docs/syntax-highlighting.md +149 -0
  13. data/exe/mui +1 -2
  14. data/lib/mui/autocmd.rb +66 -0
  15. data/lib/mui/buffer.rb +275 -0
  16. data/lib/mui/buffer_word_cache.rb +131 -0
  17. data/lib/mui/buffer_word_completer.rb +77 -0
  18. data/lib/mui/color_manager.rb +136 -0
  19. data/lib/mui/color_scheme.rb +63 -0
  20. data/lib/mui/command_completer.rb +30 -0
  21. data/lib/mui/command_context.rb +90 -0
  22. data/lib/mui/command_history.rb +89 -0
  23. data/lib/mui/command_line.rb +167 -0
  24. data/lib/mui/command_registry.rb +44 -0
  25. data/lib/mui/completion_renderer.rb +84 -0
  26. data/lib/mui/completion_state.rb +58 -0
  27. data/lib/mui/config.rb +58 -0
  28. data/lib/mui/editor.rb +395 -0
  29. data/lib/mui/error.rb +29 -0
  30. data/lib/mui/file_completer.rb +51 -0
  31. data/lib/mui/floating_window.rb +161 -0
  32. data/lib/mui/handler_result.rb +107 -0
  33. data/lib/mui/highlight.rb +22 -0
  34. data/lib/mui/highlighters/base.rb +23 -0
  35. data/lib/mui/highlighters/search_highlighter.rb +27 -0
  36. data/lib/mui/highlighters/selection_highlighter.rb +48 -0
  37. data/lib/mui/highlighters/syntax_highlighter.rb +107 -0
  38. data/lib/mui/input.rb +17 -0
  39. data/lib/mui/insert_completion_renderer.rb +92 -0
  40. data/lib/mui/insert_completion_state.rb +77 -0
  41. data/lib/mui/job.rb +81 -0
  42. data/lib/mui/job_manager.rb +113 -0
  43. data/lib/mui/key_code.rb +30 -0
  44. data/lib/mui/key_handler/base.rb +187 -0
  45. data/lib/mui/key_handler/command_mode.rb +511 -0
  46. data/lib/mui/key_handler/insert_mode.rb +323 -0
  47. data/lib/mui/key_handler/motions/motion_handler.rb +56 -0
  48. data/lib/mui/key_handler/normal_mode.rb +552 -0
  49. data/lib/mui/key_handler/operators/base_operator.rb +134 -0
  50. data/lib/mui/key_handler/operators/change_operator.rb +179 -0
  51. data/lib/mui/key_handler/operators/delete_operator.rb +176 -0
  52. data/lib/mui/key_handler/operators/paste_operator.rb +119 -0
  53. data/lib/mui/key_handler/operators/yank_operator.rb +127 -0
  54. data/lib/mui/key_handler/search_mode.rb +191 -0
  55. data/lib/mui/key_handler/visual_line_mode.rb +20 -0
  56. data/lib/mui/key_handler/visual_mode.rb +402 -0
  57. data/lib/mui/key_handler/window_command.rb +112 -0
  58. data/lib/mui/key_handler.rb +16 -0
  59. data/lib/mui/key_notation_parser.rb +152 -0
  60. data/lib/mui/key_sequence.rb +67 -0
  61. data/lib/mui/key_sequence_buffer.rb +85 -0
  62. data/lib/mui/key_sequence_handler.rb +163 -0
  63. data/lib/mui/key_sequence_matcher.rb +79 -0
  64. data/lib/mui/layout/calculator.rb +15 -0
  65. data/lib/mui/layout/leaf_node.rb +33 -0
  66. data/lib/mui/layout/node.rb +29 -0
  67. data/lib/mui/layout/split_node.rb +132 -0
  68. data/lib/mui/line_renderer.rb +173 -0
  69. data/lib/mui/mode.rb +13 -0
  70. data/lib/mui/mode_manager.rb +186 -0
  71. data/lib/mui/motion.rb +139 -0
  72. data/lib/mui/plugin.rb +35 -0
  73. data/lib/mui/plugin_manager.rb +106 -0
  74. data/lib/mui/register.rb +110 -0
  75. data/lib/mui/screen.rb +103 -0
  76. data/lib/mui/search_completer.rb +50 -0
  77. data/lib/mui/search_input.rb +40 -0
  78. data/lib/mui/search_state.rb +121 -0
  79. data/lib/mui/selection.rb +55 -0
  80. data/lib/mui/status_line_renderer.rb +40 -0
  81. data/lib/mui/syntax/language_detector.rb +106 -0
  82. data/lib/mui/syntax/lexer_base.rb +106 -0
  83. data/lib/mui/syntax/lexers/c_lexer.rb +127 -0
  84. data/lib/mui/syntax/lexers/css_lexer.rb +121 -0
  85. data/lib/mui/syntax/lexers/go_lexer.rb +205 -0
  86. data/lib/mui/syntax/lexers/html_lexer.rb +118 -0
  87. data/lib/mui/syntax/lexers/javascript_lexer.rb +197 -0
  88. data/lib/mui/syntax/lexers/markdown_lexer.rb +210 -0
  89. data/lib/mui/syntax/lexers/ruby_lexer.rb +114 -0
  90. data/lib/mui/syntax/lexers/rust_lexer.rb +148 -0
  91. data/lib/mui/syntax/lexers/typescript_lexer.rb +203 -0
  92. data/lib/mui/syntax/token.rb +42 -0
  93. data/lib/mui/syntax/token_cache.rb +91 -0
  94. data/lib/mui/tab_bar_renderer.rb +87 -0
  95. data/lib/mui/tab_manager.rb +96 -0
  96. data/lib/mui/tab_page.rb +35 -0
  97. data/lib/mui/terminal_adapter/base.rb +92 -0
  98. data/lib/mui/terminal_adapter/curses.rb +164 -0
  99. data/lib/mui/terminal_adapter.rb +4 -0
  100. data/lib/mui/themes/default.rb +315 -0
  101. data/lib/mui/undo_manager.rb +83 -0
  102. data/lib/mui/undoable_action.rb +175 -0
  103. data/lib/mui/unicode_width.rb +100 -0
  104. data/lib/mui/version.rb +1 -1
  105. data/lib/mui/window.rb +201 -0
  106. data/lib/mui/window_manager.rb +256 -0
  107. data/lib/mui/wrap_cache.rb +40 -0
  108. data/lib/mui/wrap_helper.rb +84 -0
  109. data/lib/mui.rb +171 -2
  110. metadata +123 -5
@@ -0,0 +1,256 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mui
4
+ class WindowManager
5
+ # Predicates for determining if a window is in a given direction from another
6
+ DIRECTION_PREDICATES = {
7
+ left: ->(w, active) { w.x + w.width <= active.x },
8
+ right: ->(w, active) { w.x >= active.x + active.width },
9
+ up: ->(w, active) { w.y + w.height <= active.y },
10
+ down: ->(w, active) { w.y >= active.y + active.height }
11
+ }.freeze
12
+
13
+ attr_reader :active_window, :layout_root
14
+
15
+ def initialize(screen, color_scheme: nil)
16
+ @screen = screen
17
+ @color_scheme = color_scheme
18
+ @active_window = nil
19
+ @layout_root = nil
20
+ @layout_calculator = Layout::Calculator.new
21
+ end
22
+
23
+ def add_window(buffer)
24
+ window = create_window(buffer)
25
+
26
+ @layout_root = Layout::LeafNode.new(window) if @layout_root.nil?
27
+
28
+ @active_window ||= window
29
+ update_layout
30
+ window
31
+ end
32
+
33
+ def remove_window(window)
34
+ return false if single_window?
35
+
36
+ node = @layout_root.find_window_node(window)
37
+ return false unless node
38
+
39
+ remove_node(node)
40
+
41
+ @active_window = windows.first if @active_window == window
42
+ update_layout
43
+ true
44
+ end
45
+
46
+ def split_horizontal(buffer = nil)
47
+ split(:horizontal, buffer)
48
+ end
49
+
50
+ def split_vertical(buffer = nil)
51
+ split(:vertical, buffer)
52
+ end
53
+
54
+ def close_current_window
55
+ return false if single_window?
56
+
57
+ current_node = @layout_root.find_window_node(@active_window)
58
+ return false unless current_node
59
+
60
+ remove_node(current_node)
61
+
62
+ @active_window = windows.first
63
+ update_layout
64
+ true
65
+ end
66
+
67
+ def close_all_except_current
68
+ return if single_window?
69
+
70
+ @layout_root = Layout::LeafNode.new(@active_window)
71
+ @layout_root.parent = nil
72
+ update_layout
73
+ end
74
+
75
+ def render_all(screen, selection: nil, search_state: nil)
76
+ windows.each do |window|
77
+ window_selection = window == @active_window ? selection : nil
78
+ window.render(screen, selection: window_selection, search_state:)
79
+ end
80
+ render_separators(screen)
81
+ end
82
+
83
+ def separators
84
+ return [] unless @layout_root.respond_to?(:separators)
85
+
86
+ @layout_root.separators
87
+ end
88
+
89
+ def update_sizes
90
+ update_layout
91
+ end
92
+
93
+ def focus_next
94
+ focus_cycle(1)
95
+ end
96
+
97
+ def focus_previous
98
+ focus_cycle(-1)
99
+ end
100
+
101
+ def focus_direction(direction)
102
+ return unless windows.size > 1
103
+
104
+ target = find_window_in_direction(direction)
105
+ @active_window = target if target
106
+ end
107
+
108
+ def focus_window(window)
109
+ return false unless windows.include?(window)
110
+
111
+ @active_window = window
112
+ true
113
+ end
114
+
115
+ def windows
116
+ return [] unless @layout_root
117
+
118
+ @layout_root.windows
119
+ end
120
+
121
+ def window_count
122
+ windows.size
123
+ end
124
+
125
+ def single_window?
126
+ windows.size <= 1
127
+ end
128
+
129
+ def update_layout(y_offset: 0)
130
+ return unless @layout_root
131
+
132
+ @layout_calculator.calculate(
133
+ @layout_root, 0, y_offset, @screen.width, @screen.height - 1 - y_offset
134
+ )
135
+ end
136
+
137
+ private
138
+
139
+ def focus_cycle(offset)
140
+ all_windows = windows
141
+ return if all_windows.size <= 1
142
+
143
+ current_index = all_windows.index(@active_window) || 0
144
+ @active_window = all_windows[(current_index + offset) % all_windows.size]
145
+ end
146
+
147
+ def split(direction, buffer)
148
+ return nil unless @active_window
149
+
150
+ target_buffer = buffer || @active_window.buffer
151
+ new_window = create_window(target_buffer)
152
+
153
+ current_node = @layout_root.find_window_node(@active_window)
154
+ return nil unless current_node
155
+
156
+ parent = current_node.parent
157
+
158
+ new_leaf = Layout::LeafNode.new(new_window)
159
+ split_node = Layout::SplitNode.new(
160
+ direction:,
161
+ children: [current_node, new_leaf],
162
+ ratio: 0.5
163
+ )
164
+
165
+ if parent
166
+ parent.replace_child(current_node, split_node)
167
+ else
168
+ @layout_root = split_node
169
+ end
170
+
171
+ @active_window = new_window
172
+ update_layout
173
+ new_window
174
+ end
175
+
176
+ def remove_node(node)
177
+ parent = node.parent
178
+ return false unless parent
179
+
180
+ parent.remove_child(node)
181
+
182
+ if parent.children.size == 1
183
+ remaining_child = parent.children.first
184
+ grandparent = parent.parent
185
+
186
+ if grandparent
187
+ grandparent.replace_child(parent, remaining_child)
188
+ else
189
+ @layout_root = remaining_child
190
+ remaining_child.parent = nil
191
+ end
192
+ end
193
+
194
+ true
195
+ end
196
+
197
+ def find_window_in_direction(direction)
198
+ return nil unless @active_window
199
+
200
+ predicate = DIRECTION_PREDICATES[direction]
201
+ return nil unless predicate
202
+
203
+ current_x = @active_window.x + (@active_window.width / 2)
204
+ current_y = @active_window.y + (@active_window.height / 2)
205
+
206
+ candidates = windows.reject { |w| w == @active_window }
207
+ .select { |w| predicate.call(w, @active_window) }
208
+
209
+ candidates.min_by do |w|
210
+ wx = w.x + (w.width / 2)
211
+ wy = w.y + (w.height / 2)
212
+ Math.sqrt(((wx - current_x)**2) + ((wy - current_y)**2))
213
+ end
214
+ end
215
+
216
+ def create_window(buffer)
217
+ Window.new(
218
+ buffer,
219
+ x: 0,
220
+ y: 0,
221
+ width: @screen.width,
222
+ height: @screen.height,
223
+ color_scheme: @color_scheme
224
+ )
225
+ end
226
+
227
+ def render_separators(screen)
228
+ style = separator_style
229
+ separators.each do |sep|
230
+ case sep[:type]
231
+ when :horizontal
232
+ render_horizontal_separator(screen, sep, style)
233
+ when :vertical
234
+ render_vertical_separator(screen, sep, style)
235
+ end
236
+ end
237
+ end
238
+
239
+ def render_horizontal_separator(screen, sep, style)
240
+ line = "─" * sep[:length]
241
+ screen.put_with_style(sep[:y], sep[:x], line, style)
242
+ end
243
+
244
+ def render_vertical_separator(screen, sep, style)
245
+ sep[:length].times do |i|
246
+ screen.put_with_style(sep[:y] + i, sep[:x], "│", style)
247
+ end
248
+ end
249
+
250
+ def separator_style
251
+ return nil unless @color_scheme
252
+
253
+ @color_scheme[:separator]
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mui
4
+ # Caches wrap calculation results for performance
5
+ # Cache key: [line_content, width]
6
+ class WrapCache
7
+ def initialize
8
+ @cache = {}
9
+ end
10
+
11
+ def get(line, width)
12
+ key = cache_key(line, width)
13
+ @cache[key]
14
+ end
15
+
16
+ def set(line, width, result)
17
+ key = cache_key(line, width)
18
+ @cache[key] = result
19
+ end
20
+
21
+ def invalidate(line)
22
+ # Remove all entries for this line content
23
+ @cache.delete_if { |k, _| k.start_with?("#{line}\x00") }
24
+ end
25
+
26
+ def clear
27
+ @cache.clear
28
+ end
29
+
30
+ def size
31
+ @cache.size
32
+ end
33
+
34
+ private
35
+
36
+ def cache_key(line, width)
37
+ "#{line}\x00#{width}"
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mui
4
+ # Helper module for line wrapping calculations
5
+ module WrapHelper
6
+ class << self
7
+ # Wraps a line into screen lines based on display width
8
+ # Returns: [{ text:, start_col:, end_col: }, ...]
9
+ def wrap_line(line, width, cache: nil)
10
+ return [{ text: "", start_col: 0, end_col: 0 }] if line.nil? || line.empty?
11
+ return [{ text: line, start_col: 0, end_col: line.length }] if width <= 0
12
+
13
+ if cache
14
+ cached = cache.get(line, width)
15
+ return cached if cached
16
+ end
17
+
18
+ result = compute_wrap(line, width)
19
+ cache&.set(line, width, result)
20
+ result
21
+ end
22
+
23
+ # Converts logical column to screen position
24
+ # Returns: [screen_row_offset, screen_col]
25
+ def logical_to_screen(line, col, width, cache: nil)
26
+ return [0, 0] if line.nil? || line.empty? || col <= 0
27
+
28
+ wrapped = wrap_line(line, width, cache:)
29
+
30
+ wrapped.each_with_index do |segment, row|
31
+ next unless col <= segment[:end_col]
32
+
33
+ # Found the segment containing this column
34
+ relative_col = col - segment[:start_col]
35
+ prefix = segment[:text][0, relative_col] || ""
36
+ screen_col = UnicodeWidth.string_width(prefix)
37
+ return [row, screen_col]
38
+ end
39
+
40
+ # Column is past end of line, return last position
41
+ last_segment = wrapped.last
42
+ last_text = last_segment[:text]
43
+ [wrapped.size - 1, UnicodeWidth.string_width(last_text)]
44
+ end
45
+
46
+ # Returns the number of screen lines for a logical line
47
+ def screen_line_count(line, width, cache: nil)
48
+ wrap_line(line, width, cache:).size
49
+ end
50
+
51
+ private
52
+
53
+ def compute_wrap(line, width)
54
+ result = []
55
+ chars = line.chars
56
+ current_text = String.new
57
+ current_width = 0
58
+ start_col = 0
59
+ col = 0
60
+
61
+ chars.each do |char|
62
+ char_w = UnicodeWidth.char_width(char)
63
+
64
+ # Check if adding this character would exceed width
65
+ if current_width + char_w > width && !current_text.empty?
66
+ result << { text: current_text, start_col:, end_col: col }
67
+ current_text = String.new
68
+ current_width = 0
69
+ start_col = col
70
+ end
71
+
72
+ current_text << char
73
+ current_width += char_w
74
+ col += 1
75
+ end
76
+
77
+ # Add remaining text
78
+ result << { text: current_text, start_col:, end_col: col } unless current_text.empty?
79
+
80
+ result.empty? ? [{ text: String.new, start_col: 0, end_col: 0 }] : result
81
+ end
82
+ end
83
+ end
84
+ end
data/lib/mui.rb CHANGED
@@ -1,8 +1,177 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "mui/version"
4
+ require_relative "mui/error"
5
+ require_relative "mui/key_code"
6
+ require_relative "mui/key_notation_parser"
7
+ require_relative "mui/key_sequence"
8
+ require_relative "mui/key_sequence_buffer"
9
+ require_relative "mui/key_sequence_matcher"
10
+ require_relative "mui/key_sequence_handler"
11
+ require_relative "mui/unicode_width"
12
+ require_relative "mui/wrap_cache"
13
+ require_relative "mui/wrap_helper"
14
+ require_relative "mui/config"
15
+ require_relative "mui/color_scheme"
16
+ require_relative "mui/color_manager"
17
+ require_relative "mui/themes/default"
18
+ require_relative "mui/terminal_adapter"
19
+ require_relative "mui/screen"
20
+ require_relative "mui/input"
21
+ require_relative "mui/undoable_action"
22
+ require_relative "mui/undo_manager"
23
+ require_relative "mui/buffer"
24
+ require_relative "mui/highlight"
25
+ require_relative "mui/highlighters/base"
26
+ require_relative "mui/highlighters/selection_highlighter"
27
+ require_relative "mui/highlighters/search_highlighter"
28
+ require_relative "mui/syntax/token"
29
+ require_relative "mui/syntax/lexer_base"
30
+ require_relative "mui/syntax/lexers/ruby_lexer"
31
+ require_relative "mui/syntax/lexers/c_lexer"
32
+ require_relative "mui/syntax/lexers/go_lexer"
33
+ require_relative "mui/syntax/lexers/rust_lexer"
34
+ require_relative "mui/syntax/lexers/javascript_lexer"
35
+ require_relative "mui/syntax/lexers/typescript_lexer"
36
+ require_relative "mui/syntax/lexers/markdown_lexer"
37
+ require_relative "mui/syntax/lexers/html_lexer"
38
+ require_relative "mui/syntax/lexers/css_lexer"
39
+ require_relative "mui/syntax/token_cache"
40
+ require_relative "mui/syntax/language_detector"
41
+ require_relative "mui/highlighters/syntax_highlighter"
42
+ require_relative "mui/line_renderer"
43
+ require_relative "mui/status_line_renderer"
44
+ require_relative "mui/layout/node"
45
+ require_relative "mui/layout/leaf_node"
46
+ require_relative "mui/layout/split_node"
47
+ require_relative "mui/layout/calculator"
48
+ require_relative "mui/window"
49
+ require_relative "mui/window_manager"
50
+ require_relative "mui/tab_page"
51
+ require_relative "mui/tab_manager"
52
+ require_relative "mui/tab_bar_renderer"
53
+ require_relative "mui/mode"
54
+ require_relative "mui/handler_result"
55
+ require_relative "mui/command_history"
56
+ require_relative "mui/command_line"
57
+ require_relative "mui/completion_state"
58
+ require_relative "mui/insert_completion_state"
59
+ require_relative "mui/command_completer"
60
+ require_relative "mui/file_completer"
61
+ require_relative "mui/buffer_word_completer"
62
+ require_relative "mui/buffer_word_cache"
63
+ require_relative "mui/completion_renderer"
64
+ require_relative "mui/insert_completion_renderer"
65
+ require_relative "mui/floating_window"
66
+ require_relative "mui/search_state"
67
+ require_relative "mui/search_input"
68
+ require_relative "mui/search_completer"
69
+ require_relative "mui/motion"
70
+ require_relative "mui/selection"
71
+ require_relative "mui/register"
72
+ require_relative "mui/key_handler"
73
+ require_relative "mui/mode_manager"
74
+ require_relative "mui/command_context"
75
+ require_relative "mui/command_registry"
76
+ require_relative "mui/autocmd"
77
+ require_relative "mui/plugin"
78
+ require_relative "mui/plugin_manager"
79
+ require_relative "mui/job"
80
+ require_relative "mui/job_manager"
81
+ require_relative "mui/editor"
4
82
 
83
+ # mui(無為) top level module
5
84
  module Mui
6
- class Error < StandardError; end
7
- # Your code goes here...
85
+ class << self
86
+ def config
87
+ @config ||= Config.new
88
+ end
89
+
90
+ def plugin_manager
91
+ @plugin_manager ||= PluginManager.new
92
+ end
93
+
94
+ def register
95
+ @register ||= Register.new
96
+ end
97
+
98
+ def set(key, value)
99
+ config.set(key, value)
100
+ end
101
+
102
+ # Register gem for lazy installation via bundler/inline
103
+ def use(gem_name, version = nil)
104
+ plugin_manager.add_gem(gem_name, version)
105
+ end
106
+
107
+ def keymap(mode, key, &block)
108
+ config.add_keymap(mode, key, block)
109
+ end
110
+
111
+ def command(name, &block)
112
+ config.add_command(name, block)
113
+ end
114
+
115
+ def autocmd(event, pattern: nil, &block)
116
+ config.add_autocmd(event, pattern, block)
117
+ end
118
+
119
+ def define_plugin(name, dependencies: [], &block)
120
+ plugin_manager.register(name, block, dependencies:)
121
+ end
122
+
123
+ def load_config
124
+ config.load_file(File.expand_path("~/.muirc"))
125
+ config.load_file(".lmuirc")
126
+ end
127
+
128
+ # Stub for LSP configuration DSL
129
+ # This allows .muirc to call Mui.lsp { ... } before mui-lsp gem is loaded
130
+ # When mui-lsp is loaded, it replaces this with the real ConfigDsl
131
+ def lsp(&block)
132
+ @lsp_config ||= LspConfigStub.new
133
+ @lsp_config.instance_eval(&block) if block
134
+ @lsp_config
135
+ end
136
+
137
+ def lsp_server_configs
138
+ @lsp_config&.server_configs || []
139
+ end
140
+ end
141
+
142
+ # Stub class for LSP configuration before mui-lsp gem is loaded
143
+ # Stores configuration to be applied when the actual gem loads
144
+ class LspConfigStub
145
+ attr_reader :server_configs
146
+
147
+ def initialize
148
+ @server_configs = []
149
+ end
150
+
151
+ # Stub methods that mirror Mui::Lsp::ConfigDsl
152
+ def use(name, **options)
153
+ @server_configs << { type: :preset, name: name.to_sym, options: }
154
+ end
155
+
156
+ def server(name:, command:, language_ids:, file_patterns:, auto_start: true, sync_on_change: true)
157
+ @server_configs << {
158
+ type: :custom,
159
+ name:,
160
+ command:,
161
+ language_ids:,
162
+ file_patterns:,
163
+ auto_start:,
164
+ sync_on_change:
165
+ }
166
+ end
167
+ end
168
+
169
+ class << self
170
+ def reset_config!
171
+ @config = nil
172
+ @plugin_manager = nil
173
+ @register = nil
174
+ @lsp_config = nil
175
+ end
176
+ end
8
177
  end