├── hooks ├── uninstall.fish └── install.fish ├── completions └── fuzzy_cd.fish ├── functions ├── fcd_shortest.fish ├── fcd_warn.fish ├── fcd_ffmark.fish ├── __fuzzy_cd.fish ├── fcd_ffdir.fish └── fcd_jump.fish ├── LICENSE ├── init.fish └── README.md /hooks/uninstall.fish: -------------------------------------------------------------------------------- 1 | # fuzzy_cd uninstall hook 2 | # 3 | # You can use this file to do custom cleanup when the package is uninstalled. 4 | # You can use the variable $path to access the package path. 5 | -------------------------------------------------------------------------------- /completions/fuzzy_cd.fish: -------------------------------------------------------------------------------- 1 | # Always provide completions for command line utilities. 2 | # 3 | # Check Fish documentation about completions: 4 | # http://fishshell.com/docs/current/commands.html#complete 5 | # 6 | # If your package doesn't provide any command line utility, 7 | # feel free to remove completions directory from the project. -------------------------------------------------------------------------------- /functions/fcd_shortest.fish: -------------------------------------------------------------------------------- 1 | function fcd_shortest -d 'Return the shortest string in array' 2 | set -l args 3 | if not tty >/dev/null 4 | read args 5 | else 6 | set args $argv 7 | end 8 | 9 | set -l lines 10 | for str in $args 11 | if test (string length $str) -gt 0 12 | set lines $lines "$str" 13 | end 14 | end 15 | 16 | for line in $lines 17 | echo (string length "$line") "$line" 18 | end | sort -n | head -1 | cut -d' ' -f2- 19 | end 20 | -------------------------------------------------------------------------------- /functions/fcd_warn.fish: -------------------------------------------------------------------------------- 1 | function fcd_warn -d "Echo to STDERR" 2 | set -l options 'e/error' 'w/warn' 'i/info' 'h/help' 3 | 4 | set -l error 0 5 | set -l color (set_color normal) 6 | 7 | argparse $options -- $argv 8 | 9 | if set -q _flag_help 10 | echo "Output to STDERR" 11 | echo "Options:" 12 | echo " -e, --error Error level message" 13 | echo " -w, --warn Warning level message" 14 | echo " -i, --info Info level message" 15 | return 16 | end 17 | 18 | if set -q _flag_error 19 | set color (set_color -b brred brwhite) 20 | else if set -q _flag_warn 21 | set color (set_color -b bryellow black) 22 | else if set -q _flag_info 23 | set color (set_color brgreen) 24 | end 25 | set -l prompt (set_color bryellow) 26 | printf '%s>%s %s%s%s\n' $prompt $prompt $color "$argv" (set_color normal) >&2 27 | end 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2022 Brett Terpstra 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 | -------------------------------------------------------------------------------- /init.fish: -------------------------------------------------------------------------------- 1 | # fuzzy_cd initialization hook 2 | # 3 | # You can use the following variables in this file: 4 | # * $package package name 5 | # * $path package path 6 | # * $dependencies package dependencies 7 | if functions -q __fuzzy_cd 8 | if test -d ~/.marks && test (which fasd) 9 | if not functions -q __fuzzy_wrapped_cd 10 | functions -c cd __fuzzy_wrapped_cd 11 | end 12 | functions -e cd 13 | functions -c __fuzzy_cd cd 14 | end 15 | end 16 | 17 | function fcd_shortest_common 18 | set -l root $argv[1] 19 | set -l results $argv[1] 20 | set -e argv[1] 21 | for path in (fcd_return_array $argv | sort) 22 | if not test (string match "$root*" $path) 23 | set root $path 24 | set -a results $path 25 | end 26 | end 27 | fcd_return_array $results 28 | end 29 | 30 | function fcd_dir_to_regex 31 | echo (printf '%s' (echo "$argv"|sed -E 's/ +//g'|sed -E 's/(.)/\1[^\/]*/g')) 32 | end 33 | 34 | function fcd_dir_regex 35 | set -l section 36 | set -l regex (fcd_dir_to_regex $argv[1]) 37 | for arg in $argv[2..-1] 38 | set section (fcd_dir_to_regex $arg) 39 | set regex "$regex/[^.]*$section" 40 | end 41 | echo $regex 42 | end 43 | 44 | function fcd_return_array -d 'Echo out an array one line at a time' 45 | for item in $argv 46 | echo $item 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /functions/fcd_ffmark.fish: -------------------------------------------------------------------------------- 1 | function fcd_mark_to_regex 2 | echo (printf '%s' (echo "$argv"|sed -E 's/ +//g'|sed -E 's/(.)/\1[^\/]*/g')) 3 | end 4 | 5 | function fcd_mark_regex 6 | set -l section 7 | set -l regex (fcd_mark_to_regex $argv[1]) 8 | for arg in $argv[2..-1] 9 | set section (fcd_mark_to_regex $arg) 10 | set regex "$regex/.*$section" 11 | end 12 | echo $regex 13 | end 14 | 15 | function fcd_ffmark -d "fuzzy find a jump mark" 16 | if test -e ~/.marks/$argv[1] 17 | echo -n (readlink ~/.marks/$argv[1]) 18 | return 0 19 | end 20 | 21 | set -l new_path 22 | if test (count $argv) -gt 0 23 | set -l args $argv 24 | set -l found 25 | set -l case_sensitive 26 | 27 | set -l regex (fcd_mark_regex $args) 28 | 29 | # Search .marks 30 | set -l results (find -LE -s "$MARKPATH" -iregex "$MARKPATH/$regex" -type d -maxdepth 1 | head -n 1 | tr -d "\n") 31 | # Get shortest match 32 | set found (shortest $results) 33 | 34 | if test -n "$found" 35 | set found (string replace -r '^./' '' $found) 36 | set new_path $found 37 | else 38 | set -l results (find -LE -s "$MARKPATH" -iregex "$MARKPATH/.*$regex" -type d -maxdepth 1 | head -n 1 | tr -d "\n") 39 | # Get shortest match 40 | set found (shortest $results) 41 | if test -n "$found" 42 | set found (string replace -r '^./' '' $found) 43 | set new_path $found 44 | end 45 | end 46 | end 47 | echo -n (readlink "$new_path") 48 | end 49 | 50 | 51 | -------------------------------------------------------------------------------- /hooks/install.fish: -------------------------------------------------------------------------------- 1 | function __fcd_warn -d "Echo to STDERR" 2 | set -l options 'e/error' 'w/warn' 'i/info' 'h/help' 3 | 4 | set -l error 0 5 | set -l color (set_color normal) 6 | 7 | argparse $options -- $argv 8 | 9 | if set -q _flag_help 10 | echo "Output to STDERR" 11 | echo "Options:" 12 | echo " -e, --error Error level message" 13 | echo " -w, --warn Warning level message" 14 | echo " -i, --info Info level message" 15 | return 16 | end 17 | 18 | if set -q _flag_error 19 | set color (set_color -b brred brwhite) 20 | else if set -q _flag_warn 21 | set color (set_color -b bryellow black) 22 | else if set -q _flag_info 23 | set color (set_color brgreen) 24 | end 25 | set -l prompt (set_color bryellow) 26 | printf '%s>%s %s%s%s\n' $prompt $prompt $color "$argv" (set_color normal) >&2 27 | end 28 | 29 | __fcd_warn "fuzzy_cd: testing prerequisites" 30 | 31 | if not test -d ~/.marks 32 | __fcd_warn -e "fuzzy_cd: jump doesn't appear to be installed. Please see https://github.com/oh-my-fish/plugin-jump" 33 | __fcd_warn "......... if you have oh-my-fish installed, you can use `omf install jump`" 34 | else 35 | __fcd_warn "......... jump is installed" 36 | end 37 | 38 | if not test (which fzf) 39 | __fcd_warn -e "fuzzy_cd: fzf is not installed/available in PATH. Please install https://github.com/junegunn/fzf" 40 | __fcd_warn "......... if you're on a Mac and have Homebrew installed, you can use `brew install fzf`" 41 | else 42 | __fcd_warn "......... fzf is available" 43 | end 44 | 45 | 46 | if not test (which fasd) 47 | __fcd_warn -e "fuzzy_cd: fasd is not installed/available in PATH. Please install https://github.com/clvv/fasd" 48 | __fcd_warn "......... if you're on a Mac and have Homebrew installed, you can use `brew install fasd`" 49 | else 50 | __fcd_warn "......... fasd is available" 51 | end 52 | 53 | set curr_dir (dirname (status --current-filename)) 54 | source "$curr_dir/../init.fish" 55 | -------------------------------------------------------------------------------- /functions/__fuzzy_cd.fish: -------------------------------------------------------------------------------- 1 | function __fuzzy_cd -d "fuzzy cd with jump bookmarks" 2 | function __fuzzy_cd_chdir 3 | set -l res 4 | set -l first_token $argv[1] 5 | set -l tokens (string split " " (string replace -a "/" " " (string join "/" $argv))) 6 | set -l try_mark true 7 | 8 | # if the first token contains a non alphanumeric symbol, don't match a jump mark 9 | if string match -q -r -- '[^A-Za-z0-9]' $first_token 10 | set try_mark false 11 | end 12 | 13 | set -l token 14 | for dir in $tokens 15 | switch $dir 16 | case '.' 17 | command cd . 18 | case '..' 19 | command cd .. 20 | case '*' 21 | set -a token $dir 22 | end 23 | end 24 | 25 | if test (string match --regex '\.{3,}' $first_token) 26 | set -l count (math (string length $first_token) - 1) 27 | set base '.' 28 | while test $count -gt 0 29 | set base "$base/.." 30 | set count (math $count - 1) 31 | end 32 | 33 | set -e token[1] 34 | 35 | if test (count $token) -eq 0 36 | __fuzzy_wrapped_cd $base 37 | return 0 38 | end 39 | 40 | set res (fcd_ffdir -i -d2 --multi --shortest $base $token) 41 | else if $try_mark 42 | # See if first position is a match for a jump bookmark 43 | set -l base (fcd_ffmark $first_token) 44 | if test -n "$base" 45 | set -e token[1] 46 | else 47 | set base '.' 48 | end 49 | 50 | if test (count $token) -eq 0 51 | __fuzzy_wrapped_cd $base 52 | return 0 53 | end 54 | 55 | set res (fcd_ffdir -i -d2 --multi --shortest $base $token) 56 | end 57 | 58 | if test -z "$res" || test (string match '.' $res) || test (string match $base $res) 59 | # switch to using fasd, keeping the base if we matched a jump mark 60 | set -l search 61 | if test (string match "." $base) 62 | set search $token 63 | else 64 | set search $base $token 65 | end 66 | 67 | set res (fasd -tldR0 $search| head -n 5 | awk '{print $0}') 68 | end 69 | 70 | 71 | # set -l result (shortest $res) 72 | set -l result (printf "%s\n" $res | fzf -1 -0 --height=8 --info=inline --tiebreak=begin,length) 73 | 74 | if test -n "$result" 75 | __fuzzy_wrapped_cd $result 76 | else 77 | if not $try_mark 78 | __fuzzy_cd_chdir $token 79 | else 80 | fcd_warn "No match found" 81 | end 82 | end 83 | end 84 | 85 | if test -z "$argv" 86 | __fuzzy_wrapped_cd 87 | else if string match '-' "$argv" 88 | __fuzzy_wrapped_cd - 89 | else if test (count $argv) -eq 1 && test -e $argv[1] 90 | __fuzzy_wrapped_cd $argv 91 | else 92 | __fuzzy_cd_chdir $argv 93 | end 94 | end 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | #### Fuzzy cd 4 | 5 | > A plugin for [Oh My Fish][omf-link] which replaces the `cd` command with a fuzzy searching version. 6 | 7 | [![MIT License](https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square)](/LICENSE) 8 | [![Fish Shell Version](https://img.shields.io/badge/fish-v3.0.0-007EC7.svg?style=flat-square)](https://fishshell.com) 9 | [![Oh My Fish Framework](https://img.shields.io/badge/Oh%20My%20Fish-Framework-007EC7.svg?style=flat-square)](https://www.github.com/oh-my-fish/oh-my-fish) 10 | 11 |
12 | 13 | ## Dependencies 14 | 15 | You'll definitely need to install `fasd`. This is easiest with Homebrew, just `brew install fasd`. 16 | 17 | You'll also want `fzf` available. Again, easiest with Homebrew: `brew install fzf`. 18 | 19 | To make use of the jump marks, you'll want to install [this particular jump plugin](https://github.com/oh-my-fish/plugin-jump) (via `omf install jump`, probably). The `__fuzzy_cd` function doesn't actually use it for jumping, but my replacement for the `jump` function does not include any functions for adding or listing marks. This version of jump creates symlinks in `~/.marks`, which is what fuzzy cd is set up to read. 20 | 21 | ## Install 22 | 23 | ```fish 24 | $ omf repositories add https://github.com/ttscoff/omf-packages 25 | $ omf install fuzzy_cd 26 | ``` 27 | 28 | 29 | ## Usage 30 | 31 | ```fish 32 | $ cd JUMP_MARK [fuzzy [sub [dir [sequence]]]] 33 | ``` 34 | 35 | Fuzzy cd replaces the cd command. 36 | 37 | If there's only one argument to the `cd` command and it matches a valid path, `cd` will behave normally. 38 | 39 | If the first argument is a jump bookmark, that will be used as the base directory. Bookmarks are fuzzy matched, so `cd bmark` would recognize a bookmark titled `bookmark` and use it. 40 | 41 | Any additional arguments will be used to fuzzy search subdirectories in sequence. So `cd desk pod ov 8` would locate `~/Desktop/Podcasts/Overtired/268` and cd to it. 42 | 43 | If the first argument is 3 or more dots, `cd` will navigate up the directory tree, allowing fuzzy directory searching from the base folder with additional arguments. 1 dot is the current directory, 2 dots is the next level up, each additional dot is one level further up. 3 dots is equivalent to `../..`, 4 dots is `../../..`, etc. 44 | 45 | If no valid path is found using this method, `cd` will fall back to using `fasd` to search recent directories. 46 | 47 | # License 48 | 49 | [MIT][mit] © [Brett Terpstra][author] 50 | 51 | [mit]: https://opensource.org/licenses/MIT 52 | [author]: https://github.com/ttscoff 53 | [omf-link]: https://www.github.com/oh-my-fish/oh-my-fish 54 | 55 | [license-badge]: https://img.shields.io/badge/license-MIT-007EC7.svg?style=flat-square 56 | -------------------------------------------------------------------------------- /functions/fcd_ffdir.fish: -------------------------------------------------------------------------------- 1 | function fcd_ffdir -d "fuzzy find a directory, pass root dir and sequential search strings" 2 | set -l options "c/case-sensitive" "i/case-insensitive" "m/menu" "multi" "d/depth=" "shortest" 3 | argparse $options -- $argv 4 | 5 | set -l max_depth 2 6 | set -l new_path 7 | set -l args 8 | if test (count $argv) -gt 1 9 | set new_path $argv[1] 10 | set args $argv[2..-1] 11 | else 12 | set new_path '.' 13 | set args $argv 14 | end 15 | 16 | if set -q _flag_depth 17 | set max_depth $_flag_depth 18 | end 19 | 20 | 21 | if test (count $args) -gt 0 22 | # allow traversing to number of args * max count 23 | set max_depth (math (count $args)" * $max_depth") 24 | test $max_depth -gt 4 && set max_depth 4 25 | set -l found "." 26 | # if search string contains uppercase, make search case sensitive 27 | if string match -q --regex [A-Z] $args or set -q _flag_c 28 | set case_sensitive "regex" 29 | else 30 | set case_sensitive "iregex" 31 | end 32 | # search for directory containing string up to 2 levels deeper 33 | set -l regex (fcd_dir_regex $args) 34 | # start by looking for directories starting with first char of search 35 | # string, ignoring dot directories 36 | set -l results (find -EL -s "$new_path" -$case_sensitive ".*/[^.]*$regex.*" -type d -maxdepth $max_depth -mindepth 1 2> /dev/null) 37 | # choose shortest result 38 | if set -q _flag_menu 39 | set found (echo -e (string join "\n" $results) | fzf -1 -0) 40 | if test -z "$found" 41 | return 42 | end 43 | else 44 | if set -q _flag_multi 45 | set found $results 46 | else 47 | set found (fcd_shortest $results) 48 | end 49 | end 50 | 51 | # if we found a result, clean it up 52 | if test -n "$found" 53 | if set -q _flag_multi 54 | if set -q _flag_shortest 55 | set found (fcd_shortest_common $found) 56 | end 57 | fcd_return_array $found 58 | return 59 | end 60 | set found (echo -n "$found" | sed -e 's/^\.\///') 61 | set new_path $found 62 | else # if not, try again without the first char/dot requirement 63 | set results (find -EL -s "$new_path" -$case_sensitive ".*$regex.*" -type d -maxdepth $max_depth -mindepth 1 2> /dev/null) 64 | if set -q _flag_shortest 65 | set results (fcd_shortest_common $results) 66 | end 67 | if set -q _flag_menu 68 | set found (fcd_return_array $results | fzf -1 -0) 69 | if test -z "$found" 70 | return 71 | end 72 | else 73 | if set -q _flag_multi 74 | set found $results 75 | else 76 | set found (fcd_shortest $results) 77 | end 78 | end 79 | if test -n "$found" 80 | if set -q _flag_multi 81 | echo -e (string join "\n" $found) 82 | return 83 | end 84 | set found (echo "$found" | sed -e 's/^\.\///') 85 | set new_path $found 86 | else 87 | set -e new_path 88 | end 89 | end 90 | end 91 | echo "$new_path" 92 | end 93 | -------------------------------------------------------------------------------- /functions/fcd_jump.fish: -------------------------------------------------------------------------------- 1 | # A replacement for "jump" from the jump package that 2 | # handles fuzzy subdirectory searching for additional 3 | # arguments. 4 | # 5 | # Requires that jump be installed (`omf install jump`). 6 | # Then add the following files to ~/.config/fish/functions/, 7 | # which should override the jump command from the package: 8 | # 9 | # - jump.fish 10 | # - fcd_ffmark.fish 11 | # - fcd_ffdir.fish 12 | # - fcd_shortest.fish 13 | # 14 | # Fist argument must be an existing bookmark (also fuzzy 15 | # matched), additional arguments are searched within the 16 | # bookmark directory, in argument order. If the first 17 | # argument is '.', subdirectories will be searched from 18 | # current working directory. 19 | # 20 | # Any part of the directory name can be matched, shortest 21 | # result is used. 22 | # 23 | # Subdirectory search string is separated by slashes or 24 | # spaces. Each segment of the string is a fuzzy directory 25 | # search. Segments can be matched up to two directory levels 26 | # apart. 27 | # 28 | # Assuming a bookmark called "appsupp", linked to 29 | # ~/Library/Application Support 30 | # 31 | # $ jump apsup m2/css 32 | # 33 | # would match: 34 | # ~/Library/Application Support/Marked 2/Custom CSS 35 | # 36 | # If the search arguments are all lowercase, the search is 37 | # case insensitive. If an argument contains uppercase 38 | # letters, matching becomes case sensitive. Use -i to force 39 | # case insensitive, or -c to force case sensitive. 40 | function jump -d 'Fish "jump" replacement with subdirectory matching' 41 | set -l options "I/case-sensitive" "i/case-insensitive" "h/help" "v/verbose" "c/command=" "nomenu" "multi" 42 | set -l case_sensitive 43 | set -l cmd 44 | set -l verbose 45 | set -l use_fzf ' -m' 46 | set -l multi '' 47 | 48 | argparse $options -- $argv 49 | 50 | if set -q _flag_nomenu 51 | set use_fzf '' 52 | end 53 | 54 | if set -q _flag_multi 55 | set multi ' --multi' 56 | end 57 | 58 | if set -q _flag_help || test (count $argv) -eq 0 59 | echo "Fuzzy jump with subdirectory matching" 60 | echo 61 | echo "Usage: jump [MARK] [sub directory search]" 62 | echo 63 | echo "- MARK fuzzy matches a link in $MARKPATH" 64 | echo "- following strings fuzzy match subdirectories" 65 | echo "- search folders can be separated by space or slash" 66 | echo "- folder matches can be up to 2 levels deeper than the preceding match" 67 | echo 68 | echo "Example:" 69 | echo " # where appsupp is an existing jump bookmark" 70 | echo " jump appsupp m2 css" 71 | echo " => ~/Library/Application Support/Marked 2/Custom CSS" 72 | echo 73 | echo "Options:" 74 | echo " -c, --command=CMD - run CMD instead of cd" 75 | echo " -I - force case sensitive subdirectory matching" 76 | echo " -i - force case insensitive subdirectory matching" 77 | echo " -h - display this help" 78 | return 0 79 | end 80 | 81 | if set -q _flag_I 82 | set case_sensitive " -c" 83 | else if set -q _flag_i 84 | set case_sensitive " -i" 85 | end 86 | 87 | if set -q _flag_c 88 | set cmd $_flag_c 89 | else 90 | set cmd "cd" 91 | end 92 | 93 | if set -q _flag_v 94 | if functions -q warn 95 | set verbose "warn" 96 | else 97 | set verbose "echo" 98 | end 99 | end 100 | 101 | set -l max_depth 2 102 | set -l regex 103 | set -l args 104 | set -l new_path 105 | 106 | # if first arg is '.', search from current directory 107 | if test "$argv[1]" = '.' 108 | set new_path (fcd_ffdir $use_fzf$multi$case_sensitive . $argv) 109 | if test -n "$new_path" -a -d "$new_path" 110 | 111 | eval $cmd \"$new_path\" 112 | else 113 | echo "No match found" 114 | return 1 115 | end 116 | # if first arg is an exact match for a bookmark 117 | else if test -d $MARKPATH/$argv[1] -a -L $MARKPATH/$argv[1] 118 | set new_path (readlink $MARKPATH/$argv[1]) 119 | # we have more than one argument, search for subdirs 120 | if test (count $argv) -gt 1 121 | set args $argv[2..-1] 122 | set new_path (fcd_ffdir $use_fzf$multi$case_sensitive $new_path $args) 123 | end 124 | # if test -n verbose 125 | # eval $verbose $cmd \"$new_path\" 126 | # end 127 | eval $cmd \"$new_path\" 128 | # no match, fuzzy search bookmarks 129 | else 130 | set new_path (fcd_ffmark $case_sensitive $argv[1]) 131 | 132 | if test -n "$new_path" -a -d "$new_path" 133 | # if we have more than one argument, search for 134 | # subdirs 135 | if test (count $argv) -gt 1 136 | # set args (string split / (string join "" $argv[2..-1])) 137 | set args $argv[2..-1] 138 | set new_path (fcd_ffdir $use_fzf$multi$case_sensitive $new_path $args) 139 | end 140 | 141 | eval $cmd \"$new_path\" 142 | # if first arg is an actual directory, open that 143 | else if test -d $argv[1] 144 | set new_path "$argv[1]" 145 | if test (count $argv) -gt 1 146 | set new_path (fcd_ffdir $use_fzf$multi$case_sensitive $new_path $argv[2..-1]) 147 | end 148 | 149 | eval $cmd \"$new_path\" 150 | else 151 | echo "No such mark: $argv[1]" 152 | end 153 | end 154 | end 155 | 156 | --------------------------------------------------------------------------------