*vifm-lua.txt*    For Vifm version 1.0  Last change: 2023 Mar 19

 Email for bugs and suggestions: <xaizek@posteo.net>

Note: this is very much work in progress.  Everything can change up to
complete removal of this interface (that's an unlikely scenario though).

Current API version: v0.1.0

|vifm-lua-status|      Status of plugins.
|vifm-lua-plugins|     Sample plugins.
|vifm-lua-lua|         Generic reasoning behind this API.
|vifm-lua-design|      Generic ideas about the design.
|vifm-lua-evolution|   Plans on Lua API.
|vifm-lua-loading|     Which plugins get loaded.
|vifm-lua-libs|        What Lua libraries are available.
|vifm-lua-handlers|    Lua handlers concept.
|vifm-lua-events|      Description of event types.
|vifm-lua-caps|        What using Lua in Vifm buys you.
|vifm-lua-api|         Root-level API.
|vifm-l_vifm|          `vifm` global table.
|vifm-l_vifm.cmds|     `vifm.cmds` global table.
|vifm-l_vifm.events|   `vifm.events` global table.
|vifm-l_vifm.keys|     `vifm.keys` global table.
|vifm-l_vifm.opts|     `vifm.opts` global table.
|vifm-l_vifm.plugin|   `vifm.plugin` global table.
|vifm-l_vifm.plugins|  `vifm.plugins` global table.
|vifm-l_vifm.sb|       `vifm.sb` global table.
|vifm-l_vifm.sessions| `vifm.sessions` global table.
|vifm-l_vifm.tabs|     `vifm.tabs` global table.
|vifm-l_vifm.version|  `vifm.version` global table.
|vifm-l_VifmEntry|     `VifmEntry` type.
|vifm-l_VifmJob|       `VifmJob` type.
|vifm-l_VifmTab|       `VifmTab` type.
|vifm-l_VifmView|      `VifmView` type.

--------------------------------------------------------------------------------
*vifm-lua-status*

Pre-pre-alpha.  Just figuring out the basics, trying things out and shaping
the design.  API is nowhere near being complete and there are some weird
ideas which can significantly affect their structure.

There is no manual page that corresponds to this document.  Rather significant
changes are expected, so until things stabilize, only one version will be
maintained.

--------------------------------------------------------------------------------
*vifm-lua-plugins*

Since API is not stable at all, example plugins are stored in code repository
of Vifm and are thus bound to corresponding revision of the application.

--------------------------------------------------------------------------------
*vifm-lua-why*

Think of Lua API as a way to reach deeper into the internals of Vifm.  This
isn't a replacement of existing functionality, but a richer way of interacting
with the core behind it.

One of the primary motivations were deficiencies in integrations with external
applications.  Communicating results of calling them back to Vifm was
problematic, there was simply no good way of doing it reliably.

Regular :commands are a form of user-interface by design, which has various
implications that limit their abilities.  For example, you can't reliably check
if a command succeeded and different commands treat same arguments differently
for the purpose of ease of use, which however makes automation harder.  When
things like that start to get in the way, it's a good idea to reimplement
relevant functionality in Lua.

On top of that users' preferences differ and contradict each other, this can
lead to proliferation of options to account for very fine-grained details.
It's better to let users implement their wild and highly specific ideas on their
own rather than trying to squeeze all possible use case into the application.
The useful functionality developed on the side can eventually make its way to
the code base.

--------------------------------------------------------------------------------
*vifm-lua-design*

The intent is for Lua to be a way of extending the core.  It's not meant
neither as a replacement of :commands nor as a continuation of it.  Instead
it's supposed to be a more low-level way of interacting with the core and
extending it.

One implication is that there is no builtin way of calling Lua from :commands
or vice versa.  This gets too ugly too quickly, hence they are separated except
for certain well-defined extension points where Lua parts integrate with
:commands.

Therefore one should think of :commands as a user-facing interface and Lua
part as an internal extension language with wider range of possibilities.

Callback safety~

Whenever Vifm invokes a Lua function from C code, there is a danger that Lua
will break some invariant.  To account for this, all API calls (including
things like table indexing) are classified as either "safe" or "unsafe".
Safe ones can be called from anywhere, but unsafe API is not always
accessible.  As an example, you can't change directory of any view or add a
view column from a view column handler.

Unsafe API is marked with {unsafe} in its description.  If description of a
handler doesn't say that it's run in a safe environment, it can use unsafe API
as well.  In order to allow use of unsafe API, an execution of a handler might
be postponed until Vifm reaches a state where it holds the least amount of
assumptions about what's going on, such handlers are marked as {delayed}.

--------------------------------------------------------------------------------
*vifm-lua-evolution*

Lua version is fixed at 5.4 and is bundled as part of Vifm to avoid plugin
compatibility issues.

At the moment API can change, but the idea is to figure out key principles of
organization, kinds of entities, naming strategy, ways to extend, etc. and
fix them.  Initial stable version of the API doesn't need to be exhaustive,
just sensible and relatively future proof.  Future releases should extend
functionality rather than change it (unless absolutely necessary).  Doing this
needs usage cases along with success and failure stories, so feedback is
welcome.

Current design principles:
 1. Callbacks in Lua accept a table and return one (if they return anything).
    This allows adding new fields to both input and output while staying
    backward compatible and readable at the cost of being a bit more verbose.

Random ideas~

Use camelCase?
Use tables more often?  Supposed to be more extensible.
Make "description" a required argument?

Add VifmJob:succeeded() ?
Add VifmJob:haserrors() ?

Map options to arrays when possible, like for set options ?
Forbid use of option abbreviations ?
Technically options are also part of user-interface and maybe shouldn't be
exposed in this way.

--------------------------------------------------------------------------------
*vifm-lua-loading*

There are two lists of plugins that affect plugin loading: whitelist and
blacklist.  Here's how they function:
 1. If whitelist isn't empty, only plugins in the list can be loaded.  Trying to
    load any other plugin fails.  Contents of blacklist is ignored.
 2. If whitelist is empty and blacklist isn't, loading anything that's not in
    the blacklist is allowed.

The whitelist is meant to help testing plugins in isolation for debugging
purposes.

The blacklist can be used to temporarily disable broken or just unused plugins
as well as for debugging.

--------------------------------------------------------------------------------
*vifm-lua-libs*

The following standard libraries are enabled:
 * basic (core global functions)
 * table manipulation (`tbl` table)
 * package library (`require` global and `package` table)
 * string manipulation (`string` table)
 * input and output (`io` table)
 * mathematical functions (`math` table)
 * time subset of OS facilities (`clock`, `date`, `difftime` and `time`
   elements) and `tmpname` of `os` table

--------------------------------------------------------------------------------
*vifm-plugins*

Loading of plugins is performed after processing contents of |vifm-vifmrc|.
Plugins are searched in the directories specified via |vifm---plugins-dir|
command-line option and the last specified directory is searched first.  Then
$VIFM/plugins/ is enumerated in search of plugins.  Directories or symbolic
links to directories are considered as candidates.  Those starting with a dot
are ignored.

For example, running Vifm like >

  vifm --plugins-dir dirA --plugins-dir ~/dirB

results in search for plugins in this order of directories:
 1. $PWD/dirA
 2. ~/dirB
 3. $VIFM/plugins
The order matters as it defines which of the conflicting plugins gets
loaded (see below on name conflicts).  Such an ordering allows shadowing
plugins from default location.

Implications of the default order of initialization:
 * :commands defined in configuration have precedence over :commands defined by
   plugins
 * :commands from plugins can't be used during startup

You can load plugins explicitly by calling `:plugin load` command inside
|vifm-vifmrc|.  From then on things defined by plugins can be used in
configuration.

All plugins are required to contain `init.lua` file at their root.  This file
gets processed and its return value is interpreted as plugin data.  The return
value must be a table.  The table is stored in a `vifm.plugins.all` dictionary
with a key that corresponds to the plugin's name.  At the moment the name of a
plugin is the name of its directory.  Name of a plugin must be unique (names
that differ by only by case are considered unique) or loading it will be
skipped.

Global variables created by one plugin are local to that plugin and won't
affect or be visible to other plugins.

--------------------------------------------------------------------------------
*vifm-lua-handlers*

Lua handlers are extension points within existing command-system of Vifm
which enable invoking plugin functionality in a well-defined manner.

A handler is a named Lua function, which is registered via a call to
|vifm-l_vifm.addhandler()|.  The call specifies "partial name" which is
prepended with a namespace ("`#pluginname#`" string) behind the scenes to form
a full name.  This is done to avoid conflicts between plugins.

The scope of handlers is limited to extensions that accept and return all
relevant information on each invocation.  Things like keys or commands can't
be handled this way because they need to communicate metadata about how to
call them.

Handlers are executed in a safe environment and can't call API marked as
{unsafe}.

A handler can be used in place of an external program in |vifm-:filetype| or
|vifm-:filextype| commands like this: >
  filetype {*.png} #pluginname#open

A handler can be used in place of an external viewer in |vifm-:fileviewer|
command like this: >
  fileviewer {*.vim} #pluginname#view --strip-comments %c

A viewer can also be called through |vifm-%q|: >
  :!#pluginname#something %q

A handler can be used to generate |vifm-'statusline'| or |vifm-'tabline'|
value like this: >
  set statusline=#pluginname#statusline
  set tabline=#pluginname#tabline

Below is a specification of input and output for different kinds of handlers.

:filetype or :filextype handler~

Fields of {info} argument for {handler}.handler for :file[x]type:
 - "command" (string)
   Command which handles the file.
 - "entry" (table)
   Information about a file list entry as an instance of |vifm-l_VifmEntry|.

There is no return value.

:fileviewer handler~

Fields of {info} argument:
 - "command" (string)
   Command with which the viewer was invoked.
 - "path" (string)
   Path to the file which is being viewed.
 - "x" (integer)
   X coordinate of the preview area in characters.
 - "y" (integer)
   Y coordinate of the preview area in characters.
 - "width" (integer)
   Width of the preview area in characters.
 - "height" (integer)
   Height of the preview area in characters.

Fields of returned table:
 - "lines" (array of strings)
   Preview text.

'statusline' handler~

Fields of {info} argument:
 - "view" (|vifm-l_VifmView|)
   Current view.
 - "width" (integer)
   Width of the status line.

Fields of returned table:
 - "format" (string)
   Value for |vifm-'statusline'|.

'tabline' handler~

Fields of {info} argument:
 - "other" (boolean)
   Whether this is for the tabline of inactive pane in case of pane tabs.
 - "width" (integer)
   Width of the tab line.

Fields of returned table:
 - "format" (string)
   Value for |vifm-'tabline'|.

'vicmd' or 'vixcmd' handler~

Editor is invoked by Vifm in several different contexts with generally
different input data and sometimes different expectations (like waiting until
editing is finished).  This is why a handler needs to process several kinds of
actions which correspond to those contexts.

Format of returned table is currently the same for all actions:
 - "success" (boolean)
   Whether opening editor was successful.  If we're interested in the result
   of editing (e.g., for bulk renaming), success condition also implies
   receiving non-zero exit code from the editor.

There is also common field of the input table:
 - "command" (string)
   Command specified in one of the options.

"open-help" action

Occurs on |vifm-:help| command if |vifm-'vimhelp'| is set.  Should open
documentation in Vim's format and position cursor at the specified topic (help
tag).

