src.elv.sh@v0.21.0-dev.0.20240515223629-06979efb9a2a/pkg/edit/listing_test.go (about) 1 package edit 2 3 import ( 4 "testing" 5 6 "src.elv.sh/pkg/cli/term" 7 "src.elv.sh/pkg/store/storedefs" 8 "src.elv.sh/pkg/ui" 9 ) 10 11 func TestListingBuiltins(t *testing.T) { 12 // Use the custom listing mode since it doesn't require special setup. The 13 // builtins work the same across all listing modes. 14 15 f := setup(t) 16 evals(f.Evaler, 17 `fn item {|x| put [&to-show=$x &to-accept=$x &to-filter=$x] }`, 18 `edit:listing:start-custom [(item 1) (item 2) (item 3)]`) 19 buf1 := f.MakeBuffer( 20 "~> \n", 21 " LISTING ", Styles, 22 "********* ", term.DotHere, "\n", 23 "1 ", Styles, 24 "++++++++++++++++++++++++++++++++++++++++++++++++++", 25 "2 \n", 26 "3 ", 27 ) 28 f.TTYCtrl.TestBuffer(t, buf1) 29 30 evals(f.Evaler, "edit:listing:down", "edit:redraw") 31 buf2 := f.MakeBuffer( 32 "~> \n", 33 " LISTING ", Styles, 34 "********* ", term.DotHere, "\n", 35 "1 \n", 36 "2 \n", Styles, 37 "++++++++++++++++++++++++++++++++++++++++++++++++++", 38 "3 ", 39 ) 40 f.TTYCtrl.TestBuffer(t, buf2) 41 42 evals(f.Evaler, "edit:listing:down", "edit:redraw") 43 buf3 := f.MakeBuffer( 44 "~> \n", 45 " LISTING ", Styles, 46 "********* ", term.DotHere, "\n", 47 "1 \n", 48 "2 \n", 49 "3 ", Styles, 50 "++++++++++++++++++++++++++++++++++++++++++++++++++", 51 ) 52 f.TTYCtrl.TestBuffer(t, buf3) 53 54 evals(f.Evaler, "edit:listing:down", "edit:redraw") 55 f.TTYCtrl.TestBuffer(t, buf3) 56 57 evals(f.Evaler, "edit:listing:down-cycle", "edit:redraw") 58 f.TTYCtrl.TestBuffer(t, buf1) 59 60 evals(f.Evaler, "edit:listing:up", "edit:redraw") 61 f.TTYCtrl.TestBuffer(t, buf1) 62 63 evals(f.Evaler, "edit:listing:up-cycle", "edit:redraw") 64 f.TTYCtrl.TestBuffer(t, buf3) 65 66 evals(f.Evaler, "edit:listing:page-up", "edit:redraw") 67 f.TTYCtrl.TestBuffer(t, buf1) 68 69 evals(f.Evaler, "edit:listing:page-down", "edit:redraw") 70 f.TTYCtrl.TestBuffer(t, buf3) 71 } 72 73 // Smoke tests for individual addons. 74 75 func TestHistlistAddon(t *testing.T) { 76 f := setup(t, storeOp(func(s storedefs.Store) { 77 s.AddCmd("ls") 78 s.AddCmd("echo") 79 s.AddCmd("ls") 80 s.AddCmd("LS") 81 })) 82 83 f.TTYCtrl.Inject(term.K('R', ui.Ctrl)) 84 f.TestTTY(t, 85 "~> \n", 86 " HISTORY (dedup on) ", Styles, 87 "******************** ", term.DotHere, 88 " Ctrl-D dedup\n", Styles, 89 " ++++++ ", 90 " 2 echo\n", 91 " 3 ls\n", 92 " 4 LS ", Styles, 93 "++++++++++++++++++++++++++++++++++++++++++++++++++", 94 ) 95 96 evals(f.Evaler, `edit:histlist:toggle-dedup`) 97 f.TestTTY(t, 98 "~> \n", 99 " HISTORY ", Styles, 100 "********* ", term.DotHere, 101 " Ctrl-D dedup\n", Styles, 102 " ++++++ ", 103 " 1 ls\n", 104 " 2 echo\n", 105 " 3 ls\n", 106 " 4 LS ", Styles, 107 "++++++++++++++++++++++++++++++++++++++++++++++++++", 108 ) 109 110 evals(f.Evaler, `edit:histlist:toggle-dedup`) 111 112 // Filtering is case-insensitive when filter is all lower case. 113 f.TTYCtrl.Inject(term.K('l')) 114 f.TestTTY(t, 115 "~> \n", 116 " HISTORY (dedup on) l", Styles, 117 "******************** ", term.DotHere, 118 " Ctrl-D dedup\n", Styles, 119 " ++++++ ", 120 " 3 ls\n", 121 " 4 LS ", Styles, 122 "++++++++++++++++++++++++++++++++++++++++++++++++++", 123 ) 124 125 // Filtering is case-sensitive when filter is not all lower case. 126 f.TTYCtrl.Inject(term.K(ui.Backspace), term.K('L')) 127 f.TestTTY(t, 128 "~> \n", 129 " HISTORY (dedup on) L", Styles, 130 "******************** ", term.DotHere, 131 " Ctrl-D dedup\n", Styles, 132 " ++++++ ", 133 " 4 LS ", Styles, 134 "++++++++++++++++++++++++++++++++++++++++++++++++++", 135 ) 136 } 137 138 func TestLastCmdAddon(t *testing.T) { 139 f := setup(t, storeOp(func(s storedefs.Store) { 140 s.AddCmd("echo hello world") 141 })) 142 143 f.TTYCtrl.Inject(term.K(',', ui.Alt)) 144 f.TestTTY(t, 145 "~> \n", 146 " LASTCMD ", Styles, 147 "********* ", term.DotHere, "\n", 148 " echo hello world \n", Styles, 149 "++++++++++++++++++++++++++++++++++++++++++++++++++", 150 " 0 echo\n", 151 " 1 hello\n", 152 " 2 world", 153 ) 154 } 155 156 func TestCustomListing_PassingList(t *testing.T) { 157 f := setup(t) 158 159 evals(f.Evaler, 160 `var items = [[&to-filter=1 &to-accept=echo &to-show=echo] 161 [&to-filter=2 &to-accept=put &to-show=(styled put green)]]`, 162 `edit:listing:start-custom $items &accept=$edit:insert-at-dot~ &caption=A`) 163 f.TestTTY(t, 164 "~> \n", 165 "A ", Styles, 166 "* ", term.DotHere, "\n", 167 "echo \n", Styles, 168 "++++++++++++++++++++++++++++++++++++++++++++++++++", 169 "put ", Styles, 170 "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv", 171 ) 172 // Filter - "put" will be selected. 173 f.TTYCtrl.Inject(term.K('2')) 174 // Accept. 175 f.TTYCtrl.Inject(term.K('\n')) 176 f.TestTTY(t, 177 "~> put", Styles, 178 " vvv", term.DotHere, 179 ) 180 } 181 182 func TestCustomListing_PassingValueCallback(t *testing.T) { 183 f := setup(t) 184 185 evals(f.Evaler, 186 `var f = {|q| put [&to-accept='q '$q &to-show=(styled 'q '$q blue)] }`, 187 `edit:listing:start-custom $f &caption=A`) 188 // Query. 189 f.TTYCtrl.Inject(term.K('x')) 190 f.TestTTY(t, 191 "~> \n", 192 "A x", Styles, 193 "* ", term.DotHere, "\n", 194 "q x ", Styles, 195 "##################################################", 196 ) 197 // No-op accept. 198 f.TTYCtrl.Inject(term.K('\n')) 199 f.TestTTY(t, "~> ", term.DotHere) 200 } 201 202 func TestCustomListing_PassingBytesCallback(t *testing.T) { 203 f := setup(t) 204 205 evals(f.Evaler, 206 `var f = {|q| echo '# '$q }`, 207 `edit:listing:start-custom $f &accept=$edit:insert-at-dot~ &caption=A `+ 208 `&binding=(edit:binding-table [&Ctrl-X=$edit:listing:accept~])`) 209 // Test that the query function is used to generate candidates. Also test 210 // the caption. 211 f.TTYCtrl.Inject(term.K('x')) 212 f.TestTTY(t, 213 "~> \n", 214 "A x", Styles, 215 "* ", term.DotHere, "\n", 216 "# x ", Styles, 217 "++++++++++++++++++++++++++++++++++++++++++++++++++", 218 ) 219 // Test both the binding and the accept callback. 220 f.TTYCtrl.Inject(term.K('X', ui.Ctrl)) 221 f.TestTTY(t, 222 "~> # x", Styles, 223 " ccc", term.DotHere) 224 }