Posts tagged: vim

All posts with the tag "vim"

30 posts latest post 2026-06-11
Publishing rhythm
Jun 2026 | 1 posts

How to vimgrep over hidden files.

I needed to delete all build pipeline steps that were named upload docs. I currently have about 60 projects running from the same template all running very similar builds. In the past I’ve scripted out migrations for large changes like this, they involved writing a python script that would load the yaml file into a dictionary, find the corresponding steps make the change and write it back out.

Today’s job was much simplar, just delete the step, were all steps are surrounded by newlines. My first thought was to just open all files in vim and run dap. I just needed to get these files:positions into my quickfix. My issue is that all the builds reside within hidden directories by convention.

The issue #

variability

After searching through all the projects it was clear that all the steps were in their own paragraph, though I was not 100% confident enough to completely automate it, and the word upload docs was in the paragraph.

some were a two liner

- name: upload docs
  script: aws s3 ...

Some had a variation in the name

- name: upload docs to s3
  script: aws s3 ...

some were more than 2 lines.

- name: upload docs
  script: |
    aws s3 ...

some used a different command.

- name: upload docs
  script: |
    python ...

Templates are great #

but they change

Templates are amazing, and tools like cookiecutter and copier are essential in my workflow, but those templates change over time. Some things are a constant, and others like this one are an ever evolving beast until they are tamed into something the team is happy with.

vimgrep over hidden files #

I know all the files that I care to search for are called build.yml, and they are in a hidden directory.

:args `fd -H build.yml`
:vimgrep /upload docs/ ##

Once opened as a buffer by using args, and a handy fd command I can vimgrep over all the open buffers using ##

Open buffers are represented by ##

Now I can just dap and :cnext my way through the list of changes that I have, and know that I hit every one of them when I am at the end of my list. And can double check this in about 10s by scrolling back through the quickfix list.

Vim points achieved #

You’re not a true vim enthusiast until you have spent 10 minutes writing a blog post about how vim saved you 5 minutes. Check out all the other times this has happened to me in the vim tag.

A few of my friends and I all just borked our neovim configs during a plug update, and because none of us were using :PlugSnapshot it was painful to recover from.

https://twitter.com/pypeaday/status/1524882893914398732

Lucky for me I did it on a home machine that I only occasionally edit from, so I could still take the snapshot from a working machine before taking the plunge into fixing everying.

Why snapshot #

Snapshotting ensures that you install the same git sha on every single plugin. This way when you have multiple machines running your same vim config, they are all on the same sha of each plugin, and you dont end up with weird things happening on one machine. And then you get to decide when you are ready to update, rather than when it breaks.

  • same config everywhere
  • you control the update
  • in case of a borked update you have a good working place to rever to

Let’s snapshot #

Running :PlugSnapshot will generate the following content in a buffer that you can save. I chose to save mine in ~/.config/nvim/snapshot.vim.

" Generated by vim-plug
" Fri 13 May 2022 08:01:39 PM CDT
" :source this file in vim to restore the snapshot
" or execute: vim -S snapshot.vim