Fields of {info} argument:
 - "action" (string)
   "open-help" string.
 - "topic" (string)
   Help topic (help tag).
 - "vimdocdir" (string)
   Path to parent of doc/ directory with documentation in Vim format with tags
   file.

"edit-one" action

Occurs on:
 - |vifm-:help| command if |vifm-'vimhelp'| is unset
 - pressing |vifm-v_v| key in view mode
 - opening file from a menu
 - opening file with a FUSE mounter using |vifm-i|
 - using |vifm-q:|, |vifm-q/| and |vifm-q?| commands in normal mode
 - requests to provide file names (like on :copy? or |vifm-:rename|)

Should open single file at an optionally specified location (line, column) and
support waiting until editing has finished.

Fields of {info} argument:
 - "action" (string)
   "edit-one" string.
 - "path" (string)
   Path to the file to open.
 - "mustwait" (boolean)
   Whether handler must not return until editor has exited.
 - "line" (integer) (optional)
   Line number at which to open the file.
 - "column" (integer) (optional)
   Column number at which to open the file.  Present only if "line" field is
   present.

"edit-many" action

Occurs on:
 - opening selection or current file on |vifm-Enter| key in normal mode
 - using |vifm-:edit| command

Should open one or multiple files in an editor, likely as a list of buffers or
tabs.

