├── 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 |
--------------------------------------------------------------------------------