From 1b10aa4713ead5a8801fadb23f530ab19e4b7366 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Thu, 2 Jan 2025 21:21:30 +0900 Subject: [PATCH 1/2] [refactor core/completion] Use bash_impl and tagswitch for `compgen -F` --- core/completion.py | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/core/completion.py b/core/completion.py index 1cd2eec98..56c7322de 100755 --- a/core/completion.py +++ b/core/completion.py @@ -41,6 +41,7 @@ from _devbuild.gen.runtime_asdl import (scope_e, comp_action_e, comp_action_t) from _devbuild.gen.types_asdl import redir_arg_type_e from _devbuild.gen.value_asdl import (value, value_e) +from core import bash_impl from core import error from core import pyos from core import state @@ -51,7 +52,7 @@ from frontend import location from frontend import reader from mycpp import mylib -from mycpp.mylib import print_stderr, iteritems, log +from mycpp.mylib import iteritems, log, print_stderr, tagswitch from osh.string_ops import ShellQuoteB from osh import word_ from pylib import os_path @@ -619,25 +620,30 @@ def Matches(self, comp): # Read the response. (The name 'COMP_REPLY' would be more consistent with others.) val = self.cmd_ev.mem.GetValue('COMPREPLY', scope_e.GlobalOnly) - if val.tag() == value_e.Undef: - # We set it above, so this error would only happen if the user unset it. - # Not changing it means there were no completions. - # TODO: This writes over the command line; it would be better to use an - # error object. - print_stderr('osh error: Ran function %r but COMPREPLY was unset' % - self.func.name) - return + UP_val = val + with tagswitch(val) as case: + if case(value_e.Undef): + # We set it above, so this error would only happen if the user + # unset it. Not changing it means there were no completions. + # TODO: This writes over the command line; it would be better + # to use an error object. + print_stderr('osh error: Ran function %r but COMPREPLY was unset' % + self.func.name) + return - if val.tag() != value_e.BashArray: - print_stderr('osh error: COMPREPLY should be an array, got %s' % - ui.ValType(val)) - return + elif case(value_e.BashArray): + val = cast(value.BashArray, UP_val) + strs = bash_impl.BashArray_GetValues(val) + + else: + print_stderr('osh error: COMPREPLY should be an array, got %s' % + ui.ValType(val)) + return if 0: self.debug('> %r' % val) # CRASHES in C++ - array_val = cast(value.BashArray, val) - for s in array_val.strs: + for s in strs: #self.debug('> %r' % s) yield s From ab988fb03ad4d4713b22d4cb0964a4f35f366a71 Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Thu, 2 Jan 2025 21:21:57 +0900 Subject: [PATCH 2/2] [core/completion] Support scalar COMPREPLY with `compgen -F` --- core/completion.py | 6 +++++- spec/builtin-completion.test.sh | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/core/completion.py b/core/completion.py index 56c7322de..4601712a6 100755 --- a/core/completion.py +++ b/core/completion.py @@ -631,12 +631,16 @@ def Matches(self, comp): self.func.name) return + elif case(value_e.Str): + val = cast(value.Str, UP_val) + strs = [val.s] + elif case(value_e.BashArray): val = cast(value.BashArray, UP_val) strs = bash_impl.BashArray_GetValues(val) else: - print_stderr('osh error: COMPREPLY should be an array, got %s' % + print_stderr('osh error: COMPREPLY should be an array or a string, got %s' % ui.ValType(val)) return diff --git a/spec/builtin-completion.test.sh b/spec/builtin-completion.test.sh index a5c4a3c28..85698f8dd 100644 --- a/spec/builtin-completion.test.sh +++ b/spec/builtin-completion.test.sh @@ -625,3 +625,16 @@ argv.py "${words[@]}" ## N-I bash STDOUT: ## END + + +#### compgen -F with scalar COMPREPLY + +_comp_cmd_test() { + unset -v COMPREPLY + COMPREPLY=hello +} +compgen -F _comp_cmd_test + +## STDOUT: +hello +## END