Fields of {info} argument:
 - "action" (string)
   "edit-many" string.
 - "paths" (array of strings)
   Paths to the files to open.

"edit-list" action

Occurs on pressing |vifm-m_v| key in view mode.  Should open list of files or
quickfix entries in an editor as a navigation list.

Fields of {info} argument:
 - "action" (string)
   "edit-list" string.
 - "current" (integer)
   Position of the current entry.
 - "entries" (array of strings)
   List of entries to pass to an editor.
 - "isquickfix" (boolean)
   Whether input entries are of the form "path[:line[:column]][:text]".
   Because such lists come from external tools, this information is determined
   using a simple heuristic and might not always be correct.

--------------------------------------------------------------------------------
*vifm-lua-events*

"app.exit" event~

Occurs before Vifm exits normally.  Does not happen on |vifm-:restart|.

"app.fsop" event~

Occurs after a successful execution of a file-system operation.

Fields of the only table parameter:
 - "op" (string)
   Type of an operation (see below for a list).
 - "path" (string)
   Source path or the only path affected by the operation.
 - "target" (string) (optional)
   Destination path or target of a symbolic link.
 - "isdir" (boolean)
   Whether operation is performed on a directory.
 - "fromtrash" (boolean) (optional)
   "move" operation sets the flag if "path" points inside a trash directory,
   meaning that file was restored or otherwise moved from trash.
 - "totrash" (boolean) (optional)
   "move" operation sets the flag if "target" points inside a trash directory,
   meaning that file was deleted to trash.

Operation types:
 - "copy"
   Copying a file/directory from one location to another.
 - "create"
   Creation of a file/directory.
 - "move"
   Moving a file/directory from one location to another.  Includes renames,
   moves across partition boundaries, deletion to trash and moving out of
   trash.
 - "remove"
   Removal of a file/directory.  This includes symbolic link removal on
   changing its target.
 - "symlink"
   Creation of a symbolic link, which might be a second step of updating its
   target.

The list of operations isn't complete, to be extended as needed.

Operations performed in background aren't reported.

Note: a bulk rename that contains a cycle ("a" -> "b" -> "a" being the
shortest one) will be reported the way it's performed, that is including
temporary renames (e.g., "a -> a_", "b -> a", "a_ -> b").

--------------------------------------------------------------------------------
*vifm-lua-caps*

This is what one can do by using Lua at the moment:
 * :commands in Lua with completion (|vifm-l_vifm.cmds|)
 * save and reset options (e.g., some kind of presets) (|vifm-l_vifm.opts|)
 * custom columns (|vifm-l_vifm.addcolumntype()|)
 * :filetype/:filextype/:fileviewer/%q handlers in Lua (|vifm-lua-handlers|)
 * 'statusline' and 'tabline' generators in Lua (|vifm-lua-handlers|)
 * fully integrate an arbitrary editor by changing |vifm-'vicmd'| or |vifm-'vixcmd'|
   (|vifm-lua-handlers|), while builtin logic assumes compatibility with Vim
 * starting background jobs that appear on a job bar (|vifm-l_vifm.startjob()|)
 * starting background jobs to do something when they're over (see "onexit" of
   |vifm-l_vifm.startjob()|)
 * defining custom keys and selectors (|vifm-l_vifm.keys.add()|)
 * running code before exit and when a file operation is done (|vifm-lua-events|)