silent! let g:plugs['Telegraph.nvim'].commit = '92e472f4e83acd60eb3766168e66d02718bfefe0'
silent! let g:plugs['black'].commit = '8ed3e3d07ea3e6d62e3e533e69f96a0ff148cd5d'
silent! let g:plugs['bufutils.vim'].commit = '4634feb1312fd73fab66cfaa860e7af3abde935b'
silent! let g:plugs['cmp-buffer'].commit = 'd66c4c2d376e5be99db68d2362cd94d250987525'
silent! let g:plugs['cmp-calc'].commit = '970fd5f97b4bd363260365b217f694dd6a1182cb'
silent! let g:plugs['cmp-nvim-lsp'].commit = 'ebdfc204afb87f15ce3d3d3f5df0b8181443b5ba'
silent! let g:plugs['cmp-path'].commit = '466b6b8270f7ba89abd59f402c73f63c7331ff6e'
silent! let g:plugs['cmp-rg'].commit = 'fd92d70ff36b30924401b0cf7d4ce7344c8235f7'
silent! let g:plugs['cmp-vsnip'].commit = '0abfa1860f5e095a07c477da940cfcb0d273b700'
silent! let g:plugs['colorbuddy.nvim'].commit = 'cdb5b0654d3cafe61d2a845e15b2b4b0e78e752a'
silent! let g:plugs['compe-tmux'].commit = '3c16f7e73abee43b3ea3e919e8b34c24427d9530'
silent! let g:plugs['coverage-highlight.vim'].commit = '864e03679ea4168661501246147893cc82020917'
silent! let g:plugs['diffurcate.vim'].commit = 'b804675072220ff7c7ebcd24a028aa4aa35f09cc'
silent! let g:plugs['friendly-snippets'].commit = '5fd8b920a3497dec9a3ef939595186b362d041b4'
silent! let g:plugs['fzf'].commit = 'a91a67668e0830a8cf9a792c4949e03b4189f097'
silent! let g:plugs['fzf.vim'].commit = 'd5f1f8641b24c0fd5b10a299824362a2a1b20ae0'
silent! let g:plugs['gitsigns.nvim'].commit = 'ead0d48df801431b990d6b91fa210f7efa30ac38'
silent! let g:plugs['gruvbox-flat.nvim'].commit = '756dbdd3dfd3ed84acb2f9649724df19ae41f904'
silent! let g:plugs['harpoon'].commit = '28762aa04d6395538e26e1efff5213b26720e68f'
silent! let g:plugs['impatient.nvim'].commit = '2337df7d778e17a58d8709f651653b9039946d8d'
silent! let g:plugs['instant.nvim'].commit = 'c02d72267b12130609b7ad39b76cf7f4a3bc9554'
silent! let g:plugs['lsp_extensions.nvim'].commit = '4011f4aec61ba59c734f5dbf52e91f258b99d985'
silent! let g:plugs['lsp_signature.nvim'].commit = 'a351509512687293fd659ba4ee7e34412c3a8f70'
silent! let g:plugs['lspsaga.nvim'].commit = 'cb0e35d2e594ff7a9c408d2e382945d56336c040'
silent! let g:plugs['lualine.nvim'].commit = '18a07f790ed7ed1f11d1b130c02782e9dfd8dd7d'
silent! let g:plugs['nvim-cmp'].commit = '433af3dffce64cbd3f99bdac9734768a6cc41951'
silent! let g:plugs['nvim-compe'].commit = 'd186d739c54823e0b010feb205c6f97792322c08'
silent! let g:plugs['nvim-dap'].commit = 'd6d8317ce9e096029150bc5844916347a9af6f45'
silent! let g:plugs['nvim-dap-python'].commit = '4c7ea25f8ff6de6fa00bf5625d2e76753cced70f'
silent! let g:plugs['nvim-lspconfig'].commit = 'ad9903c66bac88f344890acb6532f63f1cd4dac3'
silent! let g:plugs['nvim-lspinstall'].commit = '79ec2425d6b39cdcb69d379f3e56847f49be73eb'
silent! let g:plugs['nvim-lsputils'].commit = 'ae1a4a62449863ad82c70713d5b6108f3a07917c'
silent! let g:plugs['nvim-spectre'].commit = '345e5dd57773e2b4b425a2515c831108b9808a0f'
silent! let g:plugs['nvim-tree.lua'].commit = 'ce463a53ae269544697c3dedd3d5beae05937405'
silent! let g:plugs['nvim-treesitter'].commit = '3c50297eca950b4b1a7c07b28e586b0576c0a796'
silent! let g:plugs['nvim-web-devicons'].commit = '4febe73506268a02ff15a240abcd7bf3eb9234da'
silent! let g:plugs['onebuddy'].commit = '7e16006e7dde15e3cb72889f736c49409db6ff42'
silent! let g:plugs['onedark.nvim'].commit = 'e520a0c81a5a1997ecffd846ccd9c6e63b7859c6'
silent! let g:plugs['playground'].commit = '13e2d2d63ce7bc5d875e8bdf89cb070bc8cc7a00'
silent! let g:plugs['plenary.nvim'].commit = '9069d14a120cadb4f6825f76821533f2babcab92'
silent! let g:plugs['popfix'].commit = 'ea262861ce3905b90c2c203b74a7be2539f1aba4'
silent! let g:plugs['popup.nvim'].commit = 'b7404d35d5d3548a82149238289fa71f7f6de4ac'
silent! let g:plugs['refactoring.nvim'].commit = '94eaa199ad892f26d2c8594dbbc5656314cf5bdb'
silent! let g:plugs['stylua-nvim'].commit = '8bd7fa127367178dddb9ee06fdce1d7c622d2feb'
silent! let g:plugs['targets.vim'].commit = '8d6ff2984cdfaebe5b7a6eee8f226a6dd1226f2d'
silent! let g:plugs['telescope-dap.nvim'].commit = 'b4134fff5cbaf3b876e6011212ed60646e56f060'
silent! let g:plugs['telescope.nvim'].commit = '8b02088743c07c2f82aec2772fbd2b3774195448'
silent! let g:plugs['termopen.vim'].commit = '3194a991a18a9be2fd9fcf8c4c55fe990c04b2bd'
silent! let g:plugs['undotree'].commit = '08e259be24d4476c1ee745dc735eefd44f90efdc'
silent! let g:plugs['vim-be-good'].commit = 'bc499a06c14c729b22a6cc7e730a9fbc44d4e737'
silent! let g:plugs['vim-commentary'].commit = '3654775824337f466109f00eaf6759760f65be34'
silent! let g:plugs['vim-dispatch'].commit = '00e77d90452e3c710014b26dc61ea919bc895e92'
silent! let g:plugs['vim-doge'].commit = '88d8dfacc3a5f3dfce82ef5221e5e6943e627d85'
silent! let g:plugs['vim-floaterm'].commit = '6244d1739aad6682c6c1d5db18c846c342af6e3e'
silent! let g:plugs['vim-fugitive'].commit = 'b5bbd0d181ebc3cea5c42bdaed13141850432ba1'
silent! let g:plugs['vim-indent-object'].commit = '5c5b24c959478929b54a9e831a8e2e651a465965'
silent! let g:plugs['vim-ipython-cell'].commit = 'f0548d9a8d5e31d5c7f73e8729b55e8eb402852f'
silent! let g:plugs['vim-log-highlighting'].commit = '1037e26f3120e6a6a2c0c33b14a84336dee2a78f'
silent! let g:plugs['vim-quicklink'].commit = '021167741588555501594e1fc31f130b16acefa0'
silent! let g:plugs['vim-repeat'].commit = '24afe922e6a05891756ecf331f39a1f6743d3d5a'
silent! let g:plugs['vim-signify'].commit = '69498f6d49f3eeac06870012416dd9bf867b84f3'
silent! let g:plugs['vim-slime'].commit = '0ea9b35882155996171fd15a5227e673ce2d2c60'
silent! let g:plugs['vim-sneak'].commit = '94c2de47ab301d476a2baec9ffda07367046bec9'
silent! let g:plugs['vim-surround'].commit = '81fc0ec460dd8b25a76346e09aecdbca2677f1a7'
silent! let g:plugs['vim-test'].commit = '2240d7a4b868cb594b7d83544e1b6db4df806e5e'
silent! let g:plugs['vim-tmux-runner'].commit = '54767911fd5e6e2d8e493847149e315ac2e6531a'
silent! let g:plugs['vim-ultest'].commit = 'a99eb0bdf7d901d538b5dd724e2ab3a958c1799c'
silent! let g:plugs['vim-visualstar'].commit = 'a18cd0e7a03311ac709595c1d261ed44b45c9098'
silent! let g:plugs['vim-vsnip'].commit = '8f199ef690ed26dcbb8973d9a6760d1332449ac9'

