Skip to content

Commit

Permalink
Test and doc fixes for keymapping helpers from code review
Browse files Browse the repository at this point in the history
  • Loading branch information
dbarnett committed Nov 8, 2020
1 parent 904530d commit 0fa264a
Show file tree
Hide file tree
Showing 4 changed files with 75 additions and 63 deletions.
47 changes: 22 additions & 25 deletions autoload/maktaba/keymapping.vim
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
""
" @dict KeyMapping
" A maktaba representation of a vim key mapping, which is used to configure and
" unmap it from vim.
" A maktaba representation of a Vim key mapping, which is used to configure and
" unmap it from Vim.


if !exists('s:next_keymap_id')
Expand Down Expand Up @@ -35,6 +35,7 @@ function! s:GetFuncCallKeystrokes(funcstr, mode) abort
elseif a:mode ==# 'i'
return printf('<C-\><C-o>:call %s<CR>', a:funcstr)
elseif a:mode ==# 'v'
" Needs C-u to remove "'<,'>" range inserted for commands from visual mode.
" Uses "gv" at the end to re-enter visual mode.
return printf(':<C-u>call %s<CR>gv', a:funcstr)
elseif a:mode ==# 's'
Expand All @@ -48,7 +49,16 @@ endfunction

""
" @dict KeyMapping
" Unmaps the mapping in vim.
" Returns 1 if the mapping is still defined, 0 otherwise
function! maktaba#keymapping#IsMapped() dict abort
let l:foundmap = maparg(self._lhs, self._mode, 0, 1)
return !empty(l:foundmap) && l:foundmap == self._maparg
endfunction


""
" @dict KeyMapping
" Unmaps the mapping in Vim.
" Returns 1 if mapping was found and unmapped, 0 if mapping was gone already.
function! maktaba#keymapping#Unmap() dict abort
if self.IsMapped()
Expand All @@ -68,18 +78,6 @@ function! maktaba#keymapping#Unmap() dict abort
endfunction


""
" @dict KeyMapping
" Returns 1 if the mapping is still defined, 0 otherwise
"
" Caveat: This detection can currently false positive if the original mapping
" was unmapped but then another similar one mapped afterwards.
function! maktaba#keymapping#IsMapped() dict abort
let l:foundmap = maparg(self._lhs, self._mode, 0, 1)
return !empty(l:foundmap) && l:foundmap == self._maparg
endfunction


""
" @dict KeyMapping
" Return a copy of the spec used to issue this mapping.
Expand All @@ -94,16 +92,15 @@ let s:GetSpec = function('maktaba#keymapping#GetSpec')


""
" Set up a key mapping in vim, mapping key sequence {lhs} to replacement
" sequence {rhs} in the given [mode]. This is a convenience wrapper for
" @function(#Spec) and its |KeyMappingSpec.Map| that supports the basic mapping
" options. It is equivalent to calling: >
" :call maktaba#keymapping#Spec({lhs}, {rhs}, [mode]).Map()
" Set up a key mapping in Vim, mapping key sequence {lhs} to replacement
" sequence {rhs} in the given [mode]. It is equivalent to calling: >
" :call maktaba#keymappingspec#Spec({lhs}, {rhs}, [mode]).Map()
" <
"
" See those functions for usage and behavior details.
" See the |maktaba#keymappingspec#Spec()| and |KeyMappingSpec.Map()| functions
" for usage and behavior details.
"
" @default mode=all of 'n', 'v', and 'o' (vim's default)
" @default mode=all of 'n', 'v', and 'o' (Vim's default)
function! maktaba#keymapping#Map(lhs, rhs, ...) abort
if a:0 >= 1
let l:spec = maktaba#keymappingspec#Spec(a:lhs, a:rhs, a:1)
Expand Down Expand Up @@ -179,7 +176,7 @@ endfunction
""
" @private
" @dict KeyMapping
" Defines the key mapping in vim via the |:map| commands for the keymap in self.
" Defines the key mapping in Vim via the |:map| commands for the keymap in self.
" Core internal implementation of @function(KeyMappingSpec.Map).
function! maktaba#keymapping#MapSelf() dict abort
" TODO(dbarnett): Perform a sweep for expired mapping timeouts before trying
Expand All @@ -199,7 +196,7 @@ endfunction
""
" @private
" @dict KeyMapping
" Define a buffer-local one-shot vim mapping from spec that will only trigger
" Define a buffer-local one-shot Vim mapping from spec that will only trigger
" once and then unmap itself.
"
" @throws NotImplemented if used with `WithRemap(1)`
Expand All @@ -226,7 +223,7 @@ endfunction
""
" @private
" @dict KeyMapping
" Define a short-lived vim mapping from spec that will only trigger once and
" Define a short-lived Vim mapping from spec that will only trigger once and
" will also expire if 'timeoutlen' duration expires with 'timeout' setting
" active. See |KeyMappingSpec.MapOnceWithTimeout()| for details.
"
Expand Down
15 changes: 8 additions & 7 deletions autoload/maktaba/keymappingspec.vim
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ let s:plugin = maktaba#Maktaba()