--------------------------------------------------------------------------------
*vifm-lua-api*

Builtin `print()` function puts messages to plugin's log (see |vifm-:plugins|
menu).

All API calls can raise errors:
 * on generic internal issues (like out of memory)
 * when argument is missing
 * when argument has wrong type
 * when required table key is missing
 * when table key has wrong type
 * if the API call is unsafe and is disallowed in current environment

Indices passed in or returned by the API start at 1 as arrays do in Lua.

The following callbacks can perform only safe API calls:
 * all Lua handlers (|vifm-lua-handlers|)
 * view column handlers (|vifm-l_vifm.addcolumntype()|)

Interaction with the host happens through `vifm` global table.  See |vifm-l_vifm|.

--------------------------------------------------------------------------------
*vifm-l_vifm*

Global `vifm` table is the entry-point to the API.

vifm.cmds
Table for managing command-line commands.  See |vifm-l_vifm.cmds|.

vifm.opts
Table for managing options.  See |vifm-l_vifm.opts|.

vifm.plugin
Table that provides API service for this plugin.  See |vifm-l_vifm.plugin|.

vifm.plugins
Table for managing plugins.  See |vifm-l_vifm.plugins|.

vifm.sb
Table for managing status bar.  See |vifm-l_vifm.sb|.

vifm.sessions
Table for managing sessions.  See |vifm-l_vifm.sessions|.

vifm.tabs
Table for managing tabs.  See |vifm-l_vifm.tabs|.

vifm.version
Table with version information.  See |vifm-l_vifm.version|.

vifm.addcolumntype({column})                   *vifm-l_vifm.addcolumntype()*
Registers a new view column type to be used in |vifm-'viewcolumns'| option.

Possible fields of {column}:
 - "name" (string)
   Name of the command.  Must consist of Latin characters and not start with
   the lower case one (those are reserved for builtin columns).
 - "handler" (function)
   Handler which accepts {info} and returns a table.  See below.
 - "isprimary" (boolean) (default: false)
   Whether this column is highlighted with file color and search match
   is highlighted as well.

{column}.handler is executed in a safe environment and can't call API marked
as {unsafe}.

Fields of {info} argument for {column}.handler:
 - "entry" (table)
   Information about a file list entry as an instance of |vifm-l_VifmEntry|.
 - "width" (table)
   Calculated width of the column.

Fields of table returned by {column}.handler:
 - "text" (string)
    Table cell's value as a string or convertible to it.
 - "matchstart" (integer) (default: 0)
    For a search match this is the end position of a substring found in
    entry's name, zero otherwise.
 - "matchend" (integer) (default: 0)
    For a search match this is the end position of a substring found in
    entry's name, zero otherwise.

Return:~
  `true` if column was added.

Raises an error:~
  If {column}.name has incorrect value.

vifm.addhandler({handler})                     *vifm-l_vifm.addhandler()*
Registers a new handler that will be accessible in viewers.  See
|vifm-lua-handlers| for general description and details about specific
use-cases.

Possible fields of {handler}:
 - "name" (string)
   Partial name of the handler.  Must not contain any spaces.  Can be
   #-separated list of names, e.g. "view#pdf".
 - "handler" (function)
   Handler which accepts {info} and returns a table.  See below.

Return:~
  `true` if handler was added, `false` if a handler with such name already
  exists.

Raises an error:~
  If {handler}.name has incorrect value.

vifm.currview()                                *vifm-l_vifm.currview()*
Retrieves a reference to active view.

Return:~
  Returns an instance of |vifm-l_VifmView|.

vifm.otherview()                               *vifm-l_vifm.otherview()*
Retrieves a reference to inactive view.

Return:~
  Returns an instance of |vifm-l_VifmView|.

vifm.errordialog({title}, {msg})               *vifm-l_vifm.errordialog()*
Displays error dialog.

Parameters:~
  {title}  Title of the dialog.
  {msg}    Contents of the dialog.

vifm.expand({str})                             *vifm-l_vifm.expand()*
Expands environment variables and macros in a string.

Parameters:~
  {str}  String to expand.

Return:~
  Expanded string.

vifm.fnamemodify({path}, {mods}[, {base}])     *vifm-l_vifm.fnamemodify()*
Changes path according to modifiers.

Parameters:~
  {path}  Path to modify.
  {mods}  Modifiers to apply (`:p`, `:t`, etc.).
  {base}  Base directory for relative paths.
          Default: path of active pane.

Return:~
  Modified path.

vifm.escape({what})                            *vifm-l_vifm.escape()*
Escapes input to make it suitable for use in an external command for current
value of |vifm-'shell'|.

Parameters:~
  {what}  String to escape.

Return:~
  Modified path.

vifm.executable({what})                        *vifm-l_vifm.executable()*
If {what} is absolute or relative path, checks whether it exists and refers to
an executable, otherwise checks whether command named {what} is present in
directories listed in $PATH.  Checks for various executable extensions on
Windows.

Parameters:~
  {what}  Path or command name to check.

Return:~
  `true` if an executable was found.

vifm.exists({path})                            *vifm-l_vifm.exists()*
Checks existence of a path without resolving symbolic links.

Parameters:~
  {path}  Path to check.

Return:~
  `true` if path exists.

vifm.makepath({path})                          *vifm-l_vifm.makepath()*
Creates target path and missing intermediate directories.

Parameters:~
  {path}  Path to create.

