├── LICENSE ├── README.md ├── definitions ├── fastactions.py ├── fastvim.py └── install.sh /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Daniel Ting 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 |
2 | 3 | ## Overview 4 | 5 | fastdiract (fastdir + fastaction) is a pair of shell tools based on key-value storage for quick shell navigation and command execution. 6 | 7 | Each tool saves directories/commands to one of 10 "memory" slots in a file for quick retrieval via 2-character aliases (`d0`-`d9` and `f0`-`f9`). 8 | 9 | ### Fastdir 10 | fastdir is a shell navigation tool to help you store and jump to your most frequently used directories (aka fastdirs), stored in slots `d0`-`d9`. 11 | 12 | For example, you can cd to a `/deep/very/deep/directory` and run `d2.` to save that location to slot `d2`. In the future, whenever you run `d2`, you will jump to that saved directory. 13 | 14 | Here's fastdir cycling through 7 directories in about 4 seconds: 15 | 16 | 17 | 18 | More commands: 19 | - `d`/`d?` shows the list of fastdirs 20 | - `dw` allows you to swap the position of two fastdirs 21 | - `dx` changes the fastdir context 22 | - `dX` creates a new fastdir context 23 | - `d-` deletes a fastdir context 24 | - `dm` shows the list of fastdirs and gives you a menu to run a command 25 | 26 | ### Fastaction 27 | 28 | fastaction is a tool to save frequently executed commands, stored in slots `f0`-`f9`. To save a command to slot `f7`, run something like `f7. "echo hello there > myfile"`, making sure to wrap the command in double or single quotes. You can then execute the command easily by running `f7`. 29 | 30 | 31 | 32 | More commands: 33 | - `f`/`f?` shows the list of fastactions 34 | - `fw` allows you to swap the position of two fastactions 35 | - `fx` changes the fastaction context 36 | - `fX` creates a new fastaction context 37 | - `f-` deletes a fastaction context 38 | - `fm` shows the list of fastactions and gives you a menu to run a command 39 | 40 | ### Fastdiract Contexts 41 | 42 | For situations where there are more than 10 items to save and remember, fastdiract supports the creation and management of "contexts", which can be switched between easily. 43 | 44 | The following gif shows how fastdir contexts are switched and used (the same can be done for fastaction contexts). 45 | 46 | 47 | 48 | ### Installation 49 | To install fastdiract, run `install.sh`. 50 | 51 | fzf must be installed to support fastdir/fastaction context switching, and python is needed to support setting fastactions. 52 | 53 | ### Customization 54 | 55 | fastdiract starts with some sane defaults, but it can be configured by changing the following options in the `definitions` file: 56 | 57 | | Configuration Variable | Description | 58 | |------------------------|-----------------| 59 | | `FASTDIR_POSTCMD` | Command to execute after jumping to a fastdir, e.g. `ls` | 60 | | `FASTDIR_ECHO` | Whether to echo the fastdir command being executed, e.g. `cd mydir` | 61 | | `FASTACT_ECHO` | Whether to echo the fastaction command being executed, e.g. `echo 'hello there'` | 62 | | `FASTACT_CONF` | Whether to prompt for a `y/n` confirmation before executing a fastaction command | 63 | | `FASTACT_MENU_CONF` | Whether to prompt for a `y/n` confirmation before executing a fastaction from the menu (`fm`) | 64 | | `FASTACT_D_RUNS_MENU` | If set to `"on"`, running `d` will run the fastdir menu (`dm`). Otherwise, `d` will just display the current fastdirs. | 65 | | `FASTACT_F_RUNS_MENU` | If set to `"on"`, running `f` will run the fastaction menu (`fm`). Otherwise, `f` will just display the current fastactions. | 66 | | `CTX_COLOR` | Can be set to an [ANSI color code](https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences) for highlighting the context in different fastdiract commands. The default is green (`\033[1;32m`). | 67 | 68 | ### Misc 69 | 70 | You can use fastaction commands recursively and use fastdir commands in fastaction commands, e.g. `f1. = "d1 && f2 && echo hello"` 71 | 72 | Why would you want something like this when there are so many other directory navigation tools? 73 | - Many tools like z or zoxide let you probabilistically switch to frequent or "frecent" directories, but when working with many directories with deep paths and similar names (e.g., `/tree/deep/in/the/forest` vs. `tree/deep/in/the/dark/forest`), there are no hard guarantees on where you'll end up. fastdiract, on the other hand, is fully deterministic since the user preselects the directory choices. Personally, I use bash aliases for directories I always use (e.g. `alias fav="cd myfavdir`), fastdiract for frequently used directories, and z for directories that I access infrequently. 74 | - Some tools like bashmarks let you define a bookmark name and jump to it. However, remembering the names can get difficult and typing out long names takes time, whereas fastdiract lets you jump to any predefined directory with a 2-character combination, e.g., `d1`. 75 | 76 | If you don't have fzf or would like to use a more stripped down version of fastdiract without contexts, check out the `minimal` branch. 77 | 78 | ### Acknowledgements 79 | 80 | The hand icon in the logo was created by `nightwolfdezines` and comes from [Vecteezy](https://www.vecteezy.com/free-vector/human). 81 | -------------------------------------------------------------------------------- /definitions: -------------------------------------------------------------------------------- 1 | ################## 2 | # Config Options # 3 | ################## 4 | FASTDIRACT_DIR=~/.fastdiract 5 | FASTDIR_FILE=$FASTDIRACT_DIR/fastdirs 6 | FASTDIR_CTX_POSTSWITCH_CMD="d0" 7 | FASTACT_FILE=$FASTDIRACT_DIR/fastactions 8 | FASTVIM_FILE=$FASTDIRACT_DIR/fastvim 9 | FASTDIR_POSTCMD="ls" 10 | FASTDIR_ECHO="off" 11 | 12 | FASTACT_ECHO="on" 13 | FASTACT_CONF="off" 14 | FASTACT_MENU_CONF="off" 15 | FASTACT_D_RUNS_MENU="off" 16 | FASTACT_F_RUNS_MENU="off" 17 | FASTACT_V_RUNS_MENU="off" 18 | 19 | GREEN='\033[1;32m' 20 | CTX_COLOR=$GREEN 21 | NC='\033[1;0m' 22 | 23 | #################### 24 | # Helper Functions # 25 | #################### 26 | fastdir_run () { 27 | if [ "$FASTDIR_ECHO" == "on" ]; then 28 | echo "$@" 29 | fi 30 | # NOTE: must use eval to expand envvars 31 | eval "$@" 32 | } 33 | 34 | fastact_run () { 35 | if [ "$FASTACT_ECHO" == "on" ]; then 36 | echo "$@" 37 | fi 38 | if [ "$FASTACT_CONF" == "on" ]; then 39 | # NOTE: must use eval to expand envvars 40 | echo -n "Execute [y/n]? " 41 | reply=$(bash -c "read -n 1 c; echo \$c") 42 | if [ "$reply" != "${reply#[Yy]}" ]; then 43 | echo "" 44 | eval "$@" 45 | fi 46 | else 47 | eval "$@" 48 | fi 49 | } 50 | 51 | fastdiract_get_fastdir_ctx() { 52 | echo "$(readlink -f $FASTDIR_FILE | cut -d'_' -f3)" 53 | } 54 | 55 | fastdiract_get_fastact_ctx() { 56 | echo "$(readlink -f $FASTACT_FILE | cut -d'_' -f3)" 57 | } 58 | 59 | fastdiract_get_fastvim_ctx() { 60 | echo "$(readlink -f $FASTVIM_FILE | cut -d'_' -f3)" 61 | } 62 | 63 | ####################### 64 | # Fastdir Definitions # 65 | ####################### 66 | alias d0='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d0 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 67 | alias d1='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d1 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 68 | alias d2='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d2 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 69 | alias d3='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d3 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 70 | alias d4='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d4 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 71 | alias d5='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d5 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 72 | alias d6='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d6 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 73 | alias d7='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d7 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 74 | alias d8='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d8 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 75 | alias d9='fastdir_run cd \"$(cat $FASTDIR_FILE | grep "d9 = " | cut -d"=" -f 2- | sed "s/~/\$HOME/" | xargs)\" && $FASTDIR_POSTCMD' 76 | 77 | alias d0.='sed -i --follow-symlinks "s|d0 =.*$|d0 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 78 | alias d1.='sed -i --follow-symlinks "s|d1 =.*$|d1 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 79 | alias d2.='sed -i --follow-symlinks "s|d2 =.*$|d2 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 80 | alias d3.='sed -i --follow-symlinks "s|d3 =.*$|d3 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 81 | alias d4.='sed -i --follow-symlinks "s|d4 =.*$|d4 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 82 | alias d5.='sed -i --follow-symlinks "s|d5 =.*$|d5 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 83 | alias d6.='sed -i --follow-symlinks "s|d6 =.*$|d6 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 84 | alias d7.='sed -i --follow-symlinks "s|d7 =.*$|d7 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 85 | alias d8.='sed -i --follow-symlinks "s|d8 =.*$|d8 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 86 | alias d9.='sed -i --follow-symlinks "s|d9 =.*$|d9 = $(pwd | sed "s|^$HOME|~|")|g" $FASTDIR_FILE' 87 | alias d?='echo -e "${CTX_COLOR}[$(fastdiract_get_fastdir_ctx)]${NC}"; cat $FASTDIR_FILE | grep "d[0-9]"' 88 | 89 | d() { 90 | if [ "$FASTACT_D_RUNS_MENU" == "on" ]; then 91 | dm 92 | else 93 | d? 94 | fi 95 | } 96 | 97 | dm() { 98 | if ! [ "$#" == 1 -a "$1" == "quiet" ]; then 99 | d? 100 | fi 101 | echo -n "> " 102 | reply=$(bash -c "read -n 1 c; echo \$c") 103 | echo "" 104 | local cmd="" 105 | if [ "$reply" == "." ]; then 106 | echo -n "Save cwd to: " 107 | reply=$(bash -c "read -n 1 c; echo \$c") 108 | cmd="d${reply}." 109 | eval "$cmd" 110 | elif [ "$reply" == "w" ]; then 111 | dw 112 | elif [ "$reply" == "x" ]; then 113 | dx 114 | elif [ "$reply" == "X" ]; then 115 | dX 116 | elif [ "$reply" == "-" ]; then 117 | d- 118 | elif [[ "$reply" =~ [0-9] ]]; then 119 | cmd="d${reply}" 120 | eval "$cmd" 121 | elif [ "$reply" == "?" ]; then 122 | echo "= COMMANDS ==========================================" 123 | echo ". Set dir w Swap dirs x Change context" 124 | echo "? Show help 0-9 Jump to dir X Create new context" 125 | echo "- Delete context" 126 | echo "=====================================================" 127 | dm "quiet" 128 | else 129 | echo "invalid cmd \"$reply\"" 130 | fi 131 | } 132 | 133 | dw() { 134 | echo "Swap directories:" 135 | echo -n "> " 136 | dirnum1=$(bash -c "read -n 1 c; echo \$c") 137 | echo "" 138 | if [[ $dirnum1 =~ [0-9] ]]; then 139 | echo -n "> " 140 | dirnum2=$(bash -c "read -n 1 c; echo \$c") 141 | echo "" 142 | if [[ $dirnum2 =~ [0-9] ]]; then 143 | dir1="$(cat $FASTDIR_FILE | grep 'd'${dirnum1}' = ' | cut -d'=' -f 2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" 144 | dir2="$(cat $FASTDIR_FILE | grep 'd'${dirnum2}' = ' | cut -d'=' -f 2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" 145 | sed -i --follow-symlinks "s|d${dirnum1} =.*$|d${dirnum1} = $dir2|g" $FASTDIR_FILE 146 | sed -i --follow-symlinks "s|d${dirnum2} =.*$|d${dirnum2} = $dir1|g" $FASTDIR_FILE 147 | d? 148 | fi 149 | fi 150 | } 151 | 152 | dx() { 153 | choice="$(ls -1 $FASTDIRACT_DIR/fastdirs__* | while read line; do echo $(basename $line) | cut -d'_' -f3 ; done | fzf --prompt="Change fastdir ctx from [$(fastdiract_get_fastdir_ctx)] to: " --preview="echo -e '${CTX_COLOR}[{}]${NC}'; cat '$FASTDIRACT_DIR/fastdirs__{}' | grep 'd[0-9]'" --preview-window=wrap)" 154 | # Test to handle case where fzf was cancelled 155 | if [ -n "$choice" ]; then 156 | unlink "$FASTDIR_FILE" 157 | ln -s "$FASTDIRACT_DIR/fastdirs__${choice}" "$FASTDIR_FILE" 158 | d? 159 | eval $FASTDIR_CTX_POSTSWITCH_CMD 160 | fi 161 | } 162 | 163 | dX() { 164 | echo -n "Create new fastdir ctx? [y/n] " 165 | user_resp=$(bash -c "read -n 1 c; echo \$c") 166 | if [ "$user_resp" == "y" ]; then 167 | echo -n "\nEnter new ctx name: " 168 | read new_ctx 169 | echo -ne "Use ${CTX_COLOR}[$new_ctx]${NC} as new ctx name? [y/n] " 170 | user_resp=$(bash -c "read -n 1 c; echo \$c") 171 | if [ "$user_resp" == "y" ]; then 172 | base="$(ls -1 $FASTDIRACT_DIR/fastdirs__* | while read line; do echo $(basename $line) | cut -d'_' -f3 ; done | fzf --preview="echo -e '${CTX_COLOR}[{}]${NC}'; cat '$FASTDIRACT_DIR/fastdirs__{}' | grep 'd[0-9]'" --preview-window=wrap)" 173 | echo -ne "\nUse ${CTX_COLOR}[$base]${NC} as base for new ctx? [y/n] " 174 | user_resp=$(bash -c "read -n 1 c; echo \$c") 175 | if [ "$user_resp" == "y" ]; then 176 | cp "$FASTDIRACT_DIR/fastdirs__${base}" "$FASTDIRACT_DIR/fastdirs__${new_ctx}" 177 | unlink "$FASTDIR_FILE" 178 | ln -s "$FASTDIRACT_DIR/fastdirs__${new_ctx}" "$FASTDIR_FILE" 179 | echo "\nCreated and switched to new context ${CTX_COLOR}[$new_ctx]${NC}" 180 | fi 181 | fi 182 | fi 183 | } 184 | 185 | d-() { 186 | choice="$(ls -1 $FASTDIRACT_DIR/fastdirs__* | while read line; do echo $(basename $line) | cut -d'_' -f3 ; done | fzf --prompt="fastdir ctx to delete: " --preview="echo -e '${CTX_COLOR}[{}]${NC}'; cat '$FASTDIRACT_DIR/fastdirs__{}' | grep 'd[0-9]'" --preview-window=wrap)" 187 | if [ "$(fastdiract_get_fastdir_ctx)" == "$choice" ]; then 188 | echo "Can't delete the current fastdir ctx; switch to another ctx first" 189 | else 190 | echo -ne "Delete fastdir ctx ${CTX_COLOR}[$choice]${NC}? [y/n] " 191 | user_resp=$(bash -c "read -n 1 c; echo \$c") 192 | if [ "$user_resp" == "y" ]; then 193 | rm "$FASTDIRACT_DIR/fastdirs__$choice" 194 | echo "\nDeleted fastdir ctx $choice" 195 | fi 196 | fi 197 | } 198 | 199 | ####################### 200 | # Fastact Definitions # 201 | ####################### 202 | alias f0='fastact_run $(cat $FASTACT_FILE | grep "f0 = " | cut -d"=" -f 2-)' 203 | alias f1='fastact_run $(cat $FASTACT_FILE | grep "f1 = " | cut -d"=" -f 2-)' 204 | alias f2='fastact_run $(cat $FASTACT_FILE | grep "f2 = " | cut -d"=" -f 2-)' 205 | alias f3='fastact_run $(cat $FASTACT_FILE | grep "f3 = " | cut -d"=" -f 2-)' 206 | alias f4='fastact_run $(cat $FASTACT_FILE | grep "f4 = " | cut -d"=" -f 2-)' 207 | alias f5='fastact_run $(cat $FASTACT_FILE | grep "f5 = " | cut -d"=" -f 2-)' 208 | alias f6='fastact_run $(cat $FASTACT_FILE | grep "f6 = " | cut -d"=" -f 2-)' 209 | alias f7='fastact_run $(cat $FASTACT_FILE | grep "f7 = " | cut -d"=" -f 2-)' 210 | alias f8='fastact_run $(cat $FASTACT_FILE | grep "f8 = " | cut -d"=" -f 2-)' 211 | alias f9='fastact_run $(cat $FASTACT_FILE | grep "f9 = " | cut -d"=" -f 2-)' 212 | 213 | # NOTE: When using f0.-f9., use single quotes to wrap the whole command 214 | FASTDIRACT_SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" 215 | alias f0.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f0' 216 | alias f1.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f1' 217 | alias f2.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f2' 218 | alias f3.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f3' 219 | alias f4.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f4' 220 | alias f5.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f5' 221 | alias f6.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f6' 222 | alias f7.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f7' 223 | alias f8.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f8' 224 | alias f9.='python $FASTDIRACT_SCRIPT_DIR/fastactions.py f9' 225 | alias f?='echo "${CTX_COLOR}[$(fastdiract_get_fastact_ctx)]${NC}"; cat $FASTACT_FILE | grep "f[0-9]"' 226 | 227 | f() { 228 | if [ "$FASTACT_F_RUNS_MENU" == "on" ]; then 229 | fm 230 | else 231 | f? 232 | fi 233 | } 234 | 235 | fm() { 236 | if ! [ "$#" == 1 -a "$1" == "quiet" ]; then 237 | f? 238 | fi 239 | echo -n "> " 240 | reply=$(bash -c "read -n 1 c; echo \$c") 241 | echo "" 242 | local cmd="" 243 | if [ "$reply" == "." ]; then 244 | echo -n "Enter cmd # to set: " 245 | cmdnum=$(bash -c "read -n 1 c; echo \$c") 246 | if [[ $cmdnum =~ [0-9] ]]; then 247 | setcmd="f${cmdnum}." 248 | echo -n "\nEnter cmd: " 249 | cmd=$(bash -c "read c; echo \$c") 250 | eval "$setcmd $cmd" 251 | f? 252 | else 253 | echo "\ninvalid cmd # $cmdnum" 254 | fi 255 | elif [ "$reply" == "w" ]; then 256 | fw 257 | elif [ "$reply" == "x" ]; then 258 | fx 259 | elif [ "$reply" == "X" ]; then 260 | fX 261 | elif [ "$reply" == "-" ]; then 262 | f- 263 | elif [[ "$reply" =~ [0-9] ]]; then 264 | cmd="f${reply}" 265 | if [ "$FASTACT_MENU_CONF" == "on" -a "$FASTACT_CONF" != "on" ]; then 266 | echo -n "Execute $cmd? [y/n] " 267 | user_resp=$(bash -c "read -n 1 c; echo \$c") 268 | if [ "$user_resp" == "y" ]; then 269 | echo "" 270 | eval "$cmd" 271 | fi 272 | else 273 | echo "" 274 | eval "$cmd" 275 | fi 276 | elif [ "$reply" == "?" ]; then 277 | echo "= COMMANDS =============================================" 278 | echo ". Set action w Swap actions x Change context" 279 | echo "? Show help 0-9 Execute action X Create new context" 280 | echo "- Delete context" 281 | echo "========================================================" 282 | fm "quiet" 283 | else 284 | echo "invalid cmd \"$reply\"" 285 | fi 286 | } 287 | 288 | fw() { 289 | echo "Swap actions:" 290 | echo -n "> " 291 | actnum1=$(bash -c "read -n 1 c; echo \$c") 292 | echo "" 293 | if [[ $actnum1 =~ [0-9] ]]; then 294 | echo -n "> " 295 | actnum2=$(bash -c "read -n 1 c; echo \$c") 296 | echo "" 297 | if [[ $actnum2 =~ [0-9] ]]; then 298 | act1="$(cat $FASTACT_FILE | grep 'f'${actnum1}' = ' | cut -d'=' -f 2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" 299 | act2="$(cat $FASTACT_FILE | grep 'f'${actnum2}' = ' | cut -d'=' -f 2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" 300 | # 2nd sed command is from 301 | # https://stackoverflow.com/questions/29613304/is-it-possible-to-escape-regex-metacharacters-reliably-with-sed 302 | # to escape metacharacters like &&. 303 | sed -i --follow-symlinks "s|f${actnum1} =.*$|f${actnum1} = $(sed 's/[&/\]/\\&/g' <<< $act2)|" $FASTACT_FILE 304 | sed -i --follow-symlinks "s|f${actnum2} =.*$|f${actnum2} = $(sed 's/[&/\]/\\&/g' <<< $act1)|" $FASTACT_FILE 305 | f? 306 | fi 307 | fi 308 | } 309 | 310 | fx() { 311 | choice="$(ls -1 $FASTDIRACT_DIR/fastactions__* | while read line; do echo $(basename $line) | cut -d'_' -f3 ; done | fzf --prompt="Change fastaction ctx from [$(fastdiract_get_fastact_ctx)] to: " --preview="echo -e '${CTX_COLOR}[{}]${NC}'; cat '$FASTDIRACT_DIR/fastactions__{}' | grep 'f[0-9]'" --preview-window=wrap)" 312 | # Test to handle case where fzf was cancelled 313 | if [ -n "$choice" ]; then 314 | unlink "$FASTACT_FILE" 315 | ln -s "$FASTDIRACT_DIR/fastactions__${choice}" "$FASTACT_FILE" 316 | f? 317 | fi 318 | } 319 | 320 | fX() { 321 | echo -n "Create new fastaction ctx? [y/n] " 322 | user_resp=$(bash -c "read -n 1 c; echo \$c") 323 | if [ "$user_resp" == "y" ]; then 324 | echo -n "\nEnter new ctx name: " 325 | read new_ctx 326 | echo -ne "Use ${CTX_COLOR}[$new_ctx]${NC} as new ctx name? [y/n] " 327 | user_resp=$(bash -c "read -n 1 c; echo \$c") 328 | if [ "$user_resp" == "y" ]; then 329 | base="$(ls -1 $FASTDIRACT_DIR/fastactions__* | while read line; do echo $(basename $line) | cut -d'_' -f3 ; done | fzf --preview="echo -e '${CTX_COLOR}[{}]${NC}'; cat '$FASTDIRACT_DIR/fastactions__{}' | grep 'f[0-9]'" --preview-window=wrap)" 330 | echo -ne "\nUse ${CTX_COLOR}[$base]${NC} as base for new ctx? [y/n] " 331 | user_resp=$(bash -c "read -n 1 c; echo \$c") 332 | if [ "$user_resp" == "y" ]; then 333 | cp "$FASTDIRACT_DIR/fastactions__${base}" "$FASTDIRACT_DIR/fastactions__${new_ctx}" 334 | unlink "$FASTACT_FILE" 335 | ln -s "$FASTDIRACT_DIR/fastactions__${new_ctx}" "$FASTACT_FILE" 336 | echo "\nCreated and switched to new context ${CTX_COLOR}[$new_ctx]${NC}" 337 | fi 338 | fi 339 | fi 340 | } 341 | 342 | f-() { 343 | choice="$(ls -1 $FASTDIRACT_DIR/fastactions__* | while read line; do echo $(basename $line) | cut -d'_' -f3 ; done | fzf --prompt="fastaction ctx to delete: " --preview="echo -e '${CTX_COLOR}[{}]${NC}'; cat '$FASTDIRACT_DIR/fastactions__{}' | grep 'f[0-9]'" --preview-window=wrap)" 344 | if [ "$(fastdiract_get_fastaction_ctx)" == "$choice" ]; then 345 | echo "Can't delete the current fastaction ctx; switch to another ctx first" 346 | else 347 | echo -ne "Delete fastaction ctx ${CTX_COLOR}[$choice]${NC}? [y/n] " 348 | user_resp=$(bash -c "read -n 1 c; echo \$c") 349 | if [ "$user_resp" == "y" ]; then 350 | rm "$FASTDIRACT_DIR/fastactions__$choice" 351 | echo "\nDeleted fastaction ctx $choice" 352 | fi 353 | fi 354 | } 355 | 356 | ####################### 357 | # Fastvim Definitions # 358 | ####################### 359 | alias v0='vim $(cat $FASTVIM_FILE | grep "v0 = " | cut -d"=" -f 2-)' 360 | alias v1='vim $(cat $FASTVIM_FILE | grep "v1 = " | cut -d"=" -f 2-)' 361 | alias v2='vim $(cat $FASTVIM_FILE | grep "v2 = " | cut -d"=" -f 2-)' 362 | alias v3='vim $(cat $FASTVIM_FILE | grep "v3 = " | cut -d"=" -f 2-)' 363 | alias v4='vim $(cat $FASTVIM_FILE | grep "v4 = " | cut -d"=" -f 2-)' 364 | alias v5='vim $(cat $FASTVIM_FILE | grep "v5 = " | cut -d"=" -f 2-)' 365 | alias v6='vim $(cat $FASTVIM_FILE | grep "v6 = " | cut -d"=" -f 2-)' 366 | alias v7='vim $(cat $FASTVIM_FILE | grep "v7 = " | cut -d"=" -f 2-)' 367 | alias v8='vim $(cat $FASTVIM_FILE | grep "v8 = " | cut -d"=" -f 2-)' 368 | alias v9='vim $(cat $FASTVIM_FILE | grep "v9 = " | cut -d"=" -f 2-)' 369 | 370 | # NOTE: When using v0.-v9., use single quotes to wrap the whole command 371 | FASTVIM_SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" 372 | alias v0.='python $FASTVIM_SCRIPT_DIR/fastvim.py v0 $(pwd)' 373 | alias v1.='python $FASTVIM_SCRIPT_DIR/fastvim.py v1 $(pwd)' 374 | alias v2.='python $FASTVIM_SCRIPT_DIR/fastvim.py v2 $(pwd)' 375 | alias v3.='python $FASTVIM_SCRIPT_DIR/fastvim.py v3 $(pwd)' 376 | alias v4.='python $FASTVIM_SCRIPT_DIR/fastvim.py v4 $(pwd)' 377 | alias v5.='python $FASTVIM_SCRIPT_DIR/fastvim.py v5 $(pwd)' 378 | alias v6.='python $FASTVIM_SCRIPT_DIR/fastvim.py v6 $(pwd)' 379 | alias v7.='python $FASTVIM_SCRIPT_DIR/fastvim.py v7 $(pwd)' 380 | alias v8.='python $FASTVIM_SCRIPT_DIR/fastvim.py v8 $(pwd)' 381 | alias v9.='python $FASTVIM_SCRIPT_DIR/fastvim.py v9 $(pwd)' 382 | alias v?='echo "${CTX_COLOR}[$(fastdiract_get_fastvim_ctx)]${NC}"; cat $FASTVIM_FILE | grep "v[0-9]"' 383 | 384 | v() { 385 | if [ "$FASTVIM_V_RUNS_MENU" == "on" ]; then 386 | vm 387 | else 388 | v? 389 | fi 390 | } 391 | 392 | vm() { 393 | if ! [ "$#" == 1 -a "$1" == "quiet" ]; then 394 | v? 395 | fi 396 | echo -n "> " 397 | reply=$(bash -c "read -n 1 c; echo \$c") 398 | echo "" 399 | local cmd="" 400 | if [ "$reply" == "." ]; then 401 | echo -n "Enter v # to set: " 402 | vnum=$(bash -c "read -n 1 c; echo \$c") 403 | if [[ $vnum =~ [0-9] ]]; then 404 | setfile="v${vnum}." 405 | echo -n "\nEnter file: " 406 | file=$(bash -c "read f; echo \$f") 407 | eval "$setfile $file" 408 | v? 409 | else 410 | echo "\ninvalid num # $vnum" 411 | fi 412 | elif [ "$reply" == "w" ]; then 413 | vw 414 | elif [ "$reply" == "x" ]; then 415 | vx 416 | elif [ "$reply" == "X" ]; then 417 | vX 418 | elif [ "$reply" == "-" ]; then 419 | v- 420 | elif [[ "$reply" =~ [0-9] ]]; then 421 | cmd="v${reply}" 422 | if [ "$FASTVIM_MENU_CONF" == "on" -a "$FASTVIM_CONF" != "on" ]; then 423 | echo -n "Execute $cmd? [y/n] " 424 | user_resp=$(bash -c "read -n 1 c; echo \$c") 425 | if [ "$user_resp" == "y" ]; then 426 | echo "" 427 | eval "$cmd" 428 | fi 429 | else 430 | echo "" 431 | eval "$cmd" 432 | fi 433 | elif [ "$reply" == "?" ]; then 434 | echo "= COMMANDS =============================================" 435 | echo ". Set vim file w Swap vim files x Change context" 436 | echo "? Show help 0-9 Open file in vim X Create new context" 437 | echo "- Delete context" 438 | echo "========================================================" 439 | vm "quiet" 440 | else 441 | echo "invalid cmd \"$reply\"" 442 | fi 443 | } 444 | 445 | vw() { 446 | echo "Swap vims:" 447 | echo -n "> " 448 | vnum1=$(bash -c "read -n 1 c; echo \$c") 449 | echo "" 450 | if [[ $vnum1 =~ [0-9] ]]; then 451 | echo -n "> " 452 | vnum2=$(bash -c "read -n 1 c; echo \$c") 453 | echo "" 454 | if [[ $vnum2 =~ [0-9] ]]; then 455 | vimfile1="$(cat $FASTVIM_FILE | grep 'f'${vnum1}' = ' | cut -d'=' -f 2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" 456 | vimfile2="$(cat $FASTVIM_FILE | grep 'f'${vnum2}' = ' | cut -d'=' -f 2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')" 457 | # 2nd sed command is from 458 | # https://stackoverflow.com/questions/29613304/is-it-possible-to-escape-regex-metacharvimers-reliably-with-sed 459 | # to escape metacharacters like &&. 460 | sed -i --follow-symlinks "s|f${vnum1} =.*$|f${vnum1} = $(sed 's/[&/\]/\\&/g' <<< $vimfile2)|" $FASTVIM_FILE 461 | sed -i --follow-symlinks "s|f${vnum2} =.*$|f${vnum2} = $(sed 's/[&/\]/\\&/g' <<< $vimfile1)|" $FASTVIM_FILE 462 | v? 463 | fi 464 | fi 465 | } 466 | 467 | vx() { 468 | choice="$(ls -1 $FASTDIRACT_DIR/fastvim__* | while read line; do echo $(basename $line) | cut -d'_' -f3 ; done | fzf --prompt="Change vim ctx from [$(fastdiract_get_fastvim_ctx)] to: " --preview="echo -e '${CTX_COLOR}[{}]${NC}'; cat '$FASTDIRACT_DIR/fastvim__{}' | grep 'v[0-9]'" --preview-window=wrap)" 469 | # Test to handle case where fzf was cancelled 470 | if [ -n "$choice" ]; then 471 | unlink "$FASTVIM_FILE" 472 | ln -s "$FASTDIRACT_DIR/fastvim__${choice}" "$FASTVIM_FILE" 473 | v? 474 | fi 475 | } 476 | 477 | vX() { 478 | echo -n "Create new vim ctx? [y/n] " 479 | user_resp=$(bash -c "read -n 1 c; echo \$c") 480 | if [ "$user_resp" == "y" ]; then 481 | echo -n "\nEnter new ctx name: " 482 | read new_ctx 483 | echo -ne "Use ${CTX_COLOR}[$new_ctx]${NC} as new ctx name? [y/n] " 484 | user_resp=$(bash -c "read -n 1 c; echo \$c") 485 | if [ "$user_resp" == "y" ]; then 486 | base="$(ls -1 $FASTDIRACT_DIR/fastvim__* | while read line; do echo $(basename $line) | cut -d'_' -f3 ; done | fzf --preview="echo -e '${CTX_COLOR}[{}]${NC}'; cat '$FASTDIRACT_DIR/fastvim__{}' | grep 'v[0-9]'" --preview-window=wrap)" 487 | echo -ne "\nUse ${CTX_COLOR}[$base]${NC} as base for new ctx? [y/n] " 488 | user_resp=$(bash -c "read -n 1 c; echo \$c") 489 | if [ "$user_resp" == "y" ]; then 490 | cp "$FASTDIRACT_DIR/fastvim__${base}" "$FASTDIRACT_DIR/fastvim__${new_ctx}" 491 | unlink "$FASTVIM_FILE" 492 | ln -s "$FASTDIRACT_DIR/fastvim__${new_ctx}" "$FASTVIM_FILE" 493 | echo "\nCreated and switched to new context ${CTX_COLOR}[$new_ctx]${NC}" 494 | fi 495 | fi 496 | fi 497 | } 498 | 499 | v-() { 500 | choice="$(ls -1 $FASTDIRACT_DIR/fastvim__* | while read line; do echo $(basename $line) | cut -d'_' -f3 ; done | fzf --prompt="vim ctx to delete: " --preview="echo -e '${CTX_COLOR}[{}]${NC}'; cat '$FASTDIRACT_DIR/fastvim__{}' | grep 'v[0-9]'" --preview-window=wrap)" 501 | if [ "$(fastdiract_get_fastvim_ctx)" == "$choice" ]; then 502 | echo "Can't delete the current vim ctx; switch to another ctx first" 503 | else 504 | echo -ne "Delete vim ctx ${CTX_COLOR}[$choice]${NC}? [y/n] " 505 | user_resp=$(bash -c "read -n 1 c; echo \$c") 506 | if [ "$user_resp" == "y" ]; then 507 | rm "$FASTDIRACT_DIR/fastvim__$choice" 508 | echo "\nDeleted vim ctx $choice" 509 | fi 510 | fi 511 | } 512 | -------------------------------------------------------------------------------- /fastactions.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import fileinput 4 | import os 5 | import subprocess 6 | import sys 7 | 8 | if len(sys.argv) < 3: 9 | print("Too few arguments") 10 | sys.exit() 11 | 12 | key = sys.argv[1] 13 | new_cmd = ' '.join(sys.argv[2:]) 14 | script_dir = os.path.dirname(os.path.realpath(__file__)) 15 | def_file = os.path.join(script_dir, "definitions") 16 | cmd = "bash -c 'source {}; readlink -f $FASTACT_FILE'".format(def_file) 17 | fastact_file = subprocess.check_output(cmd, shell=True).decode().strip() 18 | for line in fileinput.input(os.path.expanduser(fastact_file), inplace = 1): 19 | if line.startswith(key + " ="): 20 | line = key + " = " + new_cmd + "\n" 21 | sys.stdout.write(line) 22 | -------------------------------------------------------------------------------- /fastvim.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import fileinput 4 | import os 5 | import subprocess 6 | import sys 7 | 8 | if len(sys.argv) < 3: 9 | print("Too few arguments") 10 | sys.exit() 11 | 12 | key = sys.argv[1] 13 | filedir = sys.argv[2] 14 | vim_file = os.path.join(filedir, ' '.join(sys.argv[3:])) 15 | 16 | script_dir = os.path.dirname(os.path.realpath(__file__)) 17 | def_file = os.path.join(script_dir, "definitions") 18 | cmd = "bash -c 'source {}; readlink -f $FASTVIM_FILE'".format(def_file) 19 | fastvim_file = subprocess.check_output(cmd, shell=True).decode().strip() 20 | for line in fileinput.input(os.path.expanduser(fastvim_file), inplace = 1): 21 | if line.startswith(key + " ="): 22 | line = key + " = " + vim_file + "\n" 23 | sys.stdout.write(line) 24 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | 4 | SCRIPT_DIR="$(dirname "$(readlink -f "$0")")" 5 | source "$SCRIPT_DIR/definitions" 6 | 7 | if ! [ -d "$FASTDIRACT_DIR" ]; then 8 | mkdir -p "$FASTDIRACT_DIR" 9 | else 10 | echo "error: $FASTDIRACT_DIR already exists" 11 | fi 12 | 13 | if ! [ -f "${FASTDIR_FILE}__default" ]; then 14 | cat < "${FASTDIR_FILE}__default" 15 | d0 = ~/alpha 16 | d1 = ~/beta 17 | d2 = ~/gamma 18 | d3 = ~/delta 19 | d4 = ~/epsilon 20 | d5 = ~/zeta 21 | d6 = ~/eta 22 | d7 = ~/theta 23 | d8 = ~/iota 24 | d9 = ~/kappa 25 | EOF 26 | ln -s "$FASTDIRACT_DIR/fastdirs__default" "$FASTDIR_FILE" 27 | echo "Creating fastdirs template" 28 | else 29 | echo "fastdirs file already exists" 30 | fi 31 | 32 | if ! [ -f "${FASTACT_FILE}__default" ]; then 33 | cat < "${FASTACT_FILE}__default" 34 | f0 = echo alpha 35 | f1 = echo beta 36 | f2 = echo gamma 37 | f3 = echo delta 38 | f4 = echo epsilon 39 | f5 = echo zeta 40 | f6 = echo eta 41 | f7 = echo theta 42 | f8 = echo iota 43 | f9 = echo kappa 44 | EOF 45 | ln -s "$FASTDIRACT_DIR/fastactions__default" "$FASTACT_FILE" 46 | echo "Creating fastactions template" 47 | else 48 | echo "fastactions file already exists" 49 | fi 50 | 51 | echo "Run \"source $SCRIPT_DIR/definitions\" and add it to your bashrc/zshrc file" 52 | --------------------------------------------------------------------------------