PlugUpdate!

NOTE! the PlugUpdate! at the end. I did not catch this at first, if you are like me and automatically source *.vim files on save, this will immediately run the update when you save it. If you just took the snapshot though I don’t think it will actually do anything.

Let’s Update #

Now without the snapshot sourced, I will not have any of my plugins pinned. When I run :PlugUpdate it will update all of my plugins to the latest versions. Then I can :PlugSnapshot again, and this will kick out an updated list of sha’s. I will yank this file yyG and paste it into my snapshot.vim file vGp.

Look at these updates #

We can see these updates with a little :G diff % on the file.

diff --git a/nvim/.config/nvim/snapshot.vim b/nvim/.config/nvim/snapshot.vim
index 88db2b0..837c8e4 100644
--- a/nvim/.config/nvim/snapshot.vim
+++ b/nvim/.config/nvim/snapshot.vim
@@ -1,14 +1,14 @@
 " Generated by vim-plug
-" Fri 13 May 2022 08:01:39 PM CDT
+" Fri 13 May 2022 08:22:17 PM CDT
 " :source this file in vim to restore the snapshot
 " or execute: vim -S snapshot.vim

 silent! let g:plugs['Telegraph.nvim'].commit = '92e472f4e83acd60eb3766168e66d02718bfefe0'
-silent! let g:plugs['black'].commit = '8ed3e3d07ea3e6d62e3e533e69f96a0ff148cd5d'
+silent! let g:plugs['black'].commit = '7f033136ac5e0e5bf6cf322dd60b4a92050eedc4'
 silent! let g:plugs['bufutils.vim'].commit = '4634feb1312fd73fab66cfaa860e7af3abde935b'
-silent! let g:plugs['cmp-buffer'].commit = 'd66c4c2d376e5be99db68d2362cd94d250987525'
-silent! let g:plugs['cmp-calc'].commit = '970fd5f97b4bd363260365b217f694dd6a1182cb'
-silent! let g:plugs['cmp-nvim-lsp'].commit = 'ebdfc204afb87f15ce3d3d3f5df0b8181443b5ba'
+silent! let g:plugs['cmp-buffer'].commit = '12463cfcd9b14052f9effccbf1d84caa7a2d57f0'
+silent! let g:plugs['cmp-calc'].commit = 'f7efc20768603bd9f9ae0ed073b1c129f63eb312'
+silent! let g:plugs['cmp-nvim-lsp'].commit = 'e6b5feb2e6560b61f31c756fb9231a0d7b10c73d'
 silent! let g:plugs['cmp-path'].commit = '466b6b8270f7ba89abd59f402c73f63c7331ff6e'
 silent! let g:plugs['cmp-rg'].commit = 'fd92d70ff36b30924401b0cf7d4ce7344c8235f7'
 silent! let g:plugs['cmp-vsnip'].commit = '0abfa1860f5e095a07c477da940cfcb0d273b700'
@@ -16,60 +16,60 @@ silent! let g:plugs['colorbuddy.nvim'].commit = 'cdb5b0654d3cafe61d2a845e15b2b4b
 silent! let g:plugs['compe-tmux'].commit = '3c16f7e73abee43b3ea3e919e8b34c24427d9530'
 silent! let g:plugs['coverage-highlight.vim'].commit = '864e03679ea4168661501246147893cc82020917'
 silent! let g:plugs['diffurcate.vim'].commit = 'b804675072220ff7c7ebcd24a028aa4aa35f09cc'
-silent! let g:plugs['friendly-snippets'].commit = '5fd8b920a3497dec9a3ef939595186b362d041b4'
-silent! let g:plugs['fzf'].commit = 'a91a67668e0830a8cf9a792c4949e03b4189f097'
+silent! let g:plugs['friendly-snippets'].commit = '627dea2ff1ee8d8a7e6ad365acb3e335c8b25574'
+silent! let g:plugs['fzf'].commit = '6dcf5c3d7d6c321b17e6a5673f1533d6e8350462'
 silent! let g:plugs['fzf.vim'].commit = 'd5f1f8641b24c0fd5b10a299824362a2a1b20ae0'
-silent! let g:plugs['gitsigns.nvim'].commit = 'ead0d48df801431b990d6b91fa210f7efa30ac38'
+silent! let g:plugs['gitsigns.nvim'].commit = 'ffd06e36f6067935d8cb9793905dd2e84e291310'
 silent! let g:plugs['gruvbox-flat.nvim'].commit = '756dbdd3dfd3ed84acb2f9649724df19ae41f904'