Return:~
  `true` on success.  Trying to create path that already exists is not
  considered to be an error.

vifm.run({info})                               *vifm-l_vifm.run()*
Runs an external command similar to |vifm-:!|.  Waits for it to finish if
terminal multiplexer is not involved.

Command is dispatched via a shell, but |vifm-'shellcmdflag'| is always
ignored.

Possible fields of {info}:
 - "cmd" (string)
   Comand to execute.
 - "pause" (string) (default: "onerror")
   When to pause after command execution: "never", "onerror", "always".
 - "usetermmux" (boolean) (default: true)
   Whether to open terminal multiplexer if support was enabled via
   |vifm-:screen|.

Parameters:~
  {info}  Table with information about what and how to run.

Return:~
  Exit code of the command, see |vifm-l_VifmJob:exitcode()| for details.
  Mind that if terminal multiplexer is used, this will be exit code of a
  command that communicates with the multiplexer.

Raises an error:~
  If {info}.pause has incorrect value.

vifm.startjob({job})                           *vifm-l_vifm.startjob()*
Launches an external command as a background job.  Returns without waiting
for it to finish.

Command is dispatched via a shell, but |vifm-'shellcmdflag'| is always
ignored.

Possible fields of {job}:
 - "cmd" (string)
   Comand to execute.
 - "description" (string) (default: "")
   Description of the job to be displayed on the job bar (when "visible" key
   is set to true).
 - "iomode" (string) (default: "r")
   Specififes mode of interaction with the job:
    - "r" - reading output of the process (see |vifm-l_VifmJob:stdout()|)
    - "w" - providing input to the process (see |vifm-l_VifmJob:stdin()|)
    - ""  - no I/O interaction
 - "onexit" (function) (default: `nil`)
   Handler to invoke when the job is done.  The handler is {delayed}.
 - "mergestreams" (boolean) (default: false)
   Whether to merge error stream of the command with its output stream.
 - "visible" (boolean) (default: false)
   Whether to show this job on a job bar.

Parameters:~
  {job}  Table with information about a job.

Return:~
  Returns an instance of |vifm-l_VifmJob|.

Raises an error:~
  If "iomode" has incorrect value.

vifm.input({info})                             *vifm-l_vifm.input()*
Prompts user for input via command-line prompt.

Possible fields of {info}:
 - "prompt" (string)
   Prompt invitation.
 - "initial" (string) (default: "")
   Initial input for the prompt.
 - "complete" (string) (default: "")
   How to complete input: "dir" (directories only), "file" (files and
   directories), "" (no completion).

Parameters:~
  {info}  Table with information about the prompt.

Return:~
  String on success or nil if the prompt was cancelled.

Raises an error:~
  If {info}.complete has incorrect value.

--------------------------------------------------------------------------------
*vifm-l_vifm.cmds*

This global `vifm.cmds` table provides means of managing command-line commands.

vifm.cmds.add({cmd})                           *vifm-l_vifm.cmds.add()*
Registers a new :command of a kind that's equivalent to builtin commands.

The word "parsing" below refers to processing of command-line arguments like
removal of slashes used for escaping and skipping whitespace.

Possible fields of {cmd}:
 - "name" (string)
   Name of the command.
 - "description" (string) (default: "")
   Description of the command.
 - "handler" (function)
   Handler which accepts {info}.
 - "complete" (function)
   Completion function which accepts {info} and returns {results}.
 - "minargs" (integer) (default: 0)
   Minimal number of arguments.
 - "maxargs" (integer) (default: minargs)
   Maximal number of arguments.  Negative number means "indefinite".

Fields of {info} argument for "handler":
 - "args" (string)
   All arguments passed to the command.
 - "argv" (array of strings)
   Set of parsed arguments of the command.

Fields of {info} argument for "complete":
 - "arg" (string)
   Argument being completed.
 - "args" (string)
   Command-line up to cursor position (for cases when completion depends on
   what comes before current argument).
 - "argv" (array of strings)
   Same as "args", but parsed into an array.

Fields of {results} return value of "complete":
 - "offset" (integer) (default: 0)
   Offset from beginning of the argument.  This is useful to avoid prepending
   prefix that's common to all matches, thus completing only essential part.
   For example, in case of "var=val" use offset=4 to complete part after "=".
 - "matches" (array of strings or tables)
   List of items in values of the table (keys are ignored).  Each list item
   can either be a string or a table.  When item is a string it is used as a
   completion match.  When item is a table it can contain these keys:
    - "match" (string)
      Use "match" as a completion match.
    - "description" (string) (optional)
      A string that will be showed along with the "match" but not inserted on
      the command line.
   All other items of unspecified types will be silently ignored.

Parameters:~
  {cmd}  Table with information about a command.

Return:~
  `true` on success.

vifm.cmds.command({cmd})                       *vifm-l_vifm.cmds.command()*
Registers a new :command that works exactly as those registered using
|vifm-:command| builtin command.

Possible fields of {cmd}:
 - "name" (string)
   Name of the command.
 - "description" (string) (default: action)
   Description of the command.
 - "action" (string)
   Value of the command.  See |vifm-:command| for possible value.

Parameters:~
  {cmd}  Table with information about a command.

Return:~
  `true` on success.

vifm.cmds.delcommand({name})                   *vifm-l_vifm.cmds.delcommand()*
Removes :command added by `vifm.cmds.command()`, basically being an equivalent
of |vifm-:delcommand| builtin command.

