Search code examples
vimneovim

Modify vim (neovim) quote pairing to pair back tick with single quote in files with certain extensions


Context:

Vim and Neovim pair single quotes (') in several useful ways. In particular:

  1. When you enter ' vim generates another ' and places your cursor between the pair.
  2. The text between the 's is treated as a text object that vim can operate on.

The same behavior holds for back ticks (`) which vim pairs with a second back tick.

Question:

This is great; however, in some contexts a back tick should pair with a single quote rather than with a second back tick. My questions are:

  • Where is this behavior controlled?
  • And is this different in vim and neovim?
  • What are the my options for modifying this behavior so that a backtick pairs with a single quote only in certain contexts (i.e. files with certain extensions), while maintaining the default behavior elsewhere?

Examples:

Latex

In Latex opening double quotes are written using two backticks (``) rather than a double quote (") and are closed with two single quotes (''). In this case here the desired pairing would be two backticks and two single quotes with the cursor in the middle. Additionally, the text object should be the text between the set of backticks and the set of single quotes.

The csquotes package helpfully suggested below by Friedrich helps with the Latex case, but I'm interested in something that would address this more generally.

Stata

In Stata local macros and strings that include double quotes both use this pattern. A simple example:

local foo bar 
di "`foo'"
generate one_dbl_quote = `"""'

This puts the string bar into a local macro named foo then prints the contents of foo to the console, then creates a string variable holding a single double quote.


Solution

  • As it turns out, several answers of How can I treat LaTeX quotes as a text object? on Vi and Vim SE apply to this question as well.

    I'll not try to replicate all of the answers here but the answer by user superjer defines new mappings for aq and iq text-objects (see :help text-objects for more information). The answer is lightweight and can easily be adapted to this question. It does have the caveat that it only works for single quotes and only if the string is in one line which seems acceptable for Stata macros (not for LaTeX though).

    To enable the mappings only for the stata filetype (if the filetype is not known, consider adding it using the instructions from :help new-filetype), and create a ~/.vim/after/ftplugin/stata.vim file like this:

    vnoremap <buffer><silent> iq t'oT`
    onoremap <buffer> iq <Cmd>normal viq<CR>
    vnoremap <buffer><silent> aq f'oF`
    onoremap <buffer> aq <Cmd>normal vaq<CR>
    

    Or - a little bit less tidy - you could take a shortcut and just enable them via autocmd based on file extension in your vimrc:

    augroup quotes-text-objects
        autocmd!
        autocmd BufNew,BufEnter *.dta vnoremap <buffer><silent> iq t'oT`
        autocmd BufNew,BufEnter *.dta onoremap <buffer> iq <Cmd>normal viq<CR>
        autocmd BufNew,BufEnter *.dta vnoremap <buffer><silent> aq f'oF`
        autocmd BufNew,BufEnter *.dta onoremap <buffer> aq <Cmd>normal vaq<CR>
    augroup END
    

    Note that this uses <buffer> mappings so they don't leak out to non-Stata files. Instead of using iq and aq, you might even decide to go crazy and overwrite the default operators i` and a`.

    For strings spanning multiple lines, things get tricky fast. In that case, I'd suggest using a plugin such as the two mentioned in the linked question's answers: vim-sandwich or - for LaTeX specifically - textobj-latex.

    If you like any of these suggestions, visit Vi and Vim SE and give the respective authors your upvote!