Finish first doc

pull/3/head
Iron-E 4 years ago
parent 68e4537f15
commit 3a23642798
No known key found for this signature in database
GPG Key ID: 19B71B7B7B021D22

@ -2,18 +2,21 @@
*libmodal*
*nvim-libmodal*
=============================================================================
0. Table of Contents *libmodal-toc*
1. About ................ |libmodal-about|
2. Usage ................ |libmodal-usage|
3. Configuration ........ |libmodal-configuration|
4. License .............. |libmodal-license|
5. Bugs ................. |libmodal-bugs|
6. Contributing ......... |libmodal-contributing|
7. Changelog ............ |libmodal-changelog|
8. Credits .............. |libmodal-credits|
3. Examples ............. |libmodal-examples|
4. Configuration ........ |libmodal-configuration|
5. License .............. |libmodal-license|
6. Bugs ................. |libmodal-bugs|
7. Contributing ......... |libmodal-contributing|
8. Changelog ............ |libmodal-changelog|
9. Credits .............. |libmodal-credits|
============================================================================
1. About *libmodal-about*
==============================================================================
1. About *libmodal-about*
|nvim-libmodal|:
- Author, Iron-E @ https://github.com/Iron-E & https://gitlab.com/Iron_E
@ -30,13 +33,64 @@ modes is also creator-defined, and is outlined in |libmodal-usage|.
See: |vim-modes|
============================================================================
2. Usage *libmodal-usage*
Use Case ~
*libmodal-use-case-example*
As an |init.vim| configuration grows, it becomes harder to create keybindings
that alphabetically represent the action that they perform. To get around
this, |libmodal| allows users to create a new "layer" of keybindings contained
within a pseudo-|vim-mode|. This layer of keybindings can be bound to a
command which executes `libmodal.mode.enter()` or `libmodal.prompt.enter()`,
and any settings outside of these commands are preserved.
For example, say that a user of Neovim regularly converts between spaces and
tabs. They may define an "INDENT" mode that only requires pressing <Space>
or <Tab> to swap between 'expandtab' and 'shiftwidth' settings as well as
execute `retab`. This could be defined as a |user-function|, but the
keybindings are easier to remember as <Space> and <Tab>.
<Space> and <Tab>, however, are commonly mapped to. Rather than defining a
longer mapping to perform this operation, one may define a |user-command| to
enter "INDENT" mode where any mapping can be defined without affecting
mappings in other |vim-modes|.
Here is what that might look like:
>
--[[ .config/lua/indent_mode.lua ]]
local libmodal = require('libmodal')
local indent_mode = {}
local _combos = {
-- tabs to spaces
[' '] = 'set expandtab | %retab'
-- spaces to tabs
[' '] = 'set noexpandtab | %retab!'
}
function indent_mode.enter()
libmodal.mode.enter('INDENT', _combos)
end
return indent_mode
<
>
--[[ .config/nvim/init.vim ]]
command! IndentModeEnter lua requre('indent_mode').enter()
nnoremap <leader>i IndentModeEnter
<
Then this user could press `<leader>i` and have access to the <Space> and
<Tab> mappings that were defined, without affecting any other mappings.
See: |libmodal-usage|
==============================================================================
2. Usage *libmodal-usage*
The |libmodal| interface is designed completely in |Lua|. It is incompatable
with Vimscript until Neovim 0.5 releases (as
https://github.com/neovim/neovim/issues/11306 will merge). Because of this
timed incompatability, the following must be done:
with Vimscript until Neovim 0.5 releases (as `neovim/neovim#11306` will
merge). Because of this timed incompatability, the following must be done:
1. Define a |Lua| interface for your mode.
2. Use |lua-require| as a |user-command|.
@ -46,337 +100,518 @@ timed incompatability, the following must be done:
this. See below for a link to the repository where the source code may be
viewed.
See: |api|, |libmodal-lua|, |lua-api|, https://github.com/Iron-E/nvim-tabmode
The following is a reference for high-level functions meant to be used by mode
creators. For those who wish to see a low-level specification of |libmodal|,
see |libmodal-lua|.
Note: Examples for all topics covered here can be found in the "examples"
folder at the root of the repository.
See: |api|, |lua-api|, https://github.com/Iron-E/nvim-tabmode
Functions ~
*libmodal-mode-enter*
%%%%%%%%%%%%%%%%%%%%%%%%
%% TODO continue here %%
%%%%%%%%%%%%%%%%%%%%%%%%
|libmodal#Enter| takes three parameters. These parameters are not formally named
by the editor (as |libmodal#Enter| is declared `libmodal#Enter(`|...|`)` ).
However, the names of these parameters will be used throughout the document to
describe the index of the parameter (see |E740|).
Arg Index Use
--- ----- ---
`modeName` 0 The name for the mode when prompting the user.
`modeCallback` 1 The function used to control the mode.
`modeCombos` 1 A dictionary of |libmodal-key-combinations|.
`supressExit` 2 A flag to enable |libmodal-exit-supression|.
- NOTE: either `modeCallback` OR `modeCombos` may be specified, not both.
*libmodal#Prompt*
|libmodal#Prompt| takes two parameters. These parameters are not formally named
by the editor (as |libmodal#Prompt| is declared `libmodal#Prompt(`|...|`)` ).
However, the names of these parameters will be used throughout the document to
describe the index of the parameter (see |E740|).
Arg Index Use
--- ----- ---
`modeName` 0 The name for the mode when prompting the user.
`modeCallback` 1 The function used to control the mode.
`modeCommands` 1 A dictionary of commands→strings to execute.
`commandList` 2 A list of the commands in a `modeCallback`.
- NOTE: either `modeCallback` OR `modeCommands` may be specified, not both.
- NOTE: `commandList` is an optional parameter.
- It is used as a completion source for when `modeCallback` is
specified.
- Additionally, `commandList` is IGNORED when `modeCommands` is
specified since completions can be created from the dictionary keys.
- If `commandList` is not specified when `modeCallback` is, no
completions will be provided for the prompt.
Receiving Input ~
*libmodal-receiving-input*
When mode creators call |libmodal#Enter| or |libmodal#Prompt|, the
`modeName` parameter is used to generate a unique |global-variable| for the
specific purpose of receiving said input. The |variable| is generated as
follows:
>
let g:{tolower(a:modeName)}ModeInput = …
*libmodal-mode* *libmodal.mode.enter()*
libmodal.mode.enter({name}, {instruction} [, {handleExit}])
Enter a new |vim-mode| using {instruction} to determine what actions will
be taken upon specific user inputs.
User input is taken one character at a time using |getchar()|. It is
passed through a |g:var| determined by the {name} of the mode. For
example, if {name} is "FOO" then the |g:var| is `g:fooModeInput`.
Additionally, this input is reported as a |char2nr| number, and as such
should be decoded with `string.char()` (|nr2char| in |Lua|) if working
with raw characters is desired.
To take input on a line-by-line basis, see |libmodal-prompt|.
Note: `libmodal.mode.enter()` may be called from inside itself. See
|libmodal-examples-submodes| for an example.
Parameters: ~
{name} The name of the mode (e.g. |INSERT|).
- Case-sensitive. Caps are recommended.
{instruction} What to do when accepting user input.
- If {instruction} is a `table`, then it is treated as
a map of user key-chord to Vim |command|s. Example: >
local modeInstruction = {
['zf'] = 'split',
['zfo'] = 'vsplit',
['zfc'] = 'tabnew'
}
<
For example, if `modeName` is 'FOO', then the |variable| that is created is
`g:fooModeInput`.
Note: If no `?` key is defined, one will be created
automatically.
Creating Modes ~
*libmodal-creating-modes*
- If {instruction} is a `function`, then it is called
every time that |getchar()| completes. The user input
is received through `g:{name}ModeInput` (see above).
For an example of a plugin that uses |libmodal|, see
https://github.com/Iron-E/vim-tabmode.
Note: Some QoL features are available by default when
specifying a `table` value for {instruction} that
would otherwise have to be programmed manually if
a `function` is specified.
To define a new mode, you must first create a |user-function| to pass into
|libmodal#Enter|. Example:
- A user's typed characters will show in the
lower right corner when {instruction} is a table.
- If `g:libmodalTimeouts` is enabled, then user input will be
subjected to the |timeoutlen|.
>
function! s:FooMode()
if g:fooModeInput ==# "a"
execute 'tabnew'
elseif g:fooModeInput ==# "d"
execute 'tabclose'
endif
endfunction
{supressExit} Whether or not to automatically exit the mode upon an
<Esc> press.
- If `false`, then <Esc> is automatically mapped to
exiting.
- If `true`, then <Esc> is ignored unless specified by
the user. In such cases, the user should set the
`g:`{name}`ModeExit` variable to `true` when exiting is
desired. See |libmodal-examples-supress-exit|.
See also: ~
|lua-eval| For type conversions between Vimscript to |Lua|.
|libmodal-examples-mode| For examples of this function.
*libmodal-prompt* *libmodal.prompt.enter()*
libmodal.prompt.enter({name}, {instruction} [, {completions}])
Besides accepting user input like keys in |Normal-mode|, |libmodal| is
also capable of prompting the user for |input| like |Cmdline-mode|. To
define a |Cmdline-mode|-like prompt, use this function rather than
`libmodal.mode.enter()`.
User input is taken using |input()|. It is passed through a |g:var|
determined by the {name} of the mode. For example, if {name} is "FOO"
then the |g:var| is `g:fooModeInput`.
Parameters: ~
{name} The name of the mode (e.g. |INSERT|).
- Case-sensitive. Caps are recommended.
{instruction} What to do when accepting user input.
- If {instruction} is a `table`, then it is treated as
a map of user inputs to Vim |command|s. Example: >
local modeInstruction = {
['new'] = 'tabnew',
['close'] = 'tabclose',
['last'] = 'tablast'
}
<
- If {instruction} is a `function`, then it is called
every time that |input()| completes. The user input
is received through `g:{name}ModeInput` (see above).
After defining said |user-function|, you can create a |mapping| to enter the
mode.
Note: If you want to create commands with arguments, you will
need to use a `function`.
>
command! FooModeEnter call libmodal#Enter('FOO', funcref('s:FooMode'))
nnoremap <leader>n :FooModeEnter
{completions} An array-like `table` of commands that are offered by
the prompt.
- Automatically generated when {instruction} is a `table`.
- Used to provide auto-completion when the user is typing.
- If unspecified, and {instruction} is not a `table`, then no
completions will be provided.
Note: If no `help` command is defined, one will be created
automatically.
See also: ~
|lua-eval| For type conversions between Vimscript to |Lua|.
|libmodal-examples-prompt| For examples of this function.
==============================================================================
3. Examples *libmodal-examples*
Below are examples written in |Lua| to help show how specific features of
|libmodal| may be implemented. In each example, the name of the mode is
defined as "FOO". Additionally, each category of example has one example for
both `function` and `table` {instruction}s.
The source code can be either copied from here or downloaded from the
repository's `examples/lua` folder. Assuming |libmodal| is installed, they can
all be tested using the |luafile| |command|.
See: |libmodal-usage|, |libmodal-use-case|, |lua-require-example|.
libmodal.mode.enter() ~
*libmodal-examples-mode*
Using a callback `function`: >
local api = vim.api
local libmodal = require('libmodal')
local fooModeInputHistory = {}
local function clearHistory(indexToCheck)
if #fooModeInputHistory >= indexToCheck then
fooModeInputHistory = {}
end
end
function fooMode()
fooModeInputHistory[#fooModeInputHistory + 1] = string.char(
api.nvim_get_var('fooModeInput')
)
local index = 1
if fooModeInputHistory[1] == 'z' then
if fooModeInputHistory[2] == 'f' then
if fooModeInputHistory[3] == 'o' then
api.nvim_command("echom 'It works!'")
else index = 3 end
else index = 2 end
end
clearHistory(index)
end
libmodal.mode.enter('FOO', fooMode)
<
- NOTE: the |funcref()| call must be there or else |libmodal#Enter| won't
execute properly.
Using a |key-mapping| `table`: >
local libmodal = require('libmodal')
local fooModeCombos = {
['zf'] = 'split',
['zfo'] = 'vsplit',
['zfc'] = 'tabnew'
}
*libmodal-key-combinations*
libmodal.mode.enter('FOO', fooModeCombos)
<
While normally |libmodal| dictates that a mode creator should define their own
|user-function| for controlling a mode, there is a way to specify key
combinations. If the second argument is set to a `modeCombos` |Dictionary|,
|libmodal#Enter| will automatically detect the |call|er's intent and pass control
over to an auxilliary function built to handle pre-defined combos.
*libmodal-examples-supress-exit*
- NOTE: When providing `modeCombos`, one no longer has to receive input for
themselves. Despite this, the unique |variable| (see
|libmodal-receiving-input|) is still updated, and you can create a
listener for it just like for any other |variable|.
Using a callback `function`: >
local libmodal = require('libmodal')
- NOTE: |libmodal-exit-supression| is still compatable with defining key
combinations.
function fooMode()
local userInput = string.char(
vim.api.nvim_get_var('fooModeInput')
)
Here is an example that shows how to create a |Dictionary| that defines the
following actions:
if userInput == '' then
vim.api.nvim_command("echom 'You cant leave using <Esc>.'")
elseif userInput == 'q' then
vim.api.nvim_set_var('fooModeExit', true)
end
end
Combo Action
----- ------
`zfo` Echo a message saying "It works!"
`zfc` Create a new tab.
vim.api.nvim_set_var('fooModeExit', 0)
libmodal.mode.enter('FOO', fooMode, true)
<
>
let s:barModeCombos = {
\ 'zfo': 'echom "It works!"',
\ 'zfc': 'tabnew'
\}
Using a |key-mapping| `table`: >
local libmodal = require('libmodal')
local fooModeCombos = {
[''] = 'echom "You cant exit using escape."',
['q'] = 'let g:fooModeExit = 1'
}
vim.api.nvim_set_var('fooModeExit', 0)
libmodal.mode.enter('FOO', fooModeCombos, true)
<
- NOTE: When defining actions that involve a chorded keypress (e.g. |CTRL-W_s|),
mode creators should use |i_CTRL-V| to insert the literal of that
character.
- For example, if a mode creator wants a mapping for `<C-s>v`, then it
should be specified as `v`.
*libmodal-examples-submodes*
And then to enter that mode, you can call:
Using a callback `function`: >
local libmodal = require('libmodal')
local fooModeRecurse = 0
>
call libmodal#Enter('BAR', s:barModeCombos)
function fooMode()
local userInput = string.char(vim.api.nvim_get_var(
'foo' .. tostring(fooModeRecurse) .. 'ModeInput'
))
if userInput == 'z' then
fooModeRecurse = fooModeRecurse + 1
enter()
fooModeRecurse = fooModeRecurse - 1
end
end
function enter()
libmodal.mode.enter('FOO' .. fooModeRecurse, fooMode)
end
enter()
<
|libmodal|'s internal processing of that |Dictionary| becomes more useful the
larger the |Dictionary| is. Internally, `s:barModeCombos` is rendered into a
|Dictionary| that looks like this:
Using a |key-mapping| `table`: >
local libmodal = require('libmodal')
local fooModeRecurse = 0
local fooModeCombos = {
['z'] = 'lua fooMode()'
}
>
let s:barModeCombosInternal = {
\ 'z': {
\ 'f': {
\ 'c': 'echom "It works!"',
\ 'o': 'tabnew'
\ }
\ }
\}
function fooMode()
fooModeRecurse = fooModeRecurse + 1
libmodal.mode.enter('FOO' .. fooModeRecurse, fooModeCombos)
fooModeRecurse = fooModeRecurse - 1
end
fooMode()
<
This allows |libmodal| to quickly determine which |map|pings are and are not
part of the mode. Because of this method, modes with |map|pings that have
similar beginnings are more efficient, and modes with more mappings get more
benefit from the quick tree-like traversal.
- NOTE: |libmodal#Enter| will only parse a `modeCombos` dict once upon
entrance.
- Changes to the mapping dictionary that may occur while in a mode
are not reflected until the mode is entered again and the dictionary
is re-parsed.
*libmodal-timeouts*
When |libmodal-key-combinations| are being used, mode creators may also enable
the use of Vim's built-in |timeout| feature. Unlike other options which are
specified by passing arguments to |libmodal#Enter|, this feature is enabled
through a |variable|.
- NOTE: If two keybinds share a beginning, and one is shorter than the other,
(e.g. `zf` and `zfo`), then the user must press <CR> to execute it.
This also means that commands ending in ` ` are not permitted.
- Unfortunately, because of the limitations of Vimscript (more
specifically |getchar()|) it is not possible to execute a function
on |timeout| using |timers| exposed by the API. |getchar()| blocks
execution and there is no combination of |sleep| or |wait()| that
will allow |getchar()| to be called asynchronously
- If you are reading this and know how to do something like this
without using a secondary language, please let me know or open a
pull request.
The reasoning for this is that the use of |timeout|s is primarily chosen by the
user of a mode, rather than the creator (whereas other features like
|libmodal-exit-supression| are largely creator-oriented).
To enable |timeout|s, one may set the following |variables|:
libmodal.prompt.enter() ~
*libmodal-examples-prompt*
Using a callback `function`: >
local libmodal = require('libmodal')
local api = vim.api
local commandList = {'new', 'close', 'last'}
function fooMode()
local userInput = vim.api.nvim_get_var('fooModeInput')
if userInput == 'new' then
api.nvim_command('tabnew')
elseif userInput == 'close' then
api.nvim_command('tabclose')
elseif userInput == 'last' then
api.nvim_command('tablast')
end
end
libmodal.prompt.enter('FOO', fooMode, commandList)
<
Using a |command| `table`: >
local libmodal = require('libmodal')
local commands = {
['new'] = 'tabnew',
['close'] = 'tabclose',
['last'] = 'tablast'
}
libmodal.prompt.enter('BAR', commands)
<
==============================================================================
4. Configuration *libmodal-configuration*
Highlighting ~
*libmodal-highlight-groups*
The following |highlight-groups| can be |config|ured to change a mode's |color|s:
Name Default Description
---- ------- -----------
`LibmodalPrompt` `ModeMsg` Color for the mode text.
`LibmodalStar` `StatusLine` Color for the prompt text.
Note: `LibmodalStar`'s name — while not indicative of its use — is used for
the sake of backwards compatability.
- While |nvim-libmodal| might not be 100% backwards compatable with
|vim-libmodal| due to limitations of Neovim 0.4, an update will ship
when Neovim 0.5 launches that will introduce interoperaability between
the two.
Timeouts ~
*libmodal-timeouts*
*g:libmodalTimeouts*
When `libmodal.mode.enter()`'s {instruction} argument is a `table`, mode
creators may also enable the use of Vim's built-in 'timeout' feature.
To enable 'timeout's, one may set the following |variables|:
>
" Set libmodal modes to turn timeouts on.
let g:libmodalTimeouts = 1
" Enable timeouts for specific mode.
let g:{modeName}ModeTimeout = 1
let g:{name}ModeTimeout = 1
<
Similarly, to disable them, one may set them to `0`.
- NOTE: If not specified by the user, `g:libmodalTimeouts` automatically
references the |timeout| on/off value.
- NOTE: The `g:limbodalTimeouts` variable should NOT be defined by plugins.
- Allow users to decide whether or not they want timeouts to be
enabled globally by themselves.
- NOTE: Mode-specific timeout variables will override `g:libmodalTimeouts`.
- This is so a default may be set but overridden.
When `g:libmodalTimeouts` or `g:{name}ModeTimeout` is set to `1`, |libmodal|
will automatically execute commands that have mappings that might also be
longer mappings. For example:
If a mode specifies `zf` and `zfo` as mappings,
- Turning 'timeout's on will cause `zf` to be executed if the user waits
for 'timeoutlen' without typing another character.
- If 'timeout' were to be off in this case, then the user would either
have to hit <CR> to execute `zf` or hit `o` to execute `zfo`.
NOTE: `g:libmodalTimeouts` defaults to the 'timeout' value.
When enabled, |libmodal-timeouts| will reference the mode user's |timeoutlen|
NOTE: The `g:limbodalTimeouts` variable should NOT be defined by plugins.
- Allow users to decide whether or not they want timeouts to be
enabled globally themselves.
NOTE: Mode-specific timeout variables will override `g:libmodalTimeouts`.
When enabled, |libmodal-timeouts| will reference the mode user's 'timeoutlen'
as specified in their |config|. This way, modes will feel consistent to users
by default.
However, mode creators may change |timeoutlen| upon entrance of a mode, and
However, mode creators may change 'timeoutlen' upon entrance of a mode, and
then reset it upon exit. Example:
Vimscript: ~
>
function! s:BarMode() abort
" Get the user's preferred timeout length.
let l:timeoutlen = &timeoutlen
" Set it to something else, like 1500ms
let &timeoutlen = 1500
" Enter a mode
call libmodal#Enter(…)
" Reset the timeout
let &timeoutlen = l:timeoutlen
endfunction
function! s:FooMode() abort
" Get the user's preferred timeout length.
let l:timeoutlen = &timeoutlen
" Set it to something else, like 1500ms
let &timeoutlen = 1500
" Enter a mode
call libmodal#Enter(…)
" Reset the timeout
let &timeoutlen = l:timeoutlen
endfunction
<
Lua: ~
>
local api = vim.api
local libmodal = require('libmodal')
function fooMode()
-- Get the user's preferred timeout length.
local prevTimeoutLen = api.nvim_get_option('timeoutlen')
-- Set it to something else, like 1500ms.
api.nvim_set_option('timeoutlen', 1500)
-- Enter a mode.
libmodal.mode.enter(…)
-- Restore the `timeoutlen`
api.nvim_set_option('timeoutlen', prevTimeoutLen)
end
<
Mode creators who use `modeCallback`s may define timeouts manually using
|timers|, which is how |libmodal| implements them internally.
Mode creators who use `function` {instruction}s may define timeouts manually
using |timers|, which is how |libmodal| implements them internally.
*libmodal-exit-supression*
==============================================================================
5. License *libmodal-license*
When the `supressExit` parameter is specified, |libmodal#Enter| will ignore
<Esc> presses and instead listen for changes to a unique |variable| created
for the specific purpose of exiting the mode. The |variable| is generated as
follows:
`nvim-libmodal` Create new "modes" for Neovim.
Copyright © 2020 Iron-E
>
let g:{tolower(a:modeName)}ModeExit = 0
<
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
When this |variable| becomes set to `1`, the mode will exit the next time that
the `modeCallback` |user-function| |return|s.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
Creating Prompts ~
*libmodal-creating-prompts*
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Besides accepting user input like keys in |Normal-mode|, |libmodal| is also
capable of prompting the user for |input| like |Cmdline-mode|. To define a
|Cmdline-mode|-like prompt, use |libmodal#Prompt| rather than |libmodal#Enter|.
==============================================================================
6. Bugs *libmodal-bugs*
When `modeCommands` is specified, completions are provided the |keys| in
the |Dictionary| (see |command-completion-customlist|). See an example of this
below:
* Passing a |funcref| through Vimscript to |Lua| yields a `nil`.
* This bug is fixed in Neovim 0.5, and when it releases, there will be a
patch for this plugin to fix it and introduce compatability with
|vim-libmodal|.
>
let s:barModeCommands = {
\ 'new': 'tabnew',
\ 'close': 'tabclose',
\ 'last': 'tablast'
\}
<
==============================================================================
7. Contributing *libmodal-contributing*
When `modeCallback` is specified, completions must be provided separately.
An equivalent to the above using a `modeCallback` would be:
Code ~
>
" Define callback
function! s:BarMode() abort
if g:barModeInput ==# 'new'
execute 'tabnew'
elseif g:barModeInput ==# 'close'
execute 'tabclose'
elseif g:barModeInput ==# 'last'
execute 'tablast'
endif
endfunction
" Define completion list
let s:barModeCommandList = ['new', 'close', 'last']
<
Bugfixes ~
You can then enter the mode using one of the following commands (depending on
whether or not you used a |Dictionary| or a callback):
If you discover a bug and believe you know the solution to fixing it, then
submit a bug report and state that you are working on a fix (and what that
fix might be), and what general timeframe the fix may be completed in
(months, weeks, days, etc.).
>
" Command dict
call libmodal#Prompt('BAR', s:barModeCommands)
" Callback + completion list
call libmodal#Prompt('BAR', funcref('s:BarMode'), s:barModeCommandList)
<
When the fix is complete, submit a PR that references the issue you
submitted.
- NOTE: if you want to create commands with arguments, you will need to
use a callback.
Features ~
Submodes ~
*libmodal-submodes*
If there is a feature you would like to be a part of |libmodal|, the best
thing you can do is submit a feature request, and then state that you are
working on a pull request (PR) so others don't attempt to do the same work
at the same time.
|libmodal| has built-in support for entering additional modes while already in
a |libmodal| mode. To enter another mode, one must only call |libmodal#Enter|
(or |libmodal#Prompt|) from within a mode. Additionally, when a user presses
<Esc> they will automatically be taken back to the mode that they were
previously inside of (unless |libmodal-exit-supression| is used).
When you believe your feature is complete, write some examples for it in
the `examples/lua` folder, and add them to |libmodal-examples| as
appropriate.
To test out this feature, one may run the following:
Assure that all existing |libmodal-examples| continue to work with your
feature, unless a breaking change was discussed on the feature request.
If you need help getting them to pass, you can ask for help on the PR.
>
let s:recurse = 0
function! s:BarMode()
if g:bar{s:recurse}ModeInput ==# 'z'
let s:recurse += 1
execute 'BarModeEnter'
let s:recurse -= 1
endif
endfunction
let l:func = funcref('s:BarMode')
command! BarModeEnter call libmodal#Enter('BAR' . s:recurse, l:func)
execute 'BarModeEnter'
<
Reference the issue you submitted on the PR so that the two show up
together when looking back at the history.
This triggers |libmodal#Enter| every time the user inputs the "z" key. While
this example only uses one `modeCallback`, it is possible to use as many
submodes as Vim's call-stack can handle (i.e. a lot).
Contributing documentation is not necessary but appreciated, since the
person who knows the most about the feature being implemented is most
likely the one implementing it.
============================================================================
4. Configuration *libmodal-configuration*
Documentation ~
The following |highlight-groups| can be |config|ured to change a mode's |color|s:
If there is a problem with the documentation, or you see an area where it
could be improved, don't hesitate to submit an issue and a PR. At the very
least it will exist in history if such an issue comes up again, and likely it
will serve to help yourself and others with more clear and concise wording, or
with more helpful and practical examples.
Name Default Description
---- ------- -----------
`LibmodalPrompt` `ModeMsg` Color for the mode text.
`LibmodalStar` `StatusLine` Color for the `*` at the beginning.
Issues ~
Issues are greatly welcomed on the GitHub repository, whether they are bug
reports, feature requests, documentation improvements, or misunderstandings:
it's all good to have in the archive.
When submitting an issue, please describe the following:
1. Context regarding the issue (how you discovered it, pertinent information,
etc.)
2. Detailed description of the issue.
3. Steps to reproduce (if applicable).
4. Expected behavior (if applicable).
5. Attached media (screenshots, logs, etc.) (if applicable).
==============================================================================
8. Changelog *libmodal-changelog*
0.3.0 ~
* Generate `?` mapping for |libmodal-mode|s.
0.2.1 ~
* Fix `help` command completion being shown during an {instruction} callback
`function` when none should be shown.
0.2.0 ~
* |libmodal-prompt| implemetation from |vim-libmodal|.
* |libmodal-prompt|s now automatically generate `help` command if none is
provided.
0.1.0 ~
* |libmodal-mode| implementation from |vim-libmodal|.
==============================================================================
9. Credits *libmodal-credits*
Credit Reason
--------------------- ----------------------------------
Daniel Steinberg |vim-win| creator and inspiration.
Iron-E Primary contibuter/maintainer.
neoclide/|coc-nvim| Development environment provider.
r/Neovim |Lua| and Neovim reference.
Roberto Ierusalimschy "Programming In Lua: 5.1".
Steve Losh "Learn Vimscript The Hard Way".
tbastos/vim-lua Syntax highlighting for |Lua|.
u/Mambu38 |Lua| reference.
u/oryiesis Inspiration.
www.lua-users.org |Lua| reference.
www.stackoverflow.com Vimscript and |Lua| reference.
============================================================================
==============================================================================
vim:tw=78:ts=4:ft=help:norl:

@ -1,22 +1,22 @@
local api = vim.api
local libmodal = require('libmodal')
local barModeInputHistory = {}
local fooModeInputHistory = {}
local function clearHistory(indexToCheck)
if #barModeInputHistory >= indexToCheck then
barModeInputHistory = {}
if #fooModeInputHistory >= indexToCheck then
fooModeInputHistory = {}
end
end
function barMode()
barModeInputHistory[#barModeInputHistory + 1] = string.char(
api.nvim_get_var('barModeInput')
function fooMode()
fooModeInputHistory[#fooModeInputHistory + 1] = string.char(
api.nvim_get_var('fooModeInput')
)
local index = 1
if barModeInputHistory[1] == 'z' then
if barModeInputHistory[2] == 'f' then
if barModeInputHistory[3] == 'o' then
if fooModeInputHistory[1] == 'z' then
if fooModeInputHistory[2] == 'f' then
if fooModeInputHistory[3] == 'o' then
api.nvim_command("echom 'It works!'")
else index = 3 end
else index = 2 end
@ -25,4 +25,4 @@ function barMode()
clearHistory(index)
end
libmodal.mode.enter('BAR', barMode)
libmodal.mode.enter('FOO', fooMode)

@ -1,13 +1,13 @@
local libmodal = require('libmodal')
local barModeRecurse = 0
local barModeCombos = {
['z'] = 'lua barMode()'
local fooModeRecurse = 0
local fooModeCombos = {
['z'] = 'lua fooMode()'
}
function barMode()
barModeRecurse = barModeRecurse + 1
libmodal.mode.enter('BAR' .. barModeRecurse, barModeCombos)
barModeRecurse = barModeRecurse - 1
function fooMode()
fooModeRecurse = fooModeRecurse + 1
libmodal.mode.enter('FOO' .. fooModeRecurse, fooModeCombos)
fooModeRecurse = fooModeRecurse - 1
end
barMode()
fooMode()

@ -1,8 +1,8 @@
local libmodal = require('libmodal')
local barModeCombos = {
local fooModeCombos = {
[''] = 'echom "You cant exit using escape."',
['q'] = 'let g:barModeExit = 1'
['q'] = 'let g:fooModeExit = 1'
}
vim.api.nvim_set_var('barModeExit', 0)
libmodal.mode.enter('BAR', barModeCombos, true)
vim.api.nvim_set_var('fooModeExit', 0)
libmodal.mode.enter('FOO', fooModeCombos, true)

@ -1,8 +1,8 @@
local libmodal = require('libmodal')
local barModeCombos = {
local fooModeCombos = {
['zf'] = 'split',
['zfo'] = 'vsplit',
['zfc'] = 'tabnew'
}
libmodal.mode.enter('BAR', barModeCombos)
libmodal.mode.enter('FOO', fooModeCombos)

@ -2,8 +2,8 @@ local libmodal = require('libmodal')
local api = vim.api
local commandList = {'new', 'close', 'last'}
function barMode()
local userInput = vim.api.nvim_get_var('barModeInput')
function fooMode()
local userInput = vim.api.nvim_get_var('fooModeInput')
if userInput == 'new' then
api.nvim_command('tabnew')
elseif userInput == 'close' then
@ -13,4 +13,4 @@ function barMode()
end
end
libmodal.prompt.enter('BAR', barMode, commandList)
libmodal.prompt.enter('FOO', fooMode, commandList)

@ -1,8 +1,8 @@
local libmodal = require('libmodal')
local commands = {
['new'] = 'tabnew',
['new'] = 'tabnew',
['close'] = 'tabclose',
['last'] = 'tablast'
['last'] = 'tablast'
}
libmodal.prompt.enter('BAR', commands)
libmodal.prompt.enter('FOO', commands)

@ -1,20 +1,20 @@
local libmodal = require('libmodal')
local barModeRecurse = 0
local fooModeRecurse = 0
function barMode()
function fooMode()
local userInput = string.char(vim.api.nvim_get_var(
'bar' .. tostring(barModeRecurse) .. 'ModeInput'
'foo' .. tostring(fooModeRecurse) .. 'ModeInput'
))
if userInput == 'z' then
barModeRecurse = barModeRecurse + 1
fooModeRecurse = fooModeRecurse + 1
enter()
barModeRecurse = barModeRecurse - 1
fooModeRecurse = fooModeRecurse - 1
end
end
function enter()
libmodal.mode.enter('BAR' .. barModeRecurse, barMode)
libmodal.mode.enter('FOO' .. fooModeRecurse, fooMode)
end
enter()

@ -1,16 +1,16 @@
local libmodal = require('libmodal')
function barMode()
function fooMode()
local userInput = string.char(
vim.api.nvim_get_var('barModeInput')
vim.api.nvim_get_var('fooModeInput')
)
if userInput == '' then
vim.api.nvim_command("echom 'You cant leave using <Esc>.'")
elseif userInput == 'q' then
vim.api.nvim_set_var('barModeExit', true)
vim.api.nvim_set_var('fooModeExit', true)
end
end
vim.api.nvim_set_var('barModeExit', 0)
libmodal.mode.enter('BAR', barMode, true)
vim.api.nvim_set_var('fooModeExit', 0)
libmodal.mode.enter('FOO', fooMode, true)

117
pee

@ -0,0 +1,117 @@
local api = vim.api
local libmodal = require('libmodal')
local barModeInputHistory = {}
local function clearHistory(indexToCheck)
if #barModeInputHistory >= indexToCheck then
barModeInputHistory = {}
end
end
function barMode()
barModeInputHistory[#barModeInputHistory + 1] = string.char(
api.nvim_get_var('barModeInput')
)
local index = 1
if barModeInputHistory[1] == 'z' then
if barModeInputHistory[2] == 'f' then
if barModeInputHistory[3] == 'o' then
api.nvim_command("echom 'It works!'")
else index = 3 end
else index = 2 end
end
clearHistory(index)
end
libmodal.mode.enter('BAR', barMode)
local libmodal = require('libmodal')
local barModeRecurse = 0
local barModeCombos = {
['z'] = 'lua barMode()'
}
function barMode()
barModeRecurse = barModeRecurse + 1
libmodal.mode.enter('BAR' .. barModeRecurse, barModeCombos)
barModeRecurse = barModeRecurse - 1
end
barMode()
local libmodal = require('libmodal')
local barModeCombos = {
[''] = 'echom "You cant exit using escape."',
['q'] = 'let g:barModeExit = 1'
}
vim.api.nvim_set_var('barModeExit', 0)
libmodal.mode.enter('BAR', barModeCombos, true)
local libmodal = require('libmodal')
local barModeCombos = {
['zf'] = 'split',
['zfo'] = 'vsplit',
['zfc'] = 'tabnew'
}
libmodal.mode.enter('BAR', barModeCombos)
local libmodal = require('libmodal')
local api = vim.api
local commandList = {'new', 'close', 'last'}
function barMode()
local userInput = vim.api.nvim_get_var('barModeInput')
if userInput == 'new' then
api.nvim_command('tabnew')
elseif userInput == 'close' then
api.nvim_command('tabclose')
elseif userInput == 'last' then
api.nvim_command('tablast')
end
end
libmodal.prompt.enter('BAR', barMode, commandList)
local libmodal = require('libmodal')
local commands = {
['new'] = 'tabnew',
['close'] = 'tabclose',
['last'] = 'tablast'
}
libmodal.prompt.enter('BAR', commands)
local libmodal = require('libmodal')
local barModeRecurse = 0
function barMode()
local userInput = string.char(vim.api.nvim_get_var(
'bar' .. tostring(barModeRecurse) .. 'ModeInput'
))
if userInput == 'z' then
barModeRecurse = barModeRecurse + 1
enter()
barModeRecurse = barModeRecurse - 1
end
end
function enter()
libmodal.mode.enter('BAR' .. barModeRecurse, barMode)
end
enter()
local libmodal = require('libmodal')
function barMode()
local userInput = string.char(
vim.api.nvim_get_var('barModeInput')
)
if userInput == '' then
vim.api.nvim_command("echom 'You cant leave using <Esc>.'")
elseif userInput == 'q' then
vim.api.nvim_set_var('barModeExit', true)
end
end
vim.api.nvim_set_var('barModeExit', 0)
libmodal.mode.enter('BAR', barMode, true)
Loading…
Cancel
Save