Parameters:~
  {name}  Name of the command.

Return:~
  `true` on success.

--------------------------------------------------------------------------------
*vifm-l_vifm.events*

This global `vifm.events` table groups items related to events.

events.listen({event})                         *vifm-l_vifm.events.listen()*
Registers a handler for an event.

Possible fields of {event}:
 - "event" (string)
   Name of event to listen for.  See |vifm-lua-events| for event descriptions.
 - "handler" (function)
   Handler to invoke when the event happens.

Registering the same handler more than once for the same event has no effect.

Parameters:~
  {event}  Table with information about event handling.

Return:~
  `nil`

Raises an error:~
  On unknown event name.

--------------------------------------------------------------------------------
*vifm-l_vifm.keys*

This global `vifm.keys` table provides means of managing key bindings.

vifm.keys.add({key})                           *vifm-l_vifm.keys.add()*
Registers in one or several modes:
 * a new user-defined key which might replace an existing one
 * a new selector which must not conflict with an existing one

Possible fields of {key}:
 - "shortcut" (string)
   Left-hand side of the mapping.
 - "description" (string) (default: "")
   Description of the key.
 - "modes" (array of strings)
   List of modes to register the key in.  Supported values: cmdline, nav,
   normal, visual, menus, view and dialogs (sort, attributes, change and file
   info).  Unsupported values are ignored.
 - "isselector" (boolean) (default: false)
   Whether this handler defines a selector rather than a regular key.
 - "followedby" (string) (default: "none")
   "none", "selector" (e.g., "j" in "dj") or "keyarg" (e.g., "q" in "'q").
 - "handler" (function)
   Handler which accepts {info} and returns a table for selector handlers.
   See below.

{key}.handler for selectors is executed in a safe environment and can't call
API marked as {unsafe}.

Fields of {info} argument for {key}.handler:
 - "count" (integer)
   Count preceding the key or nil if none.
 - "register" (string)
   Register name or nil if none was specified.
 - "indexes" (table) (present if key is followed by selector)
   Table of indexes returned by selector key.
 - "keyarg" (string) (present if key is followed by keyarg)
   Key argument (e.g., "x" in "mx" sequence).

Fields of table returned by {key}.handler for selectors:
 - "indexes" (array of integers)
   Table of indexes of entries of the current view (|vifm-l_vifm.currview()|)
   that were selected for the operation.  Invalid, nonexistent and duplicate
   indexes are silently ignored.  Indexes are sorted before processing.

Parameters:~
  {key}  Table with information about a key.

Return:~
  `true` on success.

--------------------------------------------------------------------------------
*vifm-l_vifm.opts*

This global `vifm.opts` table groups items related to options in general.

opts.global (table)                            *vifm-l_vifm.opts.global*
Table that provides access to global options.  The mapping between option
types and Lua types is quite obvious:
 - boolean option   -> boolean type
 - integer option   -> number type
 - any other option -> string type
 - bad option       -> nil type

Assigning global options is {unsafe}.

--------------------------------------------------------------------------------
*vifm-l_vifm.plugin*

Table with information about current plugin and operations for it.

plugin.name (string)                           *vifm-l_vifm.plugin.name*
Name of the plugin.

plugin.path (string)                           *vifm-l_vifm.plugin.path*
Full path to plugin's root directory.

plugin.require({modname})                      *vifm-l_vifm.plugin.require()*
Plugin-specific `require`, which loads Lua modules relative to plugin's root.
Does not create a global variable for the module.

This function is {unsafe}.

Parameters:~
  {modname}  Name of the module, similar to the argument for `require`.

Return:~
  Return value of the module or `nil` on error.

Raises an error:~
  On issues with finding or running the module.

--------------------------------------------------------------------------------
*vifm-l_vifm.plugins*

This global `vifm.plugins` table groups items related to plugins.

plugins.all (table)                            *vifm-l_vifm.plugins.all*
Table that contains all plugins indexed by their names.

--------------------------------------------------------------------------------
*vifm-l_vifm.sb*

This global `vifm.sb` table groups functions for managing status bar.  It
contains the following items:

sb.info({msg})                                 *vifm-l_vifm.sb.info()*
Displays a regular message on status bar.

Parameters:~
  {msg}  Message to display.

sb.error({msg})                                *vifm-l_vifm.sb.error()*
Displays an error message on status bar.

Parameters:~
  {msg}  Message to display.

sb.quick({msg})                                *vifm-l_vifm.sb.quick()*
Displays a quick message on status bar.  It's discarded on first redraw and
isn't stored in the history of messages.

Parameters:~
  {msg}  Message to display.

--------------------------------------------------------------------------------
*vifm-l_vifm.sessions*

This global `vifm.sessions` table provides means for inspecting and
controlling sessions.

sessions.current()                             *vifm-l_vifm.sessions.current*
Retrieves name of the current session.

Return:~
  `nil` if there is no active session or its name as a string otherwise.

--------------------------------------------------------------------------------
*vifm-l_vifm.tabs*

This global `vifm.tabs` table provides means for inspecting and controlling
tabs.

tabs.get([{query}])                            *vifm-l_vifm.tabs.get()*
Retrieves a tab.  Omitting {query} is equivalent to passing an empty one.

Possible fields of {query}:
 - "index" (integer) (default: `tabs.getcurrent()`)
   Index of the tab.
 - "other" (boolean) (default: false)
   Whether to get a pane tab from inactive view.  Ignored if global tabs are
   active.

