diff --git a/fish/completions/__gitnow_completions.fish b/fish/completions/__gitnow_completions.fish new file mode 100644 index 0000000..5575fe1 --- /dev/null +++ b/fish/completions/__gitnow_completions.fish @@ -0,0 +1,76 @@ +source $__fish_data_dir/completions/git.fish + +# Merge command + +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" + +# Move command + +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 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" + + +# Tag command + +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" + +# TODO: pre-release versions are not supported yet +# complete -f -x -c tag \ +# -s a -l premajor \ +# -d "Tag auto-incrementing a premajor version number" + +# complete -f -x -c tag \ +# -s b -l preminor \ +# -d "Tag auto-incrementing a preminor version number" + +# complete -f -x -c tag \ +# -s c -l prepatch \ +# -d "Tag auto-incrementing a prepatch version number" diff --git a/fish/completions/fzf_configure_bindings.fish b/fish/completions/fzf_configure_bindings.fish new file mode 100644 index 0000000..a78fd54 --- /dev/null +++ b/fish/completions/fzf_configure_bindings.fish @@ -0,0 +1,7 @@ +complete fzf_configure_bindings --no-files +complete fzf_configure_bindings --long help --short h --description "Print help" +complete fzf_configure_bindings --long directory --description "Change the key binding for searching directory" +complete fzf_configure_bindings --long git_log --description "Change the key binding for searching git log" +complete fzf_configure_bindings --long git_status --description "Change the key binding for searching git status" +complete fzf_configure_bindings --long history --description "Change the key binding for searching history" +complete fzf_configure_bindings --long variables --description "Change the key binding for searching variables" diff --git a/fish/completions/license.fish b/fish/completions/license.fish new file mode 100644 index 0000000..d0bb95e --- /dev/null +++ b/fish/completions/license.fish @@ -0,0 +1,13 @@ +complete -c license -f -n "__fish_use_subcommand" -a mit +complete -c license -f -n "__fish_use_subcommand" -a gpl-3.0 +complete -c license -f -n "__fish_use_subcommand" -a gpl-2.0 +complete -c license -f -n "__fish_use_subcommand" -a agpl-3.0 +complete -c license -f -n "__fish_use_subcommand" -a unlicense +complete -c license -f -n "__fish_use_subcommand" -a apache-2.0 +complete -c license -f -n "__fish_use_subcommand" -a epl-1.0 +complete -c license -f -n "__fish_use_subcommand" -a bsd-2-clause +complete -c license -f -n "__fish_use_subcommand" -a mpl-2.0 +complete -c license -f -n "__fish_use_subcommand" -a bsd-3-clause +complete -c license -f -n "__fish_use_subcommand" -a lgpl-3.0 +complete -c license -f -n "__fish_use_subcommand" -a lgpl-2.1 +complete -c license -f -n "__fish_use_subcommand" -a wtfpl diff --git a/fish/completions/replay.fish b/fish/completions/replay.fish new file mode 100644 index 0000000..d4589a9 --- /dev/null +++ b/fish/completions/replay.fish @@ -0,0 +1,3 @@ +complete --command replay --no-files +complete --command replay --exclusive --long version --description "Print version" +complete --command replay --exclusive --long help --description "Print help" diff --git a/fish/conf.d/.gitnow b/fish/conf.d/.gitnow new file mode 100644 index 0000000..748ca9d --- /dev/null +++ b/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/fish/conf.d/autopair.fish b/fish/conf.d/autopair.fish new file mode 100644 index 0000000..abb4bf3 --- /dev/null +++ b/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/fish/conf.d/dracula.fish b/fish/conf.d/dracula.fish new file mode 100644 index 0000000..39a86e8 --- /dev/null +++ b/fish/conf.d/dracula.fish @@ -0,0 +1,50 @@ +# Dracula Color Palette +set -l foreground f8f8f2 +set -l selection 44475a +set -l comment 6272a4 +set -l red ff5555 +set -l orange ffb86c +set -l yellow f1fa8c +set -l green 50fa7b +set -l purple bd93f9 +set -l cyan 8be9fd +set -l pink ff79c6 + +# Syntax Highlighting Colors +set -g fish_color_normal $foreground +set -g fish_color_command $cyan +set -g fish_color_keyword $pink +set -g fish_color_quote $yellow +set -g fish_color_redirection $foreground +set -g fish_color_end $orange +set -g fish_color_error $red +set -g fish_color_param $purple +set -g fish_color_comment $comment +set -g fish_color_selection --background=$selection +set -g fish_color_search_match --background=$selection +set -g fish_color_operator $green +set -g fish_color_escape $pink +set -g fish_color_autosuggestion $comment +set -g fish_color_cancel $red --reverse +set -g fish_color_option $orange + +# Default Prompt Colors +set -g fish_color_cwd $green +set -g fish_color_host $purple +set -g fish_color_host_remote $purple +set -g fish_color_user $cyan + +# Completion Pager Colors +set -g fish_pager_color_progress $comment +set -g fish_pager_color_background +set -g fish_pager_color_prefix $cyan +set -g fish_pager_color_completion $foreground +set -g fish_pager_color_description $comment +set -g fish_pager_color_selected_background --background=$selection +set -g fish_pager_color_selected_prefix $cyan +set -g fish_pager_color_selected_completion $foreground +set -g fish_pager_color_selected_description $comment +set -g fish_pager_color_secondary_background +set -g fish_pager_color_secondary_prefix $cyan +set -g fish_pager_color_secondary_completion $foreground +set -g fish_pager_color_secondary_description $comment diff --git a/fish/conf.d/fish-ssh-agent.fish b/fish/conf.d/fish-ssh-agent.fish new file mode 100644 index 0000000..719087a --- /dev/null +++ b/fish/conf.d/fish-ssh-agent.fish @@ -0,0 +1,7 @@ +if test -z "$SSH_ENV" + set -xg SSH_ENV $HOME/.ssh/environment +end + +if not __ssh_agent_is_started + __ssh_agent_start +end diff --git a/fish/conf.d/fish_frozen_key_bindings.fish b/fish/conf.d/fish_frozen_key_bindings.fish new file mode 100644 index 0000000..495aee9 --- /dev/null +++ b/fish/conf.d/fish_frozen_key_bindings.fish @@ -0,0 +1,14 @@ +# This file was created by fish when upgrading to version 4.3, to migrate +# the 'fish_key_bindings' variable from its old default scope (universal) +# to its new default scope (global). We recommend you delete this file +# and configure key bindings in ~/.config/fish/config.fish if needed. + +# set --global fish_key_bindings fish_default_key_bindings + +# Prior to version 4.3, fish shipped an event handler that runs +# `set --universal fish_key_bindings fish_default_key_bindings` +# whenever the fish_key_bindings variable is erased. +# This means that as long as any fish < 4.3 is still running on this system, +# we cannot complete the migration. +# As a workaround, erase the universal variable at every shell startup. +set --erase --universal fish_key_bindings diff --git a/fish/conf.d/fzf.fish b/fish/conf.d/fzf.fish new file mode 100644 index 0000000..8156c11 --- /dev/null +++ b/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/fish/conf.d/gitnow.fish b/fish/conf.d/gitnow.fish new file mode 100644 index 0000000..aa767f5 --- /dev/null +++ b/fish/conf.d/gitnow.fish @@ -0,0 +1,684 @@ +# GitNow β€” Speed up your Git workflow. 🐠 +# https://github.com/joseluisq/gitnow + +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" + 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" + 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" + 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" + 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" + 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" + 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" + 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 + + 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 -h --help + echo "NAME" + echo " Gitnow: move - Switch from current branch to another but stashing uncommitted changes" + echo "EXAMPLES" + 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 " -h --help Show information about the options for this command" + return + case -\* + case '*' + set v_branch $v + end + 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 + + command git checkout $v_branch + + # --no-apply-stash + if test -n "$v_no_apply_stash" + echo "Stashed changes were not applied. 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 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/fish/conf.d/gitnow_config.fish b/fish/conf.d/gitnow_config.fish new file mode 100644 index 0000000..9478f8d --- /dev/null +++ b/fish/conf.d/gitnow_config.fish @@ -0,0 +1,32 @@ +# GitNow β€” Speed up your Git workflow. 🐠 +# https://github.com/joseluisq/gitnow + +set -g gitnow_version 2.10.0 + +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" +set -q fish_functions; or set -g fish_functions "$fish_config/functions" +set -q fish_completions; or set -g fish_completions "$fish_config/completions" +set -q GITNOW_CONFIG_FILE; or set -g GITNOW_CONFIG_FILE ~/.gitnow + +if functions -q __fundle_plugins_dir + set -l fundledir (__fundle_plugins_dir) + source "$fundledir/joseluisq/gitnow/functions/__gitnow_functions.fish" + source "$fundledir/joseluisq/gitnow/functions/__gitnow_manual.fish" + source "$fundledir/joseluisq/gitnow/functions/__gitnow_config_file.fish" + source "$fundledir/joseluisq/gitnow/completions/__gitnow_completions.fish" +else + source "$fish_functions/__gitnow_functions.fish" + source "$fish_functions/__gitnow_manual.fish" + source "$fish_functions/__gitnow_config_file.fish" + source "$fish_completions/__gitnow_completions.fish" +end + +__gitnow_read_config diff --git a/fish/config-dev.fish b/fish/config-dev.fish new file mode 100644 index 0000000..7b0243b --- /dev/null +++ b/fish/config-dev.fish @@ -0,0 +1,14 @@ +if type -q docker + + # PHP in container + alias dcomposer="docker run --rm --interactive --tty --volume \$PWD:/app --volume \$HOME/.composer:/tmp composer:latest composer" + alias dphp="docker run --rm --interactive --tty --volume \$PWD:/app --volume /Users:/Users composer:latest php" + alias dphp8="docker run --rm --interactive --tty --volume \$PWD:/app composer:latest php" + alias dphp7="docker run --rm --interactive --tty --volume \$PWD:/app --workdir /app php:7.4-cli php" + alias dlaravel="docker run --rm --interactive --tty --volume \$PWD:/app --volume \$HOME/.composer:/tmp composer:latest /tmp/vendor/bin/laravel" + + # azure-cli + # alias az="docker run --rm --name azure-cli -v \$HOME/.azure/config:/.azure/config bitnami/azure-cli:latest" + + # alias aws="docker run --rm --name aws-cli -v \$HOME/.aws/config:/.aws/config bitnami/aws-cli:latest" +end diff --git a/fish/config-osx.fish b/fish/config-osx.fish index 1bb04a1..257c6f6 100644 --- a/fish/config-osx.fish +++ b/fish/config-osx.fish @@ -1,26 +1,6 @@ -if type -q exa - alias ls "exa -g --icons --classify" - alias lsa "ls -a" - alias ll "exa -l -g --icons --classify" - alias lla "ll -a" +if type -q eza + alias ls "eza -g --icons --classify --group-directories-first" + alias lsa "ls -a" + alias ll "ls -l" + alias lla "ll -a" end - -if type -q ghq - alias ghqcd="cd \$(ghq list --full-path | fzf)" -end - -if type -q docker - - # PHP in container - alias dcomposer="docker run --rm --interactive --tty --volume \$PWD:/app --volume \$HOME/.composer:/tmp composer:latest composer" - alias dphp="docker run --rm --interactive --tty --volume \$PWD:/app --volume /Users:/Users composer:latest php" - alias dphp8="docker run --rm --interactive --tty --volume \$PWD:/app composer:latest php" - alias dphp7="docker run --rm --interactive --tty --volume \$PWD:/app --workdir /app php:7.4-cli php" - alias dlaravel="docker run --rm --interactive --tty --volume \$PWD:/app --volume \$HOME/.composer:/tmp composer:latest /tmp/vendor/bin/laravel" - -end - -if type -q thefuck - thefuck --alias | source -end - diff --git a/fish/config.fish b/fish/config.fish index 274c1a4..d2d56f5 100644 --- a/fish/config.fish +++ b/fish/config.fish @@ -1,43 +1,74 @@ if status is-interactive - # Commands to run in interactive sessions can go here - set fish_greeting "" - set -gx TERM xterm-256color + # Commands to run in interactive sessions can go here + set fish_greeting "" + set -gx TERM xterm-256color - # theme - set -g theme_color_scheme dracula - set -g fish_prompt_pwd_dir_length 1 - set -g theme_display_user yes - set -g theme_hide_hostname no - set -g theme_hostname always + # theme + set -g theme_color_scheme dracula + set -g fish_prompt_pwd_dir_length 1 + set -g theme_display_user yes + set -g theme_hide_hostname no + set -g theme_hostname always - # set default editor to nvim - set -gx EDITOR nvim - - fzf_configure_bindings - - # starship prompt - switch (uname) - case Darwin - if test -x /opt/homebrew/bin/starship; - /opt/homebrew/bin/starship init fish | source - end - case Linux - case '*' - end + # starship prompt + switch (uname) + case Darwin + if test -x /opt/homebrew/bin/starship + /opt/homebrew/bin/starship init fish | source + end + case Linux + case '*' + end end +# include devenv +source (dirname (status --current-filename))/config-dev.fish + # set PATH and load os-specify config switch (uname) - case Darwin - if test -x /opt/homebrew/bin/brew; - eval "$(/opt/homebrew/bin/brew shellenv)" - set -gx PATH ~/bin $PATH - source (dirname (status --current-filename))/config-osx.fish - end - case Linux - source (dirname (status --current-filename))/config-linux.fish - case '*' - source (dirname (status --current-filename))/config-windows.fish + case Darwin + if test -x /opt/homebrew/bin/brew + eval "$(/opt/homebrew/bin/brew shellenv)" + set -gx PATH ~/bin $PATH + source (dirname (status --current-filename))/config-osx.fish + end + case Linux + source (dirname (status --current-filename))/config-linux.fish + case '*' + source (dirname (status --current-filename))/config-windows.fish end +# using less instead of more +export LESS='-R' +alias more='less' + +# set default editor to nvim +set -gx EDITOR nvim + +fzf_configure_bindings + +# ghq functions +if type -q ghq + alias ghqcd="cd \$(ghq list --full-path | fzf)" +end + +if type -q thefuck + thefuck --alias | source +end + + +# init zoxide +if type -q zoxide + zoxide init fish | source +end + +# init yazi +function y + set tmp (mktemp -t "yazi-cwd.XXXXXX") + yazi $argv --cwd-file="$tmp" + if set cwd (command cat -- "$tmp"); and [ -n "$cwd" ]; and [ "$cwd" != "$PWD" ] + builtin cd -- "$cwd" + end + rm -f -- "$tmp" +end diff --git a/fish/fish_plugins b/fish/fish_plugins index 3f278d2..a221c8c 100644 --- a/fish/fish_plugins +++ b/fish/fish_plugins @@ -1,5 +1,4 @@ PatrickF1/fzf.fish -jethrokuan/z jorgebucaran/autopair.fish dracula/fish jorgebucaran/replay.fish diff --git a/fish/fish_variables b/fish/fish_variables new file mode 100644 index 0000000..5373732 --- /dev/null +++ b/fish/fish_variables @@ -0,0 +1,21 @@ +# This file contains fish universal variable definitions. +# VERSION: 3.0 +SETUVAR ZO_CMD:zo +SETUVAR Z_CMD:z +SETUVAR Z_DATA:/Users/rack/\x2elocal/share/z/data +SETUVAR Z_DATA_DIR:/Users/rack/\x2elocal/share/z +SETUVAR Z_EXCLUDE:\x5e/Users/rack\x24 +SETUVAR __fish_initialized:4300 +SETUVAR __tf_func:function\x20__tf_alias\x20\x2dd\x20\x22Correct\x20your\x20previous\x20console\x20command\x22\x3b\x20\x20set\x20\x2dl\x20fucked_up_command\x20\x24history\x5b1\x5d\x3b\x20\x20env\x20TF_SHELL\x3dfish\x20TF_ALIAS\x3d__tf_alias\x20PYTHONIOENCODING\x3dutf\x2d8\x20thefuck\x20\x24fucked_up_command\x20THEFUCK_ARGUMENT_PLACEHOLDER\x20\x24argv\x20\x7c\x20read\x20\x2dl\x20unfucked_command\x3b\x20\x20if\x20\x5b\x20\x22\x24unfucked_command\x22\x20\x21\x3d\x20\x22\x22\x20\x5d\x3b\x20\x20\x20\x20eval\x20\x24unfucked_command\x3b\x20\x20\x20\x20builtin\x20history\x20delete\x20\x2d\x2dexact\x20\x2d\x2dcase\x2dsensitive\x20\x2d\x2d\x20\x24fucked_up_command\x3b\x20\x20\x20\x20builtin\x20history\x20merge\x3b\x20\x20end\x3bend\x3b +SETUVAR __tf_vers:The\x20Fuck\x203\x2e32\x20using\x20Python\x203\x2e10\x2e4\x20and\x20Fish\x20Shell\x203\x2e4\x2e1 +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_file\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_danhper_2F_fish_2D_ssh_2D_agent_files:\x7e/\x2econfig/fish/functions/__ssh_agent_is_started\x2efish\x1e\x7e/\x2econfig/fish/functions/__ssh_agent_start\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/fish\x2dssh\x2dagent\x2efish +SETUVAR _fisher_dracula_2F_fish_files:\x7e/\x2econfig/fish/conf\x2ed/dracula\x2efish +SETUVAR _fisher_jethrokuan_2F_z_files:\x7e/\x2econfig/fish/functions/__z\x2efish\x1e\x7e/\x2econfig/fish/functions/__z_add\x2efish\x1e\x7e/\x2econfig/fish/functions/__z_clean\x2efish\x1e\x7e/\x2econfig/fish/functions/__z_complete\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/z\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_replay_2E_fish_files:\x7e/\x2econfig/fish/functions/replay\x2efish\x1e\x7e/\x2econfig/fish/completions/replay\x2efish +SETUVAR _fisher_joseluisq_2F_gitnow_40_32_2E_31_30_2E_30__files:\x7e/\x2econfig/fish/functions/__gitnow_config_file\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_functions\x2efish\x1e\x7e/\x2econfig/fish/functions/__gitnow_manual\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/gitnow\x2efish\x1e\x7e/\x2econfig/fish/conf\x2ed/gitnow_config\x2efish\x1e\x7e/\x2econfig/fish/completions/__gitnow_completions\x2efish +SETUVAR _fisher_oh_2D_my_2D_fish_2F_plugin_2D_license_files:\x7e/\x2econfig/fish/functions/license\x2efish\x1e\x7e/\x2econfig/fish/completions/license\x2efish +SETUVAR _fisher_plugins:PatrickF1/fzf\x2efish\x1ejethrokuan/z\x1ejorgebucaran/autopair\x2efish\x1edracula/fish\x1ejorgebucaran/replay\x2efish\x1edanhper/fish\x2dssh\x2dagent\x1ejoseluisq/gitnow\x402\x2e10\x2e0\x1eoh\x2dmy\x2dfish/plugin\x2dlicense +SETUVAR _fisher_upgraded_to_4_4:\x1d +SETUVAR fish_user_paths:/opt/homebrew/Cellar/fzf/0\x2e39\x2e0/bin\x1e/opt/homebrew/opt/fzf/bin\x1e/Applications/Ghostty\x2eapp/Contents/MacOS diff --git a/fish/functions/__gitnow_config_file.fish b/fish/functions/__gitnow_config_file.fish new file mode 100644 index 0000000..8ef513b --- /dev/null +++ b/fish/functions/__gitnow_config_file.fish @@ -0,0 +1,199 @@ +# GitNow β€” Speed up your Git workflow. 🐠 +# https://github.com/joseluisq/gitnow + +set -g gitnow_xpaste + +set -g gitnow_commands 'all' 'assume' 'bitbucket' 'bugfix' 'commit' 'feature' 'github' 'gitnow' 'hotfix' 'logs' 'merge' 'move' 'pull' 'push' 'release' 'show' 'stage' 'state' 'tag' 'unstage' 'untracked' 'upstream' + +function __gitnow_read_config -d "Reads the GitNow config file" + # Sets a clipboard program + set gitnow_xpaste (__gitnow_get_clip_program) + + # Config file path used by default + set -l config_file "$fish_snippets/.gitnow" + + # Download the default .gitnow file + # Used as 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 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 $gitnow_xpaste; and test $v_clipboard -eq 1 + set cmd (echo -n "bind \\$v_command_val \"echo; if $v_command_key ($gitnow_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 + +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/fish/functions/__gitnow_functions.fish b/fish/functions/__gitnow_functions.fish new file mode 100644 index 0000000..0a747a8 --- /dev/null +++ b/fish/functions/__gitnow_functions.fish @@ -0,0 +1,187 @@ +# 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 + +# 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 + +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 + +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 + +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 + +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 + +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 + +function __gitnow_msg_not_valid_repository -a cmd + echo "Gitnow ($cmd): Current directory is not a valid Git repository." +end + +function __gitnow_current_branch_name + command git symbolic-ref --short HEAD 2>/dev/null +end + +function __gitnow_current_branch_list + command git branch --list --no-color | LC_ALL=C command sed -E "s/^(\*?[ \t]*)//g" 2>/dev/null +end + +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 + +function __gitnow_is_git_repository + command git rev-parse --git-dir >/dev/null 2>&1 +end + +function __gitnow_has_uncommited_changes + command git diff-index --quiet HEAD -- || echo "1" 2>&1 +end + +function __gitnow_get_latest_tag + command git tag --sort=-creatordate | head -n1 2>/dev/null +end + +# 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 + +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 + +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 + +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 + +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 + +function __gitnow_is_number -a strv + command echo -n $strv | LC_ALL=C command grep -qE '^([0-9]+)$' +end diff --git a/fish/functions/__gitnow_manual.fish b/fish/functions/__gitnow_manual.fish new file mode 100644 index 0000000..779a70c --- /dev/null +++ b/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://git.io/joseluisq"(set_color normal) + echo +end diff --git a/fish/functions/__ssh_agent_is_started.fish b/fish/functions/__ssh_agent_is_started.fish new file mode 100644 index 0000000..7d481ee --- /dev/null +++ b/fish/functions/__ssh_agent_is_started.fish @@ -0,0 +1,14 @@ +function __ssh_agent_is_started -d "check if ssh agent is already started" + if begin; test -f $SSH_ENV; and test -z "$SSH_AGENT_PID"; end + source $SSH_ENV > /dev/null + end + + if begin; test -z "$SSH_AGENT_PID"; and test -z "$SSH_CONNECTION"; end + return 1 + end + + ssh-add -l > /dev/null 2>&1 + if test $status -eq 2 + return 1 + end +end diff --git a/fish/functions/__ssh_agent_start.fish b/fish/functions/__ssh_agent_start.fish new file mode 100644 index 0000000..3766fe4 --- /dev/null +++ b/fish/functions/__ssh_agent_start.fish @@ -0,0 +1,5 @@ +function __ssh_agent_start -d "start a new ssh agent" + ssh-agent -c | sed 's/^echo/#echo/' > $SSH_ENV + chmod 600 $SSH_ENV + source $SSH_ENV > /dev/null +end diff --git a/fish/functions/_autopair_backspace.fish b/fish/functions/_autopair_backspace.fish new file mode 100644 index 0000000..a43fa79 --- /dev/null +++ b/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/fish/functions/_autopair_insert_left.fish b/fish/functions/_autopair_insert_left.fish new file mode 100644 index 0000000..f078e86 --- /dev/null +++ b/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/fish/functions/_autopair_insert_right.fish b/fish/functions/_autopair_insert_right.fish new file mode 100644 index 0000000..a0bd61c --- /dev/null +++ b/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/fish/functions/_autopair_insert_same.fish b/fish/functions/_autopair_insert_same.fish new file mode 100644 index 0000000..27f971d --- /dev/null +++ b/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/fish/functions/_autopair_tab.fish b/fish/functions/_autopair_tab.fish new file mode 100644 index 0000000..b74a0fb --- /dev/null +++ b/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 delete-char + commandline --function complete +end diff --git a/fish/functions/_fzf_configure_bindings_help.fish b/fish/functions/_fzf_configure_bindings_help.fish new file mode 100644 index 0000000..1209e49 --- /dev/null +++ b/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 [--FEATURE[=KEY_SEQUENCE]...] + +DESCRIPTION + By default, fzf_configure_bindings installs mnemonic key bindings for fzf.fish's features. Each + feature's binding can be customized through a corresponding namesake option: + FEATURE | MNEMONIC 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 variables | Ctrl+V (V for variable) | --variables + Search processes | Ctrl+Alt+P (P for process) | --processes + An option with a key sequence value overrides the binding for its feature, while an option + without a value disables the binding. A feature that is not customized retains its default + menomonic binding specified above. Key bindings are installed for default and insert modes. + + In terms of validation, fzf_configure_bindings fails if passed unknown options. Furthermore, it + expects an equals sign between an option's name and value. However, it does not validate key + sequences. Rather, consider using fish_key_reader to manually validate them. + + In terms of experimentation, fzf_configure_bindings erases any bindings it previously installed + before installing new ones so it can be repeatedly executed in the same fish session without + problem. Once the desired fzf_configure_bindings command has been found, add it to config.fish + in order to persist the bindings. + + The -h and --help options print this help message. + +EXAMPLES + Install the default mnemonic bindings + \$ fzf_configure_bindings + Install the default bindings but override git log's binding to Ctrl+G + \$ fzf_configure_bindings --git_log=\cg + Install the default bindings but leave search history unbound + \$ fzf_configure_bindings --history + Alternative style of disabling search history + \$ fzf_configure_bindings --history= + An agglomeration of all the options + \$ fzf_configure_bindings --git_status=\cg --history=\ch --variables --directory --git_log +" +end diff --git a/fish/functions/_fzf_extract_var_info.fish b/fish/functions/_fzf_extract_var_info.fish new file mode 100644 index 0000000..dd4e952 --- /dev/null +++ b/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/fish/functions/_fzf_preview_file.fish b/fish/functions/_fzf_preview_file.fish new file mode 100644 index 0000000..29e7405 --- /dev/null +++ b/fish/functions/_fzf_preview_file.fish @@ -0,0 +1,43 @@ +# helper function for _fzf_search_directory +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 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/fish/functions/_fzf_report_file_type.fish b/fish/functions/_fzf_report_file_type.fish new file mode 100644 index 0000000..49e02e1 --- /dev/null +++ b/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/fish/functions/_fzf_search_directory.fish b/fish/functions/_fzf_search_directory.fish new file mode 100644 index 0000000..57d3d13 --- /dev/null +++ b/fish/functions/_fzf_search_directory.fish @@ -0,0 +1,43 @@ +function _fzf_search_directory --description "Search the current directory. Replace the current token with the selected file paths." + # --string-cwd-prefix prevents fd >= 8.3.0 from prepending ./ to relative paths + set fd_opts --color=always --strip-cwd-prefix $fzf_fd_opts + + set fzf_arguments --multi --ansi $fzf_dir_opts + set token (commandline --current-token) + # expandΒ any variables or leading tilde (~) in the token + set expanded_token (eval echo -- $token) + # unescape token because it's already quoted so backslashes will mess up the path + set 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_opts --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="$unescaped_exp_token" --preview="_fzf_preview_file $expanded_token{}" + set file_paths_selected $unescaped_exp_token(fd $fd_opts 2>/dev/null | _fzf_wrapper $fzf_arguments) + else + set --prepend fzf_arguments --query="$unescaped_exp_token" --preview='_fzf_preview_file {}' + set file_paths_selected (fd $fd_opts 2>/dev/null | _fzf_wrapper $fzf_arguments) + end + + + if test $status -eq 0 + # Fish will cd implicitly if a directory name ending in a slash is provided. + # To help the user leverage this feature, we automatically append / to the selected path if + # - only one path was selected, + # - the user was in the middle of inputting the first token, + # - the path is a directory + # Then, the user only needs to hit Enter once more to cd into that directory. + if test (count $file_paths_selected) = 1 + set commandline_tokens (commandline --tokenize) + if test "$commandline_tokens" = "$token" -a -d "$file_paths_selected" + set file_paths_selected $file_paths_selected/ + end + end + + commandline --current-token --replace -- (string escape -- $file_paths_selected | string join ' ') + end + + commandline --function repaint +end diff --git a/fish/functions/_fzf_search_git_log.fish b/fish/functions/_fzf_search_git_log.fish new file mode 100644 index 0000000..3375c1d --- /dev/null +++ b/fish/functions/_fzf_search_git_log.fish @@ -0,0 +1,28 @@ +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 + # see documentation for git format placeholders at https://git-scm.com/docs/git-log#Documentation/git-log.txt-emnem + # %h gives you the abbreviated commit hash, which is useful for saving screen space, but we will have to expand it later below + set log_fmt_str '%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)' + set selected_log_lines ( + git log --color=always --format=format:$log_fmt_str --date=short | \ + _fzf_wrapper --ansi \ + --multi \ + --tiebreak=index \ + --preview='git show --color=always --stat --patch {1}' \ + --query=(commandline --current-token) \ + $fzf_git_log_opts + ) + if test $status -eq 0 + for line in $selected_log_lines + set abbreviated_commit_hash (string split --field 1 " " $line) + set full_commit_hash (git rev-parse $abbreviated_commit_hash) + set --append commit_hashes $full_commit_hash + end + commandline --current-token --replace (string join ' ' $commit_hashes) + end + end + + commandline --function repaint +end diff --git a/fish/functions/_fzf_search_git_status.fish b/fish/functions/_fzf_search_git_status.fish new file mode 100644 index 0000000..79a5c79 --- /dev/null +++ b/fish/functions/_fzf_search_git_status.fish @@ -0,0 +1,33 @@ +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 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 \ + --query=(commandline --current-token) \ + $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 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/fish/functions/_fzf_search_history.fish b/fish/functions/_fzf_search_history.fish new file mode 100644 index 0000000..271cfcc --- /dev/null +++ b/fish/functions/_fzf_search_history.fish @@ -0,0 +1,24 @@ +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 + builtin history merge + + set command_with_ts ( + # Reference https://devhints.io/strftime to understand strftime format symbols + builtin history --null --show-time="%m-%d %H:%M:%S β”‚ " | + _fzf_wrapper --read0 \ + --tiebreak=index \ + --query=(commandline) \ + # preview current command using fish_ident in a window at the bottom 3 lines tall + --preview="echo -- {4..} | fish_indent --ansi" \ + --preview-window="bottom:3:wrap" \ + $fzf_history_opts | + string collect + ) + + if test $status -eq 0 + set command_selected (string split --max 1 " β”‚ " $command_with_ts)[2] + commandline --replace -- $command_selected + end + + commandline --function repaint +end diff --git a/fish/functions/_fzf_search_processes.fish b/fish/functions/_fzf_search_processes.fish new file mode 100644 index 0000000..e3ef59f --- /dev/null +++ b/fish/functions/_fzf_search_processes.fish @@ -0,0 +1,28 @@ +function _fzf_search_processes --description "Search all running processes. Replace the current token with the pid of the selected process." + # 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 ps_preview_fmt (string join ',' 'pid' 'ppid=PARENT' 'user' '%cpu' 'rss=RSS_IN_KB' 'start=START_TIME' 'command') + set processes_selected ( + ps -A -opid,command | \ + _fzf_wrapper --multi \ + --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 -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 --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/fish/functions/_fzf_search_variables.fish b/fish/functions/_fzf_search_variables.fish new file mode 100644 index 0000000..744f226 --- /dev/null +++ b/fish/functions/_fzf_search_variables.fish @@ -0,0 +1,46 @@ +# 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 all_variable_names (string match --invert history <$set_names_output) + + set 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 cleaned_curr_token (string replace -- '$' '' $current_token) + + set variable_names_selected ( + printf '%s\n' $all_variable_names | + _fzf_wrapper --preview "_fzf_extract_var_info {} $set_show_output" \ + --preview-window="wrap" \ + --multi \ + --query=$cleaned_curr_token \ + $fzf_shell_vars_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/fish/functions/_fzf_wrapper.fish b/fish/functions/_fzf_wrapper.fish new file mode 100644 index 0000000..a928701 --- /dev/null +++ b/fish/functions/_fzf_wrapper.fish @@ -0,0 +1,20 @@ +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 --local so that it doesn't clobber SHELL outside of this function. + set --local --export SHELL (command --search fish) + + # If FZF_DEFAULT_OPTS is not set, then set some sane defaults. + # See https://github.com/junegunn/fzf#environment-variables + if not set --query FZF_DEFAULT_OPTS + # 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/fish/functions/fish_user_key_bindings.fish b/fish/functions/fish_user_key_bindings.fish new file mode 100644 index 0000000..350a9da --- /dev/null +++ b/fish/functions/fish_user_key_bindings.fish @@ -0,0 +1,3 @@ +function fish_user_key_bindings + fzf_key_bindings +end diff --git a/fish/functions/fzf_configure_bindings.fish b/fish/functions/fzf_configure_bindings.fish new file mode 100644 index 0000000..addb55c --- /dev/null +++ b/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 options_spec h/help 'directory=?' 'git_log=?' 'git_status=?' 'history=?' 'variables=?' 'processes=?' + 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 = variables, 6 = processes + set key_sequences \e\cf \e\cl \e\cs \cr \cv \e\cp # \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_variables && set key_sequences[5] "$_flag_variables" + set --query _flag_processes && set key_sequences[6] "$_flag_processes" + + # 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_vars_command" + test -n $key_sequences[6] && bind --mode $mode $key_sequences[6] _fzf_search_processes + 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/fish/functions/fzf_key_bindings.fish b/fish/functions/fzf_key_bindings.fish new file mode 100644 index 0000000..2b44dfd --- /dev/null +++ b/fish/functions/fzf_key_bindings.fish @@ -0,0 +1,236 @@ +# ____ ____ +# / __/___ / __/ +# / /_/_ / / /_ +# / __/ / /_/ __/ +# /_/ /___/_/ key-bindings.fish +# +# - $FZF_TMUX_OPTS +# - $FZF_CTRL_T_COMMAND +# - $FZF_CTRL_T_OPTS +# - $FZF_CTRL_R_COMMAND +# - $FZF_CTRL_R_OPTS +# - $FZF_ALT_C_COMMAND +# - $FZF_ALT_C_OPTS + + +# Key bindings +# ------------ +# The oldest supported fish version is 3.1b1. To maintain compatibility, the +# command substitution syntax $(cmd) should never be used, even behind a version +# check, otherwise the source command will fail on fish versions older than 3.4.0. +function fzf_key_bindings + + # Check fish version + set -l fish_ver (string match -r '^(\d+).(\d+)' $version 2> /dev/null; or echo 0\n0\n0) + if test \( "$fish_ver[2]" -lt 3 \) -o \( "$fish_ver[2]" -eq 3 -a "$fish_ver[3]" -lt 1 \) + echo "This script requires fish version 3.1b1 or newer." >&2 + return 1 + else if not type -q fzf + echo "fzf was not found in path." >&2 + return 1 + end + + function __fzf_defaults + # $argv[1]: Prepend to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS + # $argv[2..]: Append to FZF_DEFAULT_OPTS_FILE and FZF_DEFAULT_OPTS + test -n "$FZF_TMUX_HEIGHT"; or set -l FZF_TMUX_HEIGHT 40% + string join ' ' -- \ + "--height $FZF_TMUX_HEIGHT --min-height=20+ --bind=ctrl-z:ignore" $argv[1] \ + (test -r "$FZF_DEFAULT_OPTS_FILE"; and string join -- ' ' <$FZF_DEFAULT_OPTS_FILE) \ + $FZF_DEFAULT_OPTS $argv[2..-1] + end + + function __fzfcmd + test -n "$FZF_TMUX_HEIGHT"; or set -l FZF_TMUX_HEIGHT 40% + if test -n "$FZF_TMUX_OPTS" + echo "fzf-tmux $FZF_TMUX_OPTS -- " + else if test "$FZF_TMUX" = "1" + echo "fzf-tmux -d$FZF_TMUX_HEIGHT -- " + else + echo "fzf" + end + end + + function __fzf_parse_commandline -d 'Parse the current command line token and return split of existing filepath, fzf query, and optional -option= prefix' + set -l fzf_query '' + set -l prefix '' + set -l dir '.' + + # Set variables containing the major and minor fish version numbers, using + # a method compatible with all supported fish versions. + set -l -- fish_major (string match -r -- '^\d+' $version) + set -l -- fish_minor (string match -r -- '^\d+\.(\d+)' $version)[2] + + # fish v3.3.0 and newer: Don't use option prefix if " -- " is preceded. + set -l -- match_regex '(?[\s\S]*?(?=\n?$)$)' + set -l -- prefix_regex '^-[^\s=]+=|^-(?!-)\S' + if test "$fish_major" -eq 3 -a "$fish_minor" -lt 3 + or string match -q -v -- '* -- *' (string sub -l (commandline -Cp) -- (commandline -p)) + set -- match_regex "(?$prefix_regex)?$match_regex" + end + + # Set $prefix and expanded $fzf_query with preserved trailing newlines. + if test "$fish_major" -ge 4 + # fish v4.0.0 and newer + string match -q -r -- $match_regex (commandline --current-token --tokens-expanded | string collect -N) + else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2 + # fish v3.2.0 - v3.7.1 (last v3) + string match -q -r -- $match_regex (commandline --current-token --tokenize | string collect -N) + eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)' '') + else + # fish older than v3.2.0 (v3.1b1 - v3.1.2) + set -l -- cl_token (commandline --current-token --tokenize | string collect -N) + set -- prefix (string match -r -- $prefix_regex $cl_token) + set -- fzf_query (string replace -- "$prefix" '' $cl_token | string collect -N) + eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^\\\(?=~)|\\\(?=\$\w)|\\\n\\\n$' '') + end + + if test -n "$fzf_query" + # Normalize path in $fzf_query, set $dir to the longest existing directory. + if test \( "$fish_major" -ge 4 \) -o \( "$fish_major" -eq 3 -a "$fish_minor" -ge 5 \) + # fish v3.5.0 and newer + set -- fzf_query (path normalize -- $fzf_query) + set -- dir $fzf_query + while not path is -d $dir + set -- dir (path dirname $dir) + end + else + # fish older than v3.5.0 (v3.1b1 - v3.4.1) + if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2 + # fish v3.2.0 - v3.4.1 + string match -q -r -- '(?^[\s\S]*?(?=\n?$)$)' \ + (string replace -r -a -- '(?<=/)/|(?[\s\S]*)' $fzf_query + else if test "$fish_major" -eq 3 -a "$fish_minor" -ge 2 + # fish v3.2.0 - v3.7.1 (last v3) + string match -q -r -- '^/?(?[\s\S]*?(?=\n?$)$)' \ + (string replace -- "$dir" '' $fzf_query | string collect -N) + else + # fish older than v3.2.0 (v3.1b1 - v3.1.2) + set -- fzf_query (string replace -- "$dir" '' $fzf_query | string collect -N) + eval set -- fzf_query (string escape -n -- $fzf_query | string replace -r -a '^/?|\\\n$' '') + end + end + end + + string escape -n -- "$dir" "$fzf_query" "$prefix" + end + + # Store current token in $dir as root for the 'find' command + function fzf-file-widget -d "List files and folders" + set -l commandline (__fzf_parse_commandline) + set -lx dir $commandline[1] + set -l fzf_query $commandline[2] + set -l prefix $commandline[3] + + set -lx FZF_DEFAULT_OPTS (__fzf_defaults \ + "--reverse --walker=file,dir,follow,hidden --scheme=path" \ + "$FZF_CTRL_T_OPTS --multi --print0") + + set -lx FZF_DEFAULT_COMMAND "$FZF_CTRL_T_COMMAND" + set -lx FZF_DEFAULT_OPTS_FILE + + set -l result (eval (__fzfcmd) --walker-root=$dir --query=$fzf_query | string split0) + and commandline -rt -- (string join -- ' ' $prefix(string escape -- $result))' ' + + commandline -f repaint + end + + function fzf-history-widget -d "Show command history" + set -l -- command_line (commandline) + set -l -- current_line (commandline -L) + set -l -- total_lines (count $command_line) + set -l -- fzf_query (string escape -- $command_line[$current_line]) + + set -lx FZF_DEFAULT_OPTS (__fzf_defaults '' \ + '--nth=2..,.. --scheme=history --multi --wrap-sign="\t↳ "' \ + '--bind=\'shift-delete:execute-silent(eval history delete --exact --case-sensitive -- (string escape -n -- {+} | string replace -r -a "^\d*\\\\\\t|(?<=\\\\\\n)\\\\\\t" ""))+reload(eval $FZF_DEFAULT_COMMAND)\'' \ + "--bind=ctrl-r:toggle-sort,alt-r:toggle-raw --highlight-line $FZF_CTRL_R_OPTS" \ + '--accept-nth=2.. --read0 --print0 --with-shell='(status fish-path)\\ -c) + + set -lx FZF_DEFAULT_OPTS_FILE + set -lx FZF_DEFAULT_COMMAND + + if type -q perl + set -a FZF_DEFAULT_OPTS '--tac' + set FZF_DEFAULT_COMMAND 'builtin history -z --reverse | command perl -0 -pe \'s/^/$.\t/g; s/\n/\n\t/gm\'' + else + set FZF_DEFAULT_COMMAND \ + 'set -l h (builtin history -z --reverse | string split0);' \ + 'for i in (seq (count $h) -1 1);' \ + 'string join0 -- $i\t(string replace -a -- \n \n\t $h[$i] | string collect);' \ + 'end' + end + + # Merge history from other sessions before searching + test -z "$fish_private_mode"; and builtin history merge + + if set -l result (eval $FZF_DEFAULT_COMMAND \| (__fzfcmd) --query=$fzf_query | string split0) + if test "$total_lines" -eq 1 + commandline -- (string replace -a -- \n\t \n $result) + else + set -l a (math $current_line - 1) + set -l b (math $current_line + 1) + commandline -- $command_line[1..$a] (string replace -a -- \n\t \n $result) + commandline -a -- '' $command_line[$b..-1] + end + end + + commandline -f repaint + end + + function fzf-cd-widget -d "Change directory" + set -l commandline (__fzf_parse_commandline) + set -lx dir $commandline[1] + set -l fzf_query $commandline[2] + set -l prefix $commandline[3] + + set -lx FZF_DEFAULT_OPTS (__fzf_defaults \ + "--reverse --walker=dir,follow,hidden --scheme=path" \ + "$FZF_ALT_C_OPTS --no-multi --print0") + + set -lx FZF_DEFAULT_OPTS_FILE + set -lx FZF_DEFAULT_COMMAND "$FZF_ALT_C_COMMAND" + + if set -l result (eval (__fzfcmd) --query=$fzf_query --walker-root=$dir | string split0) + cd -- $result + commandline -rt -- $prefix + end + + commandline -f repaint + end + + if not set -q FZF_CTRL_R_COMMAND; or test -n "$FZF_CTRL_R_COMMAND" + if test -n "$FZF_CTRL_R_COMMAND" + echo "warning: FZF_CTRL_R_COMMAND is set to a custom command, but custom commands are not yet supported for CTRL-R" >&2 + end + bind \cr fzf-history-widget + bind -M insert \cr fzf-history-widget + end + + if not set -q FZF_CTRL_T_COMMAND; or test -n "$FZF_CTRL_T_COMMAND" + bind \ct fzf-file-widget + bind -M insert \ct fzf-file-widget + end + + if not set -q FZF_ALT_C_COMMAND; or test -n "$FZF_ALT_C_COMMAND" + bind \ec fzf-cd-widget + bind -M insert \ec fzf-cd-widget + end + +end diff --git a/fish/functions/license.fish b/fish/functions/license.fish new file mode 100644 index 0000000..fb46cc3 --- /dev/null +++ b/fish/functions/license.fish @@ -0,0 +1,15 @@ +function license + set -l base_url https://api.github.com/licenses + set -l headers 'Accept: application/vnd.github.drax-preview+json' + + if test $argv[1] + set -l license $argv[1] + set -l res (curl --silent --header $headers $base_url/$license | jq .'body') + echo -e $res | sed -e 's/^"//' -e 's/"$//' + else + set -l res (curl --silent --header $headers $base_url) + echo "Available Licenses: " + echo + echo "$res" | jq .[].'key' | sed -e 's/^"//' -e 's/"$//' + end +end diff --git a/fish/functions/replay.fish b/fish/functions/replay.fish new file mode 100644 index 0000000..b8f170f --- /dev/null +++ b/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.0" + 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] \"$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 + string replace --all : " " "set $name $value" + 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/ghostty/config b/ghostty/config new file mode 100644 index 0000000..36e594f --- /dev/null +++ b/ghostty/config @@ -0,0 +1,17 @@ +font-size = 18 +font-family = JetBrainsMonoNL Nerd Font Mono + + +theme = Builtin Pastel Dark +# theme = Dracula +background-opacity = 0.8 + + +# Window +window-height = 30 +window-width = 100 + + +# other +copy-on-select = clipboard +shell-integration = fish diff --git a/git/dot-gitconfig b/git/dot-gitconfig index 5b048c2..6795b7b 100755 --- a/git/dot-gitconfig +++ b/git/dot-gitconfig @@ -16,6 +16,7 @@ fileMode = false ignorecase = false editor = nvim + autocrlf = true [github] user = racklin@gmail.com [ghq] diff --git a/nvim/.gitignore b/nvim/.gitignore new file mode 100644 index 0000000..cc5457a --- /dev/null +++ b/nvim/.gitignore @@ -0,0 +1,8 @@ +tt.* +.tests +doc/tags +debug +.repro +foo.* +*.log +data diff --git a/nvim/.neoconf.json b/nvim/.neoconf.json new file mode 100644 index 0000000..7c48087 --- /dev/null +++ b/nvim/.neoconf.json @@ -0,0 +1,15 @@ +{ + "neodev": { + "library": { + "enabled": true, + "plugins": true + } + }, + "neoconf": { + "plugins": { + "lua_ls": { + "enabled": true + } + } + } +} diff --git a/nvim/LICENSE b/nvim/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/nvim/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/nvim/README.md b/nvim/README.md new file mode 100644 index 0000000..185280b --- /dev/null +++ b/nvim/README.md @@ -0,0 +1,4 @@ +# πŸ’€ LazyVim + +A starter template for [LazyVim](https://github.com/LazyVim/LazyVim). +Refer to the [documentation](https://lazyvim.github.io/installation) to get started. diff --git a/nvim/init.lua b/nvim/init.lua new file mode 100644 index 0000000..2514f9e --- /dev/null +++ b/nvim/init.lua @@ -0,0 +1,2 @@ +-- bootstrap lazy.nvim, LazyVim and your plugins +require("config.lazy") diff --git a/nvim/lazy-lock.json b/nvim/lazy-lock.json new file mode 100644 index 0000000..45940b9 --- /dev/null +++ b/nvim/lazy-lock.json @@ -0,0 +1,42 @@ +{ + "LazyVim": { "branch": "main", "commit": "d1529f650fdd89cb620258bdeca5ed7b558420c7" }, + "SchemaStore.nvim": { "branch": "main", "commit": "b850ab25279ba04ada90e8b696ef5d0624af103d" }, + "blink.cmp": { "branch": "main", "commit": "4b18c32adef2898f95cdef6192cbd5796c1a332d" }, + "bufferline.nvim": { "branch": "main", "commit": "655133c3b4c3e5e05ec549b9f8cc2894ac6f51b3" }, + "catppuccin": { "branch": "main", "commit": "beaf41a30c26fd7d6c386d383155cbd65dd554cd" }, + "conform.nvim": { "branch": "master", "commit": "c2526f1cde528a66e086ab1668e996d162c75f4f" }, + "flash.nvim": { "branch": "main", "commit": "fcea7ff883235d9024dc41e638f164a450c14ca2" }, + "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" }, + "fzf-lua": { "branch": "main", "commit": "fb8c50ba62a0daa433b7ac2b78834f318322b879" }, + "gitsigns.nvim": { "branch": "main", "commit": "1ce96a464fdbc24208e24c117e2021794259005d" }, + "grug-far.nvim": { "branch": "main", "commit": "275dbedc96e61a6b8d1dfb28ba51586ddd233dcf" }, + "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, + "lazydev.nvim": { "branch": "main", "commit": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d" }, + "lualine.nvim": { "branch": "master", "commit": "47f91c416daef12db467145e16bed5bbfe00add8" }, + "markdown-preview.nvim": { "branch": "master", "commit": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee" }, + "mason-lspconfig.nvim": { "branch": "main", "commit": "ae609525ddf01c153c39305730b1791800ffe4fe" }, + "mason.nvim": { "branch": "main", "commit": "44d1e90e1f66e077268191e3ee9d2ac97cc18e65" }, + "mini.ai": { "branch": "main", "commit": "9eae720f2b20f6ad28cbfa0ddc524e10dc2c3201" }, + "mini.icons": { "branch": "main", "commit": "efc85e42262cd0c9e1fdbf806c25cb0be6de115c" }, + "mini.pairs": { "branch": "main", "commit": "4089aa6ea6423e02e1a8326a7a7a00159f6f5e04" }, + "neo-tree.nvim": { "branch": "main", "commit": "2d04b7a422c9f84788bbb4e5ca2634c81dd0f5a3" }, + "noice.nvim": { "branch": "main", "commit": "7bfd942445fb63089b59f97ca487d605e715f155" }, + "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, + "nvim-lint": { "branch": "master", "commit": "bcd1a44edbea8cd473af7e7582d3f7ffc60d8e81" }, + "nvim-lspconfig": { "branch": "master", "commit": "66fd02ad1c7ea31616d3ca678fa04e6d0b360824" }, + "nvim-treesitter": { "branch": "main", "commit": "45a07f869b0cffba342276f2c77ba7c116d35db8" }, + "nvim-treesitter-textobjects": { "branch": "main", "commit": "a0e182ae21fda68c59d1f36c9ed45600aef50311" }, + "nvim-ts-autotag": { "branch": "main", "commit": "8e1c0a389f20bf7f5b0dd0e00306c1247bda2595" }, + "persistence.nvim": { "branch": "main", "commit": "b20b2a7887bd39c1a356980b45e03250f3dce49c" }, + "plenary.nvim": { "branch": "master", "commit": "b9fd5226c2f76c951fc8ed5923d85e4de065e509" }, + "render-markdown.nvim": { "branch": "main", "commit": "48b4175dbca8439d30c1f52231cbe5a712c8f9d9" }, + "snacks.nvim": { "branch": "main", "commit": "fe7cfe9800a182274d0f868a74b7263b8c0c020b" }, + "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, + "tokyonight.nvim": { "branch": "main", "commit": "5da1b76e64daf4c5d410f06bcb6b9cb640da7dfd" }, + "trouble.nvim": { "branch": "main", "commit": "bd67efe408d4816e25e8491cc5ad4088e708a69a" }, + "ts-comments.nvim": { "branch": "main", "commit": "123a9fb12e7229342f807ec9e6de478b1102b041" }, + "vim-dadbod": { "branch": "master", "commit": "6d1d41da4873a445c5605f2005ad2c68c99d8770" }, + "vim-dadbod-completion": { "branch": "master", "commit": "a8dac0b3cf6132c80dc9b18bef36d4cf7a9e1fe6" }, + "vim-dadbod-ui": { "branch": "master", "commit": "48c4f271da13d380592f4907e2d1d5558044e4e5" }, + "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" } +} diff --git a/nvim/lazyvim.json b/nvim/lazyvim.json new file mode 100644 index 0000000..071932c --- /dev/null +++ b/nvim/lazyvim.json @@ -0,0 +1,14 @@ +{ + "extras": [ + "lazyvim.plugins.extras.lang.json", + "lazyvim.plugins.extras.lang.markdown", + "lazyvim.plugins.extras.lang.php", + "lazyvim.plugins.extras.lang.sql", + "lazyvim.plugins.extras.lang.toml", + "lazyvim.plugins.extras.lang.yaml" + ], + "news": { + "NEWS.md": "10960" + }, + "version": 7 +} \ No newline at end of file diff --git a/nvim/lua/config/autocmds.lua b/nvim/lua/config/autocmds.lua new file mode 100644 index 0000000..4221e75 --- /dev/null +++ b/nvim/lua/config/autocmds.lua @@ -0,0 +1,8 @@ +-- Autocmds are automatically loaded on the VeryLazy event +-- Default autocmds that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/autocmds.lua +-- +-- Add any additional autocmds here +-- with `vim.api.nvim_create_autocmd` +-- +-- Or remove existing autocmds by their group name (which is prefixed with `lazyvim_` for the defaults) +-- e.g. vim.api.nvim_del_augroup_by_name("lazyvim_wrap_spell") diff --git a/nvim/lua/config/keymaps.lua b/nvim/lua/config/keymaps.lua new file mode 100644 index 0000000..2c134f7 --- /dev/null +++ b/nvim/lua/config/keymaps.lua @@ -0,0 +1,3 @@ +-- Keymaps are automatically loaded on the VeryLazy event +-- Default keymaps that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/keymaps.lua +-- Add any additional keymaps here diff --git a/nvim/lua/config/lazy.lua b/nvim/lua/config/lazy.lua new file mode 100644 index 0000000..d73bfa1 --- /dev/null +++ b/nvim/lua/config/lazy.lua @@ -0,0 +1,53 @@ +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) + +require("lazy").setup({ + spec = { + -- add LazyVim and import its plugins + { "LazyVim/LazyVim", import = "lazyvim.plugins" }, + -- import/override with your plugins + { import = "plugins" }, + }, + defaults = { + -- By default, only LazyVim plugins will be lazy-loaded. Your custom plugins will load during startup. + -- If you know what you're doing, you can set this to `true` to have all your custom plugins lazy-loaded by default. + lazy = false, + -- It's recommended to leave version=false for now, since a lot the plugin that support versioning, + -- have outdated releases, which may break your Neovim install. + version = false, -- always use the latest git commit + -- version = "*", -- try installing the latest stable version for plugins that support semver + }, + install = { colorscheme = { "tokyonight", "habamax" } }, + checker = { + enabled = true, -- check for plugin updates periodically + notify = false, -- notify on update + }, -- automatically check for plugin updates + performance = { + rtp = { + -- disable some rtp plugins + disabled_plugins = { + "gzip", + -- "matchit", + -- "matchparen", + -- "netrwPlugin", + "tarPlugin", + "tohtml", + "tutor", + "zipPlugin", + }, + }, + }, +}) diff --git a/nvim/lua/config/options.lua b/nvim/lua/config/options.lua new file mode 100644 index 0000000..3ea1454 --- /dev/null +++ b/nvim/lua/config/options.lua @@ -0,0 +1,3 @@ +-- Options are automatically loaded before lazy.nvim startup +-- Default options that are always set: https://github.com/LazyVim/LazyVim/blob/main/lua/lazyvim/config/options.lua +-- Add any additional options here diff --git a/nvim/lua/plugins/example.lua b/nvim/lua/plugins/example.lua new file mode 100644 index 0000000..17f53d6 --- /dev/null +++ b/nvim/lua/plugins/example.lua @@ -0,0 +1,197 @@ +-- since this is just an example spec, don't actually load anything here and return an empty spec +-- stylua: ignore +if true then return {} end + +-- every spec file under the "plugins" directory will be loaded automatically by lazy.nvim +-- +-- In your plugin files, you can: +-- * add extra plugins +-- * disable/enabled LazyVim plugins +-- * override the configuration of LazyVim plugins +return { + -- add gruvbox + { "ellisonleao/gruvbox.nvim" }, + + -- Configure LazyVim to load gruvbox + { + "LazyVim/LazyVim", + opts = { + colorscheme = "gruvbox", + }, + }, + + -- change trouble config + { + "folke/trouble.nvim", + -- opts will be merged with the parent spec + opts = { use_diagnostic_signs = true }, + }, + + -- disable trouble + { "folke/trouble.nvim", enabled = false }, + + -- override nvim-cmp and add cmp-emoji + { + "hrsh7th/nvim-cmp", + dependencies = { "hrsh7th/cmp-emoji" }, + ---@param opts cmp.ConfigSchema + opts = function(_, opts) + table.insert(opts.sources, { name = "emoji" }) + end, + }, + + -- change some telescope options and a keymap to browse plugin files + { + "nvim-telescope/telescope.nvim", + keys = { + -- add a keymap to browse plugin files + -- stylua: ignore + { + "fp", + function() require("telescope.builtin").find_files({ cwd = require("lazy.core.config").options.root }) end, + desc = "Find Plugin File", + }, + }, + -- change some options + opts = { + defaults = { + layout_strategy = "horizontal", + layout_config = { prompt_position = "top" }, + sorting_strategy = "ascending", + winblend = 0, + }, + }, + }, + + -- add pyright to lspconfig + { + "neovim/nvim-lspconfig", + ---@class PluginLspOpts + opts = { + ---@type lspconfig.options + servers = { + -- pyright will be automatically installed with mason and loaded with lspconfig + pyright = {}, + }, + }, + }, + + -- add tsserver and setup with typescript.nvim instead of lspconfig + { + "neovim/nvim-lspconfig", + dependencies = { + "jose-elias-alvarez/typescript.nvim", + init = function() + require("lazyvim.util").lsp.on_attach(function(_, buffer) + -- stylua: ignore + vim.keymap.set( "n", "co", "TypescriptOrganizeImports", { buffer = buffer, desc = "Organize Imports" }) + vim.keymap.set("n", "cR", "TypescriptRenameFile", { desc = "Rename File", buffer = buffer }) + end) + end, + }, + ---@class PluginLspOpts + opts = { + ---@type lspconfig.options + servers = { + -- tsserver will be automatically installed with mason and loaded with lspconfig + tsserver = {}, + }, + -- you can do any additional lsp server setup here + -- return true if you don't want this server to be setup with lspconfig + ---@type table + setup = { + -- example to setup with typescript.nvim + tsserver = function(_, opts) + require("typescript").setup({ server = opts }) + return true + end, + -- Specify * to use this function as a fallback for any server + -- ["*"] = function(server, opts) end, + }, + }, + }, + + -- for typescript, LazyVim also includes extra specs to properly setup lspconfig, + -- treesitter, mason and typescript.nvim. So instead of the above, you can use: + { import = "lazyvim.plugins.extras.lang.typescript" }, + + -- add more treesitter parsers + { + "nvim-treesitter/nvim-treesitter", + opts = { + ensure_installed = { + "bash", + "html", + "javascript", + "json", + "lua", + "markdown", + "markdown_inline", + "python", + "query", + "regex", + "tsx", + "typescript", + "vim", + "yaml", + }, + }, + }, + + -- since `vim.tbl_deep_extend`, can only merge tables and not lists, the code above + -- would overwrite `ensure_installed` with the new value. + -- If you'd rather extend the default config, use the code below instead: + { + "nvim-treesitter/nvim-treesitter", + opts = function(_, opts) + -- add tsx and treesitter + vim.list_extend(opts.ensure_installed, { + "tsx", + "typescript", + }) + end, + }, + + -- the opts function can also be used to change the default opts: + { + "nvim-lualine/lualine.nvim", + event = "VeryLazy", + opts = function(_, opts) + table.insert(opts.sections.lualine_x, { + function() + return "πŸ˜„" + end, + }) + end, + }, + + -- or you can return new options to override all the defaults + { + "nvim-lualine/lualine.nvim", + event = "VeryLazy", + opts = function() + return { + --[[add your custom lualine config here]] + } + end, + }, + + -- use mini.starter instead of alpha + { import = "lazyvim.plugins.extras.ui.mini-starter" }, + + -- add jsonls and schemastore packages, and setup treesitter for json, json5 and jsonc + { import = "lazyvim.plugins.extras.lang.json" }, + + -- add any tools you want to have installed below + { + "williamboman/mason.nvim", + opts = { + ensure_installed = { + "stylua", + "shellcheck", + "shfmt", + "flake8", + }, + }, + }, +} diff --git a/nvim/stylua.toml b/nvim/stylua.toml new file mode 100644 index 0000000..5d6c50d --- /dev/null +++ b/nvim/stylua.toml @@ -0,0 +1,3 @@ +indent_type = "Spaces" +indent_width = 2 +column_width = 120 \ No newline at end of file diff --git a/starship/starship.toml b/starship/starship.toml index e8c6b55..13348cd 100644 --- a/starship/starship.toml +++ b/starship/starship.toml @@ -4,7 +4,7 @@ disabled = true [[battery.display]] # "bold red" style and discharging_symbol when capacity is between 0% and 10% threshold = 20 style = "bold red" -discharging_symbol = " " +#discharging_symbol = " " [[battery.display]] # "bold yellow" style and πŸ’¦ symbol when capacity is between 10% and 30% threshold = 30 @@ -21,7 +21,7 @@ format = "on [$hostname](bold red) " disabled = false [shell] -fish_indicator = "" +#fish_indicator = "" powershell_indicator = "ο‘ _" unknown_indicator = "mystery shell" style = "cyan bold" diff --git a/zsh/dot-fzf.zsh b/zsh/dot-fzf.zsh index 6010530..be24395 100644 --- a/zsh/dot-fzf.zsh +++ b/zsh/dot-fzf.zsh @@ -1,12 +1,9 @@ # Setup fzf # --------- if [[ ! "$PATH" == */opt/homebrew/opt/fzf/bin* ]]; then - export PATH="${PATH:+${PATH}:}/opt/homebrew/opt/fzf/bin" + PATH="${PATH:+${PATH}:}/opt/homebrew/opt/fzf/bin" fi -# using fd instead of find -export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git' - # Auto-completion # --------------- [[ $- == *i* ]] && source "/opt/homebrew/opt/fzf/shell/completion.zsh" 2> /dev/null @@ -14,4 +11,3 @@ export FZF_DEFAULT_COMMAND='fd --type f --hidden --follow --exclude .git' # Key bindings # ------------ source "/opt/homebrew/opt/fzf/shell/key-bindings.zsh" - diff --git a/zsh/dot-zshrc b/zsh/dot-zshrc index ba4219f..002489b 100644 --- a/zsh/dot-zshrc +++ b/zsh/dot-zshrc @@ -1,4 +1,3 @@ - # Setting homebrew shellenv [[ ("$(uname)" = "Darwin") && -d "/opt/homebrew" ]] && eval "$(/opt/homebrew/bin/brew shellenv)" @@ -127,4 +126,3 @@ Darwin) [ -f ~/.config-osx.zsh ] && source ~/.config-osx.zsh ;; esac -