Wednesday, February 5, 2025

Curbing `~/.vimrc` Sprawl

I've been using vi-based editors since the late 80s. While an .exrc – or, as I eventually settled on vim as my vi-like editor, a .vimrc – is a generically decent way to pre-configure one's edit sessions, they have their shortcomings. As my work causes me to need to edit files of ever-broadening file-types, I find, with greater frequency, that I want to tailor my editor's behavior along swaths of file-types. In the land of monolithic .exrcs/.vimrcs, setting up customized-behaviors for multiple file-types results in the monolithic .exrcs/.vimrcs becoming stoopid-long. This makes them harder to read, harder to understand a general pain in the ass to maintain.

In general, I'm a fan of smaller config-files and using some kind of inheritance structure or other conditional-read method. Wasn't until today that I decided to see, "do current iterations of vim let me do that?" Boy was I glad I did: it turns out that the answer is, "yes it does". The key is judicious use of not only one's ~/.vimrc but of files in ~/.vim/.

After some digging around in the documentation and experimentation, I was able to solve my most pressing needs with a collection of files:

  • ~/.vimrc: the grand-daddy
  • ~/.vim/filetype.vim: To handle mapping file-extensions to vim-recognized file-type handlers
  • ~/.vim/ftplugin/bash.vim: A file-type handler for files with the .bash extension
  • ~/.vim/ftplugin/sh.vim: A file-type handler for files with the .sh extension

…I'll be adding more 

~/.vim/filetype.vim:

This file provides file-extension to file-type mappings. These mappings are used when using file-type files in the ~/.vim/ftplugin/ directory.

The contents of the ~/.vim/filetype.vim file is (currently) fairly simple and straight-foward:

"An easier-to read filetype mapper routine
if exists("did_load_filetypes")
finish
endif
augroup filetypedetect
au! BufRead,BufNewFile *.bash setfiletype bash
au! BufRead,BufNewFile *.sh setfiletype sh
augroup END

As the comment-line indicates, this file makes it easy to legibly extend mapping of file-suffixes to file types. This is done by using a grouping-block to apply autocmd-type directives. Such a grouping-block allow line-by-line mapping-extensions. The above replaces content like:

autocmd BufRead,BufNewFile *.sh,*.bash,*.sls,*.json,*.yml <ACTION>

Thus, if one wants to, say, add further file-type mappings (say for YAML files), one could add a line like:

au! BufRead,BufNewFile *.yml           setfiletype yaml

Or even:

au! BufRead,BufNewFile *.yml           setfiletype yaml
au! BufRead,BufNewFile *.yaml          setfiletype yaml

The latter line-pair captures YAML files that might be suffixed .yml or .yaml. As someone who does work for multiple organizations – either concurrently or serially – I've found, much to my consternation, that selected file-suffixes may differ from organization to organization.

~/.vim/ftplugin/*.vim:

The …/ftplugin directory contains the files that contain the actual, per file-type configuration-directives. The previous …/filetype.vim file's `setfiletype` command provides the value of the `*` in the header's wildcarded .vim file-names. Thus a .bash file that was mapped to the bash file-type will cause the ~/.vim/ftplugin/bash.vim file's configuration-options to be read.

Note: while my earlier file-list appears to show two, discrete config-files:

  • ~/.vim/ftplugin/bash.vim
  • ~/.vim/ftplugin/sh.vim

They are actually just one file that's hard-linked:

$ ls -il *.vim
330115 -rw-r--r-- 2 ferric ferric 453 Feb  5 16:27 bash.vim
330115 -rw-r--r-- 2 ferric ferric 453 Feb  5 16:27 sh.vim

These files (currently) contain:

"Ensure that lines break at 80 characters
set wrap
set textwidth=80
set wrapmargin=0

"Ensure linewraps happen when textwidth is reached
set formatoptions+=t

"Enable auto-indent
set autoindent

"Set 4-char tabstops
set tabstop=4

"Convert tabs to spaces
set expandtab

"Set autoindent to 4-chars
set shiftwidth=4

"Eliminate trailing whitespace
augroup prewrites
   autocmd!
    autocmd BufWritePre,FileWritePre * :%s/\s\+$//e | %s/\r$//e
augroup END

One could create equivalent *.vim files for other filetypes. One would do this if, say, you leveraged different maximum line-widths, indent-paddings or the like on a per-language file-basis.

~/.vimrc:

With the other files in place, this allows for a svelter ~/.vimrc file. Mine now looks like:

"Disable syntax-highlighting
syntax off

"Turn off search-highlighting
set nohlsearch

"Turn off angry fruit-salad
set t_Co=0

I, uh, hate the "angry fruit-salad" appearance that many distro's default vim-configs use.