Return:~
  Returns an instance of |vifm-l_VifmTab| or `nil` if index is out of range.

Raises an error:~
  If tab index is out of range.

tabs.getcount([{query}])                       *vifm-l_vifm.tabs.getcount()*
Retrieves number of open tabs.

Possible fields of {query}:
 - "other" (boolean) (default: false)
   Whether to operate on tab from inactive view.  Ignored if global tabs are
   active.

Return:~
  Returns the count as an integer.

tabs.getcurrent([{query}])                     *vifm-l_vifm.tabs.getcurrent()*
Retrieves index of current tab.

Possible fields of {query}:
 - "other" (boolean) (default: false)
   Whether to operate on tab from inactive view.  Ignored if global tabs are
   active.

Return:~
  Returns the index as an integer.

--------------------------------------------------------------------------------
*vifm-l_vifm.version*

This global `vifm.version` table provides information about Vifm and Lua API.
It contains the following items:

version.app.str (string)                       *vifm-l_vifm.version.app.str*
Version of Vifm as a string.

version.api.major (integer)                    *vifm-l_vifm.version.api.major*
Major version of Lua API.  Should become 1 when API design settles and then
remain at 1.

version.api.minor (integer)                    *vifm-l_vifm.version.api.minor*
Minor version of Lua API.

version.api.patch (integer)                    *vifm-l_vifm.version.api.patch*
Patch version of Lua API.

version.api.has({feature})                     *vifm-l_vifm.version.api.has()*
Checks presence of a feature.  There are no features to test yet.

Parameters:~
  {feature}  Name of the feature

Return:~
  `true` if the feature is present and `false` otherwise.

                                             *vifm-l_vifm.version.api.atleast()*
version.api.atleast({major}, {minor}, {patch})
Checks version of Lua API.

Parameters:~
  {major}  Value to check `version.api.major` against.
  {minor}  Value to check `version.api.minor` against. (default: 0)
  {patch}  Value to check `version.api.patch` against. (default: 0)

Return:~
  `true` if the version is equal or more recent than the specified one.

--------------------------------------------------------------------------------
*vifm-l_VifmEntry*

Instances of this type are used in filetype |vifm-lua-handlers| and in
callbacks of |vifm-l_vifm.addcolumntype()|.  They are also returned by
|vifm-l_VifmView:entry()|.

Fields of this table are just copies, changing their values won't affect state
of the application.

VifmEntry.classify (table)                     *vifm-l_VifmEntry.classify*
Table that describes name decorations.  Its fields:
 - "prefix" (string)
   File name prefix.
 - "suffix" (string)
   File name suffix.

VifmEntry.name (string)                        *vifm-l_VifmEntry.name*
Name of the file.

VifmEntry.location (string)                    *vifm-l_VifmEntry.location*
Location of the file.

VifmEntry.size (integer)                       *vifm-l_VifmEntry.size*
Size of the file in bytes.

VifmEntry.atime (integer)                      *vifm-l_VifmEntry.atime*
File access time (e.g., read, executed).  In seconds since the Unix epoch.

VifmEntry.ctime (integer)                      *vifm-l_VifmEntry.ctime*
File change time (changes in metadata, like mode).  In seconds since the
Unix epoch.

VifmEntry.mtime (integer)                      *vifm-l_VifmEntry.mtime*
File modification time (when file contents is changed).  In seconds since
the Unix epoch.

VifmEntry.type (string)                        *vifm-l_VifmEntry.type*
Type of the entry.  See |vifm-filetype()| for the list of values.

VifmEntry.isdir (boolean)                      *vifm-l_VifmEntry.isdir*
True if an entry is either a directory or a symbolic link to a directory.

VifmEntry.folded (boolean)                     *vifm-l_VifmEntry.folded*
Whether this entry is folded.

VifmEntry.selected (boolean)                   *vifm-l_VifmEntry.selected*
Whether this entry is selected.

VifmEntry.match (boolean)                      *vifm-l_VifmEntry.match*
Whether this entry is a search match.

VifmEntry.matchstart (integer)                 *vifm-l_VifmEntry.matchstart*
For a search match this is the start position of a substring found in name,
zero otherwise.

VifmEntry.matchend (integer)                   *vifm-l_VifmEntry.matchend*
For a search match this is the end position of a substring found in name,
zero otherwise.

VifmEntry:gettarget()                          *vifm-l_VifmEntry.gettarget()*
Gets target of a symbolic link (not to be confused with real path resolution).

Return:~
  Returns target as a string.

Raises an error:~
  If entry doesn't correspond to a symbolic link.
  If resolving symbolic link has failed.

VifmEntry:mimetype()                          *vifm-l_VifmEntry.mimetype()*
Gets a MIME type.  Resolves target of symbolic links.

Return:~
  Returns MIME type as a string, or `nil` if no MIME type recognisers are
  available.

--------------------------------------------------------------------------------
*vifm-l_VifmJob*

Instances of this type are returned by |vifm-l_vifm.startjob()|.

VifmJob:wait()                                 *vifm-l_VifmJob:wait()*
Waits for the job to finish.

Raises an error:~
  If waiting has failed.

VifmJob:exitcode()                             *vifm-l_VifmJob:exitcode()*
Retrieves exit code of the command.

Waits for the job to finish.