""
" @dict KeyMappingSpec
" A spec for a key mapping that can be mapped in vim with
" A spec for a key mapping that can be mapped in Vim with
" @function(KeyMappingSpec.Map).


""
" Create a @dict(KeyMappingSpec) that can be configured with options and then
" mapped in vim with @function(KeyMappingSpec.Map). The eventual mapping will
" mapped in Vim with @function(KeyMappingSpec.Map). The eventual mapping will
" map {lhs} to {rhs} in the given [mode].
"
" Initialized with recursive mappings disallowed by default (see |:noremap|).
Expand All @@ -18,7 +18,7 @@ let s:plugin = maktaba#Maktaba()
" Arguments will be configured with |map-<unique>| by default. Use the
" "overwrite" option of `.WithArgs(…, 1)` if you want to map without <unique>.
"
" @default mode=all of 'n', 'v', and 'o' (vim's default)
" @default mode=all of 'n', 'v', and 'o' (Vim's default)
function! maktaba#keymappingspec#Spec(lhs, rhs, ...) abort
let l:mode = get(a:, 1, '')

Expand Down Expand Up @@ -76,6 +76,7 @@ endfunction

""
" @dict KeyMappingSpec.Map
" Define a Vim mapping from spec via the |:map| commands.
function! maktaba#keymappingspec#MapSelf() dict abort
let l:keymap = maktaba#keymapping#PopulateFromSpec(self)
call l:keymap._DoMap()
Expand All @@ -85,7 +86,7 @@ endfunction

""
" @dict KeyMappingSpec.MapOnce
" Define a buffer-local one-shot vim mapping from spec that will only trigger
" Define a buffer-local one-shot Vim mapping from spec that will only trigger
" once and then unmap itself.
"
" Not supported for recursive mappings.
Expand All @@ -99,14 +100,14 @@ endfunction

""
" @dict KeyMappingSpec.MapOnceWithTimeout
" Define a short-lived vim mapping from spec that will only trigger once and
" Define a short-lived Vim mapping from spec that will only trigger once and
" will also expire if 'timeoutlen' duration expires with 'timeout' setting
" active.
"
" This is useful to detect if the user presses a key immediately after something
" else happens, and respond with a particular behavior.
"
" It can also be used for an improved version of vim's |map-ambiguous| behavior
" It can also be used for an improved version of Vim's |map-ambiguous| behavior
" when one mapping is a prefix of another. You can create a prefix mapping that
" does one thing immediately and then a different follow-up behavior on another
" keystroke.
Expand All @@ -117,7 +118,7 @@ endfunction
" \.WithArgs(['<buffer>']).MapOnceWithTimeout()<CR>
" <
"
" Caveat: Unlike vim's |map-ambiguous| behavior, this currently doesn't stop
" Caveat: Unlike Vim's |map-ambiguous| behavior, this currently doesn't stop
" waiting for keypresses if another unrelated key is pressed while it's waiting.
" Caveat: For long mappings, you might notice that the timeout is currently for
" the entire mapping and not for each keystroke. If you need to work around that
Expand Down
41 changes: 19 additions & 22 deletions doc/maktaba.txt
Original file line number Diff line number Diff line change
Expand Up @@ -244,24 +244,21 @@ Flag.Translate({value}) *Flag.Translate()*
running {value} through all registered translators).

