Created
May 6, 2025 18:25
-
-
Save aristidebm/aebc2d90c5fae67fa5c000a24a35e9a0 to your computer and use it in GitHub Desktop.
Revisions
-
aristidebm created this gist
May 6, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,151 @@ # Argument list: The underrated [(neo)vim](https://neovim.io/) list The argument list is so powerful that I wonder why we as vimmers are underusing it. Below are some useful use cases that I have found for the (neo)vim argument list ## Arguments list for bookmarking This bookmarking journey began with [harpoon](https://github.com/ThePrimeagen/harpoon/tree/harpoon2), a plugin built by a prolific YouTube content creator named [Theprimeagen](https://www.youtube.com/playlist?list=PLm323Lc7iSW_wuxqmKx_xxNtJC_hJbQ7R). The main idea is to store commonly used files needed to achieve the task at hand into a buffer for fast access. For more information, check [Why harpoon?](https://www.youtube.com/watch?v=Qnos8aApa9g&t=12s). After that, I came across [grapple](https://github.com/cbochs/grapple.nvim). Grapple shares the same underlying concept as harpoon but is a step ahead. It provides a neat feature on top: [Scope](https://github.com/cbochs/grapple.nvim?tab=readme-ov-file#scopes). I really like the `git_branch` one, as it lets you bookmark your files per branch. So if, for example, you are working on `branch A` and for some reason you have to move to `branch B`, with that scope activated, when you come back to `branch A`, all the files you have bookmarked are there waiting for you. So why move away from all these plugins if they are working well for me? The answer is **context overhead**. With these plugins, I have bound `<C-j>`, `<C-k>`, `<C-l>`, and `<C-;>` to pick the first four files in the bookmark. When I am in a hurry, I usually don't know which file is attached to which key and mess up every time. So I needed to find a solution. An acceptable solution is to be able to fuzzy find my bookmarks. Grapple has a plugin for [telescope](https://github.com/nvim-telescope/telescope.nvim/) but not a plugin for [fzf-lua](https://github.com/ibhagwan/fzf-lua). Since I am a huge fan of **fzf-lua**, I needed to find a solution that can leverage its potential, thus the solution described below. I use `<leader>a` to add an item to the argument list, and have bound it as follows, so that I can keep the insertion order: ```lua -- Arguments list management command nnoremap("<leader>a", ":$argadd | argdedupe <CR>") ``` I use `<C-j>`, `<C-k>`, `<C-l>`, and `<C-;>` to pick the first four elements in the argument list in that order: ```lua -- It is 0-based index but the first index always corresponds -- to the first argument passed to nvim cli command and usually -- it is the folder name (since I am used to nvim .) nnoremap("<C-j>", ":execute 'edit' argv(1)<CR>") nnoremap("<C-k>", ":execute 'edit' argv(2)<CR>") nnoremap("<C-l>", ":execute 'edit' argv(3)<CR>") nnoremap("<C-;>", ":execute 'edit' argv(4)<CR>") ``` When I mess up with the `<C-*>` keys above, I can launch a fuzzy finder on my argument list by typing `<leader>pa` and have bound it as follows: ```lua vim.keymap.set("n", "<leader>pa", require("fzf-lua").args, { desc = "[P]roject [A]rgs" }) ``` To clear my argument list, I have created a custom command that clears every entry but directories. This is useful because I usually launch (neo)vim with an argument pointing to a directory (mainly `nvim .`) and don't want the current directory to be deleted from the argument list. If you want to remove everything from the argument list, (neo)vim covers this use case with `:argdelete ##`: ```lua vim.api.nvim_create_user_command("ClearArglist", function() local arglist = vim.fn.argv() for i = #arglist, 1, -1 do if vim.fn.isdirectory(arglist[i]) == 1 then --- We don't want to remove the directory added to args list --- when launching vim with nvim <directory> else vim.cmd("argdelete " .. arglist[i]) end end end, {}) ``` ## Argument list for conflicts files grabbing Previously when I had merge conflicts while merging a branch into another, I had to go through the output of `git merge <branch>` to know which files had conflicts in them. When you are a [django](https://www.djangoproject.com/) user, with multiple apps each having `django.po`, it is not a pleasant experience to go through all these files by scanning the `git merge` output when you have conflicts in them. So I needed to find a better way of doing this. Here is where it began. I first came across [git mergetool](https://git-scm.com/docs/git-mergetool). I tried it, but it did not suit my needs because the mergetool must be opened and closed for each conflicted file. I needed something that would let me go through conflicts as fast as possible, fix conflicts, and stage all the changes at the end. Since the previous solution did not suit my needs and I knew what I was looking for experience-wise and also knew git has a hooking system, I naturally searched for a hook that could be executed when a merge fails. I went through [git hooks](https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks), but unfortunately there wasn't such a hook available. So I needed another solution. I asked myself if there were a way to grab all conflicted files after a merge fails, so I could pass those files directly to `(neo)vim`. It turns out that git provides such a utility: `git diff --name-only --diff-filter=U -z`. Thus, the solution described below. I created a bash script that can grab all conflicted files and pass them to `(neo)vim` as arguments with the aid of [perplexity](https://www.perplexity.ai/): ```bash #!/usr/bin/env bash function resolve() { # Initialize an empty array to hold conflicted filenames local files=() # Read NULL-separated filenames from git diff output safely into the array while IFS= read -r -d '' file; do files+=("$file") # Append each filename to the array done < <(git diff --name-only --diff-filter=U -z) # Check if the array is not empty (i.e., there are conflicted files) if (( ${#files[@]} )); then # Open all conflicted files in Neovim, passing each as a separate argument nvim --clean "${files[@]}" fi } # Run resolve if the function is invoked as a script if [[ "${#BASH_SOURCE[@]}" -eq 1 ]]; then resolve fi ``` Then, I set the script above as a [git alias](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases) so that after a `git merge` with conflicts, I can run `git conflicts` to open all conflicted files into `(neo)vim`: ```ini [alias] conflicts = !git-resolve ``` After the above was working great, I decided to merge these two steps (`git merge` && `git conflicts`) into one, thus the `git merge-fix` alias defined as follows: ```bash #!/usr/bin/env bash function merge_fix() { local bsh="$HOME/.local/bin/bash-scripts/" source "$bsh/git-resolve" # Merge as usual git merge "$@" # Retrieve the process exit_code exit_code=$? if [ $exit_code -ne 0 ]; then # The merging process has failed, # resolve conflicts if any. resolve # exit $status fi } merge_fix $@ ``` ```ini [alias] merge-fix = !git-merge-fix ``` After fixing conflicts inside one file, I just have to hit `]a` to go to the next one. Here are other keybindings that I use when in a merge conflicts fixing session: ```lua vim.keymap.set("n", "[a", ":previous<CR>") vim.keymap.set("n", "]a", ":next<CR>") vim.keymap.set("n", "[A", ":first<CR>") vim.keymap.set("n", "]A", ":last<CR>") ``` ## Argument list for batch processing This is the most widely known and used approach. It allows you to perform batch processing on files present inside the argument list. I often use it to remove all `breakpoint()` calls that I have set inside Python files before publishing to the upstream: ```bash $ nvim *.py ``` ```vim :argdo g/breakpoint()/d | up ``` ## Conclusion Do you have different ways of using the argument list? I would appreciate if you shared them in the comment section below. Happy coding