chrisbra / matchit

The matchit plugin from Vim
61 stars 9 forks source link

Toggle the plugin on the fly [enhancement] #36

Closed zzzyxwvut closed 1 year ago

zzzyxwvut commented 1 year ago

Can we enjoy the better part of both the built-in % and matchit's % by way of sourcing the plugin and then toggling its mappings (and state) on/off on demand? Maybe, some equivalent of {Do,No}MatchParen from the mathparen plugin.

Occasionally one may come across some code with strings or comments having unbalanced 'matchpairs' characters in it. At times the built-in % is able to skip over these, whereas matchit's % is at a loss with it, and vice versa.

For example, open a shell script test.sh as follows:vim --clean test.sh

#!/bin/sh

# (KEY TO THE SHORTHAND NOTES BELOW:
#
# The @[a-z] characters denote the placement of the cursor
# on the brace character at the line that is commented with
# its matching letter '#[a-z]', e.g. @a: the cursor is at
# line #a on either { or }.
#
# The % character tells that the % motion should be issued.
#
# The -> characters describe cursor movement.
#
# The (?) characters mark questionable destination.)

colon()
{   #a
    : # *{* #b
}   #c

#### MOTIONS FOR colon ####
#
# Without the 'matchit' plugin (regardless of &ft):
# @a % (no cursor movement) (?)
# @b % -> @c (?)
# @c % -> @b (?)
#
# Without the 'matchit' plugin (regardless of &ft),
# (if *{* is quoted as "{", and (&cpo =~ '%') == 0):
# @a % -> @c
# @b % -> @c (?)
# @c % -> @a
#
# With the 'matchit' plugin enabled (with --clean):
# :let &packpath = '~/.vim,' .. &packpath
# :packadd matchit
# :filter /matchit/ scriptnames
#
# and &ft == 'sh':
# @a % -> @c
# @b % -> @c (?) (with [%: -> @a)
# @c % -> @a
#
# With the 'matchit' plugin enabled and &ft == '':
# @a % (no cursor movement) (?)
# @b % -> @c (?) (with [%: -> @a)
# @c % -> @b (?)

echo_curly()
{   #d
    echo "{" #e
}   #f

#### MOTIONS FOR echo_curly ####
#
# Without the 'matchit' plugin (regardless of &ft):
# @d % -> @f
# @e % -> @f (?)
# @f % -> @d
#
# With the 'matchit' plugin enabled (regardless of &ft):
# @d % (no cursor movement) (?)
# @e % -> @f (?) (with [%: -> @d)
# @f % -> @e (?)

Environment:

Vim version: 9.0 (Included patches 1-1378) Matchit version: 1.18 (a clone of this repo at d19661)

zzzyxwvut commented 1 year ago

Thank you. Also don't forget to bump up the Version: number and to update the Last Change: date in plugin/matchit.vim and to regenerate doc/tags.

One thing that calls attention is that we ought to be scrupulous in the matter of the mapping context we return to with :MatchDisable. After all, matchit could be sourced after some other plugin that defines % mappings. That is,

:exe "nmap % :echo 'Oops!'<CR>"
:packadd matchit
:MatchDisable
:call feedkeys('%')

So, targeting the base version of Vim (8.2+) this plugin is written against, it would be prudent, in MatchEnable(), to poke about whether there are already mappings defined for the keys of interest, and if so, collect these mappings into a script-local dictionary; complementary, in MatchDisable(), the cached mappings would be restored and the relevant dictionary values reset.

Say, along the lines of,

let s:mappings = {
    \ '%n': '',
    \ '%o': '',
    \ '%x': '',
    "\ Other mappings.
\}

fun MatchEnable()
  " <Plug> mappings.

  if hasmapto('%', 'n')
    let s:mappings['%n'] = maparg('%', 'n')
  endif

  nmap <silent> % <Plug>(MatchitNormalForward)

  " Other mappings treated likewise.
endfun

fun MatchDisable()
  if s:mappings['%n'] != ''
    exe 'nmap % ' .. s:mappings['%n']
    let s:mappings['%n'] = ''
  else
    nunmap %
  endif

  " Other mappings treated likewise.
endfun
chrisbra commented 1 year ago

those metadata headers will be updated when I send a new version to Bram for inclusion with Vim.

Regarding the other thing, let's not overcomplicate things. I don't see the value of it.