diff --git a/.aliases.sh b/.aliases.sh index 4b9dbb2..5b077de 100644 --- a/.aliases.sh +++ b/.aliases.sh @@ -10,13 +10,17 @@ alias nt="n test" alias ntd="n test:dev" # ─────────────────────────────── vim/nvim ─────────────────────────────── -if command -v zoxide > /dev/null && command -v nvim-zoxide > /dev/null; then - alias nvim="nvim-zoxide" -fi alias nv="nvim" alias lv="lvim" alias vim="nvim" alias v="vim" +if command -v zoxide > /dev/null && command -v nvim-zoxide > /dev/null; then + alias nv="nvim-zoxide" +fi + +# ───────────────────────────── drag n drop ─────────────────────────── +alias dnd="dragon-drop" +alias cpdnd='cp $(dragon-drop -p -x -t .) .' # ───────────────────────────────── eza ─────────────────────────────── if command -v eza > /dev/null; then diff --git a/.config/Code/User/snippets/typescript.json b/.config/Code/User/snippets/typescript.json new file mode 100644 index 0000000..775e02a --- /dev/null +++ b/.config/Code/User/snippets/typescript.json @@ -0,0 +1,15 @@ +{ + // Place your snippets for typescript here. Each snippet is defined under a snippet name and has a prefix, body and + // description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are: + // $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders. Placeholders with the + // same ids are connected. + // Example: + // "Print to console": { + // "prefix": "log", + // "body": [ + // "console.log('$1');", + // "$2" + // ], + // "description": "Log output to console" + // } +} \ No newline at end of file diff --git a/.config/hypr/conf/animations.conf b/.config/hypr/conf/animations.conf index 5366fb8..cd1042d 100644 --- a/.config/hypr/conf/animations.conf +++ b/.config/hypr/conf/animations.conf @@ -2,7 +2,7 @@ animations { enabled = true - # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more + # see https://wiki.hyprland.org/Configuring/Animations/ for more bezier = myBezier, 0.05, 0.9, 0.1, 1.05 bezier = easeOutQuint, 0.22, 1, 0.36, 1 diff --git a/.config/hypr/conf/keybindings.conf b/.config/hypr/conf/keybindings.conf index 61cbcac..cab7c45 100644 --- a/.config/hypr/conf/keybindings.conf +++ b/.config/hypr/conf/keybindings.conf @@ -15,6 +15,7 @@ bind = $mainMod SHIFT, T, exec, ~/.config/hypr/scripts/show-crow.sh bind = $mainMod CTRL SHIFT, T, exec, ~/.config/hypr/scripts/translate-selection.sh bind = $mainMod, E, exec, $fileManager # file manager bind = $mainMod, A, exec, $toggle_menu_cmd # wofi +bind = $mainMod CTRL ALT, V, exec, ~/.config/hypr/scripts/dnd-clipboard.sh # ──────────────────────────────── copyq ────────────────────────────── bind = CTRL_ALT, V, exec, copyq toggle @@ -99,14 +100,20 @@ bindle=, XF86AudioLowerVolume, exec, pactl set-sink-volume @DEFAULT_SINK@ -5% & bindle=, XF86MonBrightnessUp, exec, ~/.config/scripts/set_brightness.sh +10% bindle=, XF86MonBrightnessDown, exec, ~/.config/scripts/set_brightness.sh 10%- bindl=, XF86AudioMute, exec, amixer set Master toggle -bindl=, XF86AudioPlay, exec, playerctl play-pause -bindl=, XF86AudioPause, exec, playerctl play-pause -bindl=, XF86AudioStop, exec, playerctl play-pause -bindl=, XF86AudioNext, exec, playerctl next -bindl=, XF86AudioPrev, exec, playerctl previous -bindl= CTRL ALT SHIFT, H, exec, playerctl previous -bindl= CTRL ALT SHIFT, L, exec, playerctl next -bindl= CTRL ALT SHIFT, SPACE, exec, playerctl play-pause +bindl=, XF86AudioPlay, exec, playerctl --player=$(cat ~/.config/chosen_player) play-pause +bindl=, XF86AudioPause, exec, playerctl --player=$(cat ~/.config/chosen_player) play-pause +bindl=, XF86AudioStop, exec, playerctl --player=$(cat ~/.config/chosen_player) play-pause +bindl=, XF86AudioNext, exec, playerctl --player=$(cat ~/.config/chosen_player) next +bindl=, XF86AudioPrev, exec, playerctl --player=$(cat ~/.config/chosen_player) previous +bindl= CTRL ALT SHIFT, H, exec, playerctl --player=$(cat ~/.config/chosen_player) previous +bindl= CTRL ALT SHIFT, L, exec, playerctl --player=$(cat ~/.config/chosen_player) next +bindl= CTRL ALT SHIFT, SPACE, exec, playerctl --player=$(cat ~/.config/chosen_player) play-pause + +# ─────────────────────── select pulseaudio output ─────────────────────── +bind= CTRL ALT SHIFT, O, exec, ~/.config/hypr/scripts/wofi-pulse-output.sh + +# ─────────────────────── select playerctl player ───────────────────── +bind= CTRL ALT SHIFT, P, exec, ~/.config/hypr/scripts/wofi-player.sh # Move/resize windows with mainMod + LMB/RMB and dragging bindm = $mainMod, mouse:272, movewindow diff --git a/.config/hypr/hyprland.conf b/.config/hypr/hyprland.conf index 7233ea4..71c88fc 100644 --- a/.config/hypr/hyprland.conf +++ b/.config/hypr/hyprland.conf @@ -17,8 +17,8 @@ source = ./workspaces.conf # See https://wiki.hyprland.org/Configuring/Keywords/ # Set programs that you use -$terminal = alacritty -$fileManager = dolphin +$terminal = kitty +$fileManager = $terminal tmux new-session -s tmp-file-manager 'yazi' $toggle_menu_cmd = pgrep wofi >/dev/null 2>&1 && killall wofi || wofi --show drun # ╭──────────────────────────────────────────────────────────╮ diff --git a/.config/hypr/monitors.conf b/.config/hypr/monitors.conf index b61d561..cd63855 100644 --- a/.config/hypr/monitors.conf +++ b/.config/hypr/monitors.conf @@ -1,6 +1,7 @@ -# Generated by nwg-displays on 2024-08-14 at 13:35:50. Do not edit manually. +# Generated by nwg-displays on 2024-10-09 at 13:19:03. Do not edit manually. monitor=eDP-1,1920x1080@60.01,0x0,1.0 -monitor=DP-2,1920x1080@60.0,1920x-953,1.0 +monitor=DP-2,1920x1080@60.0,1920x-1440,1.0 +monitor=DP-2,transform,3 monitor=HDMI-A-1,2560x1440@59.95,-640x-1440,1.0 monitor=desc:BNQ BenQ G925HDA 29A01966019,prefered,auto,1.0 diff --git a/.config/hypr/monitors1.conf b/.config/hypr/monitors1.conf new file mode 100644 index 0000000..b61d561 --- /dev/null +++ b/.config/hypr/monitors1.conf @@ -0,0 +1,6 @@ +# Generated by nwg-displays on 2024-08-14 at 13:35:50. Do not edit manually. + +monitor=eDP-1,1920x1080@60.01,0x0,1.0 +monitor=DP-2,1920x1080@60.0,1920x-953,1.0 +monitor=HDMI-A-1,2560x1440@59.95,-640x-1440,1.0 +monitor=desc:BNQ BenQ G925HDA 29A01966019,prefered,auto,1.0 diff --git a/.config/hypr/scripts/dnd-clipboard.sh b/.config/hypr/scripts/dnd-clipboard.sh new file mode 100755 index 0000000..42a4f1b --- /dev/null +++ b/.config/hypr/scripts/dnd-clipboard.sh @@ -0,0 +1 @@ +wl-paste > /tmp/clipboard_image.jpg && dragon-drop /tmp/clipboard_image.jpg diff --git a/.config/hypr/scripts/wofi-player.sh b/.config/hypr/scripts/wofi-player.sh new file mode 100755 index 0000000..4d35dc9 --- /dev/null +++ b/.config/hypr/scripts/wofi-player.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +# Function to get info for a player +get_player_info() { + playerctl -p "$1" metadata --format "{{ artist }} - {{ title }}" 2>/dev/null +} + +# Get the currently selected player from the file, if it exists +current_player=$(cat ~/.config/chosen_player 2>/dev/null) + +# Get list of players +players=$(playerctl -l) + +# Prepare the list for rofi by appending info about each player +menu="" +for player in $players; do + info=$(get_player_info "$player") + if [ -z "$info" ]; then + info="(No track info)" + fi + # Highlight the current player with ✅ + if [ "$player" = "$current_player" ]; then + menu+="✅ $player: $info\n" + else + menu+="$player: $info\n" + fi +done + +# Use rofi to choose the player +chosen=$(echo -e "$menu" | wofi -dmenu -p "Choose player" | awk -F: '{print $1}') + +# If a player was chosen, save it to a file +if [ -n "$chosen" ]; then + echo "$chosen" > ~/.config/chosen_player + notify-send "Audio output switched" "Switched to $(echo "$chosen")" +fi + diff --git a/.config/hypr/scripts/wofi-pulse-output.sh b/.config/hypr/scripts/wofi-pulse-output.sh new file mode 100755 index 0000000..8176444 --- /dev/null +++ b/.config/hypr/scripts/wofi-pulse-output.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +# Get the current default sink +default_sink=$(pactl info | grep "Default Sink" | awk '{print $3}') +default_sink_number=$(pactl list sinks short | grep "$default_sink" | awk '{print $1}') + +# Get a list of available sinks with their descriptions +sinks=$(pactl list sinks | grep -E 'Sink|Description' | sed -E 's/Sink #([0-9]+)/\1/' | sed -E 's/Description: (.+)/\1/') + +# Format the sink list to show the index and description +formatted_sinks=$(echo "$sinks" | awk 'NR%2{printf "%s ", $0; next;}1') + +# Add ✅ to the current default sink +formatted_sinks=$(echo "$formatted_sinks" | awk -v default_sink_number="$default_sink_number" '{if ($1 == default_sink_number) {print "✅ " $0} else {print $0}}') + +# Use wofi to select a sink based on the description +selected_sink=$(echo "$formatted_sinks" | wofi --dmenu --prompt "Select audio output:") + +# Extract the sink index +sink_index=$(echo "$selected_sink" | awk '{print $1}') + +# Set the selected sink as the default +if [ -n "$sink_index" ]; then + pactl set-default-sink "$sink_index" + notify-send "Audio output switched" "Switched to $(echo "$selected_sink" | cut -d' ' -f2-)" +else + notify-send "No sink selected" +fi diff --git a/.config/kitty/kitty.conf b/.config/kitty/kitty.conf index 71bfe87..ef37606 100644 --- a/.config/kitty/kitty.conf +++ b/.config/kitty/kitty.conf @@ -66,7 +66,7 @@ inactive_border_color #6272a4 # BEGIN_KITTY_FONTS -font_family family="JetBrains Mono" +font_family family="VictorMono Nerd Font Mono" bold_font auto italic_font auto bold_italic_font auto diff --git a/.config/lazygit/config.yml b/.config/lazygit/config.yml index e69de29..12adb43 100644 --- a/.config/lazygit/config.yml +++ b/.config/lazygit/config.yml @@ -0,0 +1,4 @@ +git: + paging: + colorArg: always + pager: delta --dark --paging=never diff --git a/.config/lazygit/state.yml b/.config/lazygit/state.yml index 176b66e..6d8dbcc 100644 --- a/.config/lazygit/state.yml +++ b/.config/lazygit/state.yml @@ -1,10 +1,16 @@ lastupdatecheck: 0 recentrepos: -- /home/goodhumored/lazygit/lazygit + - /home/goodhumored/side-hustle/lambo/er_lamborgini + - /home/goodhumored/side-hustle/alexflora/frontend + - /home/goodhumored/lazygit/lazygit startuppopupversion: 5 +lastversion: 0.43.1 customcommandshistory: [] hidecommandlog: false ignorewhitespaceindiffview: false diffcontextsize: 3 +renamesimilaritythreshold: 50 localbranchsortorder: recency remotebranchsortorder: alphabetical +gitlogorder: topo-order +gitlogshowgraph: always diff --git a/.config/nvim/lua/goodhumored/autocommands.lua b/.config/nvim/lua/goodhumored/autocommands.lua new file mode 100644 index 0000000..d619cc3 --- /dev/null +++ b/.config/nvim/lua/goodhumored/autocommands.lua @@ -0,0 +1,6 @@ +vim.api.nvim_create_autocmd("BufWritePre", { + pattern = "*.ts", + callback = function() + vim.cmd("OrganizeImports") + end, +}) diff --git a/.config/nvim/lua/goodhumored/common-bindings.lua b/.config/nvim/lua/goodhumored/common-bindings.lua index 1ec80af..1631e51 100644 --- a/.config/nvim/lua/goodhumored/common-bindings.lua +++ b/.config/nvim/lua/goodhumored/common-bindings.lua @@ -1,9 +1,21 @@ +-- ───────────────────── disable highlight on search ───────────────────── +vim.keymap.set({ "n", "i" }, "", "", { noremap = true, desc = "Delete word" }) + -- ───────────────────── disable highlight on search ───────────────────── vim.keymap.set("n", "", "nohlsearch") +-- ────────────────────────── insert timestamp ─────────────────────── +vim.api.nvim_set_keymap("i", "", '=strftime("%Y-%m-%dT%H:%M:%S.000Z")', { noremap = true, silent = true }) + +-- ─────────────────────────── ctrl+left/right ─────────────────────────── +vim.api.nvim_set_keymap("i", "", "b", { noremap = true, silent = true }) +vim.api.nvim_set_keymap("i", "", "w", { noremap = true, silent = true }) + -- ───────────────────────── Diagnostic keymaps ────────────────────── vim.keymap.set("n", "q", vim.diagnostic.setloclist, { desc = "Open diagnostic [Q]uickfix list" }) +-- ─────────────────────── pasting in insert mode ──────────────────── +vim.keymap.set("i", "", "+", { desc = "" }) -- ╭─────────────────────────────────────────────────────────╮ -- │ terminal │ -- ╰─────────────────────────────────────────────────────────╯ diff --git a/.config/nvim/lua/goodhumored/init.lua b/.config/nvim/lua/goodhumored/init.lua index 712b088..2dad7d2 100644 --- a/.config/nvim/lua/goodhumored/init.lua +++ b/.config/nvim/lua/goodhumored/init.lua @@ -1,5 +1,6 @@ require("goodhumored.common-vim-settings") require("goodhumored.common-bindings") +require("goodhumored.autocommands") require("goodhumored.lazy") -- The line beneath this is called `modeline`. See `:help modeline` -- vim: ts=2 sts=2 sw=2 et diff --git a/.config/nvim/lua/goodhumored/plugins/diagram.lua.disable b/.config/nvim/lua/goodhumored/plugins/diagram.lua.disable new file mode 100644 index 0000000..a9102d3 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/diagram.lua.disable @@ -0,0 +1,13 @@ +return { + "3rd/diagram.nvim", + dependencies = { + "3rd/image.nvim", + }, + opts = { -- you can just pass {}, defaults below + renderer_options = { + plantuml = { + charset = "utf-8", + }, + }, + }, +} diff --git a/.config/nvim/lua/goodhumored/plugins/gruvbox.lua b/.config/nvim/lua/goodhumored/plugins/gruvbox.lua new file mode 100644 index 0000000..0503b75 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/gruvbox.lua @@ -0,0 +1,32 @@ +return { + "ellisonleao/gruvbox.nvim", + priority = 1000, + init = function() + require("gruvbox").setup({ + terminal_colors = true, -- add neovim terminal colors + undercurl = true, + underline = true, + bold = true, + italic = { + strings = true, + emphasis = true, + comments = true, + operators = false, + folds = true, + }, + strikethrough = true, + invert_selection = false, + invert_signs = false, + invert_tabline = false, + invert_intend_guides = false, + inverse = true, -- invert background for search, diffs, statuslines and errors + contrast = "soft", -- can be "hard", "soft" or empty string + palette_overrides = {}, + overrides = {}, + dim_inactive = false, + transparent_mode = false, + }) + vim.o.background = "dark" + vim.cmd("colorscheme gruvbox") + end, +} diff --git a/.config/nvim/lua/goodhumored/plugins/image.lua.disable b/.config/nvim/lua/goodhumored/plugins/image.lua similarity index 98% rename from .config/nvim/lua/goodhumored/plugins/image.lua.disable rename to .config/nvim/lua/goodhumored/plugins/image.lua index 63ebe56..163dba0 100644 --- a/.config/nvim/lua/goodhumored/plugins/image.lua.disable +++ b/.config/nvim/lua/goodhumored/plugins/image.lua @@ -9,6 +9,7 @@ return { -- default config image.setup({ backend = "kitty", + kitty_method = "normal", integrations = { markdown = { enabled = true, diff --git a/.config/nvim/lua/goodhumored/plugins/inlay-hints.lua b/.config/nvim/lua/goodhumored/plugins/inlay-hints.lua index 78bd06b..cb88a4a 100644 --- a/.config/nvim/lua/goodhumored/plugins/inlay-hints.lua +++ b/.config/nvim/lua/goodhumored/plugins/inlay-hints.lua @@ -4,33 +4,5 @@ return { dependencies = { "neovim/nvim-lspconfig" }, config = function() require("inlay-hints").setup() - require("lspconfig").tsserver.setup({ - settings = { - typescript = { - inlayHints = { - includeInlayParameterNameHints = "all", - includeInlayParameterNameHintsWhenArgumentMatchesName = true, - includeInlayFunctionParameterTypeHints = true, - includeInlayVariableTypeHints = true, - includeInlayVariableTypeHintsWhenTypeMatchesName = true, - includeInlayPropertyDeclarationTypeHints = true, - includeInlayFunctionLikeReturnTypeHints = true, - includeInlayEnumMemberValueHints = true, - }, - }, - javascript = { - inlayHints = { - includeInlayParameterNameHints = "all", - includeInlayParameterNameHintsWhenArgumentMatchesName = true, - includeInlayFunctionParameterTypeHints = true, - includeInlayVariableTypeHints = true, - includeInlayVariableTypeHintsWhenTypeMatchesName = true, - includeInlayPropertyDeclarationTypeHints = true, - includeInlayFunctionLikeReturnTypeHints = true, - includeInlayEnumMemberValueHints = true, - }, - }, - }, - }) end, } diff --git a/.config/nvim/lua/goodhumored/plugins/leetcode.lua b/.config/nvim/lua/goodhumored/plugins/leetcode.lua new file mode 100644 index 0000000..8505ffe --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/leetcode.lua @@ -0,0 +1,107 @@ +local leet_arg = "leetcode.nvim" + +return { + "kawre/leetcode.nvim", + build = ":TSUpdate html", + dependencies = { + "nvim-telescope/telescope.nvim", + "nvim-lua/plenary.nvim", -- required by telescope + "MunifTanjim/nui.nvim", + + -- optional + "nvim-treesitter/nvim-treesitter", + "rcarriga/nvim-notify", + "nvim-tree/nvim-web-devicons", + }, + cmd = "Leet", + lazy = leet_arg ~= vim.fn.argv()[1], + opts = { + ---@type string + arg = leet_arg, + + ---@type lc.lang + lang = "golang", + + cn = { -- leetcode.cn + enabled = false, ---@type boolean + translator = true, ---@type boolean + translate_problems = true, ---@type boolean + }, + + ---@type lc.storage + storage = { + home = vim.fn.stdpath("data") .. "/leetcode", + cache = vim.fn.stdpath("cache") .. "/leetcode", + }, + + ---@type table + plugins = { + non_standalone = false, + }, + + ---@type boolean + logging = true, + + injector = {}, ---@type table + + cache = { + update_interval = 60 * 60 * 24 * 7, ---@type integer 7 days + }, + + console = { + open_on_runcode = true, ---@type boolean + + dir = "row", ---@type lc.direction + + size = { ---@type lc.size + width = "90%", + height = "75%", + }, + + result = { + size = "60%", ---@type lc.size + }, + + testcase = { + virt_text = true, ---@type boolean + + size = "40%", ---@type lc.size + }, + }, + + description = { + position = "left", ---@type lc.position + + width = "40%", ---@type lc.size + + show_stats = true, ---@type boolean + }, + + hooks = { + ---@type fun()[] + ["enter"] = {}, + + ---@type fun(question: lc.ui.Question)[] + ["question_enter"] = {}, + + ---@type fun()[] + ["leave"] = {}, + }, + + keys = { + toggle = { "q" }, ---@type string|string[] + confirm = { "" }, ---@type string|string[] + + reset_testcases = "r", ---@type string + use_testcase = "U", ---@type string + focus_testcases = "H", ---@type string + focus_result = "L", ---@type string + }, + + ---@type lc.highlights + theme = {}, + + ---@type boolean + image_support = false, + }, +} diff --git a/.config/nvim/lua/goodhumored/plugins/lsp.lua b/.config/nvim/lua/goodhumored/plugins/lsp.lua index 48dfb6a..942f32b 100644 --- a/.config/nvim/lua/goodhumored/plugins/lsp.lua +++ b/.config/nvim/lua/goodhumored/plugins/lsp.lua @@ -142,7 +142,36 @@ return { -- LSP Configuration & Plugins -- https://github.com/pmizio/typescript-tools.nvim -- -- But for many setups, the LSP (`tsserver`) will work just fine - tsserver = { + ts_ls = { + init_options = { + preferences = { + importModuleSpecifierPreference = "relative", + }, + }, + typescript = { + inlayHints = { + includeInlayParameterNameHints = "all", + includeInlayParameterNameHintsWhenArgumentMatchesName = true, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayVariableTypeHintsWhenTypeMatchesName = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + }, + javascript = { + inlayHints = { + includeInlayParameterNameHints = "all", + includeInlayParameterNameHintsWhenArgumentMatchesName = true, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayVariableTypeHintsWhenTypeMatchesName = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + }, commands = { OrganizeImports = { function() @@ -209,7 +238,6 @@ return { -- LSP Configuration & Plugins settings = { gopls = { gofumpt = true, - golines = true, }, }, }) diff --git a/.config/nvim/lua/goodhumored/plugins/lualine.lua b/.config/nvim/lua/goodhumored/plugins/lualine.lua new file mode 100644 index 0000000..21921dc --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/lualine.lua @@ -0,0 +1,35 @@ +return { + "nvim-lualine/lualine.nvim", + dependencies = { "nvim-tree/nvim-web-devicons" }, + config = function() + require("lualine").setup({ + options = { + theme = "iceberg_dark", + component_separators = "", + section_separators = { left = "", right = "" }, + }, + sections = { + lualine_a = { { "mode", separator = { left = "" }, right_padding = 2 } }, + lualine_b = { "filename", "branch" }, + lualine_c = { + "%=", --[[ add your center compoentnts here in place of this comment ]] + }, + lualine_x = {}, + lualine_y = { "filetype", "progress" }, + lualine_z = { + { "location", separator = { right = "" }, left_padding = 2 }, + }, + }, + inactive_sections = { + lualine_a = { "filename" }, + lualine_b = {}, + lualine_c = {}, + lualine_x = {}, + lualine_y = {}, + lualine_z = { "location" }, + }, + tabline = {}, + extensions = {}, + }) + end, +} diff --git a/.config/nvim/lua/goodhumored/plugins/mini-nvim.lua b/.config/nvim/lua/goodhumored/plugins/mini-nvim.lua new file mode 100644 index 0000000..13f06d3 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/mini-nvim.lua @@ -0,0 +1,12 @@ +return { -- Collection of various small independent plugins/modules + "echasnovski/mini.nvim", + config = function() + -- Better Around/Inside textobjects + -- + -- Examples: + -- - va) - [V]isually select [A]round [)]paren + -- - yinq - [Y]ank [I]nside [N]ext [Q]uote + -- - ci' - [C]hange [I]nside [']quote + require("mini.ai").setup({ n_lines = 500 }) + end, +} diff --git a/.config/nvim/lua/goodhumored/plugins/neorg.lua b/.config/nvim/lua/goodhumored/plugins/neorg.lua index 47fb441..7200b1a 100644 --- a/.config/nvim/lua/goodhumored/plugins/neorg.lua +++ b/.config/nvim/lua/goodhumored/plugins/neorg.lua @@ -3,37 +3,47 @@ return { lazy = false, version = "*", config = function() - require("neorg").setup({ + local neorg = require("neorg") + neorg.setup({ load = { ["core.defaults"] = {}, ["core.concealer"] = {}, + ["core.integrations.image"] = {}, + ["core.latex.renderer"] = {}, + ["core.export"] = { + config = { -- Note that this table is optional and doesn't need to be provided + -- Configuration here + }, + }, ["core.dirman"] = { config = { workspaces = { notes = "~/notes", uni = "~/Uni", - job = "~/job", - side = "~/side-hustle", + dipal = "~/Job/dipal/notes", + side = "~/side-hustle/notes", }, default_workspace = "notes", + open_last_workspace = true, + }, + }, + ["core.qol.toc"] = { + config = { + close_split_on_jump = true, }, }, }, }) + neorg.modules.get_module("core.dirman").set_closest_workspace_match() vim.wo.foldlevel = 99 vim.wo.conceallevel = 2 end, keys = { - { - "n", - ":Neorg", - desc = "[N]eorg", - }, { "nw", - ":Neorg workspace", + ":Neorg workspace ", desc = "[N]eorg [W]orkspaces", }, { @@ -46,5 +56,20 @@ return { ":Neorg index", desc = "[N]eorg [I]ndex", }, + { + "nT", + ":Neorg toc qflist", + desc = "[N]eorg [T]able of contents", + }, + { + "nr", + ":Neorg return", + desc = "[N]eorg [R]eturn", + }, + { + "tl", + ":Neorg render-latex", + desc = "[N]eorg [L]atex", + }, }, } diff --git a/.config/nvim/lua/goodhumored/plugins/neotest.lua b/.config/nvim/lua/goodhumored/plugins/neotest.lua index b2fe44c..a9d4a51 100644 --- a/.config/nvim/lua/goodhumored/plugins/neotest.lua +++ b/.config/nvim/lua/goodhumored/plugins/neotest.lua @@ -85,9 +85,9 @@ return { filter_dir = function(name, rel_path, root) return name ~= "node_modules" or name ~= "dist" end, - -- is_test_file = function(file_path) - -- return file_path:match(".*%.spec%.ts") ~= nil - -- end, + is_test_file = function(file_path) + return file_path:match(".*%.spec%.ts") ~= nil + end, }), }, }) diff --git a/.config/nvim/lua/goodhumored/plugins/neozoom.lua b/.config/nvim/lua/goodhumored/plugins/neozoom.lua new file mode 100644 index 0000000..6787d10 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/neozoom.lua @@ -0,0 +1,49 @@ +return { + "nyngwang/NeoZoom.lua", + config = function() + require("neo-zoom").setup({ + popup = { enabled = true }, -- this is the default. + -- NOTE: Add popup-effect (replace the window on-zoom with a `[No Name]`). + -- EXPLAIN: This improves the performance, and you won't see two + -- identical buffers got updated at the same time. + -- popup = { + -- enabled = true, + -- exclude_filetypes = {}, + -- exclude_buftypes = {}, + -- }, + exclude_buftypes = { "terminal" }, + -- exclude_filetypes = { 'lspinfo', 'mason', 'lazy', 'fzf', 'qf' }, + winopts = { + offset = { + -- NOTE: omit `top`/`left` to center the floating window vertically/horizontally. + -- top = 0, + -- left = 0.17, + width = 150, + height = 0.85, + }, + -- NOTE: check :help nvim_open_win() for possible border values. + border = "thicc", -- this is a preset, try it :) + }, + presets = { + { + -- NOTE: regex pattern can be used here! + filetypes = { "dapui_.*", "dap-repl" }, + winopts = { + offset = { top = 0.02, left = 0.26, width = 0.74, height = 0.25 }, + }, + }, + { + filetypes = { "markdown" }, + callbacks = { + function() + vim.wo.wrap = true + end, + }, + }, + }, + }) + vim.keymap.set("n", "", function() + vim.cmd("NeoZoomToggle") + end, { silent = true, nowait = true }) + end, +} diff --git a/.config/nvim/lua/goodhumored/plugins/noice.nvim.lua b/.config/nvim/lua/goodhumored/plugins/noice.nvim.lua new file mode 100644 index 0000000..eb54ce4 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/noice.nvim.lua @@ -0,0 +1,15 @@ +return { + "folke/noice.nvim", + event = "VeryLazy", + opts = { + -- add any options here + }, + dependencies = { + -- if you lazy-load any plugin below, make sure to add proper `module="..."` entries + "MunifTanjim/nui.nvim", + -- OPTIONAL: + -- `nvim-notify` is only needed, if you want to use the notification view. + -- If not available, we use `mini` as the fallback + "rcarriga/nvim-notify", + }, +} diff --git a/.config/nvim/lua/goodhumored/plugins/nvim-surround.lua b/.config/nvim/lua/goodhumored/plugins/nvim-surround.lua new file mode 100644 index 0000000..52a9bc6 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/nvim-surround.lua @@ -0,0 +1,18 @@ +return { + "kylechui/nvim-surround", + version = "*", -- Use for stability; omit to use `main` branch for the latest features + event = "VeryLazy", + config = function() + local surround = require("nvim-surround") + surround.setup({ + aliases = { + ["a"] = ">", + ["b"] = ")", + ["B"] = "}", + ["r"] = "]", + ["q"] = { '"', "'", "`" }, + ["s"] = { "}", "]", ")", ">", '"', "'", "`" }, + }, + }) + end, +} diff --git a/.config/nvim/lua/goodhumored/plugins/plantuml.lua b/.config/nvim/lua/goodhumored/plugins/plantuml.lua new file mode 100644 index 0000000..72ff4b7 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/plantuml.lua @@ -0,0 +1,7 @@ +return { + "https://gitlab.com/itaranto/plantuml.nvim", + version = "*", + config = function() + require("plantuml").setup() + end, +} diff --git a/.config/nvim/lua/goodhumored/plugins/snippets/code-snippets b/.config/nvim/lua/goodhumored/plugins/snippets/code-snippets new file mode 100644 index 0000000..8e4cc32 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/snippets/code-snippets @@ -0,0 +1,53 @@ +{ + "private readonly ...": { + "scope": "typescript", + "prefix": "prr", + "body": [ + "private readonly _${1:name}: ${2:Type}" + ] + }, + "props": { + "scope": "typescriptreact", + "prefix": "props", + "body": [ + "{ className }: { className?: string }" + ] + }, + "prop": { + "scope": "typescript", + "prefix": "prop", + "body": [ + "private _${1:name}: ${3:Type}", + "get${2:Name}(): ${3:Type} {", + " return this._${1:name}", + "}", + "set${2:Name}(${1:name}: ${3:Type}) {", + " this._${1:name} = ${1:name}", + "}" + ] + }, + "roprop": { + "scope": "typescript", + "prefix": "ro", + "body": [ + "private readonly _${1:name}: ${3:Type};", + "get${2:Name}(): ${3:Type} {", + " return this._${1:name}", + "}" + ] + }, + "vs": { + "scope": "typescript", + "prefix": "vs", + "body": [ + "vi.spyOn(${1:class}, \"${2:method}\")${3:.mock$4};" + ] + }, + "faker lorem word": { + "scope": "typescript", + "prefix": "flw", + "body": [ + "faker.lorem.word();" + ] + } +} diff --git a/.config/nvim/lua/goodhumored/plugins/snippets/luasnip.lua b/.config/nvim/lua/goodhumored/plugins/snippets/luasnip.lua index ff4d3cd..c1c4b4d 100644 --- a/.config/nvim/lua/goodhumored/plugins/snippets/luasnip.lua +++ b/.config/nvim/lua/goodhumored/plugins/snippets/luasnip.lua @@ -7,7 +7,354 @@ return { config = function() -- load snippets from path/of/your/nvim/config/my-cool-snippets require("luasnip.loaders.from_vscode").lazy_load({ - paths = { "~/.config/Code/User/snippets/typescript.code-snippets" }, + paths = { + -- "~/.config/Code/User/snippets/typescript.code-snippets", + -- "~/.config/nvim/lua/goodhumored/plugins/snippets/code-snippets", + "./code-snippets", + }, + }) + require("luasnip.loaders.from_snipmate").lazy_load() + local ls = require("luasnip") + local s = ls.snippet + local sn = ls.snippet_node + local t = ls.text_node + local i = ls.insert_node + local f = ls.function_node + local c = ls.choice_node + local d = ls.dynamic_node + local r = ls.restore_node + local l = require("luasnip.extras").lambda + local rep = require("luasnip.extras").rep + local p = require("luasnip.extras").partial + local m = require("luasnip.extras").match + local n = require("luasnip.extras").nonempty + local dl = require("luasnip.extras").dynamic_lambda + local fmt = require("luasnip.extras.fmt").fmt + local fmta = require("luasnip.extras.fmt").fmta + local types = require("luasnip.util.types") + local conds = require("luasnip.extras.conditions") + local conds_expand = require("luasnip.extras.conditions.expand") + + local function copy(args) + return args[1] + end + + -- Make sure to not pass an invalid command, as io.popen() may write over nvim-text. + local function bash(_, _, command) + local file = io.popen(command, "r") + local res = {} + for line in file:lines() do + table.insert(res, line) + end + return res + end + + -- Returns a snippet_node wrapped around an insertNode whose initial + -- text value is set to the current date in the desired format. + local date_input = function(args, snip, old_state, fmt) + local fmt = fmt or "%Y-%m-%d" + return sn(nil, i(1, os.date(fmt))) + end + + local ts_snippets = { + s("prr", { + t("private readonly _"), + i(1, "field"), + t(";"), + }), + s("prr", { + t("private readonly _"), + i(1, "field"), + t(";"), + }), + } + + local react_snippets = { + s("comp", { + t({ + 'import React from "react";', + "", + "export default function ", + }), + i(1), + t({ "({className}: {className?: string}) {", "\treturn (", "\t\t<" }), + i(2, "div"), + t({ " className={`${className}`}>", "\t\t\t" }), + i(3), + t({ "", "\t\t", "\t)", "}" }), + }), + } + + ls.add_snippets("typescript", ts_snippets) + ls.add_snippets("typescriptreact", react_snippets) + ls.add_snippets("all", { + -- trigger is `fn`, second argument to snippet-constructor are the nodes to insert into the buffer on expansion. + s("fn", { + -- Simple static text. + t("//Parameters: "), + -- function, first parameter is the function, second the Placeholders + -- whose text it gets as input. + f(copy, 2), + t({ "", "function " }), + -- Placeholder/Insert. + i(1), + t("("), + -- Placeholder with initial text. + i(2, "int foo"), + -- Linebreak + t({ ") {", "\t" }), + -- Last Placeholder, exit Point of the snippet. + i(0), + t({ "", "}" }), + }), + s("class", { + -- Choice: Switch between two different Nodes, first parameter is its position, second a list of nodes. + c(1, { + t("public "), + t("private "), + }), + t("class "), + i(2), + t(" "), + c(3, { + t("{"), + -- sn: Nested Snippet. Instead of a trigger, it has a position, just like insertNodes. !!! These don't expect a 0-node!!!! + -- Inside Choices, Nodes don't need a position as the choice node is the one being jumped to. + sn(nil, { + t("extends "), + -- restoreNode: stores and restores nodes. + -- pass position, store-key and nodes. + r(1, "other_class", i(1)), + t(" {"), + }), + sn(nil, { + t("implements "), + -- no need to define the nodes for a given key a second time. + r(1, "other_class"), + t(" {"), + }), + }), + t({ "", "\t" }), + i(0), + t({ "", "}" }), + }), + -- Alternative printf-like notation for defining snippets. It uses format + -- string with placeholders similar to the ones used with Python's .format(). + s( + "fmt1", + fmt("To {title} {} {}.", { + i(2, "Name"), + i(3, "Surname"), + title = c(1, { t("Mr."), t("Ms.") }), + }) + ), + -- To escape delimiters use double them, e.g. `{}` -> `{{}}`. + -- Multi-line format strings by default have empty first/last line removed. + -- Indent common to all lines is also removed. Use the third `opts` argument + -- to control this behaviour. + s( + "fmt2", + fmt( + [[ + foo({1}, {3}) {{ + return {2} * {4} + }} + ]], + { + i(1, "x"), + rep(1), + i(2, "y"), + rep(2), + } + ) + ), + -- Empty placeholders are numbered automatically starting from 1 or the last + -- value of a numbered placeholder. Named placeholders do not affect numbering. + s( + "fmt3", + fmt("{} {a} {} {1} {}", { + t("1"), + t("2"), + a = t("A"), + }) + ), + -- The delimiters can be changed from the default `{}` to something else. + s("fmt4", fmt("foo() { return []; }", i(1, "x"), { delimiters = "[]" })), + -- `fmta` is a convenient wrapper that uses `<>` instead of `{}`. + s("fmt5", fmta("foo() { return <>; }", i(1, "x"))), + -- By default all args must be used. Use strict=false to disable the check + s("fmt6", fmt("use {} only", { t("this"), t("not this") }, { strict = false })), + -- Use a dynamicNode to interpolate the output of a + -- function (see date_input above) into the initial + -- value of an insertNode. + s("novel", { + t("It was a dark and stormy night on "), + d(1, date_input, {}, { user_args = { "%A, %B %d of %Y" } }), + t(" and the clocks were striking thirteen."), + }), + -- Parsing snippets: First parameter: Snippet-Trigger, Second: Snippet body. + -- Placeholders are parsed into choices with 1. the placeholder text(as a snippet) and 2. an empty string. + -- This means they are not SELECTed like in other editors/Snippet engines. + ls.parser.parse_snippet("lspsyn", "Wow! This ${1:Stuff} really ${2:works. ${3:Well, a bit.}}"), + + -- When wordTrig is set to false, snippets may also expand inside other words. + ls.parser.parse_snippet({ trig = "te", wordTrig = false }, "${1:cond} ? ${2:true} : ${3:false}"), + + -- When regTrig is set, trig is treated like a pattern, this snippet will expand after any number. + ls.parser.parse_snippet({ trig = "%d", regTrig = true }, "A Number!!"), + -- Using the condition, it's possible to allow expansion only in specific cases. + s("cond", { + t("will only expand in c-style comments"), + }, { + condition = function(line_to_cursor, matched_trigger, captures) + -- optional whitespace followed by // + return line_to_cursor:match("%s*//") + end, + }), + -- there's some built-in conditions in "luasnip.extras.conditions.expand" and "luasnip.extras.conditions.show". + s("cond2", { + t("will only expand at the beginning of the line"), + }, { + condition = conds_expand.line_begin, + }), + s("cond3", { + t("will only expand at the end of the line"), + }, { + condition = conds_expand.line_end, + }), + -- on conditions some logic operators are defined + s("cond4", { + t("will only expand at the end and the start of the line"), + }, { + -- last function is just an example how to make own function objects and apply operators on them + condition = conds_expand.line_end + conds_expand.line_begin * conds.make_condition(function() + return true + end), + }), + -- The last entry of args passed to the user-function is the surrounding snippet. + s( + { trig = "a%d", regTrig = true }, + f(function(_, snip) + return "Triggered with " .. snip.trigger .. "." + end, {}) + ), + -- It's possible to use capture-groups inside regex-triggers. + s( + { trig = "b(%d)", regTrig = true }, + f(function(_, snip) + return "Captured Text: " .. snip.captures[1] .. "." + end, {}) + ), + s({ trig = "c(%d+)", regTrig = true }, { + t("will only expand for even numbers"), + }, { + condition = function(line_to_cursor, matched_trigger, captures) + return tonumber(captures[1]) % 2 == 0 + end, + }), + -- Use a function to execute any shell command and print its text. + s("bash", f(bash, {}, { user_args = { "ls" } })), + -- Short version for applying String transformations using function nodes. + s("transform", { + i(1, "initial text"), + t({ "", "" }), + -- lambda nodes accept an l._1,2,3,4,5, which in turn accept any string transformations. + -- This list will be applied in order to the first node given in the second argument. + l(l._1:match("[^i]*$"):gsub("i", "o"):gsub(" ", "_"):upper(), 1), + }), + + s("transform2", { + i(1, "initial text"), + t("::"), + i(2, "replacement for e"), + t({ "", "" }), + -- Lambdas can also apply transforms USING the text of other nodes: + l(l._1:gsub("e", l._2), { 1, 2 }), + }), + s({ trig = "trafo(%d+)", regTrig = true }, { + -- env-variables and captures can also be used: + l(l.CAPTURE1:gsub("1", l.TM_FILENAME), {}), + }), + -- Set store_selection_keys = "" (for example) in your + -- luasnip.config.setup() call to populate + -- TM_SELECTED_TEXT/SELECT_RAW/SELECT_DEDENT. + -- In this case: select a URL, hit Tab, then expand this snippet. + s("link_url", { + t(''), + i(1), + t(""), + i(0), + }), + -- Shorthand for repeating the text in a given node. + s("repeat", { i(1, "text"), t({ "", "" }), rep(1) }), + -- Directly insert the ouput from a function evaluated at runtime. + s("part", p(os.date, "%Y")), + -- use matchNodes (`m(argnode, condition, then, else)`) to insert text + -- based on a pattern/function/lambda-evaluation. + -- It's basically a shortcut for simple functionNodes: + s("mat", { + i(1, { "sample_text" }), + t(": "), + m(1, "%d", "contains a number", "no number :("), + }), + -- The `then`-text defaults to the first capture group/the entire + -- match if there are none. + s("mat2", { + i(1, { "sample_text" }), + t(": "), + m(1, "[abc][abc][abc]"), + }), + -- It is even possible to apply gsubs' or other transformations + -- before matching. + s("mat3", { + i(1, { "sample_text" }), + t(": "), + m(1, l._1:gsub("[123]", ""):match("%d"), "contains a number that isn't 1, 2 or 3!"), + }), + -- `match` also accepts a function in place of the condition, which in + -- turn accepts the usual functionNode-args. + -- The condition is considered true if the function returns any + -- non-nil/false-value. + -- If that value is a string, it is used as the `if`-text if no if is explicitly given. + s("mat4", { + i(1, { "sample_text" }), + t(": "), + m(1, function(args) + -- args is a table of multiline-strings (as usual). + return (#args[1][1] % 2 == 0 and args[1]) or nil + end), + }), + -- The nonempty-node inserts text depending on whether the arg-node is + -- empty. + s("nempty", { + i(1, "sample_text"), + n(1, "i(1) is not empty!"), + }), + -- dynamic lambdas work exactly like regular lambdas, except that they + -- don't return a textNode, but a dynamicNode containing one insertNode. + -- This makes it easier to dynamically set preset-text for insertNodes. + s("dl1", { + i(1, "sample_text"), + t({ ":", "" }), + dl(2, l._1, 1), + }), + -- Obviously, it's also possible to apply transformations, just like lambdas. + s("dl2", { + i(1, "sample_text"), + i(2, "sample_text_2"), + t({ "", "" }), + dl(3, l._1:gsub("\n", " linebreak ") .. l._2, { 1, 2 }), + }), + }, { + key = "all", }) end, } diff --git a/.config/nvim/lua/goodhumored/plugins/statusline-surround-around-inside.lua b/.config/nvim/lua/goodhumored/plugins/statusline-surround-around-inside.lua deleted file mode 100644 index 958d102..0000000 --- a/.config/nvim/lua/goodhumored/plugins/statusline-surround-around-inside.lua +++ /dev/null @@ -1,37 +0,0 @@ -return { -- Collection of various small independent plugins/modules - "echasnovski/mini.nvim", - config = function() - -- Better Around/Inside textobjects - -- - -- Examples: - -- - va) - [V]isually select [A]round [)]paren - -- - yinq - [Y]ank [I]nside [N]ext [Q]uote - -- - ci' - [C]hange [I]nside [']quote - require("mini.ai").setup({ n_lines = 500 }) - - -- Add/delete/replace surroundings (brackets, quotes, etc.) - -- - -- - saiw) - [S]urround [A]dd [I]nner [W]ord [)]Paren - -- - sd' - [S]urround [D]elete [']quotes - -- - sr)' - [S]urround [R]eplace [)] ['] - require("mini.surround").setup() - - -- Simple and easy statusline. - -- You could remove this setup call if you don't like it, - -- and try some other statusline plugin - local statusline = require("mini.statusline") - -- set use_icons to true if you have a Nerd Font - statusline.setup({ use_icons = vim.g.have_nerd_font }) - - -- You can configure sections in the statusline by overriding their - -- default behavior. For example, here we set the section for - -- cursor location to LINE:COLUMN - ---@diagnostic disable-next-line: duplicate-set-field - statusline.section_location = function() - return "%2l:%-2v" - end - - -- ... and there is more! - -- Check out: https://github.com/echasnovski/mini.nvim - end, -} diff --git a/.config/nvim/lua/goodhumored/plugins/colorscheme.lua b/.config/nvim/lua/goodhumored/plugins/theme/colorscheme.lua.disable similarity index 100% rename from .config/nvim/lua/goodhumored/plugins/colorscheme.lua rename to .config/nvim/lua/goodhumored/plugins/theme/colorscheme.lua.disable diff --git a/.config/nvim/lua/goodhumored/plugins/theme/gruvbox.lua b/.config/nvim/lua/goodhumored/plugins/theme/gruvbox.lua new file mode 100644 index 0000000..44b8731 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/theme/gruvbox.lua @@ -0,0 +1,32 @@ +return { + "ellisonleao/gruvbox.nvim", + priority = 1000, + config = function() + require("gruvbox").setup({ + terminal_colors = true, -- add neovim terminal colors + undercurl = true, + underline = true, + bold = true, + italic = { + strings = true, + emphasis = true, + comments = true, + operators = false, + folds = true, + }, + strikethrough = true, + invert_selection = false, + invert_signs = false, + invert_tabline = false, + invert_intend_guides = false, + inverse = true, -- invert background for search, diffs, statuslines and errors + contrast = "", -- can be "hard", "soft" or empty string + palette_overrides = {}, + overrides = {}, + dim_inactive = false, + transparent_mode = false, + }) + vim.o.background = "dark" + vim.cmd("colorscheme gruvbox") + end, +} diff --git a/.config/nvim/lua/goodhumored/plugins/kanagawa-color-scheme.lua.disabled b/.config/nvim/lua/goodhumored/plugins/theme/kanagawa-color-scheme.lua.disable similarity index 100% rename from .config/nvim/lua/goodhumored/plugins/kanagawa-color-scheme.lua.disabled rename to .config/nvim/lua/goodhumored/plugins/theme/kanagawa-color-scheme.lua.disable diff --git a/.config/nvim/lua/goodhumored/plugins/tree.lua b/.config/nvim/lua/goodhumored/plugins/tree.lua index 9ad0deb..66a201d 100644 --- a/.config/nvim/lua/goodhumored/plugins/tree.lua +++ b/.config/nvim/lua/goodhumored/plugins/tree.lua @@ -6,7 +6,55 @@ return { "nvim-tree/nvim-web-devicons", }, config = function() - require("nvim-tree").setup({}) + local api = require("nvim-tree.api") + + local function edit_or_open() + local node = api.tree.get_node_under_cursor() + + if node.nodes ~= nil then + -- expand or collapse folder + api.node.open.edit() + else + -- open file + api.node.open.edit() + -- Close the tree if file was opened + api.tree.close() + end + end + + -- open as vsplit on current node + local function vsplit_preview() + local node = api.tree.get_node_under_cursor() + + if node.nodes ~= nil then + -- expand or collapse folder + api.node.open.edit() + else + -- open file as vsplit + api.node.open.vertical() + end + + -- Finally refocus on tree if it was lost + api.tree.focus() + end + local function collapse_folder() + local node = api.tree.get_node_under_cursor() + api.node.navigate.parent(node) + api.node.open.edit(node.parent) + end + require("nvim-tree").setup({ + on_attach = function(bufnr) + local function opts(desc) + return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true } + end + -- default mappings + api.config.mappings.default_on_attach(bufnr) + vim.keymap.set("n", "l", edit_or_open, opts("Edit Or Open")) + vim.keymap.set("n", "L", vsplit_preview, opts("Vsplit Preview")) + vim.keymap.set("n", "h", collapse_folder, opts("Close")) + vim.keymap.set("n", "H", api.tree.collapse_all, opts("Collapse All")) + end, + }) local api = require("nvim-tree.api") vim.keymap.set("n", "e", api.tree.toggle, { desc = "[E]xplorer" }) vim.keymap.set("n", "E", function() diff --git a/.config/nvim/lua/goodhumored/plugins/zen-mode.lua b/.config/nvim/lua/goodhumored/plugins/zen-mode.lua new file mode 100644 index 0000000..d783d84 --- /dev/null +++ b/.config/nvim/lua/goodhumored/plugins/zen-mode.lua @@ -0,0 +1,87 @@ +return -- Lua +{ + "folke/zen-mode.nvim", + opts = { + window = { + backdrop = 0.95, -- shade the backdrop of the Zen window. Set to 1 to keep the same as Normal + -- height and width can be: + -- * an absolute number of cells when > 1 + -- * a percentage of the width / height of the editor when <= 1 + -- * a function that returns the width or the height + width = 120, -- width of the Zen window + height = 1, -- height of the Zen window + -- by default, no options are changed for the Zen window + -- uncomment any of the options below, or add other vim.wo options you want to apply + options = { + -- signcolumn = "no", -- disable signcolumn + -- number = false, -- disable number column + -- relativenumber = false, -- disable relative numbers + -- cursorline = false, -- disable cursorline + -- cursorcolumn = false, -- disable cursor column + -- foldcolumn = "0", -- disable fold column + -- list = false, -- disable whitespace characters + }, + }, + plugins = { + -- disable some global vim options (vim.o...) + -- comment the lines to not apply the options + options = { + enabled = true, + ruler = false, -- disables the ruler text in the cmd line area + showcmd = false, -- disables the command in the last line of the screen + -- you may turn on/off statusline in zen mode by setting 'laststatus' + -- statusline will be shown only if 'laststatus' == 3 + laststatus = 0, -- turn off the statusline in zen mode + }, + twilight = { enabled = true }, -- enable to start Twilight when zen mode opens + gitsigns = { enabled = false }, -- disables git signs + tmux = { enabled = true }, -- disables the tmux statusline + todo = { enabled = false }, -- if set to "true", todo-comments.nvim highlights will be disabled + -- this will change the font size on kitty when in zen mode + -- to make this work, you need to set the following kitty options: + -- - allow_remote_control socket-only + -- - listen_on unix:/tmp/kitty + kitty = { + enabled = false, + font = "+8", -- font size increment + }, + -- this will change the font size on alacritty when in zen mode + -- requires Alacritty Version 0.10.0 or higher + -- uses `alacritty msg` subcommand to change font size + alacritty = { + enabled = false, + font = "18", -- font size + }, + -- this will change the font size on wezterm when in zen mode + -- See alse also the Plugins/Wezterm section in this projects README + wezterm = { + enabled = false, + -- can be either an absolute font size or the number of incremental steps + font = "+4", -- (10% increase per step) + }, + -- this will change the scale factor in Neovide when in zen mode + -- See alse also the Plugins/Wezterm section in this projects README + neovide = { + enabled = false, + -- Will multiply the current scale factor by this number + scale = 1.2, + -- disable the Neovide animations while in Zen mode + disable_animations = { + neovide_animation_length = 0, + neovide_cursor_animate_command_line = false, + neovide_scroll_animation_length = 0, + neovide_position_animation_length = 0, + neovide_cursor_animation_length = 0, + neovide_cursor_vfx_mode = "", + }, + }, + }, + -- callback where you can add custom code when the Zen window opens + on_open = function(win) end, + -- callback where you can add custom code when the Zen window closes + on_close = function() end, + }, + keys = { + { "tz", ":ZenMode", desc = "[T]oggle [Z]en" }, + }, +} diff --git a/.config/nvim/lua/goodhumored/snippets/typescript.snippets b/.config/nvim/lua/goodhumored/snippets/typescript.snippets new file mode 100644 index 0000000..bde6643 --- /dev/null +++ b/.config/nvim/lua/goodhumored/snippets/typescript.snippets @@ -0,0 +1,6 @@ +# comment +# snippet +# +snippet if C-style if +if ($1) + $0 diff --git a/.config/nvim/lua/goodhumored/snippets/typescriptreact.snippets b/.config/nvim/lua/goodhumored/snippets/typescriptreact.snippets new file mode 100644 index 0000000..bde6643 --- /dev/null +++ b/.config/nvim/lua/goodhumored/snippets/typescriptreact.snippets @@ -0,0 +1,6 @@ +# comment +# snippet +# +snippet if C-style if +if ($1) + $0 diff --git a/.config/waybar/custom/playerctl.sh b/.config/waybar/custom/playerctl.sh index 60fc0e4..e9d0f2a 100755 --- a/.config/waybar/custom/playerctl.sh +++ b/.config/waybar/custom/playerctl.sh @@ -1,7 +1,7 @@ -title=$(playerctl metadata --format '{{markup_escape(artist)}} - {{markup_escape(title)}}') -position=$(playerctl metadata --format '{{position}}') -length=$(playerctl metadata --format '{{mpris:length}}') -artUrl=$(playerctl metadata --format "{{mpris:artUrl}}") +title=$(playerctl --player=$(cat ~/.config/chosen_player) metadata --format '{{markup_escape(artist)}} - {{markup_escape(title)}}') +position=$(playerctl --player=$(cat ~/.config/chosen_player) metadata --format '{{position}}') +length=$(playerctl --player=$(cat ~/.config/chosen_player) metadata --format '{{mpris:length}}') +artUrl=$(playerctl --player=$(cat ~/.config/chosen_player) metadata --format "{{mpris:artUrl}}") if [[ -n "$artUrl" ]]; then cover=$(echo "$artUrl" | sed "s/file:\/\///g") diff --git a/.config/waybar/modules.json b/.config/waybar/modules.json index 6020643..33162c6 100644 --- a/.config/waybar/modules.json +++ b/.config/waybar/modules.json @@ -19,11 +19,24 @@ "*": 5 } }, -// ╭───────────────────────────────────────────────────────────╮ -// │ pomodoro │ -// ╰───────────────────────────────────────────────────────────╯ + // ╭───────────────────────────────────────────────────────────╮ + // │ pomodoro │ + // ╰───────────────────────────────────────────────────────────╯ "custom/pomodoro": { - "format-icons": ["🕛", "🕐", "🕑", "🕒", "🕓", "🕔", "🕕", "🕖", "🕗", "🕘", "🕙", "🕚"], + "format-icons": [ + "🕛", + "🕐", + "🕑", + "🕒", + "🕓", + "🕔", + "🕕", + "🕖", + "🕗", + "🕘", + "🕙", + "🕚" + ], "return-type": "json", "tooltip": true, "format": "{icon} {}", @@ -33,9 +46,9 @@ "exec": "~/.config/waybar/custom/pomodoro.sh", "interval": 1 }, - // ╭───────────────────────────────────────────────────────────╮ - // │ player │ - // ╰───────────────────────────────────────────────────────────╯ + // ╭───────────────────────────────────────────────────────────╮ + // │ player │ + // ╰───────────────────────────────────────────────────────────╯ "group/playerctl": { "orientation": "inherit", "children-class": "playerctl", @@ -46,29 +59,26 @@ "custom/playerctl-title" ] }, - "custom/playerctl-title": { "interval": 2, "format": "{}", "hide-empty-text": true, "return-type": "json", "exec": "~/.config/waybar/custom/playerctl.sh", - "on-click": "playerctl play-pause", - "on-scroll-up": "playerctl position 1+", - "on-scroll-down": "playerctl position 1-", + "on-click": "playerctl --player=$(cat ~/.config/chosen_player) play-pause", + "on-scroll-up": "playerctl --player=$(cat ~/.config/chosen_player) position 1+", + "on-scroll-down": "playerctl --player=$(cat ~/.config/chosen_player) position 1-", }, - "custom/playerctl-prev": { "interval": 1, "format": "", "tooltip-format": "previous track", "return-type": "json", - "exec": "playerctl metadata --format '{\"alt\": \"{{status}}\", \"class\": \"{{status}}\"}}'", - "on-click": "playerctl previous", - "on-scroll-up": "playerctl position 1+", - "on-scroll-down": "playerctl position 1-", + "exec": "playerctl --player=$(cat ~/.config/chosen_player) metadata --format '{\"alt\": \"{{status}}\", \"class\": \"{{status}}\"}}'", + "on-click": "playerctl --player=$(cat ~/.config/chosen_player) previous", + "on-scroll-up": "playerctl --player=$(cat ~/.config/chosen_player) position 1+", + "on-scroll-down": "playerctl --player=$(cat ~/.config/chosen_player) position 1-", }, - "custom/playerctl-pause-play": { "interval": 1, "format": "{icon}", @@ -78,23 +88,21 @@ "Paused": "" }, "return-type": "json", - "exec": "playerctl metadata --format '{\"alt\": \"{{status}}\", \"class\": \"{{status}}\"}}'", - "on-click": "playerctl play-pause", - "on-scroll-up": "playerctl position 1+", - "on-scroll-down": "playerctl position 1-", + "exec": "playerctl --player=$(cat ~/.config/chosen_player) metadata --format '{\"alt\": \"{{status}}\", \"class\": \"{{status}}\"}}'", + "on-click": "playerctl --player=$(cat ~/.config/chosen_player) play-pause", + "on-scroll-up": "playerctl --player=$(cat ~/.config/chosen_player) position 1+", + "on-scroll-down": "playerctl --player=$(cat ~/.config/chosen_player) position 1-", }, - "custom/playerctl-next": { "interval": 1, "format": "", "tooltip-format": "next track", "return-type": "json", - "exec": "playerctl metadata --format '{\"alt\": \"{{status}}\", \"class\": \"{{status}}\"}}'", - "on-click": "playerctl next", - "on-scroll-up": "playerctl position 1+", - "on-scroll-down": "playerctl position 1-", + "exec": "playerctl --player=$(cat ~/.config/chosen_player) metadata --format '{\"alt\": \"{{status}}\", \"class\": \"{{status}}\"}}'", + "on-click": "playerctl --player=$(cat ~/.config/chosen_player) next", + "on-scroll-up": "playerctl --player=$(cat ~/.config/chosen_player) position 1+", + "on-scroll-down": "playerctl --player=$(cat ~/.config/chosen_player) position 1-", }, - // ╭───────────────────────────────────────────────────────────╮ // │ sunset (night light) │ // ╰───────────────────────────────────────────────────────────╯ @@ -112,7 +120,6 @@ "exec-if": "/dotfiles/.config/scripts/sunset.sh check", "signal": 6 }, - // Taskbar "wlr/taskbar": { "format": "{icon}", @@ -120,7 +127,10 @@ "tooltip-format": "{title}", "on-click": "activate", "on-click-middle": "close", - "ignore-list": ["Alacritty", "kitty"], + "ignore-list": [ + "Alacritty", + "kitty" + ], "app_ids-mapping": { "firefoxdeveloperedition": "firefox-developer-edition" }, @@ -146,7 +156,6 @@ "on-click-right": "hyprctl switchxkblayout at-translated-set-2-keyboard prev", "interval": 1 }, - // Wofi Application Launcher "custom/appmenuicon": { "format": "", @@ -154,38 +163,32 @@ "on-click-right": "~/dotfiles/hypr/scripts/keybindings.sh", "tooltip-format": "Left: Open the application launcher\nRight: Show all keybindings" }, - // Power Menu "custom/exit": { "format": "", "on-click": "wlogout", "tooltip-format": "Power Menu" }, - // System tray "tray": { "icon-size": 21, "spacing": 10 }, - // Clock "clock": { "format": "{:%H:%M:%S\r%d.%m.%Y}", "interval": 1, }, - // CPU "cpu": { "format": "/ C {usage}% ", "on-click": "~/dotfiles/.settings/systeminfo.sh" }, - // Memory "memory": { "format": "/ M {}% ", "on-click": "~/dotfiles/.settings/systeminfo.sh" }, - // Harddisc space used "disk": { "interval": 30, @@ -193,7 +196,6 @@ "path": "/", "on-click": "~/dotfiles/.settings/systeminfo.sh" }, - // Group Hardware "group/hardware": { "orientation": "inherit", @@ -202,9 +204,14 @@ "children-class": "not-memory", "transition-left-to-right": false }, - "modules": ["custom/system", "disk", "cpu", "memory", "hyprland/language"] + "modules": [ + "custom/system", + "disk", + "cpu", + "memory", + "hyprland/language" + ] }, - // Group Tools "group/tools": { "orientation": "inherit", @@ -220,7 +227,6 @@ "custom/hyprshade" ] }, - // Battery "battery": { "states": { @@ -234,9 +240,14 @@ "format-alt": "{icon} {time}", // "format-good": "", // An empty format will hide the module // "format-full": "", - "format-icons": [" ", " ", " ", " ", " "] + "format-icons": [ + " ", + " ", + " ", + " ", + " " + ] }, - // Pulseaudio "pulseaudio": { // "scroll-step": 1, // %, can be a float @@ -253,11 +264,14 @@ "phone": " ", "portable": " ", "car": " ", - "default": ["", "", ""] + "default": [ + "", + "", + "" + ] }, "on-click": "pavucontrol" }, - // Bluetooth "bluetooth": { "format": " {status}", diff --git a/.config/yazi/bookmark b/.config/yazi/bookmark new file mode 100644 index 0000000..37ce8df --- /dev/null +++ b/.config/yazi/bookmark @@ -0,0 +1,8 @@ +Uni /home/goodhumored/Uni/ u +trash /run/user/1000/kio-fuse-LJbUkF/trash/ t +side-hustle /home/goodhumored/side-hustle/ s +Notes /home/goodhumored/notes/ n +Job /home/goodhumored/Job/ j +halloween /home/goodhumored/side-hustle/memecoins/halloween/ h +Downloads /home/goodhumored/Downloads/ d +dipal /home/goodhumored/Job/dipal/ D diff --git a/.config/yazi/init.lua b/.config/yazi/init.lua new file mode 100644 index 0000000..3eed73c --- /dev/null +++ b/.config/yazi/init.lua @@ -0,0 +1,59 @@ +-- You can configure your bookmarks by lua language +local bookmarks = {} + +function path(...) + local args = { ... } + local path_sep = package.config:sub(1, 1) + -- Trim leading slashes from the first element + args[1] = args[1]:gsub("^/*", "") + -- Trim trailing slashes from the last element + args[#args] = args[#args]:gsub("/*$", "") + -- Join the arguments with the path separator + return path_sep .. table.concat(args, path_sep) +end + +local home_path = os.getenv("HOME") +table.insert(bookmarks, { + tag = "Downloads", + path = path(home_path, "Downloads", ""), + key = "d", +}) +table.insert(bookmarks, { + tag = "Notes", + path = path(home_path, "notes", ""), + key = "n", +}) +table.insert(bookmarks, { + tag = "Job", + path = path(home_path, "Job", ""), + key = "j", +}) +table.insert(bookmarks, { + tag = "Uni", + path = path(home_path, "Uni", ""), + key = "u", +}) +table.insert(bookmarks, { + tag = "side-hustle", + path = path(home_path, "side-hustle", ""), + key = "s", +}) +table.insert(bookmarks, { + tag = "trash", + path = "/run/user/1000/kio-fuse-LJbUkF/trash/", + key = "t", +}) + +require("yamb"):setup({ + -- Optional, the path ending with path seperator represents folder. + bookmarks = bookmarks, + -- Optional, recieve notification everytime you jump. + jump_notify = true, + -- Optional, the cli of fzf. + cli = "fzf", + -- Optional, a string used for randomly generating keys, where the preceding characters have higher priority. + keys = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + -- Optional, the path of bookmarks + path = (ya.target_family() == "windows" and os.getenv("APPDATA") .. "\\yazi\\config\\bookmark") + or (os.getenv("HOME") .. "/.config/yazi/bookmark"), +}) diff --git a/.config/yazi/keymap.toml b/.config/yazi/keymap.toml new file mode 100644 index 0000000..5090425 --- /dev/null +++ b/.config/yazi/keymap.toml @@ -0,0 +1,67 @@ +[[manager.prepend_keymap]] +on = [ "" ] +run = "enter" +desc = "Enter the child directory" + +[[manager.prepend_keymap]] +on = [""] +run = "back" +desc = "Jump back" + +[[manager.prepend_keymap]] +on = [ "g", "c" ] +run = "cd ~/dotfiles/" +desc = "Go to the config directory" + +# ───────────────────────────── jump to char ───────────────────────────── +[[manager.prepend_keymap]] +on = "f" +run = "plugin jump-to-char" +desc = "Jump to char" + +# ─────────────────────────────── Compress ─────────────────────────────── +[[manager.prepend_keymap]] +on = ["C"] +run = "plugin ouch --args=zip" +desc = "Compress with ouch" + +# ────────────────────────────── bookmarks ──────────────────────────── +[[manager.prepend_keymap]] +on = [ "m" ] +run = "plugin yamb --args=save" +desc = "Add bookmark" + +[[manager.prepend_keymap]] +on = [ "'" ] +run = "plugin yamb --args=jump_by_key" +desc = "Jump bookmark by key" + +[[manager.prepend_keymap]] +on = [ "\"" ] +run = "plugin yamb --args=jump_by_fzf" +desc = "Jump bookmark by fzf" + +[[manager.prepend_keymap]] +on = [ "b", "d" ] +run = "plugin yamb --args=delete_by_key" +desc = "Delete bookmark by key" + +[[manager.prepend_keymap]] +on = [ "b", "f" ] +run = "plugin yamb --args=delete_by_fzf" +desc = "Delete bookmark by fzf" + +[[manager.prepend_keymap]] +on = [ "b", "D" ] +run = "plugin yamb --args=delete_all" +desc = "Delete all bookmarks" + +[[manager.prepend_keymap]] +on = [ "b", "r" ] +run = "plugin yamb --args=rename_by_key" +desc = "Rename bookmark by key" + +[[manager.prepend_keymap]] +on = [ "b", "R" ] +run = "plugin yamb --args=rename_by_fzf" +desc = "Rename bookmark by fzf" diff --git a/.config/yazi/package.toml b/.config/yazi/package.toml new file mode 100644 index 0000000..239a3df --- /dev/null +++ b/.config/yazi/package.toml @@ -0,0 +1,5 @@ +[plugin] +deps = [{ use = "h-hg/yamb", rev = "0598b8d" }, { use = "dedukun/bookmarks", rev = "600f87c" }, { use = "Reledia/miller", rev = "40e0265" }, { use = "yazi-rs/plugins:jump-to-char", rev = "35100e7" }, { use = "ndtoan96/ouch", rev = "251da69" }] + +[flavor] +deps = [] diff --git a/.config/yazi/plugins/bookmarks.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY b/.config/yazi/plugins/bookmarks.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY new file mode 100644 index 0000000..e69de29 diff --git a/.config/yazi/plugins/bookmarks.yazi/LICENSE b/.config/yazi/plugins/bookmarks.yazi/LICENSE new file mode 100644 index 0000000..f8ead01 --- /dev/null +++ b/.config/yazi/plugins/bookmarks.yazi/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2024 dedukun + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/.config/yazi/plugins/bookmarks.yazi/README.md b/.config/yazi/plugins/bookmarks.yazi/README.md new file mode 100644 index 0000000..06c7658 --- /dev/null +++ b/.config/yazi/plugins/bookmarks.yazi/README.md @@ -0,0 +1,132 @@ +# bookmarks.yazi + +A [Yazi](https://github.com/sxyazi/yazi) plugin that adds the basic functionality of [vi-like marks](https://neovim.io/doc/user/motion.html#mark-motions). + +https://github.com/dedukun/bookmarks.yazi/assets/25795432/9a9fe345-dd06-442e-99f1-8475ab22fad5 + +## Requirements + +- [Yazi](https://github.com/sxyazi/yazi) v0.3.0+ + +## Features + +- Create/delete bookmarks +- Custom Notifications +- `''` to go back to the previous folder +- Bookmarks persistence + +## Installation + +```sh +ya pack -a dedukun/bookmarks +``` + +## Configuration + +Add this to your `keymap.toml`: + +```toml +[[manager.prepend_keymap]] +on = [ "m" ] +run = "plugin bookmarks --args=save" +desc = "Save current position as a bookmark" + +[[manager.prepend_keymap]] +on = [ "'" ] +run = "plugin bookmarks --args=jump" +desc = "Jump to a bookmark" + +[[manager.prepend_keymap]] +on = [ "b", "d" ] +run = "plugin bookmarks --args=delete" +desc = "Delete a bookmark" + +[[manager.prepend_keymap]] +on = [ "b", "D" ] +run = "plugin bookmarks --args=delete_all" +desc = "Delete all bookmarks" +``` + +--- + +Additionally there are configurations that can be done using the plugin's `setup` function in Yazi's `init.lua`, i.e. `~/.config/yazi/init.lua`. +The following are the default configurations: + +```lua +-- ~/.config/yazi/init.lua +require("bookmarks"):setup({ + save_last_directory = false, -- DEPRECATED - will be removed in the future. Use `last_directory` + last_directory = { enable = false, persist = false }, + persist = "none", + desc_format = "full", + file_pick_mode = "hover", + notify = { + enable = false, + timeout = 1, + message = { + new = "New bookmark '' -> ''", + delete = "Deleted bookmark in ''", + delete_all = "Deleted all bookmarks", + }, + }, +}) +``` + +### `save_last_directory` + +When enabled, a new bookmark is automatically created in `'` which allows the user to jump back to +the last directory. + +***NOTE:*** This option is **DEPRECATED** and will be removed in the future in favor of `last_directory`. + +### `last_directory` + +When enabled, a new bookmark is automatically created in `'` which allows the user to jump back to +the last directory. + +There's also the option to enable persistence to this automatic bookmark. + +### `persist` + +When enabled the bookmarks will persist, i.e. if you close and reopen Yazi they will still be +present. + +There are three possible values for this option: + +| Value | Description | +| ------ | -------------------------------------------------------------------------------------------------------------------- | +| `none` | The default value, i.e., no persistance | +| `all` | All the bookmarks are saved in persistent memory | +| `vim` | This mode emulates the vim global marks, i.e., only the bookmarks in upper case (A-Z) are saved to persistent memory | + +### `desc_format` + +The format for the bookmark description. + +There are two possible values for this option: + +| Value | Description | +| -------- | ----------------------------------------------------------------------------------------------- | +| `full` | The default, it shows the full path of the bookmark, i.e., the parent folder + the hovered file | +| `parent` | Only shows the parent folder of the bookmark | + +### `file_pick_mode` + +The mode for choosing which directory to bookmark. + +There are two possible values for this option: + +| Value | Description | +| -------- | ----------------------------------------------------------------------------------------------- | +| `hover` | The default, it uses the path of the hovered file for new bookmarks | +| `parent` | Uses the path of the parent folder for new bookmarks | + +### `notify` + +When enabled, notifications will be shown when the user creates a new bookmark and deletes one or +all saved bookmarks. + +By default the notification has a 1 second timeout that can be changed with `notify.timeout`. + +Furthermore, you can customize the notification messages with `notify.message`. +For the `new` and `delete` messages, the `` and `` keywords can be used, which will be replaced by the respective new/deleted bookmark's associated key and folder. diff --git a/.config/yazi/plugins/bookmarks.yazi/init.lua b/.config/yazi/plugins/bookmarks.yazi/init.lua new file mode 100644 index 0000000..03a50c5 --- /dev/null +++ b/.config/yazi/plugins/bookmarks.yazi/init.lua @@ -0,0 +1,291 @@ +-- stylua: ignore +local SUPPORTED_KEYS = { + { on = "0"}, { on = "1"}, { on = "2"}, { on = "3"}, { on = "4"}, + { on = "5"}, { on = "6"}, { on = "7"}, { on = "8"}, { on = "9"}, + { on = "A"}, { on = "B"}, { on = "C"}, { on = "D"}, { on = "E"}, + { on = "F"}, { on = "G"}, { on = "H"}, { on = "I"}, { on = "J"}, + { on = "K"}, { on = "L"}, { on = "M"}, { on = "N"}, { on = "O"}, + { on = "P"}, { on = "Q"}, { on = "R"}, { on = "S"}, { on = "T"}, + { on = "U"}, { on = "V"}, { on = "W"}, { on = "X"}, { on = "Y"}, { on = "Z"}, + { on = "a"}, { on = "b"}, { on = "c"}, { on = "d"}, { on = "e"}, + { on = "f"}, { on = "g"}, { on = "h"}, { on = "i"}, { on = "j"}, + { on = "k"}, { on = "l"}, { on = "m"}, { on = "n"}, { on = "o"}, + { on = "p"}, { on = "q"}, { on = "r"}, { on = "s"}, { on = "t"}, + { on = "u"}, { on = "v"}, { on = "w"}, { on = "x"}, { on = "y"}, { on = "z"}, +} + +local _send_notification = ya.sync( + function(state, message) + ya.notify { + title = "Bookmarks", + content = message, + timeout = state.notify.timeout, + } + end +) + +local _get_real_index = ya.sync(function(state, idx) + for key, value in pairs(state.bookmarks) do + if value.on == SUPPORTED_KEYS[idx].on then + return key + end + end + return nil +end) + +local _get_bookmark_file = ya.sync(function(state) + local folder = cx.active.current + + if state.file_pick_mode == "parent" or not folder.hovered then + return { url = folder.cwd, is_parent = true } + end + return { url = folder.hovered.url, is_parent = false } +end) + +local _generate_description = ya.sync(function(state, file) + -- if this is true, we don't have information about the folder, so just return the folder url + if file.is_parent then + return tostring(file.url) + end + + if state.desc_format == "parent" then + return tostring(file.url:parent()) + end + -- full description + return tostring(file.url) +end) + +local _load_state = ya.sync(function(state) + ps.sub_remote("@bookmarks", function(body) + if not state.bookmarks and body then + state.bookmarks = {} + for _, value in pairs(body) do + table.insert(state.bookmarks, value) + end + end + end) +end) + +local _save_state = ya.sync(function(state, bookmarks) + if not bookmarks then + ps.pub_to(0, "@bookmarks", nil) + return + end + + local save_state = {} + if state.persist == "all" then + save_state = bookmarks + else -- VIM mode + local idx = 1 + for _, value in pairs(bookmarks) do + -- Only save bookmarks in upper case keys + if string.match(value.on, "%u") then + save_state[idx] = value + idx = idx + 1 + end + end + end + + ps.pub_to(0, "@bookmarks", save_state) +end) + +local _save_last_directory = ya.sync(function(state, persist) + if persist then + ps.sub_remote("@bookmarks-lastdir", function(body) state.curr_dir = body end) + end + + ps.sub("cd", function() + local file = _get_bookmark_file() + state.last_dir = state.curr_dir + + if persist and state.last_dir then + ps.pub_to(0, "@bookmarks-lastdir", state.last_dir) + end + + state.curr_dir = { + on = "'", + desc = _generate_description(file), + path = tostring(file.url), + is_parent = file.is_parent, + } + end) + + ps.sub("hover", function() + local file = _get_bookmark_file() + state.curr_dir.desc = _generate_description(file) + state.curr_dir.path = tostring(file.url) + end) +end) + +-- *********************************************** +-- **============= C O M M A N D S =============** +-- *********************************************** + +local save_bookmark = ya.sync(function(state, idx) + local file = _get_bookmark_file() + + state.bookmarks = state.bookmarks or {} + + local _idx = _get_real_index(idx) + if not _idx then + _idx = #state.bookmarks + 1 + end + + state.bookmarks[_idx] = { + on = SUPPORTED_KEYS[idx].on, + desc = _generate_description(file), + path = tostring(file.url), + is_parent = file.is_parent, + } + + if state.persist then + _save_state(state.bookmarks) + end + + if state.notify and state.notify.enable then + local message = state.notify.message.new + message, _ = message:gsub("", state.bookmarks[_idx].on) + message, _ = message:gsub("", state.bookmarks[_idx].desc) + _send_notification(message) + end +end) + +local all_bookmarks = ya.sync(function(state, append_last_dir) + local bookmarks = {} + + if state.bookmarks then + for _, value in pairs(state.bookmarks) do + table.insert(bookmarks, value) + end + end + + if append_last_dir and state.last_dir then + table.insert(bookmarks, state.last_dir) + end + + return bookmarks +end) + +local delete_bookmark = ya.sync(function(state, idx) + if state.notify and state.notify.enable then + local message = state.notify.message.delete + message, _ = message:gsub("", state.bookmarks[idx].on) + message, _ = message:gsub("", state.bookmarks[idx].desc) + _send_notification(message) + end + + table.remove(state.bookmarks, idx) + + if state.persist then + _save_state(state.bookmarks) + end +end) + +local delete_all_bookmarks = ya.sync(function(state) + state.bookmarks = nil + + if state.persist then + _save_state(nil) + end + + if state.notify and state.notify.enable then + _send_notification(state.notify.message.delete_all) + end +end) + +return { + entry = function(_, args) + local action = args[1] + if not action then + return + end + + if action == "save" then + local key = ya.which { cands = SUPPORTED_KEYS, silent = true } + if key then + save_bookmark(key) + end + return + end + + if action == "delete_all" then + return delete_all_bookmarks() + end + + local bookmarks = all_bookmarks(action == "jump") + local selected = #bookmarks > 0 and ya.which { cands = bookmarks } + if not selected then + return + end + + if action == "jump" then + if bookmarks[selected].is_parent then + ya.manager_emit("cd", { bookmarks[selected].path }) + else + ya.manager_emit("reveal", { bookmarks[selected].path }) + end + elseif action == "delete" then + delete_bookmark(selected) + end + end, + setup = function(state, args) + if not args then + return + end + + -- TODO: DEPRECATED + if args.save_last_directory then + _save_last_directory() + elseif type(args.last_directory) == "table" then + if args.last_directory.enable then + _save_last_directory(args.last_directory.persist) + end + end + + if args.persist == "all" or args.persist == "vim" then + state.persist = args.persist + _load_state() + end + + if args.desc_format == "parent" then + state.desc_format = "parent" + else + state.desc_format = "full" + end + + if args.file_pick_mode == "parent" then + state.file_pick_mode = "parent" + else + state.file_pick_mode = "hover" + end + + state.notify = { + enable = false, + timeout = 1, + message = { + new = "New bookmark '' -> ''", + delete = "Deleted bookmark in ''", + delete_all = "Deleted all bookmarks", + }, + } + if type(args.notify) == "table" then + if type(args.notify.enable) == "boolean" then + state.notify.enable = args.notify.enable + end + if type(args.notify.timeout) == "number" then + state.notify.timeout = args.notify.timeout + end + if type(args.notify.message) == "table" then + if type(args.notify.message.new) == "string" then + state.notify.message.new = args.notify.message.new + end + if type(args.notify.message.delete) == "string" then + state.notify.message.delete = args.notify.message.delete + end + if type(args.notify.message.delete_all) == "string" then + state.notify.message.delete_all = args.notify.message.delete_all + end + end + end + end, +} diff --git a/.config/yazi/plugins/jump-to-char.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY b/.config/yazi/plugins/jump-to-char.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY new file mode 100644 index 0000000..e69de29 diff --git a/.config/yazi/plugins/jump-to-char.yazi/LICENSE b/.config/yazi/plugins/jump-to-char.yazi/LICENSE new file mode 100644 index 0000000..fb5b1d6 --- /dev/null +++ b/.config/yazi/plugins/jump-to-char.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 yazi-rs + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.config/yazi/plugins/jump-to-char.yazi/README.md b/.config/yazi/plugins/jump-to-char.yazi/README.md new file mode 100644 index 0000000..f7e2f9e --- /dev/null +++ b/.config/yazi/plugins/jump-to-char.yazi/README.md @@ -0,0 +1,24 @@ +# jump-to-char.yazi + +Vim-like `f`, jump to the next file whose name starts with ``. + +https://github.com/yazi-rs/plugins/assets/17523360/aac9341c-b416-4e0c-aaba-889d48389869 + +## Installation + +```sh +ya pack -a yazi-rs/plugins:jump-to-char +``` + +## Usage + +Add this to your `~/.config/yazi/keymap.toml`: + +```toml +[[manager.prepend_keymap]] +on = "f" +run = "plugin jump-to-char" +desc = "Jump to char" +``` + +Make sure the f key is not used elsewhere. diff --git a/.config/yazi/plugins/jump-to-char.yazi/init.lua b/.config/yazi/plugins/jump-to-char.yazi/init.lua new file mode 100644 index 0000000..827cde9 --- /dev/null +++ b/.config/yazi/plugins/jump-to-char.yazi/init.lua @@ -0,0 +1,30 @@ +local AVAILABLE_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789." + +local changed = ya.sync(function(st, new) + local b = st.last ~= new + st.last = new + return b or not cx.active.finder +end) + +local escape = function(s) return s == "." and "\\." or s end + +return { + entry = function() + local cands = {} + for i = 1, #AVAILABLE_CHARS do + cands[#cands + 1] = { on = AVAILABLE_CHARS:sub(i, i) } + end + + local idx = ya.which { cands = cands, silent = true } + if not idx then + return + end + + local kw = escape(cands[idx].on) + if changed(kw) then + ya.manager_emit("find_do", { "^" .. kw }) + else + ya.manager_emit("find_arrow", {}) + end + end, +} diff --git a/.config/yazi/plugins/miller.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY b/.config/yazi/plugins/miller.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY new file mode 100644 index 0000000..e69de29 diff --git a/.config/yazi/plugins/miller.yazi/LICENSE b/.config/yazi/plugins/miller.yazi/LICENSE new file mode 100644 index 0000000..de882e5 --- /dev/null +++ b/.config/yazi/plugins/miller.yazi/LICENSE @@ -0,0 +1,7 @@ +Copyright © 2024 Reledia + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/.config/yazi/plugins/miller.yazi/README.md b/.config/yazi/plugins/miller.yazi/README.md new file mode 100644 index 0000000..0cd410c --- /dev/null +++ b/.config/yazi/plugins/miller.yazi/README.md @@ -0,0 +1,27 @@ +# miller.yazi + +[Miller](https://github.com/johnkerl/miller) now in [yazi](https://github.com/sxyazi/yazi). To install, use the command `ya pack -a Reledia/miller` and add to your `yazi.toml`: + +```toml +[plugin] +prepend_previewers = [ + { mime = "text/csv", run = "miller"}, +] +``` + +## Preview + +![preview](https://github.com/Reledia/miller.yazi/blob/main/preview.png?raw=true) + +## Color + +To change colors of keys and values, edit the `init.lua` file after the `--key-color` and `--value-color` flags. To view a list of possible colors, use `mlr --list-color-names`. Make sure to have miller installed and inside your PATH. + +## Other types of file + +To adapt this plugin to the other format supported from miller (like json): + +- copy the plugin folder +- change the name of the copied folder into miller\_(fmt) +- change the `--icsv` flag inside `init.lua` to `--i(fmt)` +- add the correct mime/name rule into `prepend_previewers` and the exec as `miller_(fmt)` diff --git a/.config/yazi/plugins/miller.yazi/init.lua b/.config/yazi/plugins/miller.yazi/init.lua new file mode 100644 index 0000000..9a4a752 --- /dev/null +++ b/.config/yazi/plugins/miller.yazi/init.lua @@ -0,0 +1,59 @@ +local M = {} + +function M:peek() + local child = Command("mlr") + :args({ + "--icsv", + "--opprint", + "-C", + "--key-color", + "darkcyan", + "--value-color", + "grey70", + "cat", + tostring(self.file.url), + }) + :stdout(Command.PIPED) + :stderr(Command.PIPED) + :spawn() + + local limit = self.area.h + local i, lines = 0, "" + repeat + local next, event = child:read_line() + if event == 1 then + ya.err(tostring(event)) + elseif event ~= 0 then + break + end + + i = i + 1 + if i > self.skip then + lines = lines .. next + end + until i >= self.skip + limit + + child:start_kill() + if self.skip > 0 and i < self.skip + limit then + ya.manager_emit( + "peek", + { tostring(math.max(0, i - limit)), only_if = tostring(self.file.url), upper_bound = "" } + ) + else + lines = lines:gsub("\t", string.rep(" ", PREVIEW.tab_size)) + ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) }) + end +end + +function M:seek(units) + local h = cx.active.current.hovered + if h and h.url == self.file.url then + local step = math.floor(units * self.area.h / 10) + ya.manager_emit("peek", { + tostring(math.max(0, cx.active.preview.skip + step)), + only_if = tostring(self.file.url), + }) + end +end + +return M diff --git a/.config/yazi/plugins/ouch.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY b/.config/yazi/plugins/ouch.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY new file mode 100644 index 0000000..e69de29 diff --git a/.config/yazi/plugins/ouch.yazi/LICENSE b/.config/yazi/plugins/ouch.yazi/LICENSE new file mode 100644 index 0000000..3f9d766 --- /dev/null +++ b/.config/yazi/plugins/ouch.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 ndtoan96 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.config/yazi/plugins/ouch.yazi/README.md b/.config/yazi/plugins/ouch.yazi/README.md new file mode 100644 index 0000000..2b49af2 --- /dev/null +++ b/.config/yazi/plugins/ouch.yazi/README.md @@ -0,0 +1,67 @@ +# ouch.yazi + +[ouch](https://github.com/ouch-org/ouch) plugin for [Yazi](https://github.com/sxyazi/yazi). + +![ouch.yazi](https://github.com/ndtoan96/ouch.yazi/assets/33489972/946397ec-b37b-4bf4-93f1-c676fc8e59f2) + +## Features +- Archive preview +- Compression + +## Installation + +```bash +# Linux/macOS +git clone https://github.com/ndtoan96/ouch.yazi.git ~/.config/yazi/plugins/ouch.yazi + +# Windows +git clone https://github.com/ndtoan96/ouch.yazi.git %AppData%\yazi\config\plugins\ouch.yazi +``` + +Make sure you have [ouch](https://github.com/ouch-org/ouch) installed and in your `PATH`. + +## Usage + +### Preview +For archive preview, add this to your `yazi.toml`: + +```toml +[plugin] +prepend_previewers = [ + # Archive previewer + { mime = "application/*zip", run = "ouch" }, + { mime = "application/x-tar", run = "ouch" }, + { mime = "application/x-bzip2", run = "ouch" }, + { mime = "application/x-7z-compressed", run = "ouch" }, + { mime = "application/x-rar", run = "ouch" }, + { mime = "application/x-xz", run = "ouch" }, +] +``` + +Now go to an archive on Yazi, you should see the archive's content in the preview pane. You can use `Alt-j` and `Alt-k` to roll up and down the preview. + +If you want to change the icon or the style of text, you can modify the `peek` function in `init.lua` file (all of them are stored in the `lines` variable). + +### Compression +For compession, add this to your `keymap.toml`: + +```toml +[[manager.prepend_keymap]] +on = ["C"] +run = "plugin ouch --args=zip" +desc = "Compress with ouch" +``` + +The `--args=zip` part tells the plugin that default format is `zip`. You can change that to whatever format you want. + +### Decompression +This plugin does not provide a decompression feature because it already is supported by Yazi. +To decompress with `ouch`, configure the opener in `yazi.toml`. + +```toml +[opener] +extract = [ + { run = 'ouch d -y "%*"', desc = "Extract here with ouch", for = "windows" }, + { run = 'ouch d -y "$@"', desc = "Extract here with ouch", for = "unix" }, +] +``` diff --git a/.config/yazi/plugins/ouch.yazi/init.lua b/.config/yazi/plugins/ouch.yazi/init.lua new file mode 100644 index 0000000..c6f2e69 --- /dev/null +++ b/.config/yazi/plugins/ouch.yazi/init.lua @@ -0,0 +1,143 @@ +local M = {} + +function M:peek() + local child = Command("ouch") + :args({ "l", "-t", "-y", tostring(self.file.url) }) + :stdout(Command.PIPED) + :stderr(Command.PIPED) + :spawn() + local limit = self.area.h + local file_name = string.match(tostring(self.file.url), ".*[/\\](.*)") + local lines = string.format("\x1b[2m📁 %s\x1b[0m\n", file_name) + local num_lines = 1 + local num_skip = 0 + repeat + local line, event = child:read_line() + if event == 1 then + ya.err(tostring(event)) + elseif event ~= 0 then + break + end + + if line:find('Archive', 1, true) ~= 1 and line:find('[INFO]', 1, true) ~= 1 then + if num_skip >= self.skip then + lines = lines .. line + num_lines = num_lines + 1 + else + num_skip = num_skip + 1 + end + end + until num_lines >= limit + + child:start_kill() + if self.skip > 0 and num_lines < limit then + ya.manager_emit( + "peek", + { tostring(math.max(0, self.skip - (limit - num_lines))), only_if = tostring(self.file.url), upper_bound = "" } + ) + else + ya.preview_widgets(self, { ui.Paragraph.parse(self.area, lines) }) + end +end + +function M:seek(units) + local h = cx.active.current.hovered + if h and h.url == self.file.url then + local step = math.floor(units * self.area.h / 10) + ya.manager_emit("peek", { + math.max(0, cx.active.preview.skip + step), + only_if = tostring(self.file.url), + }) + end +end + +-- Check if file exists +local function file_exists(name) + local f = io.open(name, "r") + if f ~= nil then + io.close(f) + return true + else + return false + end +end + +-- Get the files that need to be compressed and infer a default archive name +local get_compression_target = ya.sync(function() + local tab = cx.active + local default_name + local paths = {} + if #tab.selected == 0 then + if tab.current.hovered then + local name = tab.current.hovered.name + default_name = name + table.insert(paths, name) + else + return + end + else + default_name = tab.current.cwd:name() + for _, url in pairs(tab.selected) do + table.insert(paths, tostring(url)) + end + -- The compression targets are aquired, now unselect them + ya.manager_emit("escape", {}) + end + return paths, default_name +end) + +local function invoke_compress_command(paths, name) + local cmd_output, err_code = Command("ouch") + :args({ "c", "-y" }) + :args(paths) + :arg(name) + :stderr(Command.PIPED) + :output() + if err_code ~= nil then + ya.notify({ + title = "Failed to run ouch command", + content = "Status: " .. err_code, + timeout = 5.0, + level = "error", + }) + elseif not cmd_output.status.success then + ya.notify({ + title = "Compression failed: status code " .. cmd_output.status.code, + content = cmd_output.stderr, + timeout = 5.0, + level = "error", + }) + end +end + +function M:entry(args) + local default_fmt = args[1] + + -- Get the files that need to be compressed and infer a default archive name + local paths, default_name = get_compression_target() + + -- Get archive name from user + local output_name, name_event = ya.input({ + title = "Create archive:", + value = default_name .. "." .. default_fmt, + position = { "top-center", y = 3, w = 40 }, + }) + if name_event ~= 1 then + return + end + + -- Get confirmation if file exists + if file_exists(output_name) then + local confirm, confirm_event = ya.input({ + title = "Overwrite " .. output_name .. "? (y/N)", + position = { "top-center", y = 3, w = 40 }, + }) + if not (confirm_event == 1 and confirm:lower() == "y") then + return + end + end + + invoke_compress_command(paths, output_name) +end + +return M diff --git a/.config/yazi/plugins/yamb.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY b/.config/yazi/plugins/yamb.yazi/DO_NOT_MODIFY_ANYTHING_IN_THIS_DIRECTORY new file mode 100644 index 0000000..e69de29 diff --git a/.config/yazi/plugins/yamb.yazi/LICENSE b/.config/yazi/plugins/yamb.yazi/LICENSE new file mode 100644 index 0000000..12f8c8b --- /dev/null +++ b/.config/yazi/plugins/yamb.yazi/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Hunter Hwang + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/.config/yazi/plugins/yamb.yazi/README.md b/.config/yazi/plugins/yamb.yazi/README.md new file mode 100644 index 0000000..3f08f48 --- /dev/null +++ b/.config/yazi/plugins/yamb.yazi/README.md @@ -0,0 +1,112 @@ +# Yet another bookmarks + +A [Yazi](https://github.com/sxyazi/yazi) plugin for bookmark management, supporting the following features + +- Persistent bookmarks. No bookmarks are lost after you close yazi. +- Quickly jump, delete, and rename a bookmark by keymap. +- Support fuzzy search through [fzf](https://github.com/junegunn/fzf). +- Configure your bookmarks using Lua language. + +## Installation + +> [!NOTE] +> Yazi >= 0.25. + +```sh +# Linux/macOS +git clone https://github.com/h-hg/yamb.yazi.git ~/.config/yazi/plugins/yamb.yazi + +# Windows +git clone https://github.com/h-hg/yamb.yazi.git $env:APPDATA\yazi\config\plugins\yamb.yazi + +# if you are using Yazi version >= 3.0 +ya pack -a h-hg/yamb +``` + +## Usage + +Add this to your `init.lua` + +```lua +-- You can configure your bookmarks by lua language +local bookmarks = {} + +local path_sep = package.config:sub(1, 1) +local home_path = ya.target_family() == "windows" and os.getenv("USERPROFILE") or os.getenv("HOME") +if ya.target_family() == "windows" then + table.insert(bookmarks, { + tag = "Scoop Local", + + path = (os.getenv("SCOOP") or home_path .. "\\scoop") .. "\\", + key = "p" + }) + table.insert(bookmarks, { + tag = "Scoop Global", + path = (os.getenv("SCOOP_GLOBAL") or "C:\\ProgramData\\scoop") .. "\\", + key = "P" + }) +end +table.insert(bookmarks, { + tag = "Desktop", + path = home_path .. path_sep .. "Desktop" .. path_sep, + key = "d" +}) + +require("yamb"):setup { + -- Optional, the path ending with path seperator represents folder. + bookmarks = bookmarks, + -- Optional, recieve notification everytime you jump. + jump_notify = true, + -- Optional, the cli of fzf. + cli = "fzf", + -- Optional, a string used for randomly generating keys, where the preceding characters have higher priority. + keys = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ", + -- Optional, the path of bookmarks + path = (ya.target_family() == "windows" and os.getenv("APPDATA") .. "\\yazi\\config\\bookmark") or + (os.getenv("HOME") .. "/.config/yazi/bookmark"), +} +``` + +Add this to your `keymap.toml`: + +```toml +[[manager.prepend_keymap]] +on = [ "u", "a" ] +run = "plugin yamb --args=save" +desc = "Add bookmark" + +[[manager.prepend_keymap]] +on = [ "u", "g" ] +run = "plugin yamb --args=jump_by_key" +desc = "Jump bookmark by key" + +[[manager.prepend_keymap]] +on = [ "u", "G" ] +run = "plugin yamb --args=jump_by_fzf" +desc = "Jump bookmark by fzf" + +[[manager.prepend_keymap]] +on = [ "u", "d" ] +run = "plugin yamb --args=delete_by_key" +desc = "Delete bookmark by key" + +[[manager.prepend_keymap]] +on = [ "u", "D" ] +run = "plugin yamb --args=delete_by_fzf" +desc = "Delete bookmark by fzf" + +[[manager.prepend_keymap]] +on = [ "u", "A" ] +run = "plugin yamb --args=delete_all" +desc = "Delete all bookmarks" + +[[manager.prepend_keymap]] +on = [ "u", "r" ] +run = "plugin yamb --args=rename_by_key" +desc = "Rename bookmark by key" + +[[manager.prepend_keymap]] +on = [ "u", "R" ] +run = "plugin yamb --args=rename_by_fzf" +desc = "Rename bookmark by fzf" +``` diff --git a/.config/yazi/plugins/yamb.yazi/init.lua b/.config/yazi/plugins/yamb.yazi/init.lua new file mode 100644 index 0000000..c021b14 --- /dev/null +++ b/.config/yazi/plugins/yamb.yazi/init.lua @@ -0,0 +1,355 @@ +local path_sep = package.config:sub(1, 1) + +local get_hovered_path = ya.sync(function(state) + local h = cx.active.current.hovered + if h then + local path = tostring(h.url) + if h.cha.is_dir then + return path .. path_sep + end + return path + else + return '' + end +end) + +local get_state_attr = ya.sync(function(state, attr) + return state[attr] +end) + +local set_state_attr = ya.sync(function(state, attr, value) + state[attr] = value +end) + +local set_bookmarks = ya.sync(function(state, path, value) + state.bookmarks[path] = value +end) + +local sort_bookmarks = function(bookmarks, key1, key2, reverse) + reverse = reverse or false + table.sort(bookmarks, function(x, y) + if x[key1] == nil and y[key1] == nil then + return x[key2] < y[key2] + elseif x[key1] == nil then + return false + elseif y[key1] == nil then + return true + else + return x[key1] < y[key1] + end + end) + if reverse then + local n = #bookmarks + for i = 1, math.floor(n / 2) do + bookmarks[i], bookmarks[n - i + 1] = bookmarks[n - i + 1], bookmarks[i] + end + end + return bookmarks +end + +local save_to_file = function(mb_path, bookmarks) + local file = io.open(mb_path, "w") + if file == nil then + return + end + local array = {} + for _, item in pairs(bookmarks) do + table.insert(array, item) + end + sort_bookmarks(array, "tag", "key", true) + for _, item in ipairs(array) do + file:write(string.format("%s\t%s\t%s\n", item.tag, item.path, item.key)) + end + file:close() +end + +local fzf_find = function(cli, mb_path) + local permit = ya.hide() + local cmd = string.format("%s < \"%s\"", cli, mb_path) + local handle = io.popen(cmd, "r") + local result = "" + if handle then + -- strip + result = string.gsub(handle:read("*all") or "", "^%s*(.-)%s*$", "%1") + handle:close() + end + permit:drop() + local tag, path, key = string.match(result or "", "(.-)\t(.-)\t(.*)") + return path +end + +local which_find = function(bookmarks) + local cands = {} + for path, item in pairs(bookmarks) do + if #item.tag ~= 0 then + table.insert(cands, { desc = item.tag, on = item.key, path = item.path }) + end + end + sort_bookmarks(cands, "on", "desc", false) + if #cands == 0 then + ya.notify { + title = "Bookmarks", + content = "Empty bookmarks", + timeout = 2, + level = "info", + } + return nil + end + local idx = ya.which { cands = cands } + if idx == nil then + return nil + end + return cands[idx].path +end + +local action_jump = function(bookmarks, path, jump_notify) + if path == nil then + return + end + local tag = bookmarks[path].tag + if string.sub(path, -1) == path_sep then + ya.manager_emit("cd", { path }) + else + ya.manager_emit("reveal", { path }) + end + if jump_notify then + ya.notify { + title = "Bookmarks", + content = 'Jump to "' .. tag .. '"', + timeout = 2, + level = "info", + } + end +end + +local generate_key = function(bookmarks) + local keys = get_state_attr("keys") + local key2rank = get_state_attr("key2rank") + local mb = {} + for _, item in pairs(bookmarks) do + if #item.key == 1 then + table.insert(mb, item.key) + end + end + if #mb == 0 then + return keys[1] + end + table.sort(mb, function(a, b) + return key2rank[a] < key2rank[b] + end) + local idx = 1 + for _, key in ipairs(keys) do + if key2rank[key] < key2rank[mb[idx]] then + return key + end + idx = idx + 1 + end + return nil +end + +local action_save = function(mb_path, bookmarks, path) + if path == nil or #path == 0 then + return + end + + local path_obj = bookmarks[path] + -- check tag + local tag = path_obj and path_obj.tag or path:match(".*[\\/]([^\\/]+)[\\/]?$") + while true do + local value, event = ya.input({ + title = "Tag (alias name)", + value = tag, + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + tag = value or '' + if #tag == 0 then + ya.notify { + title = "Bookmarks", + content = "Empty tag", + timeout = 2, + level = "info", + } + else + -- check the tag + local tag_obj = nil + for _, item in pairs(bookmarks) do + if item.tag == tag then + tag_obj = item + break + end + end + if tag_obj == nil or tag_obj.path == path then + break + end + ya.notify { + title = "Bookmarks", + content = "Duplicated tag", + timeout = 2, + level = "info", + } + end + end + -- check key + local key = path_obj and path_obj.key or generate_key(bookmarks) + while true do + local value, event = ya.input({ + title = "Key (1 character, optional)", + value = key, + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + key = value or "" + if key == "" then + key = "" + break + elseif #key == 1 then + -- check the key + local key_obj = nil + for _, item in pairs(bookmarks) do + if item.key == key then + key_obj = item + break + end + end + if key_obj == nil or key_obj.path == path then + break + else + ya.notify { + title = "Bookmarks", + content = "Duplicated key", + timeout = 2, + level = "info", + } + end + else + ya.notify { + title = "Bookmarks", + content = "The length of key shoule be 1", + timeout = 2, + level = "info", + } + end + end + -- save + set_bookmarks(path, { tag = tag, path = path, key = key }) + bookmarks = get_state_attr("bookmarks") + save_to_file(mb_path, bookmarks) + ya.notify { + title = "Bookmarks", + content = '"' .. tag .. '" saved"', + timeout = 2, + level = "info", + } +end + +local action_delete = function(mb_path, bookmarks, path) + if path == nil then + return + end + local tag = bookmarks[path].tag + set_bookmarks(path, nil) + bookmarks = get_state_attr("bookmarks") + save_to_file(mb_path, bookmarks) + ya.notify { + title = "Bookmarks", + content = '"' .. tag .. '" deleted', + timeout = 2, + level = "info", + } +end + +local action_delete_all = function(mb_path) + local value, event = ya.input({ + title = "Delete all bookmarks? (y/n)", + position = { "top-center", y = 3, w = 40 }, + }) + if event ~= 1 then + return + end + if string.lower(value) == "y" then + set_state_attr("bookmarks", {}) + save_to_file(mb_path, {}) + ya.notify { + title = "Bookmarks", + content = "All bookmarks deleted", + timeout = 2, + level = "info", + } + else + ya.notify { + title = "Bookmarks", + content = "Cancel delete", + timeout = 2, + level = "info", + } + end +end + +return { + setup = function(state, options) + state.path = options.path or + (ya.target_family() == "windows" and os.getenv("APPDATA") .. "\\yazi\\config\\bookmark") or + (os.getenv("HOME") .. "/.config/yazi/bookmark") + state.cli = options.cli or "fzf" + state.jump_notify = options.jump_notify and true + -- init the keys + local keys = options.keys or "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + state.keys = {} + state.key2rank = {} + for i = 1, #keys do + local char = keys:sub(i, i) + table.insert(state.keys, char) + state.key2rank[char] = i + end + + -- init the bookmarks + local bookmarks = {} + for _, item in pairs(options.bookmarks or {}) do + bookmarks[item.path] = { tag = item.tag, path = item.path, key = item.key } + end + -- load the config + local file = io.open(state.path, "r") + if file ~= nil then + for line in file:lines() do + local tag, path, key = string.match(line, "(.-)\t(.-)\t(.*)") + if tag and path then + key = key or "" + bookmarks[path] = { tag = tag, path = path, key = key } + end + end + file:close() + end + -- create bookmarks file to enable fzf + save_to_file(state.path, bookmarks) + state.bookmarks = bookmarks + end, + entry = function(self, args) + local action = args[1] + if not action then + return + end + local mb_path, cli, bookmarks, jump_notify = get_state_attr("path"), get_state_attr("cli"), get_state_attr("bookmarks"), get_state_attr("jump_notify") + if action == "save" then + action_save(mb_path, bookmarks, get_hovered_path()) + elseif action == "delete_by_key" then + action_delete(mb_path, bookmarks, which_find(bookmarks)) + elseif action == "delete_by_fzf" then + action_delete(mb_path, bookmarks, fzf_find(cli, mb_path)) + elseif action == "delete_all" then + action_delete_all(mb_path) + elseif action == "jump_by_key" then + action_jump(bookmarks, which_find(bookmarks), jump_notify) + elseif action == "jump_by_fzf" then + action_jump(bookmarks, fzf_find(cli, mb_path), jump_notify) + elseif action == "rename_by_key" then + action_save(mb_path, bookmarks, which_find(bookmarks)) + elseif action == "rename_by_fzf" then + action_save(mb_path, bookmarks, fzf_find(cli, mb_path)) + end + end, +} diff --git a/.config/yazi/yazi.toml b/.config/yazi/yazi.toml new file mode 100644 index 0000000..0a0c727 --- /dev/null +++ b/.config/yazi/yazi.toml @@ -0,0 +1,25 @@ +[opener] +edit = [ + { run = 'nvim "$@"', block = true, for = "unix" }, +] +play = [ + { run = 'mpv "$@"', orphan = true, for = "unix" }, +] +open = [ + { run = 'xdg-open "$@"', desc = "Open" }, +] +extract = [ + { run = 'ouch d -y "%*"', desc = "Extract here with ouch", for = "windows" }, + { run = 'ouch d -y "$@"', desc = "Extract here with ouch", for = "unix" }, +] + +[plugin] +prepend_previewers = [ + # Archive previewer + { mime = "application/*zip", run = "ouch" }, + { mime = "application/x-tar", run = "ouch" }, + { mime = "application/x-bzip2", run = "ouch" }, + { mime = "application/x-7z-compressed", run = "ouch" }, + { mime = "application/x-rar", run = "ouch" }, + { mime = "application/x-xz", run = "ouch" }, +] diff --git a/.gitconfig b/.gitconfig index 893bb1d..1962b0d 100644 --- a/.gitconfig +++ b/.gitconfig @@ -25,3 +25,5 @@ [diff] colorMoved = default +[alias] + zip = archive HEAD -o diff --git a/.gitignore b/.gitignore index 608396f..5ad58d5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,5 @@ .config/nvim/lazy-lock.json -.oh-my-zsh/cache/.zsh-update +.oh-my-zsh/cache .config/Code/DawnGraphiteCache/ .config/Code/DawnWebGPUCache/ diff --git a/.gitmodules b/.gitmodules index 404f8b6..a0c2e18 100644 --- a/.gitmodules +++ b/.gitmodules @@ -25,3 +25,6 @@ [submodule ".tmux/plugins/vim-tmux-navigator"] path = .tmux/plugins/vim-tmux-navigator url = https://git::@github.com/christoomey/vim-tmux-navigator +[submodule ".tmux/plugins/tmux-gruvbox"] + path = .tmux/plugins/tmux-gruvbox + url = https://git::@github.com/egel/tmux-gruvbox diff --git a/.tmux.conf b/.tmux.conf index 2962eae..d101731 100644 --- a/.tmux.conf +++ b/.tmux.conf @@ -20,9 +20,15 @@ bind -n M-Right select-pane -R bind -n M-Up select-pane -U bind -n M-Down select-pane -D +# ────────────────────────────── move panes ────────────────────────────── +bind j command-prompt -p "join pane from:" "join-pane -s '%%'" +bind s command-prompt -p "send pane to:" "join-pane -t '%%'" + # ───────────────── Shift Alt vim keys to switch windows ───────────────── bind -n M-H previous-window bind -n M-L next-window +bind -n M-K switch-client -p +bind -n M-J switch-client -n # ─────────────────── trying to make home end working ───────────────── bind-key -n Home send Escape "OH" @@ -97,27 +103,33 @@ set -g @resurrect-strategy-nvim 'session' # resurrect nvim sessions set -g @plugin 'tmux-plugins/tmux-continuum' set -g @continuum-restore 'on' # enabling +# ╭──────────────────────────────────────────────────────────╮ +# │ gruvbox theme │ +# ╰──────────────────────────────────────────────────────────╯ +set -g @plugin 'egel/tmux-gruvbox' +set -g @tmux-gruvbox 'dark' + # ╭──────────────────────────────────────────────────────────╮ # │ Dracula theme │ # ╰──────────────────────────────────────────────────────────╯ # available plugins: battery, cpu-usage, git, gpu-usage, ram-usage, tmux-ram-usage, network, network-bandwidth, network-ping, ssh-session, attached-clients, network-vpn, weather, time, mpc, spotify-tui, playerctl, kubernetes-context, synchronize-panes -set -g @plugin 'dracula/tmux' -set -g @dracula-show-powerline true -set -g @dracula-plugins "git network network-vpn platerctl time battery" -# it can accept `hostname` (full hostname), `session`, `shortname` (short name), `smiley`, `window`, or any character. -set -g @dracula-show-left-icon session -set -g @dracula-show-empty-plugins false -set -g @dracula-battery-label "🔋" -set -g @dracula-show-timezone false -set -g @dracula-military-time true -set -g @dracula-day-month true -set -g @dracula-show-fahrenheit false -set -g @dracula-playerctl-format "► {{ artist }} - {{ title }}" -# for left -set -g @dracula-show-left-sep \uE0C0 - -# for right symbol (can set any symbol you like as separator) -set -g @dracula-show-right-sep \uE0B2 +# set -g @plugin 'dracula/tmux' +# set -g @dracula-show-powerline true +# set -g @dracula-plugins "git network network-vpn platerctl time battery" +# # it can accept `hostname` (full hostname), `session`, `shortname` (short name), `smiley`, `window`, or any character. +# set -g @dracula-show-left-icon session +# set -g @dracula-show-empty-plugins false +# set -g @dracula-battery-label "🔋" +# set -g @dracula-show-timezone false +# set -g @dracula-military-time true +# set -g @dracula-day-month true +# set -g @dracula-show-fahrenheit false +# set -g @dracula-playerctl-format "► {{ artist }} - {{ title }}" +# # for left +# set -g @dracula-show-left-sep \uE0C0 +# +# # for right symbol (can set any symbol you like as separator) +# set -g @dracula-show-right-sep \uE0B2 # ╭──────────────────────────────────────────────────────────╮ # │ run tmux plugin manager │ diff --git a/.tmux/plugins/tmux-gruvbox b/.tmux/plugins/tmux-gruvbox new file mode 160000 index 0000000..245e314 --- /dev/null +++ b/.tmux/plugins/tmux-gruvbox @@ -0,0 +1 @@ +Subproject commit 245e31430fb7298e02ef0d4030905b49d0385746 diff --git a/foxy-proxy-foreign-vpn-patterns.json b/foxy-proxy-foreign-vpn-patterns.json new file mode 100644 index 0000000..2a1b4b1 --- /dev/null +++ b/foxy-proxy-foreign-vpn-patterns.json @@ -0,0 +1,79 @@ +[ + { + "include": "include", + "type": "wildcard", + "title": "All", + "pattern": "*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "localhost all ports", + "pattern": "*://localhost:*/*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "127 all ports", + "pattern": "*://127.0.0.1:*/*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "localhost default port", + "pattern": "*://localhost/*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "127 default port", + "pattern": "*://127.0.0.1/*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "vk", + "pattern": "*//*.vk.*/*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "dipal vpn", + "pattern": "*://jenkins.ci-cd.svc.cluster.local/*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "local with port", + "pattern": "*://192.168.1.*:*/*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "local no port", + "pattern": "*://192.168.1.*/*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "guap", + "pattern": "*://*.guap.ru/*", + "active": true + }, + { + "include": "exclude", + "type": "wildcard", + "title": "dipal", + "pattern": "*://*.dipal.ru/*", + "active": true + } +] \ No newline at end of file