refactor: derive Ruby action namespaces from Rust catalog

This commit is contained in:
Valdemar Lorenzen
2026-10-09 17:07:29 +02:00
parent dbafaf6266
commit 18dc8cc155
5 changed files with 67 additions and 34 deletions
+36 -30
View File
@@ -53,33 +53,35 @@ module Vamp
Action = Struct.new(:name)
Mode = Struct.new(:name)
module Core
%w[
insert insert_first_nonblank append append_line_end open_below open_above
left right down up join_lines line_start line_end delete undo redo command
normal newline backspace submit palette repeat_last_edit
search search_next search_previous
word_next word_previous word_end big_word_next big_word_previous big_word_end
select copy cut change paste_before paste_after
copy_system paste_system_before paste_system_after
select_lines clone_above clone_below select_next skip_occurrence select_all
file_picker file_explorer
].each do |name|
action = Action.new("core.#{name}".freeze).freeze
define_singleton_method(name) { action }
end
Core = Module.new
module Lsp
%w[definition diagnostics hover].each do |name|
action = Action.new("core.lsp.#{name}".freeze).freeze
define_singleton_method(name) { action }
def self.install_actions(names)
raise TypeError, "core action catalog must be an Array" unless names.is_a?(Array)
namespaces = [Core]
names.each do |name|
name = string!(name, "core action name")
unless name.match?(/\Acore(?:\.[a-z_][a-z0-9_]*)+\z/)
raise ArgumentError, "invalid core action name: #{name}"
end
parts = name.split(".").drop(1)
namespace = Core
parts[0...-1].each do |part|
if namespace.singleton_methods(false).include?(part.to_sym)
child = namespace.public_send(part)
raise ArgumentError, "conflicting core action namespace: #{name}" unless child.is_a?(Module)
else
child = Module.new
namespace.define_singleton_method(part) { child }
namespaces << child
end
namespace = child
end
leaf = parts.last
raise ArgumentError, "conflicting core action name: #{name}" if namespace.singleton_methods(false).include?(leaf.to_sym)
action = Action.send(:new, name.freeze).freeze
namespace.define_singleton_method(leaf) { action }
end
Lsp.freeze
def self.lsp
Lsp
end
namespaces.each(&:freeze)
end
module Modes
@@ -247,8 +249,12 @@ module Vamp
end
end
def self.setup(mode, options, sender)
raise TypeError, "plugin options must be a Hash" unless options.is_a?(Hash)
def self.setup(mode, startup, sender)
unless startup.is_a?(Hash) && startup.keys.sort == %w[core_actions options] && startup["options"].is_a?(Hash)
raise TypeError, "invalid Ruby startup catalog/options"
end
install_actions(startup["core_actions"])
options = startup["options"]
@mode = mode
@config = Config.new
@name = nil
@@ -381,10 +387,10 @@ end
request_id = nil
begin
mode, path, encoded_options = ARGV
raise ArgumentError, "expected config or plugin mode, path, and options" unless %w[config plugin].include?(mode) && path && encoded_options
raise ArgumentError, "plugin options exceed 4 MiB" if encoded_options.bytesize > Vamp::MAX_FRAME
Vamp.setup(mode, JSON.parse(encoded_options), send_frame)
mode, path, encoded_startup = ARGV
raise ArgumentError, "expected config or plugin mode, path, and startup data" unless %w[config plugin].include?(mode) && path && encoded_startup
raise ArgumentError, "Ruby startup data exceeds 4 MiB" if encoded_startup.bytesize > Vamp::MAX_FRAME
Vamp.setup(mode, JSON.parse(encoded_startup), send_frame)
load path
send_frame.call(Vamp.startup)
if mode == "plugin"