-silent! let g:plugs['harpoon'].commit = '28762aa04d6395538e26e1efff5213b26720e68f'
+silent! let g:plugs['harpoon'].commit = 'd3d3d22b6207f46f8ca64946f4d781e975aec0fc'
 silent! let g:plugs['impatient.nvim'].commit = '2337df7d778e17a58d8709f651653b9039946d8d'
 silent! let g:plugs['instant.nvim'].commit = 'c02d72267b12130609b7ad39b76cf7f4a3bc9554'
 silent! let g:plugs['lsp_extensions.nvim'].commit = '4011f4aec61ba59c734f5dbf52e91f258b99d985'
-silent! let g:plugs['lsp_signature.nvim'].commit = 'a351509512687293fd659ba4ee7e34412c3a8f70'
+silent! let g:plugs['lsp_signature.nvim'].commit = 'db324e2ada5bb795d0016ec0ef2b4ae7f11d8904'
 silent! let g:plugs['lspsaga.nvim'].commit = 'cb0e35d2e594ff7a9c408d2e382945d56336c040'
-silent! let g:plugs['lualine.nvim'].commit = '18a07f790ed7ed1f11d1b130c02782e9dfd8dd7d'
-silent! let g:plugs['nvim-cmp'].commit = '433af3dffce64cbd3f99bdac9734768a6cc41951'
+silent! let g:plugs['lualine.nvim'].commit = 'a4e4517ac32441dd92ba869944741f0b5f468531'
+silent! let g:plugs['nvim-cmp'].commit = '9a0c639ac2324e6e9ecc54dc22b1d32bb6c42ab9'
 silent! let g:plugs['nvim-compe'].commit = 'd186d739c54823e0b010feb205c6f97792322c08'
-silent! let g:plugs['nvim-dap'].commit = 'd6d8317ce9e096029150bc5844916347a9af6f45'
-silent! let g:plugs['nvim-dap-python'].commit = '4c7ea25f8ff6de6fa00bf5625d2e76753cced70f'
-silent! let g:plugs['nvim-lspconfig'].commit = 'ad9903c66bac88f344890acb6532f63f1cd4dac3'
+silent! let g:plugs['nvim-dap'].commit = '2249fcfd09cdc27c08e9d2f3be5268ba81db3378'
+silent! let g:plugs['nvim-dap-python'].commit = 'd96bcbf3803283456c900cf25ab0995e8d2f00c0'
+silent! let g:plugs['nvim-lspconfig'].commit = '9ff2a06cebd4c8c3af5259d713959ab310125bec'
 silent! let g:plugs['nvim-lspinstall'].commit = '79ec2425d6b39cdcb69d379f3e56847f49be73eb'
 silent! let g:plugs['nvim-lsputils'].commit = 'ae1a4a62449863ad82c70713d5b6108f3a07917c'
 silent! let g:plugs['nvim-spectre'].commit = '345e5dd57773e2b4b425a2515c831108b9808a0f'
-silent! let g:plugs['nvim-tree.lua'].commit = 'ce463a53ae269544697c3dedd3d5beae05937405'
-silent! let g:plugs['nvim-treesitter'].commit = '3c50297eca950b4b1a7c07b28e586b0576c0a796'
-silent! let g:plugs['nvim-web-devicons'].commit = '4febe73506268a02ff15a240abcd7bf3eb9234da'
+silent! let g:plugs['nvim-tree.lua'].commit = '82ec79aac5557c05728d88195fb0d008cacbf565'
+silent! let g:plugs['nvim-treesitter'].commit = 'f1373051e554cc4642cda719c8023e4e8508eb2d'
+silent! let g:plugs['nvim-web-devicons'].commit = 'bdd43421437f2ef037e0dafeaaaa62b31d35ef2f'
 silent! let g:plugs['onebuddy'].commit = '7e16006e7dde15e3cb72889f736c49409db6ff42'
-silent! let g:plugs['onedark.nvim'].commit = 'e520a0c81a5a1997ecffd846ccd9c6e63b7859c6'
-silent! let g:plugs['playground'].commit = '13e2d2d63ce7bc5d875e8bdf89cb070bc8cc7a00'
-silent! let g:plugs['plenary.nvim'].commit = '9069d14a120cadb4f6825f76821533f2babcab92'
+silent! let g:plugs['onedark.nvim'].commit = '08cde8acf181b3278dafb9c8284726104a11cc0f'
+silent! let g:plugs['playground'].commit = '71b00a3c665298e5155ad64a9020135808d4e3e8'
+silent! let g:plugs['plenary.nvim'].commit = '0a907364b5cd6e3438e230df7add8b9bb5ef6fd3'
 silent! let g:plugs['popfix'].commit = 'ea262861ce3905b90c2c203b74a7be2539f1aba4'
 silent! let g:plugs['popup.nvim'].commit = 'b7404d35d5d3548a82149238289fa71f7f6de4ac'
