From f82a34af84a39c6935e21595ed01efe00c08fb59 Mon Sep 17 00:00:00 2001 From: Samuel Williams Date: Wed, 17 Jun 2026 16:14:04 +1200 Subject: [PATCH] Handle empty completion arguments. Assisted-By: devx/fd316b93-afdd-4504-b9b8-fa80105f245c --- lib/samovar/completion/context.rb | 18 +++++++----------- lib/samovar/split.rb | 2 +- test/samovar/completion.rb | 20 ++++++++++++++++++++ 3 files changed, 28 insertions(+), 12 deletions(-) diff --git a/lib/samovar/completion/context.rb b/lib/samovar/completion/context.rb index 602cbaf..f1bbd69 100644 --- a/lib/samovar/completion/context.rb +++ b/lib/samovar/completion/context.rb @@ -16,10 +16,13 @@ class Context # @parameter environment [Hash] The environment for completion callbacks. # @returns [Context] The completion context. def self.for(command_class, arguments, environment: ENV) + arguments = arguments.dup + current = arguments.pop || "" + return self.new( command_class.table.merged, arguments, - arguments.last || "", + current, environment: environment, ) end @@ -27,7 +30,7 @@ def self.for(command_class, arguments, environment: ENV) # Initialize a new completion context. # # @parameter table [Table] The command table to complete. - # @parameter arguments [Array(String)] The truncated command-line arguments. + # @parameter arguments [Array(String)] The completed words before the current token. # @parameter current [String] The token being completed. # @parameter row [Object | Nil] The parser row whose value is being completed. # @parameter environment [Hash] The environment for completion callbacks. @@ -42,7 +45,7 @@ def initialize(table, arguments, current, row = nil, environment: ENV) # @attribute [Table] The command table to complete. attr :table - # @attribute [Array(String)] The truncated command-line arguments. + # @attribute [Array(String)] The completed words before the current token. attr :arguments # @attribute [String] The token being completed. @@ -68,18 +71,11 @@ def with_row(row) ) end - # The completed words before the current token. - # - # @returns [Array(String)] The arguments before the token being completed. - def words - @arguments.take(@arguments.size - 1) - end - # Complete the current command class. # # @returns [Result] The completion result. def complete - complete_rows(@table, words) + complete_rows(@table, @arguments.dup) end # Complete the given command class with completed words. diff --git a/lib/samovar/split.rb b/lib/samovar/split.rb index 2e5543e..a622a9b 100644 --- a/lib/samovar/split.rb +++ b/lib/samovar/split.rb @@ -111,7 +111,7 @@ def complete(input, context, collected) input.first, description: "Delegate completion", type: :delegate, - index: context.words.index(@marker) + 1, + index: context.arguments.index(@marker) + 1, ), ]) end diff --git a/test/samovar/completion.rb b/test/samovar/completion.rb index 7957af4..d9f6075 100644 --- a/test/samovar/completion.rb +++ b/test/samovar/completion.rb @@ -284,4 +284,24 @@ def complete(input, **options) expect(output.string).to be(:include?, "command\tleaf\tLeaf command.\n") expect(output.string).to be(:include?, "option\t--verbose\tEnable verbose output.\n") end + + it "splits completed arguments from the current token" do + arguments = ["leaf", "--ver"] + + context = Samovar::Completion::Context.for(CompletionTop, arguments) + + expect(context.arguments).to be == ["leaf"] + expect(context.current).to be == "--ver" + expect(arguments).to be == ["leaf", "--ver"] + end + + it "completes with no arguments" do + output = StringIO.new + + result = CompletionTop.complete([], output: output) + + expect(values(result)).to be(:include?, "leaf") + expect(output.string).to be(:include?, "command\tleaf\tLeaf command.\n") + expect(output.string).to be(:include?, "option\t--verbose\tEnable verbose output.\n") + end end