Adventures in programming: Why is vim doing that?

Often in programming, you set out to write some code and you end up on a wild tangent instead. Seeing how someone else walks through one of their wild tangents can be very helpful, so here’s a walk through of the wild tangent I went on today.

What was I trying to do?


I’m working on scanning a bunch of old family photos and I eventually plan to put them online. Before I do so, I want to make sure the EXIF metadata is useful and well formatted, so I created myself a new github repo to store some scripts I’m planning to write. As I was writing a commit message while adding my initial .gitignore, I noticed that vim was inserting newlines and wrapping my commit message without me hitting Enter to move to a new line. While I certainly love a well formatted commit message, it really pulls me out of any kind of flow to have my text editor moving me to a new line without my asking. This annoys me enough, that I decided to dig into vim and figure out why my text was auto wrapping.

Why is vim automatically wrapping text?


First up, googling to remind myself what setting control text wrapping. My googling led me to https://vi.stackexchange.com/questions/2784/how-to-stop-gvim-wrapping-text-at-column-80 Based on that page, I want to check textwidth and formatoptions by running the following from within vim:

# Check textwidth value
:set tw?
# Check formatoptions value
:set fo?

I opened back up my .gitignore in vim and looked at those values:

:set tw?
  textwidth=0  
:set fo?
  formatoptions=croql

Hmmm, that textwidth=0 should mean that vim doesn’t auto wrap, but it definitely did auto wrap. I ran this from Windows Subsystem for Linux (WSL), which I’m new to using, so I decided to compare against what git bash sees. I fired up a git bash terminal, ran vim empty.txt at the command line, then re-ran those commands within vim:

:set tw?
  textwidth=0  
:set fo?
  formatoptions=tcq

Well, that also shouldn’t wrap, but doesn’t match what I saw when I opened .gitignore! My work Mac doesn’t do this, what’s different there? Checking again from vim empty.txt, but from my work Mac:

:set tw?
  textwidth=0  
:set fo?
  formatoptions=tcq

Huh, that setting is the same. Ah, but wait! I had seen the wrapping during writing a commit message. I fired up a quick commit message with git commit --allow-empty from WSL:

:set tw?
  textwidth=72
:set fo?
  formatoptions=tl

Aha! Text wrapping is turned on, but why? Is it turned on in git bash?

:set tw?
  textwidth=72
:set fo?
  formatoptions=tl

Yup, also on there! What about my work Mac?

:set tw?
  textwidth=0  
:set fo?
  formatoptions=tcq

Aha, text wrapping is NOT turned on for my work Mac when I write a commit message.


So, automatic wrapping is showing up for me on Windows when I write a git commit message, regardless of whether I’m using WSL or git bash. It is not showing up for me on my work Mac.

What is turning this automatic text wrapping on? Googling “what sets vim formatoptions git commit message” leads me to https://stackoverflow.com/questions/3459744/vim-using-non-standard-configuration-when-called-from-git-commit which mentions this might be caused by the filetype plugin. It turns out I can check my filetype plugin settings by running the following from within vim:

# Check filetype settings
:filetype

To be super sure I’m looking at the right settings, I ran this from within a git commit message again.

WSL and git bash:

:filetype
filetype detection:ON  plugin:ON  indent:ON

Mac:

:filetype
filetype detection:ON  plugin:OFF  indent:OFF

Well look at that! The filetype plugin is turned on in my Windows setup and turned off in my Mac setup! It looks like I’ve found the culprit!

Now how do I turn off this automatic text wrapping?


Now to chase down why these settings are different so I can figure out how best to turn off the filetype plugin — Time to look at what version(s) of vim I’m using and what’s in my vimrc files.

WSL:

maria@personal-laptop:/mnt/c/Users/maria/programming/image-processing-helpers$ vim --version
VIM - Vi IMproved 8.1 (2018 May 18, compiled Apr 15 2020 06:40:31)
Included patches: 1-2269
Modified by team+vim@tracker.debian.org
Compiled by team+vim@tracker.debian.org
Huge version without GUI.  Features included (+) or not (-):
+acl               -farsi             -mouse_sysmouse    -tag_any_white
+arabic            +file_in_path      +mouse_urxvt       -tcl
+autocmd           +find_in_path      +mouse_xterm       +termguicolors
+autochdir         +float             +multi_byte        +terminal
-autoservername    +folding           +multi_lang        +terminfo
-balloon_eval      -footer            -mzscheme          +termresponse
+balloon_eval_term +fork()            +netbeans_intg     +textobjects
-browse            +gettext           +num64             +textprop
++builtin_terms    -hangul_input      +packages          +timers
+byte_offset       +iconv             +path_extra        +title
+channel           +insert_expand     -perl              -toolbar
+cindent           +job               +persistent_undo   +user_commands
-clientserver      +jumplist          +postscript        +vartabs
-clipboard         +keymap            +printer           +vertsplit
+cmdline_compl     +lambda            +profile           +virtualedit
+cmdline_hist      +langmap           -python            +visual
+cmdline_info      +libcall           +python3           +visualextra
+comments          +linebreak         +quickfix          +viminfo
+conceal           +lispindent        +reltime           +vreplace
+cryptv            +listcmds          +rightleft         +wildignore
+cscope            +localmap          -ruby              +wildmenu
+cursorbind        -lua               +scrollbind        +windows
+cursorshape       +menu              +signs             +writebackup
+dialog_con        +mksession         +smartindent       -X11
+diff              +modify_fname      +sound             -xfontset
+digraphs          +mouse             +spell             -xim
-dnd               -mouseshape        +startuptime       -xpm
-ebcdic            +mouse_dec         +statusline        -xsmp
+emacs_tags        +mouse_gpm         -sun_workshop      -xterm_clipboard
+eval              -mouse_jsbterm     +syntax            -xterm_save
+ex_extra          +mouse_netterm     +tag_binary
+extra_search      +mouse_sgr         -tag_old_static
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/usr/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H   -Wdate-time  -g -O2 -fdebug-prefix-map=/build/vim-iU6mZD/vim-8.1.2269=. -fstack-protector-strong -Wformat -Werror=format-security -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: gcc   -Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -o vim        -lm -ltinfo -lnsl  -lselinux  -lcanberra -lacl -lattr -lgpm -ldl     -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -lpython3.8 -lcrypt -lpthread -ldl -lutil -lm -lm
maria@LAPTOP-TNGCNLQI:/mnt/c/Users/maria/programming/image-processing-helpers$ cat ~/.vimrc
cat: /home/maria/.vimrc: No such file or directory

git bash:

maria@personal-laptop MINGW64 ~/programming/tic-tac-toe (master)
$ vim --version
VIM - Vi IMproved 8.1 (2018 May 18, compiled Feb  7 2019 12:09:30)
Included patches: 1-877
Compiled by <alexpux@gmail.com>
Huge version without GUI.  Features included (+) or not (-):
+acl               +extra_search      +mouse_netterm     +tag_old_static
+arabic            +farsi             +mouse_sgr         -tag_any_white
+autocmd           +file_in_path      -mouse_sysmouse    -tcl
+autochdir         +find_in_path      +mouse_urxvt       +termguicolors
-autoservername    +float             +mouse_xterm       +terminal
-balloon_eval      +folding           +multi_byte        +terminfo
+balloon_eval_term -footer            +multi_lang        +termresponse
-browse            +fork()            -mzscheme          +textobjects
++builtin_terms    +gettext           +netbeans_intg     +textprop
+byte_offset       -hangul_input      +num64             +timers
+channel           +iconv             +packages          +title
+cindent           +insert_expand     +path_extra        -toolbar
-clientserver      +job               +perl/dyn          +user_commands
+clipboard         +jumplist          +persistent_undo   +vartabs
+cmdline_compl     +keymap            +postscript        +vertsplit
+cmdline_hist      +lambda            +printer           +virtualedit
+cmdline_info      +langmap           +profile           +visual
+comments          +libcall           +python/dyn        +visualextra
+conceal           +linebreak         +python3/dyn       +viminfo
+cryptv            +lispindent        +quickfix          +vreplace
+cscope            +listcmds          +reltime           +wildignore
+cursorbind        +localmap          +rightleft         +wildmenu
+cursorshape       -lua               +ruby/dyn          +windows
+dialog_con        +menu              +scrollbind        +writebackup
+diff              +mksession         +signs             -X11
+digraphs          +modify_fname      +smartindent       -xfontset
-dnd               +mouse             +startuptime       -xim
-ebcdic            -mouseshape        +statusline        -xpm
+emacs_tags        +mouse_dec         -sun_workshop      -xsmp
+eval              -mouse_gpm         +syntax            -xterm_clipboard
+ex_extra          -mouse_jsbterm     +tag_binary        -xterm_save
   system vimrc file: "/etc/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/etc"
 f-b for $VIMRUNTIME: "/usr/share/vim/vim81"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H   -I/usr/include/ncursesw  -march=x86-64 -mtune=generic -O2 -pipe -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: gcc   -L. -pipe -fstack-protector-strong -pipe -Wl,--as-needed -o vim.exe        -lm -lelf    -lncursesw -liconv -lacl -lintl   -Wl,--enable-auto-import -Wl,--export-all-symbols -Wl,--enable-auto-image-base -fstack-protector-strong  -L/usr/lib/perl5/core_perl/CORE -lperl -lpthread -ldl -lcrypt