-silent! let g:plugs['refactoring.nvim'].commit = '94eaa199ad892f26d2c8594dbbc5656314cf5bdb'
-silent! let g:plugs['stylua-nvim'].commit = '8bd7fa127367178dddb9ee06fdce1d7c622d2feb'
+silent! let g:plugs['refactoring.nvim'].commit = '33ac6f3bcfe97447037ded20291d40de34d8912c'
+silent! let g:plugs['stylua-nvim'].commit = 'ce59a353f02938cba3e0285e662fcd3901cd270f'
 silent! let g:plugs['targets.vim'].commit = '8d6ff2984cdfaebe5b7a6eee8f226a6dd1226f2d'
 silent! let g:plugs['telescope-dap.nvim'].commit = 'b4134fff5cbaf3b876e6011212ed60646e56f060'
-silent! let g:plugs['telescope.nvim'].commit = '8b02088743c07c2f82aec2772fbd2b3774195448'
+silent! let g:plugs['telescope.nvim'].commit = '39b12d84e86f5054e2ed98829b367598ae53ab41'
 silent! let g:plugs['termopen.vim'].commit = '3194a991a18a9be2fd9fcf8c4c55fe990c04b2bd'
 silent! let g:plugs['undotree'].commit = '08e259be24d4476c1ee745dc735eefd44f90efdc'
 silent! let g:plugs['vim-be-good'].commit = 'bc499a06c14c729b22a6cc7e730a9fbc44d4e737'
 silent! let g:plugs['vim-commentary'].commit = '3654775824337f466109f00eaf6759760f65be34'
 silent! let g:plugs['vim-dispatch'].commit = '00e77d90452e3c710014b26dc61ea919bc895e92'
-silent! let g:plugs['vim-doge'].commit = '88d8dfacc3a5f3dfce82ef5221e5e6943e627d85'
-silent! let g:plugs['vim-floaterm'].commit = '6244d1739aad6682c6c1d5db18c846c342af6e3e'
-silent! let g:plugs['vim-fugitive'].commit = 'b5bbd0d181ebc3cea5c42bdaed13141850432ba1'
+silent! let g:plugs['vim-doge'].commit = 'd5b08d01f64396557d9912b3830717d45671764b'
+silent! let g:plugs['vim-floaterm'].commit = 'ab7876f86c05c1935eb23a193f4f276132902ac1'
+silent! let g:plugs['vim-fugitive'].commit = 'a8139d37b242c5bc5ceeddc4fcd7dddf2b2c2650'
 silent! let g:plugs['vim-indent-object'].commit = '5c5b24c959478929b54a9e831a8e2e651a465965'
 silent! let g:plugs['vim-ipython-cell'].commit = 'f0548d9a8d5e31d5c7f73e8729b55e8eb402852f'
 silent! let g:plugs['vim-log-highlighting'].commit = '1037e26f3120e6a6a2c0c33b14a84336dee2a78f'
 silent! let g:plugs['vim-quicklink'].commit = '021167741588555501594e1fc31f130b16acefa0'
 silent! let g:plugs['vim-repeat'].commit = '24afe922e6a05891756ecf331f39a1f6743d3d5a'
 silent! let g:plugs['vim-signify'].commit = '69498f6d49f3eeac06870012416dd9bf867b84f3'
-silent! let g:plugs['vim-slime'].commit = '0ea9b35882155996171fd15a5227e673ce2d2c60'
+silent! let g:plugs['vim-slime'].commit = '6e4b81303968f37346925d6907b96ef07788cc82'
 silent! let g:plugs['vim-sneak'].commit = '94c2de47ab301d476a2baec9ffda07367046bec9'
-silent! let g:plugs['vim-surround'].commit = '81fc0ec460dd8b25a76346e09aecdbca2677f1a7'
+silent! let g:plugs['vim-surround'].commit = 'bf3480dc9ae7bea34c78fbba4c65b4548b5b1fea'
 silent! let g:plugs['vim-test'].commit = '2240d7a4b868cb594b7d83544e1b6db4df806e5e'
 silent! let g:plugs['vim-tmux-runner'].commit = '54767911fd5e6e2d8e493847149e315ac2e6531a'
-silent! let g:plugs['vim-ultest'].commit = 'a99eb0bdf7d901d538b5dd724e2ab3a958c1799c'
+silent! let g:plugs['vim-ultest'].commit = '6978fd32e3ca2c1c5591884eea0d57a7ee43d212'
 silent! let g:plugs['vim-visualstar'].commit = 'a18cd0e7a03311ac709595c1d261ed44b45c9098'
 silent! let g:plugs['vim-vsnip'].commit = '8f199ef690ed26dcbb8973d9a6760d1332449ac9'

Commits #

Now I can look through all the versions of my snapshot.vim by opening it, running :0Gclog and navigating the quickfix list with :cnext and :cprev. If I want to install one of the old versions while its open in a buffer, all I need to do is run :source %.

Log #

Now the log of my snapshots.vim looks like this. I saved the working version, and successfully updated to the latest versions of all plugins, with a save point I can revert back to.

commit 20e901196b0d9633a42176f1fe1757e45f709fd3
Author: Waylon S. Walker <[email protected]>
Date:   Fri May 13 20:37:03 2022 -0500

    plugupdate

commit f9d76368697b4c4427c0fa8ccd5e2449b6e5a9ff
Author: Waylon S. Walker <[email protected]>
Date:   Fri May 13 20:16:11 2022 -0500

    commit my plugin snapshot

Let’s make a vim command to automatically collect all the links in these posts at the end of each article. Regex confuses the heck out of me… I don’t have my regex liscense, but regex can be so darn powerful especially in an editor.

Step one #

Before you run someone’s regex from the internet that you don’t fully understand, check your git status and make sure you are all clear with git before you wreck something

