diff --git a/.dotter/global.toml b/.dotter/global.toml
index 9186224..dcc2da4 100644
--- a/.dotter/global.toml
+++ b/.dotter/global.toml
@@ -4,10 +4,58 @@
depends = []
[git.files]
-"git/.gitconfig" = "~/.gitconfig"
-"git/.gitignore" = "~/.gitignore"
+"git/gitconfig" = "~/.gitconfig"
+"git/gitignore" = "~/.gitignore"
[git.variables]
+[nvim]
+depends = []
+
+[nvim.files]
+"nvim/init.lua" = "~/.config/nvim/init.lua"
+"nvim/lazy-lock.json" = "~/.config/nvim/lazy-lock.json"
+"nvim/lua/config/lazy.lua" = "~/.config/nvim/lua/config/lazy.lua"
+"nvim/lua/plugins/hop.lua" = "~/.config/nvim/lua/plugins/hop.lua"
+"nvim/lua/plugins/mini-surround.lua" = "~/.config/nvim/lua/plugins/mini-surround.lua"
+
+[nvim.variables]
+
+[fish]
+depends = []
+
+[fish.files]
+"fish/config.fish" = "~/.config/fish/config.fish"
+"fish/fish_plugins" = "~/.config/fish/fish_plugins"
+"fish/completions" = "~/.config/fish/completions"
+"fish/conf.d" = "~/.config/fish/conf.d"
+"fish/functions" = "~/.config/fish/functions"
+
+[fish.variables]
+
+[zellij]
+depends = []
+
+[zellij.files]
+"zellij/config.kdl" = "~/.config/zellij/config.kdl"
+
+[zellij.variables]
+
+[htop]
+depends = []
+
+[htop.files]
+"htop/htoprc" = "~/.config/htop/htoprc"
+
+[htop.variables]
+
+[asdf]
+depends = []
+
+[asdf.files]
+"asdf/.tool-versions" = "~/.tool-versions"
+
+[asdf.variables]
+
[settings]
default_target_type = "automatic"
diff --git a/asdf/.tool-versions b/asdf/.tool-versions
new file mode 100644
index 0000000..e241e8b
--- /dev/null
+++ b/asdf/.tool-versions
@@ -0,0 +1,2 @@
+nodejs 22.11.0
+golang 1.25.1
diff --git a/fish/completions/fisher.fish b/fish/completions/fisher.fish
new file mode 100644
index 0000000..6d23ce4
--- /dev/null
+++ b/fish/completions/fisher.fish
@@ -0,0 +1,7 @@
+complete --command fisher --exclusive --long help --description "Print help"
+complete --command fisher --exclusive --long version --description "Print version"
+complete --command fisher --exclusive --condition __fish_use_subcommand --arguments install --description "Install plugins"
+complete --command fisher --exclusive --condition __fish_use_subcommand --arguments update --description "Update installed plugins"
+complete --command fisher --exclusive --condition __fish_use_subcommand --arguments remove --description "Remove installed plugins"
+complete --command fisher --exclusive --condition __fish_use_subcommand --arguments list --description "List installed plugins matching regex"
+complete --command fisher --exclusive --condition "__fish_seen_subcommand_from update remove" --arguments "(fisher list)"
diff --git a/fish/conf.d/done.fish b/fish/conf.d/done.fish
new file mode 100644
index 0000000..3f9f0d3
--- /dev/null
+++ b/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/fish/conf.d/rustup.fish b/fish/conf.d/rustup.fish
new file mode 100644
index 0000000..e4cb363
--- /dev/null
+++ b/fish/conf.d/rustup.fish
@@ -0,0 +1 @@
+source "$HOME/.cargo/env.fish"
diff --git a/fish/conf.d/sponge.fish b/fish/conf.d/sponge.fish
new file mode 100644
index 0000000..e37fe38
--- /dev/null
+++ b/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/fish/conf.d/z.fish b/fish/conf.d/z.fish
new file mode 100644
index 0000000..59c960f
--- /dev/null
+++ b/fish/conf.d/z.fish
@@ -0,0 +1,63 @@
+if test -z "$Z_DATA"
+ if test -z "$XDG_DATA_HOME"
+ set -U Z_DATA_DIR "$HOME/.local/share/z"
+ else
+ set -U Z_DATA_DIR "$XDG_DATA_HOME/z"
+ end
+ set -U Z_DATA "$Z_DATA_DIR/data"
+end
+
+if test ! -e "$Z_DATA"
+ if test ! -e "$Z_DATA_DIR"
+ mkdir -p -m 700 "$Z_DATA_DIR"
+ end
+ touch "$Z_DATA"
+end
+
+if test -z "$Z_CMD"
+ set -U Z_CMD z
+end
+
+set -U ZO_CMD "$Z_CMD"o
+
+if test ! -z $Z_CMD
+ function $Z_CMD -d "jump around"
+ __z $argv
+ end
+end
+
+if test ! -z $ZO_CMD
+ function $ZO_CMD -d "open target dir"
+ __z -d $argv
+ end
+end
+
+if not set -q Z_EXCLUDE
+ set -U Z_EXCLUDE "^$HOME\$"
+else if contains $HOME $Z_EXCLUDE
+ # Workaround: migrate old default values to a regex (see #90).
+ set Z_EXCLUDE (string replace -r -- "^$HOME\$" '^'$HOME'$$' $Z_EXCLUDE)
+end
+
+# Setup completions once first
+__z_complete
+
+function __z_on_variable_pwd --on-variable PWD
+ __z_add
+end
+
+function __z_uninstall --on-event z_uninstall
+ functions -e __z_on_variable_pwd
+ functions -e $Z_CMD
+ functions -e $ZO_CMD
+
+ if test ! -z "$Z_DATA"
+ printf "To completely erase z's data, remove:\n" >/dev/stderr
+ printf "%s\n" "$Z_DATA" >/dev/stderr
+ end
+
+ set -e Z_CMD
+ set -e ZO_CMD
+ set -e Z_DATA
+ set -e Z_EXCLUDE
+end
diff --git a/fish/config.fish b/fish/config.fish
new file mode 100644
index 0000000..ff2ddde
--- /dev/null
+++ b/fish/config.fish
@@ -0,0 +1,22 @@
+if status is-interactive
+ # Commands to run in interactive sessions can go here
+end
+
+eval ({{brew_path}}/bin/brew shellenv)
+set -gx ASDF_DIR {{brew_path}}/opt/asdf/libexec
+
+# ASDF configuration code
+if test -z $ASDF_DATA_DIR
+ set _asdf_shims "$HOME/.asdf/shims"
+else
+ set _asdf_shims "$ASDF_DATA_DIR/shims"
+end
+
+# Do not use fish_add_path (added in Fish 3.2) because it
+# potentially changes the order of items in PATH
+if not contains $_asdf_shims $PATH
+ set -gx --prepend PATH $_asdf_shims
+end
+set --erase _asdf_shims
+zoxide init fish | source
+
diff --git a/fish/fish_plugins b/fish/fish_plugins
new file mode 100644
index 0000000..f39b138
--- /dev/null
+++ b/fish/fish_plugins
@@ -0,0 +1,4 @@
+jorgebucaran/fisher
+franciscolourenco/done
+jethrokuan/z
+meaningful-ooo/sponge
diff --git a/fish/functions/__z.fish b/fish/functions/__z.fish
new file mode 100644
index 0000000..f72ff0e
--- /dev/null
+++ b/fish/functions/__z.fish
@@ -0,0 +1,174 @@
+function __z -d "Jump to a recent directory."
+ function __print_help -d "Print z help."
+ printf "Usage: $Z_CMD [-celrth] string1 string2...\n\n"
+ printf " -c --clean Removes directories that no longer exist from $Z_DATA\n"
+ printf " -d --dir Opens matching directory using system file manager.\n"
+ printf " -e --echo Prints best match, no cd\n"
+ printf " -l --list List matches and scores, no cd\n"
+ printf " -p --purge Delete all entries from $Z_DATA\n"
+ printf " -r --rank Search by rank\n"
+ printf " -t --recent Search by recency\n"
+ printf " -x --delete Removes the current directory from $Z_DATA\n"
+ printf " -h --help Print this help\n\n"
+ end
+ function __z_legacy_escape_regex
+ # taken from escape_string_pcre2 in fish
+ # used to provide compatibility with fish 2
+ for c in (string split '' $argv)
+ if contains $c (string split '' '.^$*+()?[{}\\|-]')
+ printf \\
+ end
+ printf '%s' $c
+ end
+ end
+
+ set -l options h/help c/clean e/echo l/list p/purge r/rank t/recent d/directory x/delete
+
+ argparse $options -- $argv
+
+ if set -q _flag_help
+ __print_help
+ return 0
+ else if set -q _flag_clean
+ __z_clean
+ printf "%s cleaned!\n" $Z_DATA
+ return 0
+ else if set -q _flag_purge
+ echo >$Z_DATA
+ printf "%s purged!\n" $Z_DATA
+ return 0
+ else if set -q _flag_delete
+ sed -i -e "\:^$PWD|.*:d" $Z_DATA
+ return 0
+ end
+
+ set -l typ
+
+ if set -q _flag_rank
+ set typ rank
+ else if set -q _flag_recent
+ set typ recent
+ end
+
+ set -l z_script '
+ function frecent(rank, time) {
+ dx = t-time
+ if( dx < 3600 ) return rank*4
+ if( dx < 86400 ) return rank*2
+ if( dx < 604800 ) return rank/2
+ return rank/4
+ }
+
+ function output(matches, best_match, common) {
+ # list or return the desired directory
+ if( list ) {
+ cmd = "sort -nr"
+ for( x in matches ) {
+ if( matches[x] ) {
+ printf "%-10s %s\n", matches[x], x | cmd
+ }
+ }
+ } else {
+ if( common ) best_match = common
+ print best_match
+ }
+ }
+
+ function common(matches) {
+ # find the common root of a list of matches, if it exists
+ for( x in matches ) {
+ if( matches[x] && (!short || length(x) < length(short)) ) {
+ short = x
+ }
+ }
+ if( short == "/" ) return
+ for( x in matches ) if( matches[x] && index(x, short) != 1 ) {
+ return
+ }
+ return short
+ }
+
+ BEGIN {
+ hi_rank = ihi_rank = -9999999999
+ }
+ {
+ if( typ == "rank" ) {
+ rank = $2
+ } else if( typ == "recent" ) {
+ rank = $3 - t
+ } else rank = frecent($2, $3)
+ if( $1 ~ q ) {
+ matches[$1] = rank
+ } else if( tolower($1) ~ tolower(q) ) imatches[$1] = rank
+ if( matches[$1] && matches[$1] > hi_rank ) {
+ best_match = $1
+ hi_rank = matches[$1]
+ } else if( imatches[$1] && imatches[$1] > ihi_rank ) {
+ ibest_match = $1
+ ihi_rank = imatches[$1]
+ }
+ }
+
+ END {
+ # prefer case sensitive
+ if( best_match ) {
+ output(matches, best_match, common(matches))
+ } else if( ibest_match ) {
+ output(imatches, ibest_match, common(imatches))
+ }
+ }
+ '
+
+ set -l qs
+ for arg in $argv
+ set -l escaped $arg
+ if string escape --style=regex '' >/dev/null 2>&1 # use builtin escape if available
+ set escaped (string escape --style=regex $escaped)
+ else
+ set escaped (__z_legacy_escape_regex $escaped)
+ end
+ # Need to escape twice, see https://www.math.utah.edu/docs/info/gawk_5.html#SEC32
+ set escaped (string replace --all \\ \\\\ $escaped)
+ set qs $qs $escaped
+ end
+ set -l q (string join '.*' $qs)
+
+ if set -q _flag_list
+ # Handle list separately as it can print common path information to stderr
+ # which cannot be captured from a subcommand.
+ command awk -v t=(date +%s) -v list="list" -v typ="$typ" -v q="$q" -F "|" $z_script "$Z_DATA"
+ return
+ end
+
+ set target (command awk -v t=(date +%s) -v typ="$typ" -v q="$q" -F "|" $z_script "$Z_DATA")
+
+ if test "$status" -gt 0
+ return
+ end
+
+ if test -z "$target"
+ printf "'%s' did not match any results\n" "$argv"
+ return 1
+ end
+
+ if set -q _flag_echo
+ printf "%s\n" "$target"
+ else if set -q _flag_directory
+ if test -n "$ZO_METHOD"
+ type -q "$ZO_METHOD"; and "$ZO_METHOD" "$target"; and return $status
+ echo "Cannot open with ZO_METHOD set to $ZO_METHOD"; and return 1
+ else if test "$OS" = Windows_NT
+ # Be careful, in msys2, explorer always return 1
+ type -q explorer; and explorer "$target"
+ return 0
+ echo "Cannot open file explorer"
+ return 1
+ else
+ type -q xdg-open; and xdg-open "$target"; and return $status
+ type -q open; and open "$target"; and return $status
+ echo "Not sure how to open file manager"; and return 1
+ end
+ else
+ pushd "$target"
+ end
+end
diff --git a/fish/functions/__z_add.fish b/fish/functions/__z_add.fish
new file mode 100644
index 0000000..20d5d7e
--- /dev/null
+++ b/fish/functions/__z_add.fish
@@ -0,0 +1,49 @@
+function __z_add -d "Add PATH to .z file"
+ test -n "$fish_private_mode"; and return 0
+
+ for i in $Z_EXCLUDE
+ if string match -r $i $PWD >/dev/null
+ return 0 #Path excluded
+ end
+ end
+
+ set -l tmpfile (mktemp $Z_DATA.XXXXXX)
+
+ if test -f $tmpfile
+ set -l path (string replace --all \\ \\\\ $PWD)
+ command awk -v path=$path -v now=(date +%s) -F "|" '
+ BEGIN {
+ rank[path] = 1
+ time[path] = now
+ }
+ $2 >= 1 {
+ if( $1 == path ) {
+ rank[$1] = $2 + 1
+ time[$1] = now
+ }
+ else {
+ rank[$1] = $2
+ time[$1] = $3
+ }
+ count += $2
+ }
+ END {
+ if( count > 1000 ) {
+ for( i in rank ) print i "|" 0.9*rank[i] "|" time[i] # aging
+ }
+ else for( i in rank ) print i "|" rank[i] "|" time[i]
+ }
+ ' $Z_DATA 2>/dev/null >$tmpfile
+
+ if test ! -z "$Z_OWNER"
+ chown $Z_OWNER:(id -ng $Z_OWNER) $tmpfile
+ end
+ #
+ # Don't use redirection here as it can lead to a race condition where $Z_DATA is clobbered.
+ # Note: There is a still a possible race condition where an old version of $Z_DATA is
+ # read by one instance of Fish before another instance of Fish writes its copy.
+ #
+ command mv $tmpfile $Z_DATA
+ or command rm $tmpfile
+ end
+end
diff --git a/fish/functions/__z_clean.fish b/fish/functions/__z_clean.fish
new file mode 100644
index 0000000..ae1721a
--- /dev/null
+++ b/fish/functions/__z_clean.fish
@@ -0,0 +1,11 @@
+function __z_clean -d "Clean up .z file to remove paths no longer valid"
+ set -l tmpfile (mktemp $Z_DATA.XXXXXX)
+
+ if test -f $tmpfile
+ while read line
+ set -l path (string split '|' $line)[1]
+ test -d $path; and echo $line
+ end <$Z_DATA >$tmpfile
+ command mv -f $tmpfile $Z_DATA
+ end
+end
diff --git a/fish/functions/__z_complete.fish b/fish/functions/__z_complete.fish
new file mode 100644
index 0000000..a626456
--- /dev/null
+++ b/fish/functions/__z_complete.fish
@@ -0,0 +1,13 @@
+function __z_complete -d "add completions"
+ complete -c $Z_CMD -a "(__z -l | string replace -r '^\\S*\\s*' '')" -f -k
+ complete -c $ZO_CMD -a "(__z -l | string replace -r '^\\S*\\s*' '')" -f -k
+
+ complete -c $Z_CMD -s c -l clean -d "Cleans out $Z_DATA"
+ complete -c $Z_CMD -s e -l echo -d "Prints best match, no cd"
+ complete -c $Z_CMD -s l -l list -d "List matches, no cd"
+ complete -c $Z_CMD -s p -l purge -d "Purges $Z_DATA"
+ complete -c $Z_CMD -s r -l rank -d "Searches by rank, cd"
+ complete -c $Z_CMD -s t -l recent -d "Searches by recency, cd"
+ complete -c $Z_CMD -s h -l help -d "Print help"
+ complete -c $Z_CMD -s x -l delete -d "Removes the current directory from $Z_DATA"
+end
diff --git a/fish/functions/_sponge_clear_state.fish b/fish/functions/_sponge_clear_state.fish
new file mode 100644
index 0000000..c6a07da
--- /dev/null
+++ b/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/fish/functions/_sponge_on_exit.fish b/fish/functions/_sponge_on_exit.fish
new file mode 100644
index 0000000..0c6cc19
--- /dev/null
+++ b/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/fish/functions/_sponge_on_postexec.fish b/fish/functions/_sponge_on_postexec.fish
new file mode 100644
index 0000000..1d67935
--- /dev/null
+++ b/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/fish/functions/_sponge_on_preexec.fish b/fish/functions/_sponge_on_preexec.fish
new file mode 100644
index 0000000..a866491
--- /dev/null
+++ b/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/fish/functions/_sponge_on_prompt.fish b/fish/functions/_sponge_on_prompt.fish
new file mode 100644
index 0000000..03e989a
--- /dev/null
+++ b/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/fish/functions/_sponge_remove_from_history.fish b/fish/functions/_sponge_remove_from_history.fish
new file mode 100644
index 0000000..4d4f827
--- /dev/null
+++ b/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/fish/functions/fisher.fish b/fish/functions/fisher.fish
new file mode 100644
index 0000000..e915cb8
--- /dev/null
+++ b/fish/functions/fisher.fish
@@ -0,0 +1,240 @@
+function fisher --argument-names cmd --description "A plugin manager for Fish"
+ set --query fisher_path || set --local fisher_path $__fish_config_dir
+ set --local fisher_version 4.4.5
+ set --local fish_plugins $__fish_config_dir/fish_plugins
+
+ switch "$cmd"
+ case -v --version
+ echo "fisher, version $fisher_version"
+ case "" -h --help
+ echo "Usage: fisher install Install plugins"
+ echo " fisher remove Remove installed plugins"
+ echo " fisher update Update installed plugins"
+ echo " fisher update Update all installed plugins"
+ echo " fisher list [] List installed plugins matching regex"
+ echo "Options:"
+ echo " -v, --version Print version"
+ echo " -h, --help Print this help message"
+ echo "Variables:"
+ echo " \$fisher_path Plugin installation path. Default: $__fish_config_dir" | string replace --regex -- $HOME \~
+ case ls list
+ string match --entire --regex -- "$argv[2]" $_fisher_plugins
+ case install update remove
+ isatty || read --local --null --array stdin && set --append argv $stdin
+
+ set --local install_plugins
+ set --local update_plugins
+ set --local remove_plugins
+ set --local arg_plugins $argv[2..-1]
+ set --local old_plugins $_fisher_plugins
+ set --local new_plugins
+
+ test -e $fish_plugins && set --local file_plugins (string match --regex -- '^[^\s]+$' <$fish_plugins | string replace -- \~ ~)
+
+ if ! set --query argv[2]
+ if test "$cmd" != update
+ echo "fisher: Not enough arguments for command: \"$cmd\"" >&2 && return 1
+ else if ! set --query file_plugins
+ echo "fisher: \"$fish_plugins\" file not found: \"$cmd\"" >&2 && return 1
+ end
+ set arg_plugins $file_plugins
+ end
+
+ for plugin in $arg_plugins
+ set plugin (test -e "$plugin" && realpath $plugin || string lower -- $plugin)
+ contains -- "$plugin" $new_plugins || set --append new_plugins $plugin
+ end
+
+ if set --query argv[2]
+ for plugin in $new_plugins
+ if contains -- "$plugin" $old_plugins
+ test "$cmd" = remove &&
+ set --append remove_plugins $plugin ||
+ set --append update_plugins $plugin
+ else if test "$cmd" = install
+ set --append install_plugins $plugin
+ else
+ echo "fisher: Plugin not installed: \"$plugin\"" >&2 && return 1
+ end
+ end
+ else
+ for plugin in $new_plugins
+ contains -- "$plugin" $old_plugins &&
+ set --append update_plugins $plugin ||
+ set --append install_plugins $plugin
+ end
+
+ for plugin in $old_plugins
+ contains -- "$plugin" $new_plugins || set --append remove_plugins $plugin
+ end
+ end
+
+ set --local pid_list
+ set --local source_plugins
+ set --local fetch_plugins $update_plugins $install_plugins
+ set --local fish_path (status fish-path)
+
+ echo (set_color --bold)fisher $cmd version $fisher_version(set_color normal)
+
+ for plugin in $fetch_plugins
+ set --local source (command mktemp -d)
+ set --append source_plugins $source
+
+ command mkdir -p $source/{completions,conf.d,themes,functions}
+
+ $fish_path --command "
+ if test -e $plugin
+ command cp -Rf $plugin/* $source
+ else
+ set temp (command mktemp -d)
+ set repo (string split -- \@ $plugin) || set repo[2] HEAD
+
+ if set path (string replace --regex -- '^(https://)?gitlab.com/' '' \$repo[1])
+ set name (string split -- / \$path)[-1]
+ set url https://gitlab.com/\$path/-/archive/\$repo[2]/\$name-\$repo[2].tar.gz
+ else
+ set url https://api.github.com/repos/\$repo[1]/tarball/\$repo[2]
+ end
+
+ echo Fetching (set_color --underline)\$url(set_color normal)
+
+ if command curl -q --silent -L \$url | command tar -xzC \$temp -f - 2>/dev/null
+ command cp -Rf \$temp/*/* $source
+ else
+ echo fisher: Invalid plugin name or host unavailable: \\\"$plugin\\\" >&2
+ command rm -rf $source
+ end
+
+ command rm -rf \$temp
+ end
+
+ set files $source/* && string match --quiet --regex -- .+\.fish\\\$ \$files
+ " &
+
+ set --append pid_list (jobs --last --pid)
+ end
+
+ wait $pid_list 2>/dev/null
+
+ for plugin in $fetch_plugins
+ if set --local source $source_plugins[(contains --index -- "$plugin" $fetch_plugins)] && test ! -e $source
+ if set --local index (contains --index -- "$plugin" $install_plugins)
+ set --erase install_plugins[$index]
+ else
+ set --erase update_plugins[(contains --index -- "$plugin" $update_plugins)]
+ end
+ end
+ end
+
+ for plugin in $update_plugins $remove_plugins
+ if set --local index (contains --index -- "$plugin" $_fisher_plugins)
+ set --local plugin_files_var _fisher_(string escape --style=var -- $plugin)_files
+
+ if contains -- "$plugin" $remove_plugins
+ for name in (string replace --filter --regex -- '.+/conf\.d/([^/]+)\.fish$' '$1' $$plugin_files_var)
+ emit {$name}_uninstall
+ end
+ printf "%s\n" Removing\ (set_color red --bold)$plugin(set_color normal) " "$$plugin_files_var | string replace -- \~ ~
+ set --erase _fisher_plugins[$index]
+ end
+
+ command rm -rf (string replace -- \~ ~ $$plugin_files_var)
+
+ functions --erase (string replace --filter --regex -- '.+/functions/([^/]+)\.fish$' '$1' $$plugin_files_var)
+
+ for name in (string replace --filter --regex -- '.+/completions/([^/]+)\.fish$' '$1' $$plugin_files_var)
+ complete --erase --command $name
+ end
+
+ set --erase $plugin_files_var
+ end
+ end
+
+ if set --query update_plugins[1] || set --query install_plugins[1]
+ command mkdir -p $fisher_path/{functions,themes,conf.d,completions}
+ end
+
+ for plugin in $update_plugins $install_plugins
+ set --local source $source_plugins[(contains --index -- "$plugin" $fetch_plugins)]
+ set --local files $source/{functions,themes,conf.d,completions}/*
+
+ if set --local index (contains --index -- $plugin $install_plugins)
+ set --local user_files $fisher_path/{functions,themes,conf.d,completions}/*
+ set --local conflict_files
+
+ for file in (string replace -- $source/ $fisher_path/ $files)
+ contains -- $file $user_files && set --append conflict_files $file
+ end
+
+ if set --query conflict_files[1] && set --erase install_plugins[$index]
+ echo -s "fisher: Cannot install \"$plugin\": please remove or move conflicting files first:" \n" "$conflict_files >&2
+ continue
+ end
+ end
+
+ for file in (string replace -- $source/ "" $files)
+ command cp -RLf $source/$file $fisher_path/$file
+ end
+
+ set --local plugin_files_var _fisher_(string escape --style=var -- $plugin)_files
+
+ set --query files[1] && set --universal $plugin_files_var (string replace -- $source $fisher_path $files | string replace -- ~ \~)
+
+ contains -- $plugin $_fisher_plugins || set --universal --append _fisher_plugins $plugin
+ contains -- $plugin $install_plugins && set --local event install || set --local event update
+
+ printf "%s\n" Installing\ (set_color --bold)$plugin(set_color normal) " "$$plugin_files_var | string replace -- \~ ~
+
+ for file in (string match --regex -- '.+/[^/]+\.fish$' $$plugin_files_var | string replace -- \~ ~)
+ source $file
+ if set --local name (string replace --regex -- '.+conf\.d/([^/]+)\.fish$' '$1' $file)
+ emit {$name}_$event
+ end
+ end
+ end
+
+ command rm -rf $source_plugins
+
+ if set --query _fisher_plugins[1]
+ set --local commit_plugins
+
+ for plugin in $file_plugins
+ contains -- (string lower -- $plugin) (string lower -- $_fisher_plugins) && set --append commit_plugins $plugin
+ end
+
+ for plugin in $_fisher_plugins
+ contains -- (string lower -- $plugin) (string lower -- $commit_plugins) || set --append commit_plugins $plugin
+ end
+
+ string replace --regex -- $HOME \~ $commit_plugins >$fish_plugins
+ else
+ set --erase _fisher_plugins
+ command rm -f $fish_plugins
+ end
+
+ set --local total (count $install_plugins) (count $update_plugins) (count $remove_plugins)
+
+ test "$total" != "0 0 0" && echo (string join ", " (
+ test $total[1] = 0 || echo "Installed $total[1]") (
+ test $total[2] = 0 || echo "Updated $total[2]") (
+ test $total[3] = 0 || echo "Removed $total[3]")
+ ) plugin/s
+ case \*
+ echo "fisher: Unknown command: \"$cmd\"" >&2 && return 1
+ end
+end
+
+if ! set --query _fisher_upgraded_to_4_4
+ set --universal _fisher_upgraded_to_4_4
+ if functions --query _fisher_list
+ set --query XDG_DATA_HOME[1] || set --local XDG_DATA_HOME ~/.local/share
+ command rm -rf $XDG_DATA_HOME/fisher
+ functions --erase _fisher_{list,plugin_parse}
+ fisher update >/dev/null 2>/dev/null
+ else
+ for var in (set --names | string match --entire --regex '^_fisher_.+_files$')
+ set $var (string replace -- ~ \~ $$var)
+ end
+ functions --erase _fisher_fish_postexec
+ end
+end
diff --git a/fish/functions/lsl.fish b/fish/functions/lsl.fish
new file mode 100644
index 0000000..ce0e39e
--- /dev/null
+++ b/fish/functions/lsl.fish
@@ -0,0 +1,3 @@
+function lsl --wraps=eza --wraps='eza -l' --description 'alias lsl eza -l'
+ eza -l $argv
+end
diff --git a/fish/functions/sponge_filter_failed.fish b/fish/functions/sponge_filter_failed.fish
new file mode 100644
index 0000000..be26e5d
--- /dev/null
+++ b/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/fish/functions/sponge_filter_matched.fish b/fish/functions/sponge_filter_matched.fish
new file mode 100644
index 0000000..c3c7ea2
--- /dev/null
+++ b/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
diff --git a/git/gitconfig b/git/gitconfig
new file mode 100644
index 0000000..6b8f05a
--- /dev/null
+++ b/git/gitconfig
@@ -0,0 +1,14 @@
+[core]
+ excludesFile = ~/.gitignore
+[push]
+ autoSetupRemote = true
+[user]
+ name = {{ git_name }}
+ email = {{ git_email }}
+[filter "lfs"]
+ clean = git-lfs clean -- %f
+ smudge = git-lfs smudge -- %f
+ process = git-lfs filter-process
+ required = true
+[init]
+ defaultBranch = main
diff --git a/git/gitignore b/git/gitignore
new file mode 100644
index 0000000..aa05008
--- /dev/null
+++ b/git/gitignore
@@ -0,0 +1,2 @@
+.history/
+
diff --git a/htop/htoprc b/htop/htoprc
new file mode 100644
index 0000000..ed8f13f
--- /dev/null
+++ b/htop/htoprc
@@ -0,0 +1,53 @@
+# Beware! This file is rewritten by htop when settings are changed in the interface.
+# The parser is also very primitive, and not human-friendly.
+htop_version=3.3.0
+config_reader_min_version=3
+fields=0 48 17 18 38 39 2 46 47 49 1
+hide_kernel_threads=1
+hide_userland_threads=0
+hide_running_in_container=0
+shadow_other_users=0
+show_thread_names=0
+show_program_path=1
+highlight_base_name=0
+highlight_deleted_exe=1
+shadow_distribution_path_prefix=0
+highlight_megabytes=1
+highlight_threads=1
+highlight_changes=0
+highlight_changes_delay_secs=5
+find_comm_in_cmdline=1
+strip_exe_from_cmdline=1
+show_merged_command=0
+header_margin=1
+screen_tabs=1
+detailed_cpu_time=0
+cpu_count_from_one=0
+show_cpu_usage=1
+show_cpu_frequency=0
+update_process_names=0
+account_guest_in_cpu_meter=0
+color_scheme=0
+enable_mouse=1
+delay=15
+hide_function_bar=0
+header_layout=two_50_50
+column_meters_0=LeftCPUs2 Memory Swap
+column_meter_modes_0=1 1 1
+column_meters_1=RightCPUs2 Tasks LoadAverage Uptime
+column_meter_modes_1=1 2 2 2
+tree_view=0
+sort_key=46
+tree_sort_key=0
+sort_direction=-1
+tree_sort_direction=1
+tree_view_always_by_pid=0
+all_branches_collapsed=0
+screen:Main=PID USER PRIORITY NICE M_VIRT M_RESIDENT STATE PERCENT_CPU PERCENT_MEM TIME Command
+.sort_key=PERCENT_CPU
+.tree_sort_key=PID
+.tree_view_always_by_pid=0
+.tree_view=0
+.sort_direction=-1
+.tree_sort_direction=1
+.all_branches_collapsed=0
diff --git a/nvim/init.lua b/nvim/init.lua
new file mode 100644
index 0000000..551ec67
--- /dev/null
+++ b/nvim/init.lua
@@ -0,0 +1,2 @@
+require("config.lazy")
+
diff --git a/nvim/lazy-lock.json b/nvim/lazy-lock.json
new file mode 100644
index 0000000..19c6f69
--- /dev/null
+++ b/nvim/lazy-lock.json
@@ -0,0 +1,5 @@
+{
+ "hop.nvim": { "branch": "master", "commit": "08ddca799089ab96a6d1763db0b8adc5320bf050" },
+ "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" },
+ "mini.nvim": { "branch": "main", "commit": "94cae4660a8b2d95dbbd56e1fbc6fcfa2716d152" }
+}
diff --git a/nvim/lua/config/lazy.lua b/nvim/lua/config/lazy.lua
new file mode 100644
index 0000000..f5ee74c
--- /dev/null
+++ b/nvim/lua/config/lazy.lua
@@ -0,0 +1,35 @@
+-- Bootstrap lazy.nvim
+local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
+if not (vim.uv or vim.loop).fs_stat(lazypath) then
+ local lazyrepo = "https://github.com/folke/lazy.nvim.git"
+ local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
+ if vim.v.shell_error ~= 0 then
+ vim.api.nvim_echo({
+ { "Failed to clone lazy.nvim:\n", "ErrorMsg" },
+ { out, "WarningMsg" },
+ { "\nPress any key to exit..." },
+ }, true, {})
+ vim.fn.getchar()
+ os.exit(1)
+ end
+end
+vim.opt.rtp:prepend(lazypath)
+
+-- Make sure to setup `mapleader` and `maplocalleader` before
+-- loading lazy.nvim so that mappings are correct.
+-- This is also a good place to setup other settings (vim.opt)
+vim.g.mapleader = " "
+vim.g.maplocalleader = "\\"
+
+-- Setup lazy.nvim
+require("lazy").setup({
+ spec = {
+ -- import your plugins
+ { import = "plugins" },
+ },
+ -- Configure any other settings here. See the documentation for more details.
+ -- colorscheme that will be used when installing plugins.
+ install = { colorscheme = { "habamax" } },
+ -- automatically check for plugin updates
+ checker = { enabled = true },
+})
diff --git a/nvim/lua/plugins/hop.lua b/nvim/lua/plugins/hop.lua
new file mode 100644
index 0000000..7fdaf0c
--- /dev/null
+++ b/nvim/lua/plugins/hop.lua
@@ -0,0 +1,61 @@
+
+return {
+ 'smoka7/hop.nvim',
+ version = "*",
+ opts = {
+ keys = 'etovxqpdygfblzhckisuran'
+ },
+ config = function()
+ local hop = require('hop')
+ hop.setup()
+ local directions = require('hop.hint').HintDirection
+ vim.keymap.set('', '', function ()
+ hop.hint_words({})
+ end, {remap=true})
+
+ vim.keymap.set('', '', function ()
+ vim.api.nvim_echo({{" Enter letter: ", "Normal"}}, false, {})
+ local char = vim.fn.nr2char(vim.fn.getchar())
+
+ if not char:match('^[%w%p]$') then
+ vim.api.nvim_echo({{" Invalid input!", "ErrorMsg"}}, false, {})
+ return
+ end
+ vim.api.nvim_echo({}, false, {})
+
+ local pattern = '\\%(\\_^\\|[[:space:]{}.|>
+//
+// session_name "My singleton session"
+
+// When `session_name` is provided, attaches to that session
+// if it is already running or creates it otherwise.
+// Default: false
+//
+// attach_to_session true
+
+// Toggle between having Zellij lay out panes according to a predefined set of layouts whenever possible
+// Options:
+// - true (default)
+// - false
+//
+// auto_layout false
+
+// Whether sessions should be serialized to the cache folder (including their tabs/panes, cwds and running commands) so that they can later be resurrected
+// Options:
+// - true (default)
+// - false
+//
+// session_serialization false
+
+// Whether pane viewports are serialized along with the session, default is false
+// Options:
+// - true
+// - false (default)
+//
+// serialize_pane_viewport false
+
+// Scrollback lines to serialize along with the pane viewport when serializing sessions, 0
+// defaults to the scrollback size. If this number is higher than the scrollback size, it will
+// also default to the scrollback size. This does nothing if `serialize_pane_viewport` is not true.
+//
+// scrollback_lines_to_serialize 10000
+
+// Enable or disable the rendering of styled and colored underlines (undercurl).
+// May need to be disabled for certain unsupported terminals
+// (Requires restart)
+// Default: true
+//
+// styled_underlines false
+
+// How often in seconds sessions are serialized
+//
+// serialization_interval 10000
+
+// Enable or disable writing of session metadata to disk (if disabled, other sessions might not know
+// metadata info on this session)
+// (Requires restart)
+// Default: false
+//
+// disable_session_metadata false
+
+// Enable or disable support for the enhanced Kitty Keyboard Protocol (the host terminal must also support it)
+// (Requires restart)
+// Default: true (if the host terminal supports it)
+//
+// support_kitty_keyboard_protocol false
+// Whether to make sure a local web server is running when a new Zellij session starts.
+// This web server will allow creating new sessions and attaching to existing ones that have
+// opted in to being shared in the browser.
+// When enabled, navigate to http://127.0.0.1:8082
+// (Requires restart)
+//
+// Note: a local web server can still be manually started from within a Zellij session or from the CLI.
+// If this is not desired, one can use a version of Zellij compiled without
+// `web_server_capability`
+//
+// Possible values:
+// - true
+// - false
+// Default: false
+//
+// web_server false
+// Whether to allow sessions started in the terminal to be shared through a local web server, assuming one is
+// running (see the `web_server` option for more details).
+// (Requires restart)
+//
+// Note: This is an administrative separation and not intended as a security measure.
+//
+// Possible values:
+// - "on" (allow web sharing through the local web server if it
+// is online)
+// - "off" (do not allow web sharing unless sessions explicitly opt-in to it)
+// - "disabled" (do not allow web sharing and do not permit sessions started in the terminal to opt-in to it)
+// Default: "off"
+//
+// web_sharing "off"
+// A path to a certificate file to be used when setting up the web client to serve the
+// connection over HTTPs
+//
+// web_server_cert "/path/to/cert.pem"
+// A path to a key file to be used when setting up the web client to serve the
+// connection over HTTPs
+//
+// web_server_key "/path/to/key.pem"
+/// Whether to enforce https connections to the web server when it is bound to localhost
+/// (127.0.0.0/8)
+///
+/// Note: https is ALWAYS enforced when bound to non-local interfaces
+///
+/// Default: false
+//
+// enforce_https_for_localhost false
+
+// Whether to stack panes when resizing beyond a certain size
+// Default: true
+//
+// stacked_resize false
+
+// Whether to show tips on startup
+// Default: true
+//
+show_startup_tips false
+
+// Whether to show release notes on first version run
+// Default: true
+//
+// show_release_notes false
+
+// Whether to enable mouse hover effects and pane grouping functionality
+// default is true
+// advanced_mouse_actions false
+
+// The ip address the web server should listen on when it starts
+// Default: "127.0.0.1"
+// (Requires restart)
+// web_server_ip "127.0.0.1"
+
+// The port the web server should listen on when it starts
+// Default: 8082
+// (Requires restart)
+// web_server_port 8082
+
+// A command to run (will be wrapped with sh -c and provided the RESURRECT_COMMAND env variable)
+// after Zellij attempts to discover a command inside a pane when resurrecting sessions, the STDOUT
+// of this command will be used instead of the discovered RESURRECT_COMMAND
+// can be useful for removing wrappers around commands
+// Note: be sure to escape backslashes and similar characters properly
+// post_command_discovery_hook "echo $RESURRECT_COMMAND | sed "