*maktaba.KeyMapping*
A maktaba representation of a vim key mapping, which is used to configure and
unmap it from vim.

KeyMapping.Unmap() *KeyMapping.Unmap()*
Unmaps the mapping in vim. Returns 1 if mapping was found and unmapped, 0 if
mapping was gone already.
A maktaba representation of a Vim key mapping, which is used to configure and
unmap it from Vim.

KeyMapping.IsMapped() *KeyMapping.IsMapped()*
Returns 1 if the mapping is still defined, 0 otherwise

Caveat: This detection can currently false positive if the original mapping
was unmapped but then another similar one mapped afterwards.
KeyMapping.Unmap() *KeyMapping.Unmap()*
Unmaps the mapping in Vim. Returns 1 if mapping was found and unmapped, 0 if
mapping was gone already.

KeyMapping.GetSpec() *KeyMapping.GetSpec()*
Return a copy of the spec used to issue this mapping.

*maktaba.KeyMappingSpec*
A spec for a key mapping that can be mapped in vim with
A spec for a key mapping that can be mapped in Vim with
|KeyMappingSpec.Map()|.

KeyMappingSpec.WithArgs({args}, [overwrite]) *KeyMappingSpec.WithArgs()*
Expand All @@ -276,23 +273,24 @@ KeyMappingSpec.WithRemap({enabled}) *KeyMappingSpec.WithRemap()*
Throws ERROR(WrongType)

KeyMappingSpec.Map() *KeyMappingSpec.Map()*
Define a Vim mapping from spec via the |:map| commands.

KeyMappingSpec.MapOnce() *KeyMappingSpec.MapOnce()*
Define a buffer-local one-shot vim mapping from spec that will only trigger
Define a buffer-local one-shot Vim mapping from spec that will only trigger
once and then unmap itself.

Not supported for recursive mappings.
Throws ERROR(NotImplemented) if used with `WithRemap(1)`

KeyMappingSpec.MapOnceWithTimeout() *KeyMappingSpec.MapOnceWithTimeout()*
Define a short-lived vim mapping from spec that will only trigger once and
Define a short-lived Vim mapping from spec that will only trigger once and
will also expire if 'timeoutlen' duration expires with 'timeout' setting
active.

This is useful to detect if the user presses a key immediately after
something else happens, and respond with a particular behavior.

It can also be used for an improved version of vim's |map-ambiguous|
It can also be used for an improved version of Vim's |map-ambiguous|
behavior when one mapping is a prefix of another. You can create a prefix
mapping that does one thing immediately and then a different follow-up
behavior on another keystroke.
Expand All @@ -304,7 +302,7 @@ KeyMappingSpec.MapOnceWithTimeout() *KeyMappingSpec.MapOnceWithTimeout()*
\.WithArgs(['<buffer>']).MapOnceWithTimeout()<CR>
<

Caveat: Unlike vim's |map-ambiguous| behavior, this currently doesn't stop
Caveat: Unlike Vim's |map-ambiguous| behavior, this currently doesn't stop
waiting for keypresses if another unrelated key is pressed while it's
waiting. Caveat: For long mappings, you might notice that the timeout is
currently for the entire mapping and not for each keystroke. If you need to
Expand Down Expand Up @@ -1246,22 +1244,21 @@ maktaba#json#python#IsDisabled() *maktaba#json#python#IsDisabled()*
disabled, and prevents further changes.