Inspiration #

Something that I have always appreciated form Nick Janetakis is his links section. I often try to gather up the links at the end of my posts, but often end up not doing it or forgetting.

Searchng through the internet I was able to find an article from Vitaly Parnas called vim ref links that did almost exactly what I needed, except it was more complicated and made them into ref liks.

Here is my interpretation of the code I took from Vitaly’s post. It makes a Links section like the one at the bottom of this post.

function! MdLinks()
    $norm o## Links
    $norm o
    g/\[[^\]]\+\]([^)]\+)/t$
    silent! '^,$s/\v[^\[]*(\[[^\]]+\])\(([^)]+)\)[^\[]*/* \1(\2)/g
    nohl
endfunction
command! MdLinks call MdLinks()

So far it is working for me and saving me a few seconds off each post I make.

I recently found a really great plugin by mhinz to open files in neovim from a different tmux split, without touching neovim at all.

Installation #

neovim-remote is not a neovim plugin at all, it’s a python cli that you can install with pip. Unlike the repo suggests, I use pipx to install nvr.

pipx install neovim-remote

How I use it #

I have this added to my .envrc that is in every one of my projects. This will tie a neovim session to that directory, and all directories under it.

export NVIM_LISTEN_ADDRESS=/tmp/nvim-$(basename $PWD)

In my workflow I open a tmux session for each project, so this essentially ties a neovim session to a tmux session.

Open neovim #

First open neovim, but with the nvr command. This will open neovim, and look pretty much the same as always.

nvr

If you try to run nvr again in another shell nothing will happen as its already runnin under that address, but if you give it a filename it will open the file in the first instance of neovim that you opened.

nvr readme.md

Anyone just starting out their vim customization journey is bound to run into this error.

E5520: <Cmd> mapping must end with <CR>

I did not get it #

I’ll admit, in hindsight it’s very clear what this is trying to tell me, but for whatever reason I still did not understand it and I just used a : everywhere.

From the docs #

If you run :h <cmd> you will see a lot of reasons why you should do it, from performance, to hygene, to ergonomics. You will also see another clear statement about how to use <cmd>.

                                                          E5520
  <Cmd> commands must terminate, that is, they must be followed by <CR> in the
  {rhs} of the mapping definition.  Command-line mode is never entered.

When to map with a : #

You still need to map your remaps with a : if you do not close it with a <cr>. This might be something like prefilling a command with a search term.

nnoremap <leader><leader>f :s/search/

Otherwise use #

If you can close the <cmd> with a <cr> the command do so. Your map will automatically be silent, more ergonomic, performant, and all that good stuff.

nnoremap <leader><leader>f <cmd>s/search/Search/g<cr>

Creating a minimal config specifically for git commits has made running git commit much more pleasant. It starts up Much faster, and has all of the parts of my config that I use while making a git commit. The one thing that I often use is autocomplete, for things coming from elsewhere in the tmux session. For this cmpe-tmux specifically is super helpful.

The other thing that is engrained into my muscle memory is jj for escape. For that I went agead and added my settings and keymap with no noticable performance hit.

Here is the config that has taken

~/.config/nvim/init-git.vim

source ~/.config/nvim/settings.vim
source ~/.config/nvim/keymap.vim
source ~/.config/nvim/git-plugins.vim
lua require'waylonwalker.cmp'

~/.config/nvim/git-plugins.vim

call plug#begin('~/.local/share/nvim/plugged')

" cmp
Plug 'hrsh7th/nvim-cmp'
Plug 'hrsh7th/cmp-nvim-lsp'
Plug 'hrsh7th/cmp-buffer'
Plug 'hrsh7th/cmp-path'
Plug 'hrsh7th/cmp-calc'
Plug 'andersevenrud/compe-tmux', { 'branch': 'cmp' }


call plug#end()

~/.gitconfig

[core]
    editor = nvim -u ~/.config/nvim/init-git.vim

One of the first things I noticed broken in my terminal based workflow moving from Windows wsl to ubuntu was that my clipboard was all messed up and not working with my terminal apps. Luckily setting tmux and neovim to work with the system clipboard was much easier than it was on windows.

First off you need to get xclip if you don’t already have it provided by your distro. I found it in the apt repositories. I have used it between Ubuntu 18.04 and 21.10 and they all work flawlessly for me.

I have tmux setup to automatically copy any selection I make to the clipboard by setting the following in my ~/.tmux.conf. While I have neovim open I need to be in insert mode for this to pick up.

# ~/tmux.conf
bind -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "xclip -i -f -selection primary | xclip -i -selection clipboard"
bind-key -T copy-mode-vi MouseDragEnd1Pane send-keys -X copy-pipe-and-cancel "xclip -selection clipboard -i"

To get my yanks to go to the system clipboard in neovim, I just added unnamedplus to my existing clipboard variable.

# ~/.config/nvim/init.vim
set clipboard+=unnamedplus

If you need to copy something right from the terminal you can use xclip directly. I do this semi-often to send someone a message in chat.

cat file.txt | clip -sel copy

I set up some alias’s for doing this a bit more efficiently, but don’t find myself using them very often. This helps me grab commands from history and copy them.

alias hclip="history | tail -n1 | cut -c 8- | xclip -sel clip"
alias fclip="history -n 1000 | fzf | cut -c 8- | xclip -sel clip"
alias fclip="history -n 1000 | fzf | xclip -sel clip"

