Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/tek/myo
neovim layout & command manager
https://github.com/tek/myo
commands error haskell neovim parser tmux
Last synced: about 2 months ago
JSON representation
neovim layout & command manager
- Host: GitHub
- URL: https://github.com/tek/myo
- Owner: tek
- License: other
- Created: 2019-01-05T22:41:52.000Z (about 6 years ago)
- Default Branch: main
- Last Pushed: 2024-06-28T15:32:41.000Z (7 months ago)
- Last Synced: 2024-09-01T03:59:51.841Z (4 months ago)
- Topics: commands, error, haskell, neovim, parser, tmux
- Language: Haskell
- Size: 1.05 MB
- Stars: 6
- Watchers: 2
- Forks: 1
- Open Issues: 1
-
Metadata Files:
- Readme: readme.md
- License: LICENSE
Awesome Lists containing this project
README
# Intro
**Myo** is a [Neovim] plugin written in [Haskell] with the plugin framework [Ribosome].
It provides several interacting features that include:
* [**UI**](#ui): automatic opening, closing and layouting of tmux panes
* [**Commands**](#commands): Execution of configurable shell commands in [tmux] or subprocesses
* [**Output**](#output): Parsing, rendering and navigation of messages produced by commands**Myo** benefits a lot from having per-project and per-project-type configuration for setting up language-specific commands.
If you don't have a solution for this, the author also maintains [proteome], a project management plugin.![Haskell output screenshot](img/haskell-output.png)
# Install
The plugin can be loaded by specifying the repo to a package manager like any other, for example by cloning it in a
subdirectory of `'packpath'` or using one of the many plugin managers.```vim
Plug 'tek/myo'
```Since the plugin is written in Haskell, its executable has to be fetched or built on the first start.
* If the [Nix package manager](https://nixos.org/learn.html) is available, the plugin will be fetched from the Nix cache
(or built if the current commit isn't in the cache)
* Otherwise it will be downloaded from Github's releases.
* If the variable `g:myo_fetch_bin` is set to `1`, Nix is ignored and the binary is downloaded from Github
regardless.# Configuration
There are a few settings that, when changing their variables, will trigger
reconfiguration of the corresponding component:* `myo_ui`
* `myo_commands`**Myo** uses several autocommands to detect changes.
For the examples in this Readme, I will be using a setup for compiling and testing [Scala] with [sbt].
## MyoDiag
This command will display some information about the plugin in a scratch buffer.
# UI
The purpose of the UI component is to allow creating tracked tmux panes with a fixed layout from mappings that are
cleaned up when vim quits.
The UI is configured through the variable `myo_ui` whenever it is modified.
Its schema looks like this:```vim
let s:sbt_pane =
\ {
\ 'layout': 'make',
\ 'ident': 'sbt',
\ 'minSize': 0.5,
\ 'maxSize': 35,
\ 'position': 8
\ }
let g:myo_ui = {
\ 'panes': [s:sbt_pane]
\ }
```These settings will be combined with the built-in default layout that consists of determining the window and pane in
which Neovim has been started and a vertical layout named `make` positioned to the right of the Neovim pane that
contains one pane, also called `make`, which is used as the default target when executing system commands.It is possible to set up much more complex layouts, with windows and sessions yet to come.
The `myo_ui` variable may contain a key `layouts` with the same schema as for panes.The library used for interacting with tmux is [chiasma].
### Pane Fields
* `layout` is the name of the parent layout of the pane.
* `pin` causes this pane to be opened whenever its layout becomes visible, i.e. when another pane in it is opened.
The default `make` pane has this set.
* `position` is a value that orders panes in a layout. It can have any numerical value.
* `fixed_size` tries to make a pane always have this number of lines or columns.
* `minimized_size`, default `2`, is the number of cells that the pane gets when minimized.
* `weight` is used to distribute surplus space onto panes.Panes open automatically when a command is executed in them, but there are functions for doing so manually.
## Opening and minimizing panes and layouts
```vim
:MyoTogglePane sbt
```will open the pane `sbt` in the lower right corner, or, if it is open already, minimize it to a size of two cells in the
direction of its parent layout (in this case, vertically).```vim
:MyoToggleLayout make
```will open the primary pane of the layout `make` if no panes in the layout are open, or minimize the layout.
```vim
:MyoOpenPane sbt
:MyoOpenLayout make
```will perform the same tasks, but won't minimize an already open view.
```vim
:MyoHidePane sbt
:MyoHideLayout make
```will minimize the view if it is open, otherwise it will do nothing.
## MyoFocus
This command takes a pane name and will set it as the active pane in tmux.
## Inspecting view state
```vim
:echo MyoPaneState('make')
```will print the current target state of a pane (what is configured by **Myo**, not the actual tmux state).
```vim
:echo MyoLayoutState('make')
```will print the same for a layout.
# Commands
A command consists of a list of shell commands and some optional values:
* a tmux pane in which to execute it
* a shell command in which to execute it
* a runner (tmux or subprocess)
* a language for parsing its outputCommands are read from the `myo_commands` variable:
```vim
let s:sbt_cmd = {
\ 'ident': 'sbt',
\ 'lines': ['sbt'],
\ 'target': 'sbt',
\ 'lang': 'scala',
\ }
let s:compile_cmd = {
\ 'ident': 'compile',
\ 'lines': ['test:compile'],
\ 'target': 'sbt',
\ 'lang': 'scala',
\ }
let g:myo_commands = { 'system': [s:sbt_cmd], 'shell': [s:compile_cmd] }
```This snippet defines a _system command_ (run directly in the tmux pane) with the command line `sbt` that will be
executed in the previously created pane `sbt` (defined by the `target` field).Next, it defines a _shell command_ named `compile`, which has as its target the name of a system command, here `sbt`.
This means that when running this command, it will be sent to the tmux pane running `sbt` (it will be started if
necessary) and some interactions with it, like output parsing, will be deferred to the system command.
Its command line is `test:compile`, which is the text sent to `sbt`.### Command Fields
* `ident` is the name of the command, to be used with `MyoRun` and `MyoParse`.
* `lines` is a list of command lines that will be executed in tmux. For subprocess commands, only one line is valid.
* `target` points to a pane or shell in which the command will be run.
* `lang` is used to find the appropriate parser for command output. Currently supported: `scala`, `haskell`.
* `displayName` is an optional override for the text to be displayed to the user instead of the `ident`.
* `skipHistory` is a boolean that excludes the command from the command history.
* `kill` is a boolean that causes a running command to be killed when another one is run in the same target.
* `capture` is a boolean that changes how the command's output is parsed.
If it is `true`, the currently visible output in a tmux pane is used; otherwise, the entire output since the start of
execution.
* `maxLogBytes` is a number that limits the size of the stored output.### Parameter interpolation
Command lines may be template strings with references to parameters:
```vim
let ghc_test_cmd = {
\ 'ident': 'test',
\ 'lines': ['hadrian/build test {test_way:--test-way={test_way}} {test_options} {test_case:--only={test_case}}'],
\ 'params': { 'test_options': '-j6' }
\ 'target': 'make',
\ }
```There are four variants of interpolations:
* `{param_name}` substitutes the value and terminates with error if it is undefined
* `{param_name:}` substitutes the value or the empty string
* `{param_name:expr}` processes `expr` as a template or substitutes the empty string if the parameter is undefined
* `{param_name?expr}` processes `expr` as a template if the parameter is a boolean and true (`v:true` or a nonzero
number) or substitutes the empty string if the parameter is false or undefinedParameter values are determined from several sources, in decreasing order of precedence:
* [CLI-style options](#cli).
* Overrides from edits in a menu.
* Overrides from the command option callback.
* The nvim function `Myo_param_`.
For example, for the param `{test_case}`, the function `Myo_param_test_case` is called.
The return value must be a string or boolean, depending on the parameter type.
Two special return values are recognized:
* `{ 'ignore': 1 }` continues resolution with the next sources (essentially "fallback to default")
* `{ 'error': 'Custom error message' }` will abort execution of the command and print the error message
* The nvim variable `:myo_param_` from the scopes `g:`, `t:`, `w:`, `b:` in that order.
For example, `b:myo_param_test_case`.
* The default values specified in the command config's attribute `params`.
If this is specified, the interpolation styles `{param_name:}` and `{param_name}` behave identically and always
substitute the default as fallback.## MyoRun
This Neovim command/function triggers the execution of a **Myo** command:
```vim
MyoRun compile
```This invocation will:
* create the tmux panes for `sbt` (which will also create `make` since it is pinned).
* run `sbt` in its pane
* send `test:compile` to the `sbt` paneSubsequent invocations will check the stored process ID and skip the second step if it is alive.
### Per-invocation option overrides
The command's options may be overridden by a Neovim callback.
If the callback exists, **Myo** will call it whenever `MyoRun` is executed.
The functions name has the schema `MyoOverrides_`, where the name is escaped by substituting
non-alphanumerical characters by `_`.
The name is either the command's `displayName` or, if that's undefined, its `ident`.
For example, for a command named `some test-command`, the function name will be `MyoOverrides_some_test_command`.The user may return arbitrary command options from that function, in particular a command line and a set of
interpolation parameter values.The purpose of this is to adapt options based on the current cursor context, to "run the test at the cursor position".
A special Neovim command, `MyoTest`, uses an automatically created command to make this more explicit.
Importantly, this doesn't happen when the command is rerun from the history – the first invocation can lock in a certain
position, to be repeated later without changing to the new position of the cursor.The function must take an argument, which will contain the following data:
```json
{
"path": "/path/to/file",
"rel": "relative/path/to/file",
"line": 5,
"col": 10,
"text": "content of the cursor line",
"cword": "result of expand('')"
}
```These denote the position of the cursor.
If the current buffer is not a file, the `path` attribute will contain Neovim's current working directory and `rel` will
be empty.
The indexes are zero-based.The function's return value may either be a dict or a single command line string.
If the `command` attribute is returned, the named command will be executed instead of the originally requested one.
This is primarily useful for `MyoTest`.If `myo-test` isn't defined, a default configuration will be created.
This command can be used to set a template string for all test executions that is dynamically changed by parameter
values returned from `MyoTestOverrides`.The `lines` attribute, or the returned string, overrides the command's default template, which may contain interpolation
placeholders that will be resolved as described above.If the `params` attribute is returned, it will be used to override the parameter values from the sources described
above.If the `shell` attribute is returned, it will set the command by that name as the shell in which the test will run;
otherwise, the `target` attribute may set the tmux pane target.### CLI style overrides {#cli}
The commands `MyoRun` and `MyoTest` allow an additional method for parameter overrides – CLI arguments:
```vim
MyoRun compile --debug=on --name='test name' --fast
```These have the highest precedence.
The `--param=value` variant works for string arguments, while `--flag` enables booleans.## MyoReRun
This function allows you to run commands from the history.
For example, to run the previous command again:```vim
:MyoReRun 0
```## MyoTest
This Neovim command/function runs the command `myo-test`, which will be created with default settings if the user didn't
configure it.
It will call the function `MyoTestOverrides` instead of the command name based function to determine the overrides.
This is mere convenience to ensure that a command for running the cursor test is always available.## MyoHistory
This command displays the history in a scratch buffer with a prompt for substring searching.
Selecting one of the entries with `` will rerun the command.
The prompt starts in normal mode, where you can cycle through the history with `j`/`k`, run a command with ``,
and abort with `` or ``.Pressing `e` will change to a different view, in which each of the command lines and parameters will be listed.
Pressing `e` again on one of them will load its value into the prompt, where it can be modified and written back with
``.
When you are satisfied with the edits, you can press `` to run the command with the modified values.## MyoCommands
This command displays all defined commands in a menu like [`MyoHistory`](#myohistory).
## MyoVimTest
**Myo** features support for [vim-test], which is a plugin with many built-in heuristics for determining the appropriate
command to execute something relating to the current cursor position.
When running this function:```vim
:MyoVimTest
```**Myo** will call [vim-test] and execute its output in the pane or shell configured by `g:myo_test_pane` or
`g:myo_test_shell` (default being `make`).# Output
When a command is executed, its output is read into **Myo**'s state.
Running the command```vim
:MyoParseLatest
```Will run the appropriate parser, read from the command option `pane` or the variable `g:myo_test_lang` (currently only
`haskell or ``scala`), and display its result in a scratch window, as showcased in the screenshot at the top of the
readme.After parsing, the cursor will be set to the last of first error (depending on the values of `g:myo_output_jump_first`
and `g:myo_output_auto_jump`).
Using the functions `MyoPrev` and `MyoNext`, you can cycle through the error list.# Default Commands
For some languages, a default layout and command set will be set up on startup.
To prevent this, set:```vim
let g:myo_default_commands = v:false
```[Neovim]: https://github.com/neovim/neovim
[Haskell]: https://www.haskell.org
[ribosome]: https://github.com/tek/ribosome
[chromatin]: https://github.com/tek/chromatin
[tmux]: https://github.com/tmux/tmux
[proteome]: https://github.com/tek/proteome
[Scala]: https://scala-lang.org
[sbt]: https://scala-sbt.org
[chiasma]: https://github.com/tek/chiasma
[vim-test]: https://github.com/janko/vim-test
[stack]: https://docs.haskellstack.org/en/stable/README