├── nvim ├── after │ └── indent │ │ └── ruby.vim ├── lua │ ├── lsp │ │ ├── settings │ │ │ ├── ts_ls.lua │ │ │ ├── basedpyright.lua │ │ │ ├── gopls.lua │ │ │ ├── jsonls.lua │ │ │ ├── yamlls.lua │ │ │ └── lua_ls.lua │ │ ├── keymaps.lua │ │ └── init.lua │ ├── plugins │ │ ├── clever-f.lua │ │ ├── vim-rails.lua │ │ ├── git.lua │ │ ├── which-key.lua │ │ ├── nvim-navbuddy.lua │ │ ├── hop.lua │ │ ├── treesj.lua │ │ ├── vim-test.lua │ │ ├── copilot.lua │ │ ├── fzf-lua.lua │ │ ├── mason.lua │ │ ├── cursorword.lua │ │ ├── indent-blankline.lua │ │ ├── easypick.lua │ │ ├── tmux.lua │ │ ├── nvim-lint.lua │ │ ├── neorg.lua │ │ ├── vim-visual-multi.lua │ │ ├── conform.lua │ │ ├── other.lua │ │ ├── comment.lua │ │ ├── vim-startify.lua │ │ ├── nvim-autopairs.lua │ │ ├── nvim-treesitter.lua │ │ ├── blink-cmp.lua │ │ ├── nvim-ufo.lua │ │ ├── gitsigns.lua │ │ ├── jdtls.lua │ │ ├── sfm.lua │ │ ├── telescope.lua │ │ ├── nvim-dap.lua │ │ └── barbar.lua │ ├── config │ │ ├── commands.lua │ │ ├── colorschema.lua │ │ ├── autocmds.lua │ │ ├── keymaps.lua │ │ └── options.lua │ ├── core │ │ ├── cutlass.lua │ │ ├── open.lua │ │ ├── nohlsearch.lua │ │ ├── float_input.lua │ │ ├── floaterm.lua │ │ ├── picsur.lua │ │ ├── tasks.lua │ │ └── statusline.lua │ ├── icons.lua │ └── plugin_loader.lua ├── ftplugin │ ├── go.lua │ ├── java.lua │ └── gomod.lua └── init.lua ├── mise └── config.toml ├── sketchybar ├── plugins │ ├── time.sh │ ├── date.sh │ ├── aerospace.sh │ ├── vpn.sh │ ├── wifi.sh │ ├── slack.sh │ ├── input_source.sh │ ├── volume.sh │ ├── task.sh │ └── battery.sh └── sketchybarrc ├── aerospace ├── notification.sh └── aerospace.toml ├── zsh ├── functions │ ├── __fzfp │ ├── mcd │ ├── fgm │ ├── fgco │ ├── fprj │ ├── fcmd │ └── sgg ├── zshrc.d │ ├── alias.zsh │ ├── keybindings.zsh │ ├── log.zsh │ ├── aws.zsh │ ├── kubectl.zsh │ └── bitwarden.zsh └── zshrc ├── raycast └── Raycast 2025-03-07 15.53.10.rayconfig ├── navi ├── cheats │ ├── base64.cheat │ ├── qmk.cheat │ ├── bitwarden.cheat │ ├── ssh.cheat │ ├── wireguard.cheat │ ├── mysql.cheat │ ├── docker.cheat │ ├── network.cheat │ ├── osx.cheat │ ├── redis.cheat │ ├── mise.cheat │ ├── psql.cheat │ ├── aws.cheat │ └── git.cheat └── config.yaml ├── .editorconfig ├── .stylua.toml ├── borders └── bordersrc ├── .gitignore ├── docker └── config.json ├── git ├── gitignore └── gitconfig ├── task └── taskrc ├── warpd └── config ├── .luacheckrc ├── ai ├── mcp.json ├── commands │ └── gemini │ │ ├── review.toml │ │ └── commit.toml └── CLAUDE.md ├── docs ├── alacritty-popup.md ├── macos.md └── karabiner.md ├── brew └── Brewfile ├── alacritty ├── alacritty-popup.yml └── alacritty.toml ├── surfingkeys └── surfingkeys.js ├── karabiner └── karabiner.edn ├── starship └── starship.toml ├── install.sh └── tmux └── tmux.conf /nvim/after/indent/ruby.vim: -------------------------------------------------------------------------------- 1 | setlocal indentkeys-=. 2 | -------------------------------------------------------------------------------- /mise/config.toml: -------------------------------------------------------------------------------- 1 | [tools] 2 | node = "latest" 3 | go = "latest" 4 | rust = "latest" 5 | -------------------------------------------------------------------------------- /sketchybar/plugins/time.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sketchybar --set $NAME label="$(date '+%H:%M')" 4 | 5 | -------------------------------------------------------------------------------- /aerospace/notification.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | osascript -e "display notification \"$1\" with title \"AeroSpace\"" 4 | -------------------------------------------------------------------------------- /nvim/lua/lsp/settings/ts_ls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | init_options = { 3 | maxTsServerMemory = 8192 4 | }, 5 | } 6 | -------------------------------------------------------------------------------- /sketchybar/plugins/date.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | sketchybar --set $NAME label="$(date '+%a %d. %b')" 4 | 5 | -------------------------------------------------------------------------------- /zsh/functions/__fzfp: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Open fzf in tmux popup 4 | function __fzfp() { 5 | fzf-tmux -p -w 70% -h 70% 6 | } 7 | -------------------------------------------------------------------------------- /zsh/functions/mcd: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Make directory and change into it. 4 | function mcd() { 5 | mkdir -p "$1" && cd "$1"; 6 | } 7 | -------------------------------------------------------------------------------- /raycast/Raycast 2025-03-07 15.53.10.rayconfig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinhhuy258/dotfiles/HEAD/raycast/Raycast 2025-03-07 15.53.10.rayconfig -------------------------------------------------------------------------------- /navi/cheats/base64.cheat: -------------------------------------------------------------------------------- 1 | % base64 2 | 3 | # Encode 4 | echo -n | base64 5 | 6 | # Decode 7 | echo -n | base64 --decode 8 | -------------------------------------------------------------------------------- /zsh/zshrc.d/alias.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | alias vim=nvim 4 | alias vi=nvim 5 | 6 | alias lg=lazygit 7 | 8 | alias gdlm="git delete-local-merged" 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | charset = utf-8 3 | 4 | [*.lua] 5 | max_line_length = 120 6 | indent_size = 2 7 | 8 | [gitconfig] 9 | indent_style = tab 10 | -------------------------------------------------------------------------------- /.stylua.toml: -------------------------------------------------------------------------------- 1 | column_width = 120 2 | line_endings = "Unix" 3 | indent_type = "Spaces" 4 | indent_width = 2 5 | quote_style = "AutoPreferDouble" 6 | no_call_parentheses = true 7 | -------------------------------------------------------------------------------- /borders/bordersrc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | options=( 4 | width=5.0 5 | active_color=0xffe1e3e4 6 | inactive_color=0xff494d64 7 | ) 8 | 9 | borders "${options[@]}" 10 | -------------------------------------------------------------------------------- /nvim/lua/plugins/clever-f.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | vim.g.clever_f_across_no_line = 1 5 | vim.g.clever_f_fix_key_direction = 1 6 | end 7 | 8 | return M 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | nvim/autoload 2 | nvim/plugged 3 | nvim/session 4 | 5 | navi/*.log 6 | 7 | .DS_Store 8 | 9 | lazy-lock.json 10 | 11 | Brewfile.lock.json 12 | 13 | .* 14 | !/.gitignore 15 | -------------------------------------------------------------------------------- /docker/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "auths": {}, 3 | "credsStore": "osxkeychain", 4 | "currentContext": "colima", 5 | "cliPluginsExtraDirs": [ 6 | "$HOMEBREW_PREFIX/lib/docker/cli-plugins" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /nvim/lua/lsp/settings/basedpyright.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | basedpyright = { 4 | analysis = { 5 | typeCheckingMode = "basic", 6 | }, 7 | }, 8 | }, 9 | } 10 | -------------------------------------------------------------------------------- /zsh/functions/fgm: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | function fgm() { 4 | branch=$(git for-each-ref --format="%(refname:short)" refs/heads | __fzfp) 5 | if [ -n "$branch" ]; then 6 | git merge "$branch" 7 | fi 8 | } 9 | -------------------------------------------------------------------------------- /zsh/functions/fgco: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | function fgco() { 4 | branch=$(git for-each-ref --format="%(refname:short)" refs/heads | __fzfp) 5 | if [ -n "$branch" ]; then 6 | git checkout "$branch" 7 | fi 8 | } 9 | -------------------------------------------------------------------------------- /git/gitignore: -------------------------------------------------------------------------------- 1 | # Mac 2 | .DS_Store 3 | 4 | # Editor 5 | .*.sw[a-z] 6 | *~ 7 | .#* 8 | .idea 9 | .vscode 10 | 11 | # Claude 12 | .claude 13 | CLAUDE.md 14 | 15 | # Codex 16 | AGENTS.md 17 | 18 | # ENV 19 | .env 20 | -------------------------------------------------------------------------------- /sketchybar/plugins/aerospace.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [ "$1" = "$FOCUSED_WORKSPACE" ]; then 4 | sketchybar --set "$NAME" background.drawing=on 5 | else 6 | sketchybar --set "$NAME" background.drawing=off 7 | fi 8 | -------------------------------------------------------------------------------- /nvim/lua/plugins/vim-rails.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | keymaps.set("n", "aa", ":A", { noremap = true, silent = true }) 7 | end 8 | 9 | return M 10 | -------------------------------------------------------------------------------- /sketchybar/plugins/vpn.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | WIREGUARD_RUNNING="$(ls /var/run/wireguard)" 4 | 5 | if [ -n "$WIREGUARD_RUNNING" ]; then 6 | sketchybar --set "$NAME" icon= 7 | else 8 | sketchybar --set "$NAME" icon= 9 | fi 10 | -------------------------------------------------------------------------------- /nvim/lua/plugins/git.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | local status_ok, git = pcall(require, "git") 5 | if not status_ok then 6 | return 7 | end 8 | 9 | git.setup { 10 | winbar = true, 11 | } 12 | end 13 | 14 | return M 15 | -------------------------------------------------------------------------------- /nvim/ftplugin/go.lua: -------------------------------------------------------------------------------- 1 | vim.opt_local.expandtab = false -- Use tabs instead of spaces 2 | vim.opt_local.softtabstop = 4 -- Number of spaces that a in the file counts for 3 | vim.opt_local.shiftwidth = 4 -- Number of spaces to use for each step of (auto)indent. Used for >>, <<, etc 4 | -------------------------------------------------------------------------------- /nvim/ftplugin/java.lua: -------------------------------------------------------------------------------- 1 | vim.opt_local.expandtab = true -- Convert tabs to spaces 2 | vim.opt_local.softtabstop = 4 -- Number of spaces that a in the file counts for 3 | vim.opt_local.shiftwidth = 4 -- Number of spaces to use for each step of (auto)indent. Used for >>, <<, etc 4 | -------------------------------------------------------------------------------- /task/taskrc: -------------------------------------------------------------------------------- 1 | # Files 2 | data.location=~/.task 3 | 4 | # From taskrc man page https://linux.die.net/man/5/taskrc 5 | weekstart=monday 6 | dateformat=d/m/Y 7 | dateformat.report=d/m/Y 8 | dateformat.holiday=DMY 9 | dateformat.annotation=d/m/Y 10 | report.X.dateformat=d/m/Y 11 | -------------------------------------------------------------------------------- /nvim/ftplugin/gomod.lua: -------------------------------------------------------------------------------- 1 | vim.opt_local.expandtab = false -- Use tabs instead of spaces 2 | vim.opt_local.softtabstop = 4 -- Number of spaces that a in the file counts for 3 | vim.opt_local.shiftwidth = 4 -- Number of spaces to use for each step of (auto)indent. Used for >>, <<, etc 4 | -------------------------------------------------------------------------------- /warpd/config: -------------------------------------------------------------------------------- 1 | hint_activation_key:unbind 2 | hint2_activation_key:unbind 3 | grid_activation_key:unbind 4 | history_activation_key:unbind 5 | activation_key:unbind 6 | hint2_oneshot_key:unbind 7 | screen_activation_key:unbind 8 | hint_oneshot_key:A-M-l 9 | screen_oneshot_key:A-M-s 10 | -------------------------------------------------------------------------------- /nvim/lua/plugins/which-key.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | local which_key_ok, which_key = pcall(require, "which-key") 5 | if not which_key_ok then 6 | return 7 | end 8 | 9 | which_key.setup { 10 | preset = "modern", 11 | } 12 | end 13 | 14 | return M 15 | -------------------------------------------------------------------------------- /sketchybar/plugins/wifi.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | SSID="$(ipconfig getsummary en0 | awk -F ' SSID : ' '/ SSID : / {print $2}')" 4 | 5 | if [ "$SSID" = "" ]; then 6 | sketchybar --set "$NAME" label="Disconnected" icon=󰖪 7 | else 8 | sketchybar --set "$NAME" label="$SSID" icon=󰖩 9 | fi 10 | -------------------------------------------------------------------------------- /zsh/functions/fprj: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Open project under workspace folder 4 | function fprj() { 5 | cd $WORKSPACE; ls -d */ | __fzfp | { 6 | cd -; 7 | read result; 8 | if [ ! -z "$result" ]; then 9 | cd $WORKSPACE/$result 10 | fi 11 | } 12 | zle && zle reset-prompt 13 | } 14 | -------------------------------------------------------------------------------- /sketchybar/plugins/slack.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | STATUS_LABEL=$(lsappinfo info -only StatusLabel "Slack") 4 | 5 | if [[ $STATUS_LABEL =~ \"label\"=\"([^\"]*)\" ]]; then 6 | LABEL="${BASH_REMATCH[1]}" 7 | ICON="󰒱" 8 | else 9 | exit 0 10 | fi 11 | 12 | sketchybar --set $NAME icon=$ICON label="${LABEL}" 13 | -------------------------------------------------------------------------------- /nvim/lua/lsp/settings/gopls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | gopls = { 4 | analyses = { 5 | unusedvariable = true, 6 | unusedparams = true, 7 | unusedwrite = true, 8 | }, 9 | staticcheck = true, 10 | completeUnimported = true, 11 | usePlaceholders = true, 12 | }, 13 | }, 14 | } 15 | -------------------------------------------------------------------------------- /nvim/lua/plugins/nvim-navbuddy.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local status_ok, _ = pcall(require, "nvim-navbuddy") 7 | if not status_ok then 8 | return 9 | end 10 | 11 | keymaps.set("n", "cc", ":Navbuddy", { noremap = false }) 12 | end 13 | 14 | return M 15 | -------------------------------------------------------------------------------- /navi/cheats/qmk.cheat: -------------------------------------------------------------------------------- 1 | % qmk 2 | 3 | # Flash ErgoDox EZ 4 | make ergodox_ez:dinhhuy258:teensy 5 | 6 | # Flash Corne (default) 7 | make crkbd:dinhhuy258:flash 8 | 9 | # Flash Corne (with serial pin D3) 10 | make crkbd:dinhhuy258:flash SERIAL_PIN=D3 TAPPING_TERM=175 11 | 12 | # Flash Corne (with RGB Lighting) 13 | make crkbd:dinhhuy258:flash USE_RGB_LIGHTING=yes 14 | -------------------------------------------------------------------------------- /navi/cheats/bitwarden.cheat: -------------------------------------------------------------------------------- 1 | % bitwarden 2 | 3 | # Create a session environment variable 4 | export BW_SESSION="$(bw unlock --raw)" 5 | 6 | # Sync the vault 7 | bw sync 8 | 9 | # Check bitwarden status 10 | bw status | jq -r '.status' 11 | 12 | # Lock the vault 13 | bw lock 14 | 15 | # Add SSH key to ssh-agent 16 | bw_load_ssh_keys 17 | 18 | # Get password 19 | bw_get_password 20 | -------------------------------------------------------------------------------- /nvim/lua/lsp/settings/jsonls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | json = { 4 | schemas = require("schemastore").json.schemas(), 5 | }, 6 | }, 7 | setup = { 8 | commands = { 9 | Format = { 10 | function() 11 | vim.lsp.buf.range_formatting({}, { 0, 0 }, { vim.fn.line "$", 0 }) 12 | end, 13 | }, 14 | }, 15 | }, 16 | } 17 | -------------------------------------------------------------------------------- /sketchybar/plugins/input_source.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | INPUT_SOURCE=$(defaults read ~/Library/Preferences/com.apple.HIToolbox.plist AppleSelectedInputSources | grep 'KeyboardLayout Name' | sed -E 's/^.+ = \"?([^\"]+)\"?;$/\1/') 4 | if [ $INPUT_SOURCE = "ABC" ] || [ $INPUT_SOURCE = "Australian" ]; then 5 | ICON="󰬌" 6 | else 7 | ICON="󰬝" 8 | fi 9 | 10 | sketchybar --set $NAME icon="$ICON" 11 | 12 | -------------------------------------------------------------------------------- /navi/cheats/ssh.cheat: -------------------------------------------------------------------------------- 1 | % ssh 2 | 3 | # Copy a file from a remote host to the local host 4 | scp @: 5 | 6 | # Copy a file from the local host to a remote host 7 | scp @: 8 | 9 | # Delete all currently loaded keys from the ssh-agent 10 | ssh-add -D 11 | 12 | # List fingerprints of currently loaded keys 13 | ssh-add -l 14 | -------------------------------------------------------------------------------- /navi/cheats/wireguard.cheat: -------------------------------------------------------------------------------- 1 | % wireguard 2 | 3 | # Start tunnel 4 | sudo wg-quick up 5 | 6 | # Stop tunnel 7 | sudo wg-quick down 8 | 9 | # Show wireguard status 10 | sudo wg show 11 | 12 | # Show tunnel configuration 13 | sudo cat /usr/local/etc/wireguard/.conf 14 | 15 | $ wireguard-conf: ls /usr/local/etc/wireguard/*.conf | awk -F/ '{print $NF}' | sed 's/\.conf$//' | tail -n +1 16 | -------------------------------------------------------------------------------- /navi/cheats/mysql.cheat: -------------------------------------------------------------------------------- 1 | % mysql 2 | 3 | # Connect to the MySQL database server 4 | mysql -h -P -u -p 5 | 6 | # List all databases 7 | SHOW DATABASES; 8 | 9 | # Connect to a specific database 10 | USE ; 11 | 12 | # List all tables in the current database 13 | SHOW TABLES; 14 | 15 | $ host: echo 'localhost' --- --fzf-overrides '--no-select-1' 16 | $ port: echo '3306' --- --fzf-overrides '--no-select-1' 17 | -------------------------------------------------------------------------------- /nvim/lua/plugins/hop.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local status_ok, hop = pcall(require, "hop") 7 | if not status_ok then 8 | return 9 | end 10 | 11 | hop.setup { keys = "etovxqpdygfblzhckisuran" } 12 | 13 | keymaps.set("n", "", ":HopChar1", { noremap = false }) 14 | keymaps.set("n", "l", ":HopLine", { noremap = false }) 15 | end 16 | 17 | return M 18 | -------------------------------------------------------------------------------- /sketchybar/plugins/volume.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | VOLUME=$(osascript -e "output volume of (get volume settings)") 4 | IS_MUTED=$(osascript -e "output muted of (get volume settings)") 5 | 6 | if [ "$IS_MUTED" = "true" ]; then 7 | ICON="󰝟" 8 | else 9 | if [ "$VOLUME" = "0" ]; then 10 | ICON="" 11 | elif [ "$VOLUME" -lt "50" ]; then 12 | ICON="" 13 | else 14 | ICON="" 15 | fi 16 | fi 17 | 18 | sketchybar --set $NAME icon="$ICON" label="${VOLUME}%" 19 | -------------------------------------------------------------------------------- /nvim/lua/plugins/treesj.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local treesj_ok, treesj = pcall(require, "treesj") 7 | if not treesj_ok then 8 | return 9 | end 10 | 11 | treesj.setup { 12 | use_default_keymaps = false, 13 | max_join_length = 9999, 14 | } 15 | 16 | keymaps.set("n", "jj", function() 17 | treesj.toggle() 18 | end, { noremap = true, silent = true }) 19 | end 20 | 21 | return M 22 | -------------------------------------------------------------------------------- /navi/cheats/docker.cheat: -------------------------------------------------------------------------------- 1 | % docker 2 | 3 | # Delete a Docker image 4 | docker rmi 5 | 6 | # Stop a running container through SIGTERM 7 | docker stop sh 11 | 12 | # Print the last lines of a container's logs and following its logs 13 | docker logs --tail 100 -f 14 | 15 | $ image_id: docker images --- --headers 1 --column 3 16 | $ container_id: docker ps --- --headers 1 --column 1 17 | -------------------------------------------------------------------------------- /zsh/zshrc.d/keybindings.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | autoload -z edit-command-line 4 | zle -N edit-command-line 5 | bindkey '^v' edit-command-line 6 | 7 | zle -N fprj 8 | bindkey '^ ' fprj 9 | 10 | # see `man bash` to define more key bindings 11 | bindkey "^[[1;3C" forward-word 12 | bindkey "^[[1;3D" backward-word 13 | bindkey "^i" kill-line 14 | bindkey "^y" kill-whole-line 15 | 16 | bindkey '\t' complete-word 17 | 18 | bindkey -r '^g' # default key binding for navi 19 | bindkey '^a' _navi_widget 20 | -------------------------------------------------------------------------------- /navi/cheats/network.cheat: -------------------------------------------------------------------------------- 1 | % network 2 | 3 | # Find the process running on a given port 4 | lsof -i : 5 | 6 | # Kill a process running on a given port 7 | lsof -i : \ 8 | | awk '{l=$2} END {print l}' \ 9 | | xargs kill 10 | 11 | # Find local IP address 12 | ifconfig \ 13 | | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' \ 14 | | grep -Eo '([0-9]*\.){3}[0-9]*' \ 15 | | grep -v '127.0.0.1' \ 16 | | tail -n1 17 | 18 | # Find public IP address 19 | dig +short myip.opendns.com @resolver1.opendns.com 20 | -------------------------------------------------------------------------------- /navi/cheats/osx.cheat: -------------------------------------------------------------------------------- 1 | % osx 2 | 3 | # Show hidden files in Finder 4 | defaults write com.apple.finder AppleShowAllFiles -bool true; \ 5 | killall Finder 6 | 7 | # Hide hidden files in Finder 8 | defaults write com.apple.finder AppleShowAllFiles -bool false; \ 9 | killall Finder 10 | 11 | # Show items in desktop 12 | defaults write com.apple.finder CreateDesktop -bool true; \ 13 | killall Finder 14 | 15 | # Hide items in desktop 16 | defaults write com.apple.finder CreateDesktop -bool false; \ 17 | killall Finder 18 | -------------------------------------------------------------------------------- /nvim/lua/plugins/vim-test.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | vim.g["test#strategy"] = "vimux" 7 | 8 | -- setup keymap 9 | -- run nearest test 10 | keymaps.set("n", "tt", ":TestNearest", { noremap = true }) 11 | -- run the current file 12 | keymaps.set("n", "tT", ':TestFile', { noremap = true }) 13 | -- run the last test 14 | keymaps.set("n", "t.", ':TestLast', { noremap = true }) 15 | end 16 | 17 | return M 18 | -------------------------------------------------------------------------------- /navi/cheats/redis.cheat: -------------------------------------------------------------------------------- 1 | % redis 2 | 3 | # Connect to the Redis 4 | redis-cli -h -p 5 | 6 | # Returns all keys matching pattern 7 | KEYS 8 | 9 | # Set key to hold the string value 10 | SET 11 | 12 | # Get the string value of key 13 | GET 14 | 15 | # Checks if one or more keys exist 16 | EXISTS 17 | 18 | # Removes the specified keys 19 | DEL 20 | 21 | $ host: echo 'localhost' --- --fzf-overrides '--no-select-1' 22 | $ port: echo '6379' --- --fzf-overrides '--no-select-1' 23 | -------------------------------------------------------------------------------- /sketchybar/plugins/task.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PENDING_TASK=$(task +PENDING count) 4 | OVERDUE_TASK=$(task +OVERDUE count) 5 | 6 | if [[ $PENDING_TASK == 0 ]]; then 7 | sketchybar --set $NAME label.drawing=off icon="󱃔" 8 | else 9 | if [[ $OVERDUE_TASK == 0 ]]; then 10 | LABEL=$PENDING_TASK 11 | else 12 | LABEL="!$OVERDUE_TASK/$PENDING_TASK" 13 | fi 14 | 15 | sketchybar --set $NAME label="${LABEL}" \ 16 | label.drawing=on \ 17 | icon="󱃔" 18 | fi 19 | -------------------------------------------------------------------------------- /zsh/functions/fcmd: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Run frequently used commands 4 | # First param take local path to set of commands, i.e. ~/local/cmds 5 | function fcmd() { 6 | echo $1 7 | local cmd=$(cat $1 | ${2-"__fzfp"}) 8 | if [ -n "$cmd" ]; then 9 | local escape=$(echo $cmd | sed 's/[]\/$*.^[]/\\&/g') 10 | echo -e "$cmd\n$(cat $1 | sed "s/$escape//g" | sed '/^$/d')" > $1 11 | echo "" 12 | echo $fg[yellow] "$cmd" 13 | echo "" 14 | eval $cmd 15 | else 16 | echo $fg[red] "Run nothing!" 17 | fi 18 | } 19 | -------------------------------------------------------------------------------- /navi/cheats/mise.cheat: -------------------------------------------------------------------------------- 1 | % mise 2 | 3 | # Install the latest version of a package 4 | mise install 5 | 6 | # Install a specific version of a package 7 | mise install @ 8 | 9 | # Set global version of a package 10 | mise use -g 11 | 12 | # Set global version to a specific version of a package 13 | mise use -g @ 14 | 15 | # Show currently active versions 16 | mise current 17 | 18 | # List installed runtime versions 19 | mise ls 20 | 21 | # List runtime versions available for install 22 | mise ls-remote 23 | -------------------------------------------------------------------------------- /nvim/lua/plugins/copilot.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | local status_ok, copilot = pcall(require, "copilot") 5 | if not status_ok then 6 | return 7 | end 8 | 9 | copilot.setup { 10 | suggestion = { 11 | enabled = true, 12 | auto_trigger = false, 13 | debounce = 75, 14 | keymap = { 15 | accept = "", 16 | accept_word = false, 17 | accept_line = false, 18 | next = "", 19 | prev = "", 20 | }, 21 | }, 22 | panel = { 23 | enabled = false, 24 | }, 25 | } 26 | end 27 | 28 | return M 29 | -------------------------------------------------------------------------------- /nvim/lua/plugins/fzf-lua.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local fzf_status_ok, fzf = pcall(require, "fzf-lua") 7 | if not fzf_status_ok then 8 | return 9 | end 10 | 11 | local actions = require "fzf-lua.actions" 12 | 13 | fzf.setup { 14 | actions = { 15 | files = { 16 | true, 17 | ["ctrl-h"] = actions.file_split, 18 | ["ctrl-v"] = actions.file_vsplit, 19 | }, 20 | }, 21 | } 22 | 23 | keymaps.set("n", "ff", ":lua require('fzf-lua').files()", { noremap = true }) 24 | end 25 | 26 | return M 27 | -------------------------------------------------------------------------------- /nvim/lua/plugins/mason.lua: -------------------------------------------------------------------------------- 1 | local icons = require "icons" 2 | 3 | local M = {} 4 | 5 | function M.setup() 6 | local mason_ok, mason = pcall(require, "mason") 7 | if not mason_ok then 8 | return 9 | end 10 | 11 | mason.setup { 12 | ui = { 13 | border = "rounded", 14 | icons = { 15 | package_installed = icons.mason.package_installed, 16 | package_pending = icons.mason.package_pending, 17 | package_uninstalled = icons.mason.package_uninstalled, 18 | }, 19 | }, 20 | log_level = vim.log.levels.INFO, 21 | max_concurrent_installers = 4, 22 | } 23 | end 24 | 25 | return M 26 | -------------------------------------------------------------------------------- /nvim/lua/config/commands.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.setup() 4 | vim.cmd "command! FixWhitespace :%s/\\s\\+$//e" 5 | vim.cmd "command! StartProfiling profile start ~/.profile.log | profile func * | profile file * | echo 'Profiling started'" 6 | 7 | -- Abbreviations 8 | vim.cmd "cnoreabbrev W! w!" 9 | vim.cmd "cnoreabbrev Q! q!" 10 | vim.cmd "cnoreabbrev Qall! qall!" 11 | vim.cmd "cnoreabbrev Wq wq" 12 | vim.cmd "cnoreabbrev Wa wa" 13 | vim.cmd "cnoreabbrev wQ wq" 14 | vim.cmd "cnoreabbrev WQ wq" 15 | vim.cmd "cnoreabbrev W w" 16 | vim.cmd "cnoreabbrev Q q" 17 | vim.cmd "cnoreabbrev Qall qall" 18 | end 19 | 20 | return M 21 | -------------------------------------------------------------------------------- /nvim/lua/plugins/cursorword.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.setup() 4 | local cursorword_ok, cursorword = pcall(require, "mini.cursorword") 5 | if not cursorword_ok then 6 | return 7 | end 8 | 9 | local group = vim.api.nvim_create_augroup("dotfiles_filetype_minicursorword_disable", { clear = true }) 10 | 11 | vim.api.nvim_create_autocmd("FileType", { 12 | group = group, 13 | pattern = { 14 | "sfm", 15 | "VimDatabase", 16 | "git.nvim", 17 | }, 18 | callback = function() 19 | vim.b.minicursorword_disable = true 20 | end, 21 | }) 22 | 23 | cursorword.setup() 24 | end 25 | 26 | return M 27 | -------------------------------------------------------------------------------- /nvim/lua/plugins/indent-blankline.lua: -------------------------------------------------------------------------------- 1 | local icons = require "icons" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local status_ok, ibl = pcall(require, "ibl") 7 | if not status_ok then 8 | return 9 | end 10 | 11 | ibl.setup { 12 | scope = { 13 | enabled = false, 14 | }, 15 | exclude = { 16 | filetypes = { 17 | "help", 18 | "terminal", 19 | "startify", 20 | "sfm", 21 | }, 22 | buftypes = { 23 | "terminal", 24 | }, 25 | }, 26 | indent = { 27 | char = icons.ibl.char, 28 | tab_char = icons.ibl.tab_char, 29 | }, 30 | } 31 | end 32 | 33 | return M 34 | -------------------------------------------------------------------------------- /zsh/functions/sgg: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Search google 4 | function sgg() { 5 | local gg_url="https://www.google.com/search?q=" 6 | 7 | echo -n "Search google: " 8 | read search 9 | 10 | if [ ! -z "$search" ]; then 11 | # if search goes in the query string ==> space as +, otherwise %20 12 | # see https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20 13 | local param="-P" 14 | [[ "$gg_url" == *\?*= ]] && param="" 15 | 16 | # build search url: 17 | # join arguments passed with '+', then append to search engine URL 18 | url="${gg_url}$(omz_urlencode $search)" 19 | 20 | open_command "$url" 21 | fi 22 | } 23 | -------------------------------------------------------------------------------- /nvim/lua/plugins/easypick.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local status_ok, easypick = pcall(require, "easypick") 7 | if not status_ok then 8 | return 9 | end 10 | 11 | easypick.setup { 12 | pickers = { 13 | -- list files that have conflicts with diffs in preview 14 | { 15 | name = "git_conflicts", 16 | command = "git diff --name-only --diff-filter=U --relative", 17 | previewer = easypick.previewers.file_diff(), 18 | }, 19 | }, 20 | } 21 | 22 | keymaps.set("n", "fc", ":Easypick git_conflicts", { noremap = true }) 23 | end 24 | 25 | return M 26 | -------------------------------------------------------------------------------- /.luacheckrc: -------------------------------------------------------------------------------- 1 | -- vim: ft=lua tw=80 2 | 3 | stds.nvim = { 4 | globals = { 5 | vim = { fields = { "g" } }, 6 | "C", 7 | "Config", 8 | "WORKSPACE_PATH", 9 | "JAVA_LS_EXECUTABLE", 10 | "MUtils", 11 | os = {fields = {"capture"}} 12 | }, 13 | read_globals = { 14 | "jit", 15 | "os", 16 | "vim", 17 | -- vim = { fields = { "cmd", "api", "fn", "o" } }, 18 | }, 19 | } 20 | std = "lua51+nvim" 21 | 22 | 23 | -- Don't report unused self arguments of methods. 24 | self = false 25 | 26 | -- Rerun tests only if their modification time changed. 27 | cache = true 28 | 29 | ignore = { 30 | "631", -- max_line_length 31 | "212/_.*", -- unused argument, for vars with "_" prefix 32 | } 33 | -------------------------------------------------------------------------------- /ai/mcp.json: -------------------------------------------------------------------------------- 1 | { 2 | "mcpServers": { 3 | "context7": { 4 | "args": [ 5 | "-y", 6 | "@upstash/context7-mcp" 7 | ], 8 | "command": "npx" 9 | }, 10 | "github": { 11 | "headers": { 12 | "Authorization": "Bearer ${GITHUB_PERSONAL_ACCESS_TOKEN}" 13 | }, 14 | "url": "https://api.githubcopilot.com/mcp/" 15 | }, 16 | "playwright": { 17 | "args": [ 18 | "@playwright/mcp@latest" 19 | ], 20 | "command": "npx" 21 | }, 22 | "sequentialthinking": { 23 | "args": [ 24 | "-y", 25 | "@modelcontextprotocol/server-sequential-thinking" 26 | ], 27 | "command": "npx" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /zsh/zshrc.d/log.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | bold=$(tput bold) 4 | underline=$(tput sgr 0 1) 5 | reset=$(tput sgr0) 6 | 7 | green=$(tput setaf 76) 8 | blue=$(tput setaf 38) 9 | tan=$(tput setaf 3) 10 | red=$(tput setaf 1) 11 | 12 | function e_arrow() { 13 | printf "➜ $1\n" 14 | } 15 | 16 | function e_success() { 17 | printf "${green}✔ %s${reset}\n" "$@" 18 | } 19 | 20 | function e_warning() { 21 | printf "${tan}➜ %s${reset}\n" "$@" 22 | } 23 | 24 | function e_error() { 25 | printf "${red}✖ %s${reset}\n" "$@" 26 | } 27 | 28 | function e_bold() { 29 | printf "${bold}%s${reset}\n" "$@" 30 | } 31 | 32 | function e_note() { 33 | printf "${underline}${bold}${blue}Note:${reset} ${blue}%s${reset}\n" "$@" 34 | } 35 | -------------------------------------------------------------------------------- /nvim/lua/core/cutlass.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | function M.setup() 6 | local bindings = { 7 | { "c", '"_c', "nx" }, 8 | { "cc", '"_S', "n" }, 9 | { "C", '"_C', "nx" }, 10 | { "s", '"_s', "nx" }, 11 | { "S", '"_S', "nx" }, 12 | { "d", '"_d', "nx" }, 13 | { "dd", '"_dd', "n" }, 14 | { "D", '"_D', "nx" }, 15 | { "x", '"_x', "n" }, 16 | { "X", '"_X', "nx" }, 17 | } 18 | 19 | for _, binding in pairs(bindings) do 20 | binding[3]:gsub(".", function(mode) 21 | keymaps.set(mode, binding[1], binding[2], { 22 | noremap = true, 23 | silent = true, 24 | }) 25 | end) 26 | end 27 | end 28 | 29 | return M 30 | -------------------------------------------------------------------------------- /nvim/lua/plugins/tmux.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.setup() 4 | local status_ok, tmux = pcall(require, "tmux") 5 | if not status_ok then 6 | return 7 | end 8 | 9 | tmux.setup { 10 | copy_sync = { 11 | enable = false, 12 | redirect_to_clipboard = false, 13 | sync_clipboard = false, 14 | sync_deletes = false, 15 | }, 16 | navigation = { 17 | -- Enables default keybindings (C-hjkl) for normal mode 18 | enable_default_keybindings = true, 19 | }, 20 | resize = { 21 | -- Enables default keybindings (A-hjkl) for normal mode 22 | enable_default_keybindings = true, 23 | resize_step_x = 3, 24 | resize_step_y = 3, 25 | }, 26 | } 27 | end 28 | 29 | return M 30 | -------------------------------------------------------------------------------- /navi/cheats/psql.cheat: -------------------------------------------------------------------------------- 1 | % psql 2 | 3 | # Connect to the PostgreSQL database server 4 | psql -h -p -U 5 | 6 | # List all databases 7 | \l 8 | 9 | # Connect to a specific database 10 | \c 11 | 12 | # List all tables in the current database 13 | \dt 14 | 15 | # Get detailed information on a table. 16 | \d+ 17 | 18 | # Export database 19 | pg_dump -h -p -U > 20 | 21 | # Import database 22 | psql -h -p -U < 23 | 24 | $ host: echo 'localhost' --- --fzf-overrides '--no-select-1' 25 | $ port: echo '5432' --- --fzf-overrides '--no-select-1' 26 | $ db_export_file = echo 'db.dump' --- --fzf-overrides '--no-select-1' 27 | -------------------------------------------------------------------------------- /nvim/lua/plugins/nvim-lint.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | local lint_ok, lint = pcall(require, "lint") 5 | if not lint_ok then 6 | return 7 | end 8 | 9 | lint.linters_by_ft = { 10 | javascript = { "eslint_d" }, 11 | typescript = { "eslint_d" }, 12 | javascriptreact = { "eslint_d" }, 13 | typescriptreact = { "eslint_d" }, 14 | python = { "ruff" }, 15 | go = { "golangcilint" }, 16 | ruby = { "rubocop" }, 17 | } 18 | 19 | local lint_augroup = vim.api.nvim_create_augroup("lint", { clear = true }) 20 | 21 | vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave" }, { 22 | group = lint_augroup, 23 | callback = function() 24 | require("lint").try_lint() 25 | end, 26 | }) 27 | end 28 | 29 | return M 30 | -------------------------------------------------------------------------------- /nvim/lua/core/open.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | local function open_file(path) 6 | local dir = "" 7 | if vim.fn.isdirectory(path) then 8 | dir = path 9 | else 10 | dir = vim.fn.fnamemodify(path, ":h") 11 | end 12 | 13 | if not vim.fn.isdirectory(dir) then 14 | -- if the directory was moved/deleted 15 | return 16 | end 17 | 18 | if vim.fn.filereadable(path) then 19 | vim.fn.system("open --reveal " .. vim.fn.shellescape(path)) 20 | else 21 | vim.fn.system("open " .. vim.fn.shellescape(dir)) 22 | end 23 | end 24 | 25 | function M.setup() 26 | keymaps.set("n", "gof", function() 27 | open_file(vim.fn.expand "%:p") 28 | end) 29 | 30 | keymaps.set("n", "goF", function() 31 | open_file(vim.fn.getcwd()) 32 | end) 33 | end 34 | 35 | return M 36 | -------------------------------------------------------------------------------- /docs/alacritty-popup.md: -------------------------------------------------------------------------------- 1 | # Alacritty popup 2 | 3 | I'm now creating a instance of Alacritty specifically for popup action. The issue is that using two instances of Alacritty simultaneously—one for coding and the other for popups—is somewhat difficult. 4 | 5 | ## How to build Alacritty Popup 6 | 7 | 1. Clone [this](https://github.com/dinhhuy258/alacritty) repository. 8 | 2. Checkout branch `git checkout origin/v0.9.0` 9 | 3. Run `make app` 10 | 4. The binary that is produced by the aforementioned command might not be functional. We must make a small change. 11 | 12 | - Go to `AlacrittyPopup/Contents/MacOS/` 13 | - Rename `alacritty` to `alacritty-popup` 14 | 15 | ## Q/A 16 | 17 | 1. Why is alacritty binary not shared in dotfiles? 18 | 19 | It is not possible to share the binary between machines; it needs to be unique whether we are using an M1 Mac or an Intel Mac. 20 | 21 | -------------------------------------------------------------------------------- /nvim/lua/lsp/settings/yamlls.lua: -------------------------------------------------------------------------------- 1 | return { 2 | settings = { 3 | yaml = { 4 | hover = true, 5 | completion = true, 6 | validate = true, 7 | schemaStore = { 8 | enable = true, 9 | url = "https://www.schemastore.org/api/json/catalog.json", 10 | }, 11 | schemas = require("schemastore").yaml.schemas(), 12 | customTags = { 13 | -- AWS CloudFormation 14 | "!fn", 15 | "!And", 16 | "!If", 17 | "!Not", 18 | "!Equals", 19 | "!Or", 20 | "!FindInMap sequence", 21 | "!Base64", 22 | "!Cidr", 23 | "!Ref", 24 | "!Ref Scalar", 25 | "!Sub", 26 | "!GetAtt", 27 | "!GetAZs", 28 | "!ImportValue", 29 | "!Select", 30 | "!Split", 31 | "!Join sequence", 32 | }, 33 | }, 34 | }, 35 | } 36 | -------------------------------------------------------------------------------- /nvim/lua/plugins/neorg.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local status_ok, neorg = pcall(require, "neorg") 7 | if not status_ok then 8 | return 9 | end 10 | 11 | neorg.setup { 12 | load = { 13 | ["core.defaults"] = {}, -- Loads default behaviour 14 | ["core.concealer"] = {}, -- Adds pretty icons to your documents 15 | ["core.dirman"] = { -- Manages Neorg workspaces 16 | config = { 17 | workspaces = { 18 | notes = "~/Library/Mobile Documents/com~apple~CloudDocs/Documents/notes", 19 | }, 20 | default_workspace = "notes", 21 | }, 22 | }, 23 | }, 24 | } 25 | 26 | keymaps.set("n", "ww", ":Neorg index", { noremap = true }) 27 | 28 | vim.cmd "command! NeorgFormat normal! gg=G" 29 | end 30 | 31 | return M 32 | -------------------------------------------------------------------------------- /navi/config.yaml: -------------------------------------------------------------------------------- 1 | style: 2 | tag: 3 | color: cyan # text color. possible values: https://bit.ly/3gloNNI 4 | width_percentage: 26 # column width relative to the terminal window 5 | min_width: 20 # minimum column width as number of characters 6 | comment: 7 | color: blue 8 | width_percentage: 42 9 | min_width: 45 10 | snippet: 11 | color: white 12 | 13 | finder: 14 | command: fzf # equivalent to the --finder option 15 | # overrides: --tac # equivalent to the --fzf-overrides option 16 | # overrides_var: --tac # equivalent to the --fzf-overrides-var option 17 | 18 | cheats: 19 | paths: 20 | - ~/.config/navi/cheats 21 | 22 | # search: 23 | # tags: git,!checkout # equivalent to the --tag-rules option 24 | 25 | shell: 26 | # Shell used for shell out. Possible values: bash, zsh, dash, ... 27 | command: /bin/zsh 28 | 29 | # finder_command: bash # similar, but for fzf's internals 30 | -------------------------------------------------------------------------------- /ai/commands/gemini/review.toml: -------------------------------------------------------------------------------- 1 | description="Reviews a pull request based on issue number." 2 | prompt = """ 3 | Please provide a detailed pull request review on GitHub issue: {{args}}. 4 | 5 | Follow these steps: 6 | 7 | 1. Use `gh pr view {{args}}` to pull the information of the PR. 8 | 2. Use `gh pr diff {{args}}` to view the diff of the PR. 9 | 3. Understand the intent of the PR using the PR description. 10 | 4. If PR description is not detailed enough to understand the intent of the PR, 11 | make sure to note it in your review. 12 | 5. Make sure the PR title follows Conventional Commits, here are the last five 13 | commits to the repo as examples: !{git log --pretty=format:"%s" -n 5} 14 | 6. Search the codebase if required. 15 | 7. Write a concise review of the PR, keeping in mind to encourage strong code 16 | quality and best practices. 17 | 18 | Remember to use the GitHub CLI (`gh`) with the Shell tool for all 19 | GitHub-related tasks. 20 | """ 21 | -------------------------------------------------------------------------------- /nvim/lua/core/nohlsearch.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.stop_hlsearch() 4 | if vim.v.hlsearch == 1 and vim.fn.mode() == "n" and vim.api.nvim_win_get_config(0)["relative"] == "" then 5 | vim.fn.feedkeys "(stop_hightlight_search)" 6 | end 7 | end 8 | 9 | function M.setup() 10 | vim.cmd "noremap (stop_hightlight_search) :nohlsearch" 11 | vim.cmd "noremap! (stop_hightlight_search) execute('nohlsearch')[-1]" 12 | 13 | vim.api.nvim_create_autocmd("CursorMoved", { 14 | pattern = "*", 15 | callback = function() 16 | vim.cmd [[ 17 | if v:hlsearch && !search('\%#\zs'.@/,'cnW') 18 | call luaeval("require'core.nohlsearch'.stop_hlsearch()") 19 | endif 20 | ]] 21 | end, 22 | }) 23 | 24 | vim.api.nvim_create_autocmd("InsertEnter", { 25 | pattern = "*", 26 | callback = function() 27 | require("core.nohlsearch").stop_hlsearch() 28 | end, 29 | }) 30 | end 31 | 32 | return M 33 | -------------------------------------------------------------------------------- /sketchybar/plugins/battery.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | PERCENTAGE=$(pmset -g batt | grep -Eo "\d+%" | cut -d% -f1) 4 | CHARGING=$(pmset -g batt | grep 'AC Power') 5 | 6 | if [ $PERCENTAGE = "" ]; then 7 | exit 0 8 | fi 9 | 10 | case ${PERCENTAGE} in 11 | [8-9][0-9] | 100) 12 | if [[ $CHARGING != "" ]]; then 13 | ICON="󱊦" 14 | else 15 | ICON="󱊣" 16 | fi 17 | ;; 18 | 7[0-9]) 19 | if [[ $CHARGING != "" ]]; then 20 | ICON="󱊥" 21 | else 22 | ICON="󱊢" 23 | fi 24 | ;; 25 | [4-6][0-9]) 26 | if [[ $CHARGING != "" ]]; then 27 | ICON="󱊥" 28 | else 29 | ICON="󱊢" 30 | fi 31 | ;; 32 | [1-3][0-9]) 33 | if [[ $CHARGING != "" ]]; then 34 | ICON="󱊤" 35 | else 36 | ICON="󱊡" 37 | fi 38 | ;; 39 | [0-9]) 40 | if [[ $CHARGING != "" ]]; then 41 | ICON="󰢟" 42 | else 43 | ICON="󰂎" 44 | fi 45 | ;; 46 | esac 47 | 48 | sketchybar --set $NAME icon="$ICON" label="${PERCENTAGE}%" 49 | -------------------------------------------------------------------------------- /docs/macos.md: -------------------------------------------------------------------------------- 1 | # Macos 2 | 3 | ## Increase keyboard key repeat rate 4 | 5 | **Method 1** 6 | 7 | 1. Go to `Settings -> Keyboard`. 8 | 2. Increase `Key repeat rate` and `Delay until repeat` values to maximum. 9 | 10 | **Method 2** 11 | 12 | Run following commands on the terminal: 13 | 14 | ```sh 15 | defaults write -g InitialKeyRepeat -int 10 # normal minimum is 15 (225 ms) 16 | defaults write -g KeyRepeat -int 1 # normal minimum is 2 (30 ms) 17 | ``` 18 | 19 | ## Keyboard settings 20 | 21 | - Change input source: `hyper+tab` 22 | - Disable all screenshot shortcuts 23 | 24 | ## Dock settings 25 | 26 | - Go to `Desktop & Dock` 27 | - Update `Position on screen` to `Left` 28 | - Enable `Automatically hide and show the Dock` 29 | 30 | ## Menu bar settings 31 | 32 | - Go to `Control Center` 33 | - `Bluetooth` set `Show in Menu Bar` 34 | - Set `Automatically hide and show the menu bar` to `Always` 35 | 36 | ## Disable windows opening animations 37 | 38 | ```sh 39 | defaults write -g NSAutomaticWindowAnimationsEnabled -bool false 40 | ``` 41 | -------------------------------------------------------------------------------- /navi/cheats/aws.cheat: -------------------------------------------------------------------------------- 1 | % aws 2 | 3 | # Download S3 object 4 | aws s3api get-object --bucket --key 5 | 6 | # Put S3 object 7 | aws s3api put-object --bucket --key --body 8 | 9 | # List S3 buckets 10 | aws s3api list-buckets 11 | 12 | # Invoke Lambda function 13 | aws lambda invoke --function-name --cli-binary-format raw-in-base64-out --payload '' response.json 14 | 15 | # Check codebuild status 16 | aws codebuild batch-get-builds --ids $(aws codebuild list-builds-for-project --project-name --sort-order DESCENDING --max-items 1 --output json | jq -r '.ids[0]') --query 'builds[0].{Status:buildStatus,StartTime:startTime,EndTime:endTime,Duration:timeInMinutes,Commit:sourceVersion}' --output table 17 | 18 | $ bucket: aws s3api list-buckets --query "Buckets[].Name" --output text | tr '\t' '\n' 19 | $ local_file: ls -1 20 | $ lambda-function: aws lambda list-functions --query "Functions[].FunctionName" --output text | tr '\t' '\n' 21 | $ codebuild-project: aws codebuild list-projects --query 'projects[*]' --output text | tr '\t' '\n' | fzf 22 | -------------------------------------------------------------------------------- /nvim/lua/config/colorschema.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.setup() 4 | local status_ok, tokyonight = pcall(require, "tokyonight") 5 | if not status_ok then 6 | return 7 | end 8 | 9 | tokyonight.setup { 10 | style = "night", 11 | transparent = false, 12 | on_highlights = function(highlights, colors) 13 | highlights.CursorLine.bg = colors.none 14 | highlights.StatusLine.bg = colors.none 15 | highlights.StatusLineNC.bg = colors.none 16 | 17 | -- barbar 18 | highlights.BufferCurrent.bg = colors.none 19 | highlights.BufferCurrentIndex.bg = colors.none 20 | highlights.BufferCurrentMod.bg = colors.none 21 | highlights.BufferCurrentSign.bg = colors.none 22 | highlights.BufferCurrentTarget.bg = colors.none 23 | 24 | highlights.BufferInactive.bg = colors.none 25 | highlights.BufferInactiveIndex.bg = colors.none 26 | highlights.BufferInactiveMod.bg = colors.none 27 | highlights.BufferInactiveSign.bg = colors.none 28 | highlights.BufferInactiveTarget.bg = colors.none 29 | 30 | highlights.BufferTabpageFill.bg = colors.bg 31 | end, 32 | } 33 | 34 | vim.cmd [[colorscheme tokyonight]] 35 | end 36 | 37 | return M 38 | -------------------------------------------------------------------------------- /navi/cheats/git.cheat: -------------------------------------------------------------------------------- 1 | % git 2 | 3 | # Get git user name 4 | git config user.name 5 | 6 | # Get git user email 7 | git config user.email 8 | 9 | # Set git user name 10 | git config user.name "" 11 | 12 | # Set git user email 13 | git config user.email "" 14 | 15 | # Get git current tag 16 | g describe --tags --abbrev=0 | tee /dev/tty | pbcopy 17 | 18 | # Get git current branch 19 | g branch --show-current | tee /dev/tty | pbcopy 20 | 21 | # Hard reset the current branch with origin 22 | git reset --hard origin/$(git rev-parse --abbrev-ref HEAD) 23 | 24 | # Change git commit time back to 1 day 25 | git commit --amend --no-edit --date "$(date -v -1d -R)" 26 | 27 | # Rebase interactive 28 | git rebase -i 29 | 30 | # Revert file to match origin branch (master/develop) 31 | git checkout -- 32 | 33 | $ default_user_name: echo 'Huy Duong' 34 | $ default_user_email: echo 'huy.duongdinh@gmail.com' 35 | $ branch: git branch --- --fzf-overrides '--no-select-1' 36 | $ origin_branch: echo -e "origin/master\norigin/main\norigin/develop" | fzf --prompt="Select origin branch: " 37 | $ file: find . -type f -not -path '*/\.git/*' | sed 's|^\./||' | fzf --prompt="Select file to revert: " 38 | -------------------------------------------------------------------------------- /brew/Brewfile: -------------------------------------------------------------------------------- 1 | cask 'google-chrome' 2 | cask 'firefox' 3 | cask 'alacritty' 4 | cask 'karabiner-elements' 5 | cask 'raycast' 6 | cask 'shottr' 7 | cask 'postman' 8 | cask 'slack' 9 | cask 'telegram' 10 | cask 'zalo' 11 | cask 'visual-studio-code' 12 | cask 'homerow' 13 | cask 'winbox' 14 | cask 'nikitabobko/tap/aerospace' 15 | cask 'claude-code' 16 | cask 'rectangle' 17 | tap 'homebrew/cask-fonts' 18 | cask 'font-fira-code-nerd-font' 19 | 20 | brew 'neovim' 21 | brew 'docker' 22 | brew 'docker-credential-helper' 23 | brew 'docker-compose' 24 | brew 'colima' 25 | brew 'tmux' 26 | brew 'fzf' 27 | brew 'ripgrep' 28 | brew 'fd' 29 | brew 'lazygit' 30 | brew 'urlview' 31 | brew 'tldr' 32 | brew 'pass' 33 | brew 'jq' 34 | brew 'lnav' 35 | brew 'navi' 36 | brew 'task' 37 | brew 'derailed/k9s/k9s' 38 | brew 'starship' 39 | brew 'neofetch' 40 | brew 'ncdu' 41 | brew 'iproute2mac' 42 | tap 'FelixKratz/formulae' 43 | brew 'sketchybar' 44 | brew 'borders' 45 | brew 'mise' 46 | brew 'thefuck' 47 | brew 'git-delta' 48 | brew 'calcurse' 49 | brew 'yqrashawn/goku/goku' 50 | brew 'ffmpeg' 51 | brew 'cowsay' 52 | brew 'lolcat' 53 | brew 'pngpaste' 54 | brew 'wireguard-tools' 55 | brew 'gh' 56 | brew 'gemini-cli' 57 | tap 'ayangweb/BongoCat' 58 | brew 'bongo-cat' 59 | tap 'beeftornado/rmtree' 60 | -------------------------------------------------------------------------------- /nvim/lua/plugins/vim-visual-multi.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | vim.g.VM_default_mappings = 0 5 | vim.g.VM_add_cursor_at_pos_no_mappings = 1 6 | 7 | local function visual_cursors_with_delay() 8 | -- Execute the vm-visual-cursors command. 9 | vim.cmd 'silent! execute "normal! \\(VM-Visual-Cursors)"' 10 | -- Introduce delay via VimScript's 'sleep' (set to 500 milliseconds here). 11 | vim.cmd "sleep 200m" 12 | -- Press 'A' in normal mode after the delay. 13 | vim.cmd 'silent! execute "normal! A"' 14 | end 15 | 16 | local wk = require "which-key" 17 | wk.add { 18 | { "m", group = "Visual Multi", mode = "n" }, 19 | { "ma", "(VM-Select-All)", desc = "Select All", mode = "n" }, 20 | { "mo", "(VM-Toggle-Mappings)", desc = "Toggle Mapping", mode = "n" }, 21 | { "mp", "(VM-Add-Cursor-At-Pos)", desc = "Add Cursor At Pos", mode = "n" }, 22 | { "mr", "(VM-Start-Regex-Search)", desc = "Start Regex Search", mode = "n" }, 23 | { 24 | "mv", 25 | function() 26 | visual_cursors_with_delay() 27 | end, 28 | desc = "Visual Cursors", 29 | mode = "v", 30 | }, 31 | } 32 | end 33 | 34 | return M 35 | -------------------------------------------------------------------------------- /docs/karabiner.md: -------------------------------------------------------------------------------- 1 | # Karabinner 2 | 3 | [Karabiner](https://karabiner-elements.pqrs.org/) is a software application that I use to customize my keyboard settings on macOS. It allows me to change the key mappings, and create complex modifications for different scenarios. 4 | 5 | ## Goku 6 | 7 | However, the configuration file for Karabiner is very large and complicated. Some configuration files may have thousands of lines of code, which makes it difficult to edit and maintain them. 8 | 9 | 10 | That's why I use [goku](https://github.com/yqrashawn/GokuRakuJoudo), a tool that simplifies the configuration process for Karabiner. Goku uses a concise and expressive syntax to write the configuration file in [edn format](https://github.com/edn-format/edn). 11 | 12 | The goku configuration file should be placed in the `~/.config/` folder with the name `karabiner.edn`. 13 | 14 | To convert the `karabiner.edn` file to the `karabiner.json` file that Karabiner can read, I need to run the following command in the terminal: 15 | 16 | ```sh 17 | goku 18 | ``` 19 | 20 | **Note:** Make sure to create `Default` profile in Karabiner before using `goku`. 21 | 22 | ## Troubleshooting 23 | 24 | 1. Why isn't Karabiner working with my custom keyboard? 25 | 26 | Please ensure that you have checked the box for `Modify events` under `Devices` -> your device. 27 | -------------------------------------------------------------------------------- /nvim/lua/plugins/conform.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local conform_ok, conform = pcall(require, "conform") 7 | if not conform_ok then 8 | return 9 | end 10 | 11 | conform.setup { 12 | formatters_by_ft = { 13 | javascript = { "prettier" }, 14 | typescript = { "prettier" }, 15 | javascriptreact = { "prettier" }, 16 | typescriptreact = { "prettier" }, 17 | css = { "prettier" }, 18 | html = { "prettier" }, 19 | json = { "prettier" }, 20 | yaml = { "prettier" }, 21 | markdown = { "prettier" }, 22 | graphql = { "prettier" }, 23 | lua = { "stylua" }, 24 | go = { "golines", "gofumpt" }, 25 | python = { "isort", "black" }, 26 | cpp = { "clang_format" }, 27 | php = { "pint" }, 28 | sh = { "shfmt" }, 29 | hcl = { "terragrunt_hclfmt" }, 30 | tf = { "terraform_fmt" }, 31 | }, 32 | } 33 | 34 | conform.formatters.shfmt = { 35 | prepend_args = { "-i", "2" }, 36 | } 37 | 38 | keymaps.set({ "n", "v" }, "cf", function() 39 | conform.format { 40 | lsp_fallback = true, 41 | async = false, 42 | timeout_ms = 5000, 43 | } 44 | vim.notify("✨ Code formatted successfully", vim.log.levels.INFO) 45 | end) 46 | end 47 | 48 | return M 49 | -------------------------------------------------------------------------------- /git/gitconfig: -------------------------------------------------------------------------------- 1 | [user] 2 | email = huy.duongdinh@gmail.com 3 | name = Huy Duong 4 | 5 | [core] 6 | pager = delta 7 | # don't consider trailing space change as a cause for merge conflicts 8 | whitespace = -trailing-space 9 | # global ignore file 10 | excludesFile = ~/.gitignore 11 | 12 | [interactive] 13 | diffFilter = delta --color-only 14 | 15 | [delta] 16 | navigate = true # use n and N to move between diff sections 17 | light = false # set to true if you're in a terminal w/ a light background color (e.g. the default macOS terminal) 18 | 19 | [merge] 20 | conflictstyle = diff3 21 | 22 | [diff] 23 | colorMoved = default 24 | 25 | [push] 26 | # default push should only push the current branch to its push target, regardless of its remote name 27 | default = upstream 28 | # when pushing, also push tags whose commit-ishs are now reachable upstream 29 | followTags = true 30 | 31 | [fetch] 32 | # https://dillionmegida.com/p/delete-outdated-branches/#git-fetch---prune 33 | prune = true 34 | 35 | [status] 36 | short = true 37 | 38 | [alias] 39 | delete-local-merged = "!git fetch && git branch --merged | egrep -v 'master|main|dev|develop' | xargs git branch -d" 40 | empty = "!git commit --allow-empty" 41 | [filter "lfs"] 42 | clean = git-lfs clean -- %f 43 | smudge = git-lfs smudge -- %f 44 | process = git-lfs filter-process 45 | required = true 46 | -------------------------------------------------------------------------------- /nvim/init.lua: -------------------------------------------------------------------------------- 1 | -- Disable builtin vim plugins 2 | local disabled_built_ins = { 3 | "netrw", 4 | "netrwPlugin", 5 | "netrwSettings", 6 | "netrwFileHandlers", 7 | "gzip", 8 | -- "zip", (vintellij) 9 | -- "zipPlugin", (vintellij) 10 | "tar", 11 | "tarPlugin", 12 | "getscript", 13 | "getscriptPlugin", 14 | "vimball", 15 | "vimballPlugin", 16 | "2html_plugin", 17 | "logipat", 18 | "rrhelper", 19 | "spellfile_plugin", 20 | "matchit", 21 | } 22 | 23 | for _, plugin in pairs(disabled_built_ins) do 24 | vim.g["loaded_" .. plugin] = 1 25 | end 26 | 27 | -- config variable for my plugins 28 | vim.g.huy_duong_workspace = 1 29 | 30 | -- change leader key to semicolon 31 | vim.g.mapleader = ";" -- make sure to set `mapleader` before lazy 32 | 33 | -- load plugins 34 | require("plugin_loader").init() 35 | 36 | -- load lsp config 37 | require("lsp").setup() 38 | 39 | -- load config 40 | require("config.autocmds").setup() 41 | require("config.options").setup() 42 | require("config.colorschema").setup() 43 | require("config.keymaps").setup() 44 | require("config.commands").setup() 45 | 46 | -- load core 47 | require("core.tasks").setup() 48 | require("core.open").setup() 49 | require("core.nohlsearch").setup() 50 | require("core.statusline").setup() 51 | require("core.cutlass").setup() 52 | require("core.floaterm").setup() 53 | require("core.picsur").setup() 54 | -------------------------------------------------------------------------------- /nvim/lua/plugins/other.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | function M.setup() 6 | local other_ok, other = pcall(require, "other-nvim") 7 | if not other_ok then 8 | return 9 | end 10 | 11 | keymaps.set("n", "aa", ":Other", { noremap = true, silent = true }) 12 | 13 | other.setup { 14 | mappings = { 15 | "golang", 16 | -- python 17 | { 18 | context = "test", 19 | pattern = "(.*)/src/(.*).py$", 20 | target = "%1/test/test_%2.py", 21 | }, 22 | { 23 | context = "implementation", 24 | pattern = "(.*)/test/test_(.*).py$", 25 | target = "%1/src/%2.py", 26 | }, 27 | -- laravel 28 | { 29 | context = "controller test", 30 | pattern = "/app/Http/Controllers/.*/(.*)Controller.php$", 31 | target = "/tests/Feature/%1ControllerTest.php", 32 | }, 33 | { 34 | context = "controller implementation", 35 | pattern = "/tests/Feature/(.*)ControllerTest.php$", 36 | target = "/app/Http/Controllers/*/%1Controller.php", 37 | }, 38 | { 39 | context = "service/respository interface", 40 | pattern = "(.*).php$", 41 | target = "%1Interface.php", 42 | }, 43 | { 44 | context = "service/respository implementation", 45 | pattern = "(.*)Interface.php$", 46 | target = "%1.php", 47 | }, 48 | }, 49 | } 50 | end 51 | 52 | return M 53 | -------------------------------------------------------------------------------- /nvim/lua/plugins/comment.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local status_ok, comment = pcall(require, "Comment") 7 | if not status_ok then 8 | return 9 | end 10 | 11 | comment.setup { 12 | ---Add a space b/w comment and the line 13 | padding = true, 14 | ---Whether the cursor should stay at its position 15 | sticky = true, 16 | ---Lines to be ignored while (un)comment 17 | ignore = "^$", 18 | ---Enable keybindings 19 | ---NOTE: If given `false` then the plugin won't create any mappings 20 | mappings = { 21 | ---Operator-pending mapping; `gcc` `gbc` `gc[count]{motion}` `gb[count]{motion}` 22 | basic = false, 23 | ---Extra mapping; `gco`, `gcO`, `gcA` 24 | extra = false, 25 | ---Extended mapping; `g>` `g<` `g>[count]{motion}` `g<[count]{motion}` 26 | extended = false, 27 | }, 28 | ---Function to call before (un)comment 29 | pre_hook = require("ts_context_commentstring.integrations.comment_nvim").create_pre_hook(), 30 | ---Function to call after (un)comment 31 | post_hook = nil, 32 | } 33 | 34 | keymaps.set( 35 | "n", 36 | "cl", 37 | "lua require('Comment.api').toggle.linewise.current()", 38 | { noremap = true, silent = true } 39 | ) 40 | keymaps.set( 41 | "x", 42 | "cl", 43 | "lua require('Comment.api').toggle.linewise(vim.fn.visualmode())", 44 | { noremap = true, silent = true } 45 | ) 46 | end 47 | 48 | return M 49 | -------------------------------------------------------------------------------- /nvim/lua/lsp/keymaps.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | function M.setup(bufnr) 6 | local opts = { buffer = bufnr } 7 | 8 | -- Navigation 9 | keymaps.set("n", "gd", "lua require('telescope.builtin').lsp_definitions()", opts) 10 | keymaps.set("n", "gr", "lua require('telescope.builtin').lsp_references()", opts) 11 | keymaps.set("n", "gi", "lua require('telescope.builtin').lsp_implementations()", opts) 12 | keymaps.set("n", "gy", "lua require('telescope.builtin').lsp_type_definitions()", opts) 13 | 14 | -- Code actions 15 | keymaps.set("n", "ca", "lua vim.lsp.buf.code_action()", opts) 16 | keymaps.set("n", "cr", "lua vim.lsp.buf.rename()", opts) 17 | 18 | -- Diagnostics navigation 19 | keymaps.set("n", "gnN", function() 20 | vim.diagnostic.jump { 21 | count = -1, 22 | float = true, 23 | } 24 | end, opts) 25 | 26 | keymaps.set("n", "gnn", function() 27 | vim.diagnostic.jump { 28 | count = 1, 29 | float = true, 30 | } 31 | end, opts) 32 | 33 | keymaps.set("n", "gno", "lua vim.diagnostic.open_float({ border = 'rounded' })", opts) 34 | 35 | -- Hover and signature help with rounded borders 36 | keymaps.set("n", "K", function() 37 | vim.lsp.buf.hover { border = "rounded" } 38 | end, opts) 39 | 40 | -- Inlay hints toggle 41 | keymaps.set("n", "hh", function() 42 | vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled { bufnr = bufnr }, { bufnr = bufnr }) 43 | end, opts) 44 | end 45 | 46 | return M 47 | -------------------------------------------------------------------------------- /alacritty/alacritty-popup.yml: -------------------------------------------------------------------------------- 1 | env: 2 | TERM: xterm-256color 3 | ALACRITTY_POPUP: ALACRITTY_POPUP 4 | 5 | window: 6 | dimensions: 7 | columns: 0 8 | lines: 0 9 | padding: 10 | x: 0 11 | y: 0 12 | dynamic_padding: false 13 | decorations: none 14 | startup_mode: Windowed 15 | 16 | font: 17 | normal: 18 | family: "FiraCode Nerd Font" 19 | style: Retina 20 | bold: 21 | family: 'FiraCode Nerd Font' 22 | style: Bold 23 | italic: 24 | family: 'FiraCode Nerd Font' 25 | style: Italic 26 | bold_italic: 27 | family: 'FiraCode Nerd Font' 28 | style: Bold Italic 29 | size: 14.0 30 | offset: 31 | x: 0 32 | y: 0 33 | glyph_offset: 34 | x: 0 35 | y: 0 36 | 37 | draw_bold_text_with_bright_colors: false 38 | 39 | # Colors (TokyoNight) 40 | colors: 41 | # Default colors 42 | primary: 43 | background: '0x1a1b26' 44 | foreground: '0xc0caf5' 45 | # Normal colors 46 | normal: 47 | black: '0x15161E' 48 | red: '0xf7768e' 49 | green: '0x9ece6a' 50 | yellow: '0xe0af68' 51 | blue: '0x7aa2f7' 52 | magenta: '0xbb9af7' 53 | cyan: '0x7dcfff' 54 | white: '0xa9b1d6' 55 | # Bright colors 56 | bright: 57 | black: '0x414868' 58 | red: '0xf7768e' 59 | green: '0x9ece6a' 60 | yellow: '0xe0af68' 61 | blue: '0x7aa2f7' 62 | magenta: '0xbb9af7' 63 | cyan: '0x7dcfff' 64 | white: '0xc0caf5' 65 | indexed_colors: 66 | - { index: 16, color: '0xff9e64' } 67 | - { index: 17, color: '0xdb4b4b' } 68 | 69 | background_opacity: 1.0 70 | 71 | cursor: 72 | style: Beam 73 | -------------------------------------------------------------------------------- /nvim/lua/plugins/vim-startify.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | vim.g.startify_custom_header = { 5 | " *--------------------------------------------------*", 6 | " | __ __ ___ |", 7 | " | / // /_ ____ __ / _ \\__ _____ ___ ___ _ |", 8 | " | / _ / // / // / / // / // / _ \\/ _ \\/ _ `/ |", 9 | " | /_//_/\\_,_/\\_, / /____/\\_,_/\\___/_//_/\\_, / |", 10 | " | /___/ /___/ |", 11 | " | |", 12 | " *--------------------------------------------------*", 13 | " o", 14 | " o ^__^", 15 | " o (oo)\\_______", 16 | " (__)\\ )\\/\\", 17 | " ||----w |", 18 | " || ||", 19 | } 20 | 21 | vim.g.startify_lists = { 22 | { ["type"] = "dir", ["header"] = { " Current Directory " .. vim.call "getcwd" } }, 23 | { ["type"] = "sessions", ["header"] = { " Sessions" } }, 24 | { ["type"] = "bookmarks", ["header"] = { " Bookmarks" } }, 25 | } 26 | 27 | vim.g.startify_bookmarks = { 28 | { ["z"] = "~/.zshrc" }, 29 | } 30 | 31 | vim.g.startify_session_dir = "~/.config/nvim/session" 32 | vim.g.startify_session_autoload = 1 33 | vim.g.startify_session_delete_buffers = 1 34 | vim.g.startify_change_to_vcs_root = 1 35 | vim.g.startify_fortune_use_unicode = 1 36 | vim.g.startify_session_persistence = 1 37 | vim.g.startify_enable_special = 0 38 | vim.g.webdevicons_enable_startify = 1 39 | end 40 | 41 | return M 42 | -------------------------------------------------------------------------------- /nvim/lua/lsp/settings/lua_ls.lua: -------------------------------------------------------------------------------- 1 | local lspconfig = require "lspconfig" 2 | 3 | local default_workspace = { 4 | library = { 5 | vim.fn.expand "$VIMRUNTIME", 6 | require("neodev.config").types(), 7 | "${3rd}/busted/library", 8 | "${3rd}/luassert/library", 9 | "${3rd}/luv/library", 10 | }, 11 | 12 | maxPreload = 5000, 13 | preloadFileSize = 10000, 14 | } 15 | 16 | local add_packages_to_workspace = function(packages, config) 17 | local runtime_dirs = vim.api.nvim__get_runtime({ "lua" }, true, { is_lua = true }) 18 | local workspace = config.settings.Lua.workspace 19 | for _, v in pairs(runtime_dirs) do 20 | for _, pack in ipairs(packages) do 21 | if v:match(pack) and not vim.tbl_contains(workspace.library, v) then 22 | table.insert(workspace.library, v) 23 | end 24 | end 25 | end 26 | end 27 | 28 | local make_on_new_config = function(on_new_config, _) 29 | return lspconfig.util.add_hook_before(on_new_config, function(new_config, _) 30 | local server_name = new_config.name 31 | 32 | if server_name ~= "lua_ls" then 33 | return 34 | end 35 | local plugins = { "plenary.nvim", "telescope.nvim", "nvim-treesitter" } 36 | add_packages_to_workspace(plugins, new_config) 37 | end) 38 | end 39 | 40 | lspconfig.util.default_config = vim.tbl_extend("force", lspconfig.util.default_config, { 41 | on_new_config = make_on_new_config(lspconfig.util.default_config.on_new_config), 42 | }) 43 | 44 | return { 45 | settings = { 46 | Lua = { 47 | telemetry = { enable = false }, 48 | runtime = { 49 | version = "LuaJIT", 50 | special = { 51 | reload = "require", 52 | }, 53 | }, 54 | diagnostics = { 55 | globals = { "vim", "reload" }, 56 | }, 57 | workspace = default_workspace, 58 | hint = { enable = true } 59 | }, 60 | }, 61 | } 62 | -------------------------------------------------------------------------------- /nvim/lua/plugins/nvim-autopairs.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | local autopairs = require "nvim-autopairs" 5 | local Rule = require "nvim-autopairs.rule" 6 | local cond = require "nvim-autopairs.conds" 7 | 8 | autopairs.setup { 9 | check_ts = true, 10 | ts_config = { 11 | lua = { "string" }, -- it will not add a pair on that treesitter node 12 | javascript = { "template_string" }, 13 | java = false, -- don't check treesitter on java 14 | }, 15 | } 16 | 17 | autopairs.add_rule(Rule("$$", "$$", "tex")) 18 | autopairs.add_rules { 19 | Rule("$", "$", { "tex", "latex" }) -- don't add a pair if the next character is % 20 | :with_pair(cond.not_after_regex_check "%%") -- don't add a pair if the previous character is xxx 21 | :with_pair(cond.not_before_regex_check("xxx", 3)) -- don't move right when repeat character 22 | :with_move(cond.none()) -- don't delete if the next character is xx 23 | :with_del(cond.not_after_regex_check "xx") -- disable add newline when press 24 | :with_cr(cond.none()), 25 | } 26 | autopairs.add_rules { 27 | Rule("$$", "$$", "tex"):with_pair(function(opts) 28 | print(vim.inspect(opts)) 29 | if opts.line == "aa $$" then 30 | -- don't add pair on that line 31 | return false 32 | end 33 | end), 34 | } 35 | 36 | require("nvim-treesitter.configs").setup { autopairs = { enable = true } } 37 | local ts_conds = require "nvim-autopairs.ts-conds" 38 | 39 | -- TODO: can these rules be safely added from "config.lua" ? 40 | -- press % => %% is only inside comment or string 41 | autopairs.add_rules { 42 | Rule("%", "%", "lua"):with_pair(ts_conds.is_ts_node { "string", "comment" }), 43 | Rule("$", "$", "lua"):with_pair(ts_conds.is_not_ts_node { "function" }), 44 | } 45 | end 46 | 47 | return M 48 | -------------------------------------------------------------------------------- /ai/commands/gemini/commit.toml: -------------------------------------------------------------------------------- 1 | description="Create commit message" 2 | prompt = """ 3 | You are an expert software engineer specializing in writing concise, meaningful git commit messages that strictly follow the Conventional Commits format. 4 | 5 | Workflow: 6 | 7 | 1. First, examine the current git status of my repository and the changes I've made. Utilize commands like "git status" and "git diff --staged" to check staged changes. If no files are staged, use "git diff" and "git status -s" to show my unstaged changes. Guide me in determining which files to stage, but do ask for my explicit consent before proposing to stage any files with "git add". 8 | 2. Help me classify the types of changes I have made. For instance, have I added a feature (feat), fixed a bug (fix), created documentation (docs), or refactored the code (refactor)? 9 | 3. Gauge how these modifications will impact the overall project. 10 | 4. If any sensitive information is present in the project, identify it and warn me about it. 11 | 5. Now let's draft a suitable Conventional Commit message. Concentrate on the "why" of the changes. 12 | - Header: type(scope): subject. Remember, it should be concise, in lowercase letters and in an imperative mood. Never use shell command or code injection syntax (e.g., $(), <(), >, backticks, etc.) in the header. 13 | - (Optional) Body: Explain what was done and why it was necessary, providing as much context as possible. Never use shell command or code injection syntax (e.g., $(), <(), >, backticks, etc.) in the body. 14 | - (Optional) Footer: Take note of any BREAKING CHANGES or link any related issues. Never use shell command or code injection syntax (e.g., $(), <(), >, backticks, etc.) in the footer. 15 | 6. Present the commit message and offer these options: 16 | - Use as-is 17 | - Modify 18 | - Add more details to the body 19 | - Stage different files 20 | 7. Upon approval, perform the commit and display the result. 21 | """ 22 | -------------------------------------------------------------------------------- /nvim/lua/plugins/nvim-treesitter.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | local status_ok, treesitter_configs = pcall(require, "nvim-treesitter.configs") 5 | if not status_ok then 6 | return 7 | end 8 | 9 | treesitter_configs.setup { 10 | ensure_installed = "all", 11 | highlight = { 12 | enable = true, 13 | }, 14 | indent = { 15 | enable = true, 16 | }, 17 | -- windwp/nvim-ts-autotag 18 | autotag = { 19 | enable = true, 20 | }, 21 | -- nvim-treesitter-endwise 22 | endwise = { 23 | enable = true, 24 | }, 25 | -- nvim-treesitter-textobjects 26 | textobjects = { 27 | move = { 28 | enable = true, 29 | set_jumps = true, 30 | goto_next_start = { 31 | ["gcf"] = "@function.outer", 32 | ["gcc"] = "@class.outer", 33 | ["gca"] = "@parameter.inner", 34 | }, 35 | goto_previous_start = { 36 | ["gcF"] = "@function.outer", 37 | ["gcC"] = "@class.outer", 38 | ["gcA"] = "@parameter.inner", 39 | }, 40 | }, 41 | swap = { 42 | enable = true, 43 | swap_next = { 44 | ["a"] = "@parameter.inner", 45 | }, 46 | swap_previous = { 47 | ["A"] = "@parameter.inner", 48 | }, 49 | }, 50 | select = { 51 | enable = true, 52 | lookahead = true, 53 | keymaps = { 54 | ["af"] = "@function.outer", 55 | ["if"] = "@function.inner", 56 | ["ac"] = "@class.outer", 57 | ["ic"] = "@class.inner", 58 | ["ia"] = "@parameter.inner", 59 | ["aa"] = "@parameter.outer", 60 | }, 61 | }, 62 | }, 63 | } 64 | 65 | local ts_context_commentstring_ok, ts_context_commentstring = pcall(require, "ts_context_commentstring") 66 | if not ts_context_commentstring_ok then 67 | return 68 | end 69 | 70 | ts_context_commentstring.setup {} 71 | vim.g.skip_ts_context_commentstring_module = true 72 | end 73 | 74 | return M 75 | -------------------------------------------------------------------------------- /surfingkeys/surfingkeys.js: -------------------------------------------------------------------------------- 1 | // Unmap close tab and re-open tab 2 | api.unmap('x'); 3 | api.unmap('X'); 4 | 5 | // Remap open link 6 | api.map('F', 'C'); 7 | api.unmap('C'); 8 | 9 | // History Back/Forward 10 | api.map('H', 'S'); 11 | api.map('L', 'D'); 12 | 13 | // Move Tab Left/Right w/ one press 14 | api.map('>', '>>'); 15 | api.map('<', '<<'); 16 | 17 | // Unmap all searches 18 | api.unmap('sg'); 19 | api.unmap('sb'); 20 | api.unmap('sd'); 21 | api.unmap('sh'); 22 | api.unmap('ss'); 23 | api.unmap('sw'); 24 | api.unmap('se'); 25 | api.unmap('sy'); 26 | 27 | function goto(site) { 28 | return () => window.open(site); 29 | } 30 | 31 | api.mapkey('ogh', 'open github', goto('https://github.com')); 32 | api.mapkey('ofb', 'open facebook', goto('https://facebook.com')); 33 | api.unmap('oy'); 34 | api.mapkey('oyt', 'open youtube', goto('https://youtube.com')); 35 | api.mapkey('otl', 'open youtube', goto('https://translate.google.com')); 36 | api.mapkey('olc', 'open leetcode', goto('https://leetcode.com/problemset/all/')); 37 | 38 | // Remap open bookmark 39 | api.unmap('ob') 40 | api.map('ob', 'b'); 41 | api.unmap('b') 42 | 43 | // Remap search google 44 | api.map('o/', 'og'); 45 | api.unmap('og'); 46 | 47 | // set theme 48 | settings.theme = ` 49 | .sk_theme { 50 | font-family: Input Sans Condensed, Charcoal, sans-serif; 51 | font-size: 10pt; 52 | background: #24272e; 53 | color: #abb2bf; 54 | } 55 | .sk_theme tbody {w 56 | color: #fff; 57 | } 58 | .sk_theme input { 59 | color: #d0d0d0; 60 | } 61 | .sk_theme .url { 62 | color: #61afef; 63 | } 64 | .sk_theme .annotation { 65 | color: #56b6c2; 66 | } 67 | .sk_theme .omnibar_highlight { 68 | color: #528bff; 69 | } 70 | .sk_theme .omnibar_timestamp { 71 | color: #e5c07b; 72 | } 73 | .sk_theme .omnibar_visitcount { 74 | color: #98c379; 75 | } 76 | .sk_theme #sk_omnibarSearchResult ul li:nth-child(odd) { 77 | background: #303030; 78 | } 79 | .sk_theme #sk_omnibarSearchResult ul li.focused { 80 | background: #3e4452; 81 | } 82 | #sk_status, #sk_find { 83 | font-size: 20pt; 84 | }`; 85 | -------------------------------------------------------------------------------- /nvim/lua/plugins/blink-cmp.lua: -------------------------------------------------------------------------------- 1 | local icons = require "icons" 2 | 3 | local M = {} 4 | 5 | M.setup = function() 6 | local blink_cmp_ok, blink_cmp = pcall(require, "blink.cmp") 7 | if not blink_cmp_ok then 8 | return 9 | end 10 | 11 | -- load VS Code style snippets from a plugin rafamadriz/friendly-snippets 12 | require("luasnip.loaders.from_vscode").lazy_load() 13 | 14 | blink_cmp.setup { 15 | keymap = { 16 | preset = "super-tab", 17 | [""] = { "accept", "fallback" }, 18 | [""] = { "snippet_forward", "select_next", "fallback" }, 19 | [""] = { "snippet_backward", "select_prev", "fallback" }, 20 | }, 21 | 22 | appearance = { 23 | nerd_font_variant = "normal", 24 | kind_icons = icons.lsp, 25 | }, 26 | 27 | completion = { 28 | keyword = { 29 | range = "prefix", 30 | }, 31 | 32 | list = { 33 | selection = { 34 | preselect = true, 35 | auto_insert = true, 36 | }, 37 | }, 38 | 39 | accept = { 40 | auto_brackets = { enabled = true }, 41 | }, 42 | 43 | menu = { 44 | auto_show = true, 45 | draw = { 46 | columns = { 47 | { "label", "label_description", gap = 1 }, 48 | { "kind_icon", "kind" }, 49 | }, 50 | }, 51 | }, 52 | 53 | documentation = { 54 | auto_show = true, 55 | auto_show_delay_ms = 500, 56 | }, 57 | }, 58 | 59 | cmdline = { 60 | enabled = true, 61 | keymap = { preset = "cmdline" }, 62 | sources = { "buffer", "cmdline" }, 63 | completion = { 64 | list = { 65 | selection = { 66 | preselect = true, 67 | auto_insert = true, 68 | }, 69 | }, 70 | menu = { auto_show = false }, 71 | ghost_text = { enabled = true }, 72 | }, 73 | }, 74 | 75 | snippets = { preset = "luasnip" }, 76 | 77 | sources = { 78 | default = { "lsp", "path", "snippets", "buffer" }, 79 | }, 80 | } 81 | end 82 | 83 | return M 84 | -------------------------------------------------------------------------------- /nvim/lua/core/float_input.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | function M.input(on_confirm, opts) 6 | opts = opts or {} 7 | local prompt = opts.prompt or "Input: " 8 | local default = opts.default or "" 9 | local input_width = opts.width or math.floor(vim.o.columns / 5) 10 | local input_height = opts.height or 1 11 | local winhl = opts.winhl or "Normal:Normal,FloatBorder:Normal,FloatTitle:Normal" 12 | local win_config = opts.win_config or {} 13 | 14 | win_config = vim.tbl_deep_extend("force", { 15 | focusable = true, 16 | style = "minimal", 17 | border = "rounded", 18 | width = input_width, 19 | height = input_height, 20 | title = prompt, 21 | relative = "win", 22 | row = vim.api.nvim_win_get_height(0) / 2 - 1, 23 | col = vim.api.nvim_win_get_width(0) / 2 - input_width / 2, 24 | }, win_config) 25 | 26 | -- create floating window. 27 | local buffer = vim.api.nvim_create_buf(false, true) 28 | local window = vim.api.nvim_open_win(buffer, true, win_config) 29 | vim.api.nvim_buf_set_text(buffer, 0, 0, 0, 0, { default }) 30 | 31 | -- window option settings 32 | vim.api.nvim_win_set_option(window, "winhl", winhl) 33 | 34 | -- put cursor at the end of the default value 35 | vim.cmd "startinsert" 36 | vim.api.nvim_win_set_cursor(window, { 1, vim.str_utfindex(default) + 1 }) 37 | 38 | -- enter to confirm 39 | keymaps.set({ "n", "i", "v" }, "", function() 40 | local lines = vim.api.nvim_buf_get_lines(buffer, 0, 1, false) 41 | if lines[1] ~= default and on_confirm then 42 | on_confirm(lines[1]) 43 | end 44 | 45 | vim.api.nvim_win_close(window, true) 46 | vim.cmd "stopinsert" 47 | end, { buffer = buffer }) 48 | 49 | -- ctr-c, esc or q to close 50 | keymaps.set("n", "", function() 51 | vim.api.nvim_win_close(window, true) 52 | end, { buffer = buffer }) 53 | keymaps.set("n", "q", function() 54 | vim.api.nvim_win_close(window, true) 55 | end, { buffer = buffer }) 56 | keymaps.set({ "n", "i" }, "", function() 57 | vim.cmd "stopinsert" 58 | vim.api.nvim_win_close(window, true) 59 | end, { buffer = buffer }) 60 | end 61 | 62 | return M 63 | -------------------------------------------------------------------------------- /ai/CLAUDE.md: -------------------------------------------------------------------------------- 1 | # Available MCPs for Development 2 | 3 | **Sequential Thinking** 4 | 5 | - Analyze feature requests and break them into clear, executable steps. 6 | - Plan code improvements, refactoring, and architectural decisions systematically. 7 | - Debug issues using structured, step-by-step strategies. 8 | - Plan test coverage and test improvements thoroughly. 9 | - Evaluate task completion and identify next steps effectively. 10 | 11 | **Context7** 12 | 13 | Use context7 to access always up-to-date, version-specific documentation and code examples directly from the source — ensuring accurate, reliable answers without hallucinated or outdated APIs. 14 | 15 | - `context7:resolve-library-id` - Find Context7-compatible library IDs for documentation lookup 16 | - `context7:get-library_docs` - Fetch up-to-date documentation for libraries and frameworks 17 | 18 | # 🤖 AI Assistant Guidelines 19 | 20 | ## Context Awareness 21 | 22 | - When implementing features, always check existing patterns first 23 | - Prefer composition over inheritance in all designs 24 | - Use existing utilities before creating new ones 25 | - Check for similar functionality in other domains/features 26 | 27 | ## Workflow Patterns 28 | 29 | - Use "think hard" for architecture decisions 30 | - Break complex tasks into smaller, testable units 31 | - Validate understanding before implementation 32 | 33 | ## Search Command Requirements 34 | 35 | **CRITICAL**: Always use `rg` (ripgrep) instead of traditional `grep` and `find` commands: 36 | 37 | ```bash 38 | # ❌ Don't use grep 39 | grep -r "pattern" . 40 | 41 | # ✅ Use rg instead 42 | rg "pattern" 43 | 44 | # ❌ Don't use find with name 45 | find . -name "*.tsx" 46 | 47 | # ✅ Use rg with file filtering 48 | rg --files | rg "\.tsx$" 49 | # or 50 | rg --files -g "*.tsx" 51 | ``` 52 | 53 | **Enforcement Rules:** 54 | 55 | ``` 56 | ( 57 | r"^grep\b(?!.*\|)", 58 | "Use 'rg' (ripgrep) instead of 'grep' for better performance and features", 59 | ), 60 | ( 61 | r"^find\s+\S+\s+-name\b", 62 | "Use 'rg --files | rg pattern' or 'rg --files -g pattern' instead of 'find -name' for better performance", 63 | ), 64 | ``` 65 | 66 | # ⚠️ Important Notes 67 | 68 | - **NEVER ASSUME OR GUESS** - When in doubt, ask for clarification 69 | - **Always verify file paths and module names** before use 70 | -------------------------------------------------------------------------------- /nvim/lua/config/autocmds.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local function augroup(name) 4 | return vim.api.nvim_create_augroup("dotfiles_" .. name, { clear = true }) 5 | end 6 | 7 | function M.setup() 8 | -- Check if we need to reload the file when it changed 9 | vim.api.nvim_create_autocmd({ "FocusGained", "TermClose", "TermLeave" }, { 10 | group = augroup "checktime", 11 | command = "checktime", 12 | }) 13 | 14 | -- Highlight on yank 15 | vim.api.nvim_create_autocmd("TextYankPost", { 16 | group = augroup "highlight_yank", 17 | callback = function() 18 | vim.highlight.on_yank { higroup = "Search", timeout = 200 } 19 | end, 20 | }) 21 | 22 | -- Go to last loc when opening a buffer 23 | vim.api.nvim_create_autocmd("BufReadPost", { 24 | group = augroup "last_loc", 25 | callback = function() 26 | local exclude = { "gitcommit" } 27 | local buf = vim.api.nvim_get_current_buf() 28 | if vim.tbl_contains(exclude, vim.bo[buf].filetype) then 29 | return 30 | end 31 | local mark = vim.api.nvim_buf_get_mark(buf, '"') 32 | local lcount = vim.api.nvim_buf_line_count(buf) 33 | if mark[1] > 0 and mark[1] <= lcount then 34 | pcall(vim.api.nvim_win_set_cursor, 0, mark) 35 | end 36 | end, 37 | }) 38 | 39 | -- Close some filetypes with 40 | vim.api.nvim_create_autocmd("FileType", { 41 | group = augroup "close_with_q", 42 | pattern = { 43 | "help", 44 | "lspinfo", 45 | "qf", 46 | "checkhealth", 47 | }, 48 | callback = function(event) 49 | vim.bo[event.buf].buflisted = false 50 | vim.keymap.set("n", "q", "close", { buffer = event.buf, silent = true }) 51 | end, 52 | }) 53 | 54 | -- Wrap and check for spell in text filetypes 55 | vim.api.nvim_create_autocmd("FileType", { 56 | group = augroup "wrap_spell", 57 | pattern = { "gitcommit", "markdown" }, 58 | callback = function() 59 | vim.opt_local.wrap = true 60 | vim.opt_local.spell = true 61 | end, 62 | }) 63 | 64 | -- Set nobuflisted for some filetypes 65 | vim.api.nvim_create_autocmd("FileType", { 66 | group = augroup "_filetype_nobuflisted", 67 | pattern = { 68 | "qf", 69 | "dap-repl", -- nvim-dap 70 | }, 71 | callback = function() 72 | vim.bo.buflisted = false 73 | end, 74 | }) 75 | end 76 | 77 | return M 78 | -------------------------------------------------------------------------------- /nvim/lua/plugins/nvim-ufo.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | local icons = require "icons" 3 | 4 | local M = {} 5 | 6 | local function handler(virtText, lnum, endLnum, width, truncate) 7 | local newVirtText = {} 8 | local suffix = (" %s %d "):format(icons.nvim_ufo.fold_suffix, endLnum - lnum) 9 | local sufWidth = vim.fn.strdisplaywidth(suffix) 10 | local targetWidth = width - sufWidth 11 | local curWidth = 0 12 | 13 | for _, chunk in ipairs(virtText) do 14 | local chunkText = chunk[1] 15 | local chunkWidth = vim.fn.strdisplaywidth(chunkText) 16 | 17 | if targetWidth > curWidth + chunkWidth then 18 | table.insert(newVirtText, chunk) 19 | else 20 | chunkText = truncate(chunkText, targetWidth - curWidth) 21 | local hlGroup = chunk[2] 22 | table.insert(newVirtText, { chunkText, hlGroup }) 23 | chunkWidth = vim.fn.strdisplaywidth(chunkText) 24 | -- str width returned from truncate() may less than 2nd argument, need padding 25 | if curWidth + chunkWidth < targetWidth then 26 | suffix = suffix .. (" "):rep(targetWidth - curWidth - chunkWidth) 27 | end 28 | break 29 | end 30 | 31 | curWidth = curWidth + chunkWidth 32 | end 33 | 34 | table.insert(newVirtText, { suffix, "MoreMsg" }) 35 | 36 | return newVirtText 37 | end 38 | 39 | M.setup = function() 40 | local ufo_status_ok, ufo = pcall(require, "ufo") 41 | if not ufo_status_ok then 42 | return 43 | end 44 | 45 | local statuscol_status_ok, statuscol = pcall(require, "statuscol") 46 | if not statuscol_status_ok then 47 | return 48 | end 49 | 50 | local statuscol_builtin_status_ok, statuscol_builtin = pcall(require, "statuscol.builtin") 51 | if not statuscol_builtin_status_ok then 52 | return 53 | end 54 | 55 | statuscol.setup { 56 | relculright = true, 57 | segments = { 58 | { text = { statuscol_builtin.foldfunc }, click = "v:lua.ScFa" }, 59 | { text = { "%s" }, click = "v:lua.ScSa" }, 60 | { text = { statuscol_builtin.lnumfunc, " " }, click = "v:lua.ScLa" }, 61 | }, 62 | } 63 | 64 | keymaps.set("n", "zR", ufo.openAllFolds) 65 | keymaps.set("n", "zM", ufo.closeAllFolds) 66 | 67 | ufo.setup { 68 | provider_selector = function() 69 | return { "treesitter", "indent" } 70 | end, 71 | fold_virt_text_handler = handler, 72 | } 73 | end 74 | 75 | return M 76 | -------------------------------------------------------------------------------- /zsh/zshrc.d/aws.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | # Get the current aws profile 4 | function agp() { 5 | echo $AWS_PROFILE 6 | } 7 | 8 | # Get the current aws region 9 | function agr() { 10 | echo $AWS_REGION 11 | } 12 | 13 | # AWS profile selection 14 | function asp() { 15 | _aws_profiles | __fzfp | { 16 | read aws_profile; 17 | if [ ! -z "$aws_profile" ]; then 18 | export AWS_PROFILE=$aws_profile 19 | fi 20 | } 21 | } 22 | 23 | # AWS region selection 24 | function asr() { 25 | local -a available_regions 26 | available_regions=($(_aws_regions)) 27 | 28 | if [ -z "${available_regions[@]}" ]; then 29 | e_error "You must specify a AWS profile." 30 | 31 | return 32 | fi 33 | 34 | printf "%s\n" "${available_regions[@]}" | __fzfp | { 35 | read aws_region; 36 | if [ ! -z "$aws_region" ]; then 37 | export AWS_REGION=$aws_region 38 | fi 39 | } 40 | } 41 | 42 | # Open AWS Console in Firefox browser 43 | function aow() { 44 | prev_profile=$AWS_PROFILE 45 | 46 | unset AWS_PROFILE 47 | 48 | # Select AWS profile 49 | asp 50 | 51 | if [[ -z $AWS_PROFILE ]];then 52 | export AWS_PROFILE=$prev_profile 53 | 54 | return 55 | fi 56 | 57 | e_arrow "Generating aws login url..." 58 | login_url=`aws-console --url` 59 | encoded_url="${login_url//&/%26}" 60 | if [ -z "${encoded_url}" ]; then 61 | e_error "AWS token is expired." 62 | 63 | return 64 | fi 65 | container_name=$AWS_PROFILE 66 | firefox "ext+container:name=${container_name}&url=${encoded_url}" 67 | 68 | export AWS_PROFILE=$prev_profile 69 | } 70 | 71 | function _aws_regions() { 72 | local region 73 | if [[ $AWS_DEFAULT_REGION ]];then 74 | region="$AWS_DEFAULT_REGION" 75 | elif [[ $AWS_REGION ]];then 76 | region="$AWS_REGION" 77 | else 78 | region="us-west-1" 79 | fi 80 | 81 | if [[ $AWS_DEFAULT_PROFILE || $AWS_PROFILE ]];then 82 | aws ec2 describe-regions --region $region |grep RegionName | awk -F ':' '{gsub(/"/, "", $2);gsub(/,/, "", $2);gsub(/ /, "", $2); print $2}' 83 | fi 84 | } 85 | 86 | function _aws_profiles() { 87 | aws --no-cli-pager configure list-profiles 2> /dev/null && return 88 | [[ -r "${AWS_CONFIG_FILE:-$HOME/.aws/config}" ]] || return 1 89 | grep --color=never -Eo '\[.*\]' "${AWS_CONFIG_FILE:-$HOME/.aws/config}" | sed -E 's/^[[:space:]]*\[(profile)?[[:space:]]*([^[:space:]]+)\][[:space:]]*$/\2/g' 90 | } 91 | -------------------------------------------------------------------------------- /karabiner/karabiner.edn: -------------------------------------------------------------------------------- 1 | { 2 | ;; to obtain the app id: `osascript -e 'id of app "application_name"'` 3 | :applications { 4 | :chrome ["^com\\.google\\.Chrome$"] 5 | :firefox ["^org\\.mozilla\\.firefox$"] 6 | :alacritty ["^org\\.alacritty$"] 7 | :cursor ["^com\\.todesktop\\.230313mzl4w4u92$"] 8 | :postman ["^com\\.postmanlabs\\.mac$"] 9 | } 10 | 11 | :templates { 12 | :launch "open -a \"%s\"" 13 | } 14 | 15 | :simlayer-threshold 500 16 | 17 | :main 18 | [ 19 | {:des "Key mappings" :rules [ 20 | [:caps_lock :left_control] ;; map caps_lock to left_control 21 | ]} 22 | 23 | {:des "Navigation" :rules [ 24 | ;; Move tabs to left/right 25 | [:f21 :!TSpage_up :chrome] 26 | [:f22 :!TSpage_down :chrome] 27 | 28 | [:f21 :!TSpage_up :firefox] 29 | [:f22 :!TSpage_down :firefox] 30 | 31 | [:f21 [:!Tf :z] :alacritty] 32 | [:f22 [:!Tf :b] :alacritty] 33 | 34 | ;; Switch tabs to left/right 35 | [:f23 :!CSopen_bracket :chrome] 36 | [:f24 :!CSclose_bracket :chrome] 37 | 38 | [:f23 :!Tpage_up :firefox] 39 | [:f24 :!Tpage_down :firefox] 40 | 41 | [:f23 [:!Tf :!Sh] :alacritty] 42 | [:f24 [:!Tf :!Sl] :alacritty] 43 | 44 | [:f23 :!CSopen_bracket :postman] 45 | [:f24 :!CSclose_bracket :postman] 46 | 47 | [:f23 :!COleft_arrow :cursor] 48 | [:f24 :!COright_arrow :cursor] 49 | ]} 50 | 51 | {:des "Launch applications" :rules [ 52 | [:!!r [:launch "Cursor"]] 53 | [:!!e [:launch "Firefox"]] 54 | [:!!w [:launch "Zalo"]] 55 | [:!!q [:launch "Postman"]] 56 | 57 | [:!!f [:launch "Alacritty"]] 58 | [:!!d [:launch "Google Chrome"]] 59 | [:!!s [:launch "Slack"]] 60 | [:!!a [:launch "Finder"]] 61 | 62 | [:!!z [:launch "Notes"]] 63 | ]} 64 | ] 65 | 66 | ;; code won't read cheatsheet section 67 | ;; ! stand for mandatory 68 | ;; # stand for optional 69 | ;; C T O S for left command control optional shift 70 | ;; F for fn 71 | ;; need to prefix C T O S F with ! or # 72 | :cheatsheet { 73 | :!Ca "command a" ;; mandatory left_command 74 | :!Ta "control a" ;; mandatory left_control 75 | :!Oa "option a" 76 | :!Sa "shift a" 77 | :#Sa "shift a" ;; keycode a, optional left_shift 78 | :!CTOa "command control option a" 79 | :!Cspacebar "command space" 80 | :!Fa "fn a" 81 | :##a "keycode a optional any" 82 | :!!a "mandatory hyper(control command option shift) a " 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /starship/starship.toml: -------------------------------------------------------------------------------- 1 | # Get editor completions based on the config schema 2 | "$schema" = 'https://starship.rs/config-schema.json' 3 | 4 | # Inserts a blank line between shell prompts 5 | add_newline = true 6 | # Timeout for commands executed by starship (in milliseconds). 7 | command_timeout = 1000 8 | 9 | [aws] 10 | symbol = " " 11 | 12 | [buf] 13 | symbol = " " 14 | 15 | [c] 16 | symbol = " " 17 | 18 | [conda] 19 | symbol = " " 20 | 21 | [dart] 22 | symbol = " " 23 | 24 | [directory] 25 | read_only = " 󰌾" 26 | 27 | [docker_context] 28 | disabled = true 29 | 30 | [php] 31 | symbol = " " 32 | 33 | [elixir] 34 | symbol = " " 35 | 36 | [elm] 37 | symbol = " " 38 | 39 | [fossil_branch] 40 | symbol = " " 41 | 42 | [git_branch] 43 | symbol = " " 44 | 45 | [golang] 46 | symbol = " " 47 | 48 | [guix_shell] 49 | symbol = " " 50 | 51 | [haskell] 52 | symbol = " " 53 | 54 | [haxe] 55 | symbol = " " 56 | 57 | [hg_branch] 58 | symbol = " " 59 | 60 | [hostname] 61 | ssh_symbol = " " 62 | 63 | [java] 64 | symbol = " " 65 | 66 | [julia] 67 | symbol = " " 68 | 69 | [lua] 70 | symbol = " " 71 | 72 | [memory_usage] 73 | symbol = "󰍛 " 74 | 75 | [meson] 76 | symbol = "󰔷 " 77 | 78 | [nim] 79 | symbol = "󰆥 " 80 | 81 | [nix_shell] 82 | symbol = " " 83 | 84 | [nodejs] 85 | symbol = " " 86 | 87 | [os.symbols] 88 | Alpaquita = " " 89 | Alpine = " " 90 | Amazon = " " 91 | Android = " " 92 | Arch = " " 93 | Artix = " " 94 | CentOS = " " 95 | Debian = " " 96 | DragonFly = " " 97 | Emscripten = " " 98 | EndeavourOS = " " 99 | Fedora = " " 100 | FreeBSD = " " 101 | Garuda = "󰛓 " 102 | Gentoo = " " 103 | HardenedBSD = "󰞌 " 104 | Illumos = "󰈸 " 105 | Linux = " " 106 | Mabox = " " 107 | Macos = " " 108 | Manjaro = " " 109 | Mariner = " " 110 | MidnightBSD = " " 111 | Mint = " " 112 | NetBSD = " " 113 | NixOS = " " 114 | OpenBSD = "󰈺 " 115 | openSUSE = " " 116 | OracleLinux = "󰌷 " 117 | Pop = " " 118 | Raspbian = " " 119 | Redhat = " " 120 | RedHatEnterprise = " " 121 | Redox = "󰀘 " 122 | Solus = "󰠳 " 123 | SUSE = " " 124 | Ubuntu = " " 125 | Unknown = " " 126 | Windows = "󰍲 " 127 | 128 | [package] 129 | symbol = "󰏗 " 130 | 131 | [pijul_channel] 132 | symbol = " " 133 | 134 | [python] 135 | symbol = " " 136 | 137 | [rlang] 138 | symbol = "󰟔 " 139 | 140 | [ruby] 141 | symbol = " " 142 | 143 | [rust] 144 | symbol = " " 145 | 146 | [scala] 147 | symbol = " " 148 | -------------------------------------------------------------------------------- /zsh/zshrc: -------------------------------------------------------------------------------- 1 | # If you come from bash you might have to change your $PATH. 2 | export PATH="/opt/homebrew/bin:$PATH" 3 | if [ -d "/usr/local/opt/llvm/bin/" ]; then 4 | export PATH=/usr/local/opt/llvm/bin/:$PATH 5 | fi 6 | 7 | # Path to your oh-my-zsh installation. 8 | export ZSH=$HOME/.oh-my-zsh 9 | 10 | # Set name of the theme to load --- if set to "random", it will 11 | # load a random theme each time oh-my-zsh is loaded, in which case, 12 | # to know which specific one was loaded, run: echo $RANDOM_THEME 13 | # See https://github.com/ohmyzsh/ohmyzsh/wiki/Themes 14 | ZSH_THEME="flazz" 15 | 16 | # Would you like to use another custom folder than $ZSH/custom? 17 | # ZSH_CUSTOM=/path/to/new-custom-folder 18 | 19 | # Which plugins would you like to load? 20 | # Standard plugins can be found in $ZSH/plugins/ 21 | # Custom plugins may be added to $ZSH_CUSTOM/plugins/ 22 | # Example format: plugins=(rails git textmate ruby lighthouse) 23 | # Add wisely, as too many plugins slow down shell startup. 24 | source $ZSH/antigen.zsh 25 | antigen bundle zsh-users/zsh-autosuggestions 26 | antigen bundle zsh-users/zsh-syntax-highlighting 27 | antigen bundle MichaelAquilina/zsh-you-should-use 28 | antigen bundle Aloxaf/fzf-tab 29 | antigen apply 30 | 31 | plugins=( 32 | brew 33 | git 34 | vi-mode 35 | z 36 | fzf 37 | mise 38 | thefuck 39 | tmux 40 | ) 41 | 42 | # tmux 43 | if [ -z "$ALACRITTY_POPUP" ] 44 | then 45 | export ZSH_TMUX_AUTOSTART=true 46 | fi 47 | 48 | source $ZSH/oh-my-zsh.sh 49 | 50 | # Path to workspace folder 51 | export WORKSPACE=$HOME/Workspace 52 | # Path to dotfiles 53 | export DOTFILES="$WORKSPACE/dotfiles" 54 | 55 | export LANG=en_US.UTF-8 56 | export LC_CTYPE=en_US.UTF-8 57 | export LC_ALL=en_US.UTF-8 58 | 59 | export EDITOR=nvim 60 | export VISUAL="$EDITOR" 61 | 62 | if [ -z "$ALACRITTY_POPUP" ] 63 | then 64 | neofetch --ascii "$(echo "Hello Huy Duong.\n\nHave a good day" | cowsay)" | lolcat 65 | fi 66 | 67 | # fzf-tab 68 | zstyle ':fzf-tab:*' fzf-command ftb-tmux-popup 69 | enable-fzf-tab 70 | 71 | # starship 72 | eval "$(starship init zsh)" 73 | 74 | # navi 75 | eval "$(navi widget zsh)" 76 | 77 | # prevent exit shell when pressing ctrl+d 78 | set -o ignoreeof 79 | 80 | # Automatically source all .zshrc* files 81 | for zshrc_file in "${DOTFILES}"/zsh/.zshrc*; do 82 | if [[ -f "$zshrc_file" ]]; then 83 | source "$zshrc_file" 84 | fi 85 | done 86 | 87 | for cfg in $DOTFILES/zsh/zshrc.d/*; do 88 | source $cfg 89 | done 90 | 91 | for fn in $DOTFILES/zsh/functions/*; do 92 | source $fn 93 | done 94 | -------------------------------------------------------------------------------- /nvim/lua/icons.lua: -------------------------------------------------------------------------------- 1 | return { 2 | mason = { 3 | package_installed = "◍", 4 | package_pending = "◍", 5 | package_uninstalled = "◍", 6 | }, 7 | diagnostics = { 8 | error = "", 9 | warning = "", 10 | hint = "󰌶", 11 | info = "", 12 | }, 13 | barbar = { 14 | active_button = "󰅖", 15 | inactive_button = "×", 16 | modified_button = "●", 17 | pinned_button = "󰐃", 18 | separator_left = "▎", 19 | }, 20 | ibl = { 21 | char = "▏", 22 | tab_char = "▏", 23 | }, 24 | dap = { 25 | breakpoint = "󰃤", 26 | disconnect = "", 27 | pause = "", 28 | play = "", 29 | run_last = "", 30 | step_back = "", 31 | step_into = "", 32 | step_out = "", 33 | step_over = "", 34 | terminate = "", 35 | collapsed = "", 36 | current_frame = "", 37 | expanded = "", 38 | }, 39 | telescope = { 40 | prompt_prefix = " ", 41 | selection_caret = " ", 42 | }, 43 | lsp = { 44 | Text = "", 45 | Method = "", 46 | Function = "", 47 | Constructor = "", 48 | 49 | Field = "", 50 | Variable = "", 51 | Property = "", 52 | 53 | Class = "", 54 | Interface = "", 55 | Struct = "", 56 | Module = "", 57 | 58 | Unit = "", 59 | Value = "", 60 | Enum = "", 61 | EnumMember = "", 62 | 63 | Keyword = "", 64 | Constant = "", 65 | 66 | Snippet = "", 67 | Color = "", 68 | File = "", 69 | Reference = "", 70 | Folder = "󰉋", 71 | Event = "", 72 | Operator = "", 73 | TypeParameter = "", 74 | }, 75 | statusline = { 76 | filetype = { 77 | sfm = "󰙅", 78 | fzf = "", 79 | VimDatabase = "", 80 | ["git.nvim"] = "", 81 | diff = "", 82 | floaterm = "", 83 | startify = "", 84 | help = "󰗚", 85 | }, 86 | buftype = { 87 | terminal = "", 88 | }, 89 | git = { 90 | branch = "󰊢", 91 | }, 92 | file = { 93 | default = "", 94 | }, 95 | }, 96 | gitsigns = { 97 | add = "│", 98 | change = "│", 99 | delete = "_", 100 | topdelete = "‾", 101 | changedelete = "~", 102 | untracked = "┆", 103 | }, 104 | nvim_ufo = { 105 | fold_suffix = "󰁂", 106 | }, 107 | fillchars = { 108 | foldopen = "", 109 | foldclose = "", 110 | foldsep = " ", 111 | eob = " ", 112 | fold = " ", 113 | }, 114 | listchars = { 115 | tab = "» ", 116 | eol = "¬", 117 | extends = "›", 118 | precedes = "‹", 119 | nbsp = "␣", 120 | trail = "·", 121 | }, 122 | } 123 | -------------------------------------------------------------------------------- /zsh/zshrc.d/kubectl.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | alias k='kubectl' 4 | alias kg='kubectl get' 5 | alias kgp='kubectl get pods' 6 | 7 | __pick_container() { 8 | containers=$(kubectl get pod $1 -o jsonpath='{.spec.containers[*].name}') 9 | if [ $(echo $containers | wc -w) -gt 1 ]; then 10 | container=$(echo $containers | tr " " "\n" | __fzfp --border="sharp") 11 | else 12 | container=$containers 13 | fi 14 | 15 | echo $container 16 | } 17 | 18 | function kdes() { 19 | resouce_name="$1" 20 | if [ -z $1 ]; then 21 | resouce_name="pod" 22 | fi 23 | 24 | resource=$(kubectl get $resouce_name --no-headers -o custom-columns=":metadata.name" | __fzfp) 25 | 26 | if [ -n "$resource" ]; then 27 | kubectl describe ${resouce_name} ${resource} 28 | fi 29 | } 30 | 31 | function kdel() { 32 | resouce_name="$1" 33 | if [ -z $1 ]; then 34 | resouce_name="pod" 35 | fi 36 | 37 | resource=$(kubectl get $resouce_name --no-headers -o custom-columns=":metadata.name" | __fzfp) 38 | 39 | if [ -n "$resource" ]; then 40 | kubectl delete ${resouce_name} $resource 41 | fi 42 | } 43 | 44 | function klf() { 45 | resouce_name="$1" 46 | if [ -z $1 ]; then 47 | resouce_name="pod" 48 | fi 49 | 50 | resource=$(kubectl get $resouce_name --no-headers -o custom-columns=":metadata.name" | __fzfp) 51 | 52 | if [ -n "$resource" ]; then 53 | container=$(__pick_container $resource) 54 | 55 | if [ -n "$container" ]; then 56 | kubectl logs -f ${resouce_name}/${resource} -c $container 57 | fi 58 | fi 59 | } 60 | 61 | 62 | function kpf() { 63 | if [ -z $1 ]; then 64 | echo "Please provide port" 65 | return 66 | fi 67 | 68 | pod=$(kubectl get pods --no-headers -o custom-columns=":metadata.name" | __fzfp) 69 | 70 | if [ -n "$pod" ]; then 71 | kubectl port-forward ${pod} $1 72 | fi 73 | } 74 | 75 | function ksf() { 76 | if [ -z $1 ]; then 77 | echo "Please provide port" 78 | return 79 | fi 80 | 81 | svc=$(kubectl get svc --no-headers -o custom-columns=":metadata.name" | __fzfp) 82 | 83 | if [ -n "$svc" ]; then 84 | kubectl port-forward svc/${svc} $1 85 | fi 86 | } 87 | 88 | function kexe() { 89 | pod=$(kubectl get pods --no-headers -o custom-columns=":metadata.name" | __fzfp) 90 | 91 | if [ -z "$pod" ]; then 92 | return 93 | fi 94 | 95 | container=$(__pick_container $pod) 96 | 97 | if [ -z "$container" ]; then 98 | return 99 | fi 100 | 101 | kubectl exec -it $pod -c $container -- ${1:-"sh"} 102 | } 103 | 104 | function kctx() { 105 | if [ -z $1 ] || [ $1 != "set" ]; then 106 | kubectl config current-context 107 | else 108 | ctx=$(kubectl config get-contexts --no-headers -o=name | __fzfp) 109 | kubectl config use-context $ctx 110 | fi 111 | } 112 | -------------------------------------------------------------------------------- /zsh/zshrc.d/bitwarden.zsh: -------------------------------------------------------------------------------- 1 | #!/bin/zsh 2 | 3 | function _bw_unlocked() { 4 | if [[ -z "${BW_SESSION}" || "$(bw status | jq -r '.status')" != "unlocked" ]]; then 5 | echo "Bitwarden is locked. Unlocking..." 6 | export BW_SESSION="$(bw unlock --raw)" 7 | 8 | # Check if unlock was successful 9 | if [[ $? -ne 0 || -z "${BW_SESSION}" ]]; then 10 | echo "Failed to unlock Bitwarden. Aborting." 11 | return 1 12 | fi 13 | echo "Bitwarden unlocked successfully." 14 | fi 15 | return 0 16 | } 17 | 18 | function bw_load_ssh_keys() { 19 | _bw_unlocked || return 1 20 | 21 | echo "Fetching SSH keys from Bitwarden..." 22 | bw list items | jq -r '.[] | select(.sshKey != null) | "\(.name)\t\(.id)"' | \ 23 | fzf --delimiter='\t' --with-nth=1 | \ 24 | cut -f2 | \ 25 | xargs -I{} sh -c 'bw get item {} | jq -r ".sshKey.privateKey" | ssh-add -' 26 | } 27 | 28 | function bw_get_password() { 29 | _bw_unlocked || return 1 30 | 31 | echo "Fetching items from Bitwarden..." 32 | local selected_option 33 | selected_option=$(bw list items | jq -r ' 34 | .[] | 35 | select(.login != null or (.fields != null and any(.fields[]; .type == 1))) | 36 | . as $item | 37 | ( 38 | if .login != null then 39 | "\($item.name)\t\($item.login.username // "")\tpassword\t\($item.id)" 40 | else empty end, 41 | if .fields != null then 42 | .fields[] | select(.type == 1) | "\($item.name) - \(.name)\t\($item.login.username // "")\t\(.name)\t\($item.id)" 43 | else empty end 44 | )' | \ 45 | fzf --delimiter='\t' --with-nth=1,2 --header="Name"$'\t'"Username" | \ 46 | cut -f3,4) 47 | 48 | if [[ -n "$selected_option" ]]; then 49 | local field_type=$(echo "$selected_option" | cut -f1) 50 | local item_id=$(echo "$selected_option" | cut -f2) 51 | 52 | if [[ "$field_type" == "password" ]]; then 53 | bw get item "$item_id" | jq -r '.login.password' | pbcopy 54 | echo "Password copied to clipboard!" 55 | else 56 | bw get item "$item_id" | jq -r --arg field_name "$field_type" '.fields[] | select(.name == $field_name and .type == 1) | .value' | pbcopy 57 | echo "Field '$field_type' copied to clipboard!" 58 | fi 59 | else 60 | echo "No item selected." 61 | fi 62 | } 63 | 64 | function bw_get_totp() { 65 | _bw_unlocked || return 1 66 | 67 | echo "Fetching items with TOTP from Bitwarden..." 68 | local selected_item 69 | selected_item=$(bw list items | jq -r '.[] | select(.login != null and .login.totp != null) | "\(.name)\t\(.login.username // "")\t\(.id)"' | \ 70 | fzf --delimiter='\t' --with-nth=1,2 --header="Name"$'\t'"Username" | \ 71 | cut -f3) 72 | 73 | if [[ -n "$selected_item" ]]; then 74 | bw get totp "$selected_item" | pbcopy 75 | echo "TOTP code copied to clipboard!" 76 | else 77 | echo "No item selected." 78 | fi 79 | } 80 | -------------------------------------------------------------------------------- /nvim/lua/config/keymaps.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | function M.setup() 4 | -- disable keys 5 | M.set("n", "Q", "") 6 | 7 | -- split 8 | M.set("n", "-", ":split") 9 | M.set("n", "\\", ":vsplit") 10 | 11 | -- alternate way to save 12 | M.set("n", "", ":w", { silent = false }) 13 | M.set("i", "", ":w", { silent = false }) 14 | 15 | -- alternate way to quit 16 | M.set("n", "", ":wq!", { silent = false }) 17 | 18 | -- close teminal 19 | M.set("t", "", ":q!", { silent = false }) 20 | 21 | -- vim move 22 | M.set("x", "", ">gv") 23 | M.set("x", "", "", ":move '<-2gv=gv") 25 | M.set("x", "", ":move '>+1gv=gv") 26 | 27 | M.set("n", "", ">>") 28 | M.set("n", "", "<<") 29 | M.set("n", "", ":move .-2") 30 | M.set("n", "", ":move .+1") 31 | 32 | -- copy 33 | M.set("n", "cpf", ":let @+ = expand('%:p')", { silent = false }) 34 | M.set("n", "cpr", ":let @+ = fnamemodify(expand('%'), ':~:.')", { silent = false }) 35 | M.set("n", "cpg", ":let @+ = system('git rev-parse --abbrev-ref HEAD')", { silent = false }) 36 | 37 | -- better navigation 38 | M.set("n", "", "10j") 39 | M.set("n", "", "10k") 40 | 41 | -- keep joinline cursor centerred 42 | M.set("n", "J", "mzJ`z") 43 | 44 | -- undo break points 45 | M.set("i", ",", ",u") 46 | M.set("i", ".", ".u") 47 | M.set("i", ";", ";u") 48 | M.set("i", "!", "!u") 49 | M.set("i", "?", "?u") 50 | 51 | -- better up/down 52 | M.set({ "n", "x" }, "j", "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true }) 53 | M.set({ "n", "x" }, "k", "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true }) 54 | 55 | -- https://github.com/mhinz/vim-galore#saner-behavior-of-n-and-n 56 | M.set("n", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" }) 57 | M.set("x", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" }) 58 | M.set("o", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result" }) 59 | M.set("n", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" }) 60 | M.set("x", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" }) 61 | M.set("o", "N", "'nN'[v:searchforward]", { expr = true, desc = "Prev search result" }) 62 | 63 | -- allow to search in selection mode 64 | M.set({ "x" }, "/", "/\\%V") 65 | 66 | -- better navigation in insert mode 67 | M.set({ "i" }, "", "ea") 68 | M.set({ "i" }, "", "bi") 69 | end 70 | 71 | function M.set(mode, lhs, rhs, opts) 72 | opts = vim.tbl_extend("force", { 73 | noremap = true, 74 | silent = true, 75 | expr = false, 76 | }, opts or {}) 77 | 78 | vim.keymap.set(mode, lhs, rhs, opts) 79 | end 80 | 81 | return M 82 | -------------------------------------------------------------------------------- /nvim/lua/lsp/init.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | local blink = require "blink.cmp" 4 | local icons = require "icons" 5 | local lsp_keymaps = require "lsp.keymaps" 6 | local lsp_signature = require "lsp_signature" 7 | local navbuddy = require "nvim-navbuddy" 8 | 9 | function M.setup_global_config() 10 | local capabilities = vim.lsp.protocol.make_client_capabilities() 11 | capabilities = vim.tbl_deep_extend("force", capabilities, blink.get_lsp_capabilities()) 12 | 13 | vim.lsp.config("*", { 14 | capabilities = capabilities, 15 | root_markers = { ".git", ".hg" }, 16 | }) 17 | end 18 | 19 | function M.setup_handlers() 20 | vim.diagnostic.config { 21 | signs = { 22 | text = { 23 | [vim.diagnostic.severity.ERROR] = icons.diagnostics.error, 24 | [vim.diagnostic.severity.WARN] = icons.diagnostics.warning, 25 | [vim.diagnostic.severity.INFO] = icons.diagnostics.info, 26 | [vim.diagnostic.severity.HINT] = icons.diagnostics.hint, 27 | }, 28 | }, 29 | virtual_text = true, 30 | update_in_insert = true, 31 | underline = true, 32 | severity_sort = true, 33 | float = { 34 | focusable = true, 35 | style = "minimal", 36 | border = "rounded", 37 | source = true, 38 | header = "", 39 | prefix = "", 40 | }, 41 | } 42 | end 43 | 44 | function M.setup_servers() 45 | local servers = { 46 | "clangd", 47 | "ts_ls", 48 | "jsonls", 49 | "lua_ls", 50 | "phpactor", 51 | "ruby_lsp", 52 | "basedpyright", 53 | "sqlls", 54 | "yamlls", 55 | "gopls", 56 | "bashls", 57 | "terraformls", 58 | "buf_ls", 59 | } 60 | 61 | for _, server in ipairs(servers) do 62 | local ok, server_config = pcall(require, "lsp.settings." .. server) 63 | if ok then 64 | vim.lsp.config(server, server_config) 65 | end 66 | 67 | vim.lsp.enable(server) 68 | end 69 | end 70 | 71 | function M.setup_autocmds() 72 | vim.api.nvim_create_autocmd("LspAttach", { 73 | group = vim.api.nvim_create_augroup("UserLspConfig", {}), 74 | callback = function(args) 75 | local client = vim.lsp.get_client_by_id(args.data.client_id) 76 | if not client then 77 | return 78 | end 79 | 80 | local bufnr = args.buf 81 | 82 | lsp_keymaps.setup(bufnr) 83 | 84 | -- Setup lsp_signature 85 | lsp_signature.on_attach({ 86 | hint_enable = false, 87 | hi_parameter = "Underlined", 88 | }, bufnr) 89 | 90 | -- Setup nvim-navbuddy (only for clients that support document symbols) 91 | if client:supports_method "textDocument/documentSymbol" then 92 | navbuddy.attach(client, bufnr) 93 | end 94 | end, 95 | }) 96 | end 97 | 98 | function M.setup() 99 | M.setup_global_config() 100 | M.setup_handlers() 101 | M.setup_servers() 102 | M.setup_autocmds() 103 | end 104 | 105 | return M 106 | -------------------------------------------------------------------------------- /alacritty/alacritty.toml: -------------------------------------------------------------------------------- 1 | live_config_reload = true 2 | 3 | [bell] 4 | animation = "EaseOutExpo" 5 | color = "#ffffff" 6 | duration = 0 7 | 8 | [colors] 9 | draw_bold_text_with_bright_colors = false 10 | 11 | [[colors.indexed_colors]] 12 | color = "0xff9e64" 13 | index = 16 14 | 15 | [[colors.indexed_colors]] 16 | color = "0xdb4b4b" 17 | index = 17 18 | 19 | [colors.bright] 20 | black = "0x414868" 21 | blue = "0x7aa2f7" 22 | cyan = "0x7dcfff" 23 | green = "0x9ece6a" 24 | magenta = "0xbb9af7" 25 | red = "0xf7768e" 26 | white = "0xc0caf5" 27 | yellow = "0xe0af68" 28 | 29 | [colors.normal] 30 | black = "0x15161E" 31 | blue = "0x7aa2f7" 32 | cyan = "0x7dcfff" 33 | green = "0x9ece6a" 34 | magenta = "0xbb9af7" 35 | red = "0xf7768e" 36 | white = "0xa9b1d6" 37 | yellow = "0xe0af68" 38 | 39 | [colors.primary] 40 | background = "0x1a1b26" 41 | foreground = "0xc0caf5" 42 | 43 | [cursor] 44 | style = "Block" 45 | unfocused_hollow = true 46 | 47 | [env] 48 | TERM = "xterm-256color" 49 | 50 | [font] 51 | size = 14.0 52 | 53 | [font.bold] 54 | family = "FiraCode Nerd Font" 55 | style = "Bold" 56 | 57 | [font.bold_italic] 58 | family = "FiraCode Nerd Font" 59 | style = "Bold Italic" 60 | 61 | [font.glyph_offset] 62 | x = 0 63 | y = 0 64 | 65 | [font.italic] 66 | family = "FiraCode Nerd Font" 67 | style = "Italic" 68 | 69 | [font.normal] 70 | family = "FiraCode Nerd Font" 71 | style = "Retina" 72 | 73 | [font.offset] 74 | x = 0 75 | y = 0 76 | 77 | [[keyboard.bindings]] 78 | action = "ResetFontSize" 79 | key = "Key0" 80 | mods = "Command" 81 | 82 | [[keyboard.bindings]] 83 | action = "IncreaseFontSize" 84 | key = "Equals" 85 | mods = "Command" 86 | 87 | [[keyboard.bindings]] 88 | action = "DecreaseFontSize" 89 | key = "Minus" 90 | mods = "Command" 91 | 92 | [[keyboard.bindings]] 93 | action = "Paste" 94 | key = "V" 95 | mods = "Command" 96 | 97 | [[keyboard.bindings]] 98 | action = "Copy" 99 | key = "C" 100 | mods = "Command" 101 | 102 | [[keyboard.bindings]] 103 | action = "Quit" 104 | key = "Q" 105 | mods = "Command" 106 | 107 | [[keyboard.bindings]] 108 | action = "None" 109 | key = "M" 110 | mods = "Command" 111 | 112 | [[keyboard.bindings]] 113 | action = "None" 114 | key = "N" 115 | mods = "Command" 116 | 117 | [[keyboard.bindings]] 118 | action = "None" 119 | key = "W" 120 | mods = "Command" 121 | 122 | [[keyboard.bindings]] 123 | chars = "\u001BOH" 124 | key = "Left" 125 | mods = "Command" 126 | 127 | [[keyboard.bindings]] 128 | chars = "\u001BOF" 129 | key = "Right" 130 | mods = "Command" 131 | 132 | [scrolling] 133 | history = 10000 134 | multiplier = 3 135 | 136 | [selection] 137 | save_to_clipboard = false 138 | semantic_escape_chars = ",│`|:\"' ()[]{}<>\t" 139 | 140 | [shell] 141 | program = "/bin/zsh" 142 | 143 | [window] 144 | decorations = "full" 145 | dynamic_padding = false 146 | startup_mode = "Maximized" 147 | option_as_alt = "Both" 148 | 149 | [window.dimensions] 150 | columns = 0 151 | lines = 0 152 | 153 | [window.padding] 154 | x = 0 155 | y = 0 156 | -------------------------------------------------------------------------------- /nvim/lua/plugins/gitsigns.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | local icons = require "icons" 3 | 4 | local M = {} 5 | 6 | M.setup = function() 7 | local status_ok, gitsigns = pcall(require, "gitsigns") 8 | if not status_ok then 9 | return 10 | end 11 | 12 | gitsigns.setup { 13 | signs = { 14 | add = { 15 | text = icons.gitsigns.add, 16 | }, 17 | change = { 18 | text = icons.gitsigns.change, 19 | }, 20 | delete = { 21 | text = icons.gitsigns.delete, 22 | }, 23 | topdelete = { 24 | text = icons.gitsigns.topdelete, 25 | }, 26 | changedelete = { 27 | text = icons.gitsigns.changedelete, 28 | }, 29 | untracked = { 30 | text = icons.gitsigns.untracked, 31 | }, 32 | }, 33 | numhl = false, 34 | linehl = false, 35 | on_attach = function(bufnr) 36 | local gs = package.loaded.gitsigns 37 | 38 | local function map(mode, l, r, opts) 39 | opts = opts or {} 40 | opts.buffer = bufnr 41 | 42 | keymaps.set(mode, l, r, opts) 43 | end 44 | 45 | -- navigation 46 | map("n", "ghn", function() 47 | if vim.wo.diff then 48 | return "ghn" 49 | end 50 | vim.schedule(function() 51 | gs.next_hunk() 52 | end) 53 | return "" 54 | end, { expr = true }) 55 | 56 | map("n", "ghN", function() 57 | if vim.wo.diff then 58 | return "ghN" 59 | end 60 | vim.schedule(function() 61 | gs.prev_hunk() 62 | end) 63 | return "" 64 | end, { expr = true }) 65 | 66 | map("n", "ghv", gs.preview_hunk) 67 | map("n", "ghu", gs.reset_hunk) 68 | map("v", "ghu", function() 69 | gs.reset_hunk { vim.fn.line ".", vim.fn.line "v" } 70 | end) 71 | map("n", "ghU", gs.reset_buffer) 72 | 73 | map("n", "ghs", gs.stage_hunk) 74 | map("v", "ghs", function() 75 | gs.stage_hunk { vim.fn.line ".", vim.fn.line "v" } 76 | end) 77 | map("n", "ghS", gs.stage_buffer) 78 | 79 | map("n", "ghl", function() 80 | gs.blame_line { full = false } 81 | end) 82 | 83 | map("n", "ghd", gs.diffthis) 84 | map("n", "ghD", function() 85 | gs.diffthis "~" 86 | end) 87 | end, 88 | signcolumn = true, 89 | word_diff = false, 90 | attach_to_untracked = true, 91 | current_line_blame = false, -- Toggle with `:Gitsigns toggle_current_line_blame` 92 | current_line_blame_opts = { 93 | virt_text = true, 94 | virt_text_pos = "eol", -- 'eol' | 'overlay' | 'right_align' 95 | delay = 1000, 96 | ignore_whitespace = false, 97 | }, 98 | max_file_length = 40000, 99 | preview_config = { 100 | -- Options passed to nvim_open_win 101 | border = "rounded", 102 | style = "minimal", 103 | relative = "cursor", 104 | row = 0, 105 | col = 1, 106 | }, 107 | watch_gitdir = { 108 | interval = 1000, 109 | follow_files = true, 110 | }, 111 | sign_priority = 6, 112 | update_debounce = 200, 113 | status_formatter = nil, -- Use default 114 | } 115 | end 116 | 117 | return M 118 | -------------------------------------------------------------------------------- /nvim/lua/core/floaterm.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | 3 | local M = {} 4 | 5 | local floaterm_win, floaterm_buf 6 | 7 | local function is_open() 8 | if not floaterm_win then 9 | return false 10 | end 11 | 12 | return vim.fn.win_gotoid(floaterm_win) > 0 and vim.api.nvim_win_get_buf(floaterm_win) == floaterm_buf 13 | end 14 | 15 | local function close_floaterm_win() 16 | if floaterm_win then 17 | if vim.api.nvim_win_is_valid(floaterm_win) then 18 | vim.api.nvim_win_close(floaterm_win, true) 19 | end 20 | end 21 | floaterm_win = nil 22 | end 23 | 24 | local function close_floaterm_buf() 25 | if floaterm_buf then 26 | if vim.api.nvim_buf_is_valid(floaterm_buf) then 27 | vim.api.nvim_buf_delete(floaterm_buf, { force = true }) 28 | end 29 | end 30 | floaterm_buf = nil 31 | end 32 | 33 | local function hide_floaterm() 34 | close_floaterm_win() 35 | end 36 | 37 | local function kill_floaterm() 38 | close_floaterm_win() 39 | close_floaterm_buf() 40 | end 41 | 42 | local function open_floaterm(cmd) 43 | local width = vim.api.nvim_get_option "columns" 44 | local height = vim.api.nvim_get_option "lines" 45 | local win_height = math.ceil(height * 0.8 - 4) 46 | local win_width = math.ceil(width * 0.8) 47 | local row = math.ceil((height - win_height) / 2 - 1) 48 | local col = math.ceil((width - win_width) / 2) 49 | 50 | local floaterm_opts = { 51 | style = "minimal", 52 | relative = "editor", 53 | width = win_width, 54 | height = win_height, 55 | row = row, 56 | col = col, 57 | anchor = "NW", 58 | border = "single", 59 | } 60 | 61 | if floaterm_buf and vim.api.nvim_buf_is_valid(floaterm_buf) then 62 | floaterm_win = vim.api.nvim_open_win(floaterm_buf, true, floaterm_opts) 63 | vim.api.nvim_command "startinsert" 64 | return 65 | end 66 | 67 | floaterm_buf = vim.api.nvim_create_buf(false, true) 68 | vim.api.nvim_buf_set_option(floaterm_buf, "buftype", "") 69 | vim.api.nvim_buf_set_option(floaterm_buf, "bufhidden", "hide") 70 | vim.api.nvim_buf_set_option(floaterm_buf, "swapfile", false) 71 | vim.api.nvim_buf_set_option(floaterm_buf, "filetype", "floaterm") 72 | 73 | floaterm_win = vim.api.nvim_open_win(floaterm_buf, true, { 74 | style = "minimal", 75 | relative = "editor", 76 | width = win_width, 77 | height = win_height, 78 | row = row, 79 | col = col, 80 | anchor = "NW", 81 | border = "single", 82 | }) 83 | vim.api.nvim_win_set_option(floaterm_win, "winhl", "Normal:Normal") 84 | vim.api.nvim_win_set_option(floaterm_win, "cursorline", true) 85 | vim.api.nvim_win_set_option(floaterm_win, "colorcolumn", "") 86 | 87 | if cmd then 88 | vim.call("termopen", "bash -c " .. cmd) 89 | else 90 | vim.api.nvim_command "terminal" 91 | end 92 | vim.api.nvim_command "startinsert" 93 | -- This option should be set after terminal command 94 | vim.api.nvim_buf_set_option(floaterm_buf, "buflisted", false) 95 | 96 | vim.api.nvim_command "autocmd TermClose ++once lua require'core.floaterm'.on_term_close()" 97 | end 98 | 99 | function M.on_floaterm_close() 100 | vim.api.nvim_command "silent checktime" 101 | end 102 | 103 | function M.on_term_close() 104 | M.on_floaterm_close() 105 | vim.schedule(function() 106 | kill_floaterm() 107 | end) 108 | end 109 | 110 | function M.new_floaterm(cmd) 111 | kill_floaterm() 112 | open_floaterm(cmd) 113 | end 114 | 115 | function M.toggle_floaterm() 116 | if is_open() then 117 | hide_floaterm() 118 | M.on_floaterm_close() 119 | else 120 | open_floaterm() 121 | end 122 | end 123 | 124 | function M.setup() 125 | keymaps.set("n", "tg", function() 126 | M.new_floaterm "lazygit" 127 | end) 128 | end 129 | 130 | return M 131 | -------------------------------------------------------------------------------- /nvim/lua/plugins/jdtls.lua: -------------------------------------------------------------------------------- 1 | local M = {} 2 | 3 | M.setup = function() 4 | local home = os.getenv "HOME" 5 | local jdtls_path = require("mason-registry").get_package("jdtls"):get_install_path() 6 | -- File types that signify a Java project's root directory. This will be 7 | -- used by eclipse to determine what constitutes a workspace 8 | local root_markers = { ".gradlew", ".git", "mvnw", "pom.xml", "build.gradle" } 9 | local root_dir = require("jdtls.setup").find_root(root_markers) 10 | 11 | -- eclipse.jdt.ls stores project specific data within a folder. If you are working 12 | -- with multiple different projects, each project must use a dedicated data directory. 13 | -- This variable is used to configure eclipse to use the directory name of the 14 | -- current project found using the root_marker as the folder for project specific data. 15 | local workspace_dir = home .. "/.cache/jdtls/workspace" .. vim.fn.fnamemodify(root_dir, ":p:h:t") 16 | local lombok_path = jdtls_path .. "/lombok.jar" 17 | local path_to_jar = vim.fn.glob(jdtls_path .. "/plugins/org.eclipse.equinox.launcher_*.jar") 18 | -- The configuration for jdtls. This will need to be updated depending on your environment 19 | local path_to_config = jdtls_path .. "/config_mac_arm" 20 | 21 | local config = { 22 | root_dir = root_dir, 23 | } 24 | 25 | config.cmd = { 26 | "java", -- or '/path/to/java17_or_newer/bin/java' 27 | "-Declipse.application=org.eclipse.jdt.ls.core.id1", 28 | "-Dosgi.bundles.defaultStartLevel=4", 29 | "-Declipse.product=org.eclipse.jdt.ls.core.product", 30 | "-Dlog.protocol=true", 31 | "-Dlog.level=ALL", 32 | "-Xmx4g", 33 | "--add-modules=ALL-SYSTEM", 34 | "--add-opens", 35 | "java.base/java.util=ALL-UNNAMED", 36 | "--add-opens", 37 | "java.base/java.lang=ALL-UNNAMED", 38 | "-javaagent:" .. lombok_path, 39 | "-jar", 40 | path_to_jar, 41 | "-configuration", 42 | path_to_config, 43 | "-data", 44 | workspace_dir, 45 | } 46 | 47 | config.settings = { 48 | java = { 49 | signatureHelp = { enabled = true }, 50 | contentProvider = { preferred = "fernflower" }, 51 | completion = { 52 | favoriteStaticMembers = { 53 | "org.hamcrest.MatcherAssert.assertThat", 54 | "org.hamcrest.Matchers.*", 55 | "org.hamcrest.CoreMatchers.*", 56 | "org.junit.jupiter.api.Assertions.*", 57 | "java.util.Objects.requireNonNull", 58 | "java.util.Objects.requireNonNullElse", 59 | "org.mockito.Mockito.*", 60 | }, 61 | filteredTypes = { 62 | "com.sun.*", 63 | "io.micrometer.shaded.*", 64 | "java.awt.*", 65 | "jdk.*", 66 | "sun.*", 67 | }, 68 | importOrder = { 69 | "java", 70 | "javax", 71 | "com", 72 | "org", 73 | }, 74 | }, 75 | sources = { 76 | organizeImports = { 77 | starThreshold = 9999, 78 | staticStarThreshold = 9999, 79 | }, 80 | }, 81 | codeGeneration = { 82 | toString = { 83 | template = "${object.className}{${member.name()}=${member.value}, ${otherMembers}}", 84 | }, 85 | hashCodeEquals = { 86 | useJava7Objects = true, 87 | }, 88 | useBlocks = true, 89 | }, 90 | -- If you are developing in projects with different Java versions, you need 91 | -- to tell eclipse.jdt.ls to use the location of the JDK for your Java version 92 | -- See https://github.com/eclipse/eclipse.jdt.ls/wiki/Running-the-JAVA-LS-server-from-the-command-line#initialize-request 93 | -- And search for `interface RuntimeOption` 94 | -- The `name` is NOT arbitrary, but must match one of the elements from `enum ExecutionEnvironment` in the link above 95 | -- configuration = { 96 | -- runtimes = { 97 | -- { 98 | -- name = "JavaSE-17", 99 | -- path = home .. "/.asdf/installs/java/corretto-17.0.10.7.1", 100 | -- }, 101 | -- }, 102 | -- }, 103 | }, 104 | } 105 | 106 | vim.api.nvim_create_autocmd("FileType", { 107 | pattern = "java", 108 | callback = function() 109 | require("jdtls").start_or_attach(config) 110 | end, 111 | }) 112 | end 113 | 114 | return M 115 | -------------------------------------------------------------------------------- /nvim/lua/plugins/sfm.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | local bdelete = require("barbar.bbye").bdelete 3 | local event = require "sfm.event" 4 | 5 | local M = {} 6 | 7 | M.setup = function() 8 | local sfm_explorer = require("sfm").setup { 9 | view = { 10 | selection_render_method = "sign", 11 | }, 12 | renderer = { 13 | icons = { 14 | selection = "*", 15 | }, 16 | }, 17 | mappings = { 18 | list = { 19 | { 20 | key = "", 21 | action = nil, 22 | }, 23 | { 24 | key = "", 25 | action = nil, 26 | }, 27 | }, 28 | }, 29 | file_nesting = { 30 | enabled = true, 31 | expand = true, 32 | patterns = { 33 | { "*.php", { "$(capture)Interface.php" } }, 34 | { "*.c", { "$(capture).h" } }, 35 | { "*.cc", { "$(capture).hpp", "$(capture).h", "$(capture).hxx" } }, 36 | { "*.cpp", { "$(capture).hpp", "$(capture).h", "$(capture).hxx" } }, 37 | { "go.mod", { "go.sum" } }, 38 | { "*.up.sql", { "$(capture).down.sql" } }, 39 | { "*.go", { "$(capture)_test.go" } }, 40 | { ".env", { "*.env", ".env.*", ".envrc", "env.d.ts" } }, 41 | { ".gitignore", { ".gitattributes", ".gitmodules", ".gitmessage", ".mailmap", ".git-blame*" } }, 42 | { "composer.json", { ".php*.cache", "composer.lock", "phpunit.xml*", "psalm*.xml" } }, 43 | { 44 | "readme*", 45 | { 46 | "authors", 47 | "backers*", 48 | "changelog*", 49 | "citation*", 50 | "code_of_conduct*", 51 | "codeowners", 52 | "contributing*", 53 | "contributors", 54 | "copying*", 55 | "credits", 56 | "governance.md", 57 | "history.md", 58 | "license*", 59 | "maintainers", 60 | "readme*", 61 | "security.md", 62 | "sponsors*", 63 | }, 64 | }, 65 | { 66 | "artisan", 67 | { 68 | "*.env", 69 | ".babelrc*", 70 | ".codecov", 71 | ".cssnanorc*", 72 | ".env.*", 73 | ".envrc", 74 | ".htmlnanorc*", 75 | ".lighthouserc.*", 76 | ".mocha*", 77 | ".postcssrc*", 78 | ".terserrc*", 79 | "api-extractor.json", 80 | "ava.config.*", 81 | "babel.config.*", 82 | "contentlayer.config.*", 83 | "cssnano.config.*", 84 | "cypress.*", 85 | "env.d.ts", 86 | "formkit.config.*", 87 | "formulate.config.*", 88 | "histoire.config.*", 89 | "htmlnanorc.*", 90 | "i18n.config.*", 91 | "jasmine.*", 92 | "jest.config.*", 93 | "jsconfig.*", 94 | "karma*", 95 | "lighthouserc.*", 96 | "playwright.config.*", 97 | "postcss.config.*", 98 | "puppeteer.config.*", 99 | "rspack.config.*", 100 | "server.php", 101 | "svgo.config.*", 102 | "tailwind.config.*", 103 | "tsconfig.*", 104 | "tsdoc.*", 105 | "uno.config.*", 106 | "unocss.config.*", 107 | "vitest.config.*", 108 | "vuetify.config.*", 109 | "webpack.config.*", 110 | "webpack.mix.js", 111 | "windi.config.*", 112 | }, 113 | }, 114 | }, 115 | }, 116 | } 117 | 118 | sfm_explorer:load_extension "sfm-bookmark" 119 | sfm_explorer:load_extension "sfm-filter" 120 | sfm_explorer:load_extension "sfm-git" 121 | sfm_explorer:load_extension "sfm-telescope" 122 | sfm_explorer:load_extension "sfm-paste" 123 | 124 | sfm_explorer:subscribe(event.EntryDeleted, function(payload) 125 | local path = payload["path"] 126 | local bufnr = vim.fn.bufnr(path, true) 127 | bdelete(false, bufnr) 128 | end) 129 | 130 | sfm_explorer:subscribe(event.EntryRenamed, function(payload) 131 | local from_path = payload["from_path"] 132 | local bufnr = vim.fn.bufnr(from_path, true) 133 | bdelete(false, bufnr) 134 | end) 135 | 136 | keymaps.set("n", "", "SFMToggle", { noremap = true, silent = true }) 137 | keymaps.set("n", "fm", "SFMToggle", { noremap = true, silent = true }) 138 | end 139 | 140 | return M 141 | -------------------------------------------------------------------------------- /nvim/lua/plugins/telescope.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | local icons = require "icons" 3 | 4 | local M = {} 5 | 6 | local action_state = require "telescope.actions.state" 7 | local helpers = require "telescope-live-grep-args.helpers" 8 | 9 | local function quote_prompt(opts) 10 | opts = opts or {} 11 | opts = vim.tbl_extend("force", { 12 | quote_char = '"', 13 | postfix = " ", 14 | trim = true, 15 | }, opts) 16 | 17 | return function(prompt_bufnr) 18 | local picker = action_state.get_current_picker(prompt_bufnr) 19 | local prompt = picker:_get_prompt() 20 | if opts.trim then 21 | prompt = vim.trim(prompt) 22 | end 23 | 24 | if prompt == nil or prompt == "" then 25 | return 26 | end 27 | 28 | if prompt:sub(1, 1) ~= "\"" then 29 | prompt = helpers.quote(prompt, { quote_char = opts.quote_char }) 30 | end 31 | 32 | local postfix = vim.trim(opts.postfix) 33 | if prompt ~= nil and prompt ~= "" and prompt:sub(-#postfix) ~= postfix then 34 | prompt = prompt .. opts.postfix 35 | end 36 | 37 | picker:set_prompt(prompt) 38 | end 39 | end 40 | 41 | M.setup = function() 42 | local status_ok, telescope = pcall(require, "telescope") 43 | if not status_ok then 44 | return 45 | end 46 | 47 | local actions = require "telescope.actions" 48 | 49 | telescope.load_extension "ui-select" 50 | telescope.load_extension "sfm-telescope" 51 | 52 | telescope.setup { 53 | defaults = { 54 | entry_prefix = " ", 55 | initial_mode = "insert", 56 | prompt_prefix = icons.telescope.prompt_prefix, 57 | selection_caret = icons.telescope.selection_caret, 58 | path_display = { "smart" }, 59 | scroll_strategy = "limit", 60 | selection_strategy = "reset", 61 | sorting_strategy = "ascending", 62 | layout_strategy = "vertical", 63 | layout_config = { 64 | preview_cutoff = 0, 65 | vertical = { 66 | prompt_position = "top", 67 | mirror = true, 68 | width = 0.5, 69 | }, 70 | }, 71 | mappings = { 72 | i = { 73 | [""] = actions.close, 74 | [""] = actions.close, 75 | 76 | [""] = actions.select_default, 77 | [""] = actions.select_horizontal, 78 | [""] = actions.select_vertical, 79 | 80 | [""] = actions.cycle_history_next, 81 | [""] = actions.cycle_history_prev, 82 | 83 | [""] = actions.move_selection_next, 84 | [""] = actions.move_selection_next, 85 | [""] = actions.move_selection_previous, 86 | [""] = actions.move_selection_previous, 87 | 88 | [""] = actions.preview_scrolling_up, 89 | [""] = actions.preview_scrolling_down, 90 | 91 | [""] = actions.which_key, 92 | }, 93 | }, 94 | }, 95 | pickers = { 96 | live_grep = { 97 | only_sort_text = true, 98 | }, 99 | find_files = { 100 | hidden = false, 101 | find_command = { "fd", "--type", "f", "--follow" }, 102 | }, 103 | }, 104 | extensions = { 105 | ["ui-select"] = {}, 106 | live_grep_args = { 107 | auto_quoting = true, 108 | mappings = { 109 | i = { 110 | [""] = quote_prompt(), 111 | [""] = quote_prompt { postfix = " --iglob " }, 112 | }, 113 | }, 114 | vimgrep_arguments = { 115 | "rg", 116 | "--color=never", 117 | "--no-heading", 118 | "--with-filename", 119 | "--line-number", 120 | "--column", 121 | "--smart-case", 122 | "--hidden", 123 | "--glob=!.git/", 124 | }, 125 | }, 126 | }, 127 | } 128 | 129 | keymaps.set("n", "fg", ":lua require('telescope.builtin').git_status()", { noremap = true }) 130 | keymaps.set("n", "fb", ":lua require('telescope.builtin').buffers()", { noremap = true }) 131 | keymaps.set("n", "ft", ":lua require('telescope.builtin').treesitter()", { noremap = true }) 132 | keymaps.set("n", "fh", ":lua require('telescope.builtin').command_history()", { noremap = true }) 133 | keymaps.set("n", "f.", ":lua require('telescope.builtin').resume()", { noremap = true }) 134 | keymaps.set("n", "fr", ":lua require('telescope').extensions.live_grep_args.live_grep_args()") 135 | end 136 | 137 | return M 138 | -------------------------------------------------------------------------------- /nvim/lua/core/picsur.lua: -------------------------------------------------------------------------------- 1 | -- Reference: https://github.com/evanpurkhiser/image-paste.nvim 2 | 3 | local M = {} 4 | 5 | local image_name = "picsur.png" 6 | local picsur_base_url = "https://img.dinhhuy258.dev" 7 | local picsur_api_key = vim.env.PICSUR_API_KEY 8 | 9 | local function has_clipboard_img() 10 | local handle = io.popen "pngpaste -b 2>&1" 11 | if handle == nil then 12 | return false 13 | end 14 | 15 | local result = handle:read "*a" 16 | 17 | handle:close() 18 | 19 | -- check if the output is clipboard img 20 | return string.sub(result, 1, 9) == "iVBORw0KG" -- magic png number in base64 21 | end 22 | 23 | local function compress_image() 24 | -- Create temporary file names 25 | local temp_input = os.tmpname() 26 | local temp_output = temp_input .. ".jpg" 27 | 28 | -- Save clipboard content to temporary input file 29 | os.execute("pngpaste " .. temp_input) 30 | 31 | -- Compress image using ffmpeg 32 | local compress_command = string.format("ffmpeg -i %s %s", temp_input, temp_output) 33 | os.execute(compress_command .. " > /dev/null 2>&1") 34 | 35 | -- Copy compressed image back to clipboard 36 | os.execute("osascript -e 'set the clipboard to (read (POSIX file \"" .. temp_output .. "\") as JPEG picture)'") 37 | 38 | -- Remove temporary files 39 | os.remove(temp_input) 40 | os.remove(temp_output) 41 | 42 | -- Check for errors 43 | if vim.v.shell_error ~= 0 then 44 | return false 45 | end 46 | 47 | return true 48 | end 49 | 50 | function M.paste_image() 51 | -- check if the clipboard has image 52 | if not has_clipboard_img() then 53 | vim.notify("There is nothing to paste.", vim.log.levels.ERROR) 54 | 55 | return 56 | end 57 | 58 | -- compress image before uploading to imgur 59 | if not compress_image() then 60 | vim.notify("Failed to compress image.", vim.log.levels.ERROR) 61 | 62 | return 63 | end 64 | 65 | local template_md = "![%s](%s)" 66 | 67 | local placeholder_alt = string.format("Uploading %s…", image_name) 68 | local placeholder = string.format(template_md, placeholder_alt, "") 69 | 70 | -- Insert the upload template 71 | local buffer = vim.api.nvim_get_current_buf() 72 | local row, col = unpack(vim.api.nvim_win_get_cursor(0)) 73 | vim.api.nvim_buf_set_text(buffer, row - 1, col, row - 1, col, { placeholder }) 74 | vim.api.nvim_win_set_cursor(0, { row, col + placeholder:len() + 1 }) 75 | 76 | -- Mark the location of the template for replacing later 77 | local mark_ns = vim.api.nvim_create_namespace "" 78 | local mark_id = vim.api.nvim_buf_set_extmark( 79 | buffer, 80 | mark_ns, 81 | row - 1, 82 | col, 83 | { end_col = col + placeholder:len(), hl_group = "Whitespace" } 84 | ) 85 | 86 | local upload_command = string.format( 87 | [[pngpaste - \ 88 | | curl \ 89 | --silent \ 90 | --fail \ 91 | --request POST \ 92 | --form "image=@-" \ 93 | --header "Authorization: Api-Key %s" \ 94 | "%s/api/image/upload" \ 95 | | jq --raw-output .data.id 96 | ]], 97 | picsur_api_key, 98 | picsur_base_url 99 | ) 100 | 101 | local url = nil 102 | 103 | -- Start uploading 104 | vim.fn.jobstart(upload_command, { 105 | stdout_buffered = true, 106 | on_stdout = function(_, img_id) 107 | local id = vim.fn.join(img_id):gsub("^%s*(.-)%s*$", "%1") 108 | url = string.format("%s/i/%s.jpg", picsur_base_url, id) 109 | end, 110 | on_exit = function(_, exit_code) 111 | local failed = url == "" or exit_code ~= 0 112 | local replacement = "" 113 | 114 | -- Create the replacement string 115 | if not failed then 116 | replacement = string.format(template_md, image_name, url) 117 | else 118 | vim.notify("Failed to upload or paste image.", vim.log.levels.ERROR) 119 | end 120 | 121 | -- Locate the mark 122 | local mark_row, mark_col = unpack(vim.api.nvim_buf_get_extmark_by_id(buffer, mark_ns, mark_id, {})) 123 | 124 | -- Update the line containing the mark 125 | vim.api.nvim_buf_del_extmark(buffer, mark_ns, mark_id) 126 | vim.api.nvim_buf_set_text(buffer, mark_row, mark_col, mark_row, mark_col + placeholder:len(), { replacement }) 127 | end, 128 | }) 129 | end 130 | 131 | function M.setup() 132 | vim.api.nvim_create_autocmd("FileType", { 133 | pattern = "markdown", 134 | callback = function() 135 | vim.api.nvim_create_user_command("UploadImage", function() 136 | M.paste_image() 137 | end, { 138 | bang = true, 139 | nargs = "*", 140 | }) 141 | end, 142 | }) 143 | end 144 | 145 | return M 146 | -------------------------------------------------------------------------------- /nvim/lua/config/options.lua: -------------------------------------------------------------------------------- 1 | local icons = require "icons" 2 | 3 | local M = {} 4 | 5 | local options = { 6 | shell = "/bin/zsh", -- Shell 7 | fileencoding = "utf-8", -- File-content encoding for the current buffe 8 | fileencodings = "utf-8", -- This is a list of character encodings considered when starting to edit an existing file. Note that 'fileencodings' is not used for a new file, the global value of 'fileencoding' is used instead 9 | backspace = "indent,eol,start", -- Allow backspace over indention, line breaks and insertion start 10 | tabstop = 2, -- Number of spaces that a in the file counts for 11 | shiftwidth = 2, -- Number of spaces to use for each step of (auto)indent. Used for >>, <<, etc 12 | expandtab = true, -- Convert tabs to spaces 13 | smartindent = true, -- Do smart autoindenting when starting a new line 14 | autoindent = true, -- Copy indent from current line when starting a new line (typing in Insert mode or when using the "o" or "O" command) 15 | wrap = false, -- Display long lines as just one line 16 | scrolloff = 4, -- Minimal number of screen lines to keep above and below the cursor 17 | sidescrolloff = 4, -- The minimal number of screen columns to keep to the left and to the right of the cursor 18 | hlsearch = true, -- Highlight all matches on previous search pattern 19 | incsearch = true, -- While typing a search command, show where the pattern, as it was typed so far, matches 20 | ignorecase = true, -- Ignore case in search patterns 21 | smartcase = true, -- Override the 'ignorecase' option if the search pattern contains upper case characters 22 | number = true, -- Dislay line numbers 23 | numberwidth = 2, -- Set number column width to 2 (default 4) 24 | relativenumber = true, -- Disable relative number 25 | laststatus = 3, -- Always and ONLY the last window 26 | showtabline = 2, -- Always show tabs (2 = always) 27 | hidden = true, -- Required to keep multiple buffers open multiple buffers 28 | backup = false, -- Disable backup file 29 | writebackup = false, -- If a file is being edited by another program (or was written to file while editing with another program), it is not allowed to be edited 30 | swapfile = false, -- Disable swapfile 31 | cmdheight = 2, -- More space in the neovim command line for displaying messages 32 | updatetime = 300, -- Faster completion 33 | timeoutlen = 500, -- Time in milliseconds to wait for a mapped sequence to complete (Assuming you have two mappings: gc and gcc, when you pressed gc and stopped, neovim would wait timeoutlen to see if you want to trigger gc or just in the middle of gcc) 34 | signcolumn = "yes", -- Always show the signcolumn, otherwise it would shift the text each time diagnostics appear/become resolved 35 | showmode = false, -- We don't need the see things like -- INSERT -- anymore 36 | splitbelow = true, -- Horizontal splits will automatically be below 37 | splitright = true, -- Vertical splits will automatically be to the right 38 | clipboard = "unnamedplus", -- Allows neovim to access the system clipboard 39 | guifont = "Hack Nerd Font", -- The font used in graphical neovim applications 40 | mouse = "a", -- Allow the mouse to be used in neovim 41 | cursorline = true, -- Highlight the current line 42 | winborder = "rounded", -- Set the border style for floating windows 43 | completeopt = "menuone,noselect", 44 | background = "dark", 45 | termguicolors = true, -- Set term gui colors 46 | list = true, 47 | colorcolumn = "+0", 48 | foldenable = true, 49 | foldcolumn = "1", 50 | foldlevel = 99, 51 | foldlevelstart = 99, 52 | fillchars = { 53 | eob = icons.fillchars.eob, 54 | fold = icons.fillchars.fold, 55 | foldopen = icons.fillchars.foldopen, 56 | foldsep = icons.fillchars.foldsep, 57 | foldclose = icons.fillchars.foldclose, 58 | }, 59 | listchars = { 60 | tab = icons.listchars.tab, 61 | eol = icons.listchars.eol, 62 | extends = icons.listchars.extends, 63 | precedes = icons.listchars.precedes, 64 | nbsp = icons.listchars.nbsp, 65 | trail = icons.listchars.trail, 66 | }, 67 | } 68 | 69 | function M.setup() 70 | for k, v in pairs(options) do 71 | vim.opt[k] = v 72 | end 73 | 74 | vim.cmd "set shortmess+=c" 75 | vim.cmd "set iskeyword+=-" -- Treat dash separated words as a word text object 76 | end 77 | 78 | return M 79 | -------------------------------------------------------------------------------- /nvim/lua/plugins/nvim-dap.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | local icons = require "icons" 3 | 4 | local M = {} 5 | 6 | local function setup_dap_php() 7 | local dap_status_ok, dap = pcall(require, "dap") 8 | if not dap_status_ok then 9 | return 10 | end 11 | 12 | dap.adapters.php = { 13 | type = "executable", 14 | command = vim.fn.exepath('php-debug-adapter'), 15 | } 16 | 17 | dap.configurations.php = { 18 | { 19 | type = "php", 20 | request = "launch", 21 | name = "Listen for Xdebug", 22 | port = 9003, 23 | pathMappings = { 24 | ["/var/www/html"] = "${workspaceFolder}", 25 | }, 26 | }, 27 | } 28 | end 29 | 30 | local function setup_dap_ruby() 31 | local status_ok, dap_ruby = pcall(require, "dap-ruby") 32 | if not status_ok then 33 | return 34 | end 35 | 36 | dap_ruby.setup() 37 | end 38 | 39 | local function setup_dap_ui() 40 | local dap_status_ok, dap = pcall(require, "dap") 41 | if not dap_status_ok then 42 | return 43 | end 44 | 45 | local dap_ui_status_ok, dapui = pcall(require, "dapui") 46 | if not dap_ui_status_ok then 47 | return 48 | end 49 | 50 | dapui.setup { 51 | controls = { 52 | element = "repl", 53 | enabled = true, 54 | icons = { 55 | disconnect = icons.dap.disconnect, 56 | pause = icons.dap.pause, 57 | play = icons.dap.play, 58 | run_last = icons.dap.run_last, 59 | step_back = icons.dap.step_back, 60 | step_into = icons.dap.step_into, 61 | step_out = icons.dap.step_out, 62 | step_over = icons.dap.step_over, 63 | terminate = icons.dap.terminate, 64 | }, 65 | }, 66 | element_mappings = {}, 67 | expand_lines = false, 68 | floating = { 69 | border = "rounded", 70 | mappings = { 71 | close = { "q", "" }, 72 | }, 73 | }, 74 | force_buffers = true, 75 | icons = { 76 | collapsed = icons.dap.collapsed, 77 | current_frame = icons.dap.current_frame, 78 | expanded = icons.dap.expanded, 79 | }, 80 | layouts = { 81 | { 82 | elements = { 83 | { 84 | id = "breakpoints", 85 | size = 0.25, 86 | }, 87 | { 88 | id = "stacks", 89 | size = 0.25, 90 | }, 91 | { 92 | id = "scopes", 93 | size = 0.5, 94 | }, 95 | }, 96 | position = "right", 97 | size = 100, 98 | }, 99 | { 100 | elements = { { 101 | id = "repl", 102 | size = 1, 103 | } }, 104 | position = "bottom", 105 | size = 15, 106 | }, 107 | }, 108 | mappings = { 109 | edit = "e", 110 | expand = { "" }, 111 | open = "o", 112 | remove = "d", 113 | repl = "r", 114 | toggle = "t", 115 | }, 116 | render = { 117 | indent = 1, 118 | max_value_lines = 100, 119 | }, 120 | } 121 | 122 | dap.listeners.before.attach.dapui_config = function() 123 | dapui.open() 124 | end 125 | dap.listeners.before.launch.dapui_config = function() 126 | dapui.open() 127 | end 128 | dap.listeners.before.event_terminated.dapui_config = function() 129 | dapui.close() 130 | end 131 | dap.listeners.before.event_exited.dapui_config = function() 132 | dapui.close() 133 | end 134 | end 135 | 136 | local function setup_dap() 137 | -- Adapter configuration and installation instructions: 138 | -- https://github.com/mfussenegger/nvim-dap/wiki/Debug-Adapter-installation 139 | local dap_status_ok, dap = pcall(require, "dap") 140 | if not dap_status_ok then 141 | return 142 | end 143 | 144 | vim.fn.sign_define("DapBreakpoint", { 145 | text = icons.dap.breakpoint, 146 | texthl = "DiagnosticSignError", 147 | linehl = "", 148 | numhl = "", 149 | }) 150 | 151 | dap.defaults.fallback.terminal_win_cmd = "50vsplit new" 152 | 153 | local opts = { noremap = false } 154 | 155 | keymaps.set("n", "ds", function() 156 | -- start the debuggere 157 | dap.continue() 158 | end, opts) -- Start 159 | keymaps.set("n", "dq", function() 160 | dap.close() 161 | 162 | local dap_ui_status_ok, dapui = pcall(require, "dapui") 163 | if not dap_ui_status_ok then 164 | return 165 | end 166 | 167 | dapui.close() 168 | end, opts) -- Quit 169 | keymaps.set("n", "dd", "lua require'dap'.disconnect()", opts) -- Disconnect 170 | keymaps.set("n", "dt", "lua require'dap'.toggle_breakpoint()", opts) -- Toogle breakpoint 171 | keymaps.set("n", "dC", "lua require'dap'.run_to_cursor()", opts) -- Run to cursor 172 | keymaps.set("n", "dn", "lua require'dap'.step_over()", opts) -- Step over 173 | keymaps.set("n", "db", "lua require'dap'.step_back()", opts) -- Step back 174 | keymaps.set("n", "di", "lua require'dap'.step_into()", opts) -- Step into 175 | keymaps.set("n", "do", "lua require'dap'.step_out()", opts) -- Step out 176 | keymaps.set("n", "dp", "lua require'dap'.pause.toggle()", opts) -- Pause 177 | keymaps.set("n", "dc", "lua require'dap'.continue()", opts) -- Continue 178 | keymaps.set("n", "dr", "lua require'dap'.session()", opts) -- Get session 179 | keymaps.set("n", "dg", "lua require'dap'.repl.toggle()", opts) -- Toggle repl 180 | end 181 | 182 | M.setup = function() 183 | setup_dap() 184 | setup_dap_ui() 185 | setup_dap_ruby() 186 | setup_dap_php() 187 | end 188 | 189 | return M 190 | -------------------------------------------------------------------------------- /nvim/lua/core/tasks.lua: -------------------------------------------------------------------------------- 1 | local actions = require "telescope.actions" 2 | local action_state = require "telescope.actions.state" 3 | local pickers = require "telescope.pickers" 4 | local finders = require "telescope.finders" 5 | local conf = require("telescope.config").values 6 | local keymaps = require "config.keymaps" 7 | 8 | local M = {} 9 | 10 | local git_tasks = { 11 | { 12 | title = "󰊢 Checkout main branch", 13 | command = "gcm", 14 | type = "vimux", 15 | }, 16 | { 17 | title = "󰊢 Checkout dev branch", 18 | command = "gcd", 19 | type = "vimux", 20 | }, 21 | { 22 | title = "󰊢 Create branch", 23 | command = "gcb", 24 | prompt = "Branch name:", 25 | type = "input", 26 | }, 27 | { 28 | title = "󰊢 Git pull", 29 | command = "ggl", 30 | type = "vimux", 31 | }, 32 | { 33 | title = "󰊢 Git push", 34 | command = "ggp", 35 | type = "vimux", 36 | }, 37 | { 38 | title = "󰊢 Git force push", 39 | command = "ggf", 40 | type = "vimux", 41 | }, 42 | { 43 | title = "󰊢 Git delete local merged branches", 44 | command = "gdlm", 45 | type = "vimux", 46 | }, 47 | } 48 | 49 | local go_tasks = { 50 | { 51 | title = " Start go server", 52 | command = "make up", 53 | type = "vimux", 54 | }, 55 | { 56 | title = "󰍉 Run go lint", 57 | command = "make lint", 58 | type = "vimux", 59 | }, 60 | { 61 | title = "󰍉 Run go test", 62 | command = "make test", 63 | type = "vimux", 64 | }, 65 | { 66 | title = "󰱧 Go mod tidy", 67 | command = "go mod tidy", 68 | type = "vimux", 69 | }, 70 | } 71 | 72 | local php_tasks = { 73 | { 74 | title = " Start php server", 75 | command = "./vendor/bin/sail up", 76 | type = "vimux", 77 | }, 78 | { 79 | title = "󰍉 Run php lint", 80 | command = "./vendor/bin/pint", 81 | type = "vimux", 82 | }, 83 | { 84 | title = "󰈙 Generate php swagger", 85 | command = "./vendor/bin/sail artisan l5-swagger:generate", 86 | type = "vimux", 87 | }, 88 | } 89 | 90 | local common_tasks = { 91 | { 92 | title = "󰱽 Search config file", 93 | command = 'Telescope find_files search_dirs={"~/.config"}', 94 | }, 95 | { 96 | title = "󰅙 Interupt current vimux job", 97 | command = "VimuxInterruptRunner", 98 | }, 99 | { 100 | title = "󰅙 Close vimux pannel", 101 | command = "VimuxCloseRunner", 102 | }, 103 | } 104 | 105 | local file_type_tasks = { 106 | go = go_tasks, 107 | php = php_tasks, 108 | } 109 | 110 | local function run_tasks(tasks, opts) 111 | opts = opts or {} 112 | pickers 113 | .new(opts, { 114 | prompt_title = "Tasks", 115 | finder = finders.new_table { 116 | results = tasks, 117 | entry_maker = function(task) 118 | return { 119 | value = task, 120 | display = task.title, 121 | ordinal = task.title, 122 | } 123 | end, 124 | }, 125 | sorter = conf.generic_sorter(opts), 126 | attach_mappings = function(prompt_bufnr) 127 | actions.select_default:replace(function() 128 | actions.close(prompt_bufnr) 129 | local selection = action_state.get_selected_entry() 130 | local selection_value = selection.value 131 | local command = selection_value.command 132 | if command then 133 | local type = selection_value.type 134 | if type == "vimux" then 135 | vim.cmd("VimuxRunCommand " .. '"' .. command .. '"') 136 | elseif type == "input" then 137 | local prompt = "Input:" 138 | if selection_value.prompt then 139 | prompt = selection_value.prompt 140 | end 141 | 142 | require("core.float_input").input(function(input) 143 | local cmd = command .. " " .. input 144 | vim.cmd("VimuxRunCommand " .. '"' .. cmd .. '"') 145 | end, { 146 | prompt = prompt, 147 | }) 148 | else 149 | vim.cmd(command) 150 | end 151 | end 152 | end) 153 | 154 | return true 155 | end, 156 | }) 157 | :find() 158 | end 159 | 160 | function M.setup() 161 | keymaps.set("n", "rr", function() 162 | require("core.float_input").input(function(input) 163 | vim.cmd("VimuxRunCommand " .. '"' .. input .. '"') 164 | end, { 165 | prompt = "Command:", 166 | }) 167 | end) 168 | 169 | keymaps.set("n", "r.", ":VimuxRunLastCommand") 170 | 171 | keymaps.set("n", "rq", ":VimuxInterruptRunner") 172 | 173 | keymaps.set("n", "c", ":VimuxCloseRunner") 174 | 175 | keymaps.set("n", "rt", function() 176 | -- get current file type 177 | local file_type = vim.bo.filetype 178 | local tasks = file_type_tasks[file_type] or {} 179 | 180 | run_tasks(tasks, require("telescope.themes").get_dropdown {}) 181 | end) 182 | 183 | keymaps.set("n", "rc", function() 184 | run_tasks(common_tasks, require("telescope.themes").get_dropdown {}) 185 | end) 186 | 187 | keymaps.set("n", "rg", function() 188 | run_tasks(git_tasks, require("telescope.themes").get_dropdown {}) 189 | end) 190 | 191 | keymaps.set("n", "ra", function() 192 | -- get all tasks from all file types 193 | local tasks = {} 194 | for _, file_type_task in pairs(file_type_tasks) do 195 | for _, task in pairs(file_type_task) do 196 | table.insert(tasks, task) 197 | end 198 | end 199 | 200 | -- get all common tasks 201 | for _, task in pairs(common_tasks) do 202 | table.insert(tasks, task) 203 | end 204 | 205 | run_tasks(tasks, require("telescope.themes").get_dropdown {}) 206 | end) 207 | end 208 | 209 | return M 210 | -------------------------------------------------------------------------------- /nvim/lua/plugins/barbar.lua: -------------------------------------------------------------------------------- 1 | local keymaps = require "config.keymaps" 2 | local icons = require "icons" 3 | 4 | local M = {} 5 | 6 | M.setup = function() 7 | keymaps.set("n", "$", ":BufferPrevious", { noremap = true, silent = true }) 8 | keymaps.set("n", "~", ":BufferNext", { noremap = true, silent = true }) 9 | 10 | keymaps.set("n", "1", ":BufferGoto 1", { noremap = true, silent = true }) 11 | keymaps.set("n", "2", ":BufferGoto 2", { noremap = true, silent = true }) 12 | keymaps.set("n", "3", ":BufferGoto 3", { noremap = true, silent = true }) 13 | keymaps.set("n", "4", ":BufferGoto 4", { noremap = true, silent = true }) 14 | keymaps.set("n", "5", ":BufferGoto 5", { noremap = true, silent = true }) 15 | keymaps.set("n", "6", ":BufferGoto 6", { noremap = true, silent = true }) 16 | keymaps.set("n", "7", ":BufferGoto 7", { noremap = true, silent = true }) 17 | keymaps.set("n", "8", ":BufferGoto 8", { noremap = true, silent = true }) 18 | keymaps.set("n", "9", ":BufferGoto 9", { noremap = true, silent = true }) 19 | keymaps.set("n", "0", ":BufferLast", { noremap = true, silent = true }) 20 | 21 | keymaps.set("n", "w", ":BufferClose", { noremap = true, silent = true }) 22 | keymaps.set("n", "x", ":BufferCloseAllButCurrent", { noremap = true, silent = true }) 23 | 24 | keymaps.set("n", "bb", ":BufferPin", { noremap = true, silent = true }) 25 | 26 | -- Set barbar's options 27 | require("barbar").setup { 28 | -- Enable/disable animations 29 | animation = false, 30 | 31 | -- Enable/disable auto-hiding the tab bar when there is a single buffer 32 | auto_hide = false, 33 | 34 | -- Enable/disable current/total tabpages indicator (top right corner) 35 | tabpages = true, 36 | 37 | -- Enables/disable clickable tabs 38 | -- - left-click: go to buffer 39 | -- - middle-click: delete buffer 40 | clickable = false, 41 | 42 | -- Excludes buffers from the tabline 43 | exclude_ft = {}, 44 | exclude_name = {}, 45 | 46 | -- -- A buffer to this direction will be focused (if it exists) when closing the current buffer. 47 | -- -- Valid options are 'left' (the default) and 'right' 48 | focus_on_close = "left", 49 | 50 | -- -- Hide inactive buffers and file extensions. Other options are `alternate`, `current`, and `visible`. 51 | -- hide = { extensions = true, inactive = true }, 52 | 53 | -- Disable highlighting alternate buffers 54 | highlight_alternate = false, 55 | 56 | -- Disable highlighting file icons in inactive buffers 57 | highlight_inactive_file_icons = false, 58 | 59 | -- Enable highlighting visible buffers 60 | highlight_visible = false, 61 | 62 | icons = { 63 | -- Configure the base icons on the bufferline. 64 | buffer_index = true, 65 | buffer_number = false, 66 | button = icons.barbar.active_button, 67 | -- Enables / disables diagnostic symbols 68 | diagnostics = { 69 | [vim.diagnostic.severity.ERROR] = { enabled = false }, 70 | [vim.diagnostic.severity.WARN] = { enabled = false }, 71 | [vim.diagnostic.severity.INFO] = { enabled = false }, 72 | [vim.diagnostic.severity.HINT] = { enabled = false }, 73 | }, 74 | filetype = { 75 | -- Sets the icon's highlight group. 76 | -- If false, will use nvim-web-devicons colors 77 | custom_colors = false, 78 | 79 | -- Requires `nvim-web-devicons` if `true` 80 | enabled = true, 81 | }, 82 | separator = { left = icons.barbar.separator_left, right = "" }, 83 | 84 | -- Configure the icons on the bufferline when modified or pinned. 85 | -- Supports all the base icon options. 86 | modified = { button = icons.barbar.modified_button }, 87 | pinned = { button = icons.barbar.pinned_button }, 88 | 89 | -- Configure the icons on the bufferline based on the visibility of a buffer. 90 | -- Supports all the base icon options, plus `modified` and `pinned`. 91 | alternate = { filetype = { enabled = false } }, 92 | current = { buffer_index = true }, 93 | inactive = { button = icons.barbar.inactive_button }, 94 | visible = { modified = { buffer_number = false } }, 95 | }, 96 | 97 | -- If true, new buffers will be inserted at the start/end of the list. 98 | -- Default is to insert after current buffer. 99 | insert_at_end = false, 100 | insert_at_start = false, 101 | 102 | -- Sets the maximum padding width with which to surround each tab 103 | maximum_padding = 1, 104 | 105 | -- Sets the minimum padding width with which to surround each tab 106 | minimum_padding = 1, 107 | 108 | -- Sets the maximum buffer name length. 109 | maximum_length = 30, 110 | 111 | -- If set, the letters for each buffer in buffer-pick mode will be 112 | -- assigned based on their name. Otherwise or in case all letters are 113 | -- already assigned, the behavior is to assign letters in order of 114 | -- usability (see order below) 115 | semantic_letters = true, 116 | 117 | -- Set the filetypes which barbar will offset itself for 118 | sidebar_filetypes = { 119 | -- Use the default values: {event = 'BufWinLeave', text = nil} 120 | NvimTree = true, 121 | -- Or, specify the text used for the offset: 122 | undotree = { text = "undotree" }, 123 | -- Or, specify the event which the sidebar executes when leaving: 124 | ["neo-tree"] = { event = "BufWipeout" }, 125 | -- Or, specify both 126 | Outline = { event = "BufWinLeave", text = "symbols-outline" }, 127 | }, 128 | 129 | -- New buffer letters are assigned in this order. This order is 130 | -- optimal for the qwerty keyboard layout but might need adjustement 131 | -- for other layouts. 132 | letters = "asdfjkl;ghnmxcvbziowerutyqpASDFJKLGHNMXCVBZIOWERUTYQP", 133 | 134 | -- Sets the name of unnamed buffers. By default format is "[Buffer X]" 135 | -- where X is the buffer number. But only a static string is accepted here. 136 | no_name_title = nil, 137 | } 138 | end 139 | 140 | return M 141 | -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | DOTFILES=$(pwd -P) 4 | 5 | set -e 6 | 7 | echo '' 8 | 9 | info() { 10 | printf "\r [ \033[00;34m..\033[0m ] %s\n" "$1" 11 | } 12 | 13 | user() { 14 | printf "\r [ \033[0;33m??\033[0m ] %s\n" "$1" 15 | } 16 | 17 | success() { 18 | printf "\r\033[2K [ \033[00;32mOK\033[0m ] %s\n" "$1" 19 | } 20 | 21 | fail() { 22 | printf "\r\033[2K [\033[0;31mFAIL\033[0m] %s\n" "$1" 23 | echo '' 24 | exit 25 | } 26 | 27 | link_file() { 28 | local src=$1 dst=$2 29 | 30 | local overwrite= 31 | local backup= 32 | local skip= 33 | local action= 34 | 35 | if [ -f "$dst" ] || [ -d "$dst" ] || [ -L "$dst" ]; then 36 | 37 | if [ "$overwrite_all" == "false" ] && [ "$backup_all" == "false" ] && [ "$skip_all" == "false" ]; then 38 | 39 | # ignoring exit 1 from readlink in case where file already exists 40 | # shellcheck disable=SC2155 41 | local currentSrc="$(readlink "$dst")" 42 | 43 | if [ "$currentSrc" == "$src" ]; then 44 | 45 | skip=true 46 | 47 | else 48 | 49 | user "File already exists: $dst ($(basename "$src")), what do you want to do?\n\ 50 | [s]kip, [S]kip all, [o]verwrite, [O]verwrite all, [b]ackup, [B]ackup all?" 51 | read -n 1 action /dev/null; then 106 | info "Installing homebrew" 107 | /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" 108 | else 109 | info "Updating homebrew" 110 | brew update 111 | brew upgrade 112 | fi 113 | 114 | info "Installing homebrew packages" 115 | brew bundle --file "$DOTFILES/brew/Brewfile" 116 | } 117 | 118 | install_zsh() { 119 | if [ ! -d "$HOME/.oh-my-zsh" ]; then 120 | info "Installing oh-my-zsh" 121 | sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" 122 | fi 123 | 124 | if [ ! -f "$HOME/.oh-my-zsh/antigen.zsh" ]; then 125 | info "Installing antigen" 126 | curl -L git.io/antigen >"$HOME/.oh-my-zsh/antigen.zsh" 127 | fi 128 | } 129 | 130 | install_tmux_plugin_manager() { 131 | if [ ! -d "$HOME/.tmux/plugins" ]; then 132 | info "Installing tmux plugin manager" 133 | mkdir -p "$HOME/.tmux/plugins" 134 | git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm 135 | fi 136 | } 137 | 138 | install_dotfiles() { 139 | info 'Installing dotfiles' 140 | 141 | local overwrite_all=false backup_all=false skip_all=false 142 | 143 | mkdir -p "$HOME/.config" 144 | 145 | # nvim 146 | mkdir -p "$HOME/.config/nvim" 147 | link_file "$DOTFILES/nvim" "$HOME/.config/nvim" 148 | 149 | # alacritty 150 | link_file "$DOTFILES/alacritty/alacritty.toml" "$HOME/.config/alacritty.toml" 151 | link_file "$DOTFILES/alacritty/alacritty-popup.yml" "$HOME/.config/alacritty-popup.yml" 152 | 153 | # tmux 154 | link_file "$DOTFILES/tmux/tmux.conf" "$HOME/.tmux.conf" 155 | 156 | # zsh 157 | link_file "$DOTFILES/zsh/zshrc" "$HOME/.zshrc" 158 | 159 | # karabiner 160 | link_file "$DOTFILES/karabiner/karabiner.edn" "$HOME/.config/karabiner.edn" 161 | 162 | # aerospace 163 | mkdir -p "$HOME/.config/aerospace" 164 | link_file "$DOTFILES/aerospace/aerospace.toml" "$HOME/.config/aerospace/aerospace.toml" 165 | link_file "$DOTFILES/aerospace/notification.sh" "$HOME/.config/aerospace/notification.sh" 166 | 167 | # borders 168 | mkdir -p "$HOME/.config/borders" 169 | link_file "$DOTFILES/borders/bordersrc" "$HOME/.config/borders/bordersrc" 170 | 171 | # starship 172 | link_file "$DOTFILES/starship/starship.toml" "$HOME/.config/starship.toml" 173 | 174 | # neofetch 175 | mkdir -p "$HOME/.config/neofetch" 176 | link_file "$DOTFILES/neofetch/config.conf" "$HOME/.config/neofetch/config.conf" 177 | 178 | # sketchybar 179 | link_file "$DOTFILES/sketchybar" "$HOME/.config/sketchybar" 180 | 181 | # taskwarrior 182 | mkdir -p "$HOME/.config/task" 183 | link_file "$DOTFILES/task/taskrc" "$HOME/.config/task/taskrc" 184 | 185 | # git 186 | link_file "$DOTFILES/git/gitconfig" "$HOME/.gitconfig" 187 | link_file "$DOTFILES/git/gitignore" "$HOME/.gitignore" 188 | 189 | # navi 190 | link_file "$DOTFILES/navi" "$HOME/.config/navi" 191 | 192 | # mise 193 | link_file "$DOTFILES/mise/config.toml" "$HOME/.config/mise/config.toml" 194 | 195 | # fm 196 | link_file "$DOTFILES/fm/config.lua" "$HOME/.config/fm/config.lua" 197 | 198 | # warpd 199 | link_file "$DOTFILES/warpd/config" "$HOME/.config/warpd/config" 200 | 201 | # AI 202 | link_file "$DOTFILES/ai/mcp.json" "$HOME/.config/mcphub/mcp.json" 203 | link_file "$DOTFILES/ai/CLAUDE.md" "$HOME/.claude/CLAUDE.md" 204 | link_file "$DOTFILES/ai/commands/gemini/commit.toml" "$HOME/.gemini/commands/commit.toml" 205 | link_file "$DOTFILES/ai/commands/gemini/review.toml" "$HOME/.gemini/commands/review.toml" 206 | 207 | # docker 208 | link_file "$DOTFILES/docker/config.json" "$HOME/.docker/config.json" 209 | } 210 | 211 | create_cmds_file() { 212 | info "Creating cmds file" 213 | 214 | touch "$HOME/.cmds" 215 | { 216 | echo 'say "test speaker"' 217 | echo 'calcurse' 218 | echo 'ping google.com' 219 | echo 'nvim -u NONE ~/.cmds' 220 | echo 'brew services restart sketchybar' 221 | } >"$HOME/.cmds" 222 | } 223 | 224 | install_zsh 225 | install_tmux_plugin_manager 226 | install_dotfiles 227 | create_cmds_file 228 | install_homebrew 229 | 230 | success 'All installed!' 231 | 232 | # brew services start borders 233 | # brew services start sketchybar 234 | # brew services start colima 235 | # go install github.com/dinhhuy258/fm@latest 236 | # curl -L https://github.com/rvaiya/warpd/releases/download/v1.3.5/warpd-1.3.5-osx.tar.gz | sudo tar xzvfC - / && launchctl load /Library/LaunchAgents/com.warpd.warpd.plist 237 | -------------------------------------------------------------------------------- /tmux/tmux.conf: -------------------------------------------------------------------------------- 1 | #================================================================================# 2 | # Plugins # 3 | #================================================================================# 4 | 5 | # Install tmp if not exists 6 | if "test ! -d ~/.tmux/plugins/tpm" \ 7 | "run 'git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpm && ~/.tmux/plugins/tpm/bin/install_plugins'" 8 | 9 | # Tmux plugin manager 10 | set -g @plugin 'tmux-plugins/tpm' 11 | # Quickly open any url 12 | set -g @plugin 'tmux-plugins/tmux-urlview' 13 | # Easy jump 14 | set -g @plugin 'schasse/tmux-jump' 15 | # Persists tmux environment across system restarts. 16 | set -g @plugin 'tmux-plugins/tmux-resurrect' 17 | 18 | #================================================================================# 19 | # Settings # 20 | #================================================================================# 21 | 22 | # Change prefix key from C-b to C-f 23 | unbind C-b 24 | set -g prefix C-f 25 | bind C-f send-prefix 26 | 27 | # Enable 256 colors in the terminal emulator 28 | set -g default-terminal "screen-256color" 29 | set-option -sa terminal-overrides ",xterm-256color:Tc:RGB:xterm*:smcup@:rmcup@" 30 | 31 | # Set first window/ pane to index 1 32 | set -g base-index 1 33 | set -g pane-base-index 1 34 | 35 | # Renumber windows when a window is closed 36 | set -g renumber-windows on 37 | 38 | # Allow rename window automatically 39 | setw -g automatic-rename on 40 | 41 | # Rename window to reflect current folder 42 | set-option -g automatic-rename-format '#{b:pane_current_path}' 43 | 44 | # Increase the scrollback history limit to make Tmux panes remember more lines 45 | set -g history-limit 10000 46 | 47 | # Monitor window activity. Windows with activity are highlighted in the status line 48 | setw -g monitor-activity on 49 | 50 | # Prevent Tmux from displaying the annoying Activity in window X messages 51 | set -g visual-activity off 52 | 53 | # Pass xterm-style keys to make many key combinations work as expected 54 | setw -g xterm-keys on 55 | 56 | # Disable the delay between an escape key press and subsequent characters. This increases Vim responsiveness 57 | set -sg escape-time 0 58 | 59 | # Increase repeat timeout 60 | set -sg repeat-time 600 61 | 62 | # Enable vi-style keys instead of the default emacs-style keys 63 | setw -g mode-keys vi 64 | set -g status-keys vi 65 | 66 | # Enable mouse mode 67 | set -g mouse on 68 | 69 | # Enable focus events 70 | set -g focus-events on 71 | 72 | #================================================================================# 73 | # UI # 74 | #================================================================================# 75 | 76 | set -g status "on" 77 | set -g status-justify "left" 78 | set -g status-position "bottom" 79 | set -g status-style "fg=#9ece6a,bg=#1a1b26" 80 | 81 | set -g status-left "" 82 | set -g status-left-style NONE 83 | set -g status-left-style "" 84 | set -g status-left-length "25" 85 | 86 | set -g status-right "" 87 | set -g status-right-style NONE 88 | set -g status-right-length "25" 89 | 90 | setw -g window-status-separator "" 91 | setw -g window-status-activity-style "fg=#a9b1d6,bg=#1a1b26" 92 | setw -g window-status-style "NONE,fg=#a9b1d6,bg=#1a1b26" 93 | setw -g window-status-format "#[default] #I #W " 94 | setw -g window-status-current-format "#[fg=#9ece6a,bold] #I #W " 95 | 96 | set -g mode-style "fg=#9ece6a,bg=#3b4261" 97 | 98 | set -g message-style "fg=#9ece6a,bg=#1a1b26" 99 | set -g message-command-style "fg=#9ece6a,bg=#1a1b26" 100 | 101 | # Set pane border 102 | set -g pane-border-style "fg=#3b4261" 103 | set -g pane-active-border-style "fg=#9ece6a" 104 | 105 | #================================================================================# 106 | # Key bindings # 107 | #================================================================================# 108 | 109 | # Reload tmux config 110 | bind r source-file ~/.tmux.conf \; display "Reloaded tmux configuration" 111 | 112 | # Copy mode 113 | bind j copy-mode 114 | bind -T copy-mode-vi v send -X begin-selection 115 | bind -T copy-mode-vi y send-keys -X copy-pipe "pbcopy" 116 | bind -T copy-mode-vi enter send-keys -X copy-pipe-and-cancel "pbcopy" 117 | bind -T copy-mode-vi escape send-keys -X cancel 118 | bind -T copy-mode-vi q send-keys -X clear-selection 119 | 120 | # Vertical splits 121 | bind g split-window -h -c "#{pane_current_path}" 122 | 123 | # Horizontal splits 124 | bind v split-window -v -c "#{pane_current_path}" 125 | 126 | # Pane navigation 127 | is_vim="ps -o state= -o comm= -t '#{pane_tty}' | grep -iqE '^[^TXZ ]+ +(\\S+\\/)?g?(view|n?vim?x?)(diff)?$'" 128 | 129 | bind-key -n 'C-h' if-shell "$is_vim" 'send-keys C-h' { if -F '#{pane_at_left}' '' 'select-pane -L' } 130 | bind-key -n 'C-j' if-shell "$is_vim" 'send-keys C-j' { if -F '#{pane_at_bottom}' '' 'select-pane -D' } 131 | bind-key -n 'C-k' if-shell "$is_vim" 'send-keys C-k' { if -F '#{pane_at_top}' '' 'select-pane -U' } 132 | bind-key -n 'C-l' if-shell "$is_vim" 'send-keys C-l' { if -F '#{pane_at_right}' '' 'select-pane -R' } 133 | 134 | bind-key -T copy-mode-vi 'C-h' if -F '#{pane_at_left}' '' 'select-pane -L' 135 | bind-key -T copy-mode-vi 'C-j' if -F '#{pane_at_bottom}' '' 'select-pane -D' 136 | bind-key -T copy-mode-vi 'C-k' if -F '#{pane_at_top}' '' 'select-pane -U' 137 | bind-key -T copy-mode-vi 'C-l' if -F '#{pane_at_right}' '' 'select-pane -R' 138 | 139 | # Pane resizing 140 | bind -n 'M-h' if-shell "$is_vim" 'send-keys M-h' 'resize-pane -L 3' 141 | bind -n 'M-j' if-shell "$is_vim" 'send-keys M-j' 'resize-pane -D 3' 142 | bind -n 'M-k' if-shell "$is_vim" 'send-keys M-k' 'resize-pane -U 3' 143 | bind -n 'M-l' if-shell "$is_vim" 'send-keys M-l' 'resize-pane -R 3' 144 | 145 | bind-key -T copy-mode-vi M-h resize-pane -L 3 146 | bind-key -T copy-mode-vi M-j resize-pane -D 3 147 | bind-key -T copy-mode-vi M-k resize-pane -U 3 148 | bind-key -T copy-mode-vi M-l resize-pane -R 3 149 | 150 | bind d swap-pane -D 151 | bind s swap-pane -U 152 | 153 | # Windows 154 | bind t new-window -c "#{pane_current_path}" 155 | bind w kill-pane 156 | bind -r H previous-window 157 | bind -r L next-window 158 | 159 | # Move windows left/right 160 | bind z swap-window -t -1\; select-window -t -1 161 | bind b swap-window -t +1\; select-window -t +1 162 | 163 | # tmux-resurrect 164 | set -g @resurrect-save 'y' 165 | set -g @resurrect-restore 'p' 166 | 167 | # tmux-jump 168 | set -g @jump-key 'k' 169 | 170 | # tmux-urlview 171 | set -g @urlview-key 'l' 172 | 173 | # navi - unified keybinding with SSH detection 174 | bind-key -T prefix C-g if-shell \ 175 | "test \"$(tmux display-message -p '#{pane_current_command}')\" = \"ssh\"" \ 176 | "split-window \"$SHELL --login -i -c 'navi --print | head -n 1 | tmux load-buffer -b tmp - ; tmux paste-buffer -p -t {last} -b tmp -d'\"" \ 177 | "send-keys C-a" 178 | 179 | #================================================================================# 180 | # Commands # 181 | #================================================================================# 182 | 183 | set-environment -g PATH "/usr/local/bin:/bin:/usr/bin" 184 | set-environment -g PATH "/opt/homebrew/bin:/usr/local/bin:/bin:/usr/bin" 185 | run -b '~/.tmux/plugins/tpm/tpm' 186 | -------------------------------------------------------------------------------- /nvim/lua/core/statusline.lua: -------------------------------------------------------------------------------- 1 | local icons = require "icons" 2 | 3 | local M = {} 4 | 5 | local special_buftypes = { 6 | terminal = { 7 | name = "Terminal", 8 | icon = icons.statusline.buftype.terminal, 9 | show_section_right = false, 10 | }, 11 | } 12 | 13 | local float_filetypes = { 14 | fzf = "fzf", 15 | floaterm = "floaterm", 16 | } 17 | 18 | local float_buftypes = { 19 | terminal = "terminal", 20 | } 21 | 22 | local special_filetypes = { 23 | sfm = { 24 | name = "File explorer", 25 | icon = icons.statusline.filetype.sfm, 26 | show_section_right = false, 27 | }, 28 | fzf = { 29 | name = "fzf", 30 | icon = icons.statusline.filetype.fzf, 31 | show_section_right = false, 32 | }, 33 | VimDatabase = { 34 | name = "Database", 35 | icon = icons.statusline.filetype.VimDatabase, 36 | show_section_right = true, 37 | }, 38 | ["git.nvim"] = { 39 | name = "Git", 40 | icon = icons.statusline.filetype["git.nvim"], 41 | show_section_right = false, 42 | }, 43 | diff = { 44 | name = "diff", 45 | icon = icons.statusline.filetype.diff, 46 | show_section_right = false, 47 | }, 48 | floaterm = { 49 | name = "Terminal", 50 | icon = icons.statusline.filetype.floaterm, 51 | show_section_right = false, 52 | }, 53 | startify = { 54 | name = "Startify", 55 | icon = icons.statusline.filetype.startify, 56 | show_section_right = true, 57 | }, 58 | help = { 59 | name = "Help", 60 | icon = icons.statusline.filetype.help, 61 | show_section_right = true, 62 | }, 63 | } 64 | 65 | local function buffer_is_empty() 66 | if vim.fn.empty(vim.fn.expand "%:t") ~= 1 then 67 | return false 68 | end 69 | return true 70 | end 71 | 72 | local function line_column_provider() 73 | local line = vim.fn.line "." 74 | local column = vim.fn.col "." 75 | return string.format("%3d :%2d", line, column) 76 | end 77 | 78 | local function separator_provider(separator) 79 | return separator 80 | end 81 | 82 | local function file_info_provider(buf, active) 83 | if buffer_is_empty() then 84 | return "" 85 | end 86 | 87 | local filename = vim.api.nvim_buf_get_name(buf) 88 | local f_name = vim.fn.fnamemodify(filename, ":~:.") 89 | 90 | local ok, devicons = pcall(require, "nvim-web-devicons") 91 | if not ok then 92 | return filename 93 | end 94 | 95 | local icon, icon_hl = devicons.get_icon(vim.fn.fnamemodify(filename, "%:t"), vim.fn.fnamemodify(filename, ":e")) 96 | 97 | if icon == nil then 98 | icon = icons.statusline.file.default .. " " 99 | else 100 | vim.cmd("hi StatuslineFileIcon guibg=NONE" .. " guifg=" .. vim.fn.synIDattr(vim.fn.hlID(icon_hl), "fg")) 101 | icon = "%#StatuslineFileIcon#" .. icon 102 | 103 | if active then 104 | icon = icon .. "%#StatusLine#" 105 | else 106 | icon = icon .. "%#StatusLineNC#" 107 | end 108 | end 109 | 110 | return icon .. " " .. f_name 111 | end 112 | 113 | local function special_filetype_provider(special_filetype) 114 | return special_filetype.icon .. " " .. special_filetype.name 115 | end 116 | 117 | local function git_branch_provider() 118 | local gsd = vim.b.gitsigns_status_dict 119 | 120 | if gsd and gsd.head and #gsd.head > 0 then 121 | return icons.statusline.git.branch .. " " .. gsd.head .. " | " 122 | end 123 | 124 | return "" 125 | end 126 | 127 | local function line_percent_provider() 128 | local current_line = vim.fn.line "." 129 | local total_line = vim.fn.line "$" 130 | if current_line == 1 then 131 | return " Top " 132 | elseif current_line == vim.fn.line "$" then 133 | return " Bot " 134 | end 135 | local result, _ = math.modf((current_line / total_line) * 100) 136 | return " " .. result .. "%% " 137 | end 138 | 139 | local function generate_statusline(winid, force_inactive) 140 | local statusline = "" 141 | local buf = vim.api.nvim_win_get_buf(winid) 142 | local active_win = vim.api.nvim_get_current_win() 143 | local active = winid == active_win 144 | if force_inactive == true then 145 | active = false 146 | end 147 | 148 | local current_ft = vim.api.nvim_buf_get_option(vim.api.nvim_win_get_buf(active_win), "ft") 149 | local current_bt = vim.api.nvim_buf_get_option(vim.api.nvim_win_get_buf(active_win), "bt") 150 | 151 | if (float_filetypes[current_ft] ~= nil or float_buftypes[current_bt]) and not active then 152 | return statusline 153 | end 154 | 155 | local special_filetype = special_filetypes[vim.api.nvim_buf_get_option(buf, "ft")] 156 | local special_buftype = special_buftypes[vim.api.nvim_buf_get_option(buf, "bt")] 157 | 158 | if active then 159 | statusline = "%#StatusLine#" 160 | else 161 | statusline = "%#StatusLineNC#" 162 | end 163 | 164 | -- Section left 165 | statusline = statusline .. separator_provider " " 166 | 167 | if special_filetype then 168 | statusline = statusline .. special_filetype_provider(special_filetype) 169 | 170 | if not special_filetype.show_section_right then 171 | return statusline 172 | end 173 | elseif special_buftype then 174 | statusline = statusline .. special_filetype_provider(special_buftype) 175 | 176 | if not special_buftype.show_section_right then 177 | return statusline 178 | end 179 | else 180 | statusline = statusline .. file_info_provider(buf, active) 181 | end 182 | 183 | if not active then 184 | return statusline 185 | end 186 | 187 | -- Section right 188 | statusline = statusline .. "%=" 189 | statusline = statusline .. git_branch_provider() 190 | statusline = statusline .. line_column_provider() 191 | statusline = statusline .. separator_provider " |" 192 | statusline = statusline .. line_percent_provider() 193 | 194 | return statusline 195 | end 196 | 197 | local function create_augroup(autocmds, name) 198 | vim.cmd("augroup " .. name) 199 | vim.cmd "autocmd!" 200 | 201 | for _, autocmd in ipairs(autocmds) do 202 | vim.cmd("autocmd " .. table.concat(autocmd, " ")) 203 | end 204 | 205 | vim.cmd "augroup END" 206 | end 207 | 208 | function M.statusline() 209 | return generate_statusline(vim.api.nvim_get_current_win(), false) 210 | end 211 | 212 | function M.update_active_window(force_inactive) 213 | if not force_inactive then 214 | vim.o.statusline = "%!v:lua.require'core.statusline'.statusline()" 215 | else 216 | local winid = vim.api.nvim_get_current_win() 217 | vim.wo[winid].statusline = generate_statusline(vim.api.nvim_get_current_win(), force_inactive) 218 | end 219 | end 220 | 221 | -- Update statusline of inactive windows on the current tabpage 222 | function M.update_inactive_windows() 223 | -- Uses vim.schedule to defer executing the function until after 224 | -- all other autocommands have run. This will ensure that inactive windows 225 | -- are updated after any changes. 226 | vim.schedule(function() 227 | local current_win = vim.api.nvim_get_current_win() 228 | 229 | for _, winid in ipairs(vim.api.nvim_tabpage_list_wins(0)) do 230 | if vim.api.nvim_win_get_config(winid).relative == "" and winid ~= current_win then 231 | vim.wo[winid].statusline = generate_statusline(winid, false) 232 | end 233 | end 234 | 235 | -- Reset local statusline of current window to use the global statusline for it 236 | vim.wo.statusline = nil 237 | end) 238 | end 239 | 240 | function M.setup() 241 | -- Ensures custom quickfix statusline isn't loaded 242 | vim.g.qf_disable_statusline = true 243 | vim.o.statusline = "%!v:lua.require'core.statusline'.statusline()" 244 | 245 | create_augroup({ 246 | { 247 | "VimEnter,WinEnter,WinClosed,FileChangedShellPost", 248 | "*", 249 | "lua require'core.statusline'.update_inactive_windows()", 250 | }, 251 | { 252 | "FocusGained", 253 | "*", 254 | "lua require'core.statusline'.update_active_window(false)", 255 | }, 256 | { 257 | "FocusLost", 258 | "*", 259 | "lua require'core.statusline'.update_active_window(true)", 260 | }, 261 | }, "core.statusline") 262 | end 263 | 264 | return M 265 | -------------------------------------------------------------------------------- /sketchybar/sketchybarrc: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # Colors 4 | BACKGROUND=0xff1a1b26 5 | FOREGROUND=0xffc0caf5 6 | BLACK=0xff15161E 7 | RED=0xfff7768e 8 | GREEN=0xff9ece6a 9 | YELLOW=0xffe0af68 10 | BLUE=0xff7aa2f7 11 | MAGENTA=0xffbb9af7 12 | CYAN=0xff7dcfff 13 | WHITE=0xffa9b1d6 14 | 15 | BAR_COLOR=$BACKGROUND 16 | ICON_COLOR=$WHITE 17 | LABEL_COLOR=$WHITE 18 | POPUP_BACKGROUND_COLOR=$BLACK 19 | POPUP_BORDER_COLOR=$GREEN 20 | SHADOW_COLOR=$BLACK 21 | 22 | PLUGIN_DIR="$HOME/.config/sketchybar/plugins" # Directory where all the plugin scripts are stored 23 | 24 | FONT="FiraCode Nerd Font" # Needs to have Regular, Bold, Semibold, Heavy and Black variants 25 | 26 | PADDINGS=3 # All paddings use this value (icon, label, background and bar paddings) 27 | SEGMENT_SPACING=13 # The spacing between segments 28 | 29 | POPUP_BORDER_WIDTH=2 30 | POPUP_CORNER_RADIUS=3 31 | 32 | SHADOW=on 33 | SHADOW_DISTANCE=3 34 | SHADOW_ANGLE=35 35 | 36 | # Setting up the general bar appearance and default values 37 | sketchybar --bar height=32 \ 38 | corner_radius=0 \ 39 | border_width=0 \ 40 | margin=-200 \ 41 | blur_radius=0 \ 42 | position=top \ 43 | padding_left=4 \ 44 | padding_right=4 \ 45 | color=$BAR_COLOR \ 46 | topmost=off \ 47 | font_smoothing=off \ 48 | y_offset=-32 \ 49 | shadow=off \ 50 | notch_width=0 \ 51 | \ 52 | --default drawing=on \ 53 | updates=when_shown \ 54 | label.font="$FONT:Regular:13.0" \ 55 | icon.font="$FONT:Bold:14.0" \ 56 | icon.color=$ICON_COLOR \ 57 | label.color=$LABEL_COLOR \ 58 | icon.padding_left=$PADDINGS \ 59 | icon.padding_right=$PADDINGS \ 60 | label.padding_left=$PADDINGS \ 61 | label.padding_right=$PADDINGS \ 62 | background.padding_right=$PADDINGS \ 63 | background.padding_left=$PADDINGS \ 64 | popup.background.border_width=$POPUP_BORDER_WIDTH \ 65 | popup.background.corner_radius=$POPUP_CORNER_RADIUS \ 66 | popup.background.border_color=$POPUP_BORDER_COLOR \ 67 | popup.background.color=$POPUP_BACKGROUND_COLOR \ 68 | popup.background.shadow.drawing=$SHADOW \ 69 | icon.shadow.color=$SHADOW_COLOR \ 70 | icon.shadow.distance=$SHADOW_DISTANCE \ 71 | icon.shadow.angle=$SHADOW_ANGLE \ 72 | icon.shadow.drawing=$SHADOW \ 73 | label.shadow.color=$SHADOW_COLOR \ 74 | label.shadow.distance=$SHADOW_DISTANCE \ 75 | label.shadow.angle=$SHADOW_ANGLE \ 76 | label.shadow.drawing=$SHADOW 77 | 78 | sketchybar --add item apple.logo left \ 79 | --set apple.logo icon= \ 80 | label.drawing=off \ 81 | icon.font="$FONT:BOLD:16.0" \ 82 | icon.y_offset=2 83 | 84 | sketchybar --add event input_source_change AppleSelectedInputSourcesChangedNotification 85 | sketchybar --add item input_source left \ 86 | --set input_source script="$PLUGIN_DIR/input_source.sh" \ 87 | icon.font="$FONT:BOLD:18.0" \ 88 | icon.y_offset=0 \ 89 | label.drawing=off \ 90 | --subscribe input_source input_source_change 91 | 92 | sketchybar --add item slack left \ 93 | --set slack \ 94 | update_freq=180 \ 95 | script="$PLUGIN_DIR/slack.sh" \ 96 | icon.font="$FONT:BOLD:16.0" \ 97 | --subscribe slack system_woke 98 | 99 | sketchybar --add item task left \ 100 | --set task script="$PLUGIN_DIR/task.sh" \ 101 | update_freq=120 \ 102 | background.border_width=0 \ 103 | icon.font="$FONT:BOLD:16.0" 104 | 105 | sketchybar --add item application center \ 106 | --set application script="sketchybar --set \$NAME label=\"\$INFO\"" \ 107 | label.font="$FONT:BOLD:14.0" \ 108 | --subscribe application front_app_switched 109 | 110 | sketchybar --add item time right \ 111 | --set time update_freq=10 \ 112 | script="$PLUGIN_DIR/time.sh" \ 113 | icon="" \ 114 | icon.font="$FONT:BOLD:16.0" \ 115 | icon.y_offset=0 \ 116 | --add item date right \ 117 | --set date update_freq=10 \ 118 | script="$PLUGIN_DIR/date.sh" \ 119 | icon.font="$FONT:BOLD:13.0" \ 120 | icon="" \ 121 | icon.y_offset=0 122 | 123 | sketchybar --add item battery right \ 124 | --set battery script="$PLUGIN_DIR/battery.sh" \ 125 | icon.font="$FONT:BOLD:16.0" \ 126 | icon.y_offset=0 \ 127 | update_freq=120 \ 128 | --subscribe battery system_woke power_source_change 129 | 130 | sketchybar --add item volume right \ 131 | --set volume script="$PLUGIN_DIR/volume.sh" \ 132 | icon.font="$FONT:BOLD:16.0" \ 133 | --subscribe volume volume_change 134 | 135 | sketchybar --add item wifi right \ 136 | --set wifi script="$PLUGIN_DIR/wifi.sh" \ 137 | icon.font="$FONT:BOLD:16.0" \ 138 | --subscribe wifi wifi_change 139 | 140 | sketchybar --add item vpn right \ 141 | --set vpn script="$PLUGIN_DIR/vpn.sh" \ 142 | icon.font="$FONT:BOLD:16.0" \ 143 | update_freq=10 144 | 145 | sketchybar --add event aerospace_workspace_change 146 | for sid in $(aerospace list-workspaces --all); do 147 | sketchybar --add item space."$sid" left \ 148 | --subscribe space."$sid" aerospace_workspace_change \ 149 | --set space."$sid" \ 150 | background.color=0x44ffffff \ 151 | background.corner_radius=5 \ 152 | background.height=20 \ 153 | background.drawing=off \ 154 | label="$sid" \ 155 | click_script="aerospace workspace $sid" \ 156 | script="$CONFIG_DIR/plugins/aerospace.sh $sid" 157 | done 158 | 159 | ############## FINALIZING THE SETUP ############## 160 | sketchybar --update 161 | 162 | ############## Animation ######################## 163 | sketchybar --animate sin 30 --bar y_offset=0 notch_width=200 margin=0 shadow=on 164 | 165 | echo "sketchybar configuation loaded.." 166 | -------------------------------------------------------------------------------- /aerospace/aerospace.toml: -------------------------------------------------------------------------------- 1 | # Place a copy of this config to ~/.aerospace.toml 2 | # After that, you can edit ~/.aerospace.toml to your liking 3 | 4 | # You can use it to add commands that run after login to macOS user session. 5 | # 'start-at-login' needs to be 'true' for 'after-login-command' to work 6 | # Available commands: https://nikitabobko.github.io/AeroSpace/commands 7 | after-login-command = [] 8 | 9 | # You can use it to add commands that run after AeroSpace startup. 10 | # 'after-startup-command' is run after 'after-login-command' 11 | # Available commands : https://nikitabobko.github.io/AeroSpace/commands 12 | after-startup-command = [] 13 | 14 | # Notify Sketchybar about workspace change 15 | exec-on-workspace-change = ['/bin/bash', '-c', 16 | 'sketchybar --trigger aerospace_workspace_change FOCUSED_WORKSPACE=$AEROSPACE_FOCUSED_WORKSPACE' 17 | ] 18 | 19 | # Start AeroSpace at login 20 | start-at-login = true 21 | 22 | # Normalizations. See: https://nikitabobko.github.io/AeroSpace/guide#normalization 23 | enable-normalization-flatten-containers = true 24 | enable-normalization-opposite-orientation-for-nested-containers = true 25 | 26 | # See: https://nikitabobko.github.io/AeroSpace/guide#layouts 27 | # The 'accordion-padding' specifies the size of accordion padding 28 | # You can set 0 to disable the padding feature 29 | accordion-padding = 0 30 | 31 | # Possible values: tiles|accordion 32 | default-root-container-layout = 'tiles' 33 | 34 | # Possible values: horizontal|vertical|auto 35 | # 'auto' means: wide monitor (anything wider than high) gets horizontal orientation, 36 | # tall monitor (anything higher than wide) gets vertical orientation 37 | default-root-container-orientation = 'auto' 38 | 39 | # Mouse follows focus when focused monitor changes 40 | # Drop it from your config, if you don't like this behavior 41 | # See https://nikitabobko.github.io/AeroSpace/guide#on-focus-changed-callbacks 42 | # See https://nikitabobko.github.io/AeroSpace/commands#move-mouse 43 | # Fallback value (if you omit the key): on-focused-monitor-changed = [] 44 | on-focused-monitor-changed = ['move-mouse monitor-lazy-center'] 45 | 46 | # You can effectively turn off macOS "Hide application" (cmd-h) feature by toggling this flag 47 | # Useful if you don't use this macOS feature, but accidentally hit cmd-h or cmd-alt-h key 48 | # Also see: https://nikitabobko.github.io/AeroSpace/goodies#disable-hide-app 49 | automatically-unhide-macos-hidden-apps = false 50 | 51 | # Possible values: (qwerty|dvorak) 52 | # See https://nikitabobko.github.io/AeroSpace/guide#key-mapping 53 | [key-mapping] 54 | preset = 'qwerty' 55 | 56 | # Gaps between windows (inner-*) and between monitor edges (outer-*). 57 | # Possible values: 58 | # - Constant: gaps.outer.top = 8 59 | # - Per monitor: gaps.outer.top = [{ monitor.main = 16 }, { monitor."some-pattern" = 32 }, 24] 60 | # In this example, 24 is a default value when there is no match. 61 | # Monitor pattern is the same as for 'workspace-to-monitor-force-assignment'. 62 | # See: 63 | # https://nikitabobko.github.io/AeroSpace/guide#assign-workspaces-to-monitors 64 | [gaps] 65 | inner.horizontal = 4 66 | inner.vertical = 4 67 | outer.left = 4 68 | outer.bottom = 4 69 | outer.top = [{ monitor."Builtin-in" = 27 }, { monitor."DELL U2723QE" = 30 }, 0] 70 | outer.right = 4 71 | 72 | [workspace-to-monitor-force-assignment] 73 | 1 = ['DELL U2723QE', 'DELL U2723QE (1)', 'DELL U2723QE (2)', 'Built-in Retina Display'] # Code 74 | 2 = ['Built-in Retina Display', 3, 2, 1] # Browsers 75 | 3 = ['Built-in Retina Display', 3, 2, 1] # Communications 76 | 4 = [3, 2, 1] # IDEs 77 | 5 = [3, 2, 1] # Tools 78 | 79 | # 'main' binding mode declaration 80 | # See: https://nikitabobko.github.io/AeroSpace/guide#binding-modes 81 | # 'main' binding mode must be always presented 82 | # Fallback value (if you omit the key): mode.main.binding = {} 83 | [mode.main.binding] 84 | 85 | # All possible keys: 86 | # - Letters. a, b, c, ..., z 87 | # - Numbers. 0, 1, 2, ..., 9 88 | # - Keypad numbers. keypad0, keypad1, keypad2, ..., keypad9 89 | # - F-keys. f1, f2, ..., f20 90 | # - Special keys. minus, equal, period, comma, slash, backslash, quote, semicolon, 91 | # backtick, leftSquareBracket, rightSquareBracket, space, enter, esc, 92 | # backspace, tab 93 | # - Keypad special. keypadClear, keypadDecimalMark, keypadDivide, keypadEnter, keypadEqual, 94 | # keypadMinus, keypadMultiply, keypadPlus 95 | # - Arrows. left, down, up, right 96 | 97 | # All possible modifiers: cmd, alt, ctrl, shift 98 | 99 | # All possible commands: https://nikitabobko.github.io/AeroSpace/commands 100 | 101 | # See: https://nikitabobko.github.io/AeroSpace/commands#exec-and-forget 102 | # You can uncomment the following lines to open up terminal with alt + enter shortcut 103 | # (like in i3) 104 | # alt-enter = '''exec-and-forget osascript -e ' 105 | # tell application "Terminal" 106 | # do script 107 | # activate 108 | # end tell' 109 | # ''' 110 | 111 | cmd-h = [] # Disable "hide application" 112 | cmd-alt-h = [] # Disable "hide others" 113 | 114 | ctrl-alt-shift-h = 'focus left' 115 | ctrl-alt-shift-j = 'focus down' 116 | ctrl-alt-shift-k = 'focus up' 117 | ctrl-alt-shift-l = 'focus right' 118 | 119 | ctrl-alt-shift-q = 'workspace 1' 120 | ctrl-alt-shift-w = 'workspace 2' 121 | ctrl-alt-shift-e = 'workspace 3' 122 | ctrl-alt-shift-r = 'workspace 4' 123 | ctrl-alt-shift-t = 'workspace 5' 124 | 125 | ctrl-alt-shift-y = 'move-node-to-workspace 1' 126 | ctrl-alt-shift-u = 'move-node-to-workspace 2' 127 | ctrl-alt-shift-i = 'move-node-to-workspace 3' 128 | ctrl-alt-shift-o = 'move-node-to-workspace 4' 129 | ctrl-alt-shift-p = 'move-node-to-workspace 5' 130 | 131 | ctrl-alt-shift-m = 'move-node-to-monitor next --focus-follows-window --wrap-around' 132 | 133 | ctrl-alt-shift-a = 'fullscreen' 134 | ctrl-alt-shift-semicolon = 'layout floating tiling' 135 | ctrl-alt-shift-c = 'close' 136 | 137 | ctrl-alt-shift-f = 'layout tiles horizontal vertical' 138 | ctrl-alt-shift-g = 'layout accordion horizontal vertical' 139 | 140 | ctrl-alt-shift-z = [ 141 | 'mode join', 142 | 'exec-and-forget ~/.config/aerospace/notification.sh "Enter join mode"', 143 | ] 144 | ctrl-alt-shift-s = [ 145 | 'mode resize', 146 | 'exec-and-forget ~/.config/aerospace/notification.sh "Enter resize mode"', 147 | ] 148 | ctrl-alt-shift-d = [ 149 | 'mode move', 150 | 'exec-and-forget ~/.config/aerospace/notification.sh "Enter move mode"', 151 | ] 152 | 153 | cmd-alt-ctrl-j = '''exec-and-forget open -a AlacrittyPopup --args --config-file=$HOME/.config/alacritty-popup.yml -e zsh -ci "bw_get_password"''' 154 | cmd-alt-ctrl-k = '''exec-and-forget open -a AlacrittyPopup --args --config-file=$HOME/.config/alacritty-popup.yml -e zsh -ci "bw_get_totp"''' 155 | cmd-alt-ctrl-f = '''exec-and-forget open -a AlacrittyPopup --args --config-file=$HOME/.config/alacritty-popup.yml -e zsh -ci "fcmd ~/.cmds"''' 156 | cmd-alt-ctrl-d = '''exec-and-forget open -a AlacrittyPopup --args --config-file=$HOME/.config/alacritty-popup.yml -e zsh -ci "fm"''' 157 | cmd-alt-ctrl-s = '''exec-and-forget open -a AlacrittyPopup --args --config-file=$HOME/.config/alacritty-popup.yml -e zsh -ci "sgg"''' 158 | cmd-alt-ctrl-w = '''exec-and-forget open -a AlacrittyPopup --args --config-file=$HOME/.config/alacritty-popup.yml -e zsh -ci "aow"''' 159 | cmd-alt-ctrl-a = '''exec-and-forget open -a AlacrittyPopup --args --config-file=$HOME/.config/alacritty-popup.yml -e zsh -ci "vim ~/Library/Mobile\ Documents/com~apple~CloudDocs/Documents/notes/index.norg"''' 160 | cmd-alt-ctrl-q = '''exec-and-forget open -a AlacrittyPopup --args --config-file=$HOME/.config/alacritty-popup.yml -e zsh -ci "k9s"''' 161 | 162 | [mode.join.binding] 163 | ctrl-alt-shift-h = ['join-with left', 'mode main'] 164 | ctrl-alt-shift-j = ['join-with down', 'mode main'] 165 | ctrl-alt-shift-k = ['join-with up', 'mode main'] 166 | ctrl-alt-shift-l = ['join-with right', 'mode main'] 167 | h = ['join-with left', 'mode main'] 168 | j = ['join-with down', 'mode main'] 169 | k = ['join-with up', 'mode main'] 170 | l = ['join-with right', 'mode main'] 171 | enter = 'mode main' 172 | esc = 'mode main' 173 | 174 | [mode.resize.binding] 175 | ctrl-alt-shift-h = 'resize width -50' 176 | ctrl-alt-shift-j = 'resize height +50' 177 | ctrl-alt-shift-k = 'resize height -50' 178 | ctrl-alt-shift-l = 'resize width +50' 179 | h = 'resize width -50' 180 | j = 'resize height +50' 181 | k = 'resize height -50' 182 | l = 'resize width +50' 183 | enter = [ 184 | 'mode main', 185 | 'exec-and-forget ~/.config/aerospace/notification.sh "Exit resize mode"' 186 | ] 187 | esc = [ 188 | 'mode main', 189 | 'exec-and-forget ~/.config/aerospace/notification.sh "Exit resize mode"' 190 | ] 191 | 192 | [mode.move.binding] 193 | ctrl-alt-shift-h = 'move left' 194 | ctrl-alt-shift-j = 'move down' 195 | ctrl-alt-shift-k = 'move up' 196 | ctrl-alt-shift-l = 'move right' 197 | h = 'move left' 198 | j = 'move down' 199 | k = 'move up' 200 | l = 'move right' 201 | enter = [ 202 | 'mode main', 203 | 'exec-and-forget ~/.config/aerospace/notification.sh "Exit move mode"' 204 | ] 205 | esc = [ 206 | 'mode main', 207 | 'exec-and-forget ~/.config/aerospace/notification.sh "Exit move mode"' 208 | ] 209 | 210 | [[on-window-detected]] 211 | if.app-id = 'com.apple.systempreferences' 212 | run = 'layout floating' 213 | 214 | [[on-window-detected]] 215 | if.app-id = 'com.apple.finder' 216 | run='layout floating' 217 | 218 | [[on-window-detected]] 219 | if.app-id = 'com.google.Chrome' 220 | if.window-title-regex-substring = 'Bitwarden' 221 | run = 'layout floating' 222 | 223 | [[on-window-detected]] 224 | if.app-id = 'org.alacritty' 225 | run = 'move-node-to-workspace 1' 226 | 227 | [[on-window-detected]] 228 | if.app-id = 'com.google.Chrome' 229 | run = 'move-node-to-workspace 2' 230 | 231 | [[on-window-detected]] 232 | if.app-id = 'org.mozilla.firefox' 233 | run = 'move-node-to-workspace 2' 234 | 235 | [[on-window-detected]] 236 | if.app-id = 'com.tinyspeck.slackmacgap' 237 | run = 'move-node-to-workspace 3' 238 | 239 | [[on-window-detected]] 240 | if.app-id = 'com.vng.zalo' 241 | run = 'move-node-to-workspace 3' 242 | 243 | [[on-window-detected]] 244 | if.app-id = 'ru.keepcoder.Telegram' 245 | run = 'move-node-to-workspace 3' 246 | 247 | [[on-window-detected]] 248 | if.app-id = 'com.microsoft.teams2' 249 | run = 'move-node-to-workspace 3' 250 | 251 | [[on-window-detected]] 252 | if.app-id = 'net.whatsapp.WhatsApp' 253 | run = 'move-node-to-workspace 3' 254 | 255 | [[on-window-detected]] 256 | if.app-id = 'com.hnc.Discord' 257 | run = 'move-node-to-workspace 3' 258 | 259 | [[on-window-detected]] 260 | if.app-id = 'com.jetbrains.intellij' 261 | run = 'move-node-to-workspace 4' 262 | 263 | [[on-window-detected]] 264 | if.app-id = 'com.todesktop.230313mzl4w4u92' # Cursor 265 | run = 'move-node-to-workspace 4' 266 | 267 | [[on-window-detected]] 268 | if.app-id = 'com.postmanlabs.mac' 269 | run = 'move-node-to-workspace 5' 270 | 271 | [[on-window-detected]] 272 | if.app-id = 'com.apple.Notes' 273 | run = 'move-node-to-workspace 5' 274 | -------------------------------------------------------------------------------- /nvim/lua/plugin_loader.lua: -------------------------------------------------------------------------------- 1 | local plugin_loader = {} 2 | 3 | --- @private 4 | local function _load_plugins(opts) 5 | require("lazy").setup({ 6 | -- colorscheme 7 | { 8 | "folke/tokyonight.nvim", 9 | lazy = false, -- make sure to load this during startup 10 | priority = 1000, -- make sure to load this before all the other start plugins 11 | }, 12 | -- intellij as language server 13 | { 14 | "mfussenegger/nvim-jdtls", 15 | ft = "java", 16 | config = function() 17 | require("plugins.jdtls").setup() 18 | end, 19 | }, 20 | -- local history in vim 21 | { "dinhhuy258/vim-local-history" }, 22 | -- vim database 23 | { "dinhhuy258/vim-database" }, 24 | -- window picker 25 | { 26 | "s1n7ax/nvim-window-picker", 27 | event = "VeryLazy", 28 | opts = {}, 29 | }, 30 | -- file explorer 31 | { 32 | "dinhhuy258/sfm.nvim", 33 | dependencies = { 34 | "dinhhuy258/sfm-bookmark.nvim", 35 | "dinhhuy258/sfm-filter.nvim", 36 | "dinhhuy258/sfm-git.nvim", 37 | "dinhhuy258/sfm-telescope.nvim", 38 | "dinhhuy258/sfm-paste.nvim", 39 | "s1n7ax/nvim-window-picker", 40 | }, 41 | config = function() 42 | require("plugins.sfm").setup() 43 | end, 44 | }, 45 | -- git 46 | { 47 | "dinhhuy258/git.nvim", 48 | config = function() 49 | require("plugins.git").setup() 50 | end, 51 | }, 52 | -- tmux integration for nvim 53 | { 54 | "aserowy/tmux.nvim", 55 | config = function() 56 | require("plugins.tmux").setup() 57 | end, 58 | }, 59 | -- highlighting 60 | { 61 | "nvim-treesitter/nvim-treesitter", 62 | run = ":TSUpdate", 63 | dependencies = { 64 | "JoosepAlviste/nvim-ts-context-commentstring", 65 | "nvim-treesitter/nvim-treesitter-textobjects", 66 | "RRethy/nvim-treesitter-endwise", 67 | "windwp/nvim-ts-autotag", 68 | }, 69 | config = function() 70 | require("plugins.nvim-treesitter").setup() 71 | end, 72 | }, 73 | -- formating 74 | { 75 | "stevearc/conform.nvim", 76 | event = { "BufReadPre", "BufNewFile" }, 77 | config = function() 78 | require("plugins.conform").setup() 79 | end, 80 | }, 81 | -- linting 82 | { 83 | "mfussenegger/nvim-lint", 84 | event = { "BufReadPre", "BufNewFile" }, 85 | config = function() 86 | require("plugins.nvim-lint").setup() 87 | end, 88 | }, 89 | -- adds file type icons to Vim plugins such as: nvim-tree.lua, galaxyline.nvim, vim-startify... 90 | { "kyazdani42/nvim-web-devicons" }, 91 | -- gitsigns, telescope... depend on this library 92 | { "nvim-lua/plenary.nvim" }, 93 | -- fzf 94 | { 95 | "ibhagwan/fzf-lua", 96 | dependencies = { 97 | "vijaymarupudi/nvim-fzf", 98 | }, 99 | config = function() 100 | require("plugins.fzf-lua").setup() 101 | end, 102 | }, 103 | -- telescope 104 | { 105 | "nvim-telescope/telescope.nvim", 106 | dependencies = { 107 | "nvim-telescope/telescope-ui-select.nvim", 108 | "nvim-telescope/telescope-live-grep-args.nvim", 109 | }, 110 | config = function() 111 | require("plugins.telescope").setup() 112 | end, 113 | }, 114 | -- easy pickup 115 | { 116 | "axkirillov/easypick.nvim", 117 | requires = "nvim-telescope/telescope.nvim", 118 | event = "VeryLazy", 119 | config = function() 120 | require("plugins.easypick").setup() 121 | end, 122 | }, 123 | -- show git diff in the sign column 124 | { 125 | "lewis6991/gitsigns.nvim", 126 | event = "BufRead", 127 | config = function() 128 | require("plugins.gitsigns").setup() 129 | end, 130 | }, 131 | -- vim easy motion 132 | { 133 | "phaazon/hop.nvim", 134 | config = function() 135 | require("plugins.hop").setup() 136 | end, 137 | }, 138 | -- vim surround 139 | { 140 | "kylechui/nvim-surround", 141 | event = "BufRead", 142 | config = function() 143 | require("nvim-surround").setup() 144 | end, 145 | }, 146 | -- enable repeating supported plugins map with . 147 | { 148 | "tpope/vim-repeat", 149 | event = "BufRead", 150 | }, 151 | -- make f, F, t, T more clever 152 | { 153 | "rhysd/clever-f.vim", 154 | event = "BufRead", 155 | config = function() 156 | require("plugins.clever-f").setup() 157 | end, 158 | }, 159 | -- tabline plugin 160 | { 161 | "romgrk/barbar.nvim", 162 | event = "BufWinEnter", 163 | config = function() 164 | require("plugins.barbar").setup() 165 | end, 166 | }, 167 | -- the fancy start screen 168 | { 169 | "mhinz/vim-startify", 170 | event = "BufWinEnter", 171 | config = function() 172 | require("plugins.vim-startify").setup() 173 | end, 174 | }, 175 | -- manage lsp servers 176 | { 177 | "williamboman/mason.nvim", 178 | dependencies = { 179 | "neovim/nvim-lspconfig", 180 | }, 181 | config = function() 182 | require("plugins.mason").setup() 183 | end, 184 | }, 185 | -- lsp signature 186 | { 187 | "ray-x/lsp_signature.nvim", 188 | event = "BufRead", 189 | config = function() 190 | require("lsp_signature").setup() 191 | end, 192 | }, 193 | -- auto completion 194 | { 195 | "saghen/blink.cmp", 196 | dependencies = { 197 | "rafamadriz/friendly-snippets", 198 | { 199 | "L3MON4D3/LuaSnip", 200 | version = "v2.*", 201 | build = "make install_jsregexp", 202 | }, 203 | }, 204 | version = "1.*", 205 | event = "InsertEnter", 206 | config = function() 207 | require("plugins.blink-cmp").setup() 208 | end, 209 | }, 210 | { 211 | "folke/lazydev.nvim", 212 | ft = "lua", 213 | opts = { 214 | library = { 215 | -- Load luvit types when the `vim.uv` word is found 216 | { path = "luvit-meta/library", words = { "vim%.uv" } }, 217 | }, 218 | }, 219 | }, 220 | -- lazydev dependencies 221 | { 222 | "Bilal2453/luvit-meta", 223 | lazy = true, 224 | }, 225 | -- autopair 226 | { 227 | "windwp/nvim-autopairs", 228 | config = function() 229 | require("plugins.nvim-autopairs").setup() 230 | end, 231 | }, 232 | -- comment 233 | { 234 | "numToStr/Comment.nvim", 235 | event = "BufRead", 236 | dependencies = { 237 | "JoosepAlviste/nvim-ts-context-commentstring", 238 | }, 239 | config = function() 240 | require("plugins.comment").setup() 241 | end, 242 | }, 243 | -- indent guides 244 | { 245 | "lukas-reineke/indent-blankline.nvim", 246 | event = "BufRead", 247 | main = "ibl", 248 | config = function() 249 | require("plugins.indent-blankline").setup() 250 | end, 251 | }, 252 | -- go 253 | { 254 | "mfussenegger/nvim-dap", 255 | ft = { 256 | "go", 257 | "ruby", 258 | "php", 259 | }, 260 | dependencies = { 261 | "rcarriga/nvim-dap-ui", 262 | "suketa/nvim-dap-ruby", 263 | }, 264 | config = function() 265 | require("plugins.nvim-dap").setup() 266 | end, 267 | }, 268 | -- docs generation 269 | { 270 | "danymat/neogen", 271 | dependencies = { 272 | "nvim-treesitter/nvim-treesitter", 273 | }, 274 | config = function() 275 | require("neogen").setup {} 276 | end, 277 | }, 278 | -- spliting/ joining blocks of code 279 | { 280 | "Wansmer/treesj", 281 | dependencies = { "nvim-treesitter/nvim-treesitter" }, 282 | config = function() 283 | require("plugins.treesj").setup() 284 | end, 285 | }, 286 | -- for interacting with tests within NeoVim 287 | { 288 | "vim-test/vim-test", 289 | dependencies = { 290 | "preservim/vimux", 291 | }, 292 | config = function() 293 | require("plugins.vim-test").setup() 294 | end, 295 | }, 296 | -- easily interact with tmux from vim 297 | { "preservim/vimux" }, 298 | -- peek file 299 | { 300 | "nacro90/numb.nvim", 301 | config = function() 302 | require("numb").setup() 303 | end, 304 | }, 305 | { 306 | "echasnovski/mini.cursorword", 307 | config = function() 308 | require("plugins.cursorword").setup() 309 | end, 310 | }, 311 | { 312 | "echasnovski/mini.ai", 313 | opts = {}, 314 | }, 315 | { 316 | "SmiteshP/nvim-navbuddy", 317 | dependencies = { 318 | "SmiteshP/nvim-navic", 319 | "MunifTanjim/nui.nvim", 320 | }, 321 | opts = { 322 | lsp = { 323 | auto_attach = true, 324 | }, 325 | }, 326 | config = function() 327 | require("plugins.nvim-navbuddy").setup() 328 | end, 329 | }, 330 | { 331 | "utilyre/barbecue.nvim", 332 | dependencies = { 333 | "SmiteshP/nvim-navic", 334 | "kyazdani42/nvim-web-devicons", 335 | }, 336 | config = function() 337 | require("barbecue").setup() 338 | end, 339 | }, 340 | { 341 | "tpope/vim-abolish", 342 | }, 343 | { 344 | "tpope/vim-rails", 345 | ft = { 346 | "ruby", 347 | }, 348 | config = function() 349 | require("plugins.vim-rails").setup() 350 | end, 351 | }, 352 | { 353 | "kevinhwang91/nvim-ufo", 354 | dependencies = { 355 | "kevinhwang91/promise-async", 356 | { 357 | "luukvbaal/statuscol.nvim", 358 | }, 359 | }, 360 | config = function() 361 | require("plugins.nvim-ufo").setup() 362 | end, 363 | }, 364 | -- require for neorg 365 | { 366 | "nvim-neorg/neorg", 367 | lazy = false, 368 | config = function() 369 | require("plugins.neorg").setup() 370 | end, 371 | }, 372 | { 373 | "b0o/schemastore.nvim", 374 | lazy = true, 375 | }, 376 | { 377 | "rgroli/other.nvim", 378 | config = function() 379 | require("plugins.other").setup() 380 | end, 381 | cond = function() 382 | return vim.bo.filetype ~= "ruby" 383 | end, 384 | }, 385 | { 386 | "MeanderingProgrammer/render-markdown.nvim", 387 | ft = { 388 | "markdown", 389 | }, 390 | opts = { 391 | file_types = { "markdown" }, 392 | }, 393 | }, 394 | { 395 | "kevinhwang91/nvim-hlslens", 396 | event = { "BufReadPre" }, 397 | opts = {}, 398 | }, 399 | { 400 | "mg979/vim-visual-multi", 401 | event = "VeryLazy", 402 | config = function() 403 | require("plugins.vim-visual-multi").setup() 404 | end, 405 | }, 406 | { 407 | "folke/which-key.nvim", 408 | event = "VeryLazy", 409 | config = function() 410 | require("plugins.which-key").setup() 411 | end, 412 | }, 413 | { 414 | "zbirenbaum/copilot.lua", 415 | event = "BufRead", 416 | config = function() 417 | require("plugins.copilot").setup() 418 | end, 419 | }, 420 | }, opts) 421 | end 422 | 423 | function plugin_loader:init() 424 | local lazypath = vim.fn.stdpath "data" .. "/lazy/lazy.nvim" 425 | if not vim.loop.fs_stat(lazypath) then 426 | vim.fn.system { "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", lazypath } 427 | vim.fn.system { "git", "-C", lazypath, "checkout", "tags/stable" } -- last stable release 428 | end 429 | 430 | vim.opt.rtp:prepend(lazypath) 431 | 432 | -- load plugins 433 | _load_plugins { 434 | ui = { 435 | border = "rounded", 436 | }, 437 | install = { 438 | missing = true, 439 | }, 440 | } 441 | end 442 | 443 | return { 444 | init = function() 445 | return plugin_loader:init() 446 | end, 447 | } 448 | --------------------------------------------------------------------------------