I often pop into my blog from neovim with the intent to look at just a single series of posts, til, gratitude, or just see todays posts. Markata has a great way of mapping over posts and returning their path that is designe exactly for this use case.

Markata listing out posts from the command line

To tie these into a Telescope picker you add the command as the find_command, and comma separate the words of the command, with no spaces. I did also --sort,date,--reverse in there so that the newest posts are closest to the cursor.

nnoremap geit <cmd>Telescope find_files find_command=markata,list,--map,path,--filter,date==today<cr>
nnoremap geil <cmd>Telescope find_files find_command=markata,list,--map,path,--filter,templateKey=='til',--sort,date,--reverse<cr>
nnoremap geig <cmd>Telescope find_files find_command=markata,list,--map,path,--filter,templateKey=='gratitude',--sort,date,--reverse<cr>

NOTE telescope treates each word as a string, do not wrap an extra layer of quotes around your words, it gets messy.

using this picker in neovim

I don’t use refactoring tools as much as I probably should. mostly because I work with small functions with unique names, but I recently had a case where a variable name m was everywhere and I wanted it named better. This was not possible with find and replace, because there were other m’s in this region.

I first tried the nvim lsp rename, and it failed, Then I pip installed rope, a refactoring tool for python, and it just worked!

pip install rope

Once you have rope installed you can call rename on the variable.

:lua vim.lsp.buf.rename()

I’ve been stuck many times looking at a vim buffer with little question marks at the beginning of each line and trying to get rid of them. for so long I didn’t know what they were so trying to get rid of them was impossible.

example of what the tab character renders as in my editor

It turns out they are tabs, and you can get rid of the little leading question marks with this substitution command.

:%s/\t/    /g

One of the most useful skills you can acquire to make you faster at almost any job that uses a computer is getting good at finding text in your current working diretory and identifying the files that its in. I often use the silver searcher ag or ripgrep rg to find files in large directories quickly. Both have a sane set of defaults that ignore hidden and gitignored files, but getting them to list only the filenames and not the matched was not trivial to me.

I’ve searched throught he help/man pages many times looking for these flags and they always seem to evade me.

ag #

Passing the flag -l to ag will get it to list only the filepath, and not the match. Here I gave it a --md as well to only return markdown filetypes. ag supports a number of filetypes in a very similar way.

ag nvim --md -l

rg #

Giving rg the --files-with-matches flag will yield you a similar set of results, giving only the filepaths themselves and not the match statement. Also passing in the -g "*.md" will similarly yield only results from markdown files.

rg --files-with-matches you -g "*.md"

When I first moved to vim from and ide like vscode or sublime text one of my very first issues was trying to preview my website at localhost:8000. There had always just been a button there to do it in all of my other editors, not vim. There are not many buttons for anything in vim. While there is probably a plugin that can run a webserver for me in vim, it’s not necessary, we just need the command line we are already in.

running a separate process #

You will need a way to run another process alongside vim, here are a couple ideas to get you going that are not the focus here.style

  • use background jobs
    • c-z to send a job to the background
    • fg to bring it back
  • use a second terminal
  • use a second tab
  • use tmux and run it in a separate split/window
  • use an embeded nvim terminal

running a development webserver from the command line #

Python already exists on most linux systems by default, and most are now on python3. If you are on windows typing python will take you directly to the windows store to install it, or you can also use wsl.

# python3
python -m http.server

# running on port 5000
python -m http.server --directory markout 5000
# for the low chance you are on python2
python -m SimpleHTTPServer

# running on port 5000
python -m SimpleHTTPServer 5000
python -m SimpleHTTPServer --directory markout 5000

running a python static webserver from the command line

using nodejs #

If you are a web developer it’s likely that you need nodejs and npm on your system anyways and may want to use one of the servers from npm. I’ll admit with these not being tied to the long term support of a language they are much more feature rich with things like compression out of the box. In my opinion they are nice things that you would want out of a production server, but may not be necessary for development.

installing npx #

# if you don't alredy have npx
npm i -g npx

npx is a handy tool that lets you run command line applications straight from npm without installing them. It pulls the latest version every time you want to run, then executes it without it being installed.

running the http-server with npx #

npx http-server

# running on port 5000
npx http-server -p 5000
npx http-server markout -p 5000

running a nodejs static webserver from the command line

Many command line tools can output a list of files, this is quite powerful. I often want to search for something, then open it from a fuzzy picker. This can be done with fzf in the terminal, but often I am already in vim and I want to open it inside my current session.

Telescope #

how to pass a custom command to telescope

Telescope is the fuzzy file finder I use every day inside of neovim. Its pretty fantastic and easy to extent like this. This first example I am only passing in files from the current working directory by using ls.

:Telescope find_files find_command=ls

This brings up a normal Telescope picker with results from the ls command.

More arguments #

how to pass a muli-argument command to telescope

Adding more arguments can be done by comma separating them as shown in the example below. This command will run the silver-searcher, search for all occurences of nvim inside of a markdown file, and return only the filepaths so Telescope can pick from them.

:Telescope find_files find_command=ag,nvim,--md,-l

Finding hidden files using Telescope as you fuzzy file finder is not too hard, its a single flag passed in. Then it will use whichever file finder it can find [‘fd’, ‘fdfind’, ‘rg –files’, ‘find’, or ‘where’] in that order. These tools each have their own way of handling hidden files, but telescope takes care of that so all you need to do is pass in hidden=true.