maria@personal-laptop MINGW64 ~/programming/tic-tac-toe (master)
$ cat ~/.vimrc
cat: /c/Users/maria/.vimrc: No such file or directory

Mac:

[maria@work-laptop:~]$ vim --version
VIM - Vi IMproved 8.1 (2018 May 18, compiled Jun  5 2020 21:30:37)
macOS version
Included patches: 1-503, 505-680, 682-2292
Compiled by root@apple.com
Normal version without GUI.  Features included (+) or not (-):
+acl               -farsi             -mouse_sysmouse    -tag_any_white
-arabic            +file_in_path      -mouse_urxvt       -tcl
+autocmd           +find_in_path      +mouse_xterm       -termguicolors
+autochdir         +float             +multi_byte        +terminal
-autoservername    +folding           +multi_lang        +terminfo
-balloon_eval      -footer            -mzscheme          +termresponse
-balloon_eval_term +fork()            +netbeans_intg     +textobjects
-browse            -gettext           +num64             +textprop
+builtin_terms     -hangul_input      +packages          +timers
+byte_offset       +iconv             +path_extra        +title
+channel           +insert_expand     -perl              -toolbar
+cindent           +job               +persistent_undo   +user_commands
-clientserver      +jumplist          +postscript        -vartabs
+clipboard         -keymap            +printer           +vertsplit
+cmdline_compl     +lambda            -profile           +virtualedit
+cmdline_hist      -langmap           +python/dyn        +visual
+cmdline_info      +libcall           -python3           +visualextra
+comments          +linebreak         +quickfix          +viminfo
-conceal           +lispindent        +reltime           +vreplace
+cryptv            +listcmds          -rightleft         +wildignore
+cscope            +localmap          +ruby/dyn          +wildmenu
+cursorbind        -lua               +scrollbind        +windows
+cursorshape       +menu              +signs             +writebackup
+dialog_con        +mksession         +smartindent       -X11
+diff              +modify_fname      -sound             -xfontset
+digraphs          +mouse             +spell             -xim
-dnd               -mouseshape        +startuptime       -xpm
-ebcdic            -mouse_dec         +statusline        -xsmp
-emacs_tags        -mouse_gpm         -sun_workshop      -xterm_clipboard
+eval              -mouse_jsbterm     +syntax            -xterm_save
+ex_extra          -mouse_netterm     +tag_binary        
+extra_search      +mouse_sgr         -tag_old_static    
   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"
      user exrc file: "$HOME/.exrc"
       defaults file: "$VIMRUNTIME/defaults.vim"
  fall-back for $VIM: "/usr/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H   -DMACOS_X_UNIX  -g -O2 -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1      
Linking: gcc   -L/usr/local/lib -o vim        -lm -lncurses  -liconv -framework Cocoa  
[maria@work-laptop:~]$ cat ~/.vimrc
set expandtab
set tabstop=4
set ruler
syntax on
if has('autocmd')
    filetype on
    if !exists("autocommands_loaded")
        let autocommands_loaded = 1
        autocmd FileType go setlocal noexpandtab
    endif
endif

Hmmm, all 3 setups are using vim 8.1 though compiled at different times in different ways. A noteable difference is that I have created a ~/.vimrc file on my work laptop but not on my personal laptop.

This leads to my next question — If I don’t have a ~/.vimrc file, what configuration files does vim use? According to https://stackoverflow.com/questions/42772115/bash-on-windows-10-where-is-vimrc, we can use vim --version | grep vimrc to find out. I already ran vim --version, so I know that my interesting files are:

   system vimrc file: "$VIM/vimrc"
     user vimrc file: "$HOME/.vimrc"
 2nd user vimrc file: "~/.vim/vimrc"

Also of note is this line:

  fall-back for $VIM: "/usr/share/vim"

Adding that information together, I want to go look at /usr/share/vim/vimrc and compare between systems. Checking on WSL first:

maria@personal-laptop:/mnt/c/Users/maria/programming/image-processing-helpers$ cat /usr/share/vim/vimrc
" All system-wide defaults are set in $VIMRUNTIME/debian.vim and sourced by
" the call to :runtime you can find below.  If you wish to change any of those
" settings, you should do it in this file (/etc/vim/vimrc), since debian.vim
" will be overwritten everytime an upgrade of the vim packages is performed.
" It is recommended to make changes after sourcing debian.vim since it alters
" the value of the 'compatible' option.

runtime! debian.vim

" Vim will load $VIMRUNTIME/defaults.vim if the user does not have a vimrc.
" This happens after /etc/vim/vimrc(.local) are loaded, so it will override
" any settings in these files.
" If you don't want that to happen, uncomment the below line to prevent
" defaults.vim from being loaded.
" let g:skip_defaults_vim = 1

" Uncomment the next line to make Vim more Vi-compatible
" NOTE: debian.vim sets 'nocompatible'.  Setting 'compatible' changes numerous
" options, so any other options should be set AFTER setting 'compatible'.
"set compatible

" Vim5 and later versions support syntax highlighting. Uncommenting the next
" line enables syntax highlighting by default.
if has("syntax")
  syntax on
endif

" If using a dark background within the editing area and syntax highlighting
" turn on this option as well
"set background=dark

" Uncomment the following to have Vim jump to the last position when
" reopening a file
"au BufReadPost * if line("'\"") > 1 && line("'\"") <= line("$") | exe "normal! g'\"" | endif

" Uncomment the following to have Vim load indentation rules and plugins
" according to the detected filetype.
"filetype plugin indent on

" The following are commented out as they cause vim to behave a lot
" differently from regular Vi. They are highly recommended though.
"set showcmd            " Show (partial) command in status line.
"set showmatch          " Show matching brackets.
"set ignorecase         " Do case insensitive matching
"set smartcase          " Do smart case matching
"set incsearch          " Incremental search
"set autowrite          " Automatically save before commands like :next and :make
"set hidden             " Hide buffers when they are abandoned
"set mouse=a            " Enable mouse usage (all modes)

" Source a global configuration file if available
if filereadable("/etc/vim/vimrc.local")
  source /etc/vim/vimrc.local
endif

Hmmmm, this section looks like it might be relevant:

" Vim will load $VIMRUNTIME/defaults.vim if the user does not have a vimrc.
" This happens after /etc/vim/vimrc(.local) are loaded, so it will override
" any settings in these files.
" If you don't want that to happen, uncomment the below line to prevent
" defaults.vim from being loaded.
" let g:skip_defaults_vim = 1

What does the same file look like on my work Mac:

[maria@work-laptop:~]$ cat /usr/share/vim/vimrc 
" Configuration file for vim
set modelines=0		" CVE-2007-2438

" Normally we use vim-extensions. If you want true vi-compatibility
" remove change the following statements
set nocompatible	" Use Vim defaults instead of 100% vi compatibility
set backspace=2		" more powerful backspacing

" Don't write backup file if vim is being called by "crontab -e"
au BufWrite /private/tmp/crontab.* set nowritebackup nobackup
" Don't write backup file if vim is being called by "chpass"
au BufWrite /private/etc/pw.* set nowritebackup nobackup

let skip_defaults_vim=1

Aha, the file is different on my Mac — it is set to skip importing defaults.vim even if there is no ~/.vimrc file.


Since I know I don’t have a ~/.vimrc file on this Windows setup and my Mac setup both has a ~/.vimrc file and skips importing defaults.vim, I’ll try adding a ~/.vimrc file on my Window setup — this should cause vim to stop importing defaults.vim and should turn off the filetype plugin for me. I’ll go ahead and use the same ~/.vimrc contents from my work Mac, so my new ~/.vimrc is:

maria@personal-laptop:/mnt/c/Users/maria/programming/image-processing-helpers$ cat ~/.vimrc
set expandtab
set tabstop=4
set ruler
syntax on
if has('autocmd')
    filetype on
    if !exists("autocommands_loaded")
        let autocommands_loaded = 1
        autocmd FileType go setlocal noexpandtab
    endif
endif

Success!


Did that fix the problem? I check by again opening vim with git commit --allow-empty:

:filetype
filetype detection:ON  plugin:OFF  indent:OFF
:set tw?
  textwidth=0  
:set fo?
  formatoptions=tcq

Hooray! I turned off text wrapping! And it only took like an hour to figure out!

Final notes


Yes, programming is often like this. I didn’t actually write any code today, but I did get my configuration updated to better suit my preferences and I got a blog post out of it.