diff --git a/.config/fish/completions/fzf_configure_bindings.fish b/.config/fish/completions/fzf_configure_bindings.fish
new file mode 100644
index 00000000..b38ef927
--- /dev/null
+++ b/.config/fish/completions/fzf_configure_bindings.fish
@@ -0,0 +1,8 @@
+complete fzf_configure_bindings --no-files
+complete fzf_configure_bindings --long help --short h --description "Print help" --condition "not __fish_seen_argument --help -h"
+complete fzf_configure_bindings --long directory --description "Change the key binding for Search Directory" --condition "not __fish_seen_argument --directory"
+complete fzf_configure_bindings --long git_log --description "Change the key binding for Search Git Log" --condition "not __fish_seen_argument --git_log"
+complete fzf_configure_bindings --long git_status --description "Change the key binding for Search Git Status" --condition "not __fish_seen_argument --git_status"
+complete fzf_configure_bindings --long history --description "Change the key binding for Search History" --condition "not __fish_seen_argument --history"
+complete fzf_configure_bindings --long processes --description "Change the key binding for Search Processes" --condition "not __fish_seen_argument --processes"
+complete fzf_configure_bindings --long variables --description "Change the key binding for Search Variables" --condition "not __fish_seen_argument --variables"
diff --git a/.config/fish/completions/merge.fish b/.config/fish/completions/merge.fish
new file mode 100644
index 00000000..903ac39e
--- /dev/null
+++ b/.config/fish/completions/merge.fish
@@ -0,0 +1,20 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+# Merge command
+
+__gitnow_load_git_functions
+
+complete -f -x -c merge -a '(__fish_git_branches)'
+
+complete -f -x -c merge \
+ -s h -l help \
+ -d "Show information about the options for this command"
+
+complete -f -x -c merge \
+ -s a -l abort \
+ -d "Abort conflicted merge"
+
+complete -f -x -c merge \
+ -s c -l continue \
+ -d "Continue merge"
diff --git a/.config/fish/completions/move.fish b/.config/fish/completions/move.fish
new file mode 100644
index 00000000..88350ae9
--- /dev/null
+++ b/.config/fish/completions/move.fish
@@ -0,0 +1,26 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+# Move command
+
+__gitnow_load_git_functions
+
+complete -f -x -c move -a '(__fish_git_branches)'
+
+complete -f -x -c move \
+ -s h -l help \
+ -d "Show information about the options for this command"
+
+complete -f -x -c move \
+ -s p -l prev \
+ -d "Switch to a previous branch using the `--no-apply-stash` option (equivalent to \"move -\")"
+
+complete -f -x -c move \
+ -s n -l no-apply-stash \
+ -a '(__fish_git_branches)' \
+ -d "Switch to a local branch but without applying current stash"
+
+complete -f -x -c move \
+ -s u -l upstream \
+ -a '(__fish_git_branches)' \
+ -d "Fetch a remote branch and switch to it applying current stash"
diff --git a/.config/fish/completions/projectdo.fish b/.config/fish/completions/projectdo.fish
new file mode 100644
index 00000000..41413b38
--- /dev/null
+++ b/.config/fish/completions/projectdo.fish
@@ -0,0 +1,23 @@
+complete -c projectdo --no-files
+
+set -l commands build run test tool
+
+# Options
+complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
+ -s h -l help -d 'Display usage information'
+complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
+ -s d -l 'dry-run' -d 'Do not execute any commands with side-effects'
+complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
+ -s q -l quiet -d 'Do not print commands before execution'
+complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
+ -s v -l version -d 'Dsiplay the version'
+
+# Actions
+complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
+ -a build -d 'Build the current project'
+complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
+ -a run -d 'Run the current project'
+complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
+ -a test -d 'Test the current project'
+complete -c projectdo -n "not __fish_seen_subcommand_from $commands" \
+ -a tool -d 'Invoke the tool corresponding to the current project'
diff --git a/.config/fish/completions/replay.fish b/.config/fish/completions/replay.fish
new file mode 100644
index 00000000..34b64773
--- /dev/null
+++ b/.config/fish/completions/replay.fish
@@ -0,0 +1,2 @@
+complete --command replay --exclusive --long version --description "Print version"
+complete --command replay --exclusive --long help --description "Print help"
diff --git a/.config/fish/completions/spark.fish b/.config/fish/completions/spark.fish
new file mode 100644
index 00000000..d8daeedf
--- /dev/null
+++ b/.config/fish/completions/spark.fish
@@ -0,0 +1,4 @@
+complete --command spark --exclusive --long min --description "Minimum range"
+complete --command spark --exclusive --long max --description "Maximum range"
+complete --command spark --exclusive --long version --description "Print version"
+complete --command spark --exclusive --long help --description "Print this help message"
diff --git a/.config/fish/completions/tag.fish b/.config/fish/completions/tag.fish
new file mode 100644
index 00000000..7046d768
--- /dev/null
+++ b/.config/fish/completions/tag.fish
@@ -0,0 +1,31 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+# Tag command
+
+__gitnow_load_git_functions
+
+complete -f -x -c tag \
+ -d "List all tags in a lexicographic order and treating tag names as versions"
+
+complete -f -x -c tag -a '(__fish_git_tags)'
+
+complete -f -x -c tag \
+ -s h -l help \
+ -d "Show information about the options for this command"
+
+complete -f -x -c tag \
+ -s l -l latest \
+ -d "Show only the latest Semver release tag version (no suffixed ones or others)"
+
+complete -f -x -c tag \
+ -s x -l major \
+ -d "Tag auto-incrementing a major version number"
+
+complete -f -x -c tag \
+ -s y -l minor \
+ -d "Tag auto-incrementing a minor version number"
+
+complete -f -x -c tag \
+ -s z -l patch \
+ -d "Tag auto-incrementing a patch version number"
diff --git a/.config/fish/conf.d/.gitnow b/.config/fish/conf.d/.gitnow
new file mode 100644
index 00000000..748ca9d5
--- /dev/null
+++ b/.config/fish/conf.d/.gitnow
@@ -0,0 +1,40 @@
+[ options ]
+
+# Read text from system clipboard or from the standard input
+# only when using Gitflow keybindings
+clipboard = false
+
+[ keybindings ]
+
+# Alt + S
+state = \es
+
+# Alt + E
+stage = \ee
+
+# Ctrl + E
+unstage = \ce
+
+# Alt + M
+show = \em
+
+# Alt + C
+commit-all = \ec
+
+# Alt + D
+pull = \ed
+
+# Alt + P
+push = \ep
+
+# Alt + U
+upstream = \eu
+
+# Alt + L
+logs = \el
+
+# Alt + F
+feature = \ef
+
+# Alt + H
+hotfix = \eh
diff --git a/.config/fish/conf.d/__async_prompt.fish b/.config/fish/conf.d/__async_prompt.fish
new file mode 100644
index 00000000..adc5dc47
--- /dev/null
+++ b/.config/fish/conf.d/__async_prompt.fish
@@ -0,0 +1,201 @@
+status is-interactive
+or exit 0
+
+set -g __async_prompt_tmpdir (command mktemp -d)
+
+# Setup after the user defined prompt functions are loaded.
+function __async_prompt_setup_on_startup --on-event fish_prompt
+ functions -e (status current-function)
+ if test "$async_prompt_enable" = 0
+ return 0
+ end
+
+ for func in (__async_prompt_config_functions)
+ function $func -V func
+ test -e $__async_prompt_tmpdir'/'$fish_pid'_'$func
+ and cat $__async_prompt_tmpdir'/'$fish_pid'_'$func
+ end
+ end
+end
+
+function __async_prompt_keep_last_pipestatus
+ set -g __async_prompt_last_pipestatus $pipestatus
+end
+
+not set -q async_prompt_on_variable
+and set async_prompt_on_variable fish_bind_mode
+function __async_prompt_fire --on-event fish_prompt (for var in $async_prompt_on_variable; printf '%s\n' --on-variable $var; end)
+ for func in (__async_prompt_config_functions)
+ set -l tmpfile $__async_prompt_tmpdir'/'$fish_pid'_'$func
+
+ if functions -q $func'_loading_indicator' && test -e $tmpfile
+ read -zl last_prompt <$tmpfile
+ eval (string escape -- $func'_loading_indicator' "$last_prompt") >$tmpfile
+ end
+
+ __async_prompt_config_inherit_variables | __async_prompt_spawn \
+ $func' | read -z prompt
+ echo -n $prompt >'$tmpfile
+ end
+end
+
+function __async_prompt_spawn -a cmd
+ set -l envs
+ begin
+ while read line
+ switch "$line"
+ case fish_bind_mode
+ echo fish_bind_mode $fish_bind_mode
+ case FISH_VERSION PWD _ history 'fish_*' hostname version status_generation
+ case status pipestatus
+ echo pipestatus $__async_prompt_last_pipestatus
+ case SHLVL
+ set envs $envs SHLVL=$SHLVL
+ case '*'
+ echo $line (string escape -- $$line)
+ end
+ end
+ end | read -lz vars
+ echo $vars | env $envs fish -c '
+ function __async_prompt_signal
+ kill -s "'(__async_prompt_config_internal_signal)'" '$fish_pid' 2>/dev/null
+ end
+ while read -a line
+ test -z "$line"
+ and continue
+
+ if test "$line[1]" = pipestatus
+ set -f _pipestatus $line[2..]
+ else
+ eval set "$line"
+ end
+ end
+
+ function __async_prompt_set_status
+ return $argv
+ end
+ if set -q _pipestatus
+ switch (count $_pipestatus)
+ case 1
+ __async_prompt_set_status $_pipestatus[1]
+ case 2
+ __async_prompt_set_status $_pipestatus[1] \
+ | __async_prompt_set_status $_pipestatus[2]
+ case 3
+ __async_prompt_set_status $_pipestatus[1] \
+ | __async_prompt_set_status $_pipestatus[2] \
+ | __async_prompt_set_status $_pipestatus[3]
+ case 4
+ __async_prompt_set_status $_pipestatus[1] \
+ | __async_prompt_set_status $_pipestatus[2] \
+ | __async_prompt_set_status $_pipestatus[3] \
+ | __async_prompt_set_status $_pipestatus[4]
+ case 5
+ __async_prompt_set_status $_pipestatus[1] \
+ | __async_prompt_set_status $_pipestatus[2] \
+ | __async_prompt_set_status $_pipestatus[3] \
+ | __async_prompt_set_status $_pipestatus[4] \
+ | __async_prompt_set_status $_pipestatus[5]
+ case 6
+ __async_prompt_set_status $_pipestatus[1] \
+ | __async_prompt_set_status $_pipestatus[2] \
+ | __async_prompt_set_status $_pipestatus[3] \
+ | __async_prompt_set_status $_pipestatus[4] \
+ | __async_prompt_set_status $_pipestatus[5] \
+ | __async_prompt_set_status $_pipestatus[6]
+ case 7
+ __async_prompt_set_status $_pipestatus[1] \
+ | __async_prompt_set_status $_pipestatus[2] \
+ | __async_prompt_set_status $_pipestatus[3] \
+ | __async_prompt_set_status $_pipestatus[4] \
+ | __async_prompt_set_status $_pipestatus[5] \
+ | __async_prompt_set_status $_pipestatus[6] \
+ | __async_prompt_set_status $_pipestatus[7]
+ case 8
+ __async_prompt_set_status $_pipestatus[1] \
+ | __async_prompt_set_status $_pipestatus[2] \
+ | __async_prompt_set_status $_pipestatus[3] \
+ | __async_prompt_set_status $_pipestatus[4] \
+ | __async_prompt_set_status $_pipestatus[5] \
+ | __async_prompt_set_status $_pipestatus[6] \
+ | __async_prompt_set_status $_pipestatus[7] \
+ | __async_prompt_set_status $_pipestatus[8]
+ default
+ __async_prompt_set_status $_pipestatus[1] \
+ | __async_prompt_set_status $_pipestatus[2] \
+ | __async_prompt_set_status $_pipestatus[3] \
+ | __async_prompt_set_status $_pipestatus[4] \
+ | __async_prompt_set_status $_pipestatus[5] \
+ | __async_prompt_set_status $_pipestatus[6] \
+ | __async_prompt_set_status $_pipestatus[7] \
+ | __async_prompt_set_status $_pipestatus[8] \
+ | __async_prompt_set_status $_pipestatus[-1]
+ end
+ else
+ true
+ end
+ '$cmd'
+ __async_prompt_signal' &
+ if test (__async_prompt_config_disown) = 1
+ disown
+ end
+end
+
+function __async_prompt_config_inherit_variables
+ if set -q async_prompt_inherit_variables
+ if test "$async_prompt_inherit_variables" = all
+ set -ng
+ else
+ for item in $async_prompt_inherit_variables
+ echo $item
+ end
+ end
+ else
+ echo CMD_DURATION
+ echo fish_bind_mode
+ echo pipestatus
+ echo SHLVL
+ echo status
+ end
+end
+
+function __async_prompt_config_functions
+ set -l funcs (
+ if set -q async_prompt_functions
+ string join \n $async_prompt_functions
+ else
+ echo fish_prompt
+ echo fish_right_prompt
+ end
+ )
+ for func in $funcs
+ functions -q "$func"
+ or continue
+
+ echo $func
+ end
+end
+
+function __async_prompt_config_internal_signal
+ if test -z "$async_prompt_signal_number"
+ echo SIGUSR1
+ else
+ echo "$async_prompt_signal_number"
+ end
+end
+
+function __async_prompt_config_disown
+ if test -z "$async_prompt_disown"
+ echo 1
+ else
+ echo "$async_prompt_disown"
+ end
+end
+
+function __async_prompt_repaint_prompt --on-signal (__async_prompt_config_internal_signal)
+ commandline -f repaint >/dev/null 2>/dev/null
+end
+
+function __async_prompt_tmpdir_cleanup --on-event fish_exit
+ rm -rf "$__async_prompt_tmpdir"
+end
diff --git a/.config/fish/conf.d/autopair.fish b/.config/fish/conf.d/autopair.fish
new file mode 100644
index 00000000..abb4bf3e
--- /dev/null
+++ b/.config/fish/conf.d/autopair.fish
@@ -0,0 +1,39 @@
+status is-interactive || exit
+
+set --global autopair_left "(" "[" "{" '"' "'"
+set --global autopair_right ")" "]" "}" '"' "'"
+set --global autopair_pairs "()" "[]" "{}" '""' "''"
+
+function _autopair_fish_key_bindings --on-variable fish_key_bindings
+ set --query fish_key_bindings[1] || return
+
+ test $fish_key_bindings = fish_default_key_bindings &&
+ set --local mode default insert ||
+ set --local mode insert default
+
+ bind --mode $mode[-1] --erase \177 \b \t
+
+ bind --mode $mode[1] \177 _autopair_backspace # macOS โซ
+ bind --mode $mode[1] \b _autopair_backspace
+ bind --mode $mode[1] \t _autopair_tab
+
+ printf "%s\n" $autopair_pairs | while read --local left right --delimiter ""
+ bind --mode $mode[-1] --erase $left $right
+ if test $left = $right
+ bind --mode $mode[1] $left "_autopair_insert_same \\$left"
+ else
+ bind --mode $mode[1] $left "_autopair_insert_left \\$left \\$right"
+ bind --mode $mode[1] $right "_autopair_insert_right \\$right"
+ end
+ end
+end
+
+_autopair_fish_key_bindings
+
+function _autopair_uninstall --on-event autopair_uninstall
+ string collect (
+ bind --all | string replace --filter --regex -- "_autopair.*" --erase
+ set --names | string replace --filter --regex -- "^autopair" "set --erase autopair"
+ ) | source
+ functions --erase (functions --all | string match "_autopair_*")
+end
diff --git a/.config/fish/conf.d/done.fish b/.config/fish/conf.d/done.fish
new file mode 100644
index 00000000..3f9f0d3c
--- /dev/null
+++ b/.config/fish/conf.d/done.fish
@@ -0,0 +1,334 @@
+# MIT License
+
+# Copyright (c) 2016 Francisco Lourenรงo & Daniel Wehner
+
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+if not status is-interactive
+ exit
+end
+
+set -g __done_version 1.19.3
+
+function __done_run_powershell_script
+ set -l powershell_exe (command --search "powershell.exe")
+
+ if test $status -ne 0
+ and command --search wslvar
+
+ set -l powershell_exe (wslpath (wslvar windir)/System32/WindowsPowerShell/v1.0/powershell.exe)
+ end
+
+ if string length --quiet "$powershell_exe"
+ and test -x "$powershell_exe"
+
+ set cmd (string escape $argv)
+
+ eval "$powershell_exe -Command $cmd"
+ end
+end
+
+function __done_windows_notification -a title -a message
+ if test "$__done_notify_sound" -eq 1
+ set soundopt ""
+ else
+ set soundopt ""
+ end
+
+ __done_run_powershell_script "
+[Windows.Data.Xml.Dom.XmlDocument, Windows.Data.Xml.Dom.XmlDocument, ContentType = WindowsRuntime] | Out-Null
+[Windows.UI.Notifications.ToastNotification, Windows.UI.Notifications, ContentType = WindowsRuntime] | Out-Null
+
+\$toast_xml_source = @\"
+
+ $soundopt
+
+
+ $title
+ $message
+
+
+
+\"@
+
+\$toast_xml = New-Object Windows.Data.Xml.Dom.XmlDocument
+\$toast_xml.loadXml(\$toast_xml_source)
+
+\$toast = New-Object Windows.UI.Notifications.ToastNotification \$toast_xml
+
+[Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier(\"fish\").Show(\$toast)
+"
+end
+
+function __done_get_focused_window_id
+ if type -q lsappinfo
+ lsappinfo info -only bundleID (lsappinfo front | string replace 'ASN:0x0-' '0x') | cut -d '"' -f4
+ else if test -n "$SWAYSOCK"
+ and type -q jq
+ swaymsg --type get_tree | jq '.. | objects | select(.focused == true) | .id'
+ else if test -n "$HYPRLAND_INSTANCE_SIGNATURE"
+ hyprctl activewindow | awk 'NR==1 {print $2}'
+ else if begin
+ test "$XDG_SESSION_DESKTOP" = gnome; and type -q gdbus
+ end
+ gdbus call --session --dest org.gnome.Shell --object-path /org/gnome/Shell --method org.gnome.Shell.Eval 'global.display.focus_window.get_id()'
+ else if type -q xprop
+ and test -n "$DISPLAY"
+ # Test that the X server at $DISPLAY is running
+ and xprop -grammar >/dev/null 2>&1
+ xprop -root 32x '\t$0' _NET_ACTIVE_WINDOW | cut -f 2
+ else if uname -a | string match --quiet --ignore-case --regex microsoft
+ __done_run_powershell_script '
+Add-Type @"
+ using System;
+ using System.Runtime.InteropServices;
+ public class WindowsCompat {
+ [DllImport("user32.dll")]
+ public static extern IntPtr GetForegroundWindow();
+ }
+"@
+[WindowsCompat]::GetForegroundWindow()
+'
+ else if set -q __done_allow_nongraphical
+ echo 12345 # dummy value
+ end
+end
+
+function __done_is_tmux_window_active
+ set -q fish_pid; or set -l fish_pid %self
+
+ # find the outermost process within tmux
+ # ppid != "tmux" -> pid = ppid
+ # ppid == "tmux" -> break
+ set tmux_fish_pid $fish_pid
+ while set tmux_fish_ppid (ps -o ppid= -p $tmux_fish_pid | string trim)
+ # remove leading hyphen so that basename does not treat it as an argument (e.g. -fish), and return only
+ # the actual command and not its arguments so that basename finds the correct command name.
+ # (e.g. '/usr/bin/tmux' from command '/usr/bin/tmux new-session -c /some/start/dir')
+ and ! string match -q "tmux*" (basename (ps -o command= -p $tmux_fish_ppid | string replace -r '^-' '' | string split ' ')[1])
+ set tmux_fish_pid $tmux_fish_ppid
+ end
+
+ # tmux session attached and window is active -> no notification
+ # all other combinations -> send notification
+ tmux list-panes -a -F "#{session_attached} #{window_active} #{pane_pid}" | string match -q "1 1 $tmux_fish_pid"
+end
+
+function __done_is_screen_window_active
+ string match --quiet --regex "$STY\s+\(Attached" (screen -ls)
+end
+
+function __done_is_process_window_focused
+ # Return false if the window is not focused
+
+ if set -q __done_allow_nongraphical
+ return 1
+ end
+
+ if set -q __done_kitty_remote_control
+ kitty @ --password="$__done_kitty_remote_control_password" ls | jq -e ".[].tabs[] | select(any(.windows[]; .is_self)) | .is_focused" >/dev/null
+ return $status
+ end
+
+ set __done_focused_window_id (__done_get_focused_window_id)
+ if test "$__done_sway_ignore_visible" -eq 1
+ and test -n "$SWAYSOCK"
+ string match --quiet --regex "^true" (swaymsg -t get_tree | jq ".. | objects | select(.id == "$__done_initial_window_id") | .visible")
+ return $status
+ else if test -n "$HYPRLAND_INSTANCE_SIGNATURE"
+ and test $__done_initial_window_id = (hyprctl activewindow | awk 'NR==1 {print $2}')
+ return $status
+ else if test "$__done_initial_window_id" != "$__done_focused_window_id"
+ return 1
+ end
+ # If inside a tmux session, check if the tmux window is focused
+ if type -q tmux
+ and test -n "$TMUX"
+ __done_is_tmux_window_active
+ return $status
+ end
+
+ # If inside a screen session, check if the screen window is focused
+ if type -q screen
+ and test -n "$STY"
+ __done_is_screen_window_active
+ return $status
+ end
+
+ return 0
+end
+
+function __done_humanize_duration -a milliseconds
+ set -l seconds (math --scale=0 "$milliseconds/1000" % 60)
+ set -l minutes (math --scale=0 "$milliseconds/60000" % 60)
+ set -l hours (math --scale=0 "$milliseconds/3600000")
+
+ if test $hours -gt 0
+ printf '%s' $hours'h '
+ end
+ if test $minutes -gt 0
+ printf '%s' $minutes'm '
+ end
+ if test $seconds -gt 0
+ printf '%s' $seconds's'
+ end
+end
+
+# verify that the system has graphical capabilities before initializing
+if test -z "$SSH_CLIENT" # not over ssh
+ and count (__done_get_focused_window_id) >/dev/null # is able to get window id
+ set __done_enabled
+end
+
+if set -q __done_allow_nongraphical
+ and set -q __done_notification_command
+ set __done_enabled
+end
+
+if set -q __done_enabled
+ set -g __done_initial_window_id ''
+ set -q __done_min_cmd_duration; or set -g __done_min_cmd_duration 5000
+ set -q __done_exclude; or set -g __done_exclude '^git (?!push|pull|fetch)'
+ set -q __done_notify_sound; or set -g __done_notify_sound 0
+ set -q __done_sway_ignore_visible; or set -g __done_sway_ignore_visible 0
+ set -q __done_tmux_pane_format; or set -g __done_tmux_pane_format '[#{window_index}]'
+ set -q __done_notification_duration; or set -g __done_notification_duration 3000
+
+ function __done_started --on-event fish_preexec
+ set __done_initial_window_id (__done_get_focused_window_id)
+ end
+
+ function __done_ended --on-event fish_postexec
+ set -l exit_status $status
+
+ # backwards compatibility for fish < v3.0
+ set -q cmd_duration; or set -l cmd_duration $CMD_DURATION
+
+ if test $cmd_duration
+ and test $cmd_duration -gt $__done_min_cmd_duration # longer than notify_duration
+ and not __done_is_process_window_focused # process pane or window not focused
+
+ # don't notify if command matches exclude list
+ for pattern in $__done_exclude
+ if string match -qr $pattern $argv[1]
+ return
+ end
+ end
+
+ # Store duration of last command
+ set -l humanized_duration (__done_humanize_duration "$cmd_duration")
+
+ set -l title "Done in $humanized_duration"
+ set -l wd (string replace --regex "^$HOME" "~" (pwd))
+ set -l message "$wd/ $argv[1]"
+ set -l sender $__done_initial_window_id
+
+ if test $exit_status -ne 0
+ set title "Failed ($exit_status) after $humanized_duration"
+ end
+
+ if test -n "$TMUX_PANE"
+ set message (tmux lsw -F"$__done_tmux_pane_format" -f '#{==:#{pane_id},'$TMUX_PANE'}')" $message"
+ end
+
+ if set -q __done_notification_command
+ eval $__done_notification_command
+ if test "$__done_notify_sound" -eq 1
+ echo -e "\a" # bell sound
+ end
+ else if set -q KITTY_WINDOW_ID
+ printf "\x1b]99;i=done:d=0;$title\x1b\\"
+ printf "\x1b]99;i=done:d=1:p=body;$message\x1b\\"
+ else if type -q terminal-notifier # https://github.com/julienXX/terminal-notifier
+ if test "$__done_notify_sound" -eq 1
+ # pipe message into terminal-notifier to avoid escaping issues (https://github.com/julienXX/terminal-notifier/issues/134). fixes #140
+ echo "$message" | terminal-notifier -title "$title" -sender "$__done_initial_window_id" -sound default
+ else
+ echo "$message" | terminal-notifier -title "$title" -sender "$__done_initial_window_id"
+ end
+
+ else if type -q osascript # AppleScript
+ # escape double quotes that might exist in the message and break osascript. fixes #133
+ set -l message (string replace --all '"' '\"' "$message")
+ set -l title (string replace --all '"' '\"' "$title")
+
+ if test "$__done_notify_sound" -eq 1
+ osascript -e "display notification \"$message\" with title \"$title\" sound name \"Glass\""
+ else
+ osascript -e "display notification \"$message\" with title \"$title\""
+ end
+
+ else if type -q notify-send # Linux notify-send
+ # set urgency to normal
+ set -l urgency normal
+
+ # use user-defined urgency if set
+ if set -q __done_notification_urgency_level
+ set urgency "$__done_notification_urgency_level"
+ end
+ # override user-defined urgency level if non-zero exitstatus
+ if test $exit_status -ne 0
+ set urgency critical
+ if set -q __done_notification_urgency_level_failure
+ set urgency "$__done_notification_urgency_level_failure"
+ end
+ end
+
+ notify-send --hint=int:transient:1 --urgency=$urgency --icon=utilities-terminal --app-name=fish --expire-time=$__done_notification_duration "$title" "$message"
+
+ if test "$__done_notify_sound" -eq 1
+ echo -e "\a" # bell sound
+ end
+
+ else if type -q notify-desktop # Linux notify-desktop
+ set -l urgency
+ if test $exit_status -ne 0
+ set urgency "--urgency=critical"
+ end
+ notify-desktop $urgency --icon=utilities-terminal --app-name=fish "$title" "$message"
+ if test "$__done_notify_sound" -eq 1
+ echo -e "\a" # bell sound
+ end
+
+ else if uname -a | string match --quiet --ignore-case --regex microsoft
+ __done_windows_notification "$title" "$message"
+
+ else # anything else
+ echo -e "\a" # bell sound
+ end
+
+ end
+ end
+end
+
+function __done_uninstall -e done_uninstall
+ # Erase all __done_* functions
+ functions -e __done_ended
+ functions -e __done_started
+ functions -e __done_get_focused_window_id
+ functions -e __done_is_tmux_window_active
+ functions -e __done_is_screen_window_active
+ functions -e __done_is_process_window_focused
+ functions -e __done_windows_notification
+ functions -e __done_run_powershell_script
+ functions -e __done_humanize_duration
+
+ # Erase __done variables
+ set -e __done_version
+end
diff --git a/.config/fish/conf.d/fzf.fish b/.config/fish/conf.d/fzf.fish
new file mode 100644
index 00000000..8156c11b
--- /dev/null
+++ b/.config/fish/conf.d/fzf.fish
@@ -0,0 +1,28 @@
+# fzf.fish is only meant to be used in interactive mode. If not in interactive mode and not in CI, skip the config to speed up shell startup
+if not status is-interactive && test "$CI" != true
+ exit
+end
+
+# Because of scoping rules, to capture the shell variables exactly as they are, we must read
+# them before even executing _fzf_search_variables. We use psub to store the
+# variables' info in temporary files and pass in the filenames as arguments.
+# This variable is global so that it can be referenced by fzf_configure_bindings and in tests
+set --global _fzf_search_vars_command '_fzf_search_variables (set --show | psub) (set --names | psub)'
+
+
+# Install the default bindings, which are mnemonic and minimally conflict with fish's preset bindings
+fzf_configure_bindings
+
+# Doesn't erase autoloaded _fzf_* functions because they are not easily accessible once key bindings are erased
+function _fzf_uninstall --on-event fzf_uninstall
+ _fzf_uninstall_bindings
+
+ set --erase _fzf_search_vars_command
+ functions --erase _fzf_uninstall _fzf_migration_message _fzf_uninstall_bindings fzf_configure_bindings
+ complete --erase fzf_configure_bindings
+
+ set_color cyan
+ echo "fzf.fish uninstalled."
+ echo "You may need to manually remove fzf_configure_bindings from your config.fish if you were using custom key bindings."
+ set_color normal
+end
diff --git a/.config/fish/conf.d/gitnow.fish b/.config/fish/conf.d/gitnow.fish
new file mode 100644
index 00000000..34690f8e
--- /dev/null
+++ b/.config/fish/conf.d/gitnow.fish
@@ -0,0 +1,713 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+set -g gitnow_version 2.12.0
+
+# Default global variables
+set -q GITNOW_CONFIG_FILE; or set -g GITNOW_CONFIG_FILE ~/.gitnow
+set -g gitnow_commands 'all' 'assume' 'bitbucket' 'bugfix' 'commit' 'commit-all' 'feature' 'github' 'gitnow' 'hotfix' 'logs' 'merge' 'move' 'pull' 'push' 'release' 'show' 'stage' 'state' 'tag' 'unstage' 'untracked' 'upstream'
+
+if set -q __fish_config_dir
+ set -g fish_config "$__fish_config_dir"
+else
+ set -q XDG_CONFIG_HOME
+ and set -g fish_config "$XDG_CONFIG_HOME/fish"
+ or set -g fish_config "~/.config/fish"
+end
+
+set -q fish_snippets; or set -g fish_snippets "$fish_config/conf.d"
+
+__gitnow_load_config
+
+# Other specific global variables
+set -g g_current_branch
+
+function __gitnow_install -e gitnow_install
+ echo (gitnow -v)" is installed and ready to use!"
+ echo "Just run the `gitnow` command if you want explore the API."
+end
+
+function __gitnow_uninstall -e gitnow_uninstall
+ echo "GitNow was uninstalled successfully."
+end
+
+function gitnow -d "Gitnow: Speed up your Git workflow. ๐ " -a xversion
+ if [ "$xversion" = "-v" ]; or [ "$xversion" = "--version" ]
+ echo "GitNow version $gitnow_version"
+ else
+ __gitnow_manual | command less -r
+ end
+end
+
+function state -d "Gitnow: Show the working tree status in compact way"
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "state"
+ return
+ end
+
+ command git status -sb
+end
+
+function stage -d "Gitnow: Stage files in current working directory" -w 'git add'
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "stage"
+ return
+ end
+
+ set -l len (count $argv)
+ set -l opts .
+
+ if test $len -gt 0
+ set opts $argv
+ end
+
+ command git add $opts
+end
+
+function unstage -d "Gitnow: Unstage files in current working directory" -w 'git reset'
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "unstage"
+ return
+ end
+
+ set -l len (count $argv)
+ set -l opts .
+
+ if test $len -gt 0
+ set opts $argv
+ end
+
+ command git reset $opts
+end
+
+function show -d "Gitnow: Show commit detail objects" -w 'git show'
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "show"
+ return
+ end
+
+ set -l len (count $argv)
+
+ if test $len -gt 0
+ command git show $argv
+ else
+ command git show --compact-summary --patch HEAD
+ end
+end
+
+function untracked -d "Gitnow: Check for untracked files and directories on current working directory"
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "untracked"
+ return
+ end
+
+ command git clean --dry-run -d
+
+end
+
+function commit -d "Gitnow: Commit changes to the repository" -w 'git commit'
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "commit"
+ return
+ end
+
+ set -l len (count $argv)
+
+ if test $len -gt 0
+ command git commit $argv
+ else
+ command git commit
+ end
+end
+
+function commit-all -d "Gitnow: Add and commit all changes to the repository"
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "commit-all"
+ return
+ end
+
+ stage
+ commit .
+end
+
+function pull -d "Gitnow: Pull changes from remote server but stashing uncommitted changes" -w 'git pull'
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "pull"
+ return
+ end
+
+ set -l len (count $argv)
+ set -l xorigin (__gitnow_current_remote)
+ set -l xbranch (__gitnow_current_branch_name)
+ set -l xcmd ""
+
+ echo "โก๏ธ Pulling changes..."
+
+ set -l xdefaults --rebase --autostash --tags
+
+ if test $len -gt 2
+ set xcmd $argv
+
+ echo "Mode: Manual"
+ echo "Default flags: $xdefaults"
+ echo
+ else
+ echo "Mode: Auto"
+ echo "Default flags: $xdefaults"
+
+ if test $len -eq 1
+ set xbranch $argv[1]
+ end
+
+ if test $len -eq 2
+ set xorigin $argv[1]
+ set xbranch $argv[2]
+ end
+
+ set xcmd $xorigin $xbranch
+ set -l xremote_url (command git config --get "remote.$xorigin.url")
+
+ echo "Remote URL: $xorigin ($xremote_url)"
+ echo "Remote branch: $xbranch"
+ echo
+ end
+
+ command git pull $xcmd $xdefaults
+end
+
+# Git push with --set-upstream
+# Shortcut inspired from https://github.com/jamiew/git-friendly
+function push -d "Gitnow: Push commit changes to remote repository" -w 'git push'
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "push"
+ return
+ end
+
+ set -l opts $argv
+ set -l xorigin (__gitnow_current_remote)
+ set -l xbranch (__gitnow_current_branch_name)
+
+
+ if test (count $opts) -eq 0
+ set opts $xorigin $xbranch
+ set -l xremote_url (command git config --get "remote.$xorigin.url")
+
+ echo "๐ Pushing changes..."
+ echo "Mode: Auto"
+ echo "Remote URL: $xorigin ($xremote_url)"
+ echo "Remote branch: $xbranch"
+ else
+ set -l v_mode "auto"
+
+ for v in $argv
+ switch $v
+ case -t --tags
+ set opts $xorigin $xbranch --follow-tags
+ set -l xremote_url (command git config --get "remote.$xorigin.url")
+
+ echo "๐ Pushing changes..."
+ echo "Mode: Auto (incl. tags)"
+ echo "Remote URL: $xorigin ($xremote_url)"
+ echo "Remote branch: $xbranch"
+ case -h --help
+ echo "NAME"
+ echo " Gitnow: push - Push current branch to default origin"
+ echo "OPTIONS:"
+ echo " -t --tags (auto mode) include annotated tags that relate to the commits"
+ echo " -h --help Show information about the options for this command"
+ return
+ case -\*
+ case '*'
+ set -l v_mode "manual"
+ echo "Mode: Manual"
+ end
+ end
+ end
+
+ echo
+
+ command git push --set-upstream $opts
+end
+
+function upstream -d "Gitnow: Commit all changes and push them to remote server"
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "upstream"
+ return
+ end
+
+ commit-all
+ push
+end
+
+function feature -d "GitNow: Creates a new Gitflow feature branch from current branch" -a xbranch
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "feature"
+ return
+ end
+
+ __gitnow_gitflow_branch "feature" $xbranch
+end
+
+function hotfix -d "GitNow: Creates a new Gitflow hotfix branch from current branch" -a xbranch
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "hotfix"
+ return
+ end
+
+ __gitnow_gitflow_branch "hotfix" $xbranch
+end
+
+function bugfix -d "GitNow: Creates a new Gitflow bugfix branch from current branch" -a xbranch
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "bugfix"
+ return
+ end
+
+ __gitnow_gitflow_branch "bugfix" $xbranch
+end
+
+function release -d "GitNow: Creates a new Gitflow release branch from current branch" -a xbranch
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "release"
+ return
+ end
+
+ __gitnow_gitflow_branch "release" $xbranch
+end
+
+function merge -d "GitNow: Merges given branch into the active one"
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "merge"
+ return
+ end
+
+ set -l len (count $argv)
+ if test $len -eq 0
+ echo "Merge: No argument given, needs one parameter"
+ return
+ end
+
+ set -l v_abort
+ set -l v_continue
+ set -l v_branch
+
+ for v in $argv
+ switch $v
+ case -a --abort
+ set v_abort $v
+ case -c --continue
+ set v_continue $v
+ case -h --help
+ echo "NAME"
+ echo " Gitnow: merge - Merge given branch into the active one"
+ echo "EXAMPLES"
+ echo " merge "
+ echo "OPTIONS:"
+ echo " -a --abort Abort a conflicted merge"
+ echo " -c --continue Continue a conflicted merge"
+ echo " -h --help Show information about the options for this command"
+ return
+ case -\*
+ case '*'
+ set v_branch $v
+ end
+ end
+
+ # abort
+ if test "$v_abort";
+ echo "Abort the current merge"
+ command git merge --abort
+ return
+ end
+
+ # continue
+ if test "$v_continue";
+ echo "Continue the current merge"
+ command git merge --continue
+ return
+ end
+
+ # No branch defined
+ if not test -n "$v_branch"
+ echo "Provide a valid branch name to merge."
+ return
+ end
+
+ set -l v_found (__gitnow_check_if_branch_exist $v_branch)
+
+ # Branch was not found
+ if test $v_found -eq 0;
+ echo "Local branch `$v_branch` was not found. Not possible to merge."
+
+ return
+ end
+
+ # Detect merging current branch
+ if [ "$v_branch" = (__gitnow_current_branch_name) ]
+ echo "Branch `$v_branch` is the same as current branch. Nothing to do."
+ return
+ end
+
+ command git merge $v_branch
+end
+
+function move -d "GitNow: Switch from current branch to another but stashing uncommitted changes" -a args
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "move"
+ return
+ end
+
+ set -l v_upstream
+ set -l v_no_apply_stash
+ set -l v_branch
+ set -l v_prev
+
+ for v in $argv
+ switch $v
+ case -u --upstream
+ set v_upstream $v
+ case -n --no-apply-stash
+ set v_no_apply_stash $v
+ case -nu -un
+ set v_upstream "-u"
+ set v_no_apply_stash "-n"
+ case -p --prev
+ set v_prev "true"
+ case -h --help
+ echo "NAME"
+ echo " Gitnow: move - Switch from current branch to another but stashing uncommitted changes"
+ echo "EXAMPLES"
+ echo " move "
+ echo " move -"
+ echo "OPTIONS:"
+ echo " -n --no-apply-stash Switch to a local branch but without applying current stash"
+ echo " -u --upstream Fetch a remote branch and switch to it applying current stash. It can be combined with --no-apply-stash"
+ echo " -p --prev Switch to a previous branch if different than the current one (equivalent to \"move -\"). It uses `--no-apply-stash` option by default."
+ echo " -h --help Show information about the options for this command"
+ return
+ case -\*
+ case '*'
+ set v_branch $v
+ end
+ end
+
+ # Move to prev branch either via the --prev option or the "-" shorthand char
+ if begin test -n "$v_prev"; or [ "$args" = "-" ]; end
+ if begin test -z "$g_current_branch"; or [ "$g_current_branch" = (__gitnow_current_branch_name) ]; end
+ echo "Previous branch not found or the same as current one. Nothing to do."
+ echo "Tip: Previous branch switching only works via the `move` command."
+ return
+ end
+
+ echo "Previous branch found, switching to `$g_current_branch` (using `--no-apply-stash` option)."
+ move -n $g_current_branch
+ return
+ end
+
+ # No branch defined
+ if not test -n "$v_branch"
+ echo "Provide a valid branch name to switch to."
+ return
+ end
+
+ set -l v_fetched 0
+
+ # Fetch branch from remote
+ if test -n "$v_upstream"
+ set -l v_remote (__gitnow_current_remote)
+ command git fetch $v_remote $v_branch:refs/remotes/$v_remote/$v_branch
+ command git checkout --track $v_remote/$v_branch
+ return
+ end
+
+ set -l v_found (__gitnow_check_if_branch_exist $v_branch)
+
+ # Branch was not found
+ if begin test $v_found -eq 0; and test $v_fetched -eq 0; end
+ echo "Branch `$v_branch` was not found locally. No possible to switch."
+ echo "Tip: Use -u (--upstream) flag to fetch a remote branch."
+ return
+ end
+
+ # Prevent same branch switching
+ if [ "$v_branch" = (__gitnow_current_branch_name) ]
+ echo "Branch `$v_branch` is the same as current branch. Nothing to do."
+ return
+ end
+
+ set -l v_uncommited (__gitnow_has_uncommited_changes)
+
+ # Stash changes before checkout for uncommited changes only
+ if test $v_uncommited
+ command git stash
+ end
+
+ set g_current_branch (__gitnow_current_branch_name)
+ command git checkout $v_branch
+
+ # --no-apply-stash
+ if test -n "$v_no_apply_stash"
+ echo "Changes were stashed but not applied by default. Use `git stash pop` to apply them."
+ end
+
+ if begin test $v_uncommited; and not test -n "$v_no_apply_stash"; end
+ command git stash pop
+ echo "Stashed changes were applied."
+ end
+end
+
+function logs -d "Gitnow: Shows logs in a fancy way"
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "logs"
+ return
+ end
+
+ set -l v_max_commits "80"
+ set -l v_args
+
+ for v in $argv
+ switch $v
+ case -h --help
+ echo "NAME"
+ echo " Gitnow: logs - Show logs in a fancy way (first $v_max_commits commits by default)"
+ echo "EXAMPLES"
+ echo " logs [git log options]"
+ echo "EXTRA OPTIONS:"
+ echo " -h, --help Show information about the options for this command"
+ return
+ case -\*
+ case '*'
+ set v_args $argv
+ break
+ end
+ end
+
+ if test -n "$v_args"
+ set v_max_commits
+ else
+ set v_max_commits "-$v_max_commits"
+ end
+
+ LC_ALL=C command git log $v_max_commits $v_args --color --graph \
+ --pretty=format:"%C(red)%h%C(reset)%C(yellow)%d%Creset %s %C(green italic)(%cr)%C(reset) %C(blue)%an%C(reset) %C(white dim)%GK %C(reset)" --abbrev-commit \
+ | command less -R
+end
+
+function tag -d "Gitnow: Tag commits following Semver"
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "tag"
+ return
+ end
+
+ set -l v_major
+ set -l v_minor
+ set -l v_patch
+ set -l v_premajor
+ set -l v_preminor
+ set -l v_prepatch
+
+ set -l opts
+
+ # NOTE: this function only gets the latest *Semver release version* but no suffixed ones or others
+ set -l v_latest (__gitnow_get_latest_semver_release_tag)
+
+ for v in $argv
+ switch $v
+ case -x --major
+ set v_major $v
+ case -y --minor
+ set v_minor $v
+ case -z --patch
+ set v_patch $v
+ case -a --annotate
+ set opts $opts $v
+
+ # TODO: pre-release versions are not supported yet
+ # case -a --premajor
+ # set v_premajor $v
+ # case -b --preminor
+ # set v_preminor $v
+ # case -c --prepatch
+ # set v_prepatch $v
+
+ case -l --latest
+ if not test -n "$v_latest"
+ echo "There is no any tag created yet."
+ else
+ echo $v_latest
+ end
+
+ return
+ case -h --help
+ echo "NAME"
+ echo " Gitnow: tag - List or tag commits following The Semantic Versioning 2.0.0 (Semver) [1]"
+ echo " [1] https://semver.org/"
+ echo "EXAMPLES"
+ echo " List tags: tag"
+ echo " Custom tag: tag "
+ echo " Semver tag: tag --major"
+ echo "OPTIONS:"
+ echo " Without options all tags are listed in a lexicographic order and tag names are treated as versions"
+ echo " -x --major Tag auto-incrementing a major version number"
+ echo " -y --minor Tag auto-incrementing a minor version number"
+ echo " -z --patch Tag auto-incrementing a patch version number"
+ echo " -l --latest Show only the latest Semver release tag version (no suffixed ones or others)"
+ echo " -a --annotate Create as annotated tag"
+ echo " -h --help Show information about the options for this command"
+
+ # TODO: pre-release versions are not supported yet
+ # echo " -a --premajor Tag auto-incrementing a premajor version number"
+ # echo " -b --preminor Tag auto-incrementing a preminor version number"
+ # echo " -c --prepatch Tag auto-incrementing a prepatch version number"
+
+ return
+ case -\*
+ case '*'
+ return
+ end
+ end
+
+ # List all tags in a lexicographic order and treating tag names as versions
+ if test -z "$argv"
+ __gitnow_get_tags_ordered
+ return
+ end
+
+ # Major version tags
+ if test -n "$v_major"
+ if not test -n "$v_latest"
+ command git tag $opts v1.0.0
+ echo "First major tag \"v1.0.0\" was created."
+ return
+ else
+ set -l vstr (__gitnow_get_valid_semver_release_value $v_latest)
+
+ # Validate Semver format before to proceed
+ if not test -n "$vstr"
+ echo "The latest tag \"$v_latest\" has no a valid Semver format."
+ return
+ end
+
+ set -l x (echo $vstr | LC_ALL=C command awk -F '.' '{print $1}')
+ set -l prefix (echo $v_latest | LC_ALL=C command awk -F "$vstr" '{print $1}')
+ set x (__gitnow_increment_number $x)
+ set -l xyz "$prefix$x.0.0"
+
+ command git tag $opts $xyz
+ echo "Major tag \"$xyz\" was created."
+ return
+ end
+ end
+
+ # Minor version tags
+ if test -n "$v_minor"
+ if not test -n "$v_latest"
+ command git tag $opts v0.1.0
+ echo "First minor tag \"v0.1.0\" was created."
+ return
+ else
+ set -l vstr (__gitnow_get_valid_semver_release_value $v_latest)
+
+ # Validate Semver format before to proceed
+ if not test -n "$vstr"
+ echo "The latest tag \"$v_latest\" has no a valid Semver format."
+ return
+ end
+
+ set -l x (echo $vstr | LC_ALL=C command awk -F '.' '{print $1}')
+ set -l y (echo $vstr | LC_ALL=C command awk -F '.' '{print $2}')
+ set -l prefix (echo $v_latest | LC_ALL=C command awk -F "$vstr" '{print $1}')
+ set y (__gitnow_increment_number $y)
+ set -l xyz "$prefix$x.$y.0"
+
+ command git tag $opts $xyz
+ echo "Minor tag \"$xyz\" was created."
+ return
+ end
+ end
+
+
+ # Patch version tags
+ if test -n "$v_patch"
+ if not test -n "$v_latest"
+ command git tag $opts v0.0.1
+ echo "First patch tag \"v0.1.0\" was created."
+ return
+ else
+ set -l vstr (__gitnow_get_valid_semver_release_value $v_latest)
+
+ # Validate Semver format before to proceed
+ if not test -n "$vstr"
+ echo "The latest tag \"$v_latest\" has no a valid Semver format."
+ return
+ end
+
+ set -l x (echo $vstr | LC_ALL=C command awk -F '.' '{print $1}')
+ set -l y (echo $vstr | LC_ALL=C command awk -F '.' '{print $2}')
+ set -l z (echo $vstr | LC_ALL=C command awk -F '.' '{print $3}')
+ set -l s (echo $z | LC_ALL=C command awk -F '-' '{print $1}')
+
+ if __gitnow_is_number $s
+ set -l prefix (echo $v_latest | LC_ALL=C command awk -F "$vstr" '{print $1}')
+ set s (__gitnow_increment_number $s)
+ set -l xyz "$prefix$x.$y.$s"
+
+ command git tag $opts $xyz
+ echo "Patch tag \"$xyz\" was created."
+ else
+ echo "No patch version found."
+ end
+
+ return
+ end
+ end
+
+ # TODO: pre-release versions are not supported yet
+ # TODO: Premajor version tags
+ # TODO: Preminor version tags
+ # TODO: Prepatch version tags
+end
+
+function assume -d "Gitnow: Ignore files temporarily"
+ if not __gitnow_is_git_repository
+ __gitnow_msg_not_valid_repository "assume"
+ return
+ end
+
+ set -l v_assume_unchanged "--assume-unchanged"
+ set -l v_files
+
+ for v in $argv
+ switch $v
+ case -n --no-assume
+ set v_assume_unchanged "--no-assume-unchanged"
+ case -h --help
+ echo "NAME"
+ echo " Gitnow: assume - Ignores changes in certain files temporarily"
+ echo "OPTIONS:"
+ echo " -n --no-assume No assume unchanged files to be ignored (revert option)"
+ echo " -h --help Show information about the options for this command"
+ return
+ case -\*
+ case '*'
+ set v_files $v_files $v
+ end
+ end
+
+ if test (count $v_files) -lt 1
+ echo "Provide files in order to ignore them temporarily. E.g `assume Cargo.lock`"
+ return
+ end
+
+ command git update-index $v_assume_unchanged $v_files
+end
+
+function github -d "Gitnow: Clone a GitHub repository using SSH"
+ set -l repo (__gitnow_clone_params $argv)
+ __gitnow_clone_repo $repo "github"
+end
+
+function bitbucket -d "Gitnow: Clone a Bitbucket Cloud repository using SSH"
+ set -l repo (__gitnow_clone_params $argv)
+ __gitnow_clone_repo $repo "bitbucket"
+end
diff --git a/.config/fish/conf.d/puffer_fish_key_bindings.fish b/.config/fish/conf.d/puffer_fish_key_bindings.fish
new file mode 100644
index 00000000..58d4d3de
--- /dev/null
+++ b/.config/fish/conf.d/puffer_fish_key_bindings.fish
@@ -0,0 +1,25 @@
+status is-interactive || exit
+
+function _puffer_fish_key_bindings --on-variable fish_key_bindings
+ set -l modes
+ if test "$fish_key_bindings" = fish_default_key_bindings
+ set modes default insert
+ else
+ set modes insert default
+ end
+
+ bind --mode $modes[1] . _puffer_fish_expand_dots
+ bind --mode $modes[1] ! _puffer_fish_expand_bang
+ bind --mode $modes[1] '$' _puffer_fish_expand_lastarg
+ bind --mode $modes[2] --erase . ! '$'
+end
+
+_puffer_fish_key_bindings
+
+set -l uninstall_event puffer_fish_key_bindings_uninstall
+
+function _$uninstall_event --on-event $uninstall_event
+ bind -e .
+ bind -e !
+ bind -e '$'
+end
diff --git a/.config/fish/conf.d/sponge.fish b/.config/fish/conf.d/sponge.fish
new file mode 100644
index 00000000..e37fe384
--- /dev/null
+++ b/.config/fish/conf.d/sponge.fish
@@ -0,0 +1,52 @@
+# Sponge version
+set --global sponge_version 1.1.0
+
+# Allow to repeat previous command by default
+if not set --query --universal sponge_delay
+ set --universal sponge_delay 2
+end
+
+# Purge entries both after `sponge_delay` entries and on exit by default
+if not set --query --universal sponge_purge_only_on_exit
+ set --universal sponge_purge_only_on_exit false
+end
+
+# Add default filters
+if not set --query --universal sponge_filters
+ set --universal sponge_filters sponge_filter_failed sponge_filter_matched
+end
+
+# Don't filter out commands that already have been in the history by default
+if not set --query --universal sponge_allow_previously_successful
+ set --universal sponge_allow_previously_successful true
+end
+
+# Consider `0` the only successful exit code by default
+if not set --query --universal sponge_successful_exit_codes
+ set --universal sponge_successful_exit_codes 0
+end
+
+# No active regex patterns by default
+if not set --query --universal sponge_regex_patterns
+ set --universal sponge_regex_patterns
+end
+
+# Attach event handlers
+functions --query \
+ _sponge_on_prompt \
+ _sponge_on_preexec \
+ _sponge_on_postexec \
+ _sponge_on_exit
+
+# Initialize empty state for the first run
+function _sponge_install --on-event sponge_install
+ set --global _sponge_current_command ''
+ set --global _sponge_current_command_exit_code 0
+ set --global _sponge_current_command_previously_in_history false
+end
+
+# Clean up variables
+function _sponge_uninstall --on-event sponge_uninstall
+ _sponge_clear_state
+ set --erase sponge_version
+end
diff --git a/.config/fish/conf.d/virtualfish-loader.fish b/.config/fish/conf.d/virtualfish-loader.fish
new file mode 100644
index 00000000..ceca3ad1
--- /dev/null
+++ b/.config/fish/conf.d/virtualfish-loader.fish
@@ -0,0 +1,4 @@
+set -g VIRTUALFISH_VERSION 2.5.9
+set -g VIRTUALFISH_PYTHON_EXEC /home/fic/.local/share/uv/tools/virtualfish/bin/python
+source /home/fic/.local/share/uv/tools/virtualfish/lib/python3.11/site-packages/virtualfish/virtual.fish
+emit virtualfish_did_setup_plugins
\ No newline at end of file
diff --git a/.config/fish/fish_plugins b/.config/fish/fish_plugins
index 594dfc03..332b1a83 100644
--- a/.config/fish/fish_plugins
+++ b/.config/fish/fish_plugins
@@ -1 +1,11 @@
jorgebucaran/fisher
+patrickf1/fzf.fish
+franciscolourenco/done
+jorgebucaran/replay.fish
+jorgebucaran/spark.fish
+joseluisq/gitnow@2.12.0
+meaningful-ooo/sponge
+jorgebucaran/autopair.fish
+nickeb96/puffer-fish
+paldepind/projectdo
+acomagu/fish-async-prompt
diff --git a/.config/fish/fish_variables b/.config/fish/fish_variables
index 6be157cc..53bd6276 100644
--- a/.config/fish/fish_variables
+++ b/.config/fish/fish_variables
@@ -4,8 +4,18 @@ SETUVAR EDITOR:hx
SETUVAR --export TERM:xterm\x2d256color
SETUVAR Z_DATA_DIR:/home/fic/\x2elocal/share/z
SETUVAR __fish_initialized:3800
+SETUVAR _fisher_acomagu_2F_fish_2D_async_2D_prompt_files:\x7e/\x2econfig/fish/conf\x2ed/__async_prompt\x2efish
+SETUVAR _fisher_franciscolourenco_2F_done_files:\x7e/\x2econfig/fish/conf\x2ed/done\x2efish
+SETUVAR _fisher_jorgebucaran_2F_autopair_2E_fish_files:\x7e/\x2econfig/fish/functions/_autopair_backspace\x2efish\x1e\x7e/\x2econfig/fish/functions/_autopair_insert_left\x2efish\x1e\x7e/\x2econfig/fish/functions/_autopair_insert_right\x2efish\x1e\x7e/\x2econfig/fish/functions/_autopair_insert_same\x2efish\x1e\x7e/\x2econfig/fish/functions/_autopair_tab\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/autopair\x2efish
SETUVAR _fisher_jorgebucaran_2F_fisher_files:\x7e/\x2econfig/fish/functions/fisher\x2efish\x1e\x7e/\x2econfig/fish/completions/fisher\x2efish
-SETUVAR _fisher_plugins:jorgebucaran/fisher
+SETUVAR _fisher_jorgebucaran_2F_replay_2E_fish_files:\x7e/\x2econfig/fish/functions/replay\x2efish\x1e\x7e/\x2econfig/fish/completions/replay\x2efish
+SETUVAR _fisher_jorgebucaran_2F_spark_2E_fish_files:\x7e/\x2econfig/fish/functions/spark\x2efish\x1e\x7e/\x2econfig/fish/completions/spark\x2efish
+SETUVAR _fisher_joseluisq_2F_gitnow_40_32_2E_31_32_2E_30__files:\x7e/\x2econfig/fish/functions/__gitnow_check_if_branch_exist\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_clone_msg\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_clone_params\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_clone_repo\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_current_branch_list\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_current_branch_name\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_current_remote\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_get_clip_program\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_get_latest_semver_release_tag\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_get_latest_tag\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_get_tags_ordered\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_get_valid_semver_prerelease_value\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_get_valid_semver_release_value\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_gitflow_branch\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_has_uncommited_changes\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_increment_number\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_is_git_repository\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_is_number\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_load_config\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_load_git_functions\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_manual\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_msg_not_valid_repository\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_new_branch_switch\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_slugify\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/gitnow\x2efish\x1e\x7e/\x2econfig/fish/completions/merge\x2efish\x1e\x7e/\x2econfig/fish/completions/move\x2efish\x1e\x7e/\x2econfig/fish/completions/tag\x2efish
+SETUVAR _fisher_meaningful_2D_ooo_2F_sponge_files:\x7e/\x2econfig/fish/functions/_sponge_clear_state\x2efish\x1e\x7e/\x2econfig/fish/functions/_sponge_on_exit\x2efish\x1e\x7e/\x2econfig/fish/functions/_sponge_on_postexec\x2efish\x1e\x7e/\x2econfig/fish/functions/_sponge_on_preexec\x2efish\x1e\x7e/\x2econfig/fish/functions/_sponge_on_prompt\x2efish\x1e\x7e/\x2econfig/fish/functions/_sponge_remove_from_history\x2efish\x1e\x7e/\x2econfig/fish/functions/sponge_filter_failed\x2efish\x1e\x7e/\x2econfig/fish/functions/sponge_filter_matched\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/sponge\x2efish
+SETUVAR _fisher_nickeb96_2F_puffer_2D_fish_files:\x7e/\x2econfig/fish/functions/_puffer_fish_expand_bang\x2efish\x1e\x7e/\x2econfig/fish/functions/_puffer_fish_expand_dots\x2efish\x1e\x7e/\x2econfig/fish/functions/_puffer_fish_expand_lastarg\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/puffer_fish_key_bindings\x2efish
+SETUVAR _fisher_paldepind_2F_projectdo_files:\x7e/\x2econfig/fish/functions/projectdo_build\x2efish\x1e\x7e/\x2econfig/fish/functions/projectdo_run\x2efish\x1e\x7e/\x2econfig/fish/functions/projectdo_test\x2efish\x1e\x7e/\x2econfig/fish/functions/projectdo_tool\x2efish\x1e\x7e/\x2econfig/fish/completions/projectdo\x2efish
+SETUVAR _fisher_patrickf1_2F_fzf_2E_fish_files:\x7e/\x2econfig/fish/functions/_fzf_configure_bindings_help\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_extract_var_info\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_preview_changed_file\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_preview_file\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_report_diff_type\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_report_file_type\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_directory\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_git_log\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_git_status\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_history\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_processes\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_search_variables\x2efish\x1e\x7e/\x2econfig/fish/functions/_fzf_wrapper\x2efish\x1e\x7e/\x2econfig/fish/functions/fzf_configure_bindings\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/fzf\x2efish\x1e\x7e/\x2econfig/fish/completions/fzf_configure_bindings\x2efish
+SETUVAR _fisher_plugins:jorgebucaran/fisher\x1epatrickf1/fzf\x2efish\x1efranciscolourenco/done\x1ejorgebucaran/replay\x2efish\x1ejorgebucaran/spark\x2efish\x1ejoseluisq/gitnow\x402\x2e12\x2e0\x1emeaningful\x2dooo/sponge\x1ejorgebucaran/autopair\x2efish\x1enickeb96/puffer\x2dfish\x1epaldepind/projectdo\x1eacomagu/fish\x2dasync\x2dprompt
SETUVAR _fisher_upgraded_to_4_4:\x1d
SETUVAR cac_ip:172\x2e30\x2e90\x2e10
SETUVAR fish_color_autosuggestion:89492A
@@ -51,4 +61,10 @@ SETUVAR fish_pager_color_selected_description:\x1d
SETUVAR fish_pager_color_selected_prefix:\x1d
SETUVAR fish_user_paths:/usr/local/bin
SETUVAR linode_ip:172\x2e105\x2e6\x2e137
+SETUVAR sponge_allow_previously_successful:true
+SETUVAR sponge_delay:2
+SETUVAR sponge_filters:sponge_filter_failed\x1esponge_filter_matched
+SETUVAR sponge_purge_only_on_exit:false
+SETUVAR sponge_regex_patterns:\x1d
+SETUVAR sponge_successful_exit_codes:0
SETUVAR wtw_ip:143\x2e198\x2e33\x2e56
diff --git a/.config/fish/functions/__gitnow_check_if_branch_exist.fish b/.config/fish/functions/__gitnow_check_if_branch_exist.fish
new file mode 100644
index 00000000..a398c57e
--- /dev/null
+++ b/.config/fish/functions/__gitnow_check_if_branch_exist.fish
@@ -0,0 +1,20 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_check_if_branch_exist
+ set -l xfound 0
+
+ if test (count $argv) -eq 1
+ set -l xbranch $argv[1]
+ set -l xbranch_list (__gitnow_current_branch_list)
+
+ for b in $xbranch_list
+ if [ "$xbranch" = "$b" ]
+ set xfound 1
+ break
+ end
+ end
+ end
+
+ echo $xfound
+end
diff --git a/.config/fish/functions/__gitnow_clone_msg.fish b/.config/fish/functions/__gitnow_clone_msg.fish
new file mode 100644
index 00000000..9e3eb78e
--- /dev/null
+++ b/.config/fish/functions/__gitnow_clone_msg.fish
@@ -0,0 +1,17 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_clone_msg
+ set -l msg $argv[1]
+
+ echo "Repository name is required!"
+ echo "Example: $msg your-repo-name"
+ echo "Usages:"
+ echo " a) $msg username/repo-name"
+ echo " b) $msg username repo-name"
+ echo " c) $msg repo-name"
+ echo " For this, it's necessary to set your $msg username (login)"
+ echo " to global config before like: "
+ echo " git config --global user.$msg \"your-username\""
+ echo
+end
diff --git a/.config/fish/functions/__gitnow_clone_params.fish b/.config/fish/functions/__gitnow_clone_params.fish
new file mode 100644
index 00000000..c308cfd6
--- /dev/null
+++ b/.config/fish/functions/__gitnow_clone_params.fish
@@ -0,0 +1,18 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_clone_params
+ set -l repo
+
+ if count $argv >/dev/null
+ if test (count $argv) -gt 1
+ set repo $argv[1]/$argv[2]
+ else if echo $argv | LC_ALL=C command grep -q -E '^([a-zA-Z0-9\_\-]+)\/([a-zA-Z0-9\_\-]+)$'
+ set repo $argv
+ else
+ set repo "%S/$argv"
+ end
+ end
+
+ echo $repo
+end
diff --git a/.config/fish/functions/__gitnow_clone_repo.fish b/.config/fish/functions/__gitnow_clone_repo.fish
new file mode 100644
index 00000000..5f5e4a09
--- /dev/null
+++ b/.config/fish/functions/__gitnow_clone_repo.fish
@@ -0,0 +1,41 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_clone_repo
+ set -l repo $argv[1]
+ set -l platform $argv[2]
+
+ if test -n "$repo"
+ set -l ok 1
+
+ if echo $repo | LC_ALL=C command grep -q -E '^[\%S].+'
+ set -l user (command git config --global user.$platform)
+
+ if test -n "$user"
+ set -l repor (echo $repo | LC_ALL=C command sed -e "s/^%S/$user/")
+ set repo $repor
+ else
+ set ok 0
+ end
+ end
+
+ if test $ok -eq 1
+ if [ "$platform" = "github" ]
+ set url github.com
+ end
+
+ if [ "$platform" = "bitbucket" ]
+ set url bitbucket.org
+ end
+
+ set -l repo_url git@$url:$repo.git
+
+ echo "๐ฆ Remote repository: $repo_url"
+ command git clone $repo_url
+ else
+ __gitnow_clone_msg $platform
+ end
+ else
+ __gitnow_clone_msg $platform
+ end
+end
diff --git a/.config/fish/functions/__gitnow_current_branch_list.fish b/.config/fish/functions/__gitnow_current_branch_list.fish
new file mode 100644
index 00000000..724861f6
--- /dev/null
+++ b/.config/fish/functions/__gitnow_current_branch_list.fish
@@ -0,0 +1,6 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_current_branch_list
+ command git branch --list --no-color | LC_ALL=C command sed -E "s/^(\*?[ \t]*)//g" 2>/dev/null
+end
diff --git a/.config/fish/functions/__gitnow_current_branch_name.fish b/.config/fish/functions/__gitnow_current_branch_name.fish
new file mode 100644
index 00000000..e242c3ac
--- /dev/null
+++ b/.config/fish/functions/__gitnow_current_branch_name.fish
@@ -0,0 +1,6 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_current_branch_name
+ command git symbolic-ref --short HEAD 2>/dev/null
+end
diff --git a/.config/fish/functions/__gitnow_current_remote.fish b/.config/fish/functions/__gitnow_current_remote.fish
new file mode 100644
index 00000000..7b99a737
--- /dev/null
+++ b/.config/fish/functions/__gitnow_current_remote.fish
@@ -0,0 +1,7 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_current_remote
+ set -l branch_name (__gitnow_current_branch_name)
+ command git config "branch.$branch_name.remote" 2>/dev/null; or echo origin
+end
diff --git a/.config/fish/functions/__gitnow_get_clip_program.fish b/.config/fish/functions/__gitnow_get_clip_program.fish
new file mode 100644
index 00000000..fc522136
--- /dev/null
+++ b/.config/fish/functions/__gitnow_get_clip_program.fish
@@ -0,0 +1,18 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_get_clip_program -d "Gets the current clip installed program"
+ set -l v_paste
+
+ if type -q xclip
+ set v_paste "xclip -selection clipboard -o"
+ else if type -q wl-clipboard
+ set v_paste "wl-paste"
+ else if type -q xsel
+ set v_paste "xsel --clipboard --output"
+ else if type -q pbpaste
+ set v_paste "pbpaste"
+ end
+
+ echo -n $v_paste
+end
diff --git a/.config/fish/functions/__gitnow_get_latest_semver_release_tag.fish b/.config/fish/functions/__gitnow_get_latest_semver_release_tag.fish
new file mode 100644
index 00000000..cf0875f7
--- /dev/null
+++ b/.config/fish/functions/__gitnow_get_latest_semver_release_tag.fish
@@ -0,0 +1,11 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_get_latest_semver_release_tag
+ for tg in (__gitnow_get_tags_ordered)
+ if echo $tg | LC_ALL=C command grep -qE '^v?([0-9]+).([0-9]+).([0-9]+)$'
+ echo $tg 2>/dev/null
+ break
+ end
+ end
+end
diff --git a/.config/fish/functions/__gitnow_get_latest_tag.fish b/.config/fish/functions/__gitnow_get_latest_tag.fish
new file mode 100644
index 00000000..76883371
--- /dev/null
+++ b/.config/fish/functions/__gitnow_get_latest_tag.fish
@@ -0,0 +1,6 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_get_latest_tag
+ command git tag --sort=-creatordate | head -n1 2>/dev/null
+end
diff --git a/.config/fish/functions/__gitnow_get_tags_ordered.fish b/.config/fish/functions/__gitnow_get_tags_ordered.fish
new file mode 100644
index 00000000..0d6a7565
--- /dev/null
+++ b/.config/fish/functions/__gitnow_get_tags_ordered.fish
@@ -0,0 +1,8 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+# lexicographic order and tag names treated as versions
+# https://stackoverflow.com/a/52680984/2510591
+function __gitnow_get_tags_ordered
+ command git -c 'versionsort.suffix=-' tag --list --sort=-version:refname
+end
diff --git a/.config/fish/functions/__gitnow_get_valid_semver_prerelease_value.fish b/.config/fish/functions/__gitnow_get_valid_semver_prerelease_value.fish
new file mode 100644
index 00000000..ab6efc57
--- /dev/null
+++ b/.config/fish/functions/__gitnow_get_valid_semver_prerelease_value.fish
@@ -0,0 +1,6 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_get_valid_semver_prerelease_value -a tagv
+ command echo $tagv | LC_ALL=C command sed -n 's/^v\\{0,1\\}\([0-9].[0-9].[0-9]-[a-zA-Z0-9\-_.]*\)\([}]*\)/\1/p' 2>/dev/null
+end
diff --git a/.config/fish/functions/__gitnow_get_valid_semver_release_value.fish b/.config/fish/functions/__gitnow_get_valid_semver_release_value.fish
new file mode 100644
index 00000000..88e3ac35
--- /dev/null
+++ b/.config/fish/functions/__gitnow_get_valid_semver_release_value.fish
@@ -0,0 +1,6 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_get_valid_semver_release_value -a tagv
+ command echo $tagv | LC_ALL=C command sed -n 's/^v\\{0,1\\}\([0-9].[0-9].[0-9]*\)\([}]*\)/\1/p' 2>/dev/null
+end
diff --git a/.config/fish/functions/__gitnow_gitflow_branch.fish b/.config/fish/functions/__gitnow_gitflow_branch.fish
new file mode 100644
index 00000000..cd808e7c
--- /dev/null
+++ b/.config/fish/functions/__gitnow_gitflow_branch.fish
@@ -0,0 +1,16 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_gitflow_branch -a xprefix -a xbranch
+ set xbranch (__gitnow_slugify $xbranch)
+ set -l xbranch_full "$xprefix/$xbranch"
+ set -l xfound (__gitnow_check_if_branch_exist $xbranch_full)
+
+ if test $xfound -eq 1
+ echo "Branch `$xbranch_full` already exists. Nothing to do."
+ else
+ command git stash
+ __gitnow_new_branch_switch "$xbranch_full"
+ command git stash pop
+ end
+end
diff --git a/.config/fish/functions/__gitnow_has_uncommited_changes.fish b/.config/fish/functions/__gitnow_has_uncommited_changes.fish
new file mode 100644
index 00000000..310ae3d8
--- /dev/null
+++ b/.config/fish/functions/__gitnow_has_uncommited_changes.fish
@@ -0,0 +1,6 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_has_uncommited_changes
+ command git diff-index --quiet HEAD -- || echo "1" 2>&1
+end
diff --git a/.config/fish/functions/__gitnow_increment_number.fish b/.config/fish/functions/__gitnow_increment_number.fish
new file mode 100644
index 00000000..015463df
--- /dev/null
+++ b/.config/fish/functions/__gitnow_increment_number.fish
@@ -0,0 +1,12 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_increment_number -a strv
+ command echo $strv | LC_ALL=C command awk '
+ function increment(val) {
+ if (val ~ /[0-9]+/) { return val + 1 }
+ return val
+ }
+ { print increment($0) }
+ ' 2>/dev/null
+end
diff --git a/.config/fish/functions/__gitnow_is_git_repository.fish b/.config/fish/functions/__gitnow_is_git_repository.fish
new file mode 100644
index 00000000..dae8c0ad
--- /dev/null
+++ b/.config/fish/functions/__gitnow_is_git_repository.fish
@@ -0,0 +1,6 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_is_git_repository
+ command git rev-parse --git-dir >/dev/null 2>&1
+end
diff --git a/.config/fish/functions/__gitnow_is_number.fish b/.config/fish/functions/__gitnow_is_number.fish
new file mode 100644
index 00000000..afde0584
--- /dev/null
+++ b/.config/fish/functions/__gitnow_is_number.fish
@@ -0,0 +1,6 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_is_number -a strv
+ command echo -n $strv | LC_ALL=C command grep -qE '^([0-9]+)$'
+end
diff --git a/.config/fish/functions/__gitnow_load_config.fish b/.config/fish/functions/__gitnow_load_config.fish
new file mode 100644
index 00000000..11a6e790
--- /dev/null
+++ b/.config/fish/functions/__gitnow_load_config.fish
@@ -0,0 +1,180 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_load_config -d "Reads the GitNow configuration file"
+ # Sets a clipboard program
+ set g_xpaste (__gitnow_get_clip_program)
+
+ # Config file path used by default
+ set -l config_file "$fish_snippets/.gitnow"
+
+ # Download the default `.gitnow` file.
+ # NOTE: this is only used as a workaround for Fisher.
+ # See https://github.com/jorgebucaran/fisher/pull/573
+ if not test -e $config_file
+ curl -sSo $config_file https://raw.githubusercontent.com/joseluisq/gitnow/master/conf.d/.gitnow
+ end
+
+ # Prefer custom config file if it exists
+ if test -e $GITNOW_CONFIG_FILE
+ set config_file $GITNOW_CONFIG_FILE
+ else if not test -e $config_file
+ # Otherwise checks if default `.gitnow` file exists,
+ # if doesn't exist then skip out file parsing
+ return
+ end
+
+ # Parse `.gitnow` file content
+
+ # 2 = keybindings
+ # 3 = options
+ set -l v_section 0
+
+ # Valid sections
+ set -l v_keybindings "keybindings"
+ set -l v_options "options"
+
+ # Options set
+ set -l v_clipboard 0
+
+ # Loop every line
+ while read -la l
+ set -l v_str ""
+ set -l v_comment 0
+ set -l v_command_sep 0
+ set -l v_command_key ""
+ set -l v_command_val ""
+
+ # Loop every char for current line
+ echo $l | while read -n 1 -la c;
+ switch $c
+ case '['
+ if test $v_comment -eq 1; continue; end
+
+ # if test $v_section -gt 0
+ # set v_section 0
+ # continue
+ # end
+
+ # Start section
+ if test $v_section -eq 0; set v_section 1; end
+ case ']'
+ if test $v_comment -eq 1; continue; end
+
+ # Check section name
+ if test $v_section -eq 1
+ # options
+ if [ "$v_str" = "$v_options" ]
+ set v_section 3
+ continue
+ end
+
+ # keybindings
+ if [ "$v_str" = "$v_keybindings" ]
+ set v_section 2
+ continue
+ end
+ end
+
+ set v_section 0
+ case ' '
+ case '\n'
+ case '\t'
+ case '\r'
+ continue
+ case '#'
+ if test $v_comment -eq 0; set v_comment 1; end
+ continue
+ case '*'
+ if test $v_comment -eq 1; continue; end
+
+ # If section has started then accumulate chars and continue
+ if test $v_section -eq 1
+ set v_str "$v_str$c"
+ continue
+ end
+
+ # A [ abcde ] section is found so proceed with chars handling
+ # NOTE: only alphabetic and hyphens chars are allowed
+ if test $v_section -eq 2; or test $v_section -eq 3
+ switch $c
+ case 'a' 'b' 'c' 'd' 'e' 'f' 'g' 'h' 'i' 'j' 'k' 'l' 'm' 'n' 'o' 'p' 'q' 'r' 's' 't' 'u' 'v' 'w' 'x' 'y' 'z' '-'
+ if test $v_command_sep -eq 0
+ set v_command_key "$v_command_key$c"
+ continue
+ end
+
+ if test $v_command_sep -eq 2
+ set v_command_val "$v_command_val$c"
+ continue
+ end
+ case \\
+ if test $v_command_sep -eq 1
+ set v_command_sep 2
+ end
+ continue
+ case '='
+ set v_command_sep 1
+ if test $v_section -eq 3
+ set v_command_sep 2
+ continue
+ end
+ case '*'
+ continue
+ end
+ end
+ end
+ end
+
+ # 1. Handle options set
+ if test $v_section -eq 3
+ switch $v_command_key
+ # Clipboard option
+ case 'clipboard'
+ if [ "$v_command_val" = "true" ]
+ set v_clipboard 1
+ end
+ # NOTE: handle future new options using a new case
+ case '*'
+ continue
+ end
+ # continue loop after current option processed
+ set v_section 0
+ continue
+ end
+
+ # 2. Handle keybindings set
+ if not [ "$v_command_key" = "" ]; and not [ "$v_command_val" = "" ]
+ set -l cmd
+
+ switch $v_command_key
+ case 'release' 'hotfix' 'feature' 'bugfix'
+ # Read text from clipboard if there is a valid clipboard program
+ # and if the "clipboard" option is "true"
+ if test -n $g_xpaste; and test $v_clipboard -eq 1
+ set cmd (echo -n "bind \\$v_command_val \"echo; if $v_command_key ($g_xpaste); commandline -f repaint; else ; end\"")
+ else
+ # Otherwise read text from standard input
+ set cmd (echo -n "bind \\$v_command_val \"echo; if $v_command_key (read); commandline -f repaint; else ; end\"")
+ end
+ case '*'
+ # Check command key against a list of valid commands
+ set -l v_valid 0
+ for v in $gitnow_commands
+ if [ "$v" = "$v_command_key" ]
+ set v_valid 1
+ break
+ end
+ end
+
+ # If command key is not valid then just skip out
+ if test $v_valid -eq 0; continue; end
+
+ set cmd (echo -n "bind \\$v_command_val \"echo; $v_command_key; commandline -f repaint;\"")
+ end
+
+ eval $cmd
+ end
+
+ end < $config_file
+end
diff --git a/.config/fish/functions/__gitnow_load_git_functions.fish b/.config/fish/functions/__gitnow_load_git_functions.fish
new file mode 100644
index 00000000..f7cbd2f0
--- /dev/null
+++ b/.config/fish/functions/__gitnow_load_git_functions.fish
@@ -0,0 +1,8 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_load_git_functions -d "Gitnow: Load fish git functions on demand"
+ if begin not type -q __fish_git_branches; or not type -q __fish_git_tags; end
+ source $__fish_data_dir/completions/git.fish
+ end
+end
diff --git a/.config/fish/functions/__gitnow_manual.fish b/.config/fish/functions/__gitnow_manual.fish
new file mode 100644
index 00000000..ec11d5c7
--- /dev/null
+++ b/.config/fish/functions/__gitnow_manual.fish
@@ -0,0 +1,115 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_manual -d "Gitnow: Manual page like"
+ echo (set_color --bold)"NAME"(set_color normal)
+ echo " GitNow โ Speed up your Git workflow. ๐ "
+ echo
+ echo (set_color --bold)"VERSION"(set_color normal)
+ echo " $gitnow_version"
+ echo
+ echo (set_color --bold)"DESCRIPTION"(set_color normal)
+ echo " GitNow contains a rich command set that provides high-level operations on the top of Git(1)."
+ echo " A Fish Shell(2) alternative inspired by git-friendly(3)."
+ echo
+ echo " (1) https://git-scm.com/"
+ echo " (2) https://fishshell.com/"
+ echo " (3) https://github.com/jamiew/git-friendly"
+ echo
+ echo (set_color --bold)"COMMANDS"(set_color normal)
+ echo " "(set_color --bold)"state"(set_color normal)
+ echo " Show the working tree status in a compact way."
+ echo
+ echo " "(set_color --bold)"stage"(set_color normal)
+ echo " Stage files in the current working directory."
+ echo
+ echo " "(set_color --bold)"unstage"(set_color normal)
+ echo " Unstage files in the current working directory."
+ echo
+ echo " "(set_color --bold)"show"(set_color normal)
+ echo " Show commit detail objects."
+ echo
+ echo " "(set_color --bold)"untracked"(set_color normal)
+ echo " Check for untracked files and directories that could be removed."
+ echo
+ echo " "(set_color --bold)"commit"(set_color normal)
+ echo " Commit changes to the current repository."
+ echo
+ echo " "(set_color --bold)"commit-all"(set_color normal)
+ echo " Add and commit all changes to the current repository."
+ echo
+ echo " "(set_color --bold)"pull"(set_color normal)
+ echo " Pull changes from remote server but auto-stashing uncommitted changes."
+ echo
+ echo " "(set_color --bold)"push"(set_color normal)
+ echo " Push commit changes to the current remote repository."
+ echo
+ echo " "(set_color --bold)"upstream"(set_color normal)
+ echo " Commit all changes and push them to the current remote server."
+ echo
+ echo " "(set_color --bold)"move"(set_color normal)
+ echo " Switch from current branch to another but stashing uncommitted changes."
+ echo
+ echo " "(set_color --bold)"merge"(set_color normal)
+ echo " Merge given branch into the active one"
+ echo
+ echo " "(set_color --bold)"tag"(set_color normal)
+ echo " List and create release tag versions following Semver 2.0."
+ echo
+ echo " "(set_color --bold)"assume"(set_color normal)
+ echo " Ignore changes in certain files temporarily."
+ echo
+ echo " "(set_color --bold)"feature"(set_color normal)
+ echo " Create a new Gitflow feature branch from the current branch."
+ echo
+ echo " "(set_color --bold)"hotfix"(set_color normal)
+ echo " Create a new Gitflow hotfix branch from the current branch."
+ echo
+ echo " "(set_color --bold)"bugfix"(set_color normal)
+ echo " Create a new Gitflow bugfix branch from the current branch."
+ echo
+ echo " "(set_color --bold)"release"(set_color normal)
+ echo " Create a new Gitflow release branch from the current branch."
+ echo
+ echo " "(set_color --bold)"logs"(set_color normal)
+ echo " Show logs in a fancy way."
+ echo
+ echo " "(set_color --bold)"github"(set_color normal)
+ echo " Clone a GitHub repository over SSH."
+ echo
+ echo " "(set_color --bold)"bitbucket"(set_color normal)
+ echo " Clone a Bitbucket Cloud repository over SSH."
+ echo
+ echo (set_color --bold)"KEYBINDINGS"(set_color normal)
+ echo " state Alt + S"
+ echo " stage Alt + E"
+ echo " unstage Ctrl + E"
+ echo " show Alt + M"
+ echo " commit-all Alt + C"
+ echo " pull Alt + D"
+ echo " push Alt + P"
+ echo " upstream Alt + U"
+ echo " feature(1) Alt + F"
+ echo " hotfix(1) Alt + H"
+ echo " logs Alt + L"
+ echo
+ echo " (1) This command key binding will creates a new branch taking as name some text of the clipboard."
+ echo
+ echo (set_color --bold)"CONFIGURATION"(set_color normal)
+ echo " For a custom configuration (for example keybindings) place a "(set_color --bold)"~/.gitnow"(set_color normal)" file (1) in your home directory."
+ echo
+ echo " (1) An example file it can be found on "(set_color --bold)https://github.com/joseluisq/gitnow/tree/master/.gitnow(set_color normal)
+ echo
+ echo (set_color --bold)"FURTHER DOCUMENTATION"(set_color normal)
+ echo " For more details and examples check out "(set_color --bold)https://github.com/joseluisq/gitnow/blob/master/README.md(set_color normal)
+ echo
+ echo (set_color --bold)"CONTRIBUTIONS"(set_color normal)
+ echo " Send bug reports or pull requests to "(set_color --bold)https://github.com/joseluisq/gitnow(set_color normal)
+ echo
+ echo (set_color --bold)"LICENSE"(set_color normal)
+ echo " GitNow licensed under the MIT License "(set_color --bold)https://github.com/joseluisq/gitnow/blob/master/LICENSE.md(set_color normal)
+ echo
+ echo (set_color --bold)"AUTHOR"(set_color normal)
+ echo " (c) 2016-present Jose Quintana "(set_color --bold)"https://github.com/joseluisq"(set_color normal)
+ echo
+end
diff --git a/.config/fish/functions/__gitnow_msg_not_valid_repository.fish b/.config/fish/functions/__gitnow_msg_not_valid_repository.fish
new file mode 100644
index 00000000..8eb755b4
--- /dev/null
+++ b/.config/fish/functions/__gitnow_msg_not_valid_repository.fish
@@ -0,0 +1,6 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_msg_not_valid_repository -a cmd
+ echo "Gitnow ($cmd): Current directory is not a valid Git repository."
+end
diff --git a/.config/fish/functions/__gitnow_new_branch_switch.fish b/.config/fish/functions/__gitnow_new_branch_switch.fish
new file mode 100644
index 00000000..09850b2d
--- /dev/null
+++ b/.config/fish/functions/__gitnow_new_branch_switch.fish
@@ -0,0 +1,14 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+function __gitnow_new_branch_switch
+ set -l branch_name $argv[1]
+
+ if test (count $argv) -eq 1
+ set branch_name $branch_name
+
+ command git checkout -b $branch_name
+ else
+ echo "Provide a branch name."
+ end
+end
diff --git a/.config/fish/functions/__gitnow_slugify.fish b/.config/fish/functions/__gitnow_slugify.fish
new file mode 100644
index 00000000..6ca6dbe0
--- /dev/null
+++ b/.config/fish/functions/__gitnow_slugify.fish
@@ -0,0 +1,7 @@
+# GitNow โ Speed up your Git workflow. ๐
+# https://github.com/joseluisq/gitnow
+
+# adapted from https://gist.github.com/oneohthree/f528c7ae1e701ad990e6
+function __gitnow_slugify
+ echo $argv | LC_ALL=C command iconv -t ascii//TRANSLIT | LC_ALL=C command sed -E 's/[^a-zA-Z0-9\-]+/_/g' | LC_ALL=C command sed -E 's/^(-|_)+|(-|_)+$//g'
+end
diff --git a/.config/fish/functions/_autopair_backspace.fish b/.config/fish/functions/_autopair_backspace.fish
new file mode 100644
index 00000000..a43fa79d
--- /dev/null
+++ b/.config/fish/functions/_autopair_backspace.fish
@@ -0,0 +1,9 @@
+function _autopair_backspace
+ set --local index (commandline --cursor)
+ set --local buffer (commandline)
+
+ test $index -ge 1 &&
+ contains -- (string sub --start=$index --length=2 -- "$buffer") $autopair_pairs &&
+ commandline --function delete-char
+ commandline --function backward-delete-char
+end
diff --git a/.config/fish/functions/_autopair_insert_left.fish b/.config/fish/functions/_autopair_insert_left.fish
new file mode 100644
index 00000000..f078e861
--- /dev/null
+++ b/.config/fish/functions/_autopair_insert_left.fish
@@ -0,0 +1,13 @@
+function _autopair_insert_left --argument-names left right
+ set --local buffer (commandline)
+ set --local before (commandline --cut-at-cursor)
+
+ commandline --insert -- $left
+
+ switch "$buffer"
+ case "$before"{," "\*,$autopair_right\*}
+ set --local index (commandline --cursor)
+ commandline --insert -- $right
+ commandline --cursor $index
+ end
+end
diff --git a/.config/fish/functions/_autopair_insert_right.fish b/.config/fish/functions/_autopair_insert_right.fish
new file mode 100644
index 00000000..a0bd61c6
--- /dev/null
+++ b/.config/fish/functions/_autopair_insert_right.fish
@@ -0,0 +1,11 @@
+function _autopair_insert_right --argument-names key
+ set --local buffer (commandline)
+ set --local before (commandline --cut-at-cursor)
+
+ switch "$buffer"
+ case "$before$key"\*
+ commandline --cursor (math (commandline --cursor) + 1)
+ case \*
+ commandline --insert -- $key
+ end
+end
diff --git a/.config/fish/functions/_autopair_insert_same.fish b/.config/fish/functions/_autopair_insert_same.fish
new file mode 100644
index 00000000..27f971de
--- /dev/null
+++ b/.config/fish/functions/_autopair_insert_same.fish
@@ -0,0 +1,20 @@
+function _autopair_insert_same --argument-names key
+ set --local buffer (commandline)
+ set --local index (commandline --cursor)
+ set --local next (string sub --start=(math $index + 1) --length=1 -- "$buffer")
+
+ if test (math (count (string match --all --regex -- "$key" "$buffer")) % 2) = 0
+ test $key = $next && commandline --cursor (math $index + 1) && return
+
+ commandline --insert -- $key
+
+ if test $index -lt 1 ||
+ contains -- (string sub --start=$index --length=1 -- "$buffer") "" " " $autopair_left &&
+ contains -- $next "" " " $autopair_right
+ commandline --insert -- $key
+ commandline --cursor (math $index + 1)
+ end
+ else
+ commandline --insert -- $key
+ end
+end
diff --git a/.config/fish/functions/_autopair_tab.fish b/.config/fish/functions/_autopair_tab.fish
new file mode 100644
index 00000000..f2ab8eba
--- /dev/null
+++ b/.config/fish/functions/_autopair_tab.fish
@@ -0,0 +1,7 @@
+function _autopair_tab
+ commandline --paging-mode && down-or-search && return
+
+ string match --quiet --regex -- '\$[^\s]*"$' (commandline --current-token) &&
+ commandline --function end-of-line --function backward-delete-char
+ commandline --function complete
+end
diff --git a/.config/fish/functions/_fzf_configure_bindings_help.fish b/.config/fish/functions/_fzf_configure_bindings_help.fish
new file mode 100644
index 00000000..ecfe68ec
--- /dev/null
+++ b/.config/fish/functions/_fzf_configure_bindings_help.fish
@@ -0,0 +1,43 @@
+function _fzf_configure_bindings_help --description "Prints the help message for fzf_configure_bindings."
+ echo "\
+USAGE:
+ fzf_configure_bindings [--COMMAND=[KEY_SEQUENCE]...]
+
+DESCRIPTION
+ fzf_configure_bindings installs key bindings for fzf.fish's commands and erases any bindings it
+ previously installed. It installs bindings for both default and insert modes. fzf.fish executes
+ it without options on fish startup to install the out-of-the-box key bindings.
+
+ By default, commands are bound to a mnemonic key sequence, shown below. Each command's binding
+ can be configured using a namesake corresponding option:
+ COMMAND | DEFAULT KEY SEQUENCE | CORRESPONDING OPTION
+ Search Directory | Ctrl+Alt+F (F for file) | --directory
+ Search Git Log | Ctrl+Alt+L (L for log) | --git_log
+ Search Git Status | Ctrl+Alt+S (S for status) | --git_status
+ Search History | Ctrl+R (R for reverse) | --history
+ Search Processes | Ctrl+Alt+P (P for process) | --processes
+ Search Variables | Ctrl+V (V for variable) | --variables
+ Override a command's binding by specifying its corresponding option with the desired key
+ sequence. Disable a command's binding by specifying its corresponding option with no value.
+
+ Because fzf_configure_bindings erases bindings it previously installed, it can be cleanly
+ executed multiple times. Once the desired fzf_configure_bindings command has been found, add it
+ to your config.fish in order to persist the customized bindings.
+
+ In terms of validation, fzf_configure_bindings fails if passed unknown options. It expects an
+ equals sign between an option's name and value. However, it does not validate key sequences.
+
+ Pass -h or --help to print this help message and exit.
+
+EXAMPLES
+ Default bindings but bind Search Directory to Ctrl+F and Search Variables to Ctrl+Alt+V
+ \$ fzf_configure_bindings --directory=\cf --variables=\e\cv
+ Default bindings but disable Search History
+ \$ fzf_configure_bindings --history=
+ An agglomeration of different options
+ \$ fzf_configure_bindings --git_status=\cg --history=\ch --variables= --processes=
+
+SEE Also
+ To learn more about fish key bindings, see bind(1) and fish_key_reader(1).
+"
+end
diff --git a/.config/fish/functions/_fzf_extract_var_info.fish b/.config/fish/functions/_fzf_extract_var_info.fish
new file mode 100644
index 00000000..dd4e9523
--- /dev/null
+++ b/.config/fish/functions/_fzf_extract_var_info.fish
@@ -0,0 +1,15 @@
+# helper function for _fzf_search_variables
+function _fzf_extract_var_info --argument-names variable_name set_show_output --description "Extract and reformat lines pertaining to \$variable_name from \$set_show_output."
+ # Extract only the lines about the variable, all of which begin with either
+ # $variable_name: ...or... $variable_name[
+ string match --regex "^\\\$$variable_name(?::|\[).*" <$set_show_output |
+
+ # Strip the variable name prefix, including ": " for scope info lines
+ string replace --regex "^\\\$$variable_name(?:: )?" '' |
+
+ # Distill the lines of values, replacing...
+ # [1]: |value|
+ # ...with...
+ # [1] value
+ string replace --regex ": \|(.*)\|" ' $1'
+end
diff --git a/.config/fish/functions/_fzf_preview_changed_file.fish b/.config/fish/functions/_fzf_preview_changed_file.fish
new file mode 100644
index 00000000..78dd5611
--- /dev/null
+++ b/.config/fish/functions/_fzf_preview_changed_file.fish
@@ -0,0 +1,49 @@
+# helper for _fzf_search_git_status
+# arg should be a line from git status --short, e.g.
+# MM functions/_fzf_preview_changed_file.fish
+# D README.md
+# R LICENSE -> "New License"
+function _fzf_preview_changed_file --argument-names path_status --description "Show the git diff of the given file."
+ # remove quotes because they'll be interpreted literally by git diff
+ # no need to requote when referencing $path because fish does not perform word splitting
+ # https://fishshell.com/docs/current/fish_for_bash_users.html
+ set -f path (string unescape (string sub --start 4 $path_status))
+ # first letter of short format shows index, second letter shows working tree
+ # https://git-scm.com/docs/git-status/2.35.0#_short_format
+ set -f index_status (string sub --length 1 $path_status)
+ set -f working_tree_status (string sub --start 2 --length 1 $path_status)
+
+ set -f diff_opts --color=always
+
+ if test $index_status = '?'
+ _fzf_report_diff_type Untracked
+ _fzf_preview_file $path
+ else if contains {$index_status}$working_tree_status DD AU UD UA DU AA UU
+ # Unmerged statuses taken directly from git status help's short format table
+ # Unmerged statuses are mutually exclusive with other statuses, so if we see
+ # these, then safe to assume the path is unmerged
+ _fzf_report_diff_type Unmerged
+ git diff $diff_opts -- $path
+ else
+ if test $index_status != ' '
+ _fzf_report_diff_type Staged
+
+ # renames are only detected in the index, never working tree, so only need to test for it here
+ # https://stackoverflow.com/questions/73954214
+ if test $index_status = R
+ # diff the post-rename path with the original path, otherwise the diff will show the entire file as being added
+ set -f orig_and_new_path (string split --max 1 -- ' -> ' $path)
+ git diff --staged $diff_opts -- $orig_and_new_path[1] $orig_and_new_path[2]
+ # path currently has the form of "original -> current", so we need to correct it before it's used below
+ set path $orig_and_new_path[2]
+ else
+ git diff --staged $diff_opts -- $path
+ end
+ end
+
+ if test $working_tree_status != ' '
+ _fzf_report_diff_type Unstaged
+ git diff $diff_opts -- $path
+ end
+ end
+end
diff --git a/.config/fish/functions/_fzf_preview_file.fish b/.config/fish/functions/_fzf_preview_file.fish
new file mode 100644
index 00000000..c9264756
--- /dev/null
+++ b/.config/fish/functions/_fzf_preview_file.fish
@@ -0,0 +1,43 @@
+# helper function for _fzf_search_directory and _fzf_search_git_status
+function _fzf_preview_file --description "Print a preview for the given file based on its file type."
+ # because there's no way to guarantee that _fzf_search_directory passes the path to _fzf_preview_file
+ # as one argument, we collect all the arguments into one single variable and treat that as the path
+ set -f file_path $argv
+
+ if test -L "$file_path" # symlink
+ # notify user and recurse on the target of the symlink, which can be any of these file types
+ set -l target_path (realpath "$file_path")
+
+ set_color yellow
+ echo "'$file_path' is a symlink to '$target_path'."
+ set_color normal
+
+ _fzf_preview_file "$target_path"
+ else if test -f "$file_path" # regular file
+ if set --query fzf_preview_file_cmd
+ # need to escape quotes to make sure eval receives file_path as a single arg
+ eval "$fzf_preview_file_cmd '$file_path'"
+ else
+ bat --style=numbers --color=always "$file_path"
+ end
+ else if test -d "$file_path" # directory
+ if set --query fzf_preview_dir_cmd
+ # see above
+ eval "$fzf_preview_dir_cmd '$file_path'"
+ else
+ # -A list hidden files as well, except for . and ..
+ # -F helps classify files by appending symbols after the file name
+ command ls -A -F "$file_path"
+ end
+ else if test -c "$file_path"
+ _fzf_report_file_type "$file_path" "character device file"
+ else if test -b "$file_path"
+ _fzf_report_file_type "$file_path" "block device file"
+ else if test -S "$file_path"
+ _fzf_report_file_type "$file_path" socket
+ else if test -p "$file_path"
+ _fzf_report_file_type "$file_path" "named pipe"
+ else
+ echo "$file_path doesn't exist." >&2
+ end
+end
diff --git a/.config/fish/functions/_fzf_report_diff_type.fish b/.config/fish/functions/_fzf_report_diff_type.fish
new file mode 100644
index 00000000..cc26fb35
--- /dev/null
+++ b/.config/fish/functions/_fzf_report_diff_type.fish
@@ -0,0 +1,18 @@
+# helper for _fzf_preview_changed_file
+# prints out something like
+# โญโโโโโโโโโฎ
+# โ Staged โ
+# โฐโโโโโโโโโฏ
+function _fzf_report_diff_type --argument-names diff_type --description "Print a distinct colored header meant to preface a git patch."
+ # number of "-" to draw is the length of the string to box + 2 for padding
+ set -f repeat_count (math 2 + (string length $diff_type))
+ set -f line (string repeat --count $repeat_count โ)
+ set -f top_border โญ$lineโฎ
+ set -f btm_border โฐ$lineโฏ
+
+ set_color yellow
+ echo $top_border
+ echo "โ $diff_type โ"
+ echo $btm_border
+ set_color normal
+end
diff --git a/.config/fish/functions/_fzf_report_file_type.fish b/.config/fish/functions/_fzf_report_file_type.fish
new file mode 100644
index 00000000..49e02e1c
--- /dev/null
+++ b/.config/fish/functions/_fzf_report_file_type.fish
@@ -0,0 +1,6 @@
+# helper function for _fzf_preview_file
+function _fzf_report_file_type --argument-names file_path file_type --description "Explain the file type for a file."
+ set_color red
+ echo "Cannot preview '$file_path': it is a $file_type."
+ set_color normal
+end
diff --git a/.config/fish/functions/_fzf_search_directory.fish b/.config/fish/functions/_fzf_search_directory.fish
new file mode 100644
index 00000000..4541eec9
--- /dev/null
+++ b/.config/fish/functions/_fzf_search_directory.fish
@@ -0,0 +1,33 @@
+function _fzf_search_directory --description "Search the current directory. Replace the current token with the selected file paths."
+ # Directly use fd binary to avoid output buffering delay caused by a fd alias, if any.
+ # Debian-based distros install fd as fdfind and the fd package is something else, so
+ # check for fdfind first. Fall back to "fd" for a clear error message.
+ set -f fd_cmd (command -v fdfind || command -v fd || echo "fd")
+ set -f --append fd_cmd --color=always $fzf_fd_opts
+
+ set -f fzf_arguments --multi --ansi $fzf_directory_opts
+ set -f token (commandline --current-token)
+ # expandย any variables or leading tilde (~) in the token
+ set -f expanded_token (eval echo -- $token)
+ # unescape token because it's already quoted so backslashes will mess up the path
+ set -f unescaped_exp_token (string unescape -- $expanded_token)
+
+ # If the current token is a directory and has a trailing slash,
+ # then use it as fd's base directory.
+ if string match --quiet -- "*/" $unescaped_exp_token && test -d "$unescaped_exp_token"
+ set --append fd_cmd --base-directory=$unescaped_exp_token
+ # use the directory name as fzf's prompt to indicate the search is limited to that directory
+ set --prepend fzf_arguments --prompt="Directory $unescaped_exp_token> " --preview="_fzf_preview_file $expanded_token{}"
+ set -f file_paths_selected $unescaped_exp_token($fd_cmd 2>/dev/null | _fzf_wrapper $fzf_arguments)
+ else
+ set --prepend fzf_arguments --prompt="Directory> " --query="$unescaped_exp_token" --preview='_fzf_preview_file {}'
+ set -f file_paths_selected ($fd_cmd 2>/dev/null | _fzf_wrapper $fzf_arguments)
+ end
+
+
+ if test $status -eq 0
+ commandline --current-token --replace -- (string escape -- $file_paths_selected | string join ' ')
+ end
+
+ commandline --function repaint
+end
diff --git a/.config/fish/functions/_fzf_search_git_log.fish b/.config/fish/functions/_fzf_search_git_log.fish
new file mode 100644
index 00000000..aa54724d
--- /dev/null
+++ b/.config/fish/functions/_fzf_search_git_log.fish
@@ -0,0 +1,36 @@
+function _fzf_search_git_log --description "Search the output of git log and preview commits. Replace the current token with the selected commit hash."
+ if not git rev-parse --git-dir >/dev/null 2>&1
+ echo '_fzf_search_git_log: Not in a git repository.' >&2
+ else
+ if not set --query fzf_git_log_format
+ # %h gives you the abbreviated commit hash, which is useful for saving screen space, but we will have to expand it later below
+ set -f fzf_git_log_format '%C(bold blue)%h%C(reset) - %C(cyan)%ad%C(reset) %C(yellow)%d%C(reset) %C(normal)%s%C(reset) %C(dim normal)[%an]%C(reset)'
+ end
+
+ set -f preview_cmd 'git show --color=always --stat --patch {1}'
+ if set --query fzf_diff_highlighter
+ set preview_cmd "$preview_cmd | $fzf_diff_highlighter"
+ end
+
+ set -f selected_log_lines (
+ git log --no-show-signature --color=always --format=format:$fzf_git_log_format --date=short | \
+ _fzf_wrapper --ansi \
+ --multi \
+ --scheme=history \
+ --prompt="Git Log> " \
+ --preview=$preview_cmd \
+ --query=(commandline --current-token) \
+ $fzf_git_log_opts
+ )
+ if test $status -eq 0
+ for line in $selected_log_lines
+ set -f abbreviated_commit_hash (string split --field 1 " " $line)
+ set -f full_commit_hash (git rev-parse $abbreviated_commit_hash)
+ set -f --append commit_hashes $full_commit_hash
+ end
+ commandline --current-token --replace (string join ' ' $commit_hashes)
+ end
+ end
+
+ commandline --function repaint
+end
diff --git a/.config/fish/functions/_fzf_search_git_status.fish b/.config/fish/functions/_fzf_search_git_status.fish
new file mode 100644
index 00000000..358f88c5
--- /dev/null
+++ b/.config/fish/functions/_fzf_search_git_status.fish
@@ -0,0 +1,41 @@
+function _fzf_search_git_status --description "Search the output of git status. Replace the current token with the selected file paths."
+ if not git rev-parse --git-dir >/dev/null 2>&1
+ echo '_fzf_search_git_status: Not in a git repository.' >&2
+ else
+ set -f preview_cmd '_fzf_preview_changed_file {}'
+ if set --query fzf_diff_highlighter
+ set preview_cmd "$preview_cmd | $fzf_diff_highlighter"
+ end
+
+ set -f selected_paths (
+ # Pass configuration color.status=always to force status to use colors even though output is sent to a pipe
+ git -c color.status=always status --short |
+ _fzf_wrapper --ansi \
+ --multi \
+ --prompt="Git Status> " \
+ --query=(commandline --current-token) \
+ --preview=$preview_cmd \
+ --nth="2.." \
+ $fzf_git_status_opts
+ )
+ if test $status -eq 0
+ # git status --short automatically escapes the paths of most files for us so not going to bother trying to handle
+ # the few edges cases of weird file names that should be extremely rare (e.g. "this;needs;escaping")
+ set -f cleaned_paths
+
+ for path in $selected_paths
+ if test (string sub --length 1 $path) = R
+ # path has been renamed and looks like "R LICENSE -> LICENSE.md"
+ # extract the path to use from after the arrow
+ set --append cleaned_paths (string split -- "-> " $path)[-1]
+ else
+ set --append cleaned_paths (string sub --start=4 $path)
+ end
+ end
+
+ commandline --current-token --replace -- (string join ' ' $cleaned_paths)
+ end
+ end
+
+ commandline --function repaint
+end
diff --git a/.config/fish/functions/_fzf_search_history.fish b/.config/fish/functions/_fzf_search_history.fish
new file mode 100644
index 00000000..cafbce98
--- /dev/null
+++ b/.config/fish/functions/_fzf_search_history.fish
@@ -0,0 +1,39 @@
+function _fzf_search_history --description "Search command history. Replace the command line with the selected command."
+ # history merge incorporates history changes from other fish sessions
+ # it errors out if called in private mode
+ if test -z "$fish_private_mode"
+ builtin history merge
+ end
+
+ if not set --query fzf_history_time_format
+ # Reference https://devhints.io/strftime to understand strftime format symbols
+ set -f fzf_history_time_format "%m-%d %H:%M:%S"
+ end
+
+ # Delinate time from command in history entries using the vertical box drawing char (U+2502).
+ # Then, to get raw command from history entries, delete everything up to it. The ? on regex is
+ # necessary to make regex non-greedy so it won't match into commands containing the char.
+ set -f time_prefix_regex '^.*? โ '
+ # Delinate commands throughout pipeline using null rather than newlines because commands can be multi-line
+ set -f commands_selected (
+ builtin history --null --show-time="$fzf_history_time_format โ " |
+ _fzf_wrapper --read0 \
+ --print0 \
+ --multi \
+ --scheme=history \
+ --prompt="History> " \
+ --query=(commandline) \
+ --preview="string replace --regex '$time_prefix_regex' '' -- {} | fish_indent --ansi" \
+ --preview-window="bottom:3:wrap" \
+ $fzf_history_opts |
+ string split0 |
+ # remove timestamps from commands selected
+ string replace --regex $time_prefix_regex ''
+ )
+
+ if test $status -eq 0
+ commandline --replace -- $commands_selected
+ end
+
+ commandline --function repaint
+end
diff --git a/.config/fish/functions/_fzf_search_processes.fish b/.config/fish/functions/_fzf_search_processes.fish
new file mode 100644
index 00000000..133a8806
--- /dev/null
+++ b/.config/fish/functions/_fzf_search_processes.fish
@@ -0,0 +1,32 @@
+function _fzf_search_processes --description "Search all running processes. Replace the current token with the pid of the selected process."
+ # Directly use ps command because it is often aliased to a different command entirely
+ # or with options that dirty the search results and preview output
+ set -f ps_cmd (command -v ps || echo "ps")
+ # use all caps to be consistent with ps default format
+ # snake_case because ps doesn't seem to allow spaces in the field names
+ set -f ps_preview_fmt (string join ',' 'pid' 'ppid=PARENT' 'user' '%cpu' 'rss=RSS_IN_KB' 'start=START_TIME' 'command')
+ set -f processes_selected (
+ $ps_cmd -A -opid,command | \
+ _fzf_wrapper --multi \
+ --prompt="Processes> " \
+ --query (commandline --current-token) \
+ --ansi \
+ # first line outputted by ps is a header, so we need to mark it as so
+ --header-lines=1 \
+ # ps uses exit code 1 if the process was not found, in which case show an message explaining so
+ --preview="$ps_cmd -o '$ps_preview_fmt' -p {1} || echo 'Cannot preview {1} because it exited.'" \
+ --preview-window="bottom:4:wrap" \
+ $fzf_processes_opts
+ )
+
+ if test $status -eq 0
+ for process in $processes_selected
+ set -f --append pids_selected (string split --no-empty --field=1 -- " " $process)
+ end
+
+ # string join to replace the newlines outputted by string split with spaces
+ commandline --current-token --replace -- (string join ' ' $pids_selected)
+ end
+
+ commandline --function repaint
+end
diff --git a/.config/fish/functions/_fzf_search_variables.fish b/.config/fish/functions/_fzf_search_variables.fish
new file mode 100644
index 00000000..52a7c701
--- /dev/null
+++ b/.config/fish/functions/_fzf_search_variables.fish
@@ -0,0 +1,47 @@
+# This function expects the following two arguments:
+# argument 1 = output of (set --show | psub), i.e. a file with the scope info and values of all variables
+# argument 2 = output of (set --names | psub), i.e. a file with all variable names
+function _fzf_search_variables --argument-names set_show_output set_names_output --description "Search and preview shell variables. Replace the current token with the selected variable."
+ if test -z "$set_names_output"
+ printf '%s\n' '_fzf_search_variables requires 2 arguments.' >&2
+
+ commandline --function repaint
+ return 22 # 22 means invalid argument in POSIX
+ end
+
+ # Exclude the history variable from being piped into fzf because
+ # 1. it's not included in $set_names_output
+ # 2. it tends to be a very large value => increases computation time
+ # 3._fzf_search_history is a much better way to examine history anyway
+ set -f all_variable_names (string match --invert history <$set_names_output)
+
+ set -f current_token (commandline --current-token)
+ # Use the current token to pre-populate fzf's query. If the current token begins
+ # with a $, remove it from the query so that it will better match the variable names
+ set -f cleaned_curr_token (string replace -- '$' '' $current_token)
+
+ set -f variable_names_selected (
+ printf '%s\n' $all_variable_names |
+ _fzf_wrapper --preview "_fzf_extract_var_info {} $set_show_output" \
+ --prompt="Variables> " \
+ --preview-window="wrap" \
+ --multi \
+ --query=$cleaned_curr_token \
+ $fzf_variables_opts
+ )
+
+ if test $status -eq 0
+ # If the current token begins with a $, do not overwrite the $ when
+ # replacing the current token with the selected variable.
+ # Uses brace expansion to prepend $ to each variable name.
+ commandline --current-token --replace (
+ if string match --quiet -- '$*' $current_token
+ string join " " \${$variable_names_selected}
+ else
+ string join " " $variable_names_selected
+ end
+ )
+ end
+
+ commandline --function repaint
+end
diff --git a/.config/fish/functions/_fzf_wrapper.fish b/.config/fish/functions/_fzf_wrapper.fish
new file mode 100644
index 00000000..486e36c3
--- /dev/null
+++ b/.config/fish/functions/_fzf_wrapper.fish
@@ -0,0 +1,21 @@
+function _fzf_wrapper --description "Prepares some environment variables before executing fzf."
+ # Make sure fzf uses fish to execute preview commands, some of which
+ # are autoloaded fish functions so don't exist in other shells.
+ # Use --function so that it doesn't clobber SHELL outside this function.
+ set -f --export SHELL (command --search fish)
+
+ # If neither FZF_DEFAULT_OPTS nor FZF_DEFAULT_OPTS_FILE are set, then set some sane defaults.
+ # See https://github.com/junegunn/fzf#environment-variables
+ set --query FZF_DEFAULT_OPTS FZF_DEFAULT_OPTS_FILE
+ if test $status -eq 2
+ # cycle allows jumping between the first and last results, making scrolling faster
+ # layout=reverse lists results top to bottom, mimicking the familiar layouts of git log, history, and env
+ # border shows where the fzf window begins and ends
+ # height=90% leaves space to see the current command and some scrollback, maintaining context of work
+ # preview-window=wrap wraps long lines in the preview window, making reading easier
+ # marker=* makes the multi-select marker more distinguishable from the pointer (since both default to >)
+ set --export FZF_DEFAULT_OPTS '--cycle --layout=reverse --border --height=90% --preview-window=wrap --marker="*"'
+ end
+
+ fzf $argv
+end
diff --git a/.config/fish/functions/_puffer_fish_expand_bang.fish b/.config/fish/functions/_puffer_fish_expand_bang.fish
new file mode 100644
index 00000000..401d85e8
--- /dev/null
+++ b/.config/fish/functions/_puffer_fish_expand_bang.fish
@@ -0,0 +1,9 @@
+function _puffer_fish_expand_bang
+ switch (commandline -t)
+ case '!'
+ commandline -t $history[1]
+ case '*'
+ commandline -i '!'
+ end
+end
+
diff --git a/.config/fish/functions/_puffer_fish_expand_dots.fish b/.config/fish/functions/_puffer_fish_expand_dots.fish
new file mode 100644
index 00000000..ff82af7d
--- /dev/null
+++ b/.config/fish/functions/_puffer_fish_expand_dots.fish
@@ -0,0 +1,9 @@
+function _puffer_fish_expand_dots -d 'expand ... to ../.. etc'
+ set -l cmd (commandline --cut-at-cursor)
+ set -l split (string split -- ' ' $cmd)
+ if string match --quiet --regex -- '^(\.\./)*\.\.$' $split[-1]
+ commandline --insert '/..'
+ else
+ commandline --insert '.'
+ end
+end
diff --git a/.config/fish/functions/_puffer_fish_expand_lastarg.fish b/.config/fish/functions/_puffer_fish_expand_lastarg.fish
new file mode 100644
index 00000000..a61b8920
--- /dev/null
+++ b/.config/fish/functions/_puffer_fish_expand_lastarg.fish
@@ -0,0 +1,9 @@
+function _puffer_fish_expand_lastarg
+ switch (commandline -t)
+ case '!'
+ commandline -t ""
+ commandline -f history-token-search-backward
+ case '*'
+ commandline -i '$'
+ end
+end
diff --git a/.config/fish/functions/_sponge_clear_state.fish b/.config/fish/functions/_sponge_clear_state.fish
new file mode 100644
index 00000000..c6a07da7
--- /dev/null
+++ b/.config/fish/functions/_sponge_clear_state.fish
@@ -0,0 +1,5 @@
+function _sponge_clear_state
+ set --erase --global _sponge_current_command
+ set --erase --global _sponge_current_command_exit_code
+ set --erase --global _sponge_current_command_previously_in_history
+end
diff --git a/.config/fish/functions/_sponge_on_exit.fish b/.config/fish/functions/_sponge_on_exit.fish
new file mode 100644
index 00000000..0c6cc190
--- /dev/null
+++ b/.config/fish/functions/_sponge_on_exit.fish
@@ -0,0 +1,3 @@
+function _sponge_on_exit --on-event fish_exit
+ sponge_delay=0 _sponge_remove_from_history
+end
diff --git a/.config/fish/functions/_sponge_on_postexec.fish b/.config/fish/functions/_sponge_on_postexec.fish
new file mode 100644
index 00000000..1d679354
--- /dev/null
+++ b/.config/fish/functions/_sponge_on_postexec.fish
@@ -0,0 +1,24 @@
+function _sponge_on_postexec --on-event fish_postexec
+ set --global _sponge_current_command_exit_code $status
+
+ # Remove command from the queue if it's been added previously
+ if set --local index (contains --index -- $_sponge_current_command $_sponge_queue)
+ set --erase _sponge_queue[$index]
+ end
+
+ # Ignore empty commands
+ if test -n $_sponge_current_command
+ set --local command ''
+ # Run filters
+ for filter in $sponge_filters
+ if $filter \
+ $_sponge_current_command \
+ $_sponge_current_command_exit_code \
+ $_sponge_current_command_previously_in_history
+ set command $_sponge_current_command
+ break
+ end
+ end
+ set --prepend --global _sponge_queue $command
+ end
+end
diff --git a/.config/fish/functions/_sponge_on_preexec.fish b/.config/fish/functions/_sponge_on_preexec.fish
new file mode 100644
index 00000000..a8664911
--- /dev/null
+++ b/.config/fish/functions/_sponge_on_preexec.fish
@@ -0,0 +1,16 @@
+function _sponge_on_preexec --on-event fish_preexec \
+ --argument-names command
+ _sponge_clear_state
+
+ set --global _sponge_current_command $command
+
+ builtin history search --case-sensitive --exact --max=1 --null $command \
+ | read --local --null found_entries
+
+ # If a command is in the history and in the queue, ignore it, like if it wasnโt in the history
+ if test (count $found_entries) -ne 0; and not contains $command $_sponge_queue
+ set --global _sponge_current_command_previously_in_history true
+ else
+ set --global _sponge_current_command_previously_in_history false
+ end
+end
diff --git a/.config/fish/functions/_sponge_on_prompt.fish b/.config/fish/functions/_sponge_on_prompt.fish
new file mode 100644
index 00000000..03e989a2
--- /dev/null
+++ b/.config/fish/functions/_sponge_on_prompt.fish
@@ -0,0 +1,5 @@
+function _sponge_on_prompt --on-event fish_prompt
+ if test $sponge_purge_only_on_exit = false
+ _sponge_remove_from_history
+ end
+end
diff --git a/.config/fish/functions/_sponge_remove_from_history.fish b/.config/fish/functions/_sponge_remove_from_history.fish
new file mode 100644
index 00000000..4d4f8277
--- /dev/null
+++ b/.config/fish/functions/_sponge_remove_from_history.fish
@@ -0,0 +1,9 @@
+function _sponge_remove_from_history
+
+ while test (count $_sponge_queue) -gt $sponge_delay
+ builtin history delete --case-sensitive --exact -- $_sponge_queue[-1]
+ set --erase _sponge_queue[-1]
+ end
+
+ builtin history save
+end
diff --git a/.config/fish/functions/fzf_configure_bindings.fish b/.config/fish/functions/fzf_configure_bindings.fish
new file mode 100644
index 00000000..4b4e7a2b
--- /dev/null
+++ b/.config/fish/functions/fzf_configure_bindings.fish
@@ -0,0 +1,46 @@
+# Always installs bindings for insert and default mode for simplicity and b/c it has almost no side-effect
+# https://gitter.im/fish-shell/fish-shell?at=60a55915ee77a74d685fa6b1
+function fzf_configure_bindings --description "Installs the default key bindings for fzf.fish with user overrides passed as options."
+ # no need to install bindings if not in interactive mode or running tests
+ status is-interactive || test "$CI" = true; or return
+
+ set -f options_spec h/help 'directory=?' 'git_log=?' 'git_status=?' 'history=?' 'processes=?' 'variables=?'
+ argparse --max-args=0 --ignore-unknown $options_spec -- $argv 2>/dev/null
+ if test $status -ne 0
+ echo "Invalid option or a positional argument was provided." >&2
+ _fzf_configure_bindings_help
+ return 22
+ else if set --query _flag_help
+ _fzf_configure_bindings_help
+ return
+ else
+ # Initialize with default key sequences and then override or disable them based on flags
+ # index 1 = directory, 2 = git_log, 3 = git_status, 4 = history, 5 = processes, 6 = variables
+ set -f key_sequences \e\cf \e\cl \e\cs \cr \e\cp \cv # \c = control, \e = escape
+ set --query _flag_directory && set key_sequences[1] "$_flag_directory"
+ set --query _flag_git_log && set key_sequences[2] "$_flag_git_log"
+ set --query _flag_git_status && set key_sequences[3] "$_flag_git_status"
+ set --query _flag_history && set key_sequences[4] "$_flag_history"
+ set --query _flag_processes && set key_sequences[5] "$_flag_processes"
+ set --query _flag_variables && set key_sequences[6] "$_flag_variables"
+
+ # If fzf bindings already exists, uninstall it first for a clean slate
+ if functions --query _fzf_uninstall_bindings
+ _fzf_uninstall_bindings
+ end
+
+ for mode in default insert
+ test -n $key_sequences[1] && bind --mode $mode $key_sequences[1] _fzf_search_directory
+ test -n $key_sequences[2] && bind --mode $mode $key_sequences[2] _fzf_search_git_log
+ test -n $key_sequences[3] && bind --mode $mode $key_sequences[3] _fzf_search_git_status
+ test -n $key_sequences[4] && bind --mode $mode $key_sequences[4] _fzf_search_history
+ test -n $key_sequences[5] && bind --mode $mode $key_sequences[5] _fzf_search_processes
+ test -n $key_sequences[6] && bind --mode $mode $key_sequences[6] "$_fzf_search_vars_command"
+ end
+
+ function _fzf_uninstall_bindings --inherit-variable key_sequences
+ bind --erase -- $key_sequences
+ bind --erase --mode insert -- $key_sequences
+ end
+ end
+end
diff --git a/.config/fish/functions/projectdo_build.fish b/.config/fish/functions/projectdo_build.fish
new file mode 100644
index 00000000..21ce2921
--- /dev/null
+++ b/.config/fish/functions/projectdo_build.fish
@@ -0,0 +1,3 @@
+function projectdo_build
+ projectdo -d build
+end
diff --git a/.config/fish/functions/projectdo_run.fish b/.config/fish/functions/projectdo_run.fish
new file mode 100644
index 00000000..2a73e98a
--- /dev/null
+++ b/.config/fish/functions/projectdo_run.fish
@@ -0,0 +1,3 @@
+function projectdo_run
+ projectdo -d run
+end
diff --git a/.config/fish/functions/projectdo_test.fish b/.config/fish/functions/projectdo_test.fish
new file mode 100644
index 00000000..680e18b1
--- /dev/null
+++ b/.config/fish/functions/projectdo_test.fish
@@ -0,0 +1,3 @@
+function projectdo_test
+ projectdo -d test
+end
diff --git a/.config/fish/functions/projectdo_tool.fish b/.config/fish/functions/projectdo_tool.fish
new file mode 100644
index 00000000..3d37d66e
--- /dev/null
+++ b/.config/fish/functions/projectdo_tool.fish
@@ -0,0 +1,3 @@
+function projectdo_tool
+ projectdo -d tool
+end
diff --git a/.config/fish/functions/replay.fish b/.config/fish/functions/replay.fish
new file mode 100644
index 00000000..809a3b14
--- /dev/null
+++ b/.config/fish/functions/replay.fish
@@ -0,0 +1,48 @@
+function replay --description "Run Bash commands replaying changes in Fish"
+ switch "$argv"
+ case -v --version
+ echo "replay, version 1.2.1"
+ case "" -h --help
+ echo "Usage: replay Run Bash commands replaying changes in Fish"
+ echo "Options:"
+ echo " -v or --version Print version"
+ echo " -h or --help Print this help message"
+ case \*
+ set --local env
+ set --local sep @$fish_pid(random)(command date +%s)
+ set --local argv $argv[1] (string escape -- $argv[2..-1])
+ set --local out (command bash -c "
+ $argv
+ status=\$?
+ [ \$status -gt 0 ] && exit \$status
+
+ command compgen -e | command awk -v sep=$sep '{
+ gsub(/\n/, \"\\\n\", ENVIRON[\$0])
+ print \$0 sep ENVIRON[\$0]
+ }' && alias
+ ") || return
+
+ string replace --all -- \\n \n (
+ for line in $out
+ if string split -- $sep $line | read --local --line name value
+ set --append env $name
+
+ contains -- $name SHLVL PS1 BASH_FUNC || test "$$name" = "$value" && continue
+
+ if test "$name" = PATH
+ echo set PATH (string split -- : $value | string replace --regex --all -- '(^.*$)' '"$1"')
+ else if test "$name" = PWD
+ echo builtin cd "\"$value\""
+ else
+ echo "set --global --export $name "(string escape -- $value)
+ end
+ else
+ set --query env[1] && string match --entire --regex -- "^alias" $line || echo "echo \"$line\""
+ end
+ end | string replace --all -- \$ \\\$
+ for name in (set --export --names)
+ contains -- $name $env || echo "set --erase $name"
+ end
+ ) | source
+ end
+end
diff --git a/.config/fish/functions/spark.fish b/.config/fish/functions/spark.fish
new file mode 100644
index 00000000..0bbe6ff0
--- /dev/null
+++ b/.config/fish/functions/spark.fish
@@ -0,0 +1,33 @@
+function spark --description Sparklines
+ argparse --ignore-unknown --name=spark v/version h/help m/min= M/max= -- $argv || return
+
+ if set --query _flag_version[1]
+ echo "spark, version 1.1.0"
+ else if set --query _flag_help[1]
+ echo "Usage: spark "
+ echo " stdin | spark"
+ echo "Options:"
+ echo " --min= Minimum range"
+ echo " --max= Maximum range"
+ echo " -v or --version Print version"
+ echo " -h or --help Print this help message"
+ echo "Examples:"
+ echo " spark 1 1 2 5 14 42"
+ echo " seq 64 | sort --random-sort | spark"
+ else if set --query argv[1]
+ printf "%s\n" $argv | spark --min="$_flag_min" --max="$_flag_max"
+ else
+ command awk -v min="$_flag_min" -v max="$_flag_max" '
+ {
+ m = min == "" ? m == "" ? $0 : m > $0 ? $0 : m : min
+ M = max == "" ? M == "" ? $0 : M < $0 ? $0 : M : max
+ nums[NR] = $0
+ }
+ END {
+ n = split("โ โ โ โ โ โ โ โ", sparks, " ") - 1
+ while (++i <= NR)
+ printf("%s", sparks[(M == m) ? 3 : sprintf("%.f", (1 + (nums[i] - m) * n / (M - m)))])
+ }
+ ' && echo
+ end
+end
diff --git a/.config/fish/functions/sponge_filter_failed.fish b/.config/fish/functions/sponge_filter_failed.fish
new file mode 100644
index 00000000..be26e5d0
--- /dev/null
+++ b/.config/fish/functions/sponge_filter_failed.fish
@@ -0,0 +1,11 @@
+function sponge_filter_failed \
+ --argument-names command exit_code previously_in_history
+
+ if test $previously_in_history = true -a $sponge_allow_previously_successful = true
+ return 1
+ end
+
+ if contains $exit_code $sponge_successful_exit_codes
+ return 1
+ end
+end
diff --git a/.config/fish/functions/sponge_filter_matched.fish b/.config/fish/functions/sponge_filter_matched.fish
new file mode 100644
index 00000000..c3c7ea20
--- /dev/null
+++ b/.config/fish/functions/sponge_filter_matched.fish
@@ -0,0 +1,11 @@
+function sponge_filter_matched \
+ --argument-names command
+
+ for pattern in $sponge_regex_patterns
+ if string match --regex --quiet $pattern -- $command
+ return
+ end
+ end
+
+ return 1
+end