I have this keymap set to help me list out all files including hidden files using the pnumonic go edit hidden. I use ge for quite a few different things to take me directly to a specific file or picker.

nnoremap geh <cmd>Telescope find_files hidden=true<cr>

see the implementation telescope finds your files.

Fugitive comes with a pretty sick way to commit files and see the diff at the same time with verbose commit. Opening the fugitive menu with :G brings up your git status, you can stage files with s, unstage them with u, toggle them with -, and toggle their diff with >. Once you have staged your files for commit, you can commit with cc, but today I found that you can commit verbose with cvc. This brings up not only a commit widow with your git status shown, but the diff that you are about to commit.

fugitive verbose commit example

example of a verbose commit in fugitive

You must use augroup with autocmd in vim | Here's how

If you are running vim autocmd’s without a group, you’re killing your performance. Granted your probably not sourcing your vimscript files with autocmd’s too often, but every time you source that vimscript you are adding another command that needs to run redundantly. https://youtu.be/2ITTn4Dl0lc This is what I had # [1] Not silky smooth For WAAY too long I have had something like this in my vimrc or init.vim. It formats my python for me on every save, works great except if I source my dotfiles more than once I start adding how many times black runs. autocmd bufwritepre *.py execute 'Black' Why is a bare autocmd bad # [2] let me demonstrate Lets create a new file called format.vim and give it the :so %. Works great, it starts telling me that its formatting. autocmd bufwritepre *.py :echo("formatting with black") too-many-formats [3] BUT as every time I give it the :so % it formats an extra time on every single save. Setting up an augroup # [4] I’ve been told I need an aug...

Setup a yaml schema | yamlls for a silky smooth setup

I’ve gone far too long without a good setup for editing yaml files, I am missing out on autocomplete and proper diagnostics. This ends today as I setup yaml-language-server in neovim. https://youtu.be/xo4HrFoKF4c The video for this one is part of a challenge-playlist [1] I put out for myself to constantly improve my dotfiles for all of December. init.vim # [2] I have my init.vim setup to only source other modules, if you want everything in a single config, feel free to do as you wish. I broke mine up earlier this year as I doubled into nvim and am not going back. source ~/.config/nvim/plugins.vim lua require'waylonwalker.cmp' lua require'waylonwalker.lsp-config' Plugin setup # [3] You will need the following plugins. I use plug, if you don’t you will have to convert the syntax over to the plugin manager you use. neovim/nvim-lspconfig [4] is for configuring the lsp. It comes with a bunch of sane defaults for most servers, so you pretty much just have to call setup on that serv...

How linux users install a text editor

In honor of the neovim 0.6.0 release, I decided to do a funny skit installing neovim, and fix up my install script in the process as part of my challenge to fix up my dotfiles. I ran into one snag where I was not updating the repo that I cloned. I moved it to the directory I now keep third-party git [1] repos and set it to update with ansible. https://youtu.be/64oKLphhBuo The thing that took me the longest to realize was…. I had a path issue pointing me to an old install of the appimage over the fresh build, fixed that up and now we are on 0.7.0 nightly. Related Links # [2] https://neovim.io/ https://github.com/neovim/neovim https://github.com/neovim/neovim/releases/tag/v0.6.0 References: [1]: /glossary/git/ [2]: #related-links

I made a neovim plugin

I’ve slowly adding more and more lua functions into my neovim configuration, and recently I noticed a pattern for a class of functions that reach out to run shell commands that can be abstracted away. https://youtu.be/8m5ipBuopPU Telegraph.nvim # [1] Check out the project readme [2] for the most up to date details on the plugin itself. Motivation # [3] I want a simple way to make remaps into shell commands that can open new tmux windows, popups, or just run a command with context from the editor. For example I want to make remaps to do things like open the current file in lookatme. # vim :terminal nnoremap <leader>s <cmd>Telegraph pipx run lookatme {filepath} --live-reload --style gruvbox-dark<cmd> # tmux session nnoremap <leader><leader>s <cmd>lua require'telegraph'.telegraph({cmd='pipx run lookatme {filepath} --live-reload --style gruvbox-dark', how='tmux'})<CR> # tmux popup nnoremap <leader><leader>S <cmd>lua require'telegraph'.telegraph({cmd='pipx run lookatme {filepath...

Notes for second vim-fundamentals course meetup

newline another Mahesh Subrajmanium Venkatachalam - Plugins | Installing a Theme Hunter Phillips - Quickfix | Offline Ordering with getqflist Andrea Wackerle - Search & Replace | Macros Matthew Fletcher - Registers | Advanced Motions Jump, Delete, & Select | Advanced Motions: Paste & Move Nicholas Payne - My First Vim Plugin | What Makes a Good Plugin Zev Averbach - Harpoon | Wrap up Plugin-manager # [1] - get a plugin manager - unless you are going full lua, most people use vim-plug by the great junegunn https://github.com/junegunn/vim-plug Install pluggged # [2] curl -fLo ~/.vim/autoload/plug.vim --create-dirs \ https://raw.githubusercontent.com/junegunn/vim-plug/master/plug.vim call plug#begin('~/.vim/plugged') Plug 'junegunn/fzf', { 'do': { -> fzf#install() } } Plug 'junegunn/fzf.vim' call plug#end() Install Plugins # [3] :PlugInstall :PlugClean :PlugUpdate Installing a Theme # [4] install using plug Plug 'ayu-theme/ayu-vim' set the theme set termguicolors let ayu...
1 min read