src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/edit/completion_test.go (about)

     1  package edit
     2  
     3  import (
     4  	"testing"
     5  
     6  	"src.elv.sh/pkg/cli/term"
     7  	"src.elv.sh/pkg/eval"
     8  	"src.elv.sh/pkg/eval/vals"
     9  	"src.elv.sh/pkg/testutil"
    10  	"src.elv.sh/pkg/ui"
    11  )
    12  
    13  func TestCompletionAddon(t *testing.T) {
    14  	f := setup(t)
    15  
    16  	testutil.ApplyDir(testutil.Dir{"a": "", "b": ""})
    17  
    18  	feedInput(f.TTYCtrl, "echo \t")
    19  	f.TestTTY(t,
    20  		"~> echo a \n", Styles,
    21  		"   vvvv __",
    22  		" COMPLETING argument  ", Styles,
    23  		"********************* ", term.DotHere, "\n",
    24  		"a  b", Styles,
    25  		"+   ",
    26  	)
    27  }
    28  
    29  func TestCompletionAddon_CompletesLongestCommonPrefix(t *testing.T) {
    30  	f := setup(t)
    31  
    32  	testutil.ApplyDir(testutil.Dir{"foo1": "", "foo2": "", "foo": "", "fox": ""})
    33  
    34  	feedInput(f.TTYCtrl, "echo \t")
    35  	f.TestTTY(t,
    36  		"~> echo fo", Styles,
    37  		"   vvvv", term.DotHere,
    38  	)
    39  
    40  	feedInput(f.TTYCtrl, "\t")
    41  	f.TestTTY(t,
    42  		"~> echo foo \n", Styles,
    43  		"   vvvv ____",
    44  		" COMPLETING argument  ", Styles,
    45  		"********************* ", term.DotHere, "\n",
    46  		"foo  foo1  foo2  fox", Styles,
    47  		"+++                 ",
    48  	)
    49  }
    50  
    51  func TestCompletionAddon_AppliesAutofix(t *testing.T) {
    52  	f := setup(t)
    53  	fooNs := eval.BuildNs().AddGoFn("a", func() {}).AddGoFn("b", func() {}).Ns()
    54  	f.Evaler.AddModule("foo", fooNs)
    55  
    56  	feedInput(f.TTYCtrl, "foo:")
    57  	f.TestTTY(t,
    58  		"~> foo:", Styles,
    59  		"   !!!!", term.DotHere, "\n",
    60  		"Ctrl-A autofix: use foo Tab Enter autofix first", Styles,
    61  		"++++++                  +++ +++++",
    62  	)
    63  
    64  	feedInput(f.TTYCtrl, "\t")
    65  	f.TestTTY(t,
    66  		"~> foo:a\n", Styles,
    67  		"   VVVVV",
    68  		" COMPLETING command  ", Styles,
    69  		"******************** ", term.DotHere, "\n",
    70  		"foo:a  foo:b", Styles,
    71  		"+++++       ",
    72  	)
    73  }
    74  
    75  func TestCompleteFilename(t *testing.T) {
    76  	f := setup(t)
    77  
    78  	testutil.ApplyDir(testutil.Dir{"d": testutil.Dir{"a": "", "b": ""}})
    79  
    80  	evals(f.Evaler, `var @cands = (edit:complete-filename ls ./d/a)`)
    81  	testGlobal(t, f.Evaler,
    82  		"cands",
    83  		vals.MakeList(
    84  			complexItem{Stem: "./d/a", CodeSuffix: " ", Display: ui.T("./d/a")},
    85  			complexItem{Stem: "./d/b", CodeSuffix: " ", Display: ui.T("./d/b")}))
    86  
    87  	testThatOutputErrorIsBubbled(t, f, "edit:complete-filename ls ''")
    88  }
    89  
    90  func TestComplexCandidate_InEditModule(t *testing.T) {
    91  	// A sanity check that the complex-candidate command is part of the edit
    92  	// module.
    93  	f := setup(t)
    94  
    95  	evals(f.Evaler, `var stem = (edit:complex-candidate stem)[stem]`)
    96  	testGlobal(t, f.Evaler, "stem", "stem")
    97  }
    98  
    99  func TestCompletionArgCompleter_ArgsAndValueOutput(t *testing.T) {
   100  	f := setup(t)
   101  
   102  	evals(f.Evaler,
   103  		`var foo-args = []`,
   104  		`fn foo { }`,
   105  		`set edit:completion:arg-completer[foo] = {|@args|
   106  		   set foo-args = $args
   107  		   put 1val
   108  		   edit:complex-candidate 2val &display=2VAL
   109  		 }`)
   110  
   111  	feedInput(f.TTYCtrl, "foo foo1 foo2 \t")
   112  	f.TestTTY(t,
   113  		"~> foo foo1 foo2 1val\n", Styles,
   114  		"   vvv           ____",
   115  		" COMPLETING argument  ", Styles,
   116  		"********************* ", term.DotHere, "\n",
   117  		"1val  2VAL", Styles,
   118  		"++++      ",
   119  	)
   120  	testGlobal(t, f.Evaler,
   121  		"foo-args", vals.MakeList("foo", "foo1", "foo2", ""))
   122  }
   123  
   124  func TestCompletionArgCompleter_BytesOutput(t *testing.T) {
   125  	f := setup(t)
   126  
   127  	evals(f.Evaler,
   128  		`fn foo { }`,
   129  		`set edit:completion:arg-completer[foo] = {|@args|
   130  		   echo 1val
   131  		   echo 2val
   132  		 }`)
   133  
   134  	feedInput(f.TTYCtrl, "foo foo1 foo2 \t")
   135  	f.TestTTY(t,
   136  		"~> foo foo1 foo2 1val\n", Styles,
   137  		"   vvv           ____",
   138  		" COMPLETING argument  ", Styles,
   139  		"********************* ", term.DotHere, "\n",
   140  		"1val  2val", Styles,
   141  		"++++      ",
   142  	)
   143  }
   144  
   145  func TestCompleteSudo(t *testing.T) {
   146  	f := setup(t)
   147  
   148  	evals(f.Evaler,
   149  		`fn foo { }`,
   150  		`set edit:completion:arg-completer[foo] = {|@args|
   151  		   echo val1
   152  		   echo val2
   153  		 }`,
   154  		`var @cands = (edit:complete-sudo sudo foo '')`)
   155  	testGlobal(t, f.Evaler, "cands", vals.MakeList("val1", "val2"))
   156  }
   157  
   158  func TestCompletionMatcher(t *testing.T) {
   159  	f := setup(t)
   160  
   161  	testutil.ApplyDir(testutil.Dir{"foo": "", "oof": ""})
   162  
   163  	evals(f.Evaler, `set edit:completion:matcher[''] = $edit:match-substr~`)
   164  	feedInput(f.TTYCtrl, "echo f\t")
   165  	f.TestTTY(t,
   166  		"~> echo foo \n", Styles,
   167  		"   vvvv ____",
   168  		" COMPLETING argument  ", Styles,
   169  		"********************* ", term.DotHere, "\n",
   170  		"foo  oof", Styles,
   171  		"+++     ",
   172  	)
   173  }
   174  
   175  func TestBuiltinMatchers(t *testing.T) {
   176  	f := setup(t)
   177  
   178  	evals(f.Evaler,
   179  		`var @prefix = (edit:match-prefix ab [ab abc cab acb ba [ab] [a b] [b a]])`,
   180  		`var @substr = (edit:match-substr ab [ab abc cab acb ba [ab] [a b] [b a]])`,
   181  		`var @subseq = (edit:match-subseq ab [ab abc cab acb ba [ab] [a b] [b a]])`,
   182  	)
   183  	testGlobals(t, f.Evaler, map[string]any{
   184  		"prefix": vals.MakeList(true, true, false, false, false, false, false, false),
   185  		"substr": vals.MakeList(true, true, true, false, false, true, false, false),
   186  		"subseq": vals.MakeList(true, true, true, true, false, true, true, false),
   187  	})
   188  
   189  	testThatOutputErrorIsBubbled(t, f, "edit:match-prefix ab [ab]")
   190  }
   191  
   192  func TestBuiltinMatchers_Options(t *testing.T) {
   193  	f := setup(t)
   194  
   195  	// The two options work identically on all the builtin matchers, so we only
   196  	// test for match-prefix for simplicity.
   197  	evals(f.Evaler,
   198  		`var @a = (edit:match-prefix &ignore-case ab [abc aBc AbC])`,
   199  		`var @b = (edit:match-prefix &ignore-case aB [abc aBc AbC])`,
   200  		`var @c = (edit:match-prefix &smart-case  ab [abc aBc Abc])`,
   201  		`var @d = (edit:match-prefix &smart-case  aB [abc aBc AbC])`,
   202  	)
   203  	testGlobals(t, f.Evaler, map[string]any{
   204  		"a": vals.MakeList(true, true, true),
   205  		"b": vals.MakeList(true, true, true),
   206  		"c": vals.MakeList(true, true, true),
   207  		"d": vals.MakeList(false, true, false),
   208  	})
   209  
   210  	testThatOutputErrorIsBubbled(t, f, "edit:match-prefix &ignore-case ab [ab]")
   211  }