maktaba#keymapping#Map({lhs}, {rhs}, [mode]) *maktaba#keymapping#Map()*
Set up a key mapping in vim, mapping key sequence {lhs} to replacement
sequence {rhs} in the given [mode]. This is a convenience wrapper for
|maktaba#keymapping#Spec()| and its |KeyMappingSpec.Map| that supports the
basic mapping options. It is equivalent to calling:
Set up a key mapping in Vim, mapping key sequence {lhs} to replacement
sequence {rhs} in the given [mode]. It is equivalent to calling:
>
:call maktaba#keymapping#Spec({lhs}, {rhs}, [mode]).Map()
:call maktaba#keymappingspec#Spec({lhs}, {rhs}, [mode]).Map()
<

See those functions for usage and behavior details.
See the |maktaba#keymappingspec#Spec()| and |KeyMappingSpec.Map()| functions
for usage and behavior details.

[mode] is all of 'n', 'v', and 'o' (vim's default) if omitted.
[mode] is all of 'n', 'v', and 'o' (Vim's default) if omitted.

maktaba#keymappingspec#Spec({lhs}, {rhs}, [mode])
*maktaba#keymappingspec#Spec()*
Create a |maktaba.KeyMappingSpec| that can be configured with options and
then mapped in vim with |KeyMappingSpec.Map()|. The eventual mapping will
then mapped in Vim with |KeyMappingSpec.Map()|. The eventual mapping will
map {lhs} to {rhs} in the given [mode].

Initialized with recursive mappings disallowed by default (see |:noremap|).
Expand All @@ -1270,7 +1267,7 @@ maktaba#keymappingspec#Spec({lhs}, {rhs}, [mode])
Arguments will be configured with |map-<unique>| by default. Use the
"overwrite" option of `.WithArgs(…, 1)` if you want to map without <unique>.

[mode] is all of 'n', 'v', and 'o' (vim's default) if omitted.
[mode] is all of 'n', 'v', and 'o' (Vim's default) if omitted.

maktaba#library#Import({library}) *maktaba#library#Import()*
Imports {library}.
Expand Down
35 changes: 26 additions & 9 deletions vroom/keymapping.vroom
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Now let's try it out!
:normal i
~ Nope!

Well, that was fun, but let's unlet our mapping and restore the original
Well, that was fun, but let's unmap our mapping and restore the original
behavior.

:call evil_mapping.Unmap()
Expand Down Expand Up @@ -62,19 +62,36 @@ open parentheses.



Vim also supports special arguments to mappings, such as the "<unique>" arg to
avoid overriding any existing mapping. Let's define a unique mapping and verify
that it's behaving politely.
Vim also supports special arguments to mappings to affect mapping behavior (see
:help :map-arguments). Let's use the <buffer> argument to define a buffer-local
mapping.

Maktaba provides a builder interface for mappings configuration more complex
than LHS, RHS, and mode. That will let us pass arguments in to the mapping we're
defining.

:let first_mapping = maktaba#keymapping#Map('!', '?')
:let polite_spec = maktaba#keymappingspec#Spec('!', '??')
|.WithArgs(['<unique>'])
:call maktaba#error#Try(maktaba#function#Method(polite_spec, 'Map'))
~ Vim(noremap):E227: * (glob)
:let buffer_mapping = maktaba#keymappingspec#Spec('!', '?')
|.WithArgs(['<buffer>'])
|.Map()
:let mapping_info = maparg('!', '', 0, 1)
:echomsg mapping_info.buffer
~ 1
:call buffer_mapping.Unmap()


By default Maktaba uses <unique> and defines non-recursive mappings to avoid
unpleasant surprises, since programmatically-defined mappings usually wouldn't
intend to silently override existing mappings or expand recursively-nested
mappings. The spec interface allows you to override these default behaviors.

:let recursive_nonunique_mapping = maktaba#keymappingspec#Spec('!', '?')
|.WithArgs([], 1)
|.WithRemap(1)
|.Map()
:let mapping_info = maparg('!', '', 0, 1)
:echomsg mapping_info.noremap
~ 0
:call recursive_nonunique_mapping.Unmap()



Expand Down

0 comments on commit 0fa264a

Please sign in to comment.