Return:~
  Returns an integer number that represents exit code.  The value is `-x` if
  the application was killed by signal `x`.  `-127` or `-128` means that
  tracking the application has failed in some way.

Raises an error:~
  If waiting has failed.

VifmJob:stdin()                                *vifm-l_VifmJob:stdin()*
Retrieves stream associated with standard input of the job.

Return:~
  Returns file stream from standard I/O library of Lua.

Raises an error:~
  If the job wasn't started with "w" I/O mode (see |vifm-l_vifm.startjob()|).
  If input stream object is already closed.

VifmJob:stdout()                               *vifm-l_VifmJob:stdout()*
Retrieves stream associated with standard output of the job.  Includes error
stream if `mergestreams` was set to `true`.

Return:~
  Returns file stream from standard I/O library of Lua.

Raises an error:~
  If the job wasn't started with "r" I/O mode (see |vifm-l_vifm.startjob()|).
  If output stream object is already closed.

VifmJob:errors()                               *vifm-l_VifmJob:errors()*
Retrieves data collected from error stream of the job.  It's accumulated
automatically in background and contains all data collected so far, the call
doesn't wait for arrival of data.  Empty if `mergestreams` was set to `true`.

Return:~
  Returns a string.

--------------------------------------------------------------------------------
*vifm-l_VifmTab*

Instances of this type are returned by |vifm-l_vifm.tabs.get()|.

The corresponding tab exists independently of this type and once the tab is
closed accessing bound instance raises an error.

VifmTab:getlayout()                            *vifm-l_VifmTab:getlayout()*
Retrieves layout of a global tab or shared TUI state for a pane tab.

Fields of the result:
 - "only" (boolean)
   Whether there is only one visible window.
 - "split" (string)
   `nil` when in only one window is visible, "v" or "h" otherwise.

Return:~
  Returns description of current layout as a table.

VifmTab:getname()                              *vifm-l_VifmTab:getname()*
Retrieves name of the tab if it was set.

Return:~
  Returns name of the tab as a string, which is empty if unset.

VifmTab:getview([{query}])                     *vifm-l_VifmTab:getview()*

Possible fields of {query}:
 - "pane" (integer) (default: index of active pane)
   Which view to get from a global tab.  1 is left/top pane, 2 is right/bottom
   one.  Ignored for a pane tab.

Return:~
  Returns an instance of |vifm-l_VifmView|.

--------------------------------------------------------------------------------
*vifm-l_VifmView*

Instances of this type are returned by:
 * |vifm-l_vifm.currview()|
 * |vifm-l_vifm.otherview()|
 * |vifm-l_VifmTab:getview()|

The corresponding view exists independently of this type and once the view is
gone (e.g., its tab is closed) accessing bound instance raises an error.

VifmView.locopts (table)                       *vifm-l_VifmView.viewopts*
Equivalent of |vifm-l_vifm.opts.global| for location-specific values of
view-specific options.  These are "local" values of view-specific options,
which are reset to "global" ones on file list change.

Assigning local options is {unsafe}.

VifmView.viewopts (table)                      *vifm-l_VifmView.locopts*
Equivalent of |vifm-l_vifm.opts.global| for view-specific options, see there
for details.  These are "global" values of view-specific options.

Assigning view options is {unsafe}.

VifmView.currententry (integer)                *vifm-l_VifmView.currententry*
Index of the current entry.

VifmView.cwd (string)                          *vifm-l_VifmView.cwd*
Location of the current view.

VifmView.entrycount (integer)                  *vifm-l_VifmView.entrycount*
Number of entries in the view.

VifmView.custom (table)                        *vifm-l_VifmView.custom*
Table with information about custom file list.  The value is `nil` if custom
view isn't active.

Fields:
 - "title" (string)
   Title of a custom view which usually describes how it was created.
 - "type" (string)
   Values returned by |vifm-getpanetype()| except for "regular".

VifmView:cd({path})                            *vifm-l_VifmView:cd()*
Changes location of the view.  {path} isn't expanded in any way.

This function is {unsafe}.

Parameters:~
  {path}  Path to visit.

Return:~
  `true` on success.

VifmView:entry({index})                        *vifm-l_VifmView:entry()*
Retrieves an entry by index.

Parameters:~
  {index}  Value in the range from `1` to `VifmEntry.entrycount` inclusive.

Return:~
  |vifm-l_VifmEntry| on success and `nil` on wrong index.

VifmView:select({entries})                     *vifm-l_VifmView:select()*
Selects entries.  Does nothing in visual non-amend mode.  See
|vifm-l_VifmView:unselect()| to unselect entries.

This function is {unsafe}.

Possible fields of {entries}:
 - "indexes" (array of integers)
   Indexes of entries to select.  Invalid and nonexistent indexes are
   silently ignored.

Return:~
  Number of new selected entries.

VifmView:unselect({entries})                   *vifm-l_VifmView:unselect()*
Unselects entries.  Does nothing in visual non-amend mode.  See
|vifm-l_VifmView:select()| to select entries.

This function is {unsafe}.

Possible fields of {entries}:
 - "indexes" (array of integers)
   Indexes of entries to unselect.  Invalid and nonexistent indexes are
   silently ignored.

Return:~
  Number of new unselected entries.

--------------------------------------------------------------------------------
 vim:tw=78:fo=tcq2:isk=!-~,^*,^\|,^\":ts=8:ft=help:norl:
