├── .github ├── FUNDING.yml └── workflows │ └── test.yml ├── .gitignore ├── LICENSE ├── README.md ├── bin ├── ddv ├── ex_emacs.sh ├── ex_explorer.sh ├── ex_menu.sh ├── ex_pipe.sh ├── ex_slime.sh ├── ex_source_bash.sh ├── ex_source_zsh.sh ├── file_selector └── sentaku ├── renovate.json └── tests ├── function_check.bats └── get_bats_libs.sh /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: rcmdnk # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | function_test: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 12 | - run: sudo apt install bats 13 | - run: cd tests && ./get_bats_libs.sh 14 | - run: | 15 | export PATH=$PWD/bin:$PATH 16 | export TERM=dumb 17 | ./tests/function_check.bats 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | tests/bats-assert/ 2 | tests/bats-support/ 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2014 rcmdnk 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | sentaku 2 | ======= 3 | 4 | Utility to make sentaku (selection, 選択(sentaku)) window with shell command. 5 | 6 | ![sentaku](http://rcmdnk.github.io/images/post/20140124_sentaku.gif) 7 | 8 | If you give multi-word to sentaku by pipe at command line, 9 | you can choose one of them in the sentaku window 10 | then selected one will be returned. 11 | 12 | Requirement: 13 | 14 | - Bash 3.X or later 15 | - Zsh 4.X or later 16 | 17 | ## Installation 18 | 19 | ### Homebrew on Mac 20 | On Mac, you can install scripts by [Homebrew](https://github.com/mxcl/homebrew): 21 | 22 | $ brew tap rcmdnk/rcmdnkpac 23 | $ brew install sentaku 24 | 25 | If you have [brew file](https://github.com/rcmdnk/homebrew-file), add following lines to Brewfile: 26 | 27 | tap 'rcmdnk/rcmdnkpac' 28 | brew 'sentaku' 29 | 30 | then, do: 31 | 32 | $ brew file install 33 | 34 | Or if you write like: 35 | 36 | tapall 'rcmdnk/rcmdnkpac' 37 | 38 | and do `brew file install`, you will have all useful scripts in 39 | [rcmdnkpac](https://github.com/rcmdnk/homebrew-rcmdnkpac). 40 | 41 | Homebrew installation installs all scripts in `bin` directory including examples. 42 | 43 | 44 | ### cURL 45 | 46 | You can also use an install script on the web like: 47 | 48 | $ curl -fsSL https://raw.github.com/rcmdnk/sentaku/install/install.sh| sh 49 | 50 | This will install scripts to `/usr/bin` 51 | and you may be asked root password. 52 | 53 | If you want to install other directory, do like: 54 | 55 | $ curl -fsSL https://raw.github.com/rcmdnk/sentaku/install/install.sh| prefix=~/usr/local/ sh 56 | 57 | This method installs only `sentaku` and `ddv`. 58 | 59 | ### By hand 60 | 61 | Or, simply download scripts and set where you like. 62 | 63 | ## Usage 64 | 65 | ### Standalone 66 | 67 | Use with pipe at command line. 68 | If you run sentaku alone, nothing happens. 69 | 70 | Give any words to sentaku by pipe. 71 | The default separator is `$IFS`. 72 | 73 | If you want to use different separator, 74 | use `-s ` option. 75 | 76 | In case there any directory/file names which have spaces, use line break as a separator, i.e.: 77 | 78 | $ ls | sentaku -s $'\n' 79 | 80 | If you want to use input file instead of pipe, 81 | use `sentaku -F `. 82 | 83 | Other options and key operations at sentaku window are: 84 | 85 | Usage: sentaku [-HNulapEVcCURLSnvh] [-f ] [-s ] [-r ] [input variables] 86 | 87 | Arguments: 88 | -f Set input file 89 | -s Set separator (default: $IFS) 90 | If is \"line\", \$'\\n' is set as a separator. 91 | -H Force to show a header at sentaku window. 92 | -N No numbers are shown. 93 | -u Use underline to show selected line, instead of highlighting. 94 | -l Show last words instead of starting words for longer lines. 95 | -a Align input list (set selected one to the first). 96 | -r Return nth value directly. 97 | -p Push words to the file. 98 | -E Use Emacs mode 99 | -V Use Vim mode 100 | -c Load functions as a child process in other sentaku process. 101 | -C Show the file content at the list view 102 | -R Show the file content in the right (default: right) 103 | -U Show the file content under the list (default: right) 104 | -L Number of lines to show the file content under the list (default: 10) 105 | -S Open the file under the cursor by ${VISUAL:-less} at s 106 | instead of full line of the selected one 107 | -n Don't run functions, to just source this file 108 | -v Show version 109 | -h Print this HELP and exit 110 | 111 | Key operation at sentaku window 112 | Common for all: 113 | C-p/C-n Up/Down. 114 | C-u/C-d Half page down/Half page down. 115 | C-b/C-f Page up/Page down. 116 | M-v/C-v Page up/Page down. 117 | C-a/C-e Go to the beginning/end. 118 | C-i/C-o Move the item up/down. 119 | C-x Quit. 120 | C-s Start/Stop Visual mode (multi-selection). 121 | Space Select/unselect current line for multi-selection. 122 | At Emacs mode or search mode in Vim mode, 123 | it selects when space is pushed twice. 124 | Esc At search mode, first Esc takes it back to normal mode 125 | with selected words. 126 | Second Esc clear search mode. 127 | Visual mode is cleared by first Esc. 128 | Enter Select and Quit. 129 | 130 | For Vim mode: 131 | n(any number) Set number. Multi-digit can be used (13, 320, etc...). 132 | Used/reset by other key. 133 | k/j Up/Down (if n is given, n-th up/n-th down). 134 | gg/G Go to top/bottom. (If n is given, move to n-th candidate.) 135 | d Delete current candidate. (in case you use input file.) 136 | s Show detail of current candidate. 137 | v Visual mode, same as C-s 138 | / Search. 139 | q Quit. 140 | Others Nothing happens. 141 | 142 | For Emacs mode: 143 | Others Normal keys start an incremental search. 144 | 145 | #### Environment Variables 146 | 147 | Name| Description| Default 148 | :--:|:-----------|:------: 149 | SENTAKU_INPUT_FILE|File used when stdin is not used (overwritten by -f).|"$HOME/.sentaku_input" 150 | SENTAKU_SEPARATOR|Separator(overwritten by -s).|$IFS 151 | SENTAKU_MAX|Max number to be written to the file (non-stdin usage).|20 152 | SENTAKU_NOHEADER|Don't show the header (overwritten by -H). 0: show, 1: don't show.|0 (1 for noheader) 153 | SENTAKU_NONUMBER|Don't show the line number (overwritten by -N). 0: show, 1: don't show.|0 (1 for nonumber) 154 | SENTAKU_SHOWLAST|Show the number at the end of the line, too (overwritten by -l). 0: don't show, 1: show.|0 155 | SENTAKU_CONTENT_LINES|Set number of lines to show the file content under the list|10 156 | SENTAKU_CONTENT_SHOW_UNDER|Set 1 to set default view of the file content as under the list|0 157 | SENTAKU_CHILD|If this sentaku is child process of parent sentaku or not.|0 158 | SENTAKU_SEARCH_OPT|Search option, 0: AND (ignore case), 1: AND (case sensitive), 2: starts with (ignore case), 3: starts with (case sensitive).|1 159 | SENTAKU_KEYMODE|Vim Mode or Emacs Mode, 0: Vim Mode, 1: Emacs Mode (overwritten by -V/-E).| 0 160 | SENTAKU_DEBUG|If it is 1, `_sf_echo_debug` is executed.|0 161 | 162 | #### Vim/Emacs mode 163 | 164 | Default mode is Vim mode, in which you can go up/down with k/j, respectively. 165 | 166 | If you like emacs mode, you use `-E` option, 167 | or set the value like `export SENTAKU_KEYMODE=1` in your `.bashrc`/`.zshrc`. 168 | In this mode, ``/`` are used for going up/down, respectively (These keys are also available at Vim mode). 169 | It has nice feature that you can start incremental search directly 170 | by pushing any normal keys. 171 | 172 | * Simple Examples: 173 | * [ex_pipe.sh](https://github.com/rcmdnk/sentaku/blob/master/bin/ex_pipe.sh): Example for Vim mode (Default). 174 | * [ex_emacs](https://github.com/rcmdnk/sentaku/blob/master/bin/ex_emacs.sh): Example for Emacs mode. 175 | 176 | * Item Up/Down Demo 177 | 178 | ![item_up_down](http://rcmdnk.github.io/images/post/20140621_sentaku_item_updown.gif) 179 | 180 | 181 | #### Search mode 182 | 183 | If you push `/`, sentaku enters search mode (at Vim mode). 184 | 185 | You can narrow the list by pushing starting characters. 186 | 187 | Backspace (``) can be used to delete a character. 188 | In addition, `` deletes all characters. 189 | 190 | You can select the first of the list (or the last remained one) by the Enter. 191 | 192 | If you push `Esc` while some candidates are remained, 193 | you can select them as select window. 194 | 195 | When you push `Esc` again, the original list will come back. 196 | 197 | You can set search option `SENTAKU_SEARCH_OPT`: 198 | 199 | * 0: AND search (smart case, i.e. all lower case word search is case insensitive, otherwise case sensitive) (Default) 200 | * 1: AND search (case sensitive) 201 | * 2: Starts with (smart case) 202 | * 3: Starts with(case sensitive) 203 | 204 | * [Search Demo for Vim mode, SENTAKU_KEYMODE = 3](http://rcmdnk.github.io/images/post/20140805_vim_search.gif) 205 | 206 | ![sentaku_vim](http://rcmdnk.github.io/images/post/20140805_vim_search.gif) 207 | 208 | 209 | * [Search Demo for Emacs mode, SENTAKU_KEYMODE = 1](http://rcmdnk.github.io/images/post/20140805_emacs_search.gif) 210 | 211 | ![sentaku_emacs](http://rcmdnk.github.io/images/post/20140805_emacs_search.gif) 212 | 213 | #### Visual mode (multi-selection) 214 | 215 | ![sentaku_vim_multi](http://rcmdnk.github.io/images/post/20140805_vim_multi.gif) 216 | 217 | By pushing `Ctrl-s` (or `v` (only Vim mode)), 218 | you can start/stop to choose multi-line. 219 | 220 | Output will be separated by `SENTAKU_SEPARATOR` (default is $IFS). 221 | 222 | You can choose non-sequential lines. 223 | 224 | In addition, you can toggle lines by `Space`. 225 | 226 | ![sentaku_multi](http://rcmdnk.github.io/images/post/20140926_sentaku_multi.gif) 227 | 228 | #### Content view 229 | 230 | ![sentaku_multi](http://rcmdnk.github.io/images/post/20190930_sentakucontentview.gif) 231 | 232 | * [sentakuでファイルの中身を選択中に表示する](http://rcmdnk.github.io/blog/2019/09/30/computer-bash-zsh-sentaku/) 233 | 234 | ### Use as a library 235 | 236 | You can use sentaku as a library for your shell script. 237 | 238 | At sentaku window, all normal keys are assigned to functions like: 239 | 240 | * a-z: `_sf_a ()` ~ `_sf_z ()` 241 | * A-Z: `_sf_A ()` ~ `_sf_z ()` 242 | * 0-9: `_sf_0 ()` ~ `_sf_9 ()` 243 | * Ctrl-a - Ctrl-z: `_sf_c_a ()` ~ `_sf_c_z ()` 244 | 245 | In addition following keys are assigned: 246 | 247 | * Enter/Space: `_sf_select ()` 248 | * /: Start Search 249 | * Esc: Reset Search 250 | 251 | Following functions have default methods: 252 | 253 | * `_sf_0 ()` ~ `_sf_9 ()` 254 | * `_sf_d ()`/`_sf_g ()`/`_sf_j ()`/`_sf_k ()`/`_sf_q ()`/`_sf_s ()`/`_sf_v ()`/`_sf_G ()` 255 | * `_sf_c_a ()`/`_sf_c_b ()`/`_sf_c_c ()`/`_sf_c-e ()`/`_sf_c_f ()`/`_sf_c_c_n ()`/`_sf_c_s ()`/`_sf_c_u ()`/`_sf_c_v ()`/`_sf_c_x ()` 256 | 257 | And others are just set like `_sf_a () { :;}` (do nothing). 258 | 259 | If you simply add new key operation, make a script like: 260 | 261 | ``` sh 262 | #!/usr/bin/env bash 263 | . sentaku -n 264 | _sf_a () { 265 | _sf_echo "You pushed a!" 266 | } 267 | _sf_main "$@" 268 | ``` 269 | 270 | First, load `sentaku` with `-n` option, which don't execute functions here. 271 | 272 | Then, add your functions. 273 | 274 | In the last, call `_sf_main` function with arguments (`$@`). 275 | 276 | Save this script as `my_sentaku.sh`, then you can use it as same as 277 | original sentaku command. 278 | In addition, you can see `You pushed a!` when you push `a`. 279 | To show something, use `_sf_echo` instead of `echo`. 280 | 281 | You can define functions instead of making scripts, too. 282 | 283 | In **.bashrc** or **.zshrc**, 284 | add 285 | 286 | ``` sh 287 | my_sentaku () { 288 | ( 289 | . sentaku -n 290 | 291 | _sf_a () { 292 | _sf_echo "You pushed a!" 293 | } 294 | 295 | _sf_main "$@" 296 | ) 297 | } 298 | ``` 299 | 300 | then you can use `my_sentaku` with your `_sf_a` instead of `sentaku`. 301 | 302 | Note: Use sub shell (define function content in `()`) 303 | because `. sentaku -n` loads a lot of functions 304 | and it is better to avoid making current environment dirty. 305 | 306 | More examples can be found below. 307 | 308 | #### Simple examples to use like snippet 309 | 310 | The easiest examples are: 311 | 312 | * [ex_source_bash.sh](https://github.com/rcmdnk/sentaku/blob/master/bin/ex_source_bash.sh) 313 | * [ex_source_zsh.sh](https://github.com/rcmdnk/sentaku/blob/master/bin/ex_source_zsh.sh) 314 | 315 | They are example to use pre-defined list file (`$HOME/.my_input`), 316 | and select one from it. 317 | 318 | The separator is `$'\x07'` (BELL), therefore you can store even sentences in the list file (can be used as a snippet application). 319 | 320 | These two are examples for Bash and Zsh, respectively. 321 | (only the shebang is different.) 322 | 323 | #### Example: Explorer 324 | 325 | * [ex_explorer.sh](https://github.com/rcmdnk/sentaku/blob/master/bin/ex_explorer.sh) 326 | 327 | It starts from current directory, show all files/directories. 328 | If you choose directory, the window goes to the chosen directory. 329 | 330 | At sentaku window: 331 | 332 | * `s`: Show details (ls -l) 333 | * `d`: Delete selected file/directory 334 | * `l`: Open file with `less` 335 | * `e`: Open file with $EDITOR (or `vim`) 336 | * `Enter`/`Space`: Move the directly 337 | * `q`: Quit 338 | 339 | ##### Tips 340 | 341 | The original `_sf_select` function, which is executed when you push `Enter` or `Space`, is defined as: 342 | 343 | ``` sh 344 | _sf_select () { # {{{ 345 | _s_break=1 346 | } # }}} 347 | ``` 348 | 349 | If `_s_break` flag is 1, it breaks key operation and goes to `_sf_execute ()`. 350 | If you want to skip `_sf_execute`, call `_sf_quit` instead of `_sf_select=`. 351 | 352 | In this script, this function is redefined like: 353 | 354 | ``` sh 355 | _sf_select () { 356 | cd ${_s_inputs[$_s_current_n]} 357 | ... 358 | } 359 | ``` 360 | 361 | It does `cd` to currently selected directory (`${_s_inputs[$_s_current_n]}`), 362 | 363 | `_s_current_n` is currently selected number (same as the number in the left of the list.) 364 | `_s_inputs` is an array which is made from the input. 365 | Therefore, `${_s_inputs[$_s_current_n]}` is currently selected value. 366 | 367 | And it does not set `_s_break` flag, 368 | therefore it stays in key operation (sentaku window). 369 | 370 | If you want to break with any key, you can change `_s_break` flag in 371 | corresponding function. 372 | 373 | 374 | Another point: `_sf_l` is defined as: 375 | 376 | ``` sh 377 | _sf_l () { # {{{ 378 | clear >/dev/tty 379 | less ${_s_inputs[$_s_current_n]} >/dev/tty /dev/tty 2>/dev/null || tput vi >/dev/tty 2>/dev/null 15 | _sf_rm_del 16 | } # }}} 17 | 18 | _sf_set_header () { # {{{ 19 | _s_show="$_s_first_dir" 20 | _sf_show 0 $((_s_cols-3)) 21 | local a_dir="$_s_show" 22 | _s_show="$_s_second_dir" 23 | _sf_show 0 $((_s_cols-3)) 24 | local b_dir="$_s_show" 25 | _s_header="" 26 | if [ $_s_noheader = 1 -o $_s_lines -lt 10 ];then 27 | return 28 | elif [ $_s_cols -ge 66 ];then 29 | _s_header=" $_s_n files are different in 30 | <:$a_dir 31 | >:$b_dir 32 | [n]j(n-down), [n]k(n-up), gg(top), G(bottom), [n]gg/G, (go to n) 33 | ^D(lf page down), ^U(Half page up), ^F(Page down), ^B(Page Up) 34 | d(delete from the list), Enter/Space(vim diff), q(quit)" 35 | elif [ $_s_cols -ge 40 ];then 36 | _s_header=" $_s_n values in total 37 | a:$a_dir 38 | b:$b_dir 39 | vimike updown, e.g)j:down, k:up, gg/G 40 | d(delete from the list), 41 | Enter/Space(vim diff), q(quit)" 42 | fi 43 | } # }}} 44 | 45 | opt="" 46 | if [ "$1" = "-w" ];then 47 | opt=$1 48 | shift 49 | fi 50 | 51 | if [ $# -ne 2 ];then 52 | echo "usage: basename($0) [-n] dir1 dir2" 53 | echo " -w: Ignore all spaces (--ignore-blank-lines -w)" 54 | exit 1 55 | fi 56 | _s_first_dir="${1%/}/" 57 | _s_second_dir="${2%/}/" 58 | 59 | if [ ! -d "$_s_first_dir" ] || [ ! -d "$_s_second_dir" ];then 60 | "$_s_first_dir" or "$_s_second_dir" is not a directory. 61 | exit 1 62 | fi 63 | 64 | #echo "diff $opt -rq \"$_s_first_dir\" \"$_s_second_dir\" |grep \"^Files\" |grep -v "\.svn\/"| grep -v "\.git\/"|grep -v ^Binary| sed \"s|.*${_s_second_dir}||g\"|sed \"s| differ$||\"" 65 | diff_ret=$(diff $opt -rq "$_s_first_dir" "$_s_second_dir" |grep "^Files" |grep -v .svn| grep -v .git|grep -v Binary|\ 66 | sed "s|.*${_s_second_dir}||g"|sed "s| differ$||") 67 | if [ "$diff_ret" = "" ];then 68 | echo "There are no remained diff files" 69 | else 70 | echo "$diff_ret"|_sf_main 71 | fi 72 | -------------------------------------------------------------------------------- /bin/ex_emacs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # example script to use emacs mode 4 | 5 | export SENTAKU_KEYMODE=1 6 | list="aaa abc xxxaaaxxx bbbAAA cccaaaXXX" 7 | ret=$(echo $list|sentaku "$@") 8 | if [ "x$ret" != "x" ];then 9 | echo $ret is selected 10 | fi 11 | -------------------------------------------------------------------------------- /bin/ex_explorer.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Example of explorer 4 | . sentaku -n 5 | 6 | _SENTAKU_SEPARATOR=$'\n' 7 | _SENTAKU_EDITOR="" 8 | 9 | # New variable 10 | _s_a=0 11 | 12 | # New help 13 | _s_help=" 14 | Usage: ex_explorer.sh [-aHNl] [-f ] [-s ] 15 | 16 | Arguments: 17 | -a Show hidden files/directories. 18 | -H Header is shown at sentaku window. 19 | -N No nubmers are shown. 20 | -l Show last words instead of starting words for longer lines. 21 | -h Print this HELP and exit. 22 | " 23 | 24 | _sf_get_values () { # {{{ 25 | # Get variables 26 | local orig_ifs=$IFS 27 | IFS="$_s_s" 28 | if [ $_s_a -eq 1 ];then 29 | _s_inputs=($(ls -a)) 30 | else 31 | _s_inputs=(".." $(ls)) 32 | fi 33 | IFS=$orig_ifs 34 | _s_n=${#_s_inputs[@]} 35 | } # }}} 36 | 37 | _sf_printline () { # useage: _sf_printline is_selected n_line n_input {{{ 38 | local show=${_s_inputs[$3]} 39 | tput cup $2 0 >/dev/tty 40 | if [ $1 -eq 1 ];then 41 | printf "\e[7m" >/dev/tty 42 | fi 43 | if [ -d "$show" ];then 44 | printf "\e[33;1m" >/dev/tty 45 | fi 46 | local n_show=$_s_cols 47 | local num="" 48 | if [ $_s_nonumber -eq 0 ];then 49 | n_show=$((_s_cols-5)) 50 | num=$(printf "%3d: " $3) 51 | fi 52 | if [ ${#show} -gt $n_show ];then 53 | if [ $_s_showlast -eq 0 ];then 54 | if [ "$ZSH_NAME" = "zsh" ];then # need for zsh version < 5 55 | printf "$num${show[0,$((n_show-1))]}" >/dev/tty 56 | else 57 | printf "$num${show: 0: $n_show}" >/dev/tty 58 | fi 59 | else 60 | if [ "$ZSH_NAME" = "zsh" ];then # need for zsh version < 5 61 | printf "$num${show[$((${#show}-$n_show)),-1]}" >/dev/tty 62 | else 63 | printf "$num${show: $((${#show}-$n_show))}" >/dev/tty 64 | fi 65 | fi 66 | else 67 | printf "$num${show}" >/dev/tty 68 | fi 69 | printf "\e[m" >/dev/tty 70 | tput cup $2 0 >/dev/tty 71 | } # }}} 72 | 73 | _sf_execute () { # {{{ 74 | : 75 | } # }}} 76 | 77 | _sf_check_args () { # {{{ 78 | # Get arguments 79 | _s_continue=0 80 | while [ $# -gt 0 ];do 81 | case $1 in 82 | "-a" ) _s_a=1;shift;; 83 | "-H" ) _s_noheader=1;shift;; 84 | "-N" ) _s_nonumber=1;shift;; 85 | "-l" ) _s_showlast=1;shift;; 86 | "-h" ) 87 | _sf_echo "$_s_help" 88 | return 0 89 | ;; 90 | * ) 91 | _sf_echo "$_s_help" 92 | return 1 93 | ;; 94 | esac 95 | done 96 | _s_continue=1 97 | return 0 98 | } # }}} 99 | 100 | _sf_finalize_user () { # {{{ 101 | unset _s_a 102 | } # }}} 103 | 104 | _sf_select () { # {{{ 105 | if [ -d "${_s_inputs[$_s_current_n]}" ];then 106 | cd "${_s_inputs[$_s_current_n]}" 107 | _sf_get_values 108 | _sf_reset 109 | else 110 | _sf_echo "${_s_inputs[$_s_current_n]} is not a directory" 111 | fi 112 | } # }}} 113 | 114 | _sf_set_header () { # {{{ 115 | _s_header="" 116 | if [ $_s_noheader != 1 -a $_s_lines -gt 10 ];then 117 | local curdir=$(pwd) 118 | if [ $((${#curdir}+1)) -gt $_s_cols ];then 119 | if [ "$ZSH_NAME" = "zsh" ];then 120 | curdir=${curdir[$((${#curdir}-${_s_cols}+1)),-1]} 121 | else 122 | curdir=${curdir: $((${#curdir}-${_s_cols}+1))} 123 | fi 124 | fi 125 | if [ $_s_cols -ge 66 ];then 126 | _s_header=" $curdir 127 | [n]j(n-down), [n]k(n-up), gg(top), G(bottom), [n]gg/G, (go to n), 128 | ^D(Half page down), ^U(Half page up), ^F(Page down), ^B(Page Up), 129 | s(show detail), d(delete), l(open with less), e(edit the file) 130 | Enter(select, move to the directory), q(quit)" 131 | elif [ $_s_cols -ge 42 ];then 132 | _s_header=" $curdir 133 | vim-like updown, e.g)j:down, k:up, gg/G 134 | s(show detail), d(delete), 135 | l(open with less), e(edit the file) 136 | Enter(move to the directory), q(quit)" 137 | fi 138 | fi 139 | } # }}} 140 | 141 | _sf_d () { 142 | clear >/dev/tty 143 | local yes=0 144 | while : ;do 145 | echo "Delete ${_s_inputs[$_s_current_n]}?: (y/n)" 146 | _sf_read 147 | if [ "$_s_read" = "y" ];then 148 | yes=1 149 | break 150 | elif [ "$_s_read" = "n" ];then 151 | break 152 | fi 153 | done 154 | if [ $yes -eq 1 ];then 155 | rm -rf ${_s_inputs[$_s_current_n]} 156 | fi 157 | _sf_get_values 158 | } 159 | 160 | _sf_s () { # {{{ 161 | _sf_echo $(ls -l "${_s_inputs[$_s_current_n]}") 162 | } # }}} 163 | 164 | _sf_l () { # {{{ 165 | clear >/dev/tty 166 | less ${_s_inputs[$_s_current_n]} >/dev/tty /dev/tty /dev/tty 29 | 30 | echo "Enter words: " >/dev/tty 31 | # Show cursor 32 | tput cnorm >/dev/tty 2>/dev/null || tput vs >/dev/tty 2>/dev/null 33 | read _s_selected /dev/tty 121 | _sf_wait 122 | return 0 123 | ;; 124 | * ) 125 | echo "$_s_help" >/dev/tty 126 | _sf_wait 127 | return 1 128 | ;; 129 | esac 130 | done 131 | if [ $_s_lang = "en" ];then 132 | _s_your_name="${_YOUR_NAME_EN}" 133 | _s_weapon=$_YOUR_WEAPON_EN 134 | _s_weapon_message="Weapon: $_s_weapon" 135 | _s_your_spells=("${_YOUR_SPELLS_EN[@]}") 136 | _s_spell_message="Spell: 137 | $(for ((i=0; i<${#_s_your_spells[@]}; i++));do \ 138 | echo " ${_s_your_spells[$i]}: MP ${_YOUR_SPELLS_MP[$i]} Required";done)" 139 | _s_spells_message="Spell: ${_s_spells[@]}" 140 | _s_item_message="No Item" 141 | _s_command=" Command:" 142 | _s_your_info=" $_s_your_name HP: $_s_your_hp MP: $_s_your_mp" 143 | _s_message=" A $_SLIME_NAME_EN Draws Near! $_s_command 144 | " 145 | _s_fight_command=" ${_s_your_name} attacks!" 146 | _sf_spell_command () { echo " ${_s_your_name} casts $1!";} 147 | _s_run_command=" Failed to escape!" 148 | _s_item_command=" No Item!" 149 | _s_slime_fight=" The $_SLIME_NAME_EN attacks!" 150 | _s_damage="damage!" 151 | _sf_cured () { echo "HP ${1} cured!";} 152 | _s_failed=" Failed!" 153 | _s_nomp=" No enough MP remained!" 154 | _s_attacks=" 155 | 156 | $_s_command" 157 | fi 158 | _s_continue=1 159 | return 0 160 | 161 | } # }}} 162 | 163 | _sf_get_values () { # {{{ 164 | if [ $_s_lang = "ja" ];then 165 | _s_inputs=($(echo $_MENU)) 166 | else 167 | _s_inputs=($(echo $_MENU_EN)) 168 | fi 169 | _s_n=${#_s_inputs[@]} 170 | } # }}} 171 | 172 | _sf_initialize_user () { # {{{ 173 | _s_your_hp=$_YOUR_HP 174 | _s_your_hp_max=$_YOUR_HP 175 | _s_your_mp=$_YOUR_MP 176 | _s_slime_hp=$((_SLIME_MIN_HP+RANDOM%(_SLIME_MAX_HP-_SLIME_MIN_HP+1))) 177 | _s_slime_this_max_hp=$_s_slime_hp 178 | [ $_s_slime_hp -eq 0 ] && _s_slime_hp=1 179 | _s_lang="ja" 180 | 181 | _s_your_name="$_YOUR_NAME" 182 | _s_weapon="$_YOUR_WEAPON" 183 | _s_weapon_message="武器: $_s_weapon" 184 | _s_your_spells=("${_YOUR_SPELLS[@]}") 185 | _s_spell_message="魔法: 186 | $(for ((i=0; i<${#_s_your_spells[@]}; i++));do \ 187 | echo " ${_YOUR_SPELLS[$i]}: 消費MP ${_YOUR_SPELLS_MP[$i]}";done)" 188 | _s_item_message="何も持ってない" 189 | _s_command=" コマンド:" 190 | _s_your_info=" $_s_your_name HP: $_s_your_hp MP: $_s_your_mp" 191 | _s_message=" ${_SLIME_NAME}があらわれた! $_s_command 192 | " 193 | _s_fight_command=" ${_s_your_name}の攻撃!" 194 | _sf_spell_command () { echo " ${_s_your_name}は${1}を唱えた!";} 195 | _s_run_command=" 逃げだした! しかし回りこまれた!" 196 | _s_item_command=" アイテムを持ってない!" 197 | _s_slime_fight=" ${_SLIME_NAME}の攻撃!" 198 | _s_damage="のダメージ!" 199 | _sf_cured () { echo "HP ${1} 回復!";} 200 | _s_failed=" かわされた!" 201 | _s_nomp=" しかしMPがたりない!" 202 | _s_attacks=" 203 | 204 | $_s_command" 205 | _s_message_tmp="" 206 | _s_first_message="" 207 | _s_second_message="" 208 | 209 | _s_your_attack=0 210 | _s_slime_attack=0 211 | } # }}} 212 | 213 | _sf_finzlize_user () { # {{{ 214 | : 215 | } # }}} 216 | 217 | _sf_win () { # {{{ 218 | _s_message="\e[1;5;35;42m 219 | __ __ __ ___ _ 220 | \ \ / / \ \ / (_) | | 221 | \ \_/ /__ _ _ \ \ /\ / / _ _ __ | | 222 | \ / _ \| | | | \ \/ \/ / | | _ \| | 223 | | | (_) | |_| | \ /\ / | | | | |_| 224 | |_|\___/ \__,_| \/ \/ |_|_| |_(_) 225 | \e[m 226 | " 227 | _sf_set_header 228 | _sf_echo "$_s_header" 229 | _sf_quit 0 230 | } # }}} 231 | 232 | _sf_lose () { # {{{ 233 | _s_message="\e[1;5;31;44m 234 | __ __ _ _ 235 | \ \ / / | | | | 236 | \ \_/ /__ _ _ | | ___ ___ ___| | 237 | \ / _ \| | | | | | / _ \/ __|/ _ \ | 238 | | | (_) | |_| | | |___| (_) \__ \ __/_| 239 | |_|\___/ \__,_| |______\___/|___/\___(_) 240 | \e[m 241 | " 242 | _sf_set_header 243 | _sf_echo "$_s_header" 244 | _sf_quit 1 245 | } # }}} 246 | 247 | _sf_rand () { # _sf_rand min max [miss] {{{ 248 | local min=$1 249 | local max=$2 250 | local miss=${3:-0} 251 | if [ $max -ne 0 ];then 252 | if [ $miss -eq 0 ] || [ $((RANDOM%miss)) -ne 0 ];then 253 | echo $((min+RANDOM%(max-min+1))) 254 | return 255 | fi 256 | fi 257 | echo 0 258 | return 259 | } # }}} 260 | 261 | _sf_attacks () { # your_min your_max your_miss slime_min slime_max slime_miss {{{ 262 | _s_your_attack=$(_sf_rand $1 $2 $3) 263 | _s_slime_attack=$(_sf_rand $4 $5 $6) 264 | } # }}} 265 | 266 | _sf_your_attack () { # {{{ 267 | if [ $_s_your_attack -eq 0 ];then 268 | _s_message_tmp="$1 $_s_failed" 269 | return 270 | fi 271 | _s_slime_hp=$((_s_slime_hp-_s_your_attack)) 272 | [ $_s_slime_hp -lt 0 ] && _s_slime_hp=0 273 | _s_message_tmp="$1 $_s_your_attack $_s_damage" 274 | } # }}} 275 | 276 | _sf_your_heal () { # {{{ 277 | local cur_hp=$_s_your_hp 278 | _s_your_hp=$((_s_your_hp+_s_your_heal)) 279 | [ $_s_your_hp -gt $_s_your_hp_max ] && _s_your_hp=$_s_your_hp_max 280 | _s_message_tmp="$1 $(_sf_cured $((_s_your_hp-cur_hp)))" 281 | } # }}} 282 | 283 | _sf_slime_attack () { # {{{ 284 | if [ $_s_slime_attack -eq 0 ];then 285 | _s_message_tmp="$1 $_s_failed" 286 | return 287 | fi 288 | _s_your_hp=$((_s_your_hp-_s_slime_attack)) 289 | _s_message_tmp="$1 $_s_slime_attack $_s_damage" 290 | } # }}} 291 | 292 | _sf_your_info () { # {{{ 293 | if [ $_s_your_hp -lt 0 ];then 294 | _s_your_hp=0 295 | _s_your_info=" \e[34m$_s_your_name HP: $_s_your_hp MP: $_s_your_mp\e[m" 296 | elif [ $_s_your_hp -lt 10 ];then 297 | _s_your_info=" \e[31m$_s_your_name HP: $_s_your_hp MP: $_s_your_mp\e[m" 298 | else 299 | _s_your_info=" $_s_your_name HP: $_s_your_hp MP: $_s_your_mp" 300 | fi 301 | } # }}} 302 | 303 | _sf_slime_heal () { # {{{ 304 | local cur_hp=$_s_slime_hp 305 | _s_slime_hp=$((_s_slime_hp+_s_slime_heal)) 306 | [ $_s_slime_hp -gt $_s_slime_this_max_hp ] && _s_slime_hp=$_s_slime_this_max_hp 307 | _s_message_tmp="$1" 308 | _s_message_tmp="$1 $(_sf_cured $((_s_slime_hp-cur_hp)))" 309 | } # }}} 310 | 311 | _sf_check_hp () { # {{{ 312 | [ $_s_your_hp -le 0 ] && _sf_lose 313 | [ $_s_slime_hp -le 0 ] && _sf_win 314 | } # }}} 315 | 316 | _sf_new_message () { # {{{ 317 | _s_message="$1" 318 | _sf_your_info 319 | _sf_setview 320 | _sf_echo "${_s_header}" 321 | } # }}} 322 | 323 | _sf_command_reset () { # {{{ 324 | _s_message="$_s_command 325 | " 326 | } # }}} 327 | 328 | _sf_message () { # is_you_first your_message is_attack slime_message is_attack {{{ 329 | _s_first_message=$2 330 | if [ $1 -eq 0 ];then 331 | _s_first_message=$4 332 | fi 333 | _sf_new_message "$_s_first_message 334 | " 335 | 336 | if [ $1 -eq 1 -a "$3" -eq 1 ] || [ $1 -eq 0 -a "$5" -eq 1 ] ;then 337 | if [ $1 -eq 1 ];then 338 | _sf_your_attack "$2" 339 | else 340 | _sf_slime_attack "$4" 341 | fi 342 | _s_first_message=$_s_message_tmp 343 | _sf_new_message "$_s_first_message 344 | " 345 | _sf_check_hp 346 | [ $_s_break -eq 1 ] && return 347 | elif [ $1 -eq 1 -a "$3" -eq 2 ] || [ $1 -eq 0 -a "$5" -eq 2 ] ;then 348 | if [ $1 -eq 1 ];then 349 | _sf_your_heal "$2" 350 | else 351 | _sf_slime_heal "$4" 352 | fi 353 | _s_first_message=$_s_message_tmp 354 | _sf_new_message "$_s_first_message 355 | " 356 | elif [ $1 -eq 1 -a "$3" -eq 3 ] || [ $1 -eq 0 -a "$5" -eq 3 ] ;then 357 | if [ $1 -eq 1 ];then 358 | _s_first_message="$2 $_s_nomp" 359 | else 360 | _s_first_message="$4 $_s_nomp" 361 | fi 362 | _sf_new_message "$_s_first_message 363 | " 364 | fi 365 | 366 | _s_second_message="$4" 367 | if [ $1 -eq 0 ];then 368 | _s_second_message="$2" 369 | fi 370 | _sf_new_message "$_s_first_message 371 | $_s_second_message" 372 | if [ $1 -eq 0 -a "$3" -eq 1 ] || [ $1 -eq 1 -a "$5" -eq 1 ] ;then 373 | if [ $1 -eq 1 ];then 374 | _sf_slime_attack "$4" 375 | else 376 | _sf_your_attack "$2" 377 | fi 378 | _s_second_message=$_s_message_tmp 379 | _sf_new_message "$_s_first_message 380 | $_s_second_message" 381 | _sf_check_hp 382 | [ $_s_break -eq 1 ] && return 383 | elif [ $1 -eq 0 -a "$3" -eq 2 ] || [ $1 -eq 1 -a "$5" -eq 2 ] ;then 384 | if [ $1 -eq 1 ];then 385 | _sf_slime_heal "$4" 386 | else 387 | _sf_your_heal "$2" 388 | fi 389 | _s_second_message=$_s_message_tmp 390 | _sf_new_message "$_s_first_message 391 | $_s_second_message" 392 | elif [ $1 -eq 0 -a "$3" -eq 3 ] || [ $1 -eq 1 -a "$5" -eq 3 ] ;then 393 | if [ $1 -eq 1 ];then 394 | _s_second_message="$4 $_s_nomp" 395 | else 396 | _s_second_message="$2 $_s_nomp" 397 | fi 398 | _sf_new_message "$_s_first_message 399 | $_s_second_message" 400 | fi 401 | _sf_command_reset 402 | } # }}} 403 | 404 | _sf_0 () { # FIGHT {{{ 405 | local first=$((RANDOM%2)) 406 | _sf_attacks ${_YOUR_WEAPON_POWER[0]} ${_YOUR_WEAPON_POWER[1]} $_YOUR_WEAPON_MISS \ 407 | ${_SLIME_POWER[0]} ${_SLIME_POWER[1]} $_SLIME_POWER_MISS 408 | _sf_message $first "$_s_fight_command" 1 "$_s_slime_fight" 1 409 | } # }}} 410 | 411 | _sf_1 () { # SPELL {{{ 412 | local first=$((RANDOM%2)) 413 | local spell=$(_sf_spell) 414 | #_sf_hide 415 | local is_attack=2 416 | if [ "$spell" = "${_s_your_spells[0]}" ];then 417 | local s_m=$(_sf_spell_command "$spell") 418 | if [ $_s_your_mp -lt ${_YOUR_SPELLS_MP[0]} ];then 419 | _s_your_heal=0 420 | is_attack=3 421 | else 422 | _s_your_heal=$(_sf_rand ${_YOUR_HEAL[0]} ${_YOUR_HEAL[1]}) 423 | _s_your_mp=$((_s_your_mp-${_YOUR_SPELLS_MP[0]})) 424 | fi 425 | _sf_attacks 0 0 0\ 426 | ${_SLIME_POWER[0]} ${_SLIME_POWER[1]} $_SLIME_POWER_MISS 427 | _sf_message $first "$s_m" $is_attack "$_s_slime_fight" 1 428 | elif [ "$spell" = "${_s_your_spells[1]}" ];then 429 | local s_m=$(_sf_spell_command "$spell") 430 | local min=0 431 | local max=0 432 | local miss=0 433 | if [ $_s_your_mp -lt ${_YOUR_SPELLS_MP[1]} ];then 434 | is_attack=3 435 | else 436 | is_attack=1 437 | min=${_YOUR_HURT[0]} 438 | max=${_YOUR_HURT[1]} 439 | _s_your_mp=$((_s_your_mp-${_YOUR_SPELLS_MP[1]})) 440 | fi 441 | _sf_attacks $min $max $miss\ 442 | ${_SLIME_POWER[0]} ${_SLIME_POWER[1]} $_SLIME_POWER_MISS 443 | _sf_message $first "$s_m" $is_attack "$_s_slime_fight" 1 444 | fi 445 | _sf_command_reset 446 | } # }}} 447 | 448 | _sf_spell () { # {{{ 449 | . sentaku -n -c 450 | 451 | _sf_set_header () { 452 | _sf_set_header_mine 453 | } 454 | 455 | _sf_s () { 456 | local i 457 | for((i=0; i<${#_s_your_spells[@]}; i++));do 458 | if [ $_s_current_n -eq $i ];then 459 | _sf_new_message " ${_s_your_spells[$i]}: MP ${_YOUR_SPELLS_MP[$i]}" 460 | _sf_command_reset 461 | break 462 | fi 463 | done 464 | } 465 | 466 | echo "${_s_your_spells[@]}"| _sf_main 467 | } # }}} 468 | 469 | _sf_2 () { # RUN {{{ 470 | if [ $((RANDOM%sudden_death)) -eq 0 ];then 471 | _sf_sudden_death 472 | else 473 | _sf_attacks 0 0 0\ 474 | ${_SLIME_POWER[0]} ${_SLIME_POWER[1]} $_SLIME_POWER_MISS 475 | _sf_message 1 "$_s_run_command" 0 "$_s_slime_fight" 1 476 | fi 477 | } # }}} 478 | 479 | _sf_3 () { # ITEM {{{ 480 | _sf_new_message "$_s_item_command 481 | " 482 | _sf_command_reset 483 | } # }}} 484 | 485 | _sf_s () { # {{{ 486 | if [ $_s_current_n -eq 0 ];then 487 | _sf_new_message "$_s_weapon_message 488 | " 489 | elif [ $_s_current_n -eq 1 ];then 490 | _sf_new_message "$_s_spell_message 491 | " 492 | elif [ $_s_current_n -eq 2 ];then 493 | : 494 | elif [ $_s_current_n -eq 3 ];then 495 | _sf_new_message "$_s_item_message 496 | " 497 | fi 498 | _sf_command_reset 499 | } # }}} 500 | 501 | _sf_q () { # {{{ 502 | : 503 | } # }}} 504 | 505 | _sf_select () { # {{{ 506 | if [ $_s_current_n -eq 0 ];then 507 | _sf_0 508 | elif [ $_s_current_n -eq 1 ];then 509 | _sf_1 510 | elif [ $_s_current_n -eq 2 ];then 511 | _sf_2 512 | elif [ $_s_current_n -eq 3 ];then 513 | _sf_3 514 | fi 515 | _s_is_print=1 516 | } # }}} 517 | 518 | _sf_main "$@" 519 | -------------------------------------------------------------------------------- /bin/ex_source_bash.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Example to make new scripts with sentaku functions 4 | 5 | . sentaku -n 6 | 7 | # User Default Variables 8 | _SENTAKU_INPUT_FILE="$HOME/.my_input" 9 | _SENTAKU_SEPARATOR=$'\x07' 10 | 11 | _sf_a () { 12 | _sf_echo "in function a 13 | Check Shell 14 | BASH_VERSION: $BASH_VERSION 15 | ZSH_VERSION: $ZSH_VERSION" 16 | } 17 | _sf_l () { 18 | _sf_echo "$(pwd;ls)" 19 | } 20 | 21 | _sf_main "$@" 22 | -------------------------------------------------------------------------------- /bin/ex_source_zsh.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env zsh 2 | 3 | # Example to make new scripts with sentaku functions 4 | 5 | . sentaku -n 6 | 7 | # User Default Variables 8 | _SENTAKU_INPUT_FILE="$HOME/.my_input" 9 | _SENTAKU_SEPARATOR=$'\x07' 10 | 11 | _sf_a () { 12 | _sf_echo "in function a 13 | Check Shell 14 | BASH_VERSION: $BASH_VERSION 15 | ZSH_VERSION: $ZSH_VERSION" 16 | } 17 | _sf_l () { 18 | _sf_echo "$(pwd;ls)" 19 | } 20 | 21 | _sf_main "$@" 22 | -------------------------------------------------------------------------------- /bin/file_selector: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | . sentaku -n 4 | 5 | _SENTAKU_FILE_CONTENT_LINES=${_SENTAKU_FILE_CONTENT_LINES:-10} 6 | _SENTAKU_CONTENT_SHOW_UNDER=${_SENTAKU_CONTENT_SHOW_UNDER:-0} 7 | 8 | _s_file_content_lines=${SENTAKU_FILE_CONTENT_LINES:-$_SENTAKU_FILE_CONTENT_LINES} 9 | _s_content_show_under=${SENTAKU_CONTENT_SHOW_UNDER:-$_SENTAKU_CONTENT_SHOW_UNDER} 10 | 11 | _sf_file_content () { 12 | if [ $_s_file_content -eq 0 ];then 13 | return 14 | fi 15 | local i 16 | local start_line=$((_s_lines+1)) 17 | local end_line=$(($(tput lines)-1)) 18 | local start_col=0 19 | local n_cols=$_s_cols 20 | 21 | if [ $_s_content_show_under -eq 0 ];then 22 | start_line=0 23 | start_col=$_s_cols 24 | n_cols=$_s_content_cols 25 | fi 26 | 27 | for i in $(seq $start_line $end_line);do 28 | tput cup "$i" "$start_col" >/dev/tty 29 | printf "%-${n_cols}s" "" >/dev/tty 30 | done 31 | 32 | if [ $_s_content_show_under -eq 1 ];then 33 | tput cup "$_s_lines" 0 >/dev/tty 34 | if [ $n_cols -ge 20 ];then 35 | printf "====File content====" 36 | else 37 | printf "==" 38 | fi 39 | fi 40 | 41 | if ! file "${_s_inputs[$_s_current_n]}"|grep -q text;then 42 | if [ $_s_content_show_under -eq 0 ];then 43 | if [ $n_cols -ge 16 ];then 44 | tput cup "$start_line" "$start_col" >/dev/tty 45 | printf "|Not a text file" 46 | fi 47 | else 48 | if [ $n_cols -ge 16 ];then 49 | tput cup "$start_line" "$start_col" >/dev/tty 50 | printf "Not a text file" 51 | fi 52 | fi 53 | else 54 | i=$start_line 55 | while read line;do 56 | if [ $_s_content_show_under -eq 0 ];then 57 | line="|$line" 58 | fi 59 | if [ "${#line}" -gt "$n_cols" ];then 60 | if [ "x$ZSH_VERSION" != "x" ];then 61 | line="${line[0,$((n_cols-1))]}" 62 | else 63 | line="${line: 0: $n_cols}" 64 | fi 65 | fi 66 | tput cup "$i" $start_col >/dev/tty 67 | printf "%s" "$line" 68 | ((i++)) 69 | if [ $i -gt $end_line ];then 70 | break 71 | fi 72 | done < ${_s_inputs[$_s_current_n]} 73 | while [ $i -lt $end_line ];do 74 | tput cup "$i" $start_col >/dev/tty 75 | printf "|" 76 | ((i++)) 77 | done 78 | fi 79 | } 80 | 81 | _sf_set_header () { # {{{ 82 | _s_header="\e[43;30m$_s_n values in total\e[0m " 83 | if [ "$_s_noheader" = 1 ];then 84 | return 85 | fi 86 | if [ $_s_delete -eq 1 ];then 87 | local delete_key="d(delete), " 88 | else 89 | local delete_key="" 90 | fi 91 | if [ $_s_keymode -eq 0 ];then 92 | if [ "$_s_cols" -ge 41 ];then 93 | _s_header="$_s_header 94 | vimike updown, e.g)j:down, k:up, gg/G, 95 | s(show content by \$VISUAL) 96 | ${delete_key}Enter/Space(select), q(quit)" 97 | fi 98 | else 99 | if [ "$_s_cols" -ge 51 ];then 100 | _s_header="$_s_header 101 | C-n(down), C-j(up), C-v(Page down), M-v(Page up) 102 | Enter(select), C-x(quit) 103 | Other normal keys start an incremental search" 104 | fi 105 | fi 106 | } # }}} 107 | 108 | _sf_setview () { # {{{ 109 | if [ $_s_content_show_under -eq 0 ];then 110 | _s_file_content=1 111 | local full_cols=$_s_cols 112 | _s_cols=$((full_cols/2)) 113 | _s_content_cols=$((full_cols-_s_cols)) 114 | fi 115 | 116 | if [ "$_s_lines" -le "$((_s_min_show))" ];then 117 | _s_header="" 118 | _s_ext_row=0 119 | elif [ "$_s_lines" -eq "$((_s_min_show+1))" ];then 120 | _s_header="${_s_search}" 121 | _s_ext_row=1 122 | else 123 | _sf_set_header 124 | _s_header="$(printf "%b\n\n" "$_s_header"|\ 125 | sed -e :loop -e 'N; $!b loop' -e 's/[[:space:]\n]*$//')\ 126 | \n${_s_search}" 127 | if [ "$(printf "%b\n" "$_s_header"|grep -c ^)" -gt "$((_s_lines-_s_min_show))" ];then 128 | _s_header="\e[43;30m$_s_n values in total\e[0m\n${_s_search}" 129 | fi 130 | _s_ext_row=$(printf "%b\n" "$_s_header"|grep -c ^) 131 | fi 132 | 133 | if [ $_s_content_show_under -eq 1 ];then 134 | if [ $((_s_lines-_ext_row-_s_file_content_lines-1)) -ge 0 ];then 135 | _s_lines=$((_s_lines-_s_file_content_lines-1)) 136 | _s_file_content=1 137 | else 138 | _s_file_content=0 139 | fi 140 | fi 141 | 142 | _s_max_show=$_s_n 143 | if [ "$_s_n" -gt $((_s_lines-_s_ext_row)) ];then 144 | _s_max_show=$((_s_lines-_s_ext_row)) 145 | fi 146 | } # }}} 147 | 148 | _sf_print_current_line () { # print current line {{{ 149 | local cursor_r=$((_s_current_n-_s_n_offset+_s_ext_row)) 150 | _sf_printline 1 $cursor_r $_s_current_n 151 | _sf_file_content 152 | } # }}} 153 | 154 | _sf_s () { 155 | if [ ! -f ${_s_inputs[$_s_current_n]} ];then 156 | output="$(_sf_nth $((_s_current_n))) value: ${_s_inputs[$_s_current_n]} 157 | =============== 158 | Not a file. 159 | " 160 | _sf_echo "$output" 161 | else 162 | clear >/dev/tty 163 | ${VISUAL:-less} "${_s_inputs[$_s_current_n]}" >/dev/tty ] [-s ] [input variables] 10 | # 11 | # 12 | SENTAKU_VERSION=v0.8.0 13 | SENTAKU_DATE="30/Sep/2019" 14 | # 15 | # }}} 16 | 17 | ## License {{{ 18 | # 19 | #The MIT License (MIT) 20 | # 21 | #Copyright (c) 2014 rcmdnk 22 | # 23 | #Permission is hereby granted, free of charge, to any person obtaining a copy of 24 | #this software and associated documentation files (the "Software"), to deal in 25 | #the Software without restriction, including without limitation the rights to 26 | #use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 27 | #the Software, and to permit persons to whom the Software is furnished to do so, 28 | #subject to the following conditions: 29 | # 30 | #The above copyright notice and this permission notice shall be included in all 31 | #copies or substantial portions of the Software. 32 | # 33 | #THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 34 | #IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 35 | #FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 36 | #COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 37 | #IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 38 | #CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 39 | # }}} 40 | 41 | # Default variables # {{{ 42 | _SENTAKU_INPUT_FILE=${_SENTAKU_INPUT_FILE:-} 43 | _SENTAKU_SEPARATOR=${_SENTAKU_SEPARATOR:-$IFS} 44 | _SENTAKU_MAX=${_SENTAKU_MAX:-20} 45 | _SENTAKU_MIN_SHOW=${_SENTAKU_MIN_SHOW:-3} 46 | _SENTAKU_NOHEADER=${_SENTAKU_NOHEADER:-0} 47 | _SENTAKU_NONUMBER=${_SENTAKU_NONUMBER:-0} 48 | _SENTAKU_SHOWLAST=${_SENTAKU_SHOWLAST:-0} 49 | _SENTAKU_CONTENT_LINES=${_SENTAKU_CONTENT_LINES:-10} 50 | _SENTAKU_CONTENT_SHOW_UNDER=${_SENTAKU_CONTENT_SHOW_UNDER:-0} 51 | _SENTAKU_CHILD=${_SENTAKU_CHILD:-0} 52 | # 0: AND (smart case), 1: AND (case sensitive), 2: starts with (smart case), 3: starts with (case sensitive) 53 | _SENTAKU_SEARCH_OPT=${_SENTAKU_SEARCH_OPT:-0} 54 | _SENTAKU_PAGE_CHANGE=${_SENTAKU_PAGE_CHANGE:-1} 55 | _SENTAKU_KEYMODE=${_SENTAKU_KEYMODE:-0} 56 | _SENTAKU_COLOR_NUM_ONLY=${_SENTAKU_COLOR_NUM_ONLY:-0} 57 | _SENTAKU_LINE_HIGHLIGHT=${_SENTAKU_LINE_HIGHLIGHT:-1} 58 | _SENTAKU_DEBUG=${_SENTAKU_DEBUG:-0} 59 | # }}} 60 | 61 | _sf_help () { # {{{ 62 | if [[ -t 1 ]];then 63 | echo "$_s_help"|${PAGER:-less} >/dev/tty 64 | else 65 | echo "$_s_help" 66 | fi 67 | } # }}} 68 | 69 | _sf_initialize () { # {{{ 70 | # Set variables 71 | _s_file="${SENTAKU_INPUT_FILE:-$_SENTAKU_INPUT_FILE}" 72 | _s_use_file=0 73 | _s_s="${SENTAKU_SEPARATOR:-$_SENTAKU_SEPARATOR}" 74 | # If a separator is normal IFS, use space for file write out. 75 | # note: $' \t\n' should not be surrounded by '"'. 76 | if [[ "$_s_s" = $' \t\n' ]];then 77 | _s_s_push=" " 78 | else 79 | _s_s_push="$_s_s" 80 | fi 81 | _s_inputs=() 82 | _s_cmd_line_inputs="" 83 | _s_n=0 84 | _s_max=${SENTAKU_MAX:-$_SENTAKU_MAX} 85 | _s_min_show=${SENTAKU_MIN_SHOW:-$_SENTAKU_MIN_SHOW} 86 | _s_header="" 87 | _s_noheader=${SENTAKU_NOHEADER:-$_SENTAKU_NOHEADER} 88 | _s_nonumber=${SENTAKU_NONUMBER:-$_SENTAKU_NONUMBER} 89 | _s_showlast=${SENTAKU_SHOWLAST:-$_SENTAKU_SHOWLAST} 90 | _s_content_view=0 91 | _s_s_content=0 92 | _s_show_content=0 93 | _s_content_lines=${SENTAKU_CONTENT_LINES:-$_SENTAKU_CONTENT_LINES} 94 | _s_content_show_under=${SENTAKU_CONTENT_SHOW_UNDER:-$_SENTAKU_CONTENT_SHOW_UNDER} 95 | _s_search_opt=${SENTAKU_SEARCH_OPT:-$_SENTAKU_SEARCH_OPT} 96 | _s_page_change=${SENTAKU_PAGE_CHANGE:-$_SENTAKU_PAGE_CHANGE} 97 | _s_keymode=${SENTAKU_KEYMODE:-$_SENTAKU_KEYMODE} 98 | _s_col_n_only=${SENTAKU_COLOR_NUM_ONLY:-$_SENTAKU_COLOR_NUM_ONLY} 99 | _s_line_highlight=${SENTAKU_LINE_HIGHLIGHT:-$_SENTAKU_LINE_HIGHLIGHT} 100 | _s_debug=${SENTAKU_DEBUG:-$_SENTAKU_DEBUG} 101 | _s_show="" 102 | _s_lines=0 103 | _s_cols=0 104 | _s_max_show=0 105 | _s_stdin=0 106 | _s_align=0 107 | _s_delete=0 108 | _s_continue=0 109 | _s_noshow=0 110 | _s_trapped=0 111 | _s_normal_echo=${_s_normal_echo:-1} 112 | 113 | _s_is_print=1 114 | 115 | _s_ext_row=0 116 | _s_current_n=-1 117 | _s_num="" 118 | _s_n_offset=0 119 | _s_g=0 120 | _s_n_move=-1 121 | _s_visual=-1 122 | _s_v_selected=() 123 | _s_break=0 124 | _s_search="" 125 | _s_search_words="" 126 | _s_pre_inputs_n=0 127 | local i 128 | for i in $(seq 0 999);do 129 | eval "_s_pre_inputs_$i=()" 130 | done 131 | _s_read="" 132 | _s_zsh_ksharrays=0 133 | _s_stty="" 134 | _s_IFS=$IFS 135 | 136 | _s_ret=0 137 | 138 | # Help 139 | _s_help=${_s_help:-"Usage: sentaku [-HNulapEVcCURLSnvh] [-f ] [-s ] [-r ] [input variables] 140 | 141 | Arguments: 142 | -f Set input file 143 | -s Set separator (default: ${SENTAKU_SEPARATOR:-$_SENTAKU_SEPARATOR}) 144 | If is \"line\", \$'\\n' is set as a separator. 145 | -H Force to show a header at sentaku window. 146 | -N No numbers are shown. 147 | -u Use underline to show selected line, instead of highlighting. 148 | -l Show last words instead of starting words for longer lines. 149 | -a Align input list (set selected one to the first). 150 | -r Return nth value directly. 151 | -p Push words to the file. 152 | -E Use Emacs mode 153 | -V Use Vim mode 154 | -c Load functions as a child process in other sentaku process. 155 | -C Show the file content at the list view 156 | -R Show the file content in the right (default: right) 157 | -U Show the file content under the list (default: right) 158 | -L Number of lines to show the file content under the list (default: ${SENTAKU_CONTENT_LINES:-$_SENTAKU_CONTENT_LINES}) 159 | -S Open the file under the cursor by \${VISUAL:-less} at s 160 | instead of showing full line of the selected one 161 | -n Don't run functions, to just source this file 162 | -v Show version 163 | -h Print this HELP and exit 164 | 165 | Key operation at sentaku window 166 | Common for all: 167 | C-p/C-n Up/Down. 168 | C-u/C-d Half page down/Half page down. 169 | C-b/C-f Page up/Page down. 170 | M-v/C-v Page up/Page down. 171 | C-a/C-e Go to the beginning/end. 172 | C-i/C-o Move the item up/down. 173 | C-x Quit. 174 | C-s Start/Stop Visual mode (multi-selection). 175 | Space Select/unselect current line for multi-selection. 176 | At Emacs mode or search mode in Vim mode, 177 | it selects when space is pushed twice. 178 | Esc At search mode, first Esc takes it back to normal mode 179 | with selected words. 180 | Second Esc clear search mode. 181 | Visual mode is cleared by first Esc. 182 | Enter Select and Quit. 183 | 184 | For Vim mode: 185 | n(any number) Set number. Multi-digit can be used (13, 320, etc...). 186 | Used/reset by other key. 187 | k/j Up/Down (if n is given, n-th up/n-th down). 188 | gg/G Go to top/bottom. (If n is given, move to n-th candidate.) 189 | d Delete current candidate. (in case you use input file.) 190 | s Show detail of current candidate. 191 | v Visual mode, same as C-s 192 | / Search. 193 | q Quit. 194 | Others Nothing happens. 195 | 196 | For Emacs mode: 197 | Others Normal keys start an incremental search. 198 | "} 199 | 200 | # Lines and columns at beginning 201 | _s_lines=$(tput lines) 202 | _s_cols=$(tput cols) 203 | 204 | # Fix array for zsh 205 | if [[ -n "$ZSH_VERSION" ]];then 206 | if ! setopt|grep -q ksharrays;then 207 | _s_zsh_ksharrays=1 208 | setopt ksharrays 209 | fi 210 | fi 211 | 212 | # Check std input 213 | [[ ! -t 0 ]] && _s_stdin=1 214 | 215 | # User initialization 216 | _sf_initialize_user 217 | } # }}} 218 | 219 | _sf_initialize_user () { # {{{ 220 | : 221 | } # }}} 222 | 223 | _sf_finalize () { # {{{ 224 | IFS=$_s_IFS 225 | 226 | if ((_s_ret == 0 && _s_current_n >= 0));then 227 | # Align values 228 | if [[ "$_s_search" != "" ]];then 229 | local val="${_s_inputs[$_s_current_n]}" 230 | local -a selected 231 | selected=() 232 | IFS="$_s_s" 233 | if [[ $_s_visual -ne -1 ]];then 234 | local is_first=1 235 | local i 236 | local j=0 237 | for i in $(seq 0 $((_s_n-1)));do 238 | if ((_s_v_selected[i] == 1 ));then 239 | selected[$j]=${_s_inputs[$i]} 240 | ((j++)) 241 | fi 242 | done 243 | fi 244 | _s_inputs=("${_s_pre_inputs_0[@]}") 245 | IFS=$_s_IFS 246 | _s_n=${#_s_inputs[@]} 247 | if ((_s_visual != -1));then 248 | local i 249 | for i in $(seq 0 $((_s_n-1)));do 250 | _s_v_selected[$i]=0 251 | done 252 | fi 253 | _s_current_n=0 254 | if ((_s_visual != -1));then 255 | local i 256 | local j 257 | for i in $(seq 0 $((_s_n-1)));do 258 | for j in $(seq 0 $((${#selected[@]}-1)));do 259 | if [[ "${selected[$j]}" = "${_s_inputs[$i]}" ]];then 260 | _s_current_n=$i 261 | _s_v_selected[$i]=1 262 | fi 263 | done 264 | done 265 | else 266 | local i 267 | for i in $(seq 0 $((_s_n-1)));do 268 | if [[ "$val" = "${_s_inputs[$i]}" ]];then 269 | _s_current_n=$i 270 | break 271 | fi 272 | done 273 | fi 274 | _s_search="" 275 | fi 276 | 277 | # Execution for selected value 278 | _sf_execute 279 | 280 | ((_s_align == 1 && _s_stdin == 0)) && _sf_align_values "$_s_current_n" 0 281 | fi 282 | 283 | if ((_SENTAKU_CHILD == 0 && _s_noshow == 0));then 284 | # Show cursor 285 | tput cnorm >/dev/tty 2>/dev/null || tput vs >/dev/tty 2>/dev/null 286 | 287 | # Enable echo input 288 | if ((_s_stdin == 0));then 289 | if [[ "$_s_stty" != "" ]];then 290 | stty $_s_stty 291 | # followings are for fixing problems of previous commands... 292 | stty echo 293 | fi 294 | fi 295 | fi 296 | if ((_s_trapped == 1));then 297 | # fixed at C-c 298 | stty echo 2>/dev/null 299 | fi 300 | 301 | # Release variables 302 | unset _s_file 303 | unset _s_use_file 304 | unset _s_s 305 | unset _s_s_push 306 | unset _s_inputs 307 | unset _s_cmd_line_inputs 308 | unset _s_n 309 | unset _s_max 310 | unset _s_min_show 311 | unset _s_header 312 | unset _s_noheader 313 | unset _s_nonumber 314 | unset _s_showlast 315 | unset _s_content_view 316 | unset _s_s_content 317 | unset _s_show_content 318 | unset _s_content_lines 319 | unset _s_content_show_under 320 | unset _s_search_opt 321 | unset _s_page_change 322 | unset _s_keymode 323 | unset _s_col_n_only 324 | unset _s_line_highlight 325 | unset _s_debug 326 | unset _s_show 327 | unset _s_lines 328 | unset _s_cols 329 | unset _s_max_show 330 | unset _s_stdin 331 | unset _s_align 332 | unset _s_delete 333 | unset _s_continue 334 | unset _s_noshow 335 | unset _s_trapped 336 | unset _s_normal_echo 337 | 338 | unset _s_is_print 339 | 340 | unset _s_ext_row 341 | unset _s_current_n 342 | unset _s_num 343 | unset _s_n_offset 344 | unset _s_g 345 | unset _s_n_move 346 | unset _s_visual 347 | unset _s_v_selected 348 | unset _s_break 349 | unset _s_search 350 | unset _s_search_words 351 | unset _s_pre_inputs_n 352 | local i 353 | for i in $(seq 0 999);do 354 | eval "unset _s_pre_inputs_$i" 355 | done 356 | unset _s_read 357 | 358 | unset _s_help 359 | 360 | [[ "x$_s_zsh_ksharrays" != "x" && $_s_zsh_ksharrays -eq 1 ]] && unsetopt ksharrays 361 | unset _s_zsh_ksharrays 362 | 363 | unset _s_stty 364 | unset _s_IFS 365 | 366 | _sf_finalize_user 367 | 368 | local ret=$_s_ret 369 | unset _s_ret 370 | return $ret 371 | } # }}} 372 | 373 | _sf_finalize_user () { # {{{ 374 | : 375 | } # }}} 376 | 377 | _sf_execute () { # {{{ 378 | if ((_s_visual != -1));then 379 | local is_first=1 380 | local i 381 | for i in $(seq 0 $((_s_n-1)));do 382 | if ((_s_v_selected[i] == 1));then 383 | if ((is_first == 1));then 384 | printf "%s" "${_s_inputs[$i]}" 385 | is_first=0 386 | else 387 | printf "$_s_s%s" "${_s_inputs[$i]}" 388 | fi 389 | fi 390 | done 391 | else 392 | printf "%s" "${_s_inputs[$_s_current_n]}" 393 | fi 394 | } # }}} 395 | 396 | _sf_hide () { # {{{ 397 | if ((_SENTAKU_CHILD == 0 && _s_noshow == 0));then 398 | if ((_s_stdin == 0));then 399 | # Save current stty 400 | _s_stty=$(stty -g) 401 | 402 | # Hide any input 403 | stty -echo 404 | 405 | fi 406 | 407 | # Hide cursor 408 | tput civis >/dev/tty 2>/dev/null || tput vi >/dev/tty 2>/dev/null 409 | 410 | # Save current display 411 | tput smcup >/dev/tty 2>/dev/null || tput ti >/dev/tty 2>/dev/null 412 | 413 | _s_normal_echo=0 414 | fi 415 | } # }}} 416 | 417 | _sf_clear () { # {{{ 418 | if ((_SENTAKU_CHILD == 0 && _s_noshow == 0));then 419 | # clear after selection 420 | clear >/dev/tty 421 | 422 | # Restore display 423 | tput rmcup >/dev/tty 2>/dev/null || tput te >/dev/tty 2>/dev/null 424 | 425 | _s_normal_echo=1 426 | fi 427 | } # }}} 428 | 429 | _sf_nth () { # {{{ 430 | case $1 in 431 | 1)echo 1st;; 432 | 2)echo 2nd;; 433 | 3)echo 3rd;; 434 | *)echo "${1}th";; 435 | esac 436 | } # }}} 437 | 438 | _sf_read () { # {{{ 439 | IFS= 440 | if [[ -n "$ZSH_VERSION" ]];then 441 | read -srk 1 _s_read /dev/tty 456 | echo "$message [y/n]: " >/dev/tty 457 | _sf_read 458 | if [[ "$_s_read" = "y" ]];then 459 | return 0 460 | elif [[ "$_s_read" = "n" ]];then 461 | _sf_quit 462 | return 1 463 | fi 464 | done 465 | } # }}} 466 | 467 | _sf_check_args () { # {{{ 468 | # Get arguments 469 | _s_continue=0 470 | while [[ $# -gt 0 ]];do 471 | case $1 in 472 | "-f") # Use file 473 | _s_file=$2 474 | _s_use_file=1 475 | if [[ "$_s_file" = "" ]];then 476 | echo "ERROR: empty input was given with -i" >/dev/tty 477 | return 1 478 | fi 479 | shift 480 | ;; 481 | "-s") # Set separator 482 | _s_s=$2 483 | if [[ "$_s_s" = "line" ]];then 484 | _s_s=$'\n' 485 | fi 486 | if [[ "$_s_s" = $' \t\n' ]];then 487 | _s_s_push=" " 488 | else 489 | _s_s_push="$_s_s" 490 | fi 491 | shift 492 | ;; 493 | "-H" ) _s_noheader=0;; 494 | "-N" ) _s_nonumber=1;; 495 | "-u" ) _s_line_highlight=0;; 496 | "-l" ) _s_showlast=1;; 497 | "-a" ) _s_align=1;; 498 | "-m" ) ;; 499 | "-r" ) 500 | if [[ "$2" =~ ^[0-9]+$ ]];then 501 | _s_current_n=$2 502 | shift 503 | else 504 | echo "-r option requires a number" >/dev/tty 505 | return 1 506 | fi 507 | ;; 508 | "-p" ) 509 | shift 510 | _sf_push "$@" 511 | return $? 512 | ;; 513 | "-E" ) _s_keymode=1;; 514 | "-V" ) _s_keymode=0;; 515 | "-c" ) _SENTAKU_CHILD=1;; 516 | "-C" ) _s_show_content=1;; 517 | "-R" ) _s_show_content=1;_s_content_show_under=0;; 518 | "-U" ) _s_show_content=1;_s_content_show_under=1;; 519 | "-L" ) _s_content_lines=$2;shift;; 520 | "-S" ) _s_s_content=1;; 521 | "-n" ) ;; 522 | "-v" ) echo "$(basename "$0") $SENTAKU_VERSION $SENTAKU_DATE" >/dev/tty; return 0;; 523 | "-h" ) 524 | _sf_help 525 | return 0 526 | ;; 527 | -* ) 528 | echo "$(basename "$0") $1: unknown argument 529 | Check \"$(basename "$0") -h\" for further information" >/dev/tty 530 | return 1 531 | ;; 532 | * ) 533 | break 534 | esac 535 | shift 536 | done 537 | _s_cmd_line_inputs="$*" 538 | _s_continue=1 539 | return 0 540 | } # }}} 541 | 542 | _sf_get_values_wrapper () { # {{{ _sf_get_values_wrapper [ []] 543 | _sf_get_values "$1" "$2" 544 | if ((_s_n == 0));then 545 | return 1 546 | else 547 | _sf_setview 548 | fi 549 | } # }}} 550 | 551 | _sf_get_values () { # {{{ _sf_get_values [ []] 552 | local stdin=$_s_stdin 553 | local check=1 554 | if [[ "$1" != "" ]];then 555 | stdin=$1 556 | fi 557 | if [[ "$2" != "" ]];then 558 | check=$2 559 | fi 560 | # Get values 561 | IFS="$_s_s" 562 | if [[ "$stdin" -eq 0 || "$_s_use_file" -eq 1 ]];then 563 | if [[ "$_s_use_file" -eq 0 && -z "$_s_file" ]];then 564 | _s_inputs=($(echo "$_s_cmd_line_inputs")) 565 | else 566 | touch "$_s_file" 567 | _s_inputs=($(cat "$_s_file")) 568 | fi 569 | else 570 | _s_inputs=($(cat -)) 571 | fi 572 | IFS=$_s_IFS 573 | if [[ -n "$ZSH_VERSION" ]];then 574 | # Fix array for ZSH 575 | # Zsh's array adds additional empty value to array if IFS is in the end of file. 576 | if [[ ${#_s_inputs[@]} -gt 0 ]];then 577 | local last="${_s_inputs[$((${#_s_inputs[@]}-1))]}" 578 | if [[ "${#last}" -eq 0 ]];then 579 | _s_inputs=(${_s_inputs[0,$((${#_s_inputs[@]}-2))]}) 580 | fi 581 | fi 582 | fi 583 | _s_n=${#_s_inputs[@]} 584 | 585 | if ((check == 1 && _s_n == 0));then 586 | if ((stdin == 0 || _s_use_file == 1));then 587 | _sf_echoln "No value in $_s_file\\n" 588 | else 589 | _sf_echoln "No value in stdin\\n" 590 | fi 591 | _s_ret=1 592 | return 593 | elif ((_s_n > 0));then 594 | _s_v_selected=() 595 | local i 596 | for i in $(seq 0 $((_s_n-1)));do 597 | _s_v_selected[$i]=0 598 | done 599 | fi 600 | _s_ret=0 601 | } # }}} 602 | 603 | _sf_align_values () { # {{{ _sf_align_values [ []] 604 | local n=${1:-$_s_current_n} 605 | local is_get=${2:-1} 606 | if [[ ! "$n" =~ ^[0-9]+$ || "$n" -ge "$_s_n" ]];then 607 | _sf_echoln "$n is not valid for _sf_align_values" 608 | return 1 609 | fi 610 | local v="${_s_inputs[$n]}" 611 | printf "%s$_s_s_push" "$v" > "$_s_file" 612 | local i=0 613 | for i in $(seq 0 $((_s_n-1)));do 614 | if [[ "$i" -ge "$_s_max" ]];then break;fi 615 | if [[ "${_s_inputs[$i]}" != "$v" ]];then 616 | printf "%s$_s_s_push" "${_s_inputs[$i]}" >> "$_s_file" 617 | fi 618 | done 619 | if [[ "$is_get" -eq 1 ]];then 620 | _sf_get_values_wrapper 621 | fi 622 | } # }}} 623 | 624 | _sf_delete () { # {{{ 625 | echo -n > "$_s_file" 626 | local i 627 | local old_current_n=$_s_current_n 628 | for i in $(seq 0 $((_s_n-1)));do 629 | if (((_s_visual != -1 && _s_v_selected[i] == 1 ) ||\ 630 | (_s_visual == -1 && i == old_current_n)));then 631 | if ((i < old_current_n));then 632 | ((_s_current_n--)) 633 | fi 634 | continue 635 | fi 636 | printf "%s$_s_s_push" "${_s_inputs[$i]}" >> "$_s_file" 637 | done 638 | _sf_get_values_wrapper 639 | } # }}} 640 | 641 | _sf_remove () { # {{{ 642 | local inputs 643 | inputs=() 644 | local i 645 | local old_current_n=$_s_current_n 646 | for i in $(seq 0 $((_s_n-1)));do 647 | if (((_s_visual != -1 && _s_v_selected[i] == 1) ||\ 648 | (_s_visual == -1 && i == old_current_n)));then 649 | if ((i < old_current_n));then 650 | ((_s_current_n--)) 651 | fi 652 | continue 653 | fi 654 | inputs[${#inputs[@]}]="${_s_inputs[$i]}" 655 | done 656 | _s_inputs=("${inputs[@]}") 657 | _s_n=${#_s_inputs[@]} 658 | for i in $(seq 0 $((_s_n-1)));do 659 | _s_v_selected[$i]=0 660 | done 661 | } # }}} 662 | 663 | _sf_rm_del () { # {{{ 664 | if ((_s_delete == 0 || _s_stdin == 1));then 665 | _sf_remove 666 | else 667 | _sf_delete 668 | fi 669 | if ((_s_n == 0));then 670 | _sf_echoln "There are no remained entries" 671 | _s_ret=1 672 | fi 673 | if ((_s_ret != 0));then 674 | _sf_quit $_s_ret 675 | return 676 | fi 677 | if ((_s_current_n >= _s_n));then 678 | _s_current_n=$((_s_n-1)) 679 | fi 680 | if ((_s_current_n < _s_n_offset));then 681 | _s_n_offset=$_s_current_n 682 | fi 683 | local n_move 684 | if ((_s_n < (_s_lines-_s_ext_row+_s_n_offset)));then 685 | local n_move=$((_s_lines-_s_ext_row+_s_n_offset-_s_n)) 686 | if ((n_move > _s_n_offset));then 687 | n_move=$_s_n_offset 688 | fi 689 | _s_n_offset=$((_s_n_offset-n_move)) 690 | fi 691 | _s_visual=-1 692 | local i 693 | for i in $(seq 0 $((_s_n-1)));do 694 | _s_v_selected[$i]=0 695 | done 696 | _s_is_print=1 697 | } # }}} 698 | 699 | _sf_add_spaces () { # {{{ _sf_add_spaces [is_prepend] 700 | local var=$1 701 | local n=$2 702 | local prepend=${3:-0} 703 | while ((n > 0));do 704 | if ((prepend == 1));then 705 | eval "$var=\" \$$var\"" 706 | else 707 | eval "$var=\"\$$var \"" 708 | fi 709 | ((n--)) 710 | done 711 | } # }}} 712 | 713 | _sf_cut_word () { # {{{ _sf_cut_word [] 714 | local var=$1 715 | local max_length=$2 716 | local is_last_show=${3:-0} 717 | if eval "[[ \${#$var} -le $max_length ]]";then 718 | eval "_sf_add_spaces $var \$(($max_length-\${#$var}))" 719 | return 720 | fi 721 | if ((is_last_show == 0));then 722 | eval "$var=\${$var: 0: $max_length}" 723 | return 724 | else 725 | eval "$var=\${$var: \$((\${#$var}-max_length))}" 726 | return 727 | fi 728 | } # }}} 729 | 730 | _sf_get_content () { # {{{ 731 | if ! file "${_s_inputs[$_s_current_n]}"|grep -q text;then 732 | echo "Not a text file" 733 | else 734 | cat "${_s_inputs[$_s_current_n]}" 735 | fi 736 | } # }}} 737 | 738 | _sf_content () { # {{{ 739 | if ((_s_content_view == 0));then 740 | return 741 | fi 742 | local i 743 | local start_line=$((_s_lines+1)) 744 | local end_line=$(($(tput lines)-1)) 745 | local start_col=0 746 | local n_cols=$_s_cols 747 | 748 | if ((_s_content_show_under == 0));then 749 | start_line=0 750 | start_col=$_s_cols 751 | n_cols=$_s_content_cols 752 | fi 753 | 754 | for i in $(seq $start_line $end_line);do 755 | tput cup "$i" "$start_col" >/dev/tty 756 | printf "%-${n_cols}s" "" >/dev/tty 757 | done 758 | 759 | if ((_s_content_show_under == 1));then 760 | tput cup "$_s_lines" 0 >/dev/tty 761 | printf -- "---" 762 | fi 763 | 764 | i=$start_line 765 | while read -r line;do 766 | if ((_s_content_show_under == 0));then 767 | line="|$line" 768 | fi 769 | if ((${#line} >= n_cols));then 770 | if [ "x$ZSH_VERSION" != "x" ];then 771 | line="${line[0,$((n_cols-1))]}" 772 | else 773 | line="${line: 0: $n_cols}" 774 | fi 775 | fi 776 | tput cup "$i" "$start_col" >/dev/tty 777 | printf "%s" "$line" 778 | ((i++)) 779 | if [ $i -gt $end_line ];then 780 | break 781 | fi 782 | done < <(_sf_get_content) 783 | if ((_s_content_show_under == 0));then 784 | while ((i < end_line));do 785 | tput cup "$i" "$start_col" >/dev/tty 786 | printf "|" 787 | ((i++)) 788 | done 789 | fi 790 | } # }}} 791 | 792 | _sf_show () { # _sf_show [] [] {{{ 793 | local is_selected=${1:-0} 794 | local n_show=${2:-$_s_cols} 795 | _sf_cut_word _s_show "$n_show" "$_s_showlast" 796 | 797 | # Color search words 798 | if [[ "$_s_search_words" != "" ]];then 799 | local ignore_case=0 800 | local search_words=$_s_search_words 801 | if ((_s_search_opt == 0 || _s_search_opt == 2));then 802 | if [[ -n "$ZSH_VERSION" ]];then 803 | local words_lower=$_s_search_words:l 804 | elif [[ -n ${BASH_VERSINFO[0]} ]] && [[ ${BASH_VERSINFO[0]} -ge 4 ]];then 805 | local words_lower=${_s_search_words,,} 806 | else 807 | local words_lower=$(echo ${_s_search_words}|tr "[:upper:]" "[:lower:]") 808 | fi 809 | if [[ $words_lower = "$_s_search_words" ]];then 810 | local ignore_case=1 811 | search_words=$words_lower 812 | fi 813 | fi 814 | 815 | local negative="" 816 | if ((is_selected == 1));then 817 | negative=";7" 818 | fi 819 | 820 | if ((_s_search_opt <= 1));then 821 | local -a words 822 | words=($search_words) 823 | local w 824 | for w in "${words[@]}";do 825 | if ((ignore_case == 1));then 826 | # Similar replace can be done by GNU sed, BSD sed doesn't support ignore case option 827 | _s_show=$(echo "$_s_show"|perl -pe "s|($w)|\\e[31${negative}m\\1\\e[0${negative}m|gi") 828 | else 829 | _s_show="${_s_show//$w/\\e[31${negative}m$w\\e[${negative}m}" 830 | fi 831 | done 832 | else 833 | if ((ignore_case == 1));then 834 | _s_show=$(echo "$_s_show"|perl -pe "s|(^$search_words)|\\e[31${negative}m\\1\\e[0${negative}m|gi") 835 | else 836 | _s_show="\\e[31${negative}m$search_words\\e[${negative}m${_s_show#$search_words}" 837 | fi 838 | fi 839 | fi 840 | } # }}} 841 | 842 | _sf_printline () { # usage: _sf_printline is_selected n_line n_input {{{ 843 | local is_selected=$1 844 | local n_line=$2 845 | local n_input=$3 846 | 847 | local color="" 848 | if ((_s_v_selected[n_input] == 1));then 849 | color="" 850 | fi 851 | if ((is_selected == 1));then 852 | if ((_s_line_highlight == 1));then 853 | color="${color}" 854 | else 855 | color="${color}" 856 | fi 857 | fi 858 | 859 | # Change line breaks to \n (to be shown), remove the last line break, replace tab to space 860 | _s_show=${_s_inputs[$n_input]//$'\n'/\\\\n} 861 | _s_show=${_s_show%\\\\n} 862 | _s_show=${_s_show//$'\t'/ } 863 | 864 | tput cup "$n_line" 0 >/dev/tty 865 | local n_show=$_s_cols 866 | _s_num="" 867 | if ((_s_nonumber == 0));then 868 | local nmax=$((_s_n-1)) 869 | local num_width=${#nmax} 870 | n_show=$((_s_cols-num_width-2)) 871 | _sf_add_spaces _s_num $((num_width-${#n_input})) 1 872 | _s_num="$_s_num$n_input: " 873 | fi 874 | _sf_show "$is_selected" "$n_show" 875 | if ((_s_col_n_only == 1));then 876 | printf "${color}${_s_num}${_s_show}" >/dev/tty 877 | else 878 | printf "${color}${_s_num}${_s_show}" >/dev/tty 879 | fi 880 | tput cup "$n_line" 0 >/dev/tty 881 | } # }}} 882 | 883 | _sf_print_current_line () { # print current line {{{ 884 | _sf_printline 1 $((_s_current_n-_s_n_offset+_s_ext_row)) $_s_current_n 885 | _sf_content 886 | } # }}} 887 | 888 | _sf_printall () { # usage: _sf_printall [not force] {{{ 889 | # if any argument is given, check if echoed or not. 890 | local n=$# 891 | if ((n >= 1 && _s_is_print == 0));then 892 | return 893 | fi 894 | 895 | local lines=$_s_lines 896 | local cols=$_s_cols 897 | _s_lines=$(tput lines) 898 | _s_cols=$(tput cols) 899 | 900 | _sf_setview 901 | 902 | if ((lines != _s_lines || cols != _s_cols));then 903 | _s_current_n=0 904 | _s_n_offset=0 905 | fi 906 | 907 | clear >/dev/tty 908 | 909 | # Header 910 | _sf_print "${_s_header}" 911 | 912 | local i 913 | for i in $(seq 0 $((_s_max_show-1)));do 914 | if (((i+_s_n_offset) >= _s_n));then break;fi 915 | if (((i+_s_n_offset) == _s_current_n));then 916 | _sf_print_current_line 917 | else 918 | _sf_printline 0 $((i+_s_ext_row)) $((i+_s_n_offset)) 919 | fi 920 | done 921 | _s_is_print=0 922 | } # }}} 923 | 924 | _sf_print () { # {{{ 925 | printf "%b" "$*" >/dev/tty 926 | } # }}} 927 | 928 | _sf_echo () { # {{{ 929 | if ((_s_noshow == 1));then 930 | : 931 | elif ((_s_normal_echo == 1));then 932 | _sf_print "$*" 933 | else 934 | clear >/dev/tty 935 | _sf_print "$*" 936 | _s_is_print=1 937 | _sf_wait 938 | fi 939 | } # }}} 940 | 941 | _sf_echoln () { # {{{ 942 | _sf_echo "$*\\n" 943 | } # }}} 944 | 945 | _sf_echo_debug () { # {{{ 946 | if [[ "$_s_debug" = "" ]];then 947 | # Temporarily use default value for debug_echo before initialization. 948 | _s_debug=$_SENTAKU_DEBUG 949 | fi 950 | if ((_s_debug > 0));then 951 | _sf_echo "$*" 952 | fi 953 | } # }}} 954 | 955 | _sf_echoln_debug () { # {{{ 956 | _sf_echo_debug "$*\\n" 957 | } # }}} 958 | 959 | _sf_echo_printall () { # {{{ 960 | _sf_echo "$*" 961 | _sf_printall 962 | } # }}} 963 | 964 | _sf_set_header () { # {{{ 965 | _s_header="\\e[43;30m$_s_n values in total\\e[0m " 966 | if ((_s_noheader == 1));then 967 | return 968 | fi 969 | if ((_s_delete == 1));then 970 | local delete_key="d(delete), " 971 | else 972 | local delete_key="" 973 | fi 974 | if ((_s_keymode == 0));then 975 | if ((_s_cols >= 68));then 976 | _s_header="$_s_header 977 | [n]j(n-down), [n]k(n-up), gg(top), G(bottom), [n]gg/G, (go to n) 978 | ^D(Half page down), ^U(Half page up), ^F(Page down), ^B(Page Up) 979 | ${delete_key}/(search), Enter/Space(select), q(quit)" 980 | elif ((_s_cols >= 41));then 981 | _s_header="$_s_header 982 | vimike updown, e.g)j:down, k:up, gg/G 983 | ${delete_key}Enter/Space(select), q(quit)" 984 | fi 985 | else 986 | if ((_s_cols >= 51));then 987 | _s_header="$_s_header 988 | C-n(down), C-j(up), C-v(Page down), M-v(Page up) 989 | Enter(select), C-x(quit) 990 | Other normal keys start an incremental search" 991 | fi 992 | fi 993 | } # }}} 994 | 995 | _sf_setview () { # {{{ 996 | if ((_s_show_content)) && ((_s_content_show_under == 0 ));then 997 | _s_content_view=1 998 | local full_cols=$_s_cols 999 | _s_cols=$((full_cols/2)) 1000 | _s_content_cols=$((full_cols-_s_cols)) 1001 | fi 1002 | 1003 | if ((_s_lines <= _s_min_show));then 1004 | _s_header="" 1005 | _s_ext_row=0 1006 | elif ((_s_lines == (_s_min_show+1)));then 1007 | _s_header="${_s_search}" 1008 | _s_ext_row=1 1009 | else 1010 | _sf_set_header 1011 | _s_header="$_s_header\\n$_s_search" 1012 | if [[ "$(printf "%b\n" "$_s_header"|grep -c ^)" -gt "$((_s_lines-_s_min_show))" ]];then 1013 | _s_header="\e[43;30m$_s_n values in total\e[0m\n${_s_search}" 1014 | fi 1015 | _s_ext_row=$(printf "%b\n" "$_s_header"|grep -c ^) 1016 | fi 1017 | 1018 | if ((_s_show_content == 1)) && ((_s_content_show_under == 1));then 1019 | if ((_s_lines - _s_ext_row - _s_content_lines - 1 >= 0));then 1020 | _s_lines=$((_s_lines-_s_content_lines-1)) 1021 | _s_content_view=1 1022 | else 1023 | _s_content_view=0 1024 | fi 1025 | fi 1026 | 1027 | _s_max_show=$_s_n 1028 | if ((_s_n > (_s_lines-_s_ext_row)));then 1029 | _s_max_show=$((_s_lines-_s_ext_row)) 1030 | fi 1031 | } # }}} 1032 | 1033 | _sf_n_down () { # The line goes Down. (Increase the line number) {{{ 1034 | ((_s_n_move <= 0)) && _s_n_move=1 1035 | local all=0 1036 | local old_current_n=$_s_current_n 1037 | local old_cursor_r=$((_s_current_n-_s_n_offset+_s_ext_row)) 1038 | _s_current_n=$((_s_current_n+_s_n_move)) 1039 | ((_s_current_n >= _s_n)) && _s_n_move=-1 && _s_current_n=$((_s_n-1)) 1040 | _s_g=0 1041 | _s_n_move=-1 1042 | ((_s_current_n == old_current_n)) && return 1043 | if (((_s_current_n+1-_s_max_show) > _s_n_offset));then 1044 | if ((_s_page_change == 0));then 1045 | _s_n_offset=$((_s_current_n+1-_s_max_show)) 1046 | else 1047 | _s_n_offset=$((_s_current_n-(_s_current_n)%_s_max_show)) 1048 | fi 1049 | all=1 1050 | fi 1051 | if ((all == 1));then 1052 | _s_is_print=1 1053 | elif ((_s_visual < 0));then 1054 | _sf_printline 0 $old_cursor_r $old_current_n 1055 | _sf_print_current_line 1056 | fi 1057 | if ((_s_visual >= 0));then 1058 | local tmp_r=$old_cursor_r 1059 | local tmp_n=$old_current_n 1060 | while ((tmp_n < _s_current_n));do 1061 | if ((tmp_n < _s_visual));then 1062 | _s_v_selected[$tmp_n]=0 1063 | else 1064 | _s_v_selected[$tmp_n]=1 1065 | fi 1066 | ((all != 1)) && _sf_printline 0 $tmp_r $tmp_n 1067 | ((tmp_r++));((tmp_n++)) 1068 | done 1069 | _s_v_selected[$_s_current_n]=1 1070 | ((all != 1)) && _sf_print_current_line 1071 | fi 1072 | } # }}} 1073 | 1074 | _sf_n_up () { # The line goes up. (Decrease the line Number!) {{{ 1075 | ((_s_n_move <= 0)) && _s_n_move=1 1076 | local all=0 1077 | local old_current_n=$_s_current_n 1078 | local old_cursor_r=$((_s_current_n-_s_n_offset+_s_ext_row)) 1079 | _s_current_n=$((_s_current_n-_s_n_move)) 1080 | ((_s_current_n < 0)) && _s_current_n=0 1081 | _s_n_move=-1 1082 | _s_g=0 1083 | ((_s_current_n == old_current_n)) && return 1084 | if ((_s_current_n < _s_n_offset));then 1085 | if ((_s_page_change == 0));then 1086 | _s_n_offset=$_s_current_n 1087 | else 1088 | _s_n_offset=$((_s_current_n-(_s_current_n)%_s_max_show)) 1089 | fi 1090 | all=1 1091 | fi 1092 | if ((all == 1));then 1093 | _s_is_print=1 1094 | elif ((_s_visual < 0));then 1095 | _sf_printline 0 $old_cursor_r $old_current_n 1096 | _sf_print_current_line 1097 | fi 1098 | if ((_s_visual >= 0));then 1099 | local tmp_r=$old_cursor_r 1100 | local tmp_n=$old_current_n 1101 | while ((tmp_n > _s_current_n));do 1102 | if ((tmp_n > _s_visual));then 1103 | _s_v_selected[$tmp_n]=0 1104 | else 1105 | _s_v_selected[$tmp_n]=1 1106 | fi 1107 | ((all != 1)) && _sf_printline 0 $tmp_r $tmp_n 1108 | ((tmp_r--));((tmp_n--)) 1109 | done 1110 | _s_v_selected[$_s_current_n]=1 1111 | ((all != 1)) && _sf_print_current_line 1112 | fi 1113 | _s_g=0 1114 | _s_n_move=-1 1115 | } # }}} 1116 | 1117 | _sf_item_move_up () { # {{{ Move the item up 1118 | ((_s_current_n == 0)) && return 1119 | 1120 | ((_s_n_move <= 0)) && _s_n_move=1 1121 | 1122 | local replace=$((_s_current_n-_s_n_move)) 1123 | ((replace < 0)) && replace=0 1124 | 1125 | local v_current=${_s_inputs[$_s_current_n]} 1126 | local v_replace=${_s_inputs[$replace]} 1127 | _s_inputs[$_s_current_n]=$v_replace 1128 | _s_inputs[$replace]=$v_current 1129 | ((_s_visual>=0)) && _s_visual=-2 1130 | if ((_s_visual!=-1)); then 1131 | local s_current=${_s_v_selected[$_s_current_n]} 1132 | local s_replace=${_s_v_selected[$replace]} 1133 | _s_v_selected[$_s_current_n]=$s_replace 1134 | _s_v_selected[$replace]=$s_current 1135 | fi 1136 | ((_s_stdin == 0)) && _sf_align_values 0 0 1137 | _sf_n_up 1138 | } # }}} 1139 | 1140 | _sf_item_move_down () { # {{{ Move the item down 1141 | ((_s_current_n == _s_n-1)) && return 1142 | 1143 | ((_s_n_move <= 0)) && _s_n_move=1 1144 | 1145 | local replace=$((_s_current_n+_s_n_move)) 1146 | ((replace > _s_n-1)) && replace=$((_s_n-1)) 1147 | 1148 | local v_current=${_s_inputs[$_s_current_n]} 1149 | local v_replace=${_s_inputs[$replace]} 1150 | _s_inputs[$_s_current_n]=$v_replace 1151 | _s_inputs[$replace]=$v_current 1152 | ((_s_visual>=0)) && _s_visual=-2 1153 | if ((_s_visual!=-1)); then 1154 | local s_current=${_s_v_selected[$_s_current_n]} 1155 | local s_replace=${_s_v_selected[$replace]} 1156 | _s_v_selected[$_s_current_n]=$s_replace 1157 | _s_v_selected[$replace]=$s_current 1158 | fi 1159 | ((_s_stdin == 0)) && _sf_align_values 0 0 1160 | _sf_n_down 1161 | } # }}} 1162 | 1163 | _sf_quit () { # {{{ 1164 | local n=$# 1165 | ((n > 0)) && _s_ret=$1 1166 | _s_current_n=-1 1167 | _s_break=1 1168 | } # }}} 1169 | 1170 | _sf_select () { # {{{ 1171 | _s_break=1 1172 | } # }}} 1173 | 1174 | _sf_search () { # {{{ 1175 | if ((_s_ext_row == 0));then 1176 | _sf_echo "Too few lines for search mode." 1177 | return 1178 | fi 1179 | local first_char=$1 1180 | if [[ "$_s_search" = "" ]];then 1181 | _s_pre_inputs_0=("${_s_inputs[@]}") 1182 | _s_pre_inputs_n=0 1183 | _s_search="\e[41;30mSearch:\e[0m" 1184 | fi 1185 | 1186 | if [[ "$first_char" = "" ]];then 1187 | _sf_printall 1188 | fi 1189 | while : ;do 1190 | local del=0 1191 | if [[ "$first_char" != "" ]];then 1192 | _s_search_words="$_s_search_words$first_char" 1193 | first_char="" 1194 | else 1195 | _sf_read 1196 | local r=$_s_read 1197 | case $r in 1198 | $'\E' ) # Esc 1199 | _sf_read 1200 | local r2=$_s_read 1201 | if [[ "$r2" = "v" ]];then # M-v 1202 | _s_n_move=$((_s_max_show)); _sf_n_up 1203 | continue 1204 | elif [[ "$r2" = "[" ]];then 1205 | _sf_read 1206 | local r3=$_s_read 1207 | if [[ "$r3" = "A" ]];then # cursor up 1208 | _sf_n_up 1209 | continue 1210 | elif [[ "$r3" = "B" ]];then # cursor down 1211 | _sf_n_down 1212 | continue 1213 | fi 1214 | fi 1215 | if ((_s_n == 0 || _s_keymode == 1));then 1216 | _s_inputs=("${_s_pre_inputs_0[@]}") 1217 | _s_n=${#_s_inputs[@]} 1218 | _s_search="" 1219 | _s_search_words="" 1220 | _sf_reset 1221 | fi 1222 | return 1223 | ;; 1224 | $'\ch'|$'\x7f') # ^H/Backspace 1225 | if [[ "$_s_search_words" = "" ]];then 1226 | _s_search="" 1227 | _s_search_words="" 1228 | _sf_reset 1229 | return 1230 | fi 1231 | _sf_cut_word _s_search_words $((${#_s_search_words}-1)) 1232 | ((_s_pre_inputs_n--)) 1233 | eval "_s_inputs=(\"\${_s_pre_inputs_$((_s_pre_inputs_n))[@]}\")" 1234 | _s_n=${#_s_inputs[@]} 1235 | del=1 1236 | ;; 1237 | $'\cu') # ^U 1238 | _s_search_words="" 1239 | _s_pre_inputs_n=0 1240 | ;; 1241 | ""|$'\n' ) 1242 | _sf_enter 1243 | return 1244 | ;; 1245 | $'\ca' ) _sf_c_a; continue;; 1246 | $'\cb' ) _sf_c_b; continue;; 1247 | $'\cc' ) _sf_c_c; continue;; 1248 | $'\cd' ) _sf_c_d; continue;; 1249 | $'\ce' ) _sf_c_e; continue;; 1250 | $'\cf' ) _sf_c_f; continue;; 1251 | $'\cg' ) _sf_c_g; continue;; 1252 | $'\ch' ) _sf_c_h; continue;; 1253 | $'\ci' ) _sf_c_i; continue;; 1254 | $'\cj' ) _sf_c_j; continue;; 1255 | $'\ck' ) _sf_c_k; continue;; 1256 | $'\cl' ) _sf_c_l; continue;; 1257 | $'\cm' ) _sf_c_m; continue;; 1258 | $'\cn' ) _sf_c_n; continue;; 1259 | $'\co' ) _sf_c_o; continue;; 1260 | $'\cp' ) _sf_c_p; continue;; 1261 | $'\cr' ) _sf_c_r; continue;; 1262 | $'\cs' ) _sf_c_s; continue;; 1263 | $'\ct' ) _sf_c_t; continue;; 1264 | $'\cu' ) _sf_c_u; continue;; 1265 | $'\cv' ) _sf_c_v; continue;; 1266 | $'\cw' ) _sf_c_w; continue;; 1267 | $'\cx' ) _sf_c_x; continue;; 1268 | $'\cy' ) _sf_c_y; continue;; 1269 | $'\cz' ) _sf_c_z; continue;; 1270 | 1271 | *)_s_search_words="$_s_search_words$_s_read";; 1272 | esac 1273 | fi 1274 | 1275 | _s_search="\e[41;30mSearch:\e[0m \e[31m$_s_search_words\e[0m" 1276 | 1277 | if [[ "$_s_search_words" = "" ]];then 1278 | _s_inputs=("${_s_pre_inputs_0[@]}") 1279 | _s_n=${#_s_inputs[@]} 1280 | elif ((del == 1));then 1281 | : 1282 | else 1283 | local -a inputs 1284 | inputs=() 1285 | local i 1286 | local j 1287 | for i in $(seq 0 $((_s_n-1)));do 1288 | if _sf_search_check "${_s_inputs[$i]}";then 1289 | inputs[j]="${_s_inputs[$i]}" 1290 | ((j++)) 1291 | fi 1292 | done 1293 | _s_inputs=("${inputs[@]}") 1294 | _s_n=${#_s_inputs[@]} 1295 | ((_s_pre_inputs_n++)) 1296 | eval "_s_pre_inputs_${_s_pre_inputs_n}=(\"\${_s_inputs[@]}\")" 1297 | fi 1298 | 1299 | _sf_reset 1300 | done 1301 | } # }}} 1302 | 1303 | _sf_search_check () { # {{{ 1304 | local input="$1" 1305 | local search_words=$_s_search_words 1306 | 1307 | if ((_s_search_opt == 0 || _s_search_opt == 2));then 1308 | if [[ -n "$ZSH_VERSION" ]];then 1309 | local input_lower=$input:l 1310 | local words_lower=$_s_search_words:l 1311 | elif [[ -n ${BASH_VERSINFO[0]} && ${BASH_VERSINFO[0]} -ge 4 ]];then 1312 | local input_lower=${input,,} 1313 | local words_lower=${_s_search_words,,} 1314 | else 1315 | local input_lower=$(echo "${input}"|tr "[:upper:]" "[:lower:]") 1316 | local words_lower=$(echo "${_s_search_words}"|tr "[:upper:]" "[:lower:]") 1317 | fi 1318 | if [[ $words_lower = "$_s_search_words" ]];then 1319 | input=$input_lower 1320 | search_words=$words_lower 1321 | fi 1322 | fi 1323 | if ((_s_search_opt <= 1));then 1324 | local -a words 1325 | words=(${search_words}) 1326 | local w 1327 | for w in "${words[@]}";do 1328 | if ((_s_search_opt <= 1));then 1329 | if [[ ! $input = *$w* ]];then 1330 | return 1 1331 | fi 1332 | fi 1333 | done 1334 | else 1335 | if [[ ! $input = $search_words* ]];then 1336 | return 1 1337 | fi 1338 | fi 1339 | return 0 1340 | } # }}} 1341 | 1342 | _sf_reset () { # {{{ 1343 | _s_current_n=0 1344 | _s_n_offset=0 1345 | _s_g=0 1346 | _s_n_move=-1 1347 | _s_visual=-1 1348 | _s_v_selected=() 1349 | local i 1350 | for i in $(seq 0 $((_s_n-1)));do 1351 | _s_v_selected[$i]=0 1352 | done 1353 | tput cup "$_s_ext_row" 0 >/dev/tty 1354 | _sf_printall 1355 | } # }}} 1356 | 1357 | _sf_visual_start () { # {{{ 1358 | if ((_s_visual >= 0));then 1359 | _s_visual=-2 1360 | else 1361 | _s_v_selected[$_s_current_n]=1 1362 | _s_visual=$_s_current_n 1363 | _sf_print_current_line 1364 | fi 1365 | } # }}} 1366 | 1367 | _sf_gG () { # {{{ 1368 | _s_n_move=$((_s_n_move-_s_current_n)) 1369 | if ((_s_n_move == 0));then 1370 | return 1371 | fi 1372 | if ((_s_n_move < 0));then 1373 | _s_n_move=$((0-_s_n_move)) 1374 | _sf_n_up 1375 | else 1376 | _sf_n_down 1377 | fi 1378 | } # }}} 1379 | 1380 | _sf_n_move_inc () { # {{{ 1381 | local n=${1:-"0"} 1382 | ((_s_n_move > 0)) && _s_n_move="$_s_n_move""$n" || _s_n_move=$n 1383 | } # }}} 1384 | 1385 | # function for 0-9 {{{ 1386 | _sf_0 () { # {{{ 1387 | _sf_n_move_inc 0 1388 | } # }}} 1389 | _sf_1 () { # {{{ 1390 | _sf_n_move_inc 1 1391 | } # }}} 1392 | _sf_2 () { # {{{ 1393 | _sf_n_move_inc 2 1394 | } # }}} 1395 | _sf_3 () { # {{{ 1396 | _sf_n_move_inc 3 1397 | } # }}} 1398 | _sf_4 () { # {{{ 1399 | _sf_n_move_inc 4 1400 | } # }}} 1401 | _sf_5 () { # {{{ 1402 | _sf_n_move_inc 5 1403 | } # }}} 1404 | _sf_6 () { # {{{ 1405 | _sf_n_move_inc 6 1406 | } # }}} 1407 | _sf_7 () { # {{{ 1408 | _sf_n_move_inc 7 1409 | } # }}} 1410 | _sf_8 () { # {{{ 1411 | _sf_n_move_inc 8 1412 | } # }}} 1413 | _sf_9 () { # {{{ 1414 | _sf_n_move_inc 9 1415 | } # }}} 1416 | # }}} function for 0-9 1417 | 1418 | # function for a-z {{{ 1419 | _sf_a () { # {{{ 1420 | : 1421 | } # }}} 1422 | _sf_b () { # {{{ 1423 | : 1424 | } # }}} 1425 | _sf_c () { # {{{ 1426 | : 1427 | } # }}} 1428 | _sf_d () { # {{{ 1429 | _sf_rm_del 1430 | } # }}} 1431 | _sf_e () { # {{{ 1432 | : 1433 | } # }}} 1434 | _sf_f () { # {{{ 1435 | : 1436 | } # }}} 1437 | _sf_g () { # {{{ 1438 | if ((_s_g == 0));then 1439 | _s_g=1 1440 | return 1441 | fi 1442 | if ((_s_n_move < 0));then 1443 | _s_n_move=0 1444 | fi 1445 | _sf_gG 1446 | } # }}} 1447 | _sf_h () { # {{{ 1448 | : 1449 | } # }}} 1450 | _sf_i () { # {{{ 1451 | : 1452 | } # }}} 1453 | _sf_j () { # {{{ 1454 | _sf_n_down 1455 | } # }}} 1456 | _sf_k () { # {{{ 1457 | _sf_n_up 1458 | } # }}} 1459 | _sf_l () { # {{{ 1460 | : 1461 | } # }}} 1462 | _sf_m () { # {{{ 1463 | : 1464 | } # }}} 1465 | _sf_n () { # {{{ 1466 | : 1467 | } # }}} 1468 | _sf_o () { # {{{ 1469 | : 1470 | } # }}} 1471 | _sf_p () { # {{{ 1472 | : 1473 | } # }}} 1474 | _sf_q () { # {{{ 1475 | _sf_quit 1476 | } # }}} 1477 | _sf_r () { # {{{ 1478 | : 1479 | } # }}} 1480 | _sf_s () { # {{{ 1481 | if ((_s_s_content == 1));then 1482 | if [ ! -f "${_s_inputs[$_s_current_n]}" ];then 1483 | output="$(_sf_nth $((_s_current_n))) value: ${_s_inputs[$_s_current_n]} 1484 | =============== 1485 | Not a file. 1486 | " 1487 | _sf_echo "$output" 1488 | else 1489 | clear >/dev/tty 1490 | ${VISUAL:-less} "${_s_inputs[$_s_current_n]}" >/dev/tty -, {{{ 1607 | _sf_c_a () { # {{{ 1608 | _s_n_move=0 1609 | _sf_gG 1610 | #local i 1611 | #for i in $(seq 0 $((_s_n-1)));do 1612 | # _s_visual=-2 1613 | # _s_v_selected[$i]=1 1614 | #done 1615 | #_s_is_print=1 1616 | } # }}} 1617 | _sf_c_b () { # {{{ 1618 | _s_n_move=$((_s_max_show)) 1619 | _sf_n_up 1620 | } # }}} 1621 | _sf_c_c () { # {{{ 1622 | : 1623 | } # }}} 1624 | _sf_c_d () { # {{{ 1625 | _s_n_move=$((_s_max_show/2)) 1626 | _sf_n_down 1627 | } # }}} 1628 | _sf_c_e () { # {{{ 1629 | _s_n_move=$_s_n 1630 | _sf_gG 1631 | } # }}} 1632 | _sf_c_f () { # {{{ 1633 | _s_n_move=$((_s_max_show)) 1634 | _sf_n_down 1635 | } # }}} 1636 | _sf_c_g () { # {{{ 1637 | : 1638 | } # }}} 1639 | _sf_c_h () { # {{{ 1640 | : 1641 | } # }}} 1642 | _sf_c_i () { # {{{ 1643 | _sf_item_move_up 1644 | } # }}} 1645 | _sf_c_j () { # {{{ 1646 | : 1647 | } # }}} 1648 | _sf_c_k () { # {{{ 1649 | : 1650 | } # }}} 1651 | _sf_c_l () { # {{{ 1652 | : 1653 | } # }}} 1654 | _sf_c_m () { # {{{ 1655 | : 1656 | } # }}} 1657 | _sf_c_n () { # {{{ 1658 | _sf_n_down 1659 | } # }}} 1660 | _sf_c_o () { # {{{ 1661 | _sf_item_move_down 1662 | } # }}} 1663 | _sf_c_p () { # {{{ 1664 | _sf_n_up 1665 | } # }}} 1666 | _sf_c_q () { # {{{ 1667 | : 1668 | } # }}} 1669 | _sf_c_r () { # {{{ 1670 | _s_is_print=1 1671 | : 1672 | } # }}} 1673 | _sf_c_s () { # {{{ 1674 | _sf_visual_start 1675 | } # }}} 1676 | _sf_c_t () { # {{{ 1677 | : 1678 | } # }}} 1679 | _sf_c_u () { # {{{ 1680 | _s_n_move=$((_s_max_show/2)) 1681 | _sf_n_up 1682 | } # }}} 1683 | _sf_c_v () { # {{{ 1684 | _s_n_move=$((_s_max_show)) 1685 | _sf_n_down 1686 | } # }}} 1687 | _sf_c_w () { # {{{ 1688 | : 1689 | } # }}} 1690 | _sf_c_x () { # {{{ 1691 | _sf_quit 1692 | } # }}} 1693 | _sf_c_y () { # {{{ 1694 | : 1695 | } # }}} 1696 | _sf_c_z () { # {{{ 1697 | : 1698 | } # }}} 1699 | # function for C-a-C-Z }}} 1700 | 1701 | _sf_esc () { # {{{ 1702 | _sf_read 1703 | local r2=$_s_read 1704 | if [[ "$r2" = "v" ]];then # M-v 1705 | _s_n_move=$((_s_max_show)); _sf_n_up 1706 | return 1707 | elif [[ "$r2" = "[" ]];then 1708 | _sf_read 1709 | local r3=$_s_read 1710 | if [[ "$r3" = "A" ]];then # cursor up 1711 | _sf_n_up 1712 | return 1713 | elif [[ "$r3" = "B" ]];then # cursor down 1714 | _sf_n_down 1715 | return 1716 | fi 1717 | fi 1718 | if ((_s_visual != -1));then 1719 | _s_visual=-1 1720 | local i 1721 | for i in $(seq 0 $((_s_n-1)));do 1722 | _s_v_selected[$i]=0 1723 | done 1724 | _s_is_print=1 1725 | fi 1726 | if [[ "$_s_search" != "" ]];then 1727 | _s_inputs=("${_s_pre_inputs_0[@]}") 1728 | _s_n=${#_s_inputs[@]} 1729 | _s_search="" 1730 | _s_search_words="" 1731 | _sf_reset 1732 | fi 1733 | } # }}} 1734 | 1735 | _sf_space () { # {{{ 1736 | # Space to start visual 1737 | if ((_s_v_selected[_s_current_n] == 1));then 1738 | _s_v_selected[$_s_current_n]=0 1739 | else 1740 | _s_v_selected[$_s_current_n]=1 1741 | fi 1742 | _s_visual=-2 1743 | _sf_print_current_line 1744 | } # }}} 1745 | 1746 | _sf_enter () { # {{{ 1747 | _sf_select 1748 | } # }}} 1749 | 1750 | _sf_slash () { # {{{ 1751 | _sf_search 1752 | } # }}} 1753 | 1754 | _sf_push () { # {{{ 1755 | # Set input 1756 | local input="$*" 1757 | shift $# 1758 | if ((_s_stdin == 1));then 1759 | input=$(cat -) 1760 | fi 1761 | 1762 | # Ignore blank 1763 | if [[ "$input" = "" ]];then 1764 | return 1 1765 | fi 1766 | 1767 | # Renew values 1768 | _sf_get_values_wrapper 0 0 1769 | IFS="$_s_s_push" 1770 | _s_inputs=(${input}${_s_s_push}${_s_inputs[@]}) 1771 | IFS=$_s_IFS 1772 | _s_n=${#_s_inputs[@]} 1773 | _sf_align_values 0 0 1774 | 1775 | _sf_echoln "$input is stored in $_s_file" 1776 | } # }}} 1777 | 1778 | _sf_main () { # {{{ 1779 | 1780 | # Set trap 1781 | trap "_sf_clear;_s_trapped=1;_s_stdin=0;_s_ret=1;_sf_finalize;exit" HUP INT QUIT ABRT SEGV TERM 1782 | 1783 | # Initialization 1784 | _sf_initialize 1785 | 1786 | # Get arguments 1787 | _sf_check_args "$@" 1788 | _s_ret=$? 1789 | if ((_s_ret != 0));then 1790 | _sf_finalize 1791 | return $? 1792 | fi 1793 | if ((_s_continue == 0));then 1794 | _sf_finalize 1795 | return $? 1796 | fi 1797 | 1798 | # Get values 1799 | _sf_get_values_wrapper 1800 | _s_ret=$? 1801 | if ((_s_ret != 0));then 1802 | _sf_finalize 1803 | return $? 1804 | fi 1805 | 1806 | # Return nth 1807 | if ((_s_current_n >= 0));then 1808 | _sf_finalize 1809 | return $? 1810 | fi 1811 | 1812 | # Hide displays 1813 | _sf_hide 1814 | 1815 | # Initialize values 1816 | _sf_reset 1817 | 1818 | while : ;do 1819 | _sf_printall 1 1820 | _sf_read 1821 | local r=$_s_read 1822 | case $r in 1823 | # Use common functions of C-*, Esc, Space and Enter for both vim/emacs modes. 1824 | $'\ca' ) _sf_c_a;; 1825 | $'\cb' ) _sf_c_b;; 1826 | $'\cc' ) _sf_c_c;; 1827 | $'\cd' ) _sf_c_d;; 1828 | $'\ce' ) _sf_c_e;; 1829 | $'\cf' ) _sf_c_f;; 1830 | $'\cg' ) _sf_c_g;; 1831 | $'\ch' ) _sf_c_h;; 1832 | $'\ci' ) _sf_c_i;; 1833 | $'\cj' ) _sf_c_j;; 1834 | $'\ck' ) _sf_c_k;; 1835 | $'\cl' ) _sf_c_l;; 1836 | $'\cm' ) _sf_c_m;; 1837 | $'\cn' ) _sf_c_n;; 1838 | $'\co' ) _sf_c_o;; 1839 | $'\cp' ) _sf_c_p;; 1840 | $'\cr' ) _sf_c_r;; 1841 | $'\cs' ) _sf_c_s;; 1842 | $'\ct' ) _sf_c_t;; 1843 | $'\cu' ) _sf_c_u;; 1844 | $'\cv' ) _sf_c_v;; 1845 | $'\cw' ) _sf_c_w;; 1846 | $'\cx' ) _sf_c_x;; 1847 | $'\cy' ) _sf_c_y;; 1848 | $'\cz' ) _sf_c_z;; 1849 | $'\E' ) _sf_esc;; 1850 | " " ) _sf_space;; 1851 | ""|$'\n' ) _sf_enter;; # Enter (Normally "" corresponds to Enter (line break before any key)) 1852 | 1853 | # Differences for difference modes. 1854 | * ) 1855 | if ((_s_keymode == 0));then 1856 | case $r in 1857 | # Vim mode 1858 | "0" ) _sf_0;; 1859 | "1" ) _sf_1;; 1860 | "2" ) _sf_2;; 1861 | "3" ) _sf_3;; 1862 | "4" ) _sf_4;; 1863 | "5" ) _sf_5;; 1864 | "6" ) _sf_6;; 1865 | "7" ) _sf_7;; 1866 | "8" ) _sf_8;; 1867 | "9" ) _sf_9;; 1868 | "a" ) _sf_a;; 1869 | "b" ) _sf_b;; 1870 | "c" ) _sf_c;; 1871 | "d" ) _sf_d;; 1872 | "e" ) _sf_e;; 1873 | "f" ) _sf_f;; 1874 | "g" ) _sf_g;; 1875 | "h" ) _sf_h;; 1876 | "i" ) _sf_i;; 1877 | "j" ) _sf_j;; 1878 | "k" ) _sf_k;; 1879 | "l" ) _sf_l;; 1880 | "m" ) _sf_m;; 1881 | "n" ) _sf_n;; 1882 | "o" ) _sf_o;; 1883 | "p" ) _sf_p;; 1884 | "q" ) _sf_q;; 1885 | "r" ) _sf_r;; 1886 | "s" ) _sf_s;; 1887 | "t" ) _sf_t;; 1888 | "u" ) _sf_u;; 1889 | "v" ) _sf_v;; 1890 | "w" ) _sf_w;; 1891 | "x" ) _sf_x;; 1892 | "y" ) _sf_y;; 1893 | "z" ) _sf_z;; 1894 | "A" ) _sf_A;; 1895 | "B" ) _sf_B;; 1896 | "C" ) _sf_C;; 1897 | "D" ) _sf_D;; 1898 | "E" ) _sf_E;; 1899 | "F" ) _sf_F;; 1900 | "G" ) _sf_G;; 1901 | "H" ) _sf_H;; 1902 | "I" ) _sf_I;; 1903 | "J" ) _sf_J;; 1904 | "K" ) _sf_K;; 1905 | "L" ) _sf_L;; 1906 | "M" ) _sf_M;; 1907 | "N" ) _sf_N;; 1908 | "O" ) _sf_O;; 1909 | "P" ) _sf_P;; 1910 | "Q" ) _sf_Q;; 1911 | "R" ) _sf_R;; 1912 | "S" ) _sf_S;; 1913 | "T" ) _sf_T;; 1914 | "U" ) _sf_U;; 1915 | "V" ) _sf_V;; 1916 | "W" ) _sf_W;; 1917 | "X" ) _sf_X;; 1918 | "Y" ) _sf_Y;; 1919 | "Z" ) _sf_Z;; 1920 | "/" ) _sf_slash;; 1921 | esac 1922 | else 1923 | _sf_search "$r" 1924 | fi 1925 | ;; 1926 | esac 1927 | ((_s_break == 1)) && break 1928 | done 1929 | 1930 | # Clear (Show cursor, Restore display, Enable echo input) 1931 | _sf_clear 1932 | 1933 | # Finalization 1934 | _sf_finalize 1935 | } # }}} 1936 | 1937 | # Execution part {{{ 1938 | if [ "$1" != "-n" ];then 1939 | _sf_main "$@" 1940 | fi 1941 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /tests/function_check.bats: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bats 2 | 3 | setup() { 4 | load ./bats-assert/load 5 | load ./bats-support/load 6 | tmpdir=$(mktemp -d) 7 | cd "$tmpdir" 8 | . sentaku -n 9 | _sf_initialize 10 | } 11 | 12 | teardown() { 13 | rm -rf "$tmpdir" 14 | } 15 | 16 | @test "_sf_help" { 17 | run _sf_help 18 | assert_success 19 | assert [ "$output" != "" ] 20 | } 21 | 22 | @test "_sf_initialize" { 23 | assert_equal "$_s_n" 0 24 | } 25 | 26 | @test "_sf_initialize_user" { 27 | skip 28 | } 29 | 30 | @test "_sf_finalize" { 31 | skip 32 | _sf_finalize 33 | assert_equal "$_s_n" "" 34 | } 35 | 36 | @test "_sf_finalize_user" { 37 | skip 38 | } 39 | 40 | @test "_sf_execute" { 41 | _s_inputs=(0 1 2 3 4 5 6 7 8 9 10) 42 | _s_v_selected=(0 1 0 1 1 0 1 0 0 0 0) 43 | _s_n=${#_s_inputs[@]} 44 | _s_s=" " 45 | _s_current_n=5 46 | _s_visual=-1 47 | run _sf_execute 48 | assert_output "5" 49 | _s_visual=1 50 | run _sf_execute 51 | assert_output "1 3 4 6" 52 | } 53 | 54 | @test "_sf_hide" { 55 | skip 56 | #run _sf_hide 57 | #assert_success 58 | } 59 | 60 | @test "_sf_clear" { 61 | skip 62 | #run _sf_clear 63 | #assert_success 64 | } 65 | 66 | @test "_sf_nth" { 67 | run _sf_nth 1 68 | assert_output "1st" 69 | run _sf_nth 2 70 | assert_output "2nd" 71 | run _sf_nth 3 72 | assert_output "3rd" 73 | run _sf_nth 4 74 | assert_output "4th" 75 | } 76 | 77 | @test "_sf_read" { 78 | skip 79 | } 80 | 81 | @test "_sf_wait" { 82 | skip 83 | } 84 | 85 | @test "_sf_yn" { 86 | skip 87 | } 88 | 89 | @test "_sf_check_args" { 90 | skip 91 | } 92 | 93 | @test "_sf_get_values_wrapper" { 94 | skip 95 | } 96 | 97 | @test "_sf_get_values" { 98 | _s_use_file=1 99 | _s_file=./test_inputs.txt 100 | printf "aaa\nbbb\nccc\nddd\neee" > $_s_file 101 | _sf_get_values 0 0 102 | assert_equal "$_s_n" 5 103 | assert_equal "${_s_inputs[0]}" "aaa" 104 | assert_equal "${_s_inputs[2]}" "ccc" 105 | 106 | _s_max=4 107 | _sf_align_values 1 108 | assert_equal "$_s_n" 4 109 | assert_equal "${_s_inputs[1]}" "aaa" 110 | 111 | _s_current_n=1 112 | _sf_delete 113 | assert_equal "$_s_n" 3 114 | assert_equal "${_s_inputs[1]}" "ccc" 115 | 116 | rm -f $_s_file 117 | } 118 | 119 | @test "_sf_align_values" { 120 | : # combined with _sf_get_values 121 | } 122 | 123 | @test "_sf_delete" { 124 | : # combined with _sf_get_values 125 | } 126 | 127 | @test "_sf_remove" { 128 | _s_inputs=(0 1 2 3 4 5) 129 | _s_n=${#_s_inputs[@]} 130 | _s_current_n=1 131 | _s_visual=-1 132 | _sf_remove 133 | assert_equal "${_s_inputs[*]}" "0 2 3 4 5" 134 | _s_visual=1 135 | _s_v_selected=(0 1 1 0 0) 136 | _sf_remove 137 | assert_equal "${_s_inputs[*]}" "0 4 5" 138 | } 139 | 140 | @test "_sf_rm_del" { 141 | skip 142 | } 143 | 144 | @test "_sf_add_spaces" { 145 | x="test" 146 | _sf_add_spaces x 3 147 | assert_equal "$x" "test " 148 | x="test" 149 | _sf_add_spaces x 3 1 150 | assert_equal "$x" " test" 151 | } 152 | 153 | @test "_sf_cut_word" { 154 | x="123456789" 155 | _sf_cut_word x 5 156 | assert_equal "$x" "12345" 157 | x="123456789" 158 | _sf_cut_word x 5 1 159 | assert_equal "$x" "56789" 160 | } 161 | 162 | @test "_sf_get_content" { 163 | file=./test_inputs.txt 164 | dir=./test_dir 165 | echo test > $file 166 | mkdir -p $dir 167 | 168 | _s_inputs=($file $dir) 169 | _s_current_n=0 170 | run _sf_get_content 171 | assert_output "test" 172 | _s_current_n=1 173 | run _sf_get_content 174 | assert_output "Not a text file" 175 | 176 | rm -rf $file $dir 177 | } 178 | 179 | @test "_sf_content" { 180 | skip 181 | } 182 | 183 | @test "_sf_show" { 184 | skip 185 | } 186 | 187 | @test "_sf_printline" { 188 | skip 189 | } 190 | 191 | @test "_sf_print_current_line" { 192 | skip 193 | } 194 | 195 | @test "_sf_printall" { 196 | skip 197 | } 198 | 199 | @test "_sf_print" { 200 | skip 201 | } 202 | 203 | @test "_sf_echo" { 204 | skip 205 | } 206 | 207 | @test "_sf_echoln" { 208 | skip 209 | } 210 | 211 | @test "_sf_echo_debug" { 212 | skip 213 | } 214 | 215 | @test "_sf_echoln_debug" { 216 | skip 217 | } 218 | 219 | @test "_sf_echo_printall" { 220 | skip 221 | } 222 | 223 | @test "_sf_set_header" { 224 | skip 225 | } 226 | 227 | @test "_sf_setview" { 228 | skip 229 | } 230 | 231 | @test "_sf_n_down" { 232 | skip 233 | } 234 | 235 | @test "_sf_n_up" { 236 | skip 237 | } 238 | 239 | @test "_sf_item_move_up" { 240 | skip 241 | } 242 | 243 | @test "_sf_item_move_down" { 244 | skip 245 | } 246 | 247 | @test "_sf_quit" { 248 | skip 249 | } 250 | 251 | @test "_sf_select" { 252 | skip 253 | } 254 | 255 | @test "_sf_search" { 256 | skip 257 | } 258 | 259 | @test "_sf_search_check" { 260 | skip 261 | } 262 | 263 | @test "_sf_reset" { 264 | skip 265 | } 266 | 267 | @test "_sf_visual_start" { 268 | skip 269 | } 270 | 271 | @test "_sf_gG" { 272 | skip 273 | } 274 | 275 | @test "_sf_n_move_inc" { 276 | skip 277 | } 278 | 279 | @test "_sf_0" { 280 | skip 281 | } 282 | 283 | @test "_sf_1" { 284 | skip 285 | } 286 | 287 | @test "_sf_2" { 288 | skip 289 | } 290 | 291 | @test "_sf_3" { 292 | skip 293 | } 294 | 295 | @test "_sf_4" { 296 | skip 297 | } 298 | 299 | @test "_sf_5" { 300 | skip 301 | } 302 | 303 | @test "_sf_6" { 304 | skip 305 | } 306 | 307 | @test "_sf_7" { 308 | skip 309 | } 310 | 311 | @test "_sf_8" { 312 | skip 313 | } 314 | 315 | @test "_sf_9" { 316 | skip 317 | } 318 | 319 | @test "_sf_a" { 320 | skip 321 | } 322 | 323 | @test "_sf_b" { 324 | skip 325 | } 326 | 327 | @test "_sf_c" { 328 | skip 329 | } 330 | 331 | @test "_sf_d" { 332 | skip 333 | } 334 | 335 | @test "_sf_e" { 336 | skip 337 | } 338 | 339 | @test "_sf_f" { 340 | skip 341 | } 342 | 343 | @test "_sf_g" { 344 | skip 345 | } 346 | 347 | @test "_sf_h" { 348 | skip 349 | } 350 | 351 | @test "_sf_i" { 352 | skip 353 | } 354 | 355 | @test "_sf_j" { 356 | skip 357 | } 358 | 359 | @test "_sf_k" { 360 | skip 361 | } 362 | 363 | @test "_sf_l" { 364 | skip 365 | } 366 | 367 | @test "_sf_m" { 368 | skip 369 | } 370 | 371 | @test "_sf_n" { 372 | skip 373 | } 374 | 375 | @test "_sf_o" { 376 | skip 377 | } 378 | 379 | @test "_sf_p" { 380 | skip 381 | } 382 | 383 | @test "_sf_q" { 384 | skip 385 | } 386 | 387 | @test "_sf_r" { 388 | skip 389 | } 390 | 391 | @test "_sf_s" { 392 | skip 393 | } 394 | 395 | @test "_sf_t" { 396 | skip 397 | } 398 | 399 | @test "_sf_u" { 400 | skip 401 | } 402 | 403 | @test "_sf_v" { 404 | skip 405 | } 406 | 407 | @test "_sf_w" { 408 | skip 409 | } 410 | 411 | @test "_sf_x" { 412 | skip 413 | } 414 | 415 | @test "_sf_y" { 416 | skip 417 | } 418 | 419 | @test "_sf_z" { 420 | skip 421 | } 422 | 423 | @test "_sf_A" { 424 | skip 425 | } 426 | 427 | @test "_sf_B" { 428 | skip 429 | } 430 | 431 | @test "_sf_C" { 432 | skip 433 | } 434 | 435 | @test "_sf_D" { 436 | skip 437 | } 438 | 439 | @test "_sf_E" { 440 | skip 441 | } 442 | 443 | @test "_sf_F" { 444 | skip 445 | } 446 | 447 | @test "_sf_G" { 448 | skip 449 | } 450 | 451 | @test "_sf_H" { 452 | skip 453 | } 454 | 455 | @test "_sf_I" { 456 | skip 457 | } 458 | 459 | @test "_sf_J" { 460 | skip 461 | } 462 | 463 | @test "_sf_K" { 464 | skip 465 | } 466 | 467 | @test "_sf_L" { 468 | skip 469 | } 470 | 471 | @test "_sf_M" { 472 | skip 473 | } 474 | 475 | @test "_sf_N" { 476 | skip 477 | } 478 | 479 | @test "_sf_O" { 480 | skip 481 | } 482 | 483 | @test "_sf_P" { 484 | skip 485 | } 486 | 487 | @test "_sf_Q" { 488 | skip 489 | } 490 | 491 | @test "_sf_R" { 492 | skip 493 | } 494 | 495 | @test "_sf_S" { 496 | skip 497 | } 498 | 499 | @test "_sf_T" { 500 | skip 501 | } 502 | 503 | @test "_sf_U" { 504 | skip 505 | } 506 | 507 | @test "_sf_V" { 508 | skip 509 | } 510 | 511 | @test "_sf_W" { 512 | skip 513 | } 514 | 515 | @test "_sf_X" { 516 | skip 517 | } 518 | 519 | @test "_sf_Y" { 520 | skip 521 | } 522 | 523 | @test "_sf_Z" { 524 | skip 525 | } 526 | 527 | @test "_sf_c_a" { 528 | skip 529 | } 530 | 531 | @test "_sf_c_b" { 532 | skip 533 | } 534 | 535 | @test "_sf_c_c" { 536 | skip 537 | } 538 | 539 | @test "_sf_c_d" { 540 | skip 541 | } 542 | 543 | @test "_sf_c_e" { 544 | skip 545 | } 546 | 547 | @test "_sf_c_f" { 548 | skip 549 | } 550 | 551 | @test "_sf_c_g" { 552 | skip 553 | } 554 | 555 | @test "_sf_c_h" { 556 | skip 557 | } 558 | 559 | @test "_sf_c_i" { 560 | skip 561 | } 562 | 563 | @test "_sf_c_j" { 564 | skip 565 | } 566 | 567 | @test "_sf_c_k" { 568 | skip 569 | } 570 | 571 | @test "_sf_c_l" { 572 | skip 573 | } 574 | 575 | @test "_sf_c_m" { 576 | skip 577 | } 578 | 579 | @test "_sf_c_n" { 580 | skip 581 | } 582 | 583 | @test "_sf_c_o" { 584 | skip 585 | } 586 | 587 | @test "_sf_c_p" { 588 | skip 589 | } 590 | 591 | @test "_sf_c_q" { 592 | skip 593 | } 594 | 595 | @test "_sf_c_r" { 596 | skip 597 | } 598 | 599 | @test "_sf_c_s" { 600 | skip 601 | } 602 | 603 | @test "_sf_c_t" { 604 | skip 605 | } 606 | 607 | @test "_sf_c_u" { 608 | skip 609 | } 610 | 611 | @test "_sf_c_v" { 612 | skip 613 | } 614 | 615 | @test "_sf_c_w" { 616 | skip 617 | } 618 | 619 | @test "_sf_c_x" { 620 | skip 621 | } 622 | 623 | @test "_sf_c_y" { 624 | skip 625 | } 626 | 627 | @test "_sf_c_z" { 628 | skip 629 | } 630 | 631 | @test "_sf_esc" { 632 | skip 633 | } 634 | 635 | @test "_sf_space" { 636 | skip 637 | } 638 | 639 | @test "_sf_enter" { 640 | skip 641 | } 642 | 643 | @test "_sf_slash" { 644 | skip 645 | } 646 | 647 | @test "_sf_push" { 648 | skip 649 | } 650 | 651 | @test "_sf_main" { 652 | skip 653 | } 654 | 655 | -------------------------------------------------------------------------------- /tests/get_bats_libs.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | git clone https://github.com/ztombol/bats-assert 3 | git clone https://github.com/ztombol/bats-support 4 | --------------------------------------------------------------------------------