What is Clink?

Clink combines the native Windows shell cmd.exe with the powerful command line editing features of the GNU Readline library, which provides rich completion, history, and line-editing capabilities. Readline is best known for its use in the Unix shell Bash, the standard shell for Mac OS X and many Linux distributions.

Features

Here are some highlights of what Clink provides:

By default Clink binds Alt-H to display the current key bindings.

Usage

There are several ways to start Clink.

  1. If you installed the auto-run, just start cmd.exe. Run clink autorun --help for more info.
  2. To manually start, run the Clink shortcut from the Start menu (or the clink.bat located in the install directory).
  3. To establish Clink to an existing cmd.exe process, use <install_dir>\clink inject.

Starting Clink injects it into a cmd.exe process, where it intercepts a handful of Windows API functions so that it can replace the prompt and input line editing with its own Readline-powered enhancements.

Getting Started

You can use Clink right away without configuring anything:

There are three main ways of customizing Clink to your preferences: the Readline init file (the .inputrc file), the Clink settings (the clink set command), and Lua scripts.

How Completion Works

Clink can offer possible completions for the word at the cursor, and can insert them for you. Clink can complete file names, directories, environment variables, and commands. It also allows you to provide custom completion generators using Lua scripts that execute inside Clink (see Extending Clink With Lua).

By default, pressing Tab performs completion the same way that bash does on Unix and Linux. When you press Tab, Clink finds matches for how to complete the word at the cursor. It automatically inserts the longest common prefix shared by the possible completions. If you press Tab again, it also lists the possible completions.

If you install Clink with "Use enhanced defaults" or if you set clink.default_bindings to use "windows" defaults, then pressing Tab cycles through the possible completions, replacing the word with the next possible completion each time.

Pressing Ctrl-Space shows an interactive list of possible completions. You can use the arrow keys to choose which completion to insert, and you can type to filter the list. Enter inserts the selected completion, or Space inserts the selected completion and makes sure a space follows it to allow typing a next argument.

The first word of each command line is the command or program to execute, or a file to open. By default, Clink provides completions for the first word based on all executable programs on the system PATH and the current directory, but not non-executable files. You can turn off executable completion by running clink set exec.enable false, or you can adjust its behavior by changing the various exec.* settings (see Clink Settings for more information about them).

See Completion Commands and Clink Commands for more available completion commands.

Common Configuration

The following sections describe some ways to begin customizing Clink to your taste.

Enhanced default settingsOptionally use enhanced default settings.
Create a .inputrc fileCreate a .inputrc file where config variables and key bindings can be set.
Bash vs WindowsMake Ctrl-F and Ctrl-M work like usual on Windows.
Auto-suggestHow to enable and use automatic suggestions.
ColorsConfigure the colors.
Key BindingsCustomize your key bindings.
Mouse InputOptionally enable mouse clicks in the input line, etc.
Startup Cmd ScriptOptional automatic clink_start.cmd script.
Custom PromptCustomizing the command line prompt.
Upgrading from Clink v0.4.9Notes on upgrading from a very old version of Clink.

Enhanced default settings

Clink can be installed with plain defaults, or it can be installed with enhanced default settings that enable more of Clink's enhancements by default.

If you install Clink with the setup program and "Use enhanced default settings" is checked, then the enhanced defaults are activated, and then in some places where this documentation refers to default settings the stated default may have been overridden.

If you install Clink from the .zip file then enhanced default settings are activated when the default_settings and default_inputrc files are present in the binaries directory or in the profile directory. The .zip file comes with the files, but their names have a _ prefix so that enhanced defaults won't automatically take effect. You can activate the enhanced default settings by renaming the files to remove the _ prefix.

Here are some of the enhanced defaults. Review the default_settings and default_inputrc files for the full list.

Create a .inputrc file

First you'll want to create a .inputrc file, and a good place is in your Windows user profile directory.

This file is used for some configuration, such as key bindings and colored completions.

Create the file by running this command at a CMD prompt:

notepad %userprofile%\.inputrc

You may want to copy/paste the following sample text into the file as a starting point, and then press Ctrl-S to save the file.

# Some common Readline config settings.

set colored-stats                 on   # Turn on completion colors.
set colored-completion-prefix     on   # Color the typed completion prefix.

# Some config settings that only work in Clink.

$if clink
set search-ignore-case            on   # Case insensitive history searches.
set completion-auto-query-items   on   # Prompt before showing completions if they'll exceed half the screen.
$endif

# Add your keybindings here...

See Init File for more information on Readline init files.

Bash vs Windows

The default Clink key bindings are the same as in the "bash" shell for Unix/Linux. That makes some keys like Ctrl-A, Ctrl-F, and Ctrl-M behave differently than you might be used to in CMD.

To instead use the familiar Windows default key bindings you can run clink set clink.default_bindings windows.

Or, if you use the setup program with "Use enhanced default settings" checked then "windows" key bindings are the default, and you can run clink set clink.default_bindings bash to use the bash default key bindings.

Clink comes with many default key bindings. Use Alt-H to see all of the active key bindings, or use Alt-Shift-? to check what is bound to a specific key. See Key Bindings to get started configuring your own key bindings.

Here are the differences between the Windows defaults and the bash defaults:

Key Windows Bash
Ctrl-A Select All. Go to beginning of line.
Ctrl-B (not bound) Move backward one character.
Ctrl-E Expands doskey aliases, environment variables, and history expansions in the current line. Go to end of line.
Ctrl-F Find text (in plain Conhost console windows). Move forward one character.
Ctrl-M Mark text (in plain Conhost console windows). Same as Enter.
Tab Cycle forward through available completions. Bash style completion.
Shift-Tab Cycle backward through available completions. (not bound)
Right Move forward one character, or at the end of the line insert the next character from the previous input line. Move forward one character.

Auto-suggest

Clink can suggest commands as you type, based on command history and completions.

To turn on automatic suggestions, run clink set autosuggest.enable true. When the cursor is at the end of the input line, a suggestion may appear in a muted color. If the suggestion isn't what you want, just ignore it. Or accept the whole suggestion with the Right arrow or End key, accept the next word of the suggestion with Ctrl-Right, or accept the next full word of the suggestion up to a space with Shift-Right.

The autosuggest.strategy setting determines how a suggestion is chosen.

Or, if you use the setup program with "Use enhanced default settings" checked then automatic suggestions are enabled by default.

Colors

Clink has many configurable colors for match completions, input line coloring, popup lists, and more.

If you use the setup program with "Use enhanced default settings" checked then many of the color settings have more colorful default values.

For completion

When performing completion (e.g. Tab or Ctrl-Space) Clink can add color to the possible completions.

To turn on colored completions, put a line set colored-stats on in the .inputrc file (if you copy/pasted the sample text, it's already there).

See the Completion Colors section for how to configure the colors for match completions.

Other colors

Clink adds color to the input line by highlighting arguments, flags, doskey macros, and more. If you don't want input line colors, you can turn it off by running clink set clink.colorize_input false.

There are also colors for popup lists, and some other things.

To configure a color, run clink set colorname colorvalue.

Match completions make it easy to change Clink settings: type clink set color. and then use completion (e.g. Tab or Ctrl-Space) to see the available color settings, and to fill in a color value.

Here are some colors you may want to set up right away:

Color Description Recommended
color.executable Apply color when the command is an executable file. clink set color.executable sgr 38;5;32
color.unrecognized Apply color when the command is not recognized. clink set color.unrecognized sgr 38;5;203

See the Clink Settings, Color Settings, and Coloring the Input Text sections for more information on Clink color settings.

Key Bindings

You can customize your key bindings (keyboard shortcuts) by assigning key bindings in the .inputrc file. See Customizing Key Bindings for more information.

Clink comes with many pre-configured key bindings that invoke named commands. Here are a few that you might find especially handy:

Alt-HThis is clink-show-help, which lists the key bindings and commands.
TabThis is complete or old-menu-complete, depending on the clink.default_bindings Clink setting. complete swhich performs completion by selecting from an interactive list of possible completions; if there is only one match, the match is inserted immediately.
Ctrl-SpaceThis is clink-select-complete, which performs completion by selecting from an interactive list of possible completions; if there is only one match, the match is inserted immediately.
Alt-=This is possible-completions, which lists the available completions for the current word in the input line.
Alt-.This is yank-last-arg, which inserts the last argument from the previous line. You can use it repeatedly to cycle backwards through the history, inserting the last argument from each line. Learn more by reading about Killing and Yanking.
Ctrl-RThis is reverse-search-history, which incrementally searches the history. Press it, then type, and it does a reverse incremental search while you type. Press Ctrl-R again (and again, etc) to search for other matches of the search text. Learn more by reading about Searching for Commands in the History.
Ctrl-Alt-DThis is remove-history, which deletes the currently selected history line after using any of the history search or navigation commands.
Ctrl-Alt-KThis is add-history, which adds the current line to the history without executing it, and then clears the input line.
Ctrl-Alt-NThis is clink-menu-complete-numbers, which grabs numbers with 3 or more digits from the current console screen and cycles through inserting them as completions (binary, octal, decimal, hexadecimal). Super handy for quickly inserting a commit hash that was printed as output from a preceding command.
Alt-0 to Alt-9These are digit-argument, which let you enter a numeric value used by many commands. For example Ctrl-Alt-W copies the current word to the clipboard, but if you first type Alt-2 followed by Ctrl-Alt-W then it copies the 3rd word to the clipboard (the first word is 0, the second is 1, etc). Learn more by reading about Readline Arguments.

For a full list of commands available for key bindings, see Bindable Commands.

Mouse Input

Clink can optionally respond to mouse input, instead of letting the terminal respond to mouse input (e.g. to select text on the screen). When mouse input is enabled in Clink, you can click in the input line or in popup lists, and the mouse wheel scrolls popup lists.

Use clink set terminal.mouse_input mode with one of the following modes to control whether Clink responds to mouse input:

Mode Description
off Lets the terminal host handle mouse input.
on Lets Clink handle mouse input.
auto Lets Clink handle mouse input in ConEmu and in the default Conhost terminal when Quick Edit mode is unchecked in the console Properties dialog.

Use clink set terminal.mouse_modifier modifiers or set CLINK_MOUSE_MODIFIER=modifiers to control which modifier keys must be held for Clink to respond to mouse input.

These select which modifier keys (Alt, Ctrl, Shift) must be held in order for Clink to respond to mouse input when mouse input is enabled by the terminal.mouse_input setting. modifiers is a text string that can list one or more modifier keys: "alt", "ctrl", and "shift". For example, setting it to "alt shift" causes Clink to only respond to mouse input when both Alt and Shift are held (and not Ctrl). If the %CLINK_MOUSE_MODIFIER% environment variable is set then its value supersedes the terminal.mouse_modifier setting. In Windows Terminal many modifier keys do special things with mouse clicks, so the modifier key combination that interferes least with built in Windows Terminal behaviors is Ctrl-Alt.

When mouse input is enabled in Clink, then mouse input works a little differently:

Startup Cmd Script

When Clink is injected, it looks for a clink_start.cmd script in the binaries directory and profile directory. Clink automatically runs the script(s), if present, when the first CMD prompt is shown after Clink is injected. You can set the clink.autostart setting to run a different command, or set it to "nul" to run no command at all.

Custom Prompt

If you want a customizable prompt with a bunch of styles and an easy-to-use configuration wizard, check out clink-flex-prompt. Also, if you've been disappointed by git making the prompt slow in other shells, try this prompt -- it makes the prompt appear instantly by running git commands in the background and refreshing the prompt once the background commands complete.

Other popular configurable prompts are oh-my-posh and starship.

See Customizing the Prompt for information on how to use Lua to customize the prompt.

The new Clink tries to be as backward compatible with Clink v0.4.9 as possible. However, in some cases upgrading may require a little bit of configuration work.

Migrating between different profile directories

All versions of Clink use the same default profile directory location. If you haven't overridden the profile directory, then your settings and history will automatically migrate when upgrading to newer versions of Clink.

If you choose to use a different profile directory, then you can still make migration happen by copying certain files:

  1. When using Clink v0.4.9 you can use clink set to find the settings file path.
  2. When using newer versions of Clink you can use clink info to find the profile directory.
  3. Copy the settings and .history files from the old directory into the new directory.
  4. If you already have a clink_settings or clink_history file in your new profile directory, then you'll need to rename them in order for migration to happen (e.g. add .txt to the names).
  5. Close the Clink session(s) and open new ones.

Configuring Clink

Clink has two configuration systems, which is a result of using the Readline library to provide command history and key bindings.

The following sections describe how to configure Clink itself. To learn about the Readline configuration and key bindings, instead see Configuring Readline.

Clink SettingsHow to customize Clink's settings.
Color SettingsDescribes the syntax used by color settings.
File LocationsWhere Clink stores its history and settings files.
Command Line OptionsDescribes the command line options for the Clink program.
Portable ConfigurationHow to set up a "portable" installation of Clink, e.g. on a USB drive or network location.

The easiest way to configure Clink is to use the clink set command. This can list, query, and set Clink's settings. Run clink set --help from a Clink-installed cmd.exe process to learn more both about how to use it and to get descriptions for Clink's various options.

The following table describes the available Clink settings:

Name Default * Description
autosuggest.async True When this is true matches are generated asynchronously for suggestions. This helps to keep typing responsive.
autosuggest.enable False * When this is true a suggested command may appear in color.suggestion color after the cursor. If the suggestion isn't what you want, just ignore it. Or accept the whole suggestion with the Right arrow or End key, accept the next word of the suggestion with Ctrl-Right, or accept the next full word of the suggestion up to a space with Shift-Right. The autosuggest.strategy setting determines how a suggestion is chosen.
autosuggest.original_case True When this is enabled (the default), accepting a suggestion uses the original capitalization from the suggestion.
autosuggest.strategy match_prev_cmd history completion This determines how suggestions are chosen. The suggestion generators are tried in the order listed, until one provides a suggestion. There are three built-in suggestion generators, and scripts can provide new ones. history chooses the most recent matching command from the history. completion chooses the first of the matching completions. match_prev_cmd chooses the most recent matching command whose preceding history entry matches the most recently invoked command, but only when the history.dupe_mode setting is add.
clink.autostart This command is automatically run when the first CMD prompt is shown after Clink is injected. If this is blank (the default), then Clink instead looks for clink_start.cmd in the binaries directory and profile directory and runs them. Set it to "nul" to not run any autostart command.
clink.autoupdate True When enabled, Clink periodically checks for updates for the Clink program files (see Automatic Updates).
clink.colorize_input True Enables context sensitive coloring for the input text (see Coloring the Input Text).
clink.default_bindings bash * Clink uses bash key bindings when this is set to bash (the default). When this is set to windows Clink overrides some of the bash defaults with familiar Windows key bindings for Tab, Ctrl-A, Ctrl-F, Ctrl-M, and Right.
clink.logo full Controls what startup logo to show when Clink is injected. full = show full copyright logo, short = show abbreviated version info, none = omit the logo.
clink.max_input_rows 0 Limits how many rows the input line can use, up to the terminal height. When this is 0 (the default), the terminal height is the limit.
clink.paste_crlf crlf What to do with CR and LF characters on paste. Setting this to delete deletes them, space replaces them with spaces, ampersand replaces them with ampersands, and crlf pastes them as-is (executing commands that end with a newline).
clink.path A list of paths from which to load Lua scripts. Multiple paths can be delimited semicolons.
clink.promptfilter True Enable prompt filtering by Lua scripts.
clink.update_interval 5 The Clink autoupdater will wait this many days between update checks (see Automatic Updates).
cmd.admin_title_prefix When set, this replaces the "Administrator: " console title prefix.
cmd.altf4_exits True When set, pressing Alt-F4 exits the cmd.exe process.
cmd.auto_answer off Automatically answers cmd.exe's "Terminate batch job (Y/N)?" prompts. off = disabled, answer_yes = answer Y, answer_no = answer N.
cmd.ctrld_exits True Ctrl-D exits the cmd.exe process when it is pressed on an empty line.
cmd.get_errorlevel True When this is enabled, Clink runs a hidden echo %errorlevel% command before each interactive input prompt to retrieve the last exit code for use by Lua scripts. If you experience problems, try turning this off. This is on by default.
color.arg The color for arguments in the input line when clink.colorize_input is enabled.
color.arginfo yellow * Argument info color. Some argmatchers may show that some flags or arguments accept additional arguments, when listing possible completions. This color is used for those additional arguments. (E.g. the "dir" in a "-x dir" listed completion.)
color.argmatcher * The color for the command name in the input line when clink.colorize_input is enabled, if the command name has an argmatcher available.
color.cmd bold * Used when displaying shell (CMD.EXE) command completions, and in the input line when clink.colorize_input is enabled.
color.cmdredir bold * The color for redirection symbols (<, >, >&) in the input line when clink.colorize_input is enabled.
color.cmdsep bold * The color for command separators (&, |) in the input line when clink.colorize_input is enabled.
color.comment_row bright white on cyan * The color for the comment row. During clink-select-complete the comment row shows the "and N more matches" or "rows X to Y of Z" messages. It can also show how history expansion will be applied at the cursor.
color.description bright cyan * Used when displaying descriptions for match completions.
color.doskey bright cyan * Used when displaying doskey alias completions, and in the input line when clink.colorize_input is enabled.
color.executable * When set, this is the color in the input line for a command word that is recognized as an executable file when clink.colorize_input is enabled.
color.filtered bold * The default color for filtered completions (see Filtering the Match Display).
color.flag default * The color for flags in the input line when clink.colorize_input is enabled.
color.hidden * Used when displaying file completions with the "hidden" attribute.
color.histexpand * The color for history expansions in the input line when clink.colorize_input is enabled. If this color is not set or history.auto_expand is disabled or history.expand_mode is off, then history expansions are not colored.
color.horizscroll * The color for the < or > horizontal scroll indicators when Readline's horizontal-scroll-mode variable is set.
color.input * The color for input line text. Note that when clink.colorize_input is disabled, the entire input line is displayed using color.input.
color.interact bold The color for prompts such as a pager's --More?-- prompt.
color.message default The color for the message area (e.g. the search prompt message, digit argument prompt message, etc).
color.popup When set, this is used as the color for popup lists and messages. If no color is set, then the console's popup colors are used (see the Properties dialog box for the console window).
color.popup_desc When set, this is used as the color for description column(s) in popup lists. If no color is set, then a color is chosen to complement the console's popup colors (see the Properties dialog box for the console window).
color.prompt When set, this is used as the default color for the prompt. But it's overridden by any colors set by Customizing The Prompt.
color.readonly * Used when displaying file completions with the "readonly" attribute.
color.selected_completion * The color for the selected completion with the clink-select-complete command. If no color is set, then bright reverse video is used.
color.selection * The color for selected text in the input line (for example, when using Shift-Arrow keys). If no color is set, then reverse video is used.
color.suggestion bright black * The color for automatic suggestions when autosuggest.enable is enabled.
color.unexpected default The color for unexpected arguments in the input line when clink.colorize_input is enabled.
color.unrecognized * When set, this is the color in the input line for a command word that is not recognized as a command, doskey macro, directory, argmatcher, or executable file.
debug.log_terminal False Logs all terminal input and output to the clink.log file. This is intended for diagnostic purposes only, and can make the log file grow significantly.
doskey.enhanced True Enhanced Doskey adds the expansion of macros that follow | and & command separators and respects quotes around words when parsing $1...$9 tags. Note that these features do not apply to Doskey use in Batch files.
exec.aliases True When matching executables as the first word (exec.enable), include doskey aliases.
exec.commands True When matching executables as the first word (exec.enable), include CMD commands (such as cd, copy, exit, for, if, etc).
exec.cwd True When matching executables as the first word (exec.enable), include executables in the current directory. (This is implicit if the word being completed is a relative path, or if exec.files is true.)
exec.dirs True When matching executables as the first word (exec.enable), also include directories relative to the current working directory as matches.
exec.enable True Match executables when completing the first word of a line. Executables are determined by the extensions listed in the %PATHEXT% environment variable.
exec.files False When matching executables as the first word (exec.enable), include files in the current directory.
exec.path True When matching executables as the first word (exec.enable), include executables found in the directories specified in the %PATH% environment variable.
exec.space_prefix True If the line begins with whitespace then Clink bypasses executable matching (exec.path) and will do normal files matching instead.
files.hidden True Includes or excludes files with the "hidden" attribute set when generating file lists.
files.system False Includes or excludes files with the "system" attribute set when generating file lists.
history.auto_expand True When enabled, history expansion is automatically performed when a command line is accepted (by pressing Enter). When disabled, history expansion is performed only when a corresponding expansion command is used (such as clink-expand-history Alt-^, or clink-expand-line Alt-Ctrl-E).
history.dont_add_to_history_cmds exit history List of commands that aren't automatically added to the history. Commands are separated by spaces, commas, or semicolons. Default is exit history, to exclude both of those commands.
history.dupe_mode erase_prev If a line is a duplicate of an existing history entry Clink will erase the duplicate when this is set to erase_prev. Setting it to ignore will not add duplicates to the history, and setting it to add will always add lines (except when overridden by history.sticky_search).
history.expand_mode not_quoted The ! character in an entered line can be interpreted to introduce words from the history. This can be enabled and disable by setting this value to on or off. Values of not_squoted, not_dquoted, or not_quoted will skip any ! character quoted in single, double, or both quotes respectively.
history.ignore_space True Ignore lines that begin with whitespace when adding lines in to the history.
history.max_lines 10000 * The number of history lines to save if history.save is enabled (1 to 50000).
history.save True Saves history between sessions. When disabled, history is neither read from nor written to a master history list; history for each session exists only in memory until the session ends.
history.shared False When history is shared, all instances of Clink update the master history list after each command and reload the master history list on each prompt. When history is not shared, each instance updates the master history list on exit.
history.sticky_search False When enabled, reusing a history line does not add the reused line to the end of the history, and it leaves the history search position on the reused line so next/prev history can continue from there (e.g. replaying commands via Up several times then Enter, Down, Enter, etc).
history.time_format %F %T   This specifies a time format string for showing timestamps for history items. For a list of format specifiers see clink set history.time_format or History Timestamps.
history.time_stamp off The default is off. When this is save, timestamps are saved for each history item but are only shown when the --show-time flag is used with the history command. When this is show, timestamps are saved for each history item, and timestamps are shown in the history command unless the --bare flag is used.
lua.break_on_error False Breaks into Lua debugger on Lua errors.
lua.break_on_traceback False Breaks into Lua debugger on traceback().
lua.debug False Loads a simple embedded command line debugger when enabled. Breakpoints can be added by calling pause().
lua.path Value to append to package.path. Used to search for Lua scripts specified in require() statements.
lua.reload_scripts False When false, Lua scripts are loaded once and are only reloaded if forced (see The Location of Lua Scripts for details). When true, Lua scripts are loaded each time the edit prompt is activated.
lua.strict True When enabled, argument errors cause Lua scripts to fail. This may expose bugs in some older scripts, causing them to fail where they used to succeed. In that case you can try turning this off, but please alert the script owner about the issue so they can fix the script.
lua.traceback_on_error False Prints stack trace on Lua errors.
match.expand_envvars False * Expands environment variables in a word before performing completion.
match.fit_columns True When displaying match completions, this calculates column widths to fit as many as possible on the screen.
match.ignore_accent True Controls accent sensitivity when completing matches. For example, ä and a are considered equivalent with this enabled.
match.ignore_case relaxed Controls case sensitivity when completing matches. off = case sensitive, on = case insensitive, relaxed = case insensitive plus - and _ are considered equal.
match.limit_fitted_columns 0 When the match.fit_columns setting is enabled, this disables calculating column widths when the number of matches exceeds this value. The default is 0 (unlimited). Depending on the screen width and CPU speed, setting a limit may avoid delays.
match.max_rows 0 The maximum number of rows that clink-select-complete can use. When this is 0, the limit is the terminal height.
match.preview_rows 0 The number of rows to show as a preview when using the clink-select-complete command (bound by default to Ctrl-Space). When this is 0, all rows are shown and if there are too many matches it instead prompts first like the complete command does. Otherwise it shows the specified number of rows as a preview without prompting, and it expands to show the full set of matches when the selection is moved past the preview rows.
match.sort_dirs with How to sort matching directory names. before = before files, with = with files, after = after files.
match.substring False * When set, if no completions are found with a prefix search, then a substring search is used.
match.translate_slashes system File and directory completions can be translated to use consistent slashes. The default is system to use the appropriate path separator for the OS host (backslashes on Windows). Use slash to use forward slashes, or backslash to use backslashes. Use off to turn off translating slashes from custom match generators.
match.wild True Matches ? and * wildcards and leading . when using any of the completion commands. Turn this off to behave how bash does, and not match wildcards or leading dots (but glob-complete-word always matches wildcards).
prompt.async True Enables asynchronous prompt refresh. Turn this off if prompt filter refreshes are annoying or cause problems.
prompt.transient off Controls when past prompts are collapsed (transient prompts). off = never collapse past prompts, always = always collapse past prompts, same_dir = only collapse past prompts when the current working directory hasn't changed since the last prompt.
readline.hide_stderr False Suppresses stderr from the Readline library. Enable this if Readline error messages are getting in the way.
terminal.adjust_cursor_style True When enabled, Clink adjusts the cursor shape and visibility to show Insert Mode, produce the visible bell effect, avoid disorienting cursor flicker, and to support ANSI escape codes that adjust the cursor shape and visibility. But it interferes with the Windows 10 Cursor Shape console setting. You can make the Cursor Shape setting work by disabling this Clink setting (and the features this provides).
terminal.differentiate_keys False When enabled, pressing Ctrl-H or I or M or [ generate special key sequences to enable binding them separately from Backspace or Tab or Enter or Esc.
terminal.east_asian_ambiguous auto There is a group of East Asian characters whose widths are ambiguous in the Unicode standard. This setting controls how to resolve the ambiguous widths. By default this is set to auto, but some terminal hosts may require setting this to a different value to work around limitations in the terminal hosts. Setting this to font measures the East Asian Ambiguous character widths using the current font. Setting it to one uses 1 as the width, or two uses 2 as the width. When this is auto (the default) and the current code page is 932, 936, 949, or 950 then the current font is used to measure the widths, or for any other code pages (including UTF8) the East Asian Ambiguous character widths are assumed to be 1.
terminal.emulation auto Clink can either emulate a virtual terminal and handle ANSI escape codes itself, or let the console host natively handle ANSI escape codes. native = pass output directly to the console host process, emulate = clink handles ANSI escape codes itself, auto = emulate except when running in ConEmu, Windows Terminal, or Windows 10 new console.
terminal.mouse_input auto Clink can optionally respond to mouse input, instead of letting the terminal respond to mouse input (e.g. to select text on the screen). When mouse input is enabled in Clink, clicking in the input line sets the cursor position, and clicking in popup lists selects an item, etc. Setting this to off lets the terminal host handle mouse input, on lets Clink handle mouse input, and auto lets Clink handle mouse input in ConEmu and in the default Conhost terminal when Quick Edit mode is unchecked in the console Properties dialog. For more information see Mouse Input.
terminal.mouse_modifier This selects which modifier keys (Alt, Ctrl, Shift) must be held in order for Clink to respond to mouse input when mouse input is enabled by the terminal.mouse_input setting. This is a text string that can list one or more modifier keys: 'alt', 'ctrl', and 'shift'. For example, setting it to "alt shift" causes Clink to only respond to mouse input when both Alt and Shift are held (and not Ctrl). If the %CLINK_MOUSE_MODIFIER% environment variable is set then its value supersedes this setting. For more information see Mouse Input.
terminal.raw_esc False When enabled, pressing Esc sends a literal escape character like in Unix or Linux terminals. This setting is disabled by default to provide a more predictable, reliable, and configurable input experience on Windows. Changing this only affects future Clink sessions, not the current session.
terminal.use_altgr_substitute False Support Windows' Ctrl-Alt substitute for AltGr. Turning this off may resolve collisions with Readline's key bindings.

* Some settings have alternative default values when Clink is installed with "Use enhanced default settings" checked in the setup program. This enables more of Clink's enhancements by default.

Compatibility Notes:

  • The esc_clears_line setting has been replaced by a clink-reset-line command that is by default bound to the Escape key. See Customizing Key Bindings for more information.
  • The match_colour setting has been removed, and Clink now supports Readline's completion coloring. See Completion Colors for more information.

Color Settings

Friendly Color Names

The Clink color settings are the ones whose names begin with color.. Color settings use the following syntax:

[attributes] [foreground_color] [on [background_color]]

Optional attributes (can be abbreviated to 3 letters):

Optional colors for foreground_color and background_color (can be abbreviated to 3 letters):

Examples (specific results may depend on the console host program):

Alternative SGR Syntax

It's also possible to set any ANSI SGR escape code using sgr SGR_parameters (for example sgr 7 is the code for reverse video, which swaps the foreground and background colors).

Be careful, since some escape code sequences might behave strangely.

File Locations

Settings and history are persisted to disk from session to session. By default Clink uses the current user's non-roaming application data directory. This user directory is usually found in one of the following locations;

All of the above locations can be overridden using the --profile path command line option which is specified when injecting Clink into cmd.exe using clink inject. Or with the %CLINK_PROFILE% environment variable if it is already present when Clink is injected (this envvar takes precedence over any other mechanism of specifying a profile directory, if more than one was used).

You can use clink info to find the directories and configuration files for the current Clink session.

Notes:

  • Clink performs tilde expansion on the %CLINK_PROFILE% environment variable value. If the path begins with ~\ then it is replaced with the current user's home directory (%HOMEDRIVE%%HOMEPATH% or %USERPROFILE%).
  • The --profile flag has a quirk for backward compatibility with older versions of Clink: ~\ in --profile is expanded to %LOCALAPPDATA% instead.

Files

.inputrc
This configures the Readline library used by Clink; it can contain key bindings and various settings. See Readline Init File for details, or see Create a .inputrc file for help getting started.

clink_settings
This is where Clink stores its settings. See Clink Settings for more information.

The location of the clink_settings file may also be overridden with the %CLINK_SETTINGS% environment variable. This is not recommended because it can be confusing; if the environment variable gets cleared or isn't always set then a different settings file may get used sometimes. But, one reason to use it is to make your settings sync with other computers.

  • set CLINK_SETTINGS=%USERPROFILE%\OneDrive\clink can let settings sync between computers through your OneDrive account.
  • set CLINK_SETTINGS=%USERPROFILE%\AppData\Roaming can let settings sync between computers in a work environment.

clink_history
This is where Clink stores command history. See Saved Command History for more information.

clink.log
The log file is written in the profile directory. Clink writes diagnostic information to the log file while Clink is running. Use clink info to find where it is located.

default_settings
This is an optional file. When Clink loads its settings, it first tries to load default values for settings from a default_settings file in either the profile directory or the binaries directory. Then it loads the clink_settings file from the profile directory.

The default_settings file can be useful for portable installations or when sharing your favorite Clink configuration with friends.

default_inputrc
This is an optional file. When Clink loads the Readline Init File, it first tries to load default values from a default_inputrc file in either the profile directory or the binaries directory. Then it loads the .inputrc file.

The default_inputrc file can be useful for portable installations or when sharing your favorite Clink configuration with friends.

Command Line Options

clink
Shows command line usage help.

clink inject
Injects Clink into a CMD.EXE process.
See clink inject --help for more information.

Note: If the --profile path begins with ~\ then it is replaced with the current user's home directory (%HOMEDRIVE%%HOMEPATH% or %USERPROFILE%).

clink autorun
Manages Clink's entry in CMD.EXE's autorun section, which can automatically inject Clink when starting CMD.EXE.
When Clink is installed for autorun, the automatic inject can be overridden by setting the CLINK_NOAUTORUN environment variable (to any value).
See clink autorun --help for more information.

clink set
clink set by itself lists all settings and their values.
clink set --describe by itself lists all settings and their descriptions (instead of their values).
clink set setting_name describes the setting and shows its current value.
clink set setting_name clear resets the setting to its default value.
clink set setting_name value sets the setting to the specified value.

clink installscripts
Adds a path to search for Lua scripts.
The path is stored in the registry and applies to all installations of Clink, regardless where their config paths are, etc. This is intended to make it easy for package managers like Scoop to be able to install (and uninstall) scripts for use with Clink.
See clink installscripts --help for more information.

clink uninstallscripts
Removes a path added by clink installscripts.
See clink uninstallscripts --help for more information.

clink history
Lists the command history.
See clink history --help for more information.
Also, Clink automatically defines history as an alias for clink history.

clink info
Prints information about Clink, including the version and various configuration directories and files.
Or clink --version shows just the version number.

clink echo
Echos key sequences to use in the .inputrc files for binding keys to Clink commands. Each key pressed prints the associated key sequence on a separate line, until Ctrl-C is pressed.

clink update
Checks for an updated version of Clink. If one is available, it is downloaded and will be installed the next time Clink is injected.

Automatic Updates

By default, Clink periodically and automatically checks for new versions. When an update is available, Clink prints a message on startup. To apply an update, run clink update when convenient to do so.

You can control the frequency of update checks with clink set clink.update_interval days, where days is the minimum number of days between checking for updates.

You can turn update checks off with clink set clink.autoupdate false, or turn them on with clink set clink.autoupdate true.

Notes:

Portable Configuration

Sometimes it's useful to run Clink from a flash drive or from a network share, especially if you want to use Clink on someone else's computer.

Here's how you can set up a portable configuration for Clink:

  1. Put your Lua scripts and other tools in the same directory as the Clink executable files. For example fzf.exe, z.cmd, oh-my-posh.exe, starship.exe etc can all go in the same directory on a flash drive or network share.
  2. Make a batch file such as portable.bat that injects Clink using a specific profile directory.
    • On a flash drive, you can have a portable profile in a subdirectory under the Clink directory.
    • On a network share, you'll want to copy some initial settings into a local profile directory (a profile directory on a network share will be slow).
  3. In any cmd.exe window on any computer, you can then run the portable.bat script to inject Clink and have all your favorite settings and key bindings work.

Here are some sample scripts:

portable.bat (on a flash drive)

This sample script assumes the portable.bat script is in the Clink directory, and it uses a clink_portable profile directory under the Clink directory.

@echo off
rem -- Do any other desired configuration here, such as loading a doskey macro file.
call "%~dp0clink.bat" inject --profile "%~dp0clink_portable" %1 %2 %3 %4 %5 %6 %7 %8 %9

portable.bat (on a network share)

This sample script assumes the portable.bat script is in the Clink directory, and that there is a file portable_clink_settings with the settings you want to copy to the local profile directory.

@echo off
if not exist "%TEMP%\clink_portable" md "%TEMP%\clink_portable" >nul
if not exist "%TEMP%\clink_portable\clink_settings" copy "%~dp0portable_clink_settings" "%TEMP%\clink_portable\clink_settings" >nul
rem -- Do any other desired configuration here, such as loading a doskey macro file.
call "%~dp0clink.bat" inject --profile "%TEMP%\clink_portable" %1 %2 %3 %4 %5 %6 %7 %8 %9

Configuring Readline

Clink uses the GNU Readline library to provide line editing functionality, which can be configured to add custom keybindings and macros by creating a Readline init file. The Clink documentation includes an updated and tailored copy of the Readline documentation, below.

The BasicsThe basics of using the Readline input editor in Clink.
Init FileAbout the .inputrc init file, configuration variables, and key bindings.
Bindable CommandsThe commands available for key bindings.
Completion ColorsHow to customize the completion colors.
Popup WindowsUsing the popup windows.

The Basics

Bare Essentials

To enter characters into the line, simply type them. The typed character appears where the cursor was, and then the cursor moves one space to the right. If you mistype a character, you can use Backspace to back up and delete the mistyped character.

Sometimes you may mistype a character, and not notice the error until you have typed several other characters. In that case, you can type Left (the left arrow key) to move the cursor to the left, and then correct your mistake. Afterwards, you can move the cursor to the right with Right (the right arrow key).

When you add text in the middle of a line, you will notice that characters to the right of the cursor are "pushed over" to make room for the text that you have inserted. Likewise, when you delete text behind the cursor, characters to the right of the cursor are "pulled back" to fill in the blank space created by the removal of the text. A list of the bare essentials for editing the text of an input line follows.

Key Description
Left Move back one character.
Right Move forward one character.
Backspace Delete the character to the left of the cursor.
Del Delete the character underneath the cursor.
A, a, 1, !, ", /, etc Insert the typed character into the line at the cursor.
Ctrl-z or
Ctrl-x Ctrl-u
Undo the last editing command. You can undo all the way back to an empty line.
Home Move to the start of the line.
End Move to the end of the line.
Ctrl-Left Move backward a word, where a word is composed of letters and digits.
Ctrl-Right Move forward a word.

Killing and Yanking

Killing text means to delete the text from the line, but to save it away for later use, usually by yanking (re-inserting) it back into the line. ("Cut" and "paste" are more recent jargon for "kill" and "yank", but killing and yanking do not affect the system's clipboard.)

If the description for a command says that it "kills" text, then you can be sure that you can get the text back in a different (or the same) place later.

When you use a kill command, the text is saved in a kill-ring. Any number of consecutive kills save all of the killed text together, so that when you yank it back, you get it all. The kill ring is not line specific; the text that you killed on a previously typed line is available to be yanked back later, when you are typing another line.

Here are some basic commands for killing text.

Key Description
Ctrl-End Kill the text from the current cursor position to the end of the line.
Ctrl-Del Kill from the cursor to the end of the current word, or, if between words, to the end of the next word. Word boundaries are the same as those used by Ctrl-Right.
Ctrl-Backspace Kill from the cursor the start of the current word, or, if between words, to the start of the previous word. Word boundaries are the same as those used by Ctrl-Left.
Ctrl-w Kill from the cursor to the previous whitespace. This is different than Ctrl-Backspace because the word boundaries differ.

Here is how to yank the text back into the line. Yanking means to copy the most-recently-killed text from the kill buffer.

Key Description
Ctrl-y Yank the most recently killed text back into the buffer at the cursor.
Alt-y Rotate the kill-ring, and yank the new top. You can only do this if the prior command is Ctrl-y or Alt-y.

Readline Arguments

You can pass numeric arguments to Readline commands. Sometimes the argument acts as a repeat count, other times it is the sign of the argument that is significant. If you pass a negative argument to a command which normally acts in a forward direction, that command will act in a backward direction. For example, to kill text back to the start of the line, you might type Alt-- Ctrl-k.

The general way to pass numeric arguments to a command is to type meta digits before the command. If the first "digit" typed is a minus sign (-), then the sign of the argument will be negative. Once you have typed one meta digit to get the argument started, you can type the remainder of the digits, and then the command. For example, to give the Del command an argument of 10, you could type Alt-1 0 Del, which will delete the next ten characters on the input line.

Searching for Commands in the History

Readline provides commands for searching through the command history for lines containing a specified string. There are two search modes: incremental and non-incremental.

Incremental searches begin before the user has finished typing the search string. As each character of the search string is typed, Readline displays the next entry from the history matching the string typed so far. An incremental search requires only as many characters as needed to find the desired history entry. To search backward in the history for a particular string, type Ctrl-r. Typing Ctrl-s searches forward through the history. The characters present in the value of the isearch-terminators variable are used to terminate an incremental search. If that variable has not been assigned a value, then Esc or Ctrl-j will terminate an incremental search. Ctrl-g will abort an incremental search and restore the original line. When the search is terminated, the history entry containing the search string becomes the current line.

To find other matching entries in the history list, type Ctrl-r or Ctrl-s as appropriate. This will search backward or forward in the history for the next entry matching the search string typed so far. Any other key sequence bound to a Readline command will terminate the search and execute that command. For instance, Enter will terminate the search and accept the line, thereby executing the command from the history list. A movement command will terminate the search, make the last line found the current line, and begin editing.

Readline remembers the last incremental search string. If two Ctrl-r's are typed without any intervening characters defining a new search string, any remembered search string is used.

Non-incremental searches read the entire search string before starting to search for matching history lines. The search string may be typed by the user or be part of the contents of the current line. Type Alt-p or Alt-n to start a non-incremental search backwards or forwards.

To search backward in the history for a line starting with the text before the cursor, type PgUp. Or search forward by typing PgDn.

See Saved Command History for more information on how history works.

Init File

You can customize key bindings and configuration variables by using an init file.

"Configuration variables" are customized in the init file, but "Clink settings" are customized with the clink set command.

Init File Location

The Readline init file is named .inputrc or _inputrc. Clink searches the directories referenced by the following environment variables in the order listed here, and loads the first .inputrc or _inputrc file it finds:

Other software that also uses the Readline library will also look for the .inputrc file (and possibly the _inputrc file too). To set macros and keybindings intended only for Clink, one can use the Readline init file conditional construct like this; $if clink [...] $endif.

You can use clink info to find the directories and configuration file for the current Clink session.

Compatibility Notes:

  • The clink_inputrc_base file from v0.4.8 is no longer used.
  • For backward compatibility, clink_inputrc is also loaded from the above locations, but it has been deprecated and may be removed in the future.
  • Clink v1.0.0a0 through Clink v1.2.27 accidentally loaded up to one Readline init file from each of the searched directories. That was incorrect behavior for loading Readline init files and has been fixed. If similar behavior is still desired, consider using the $include directive in the Readline init file, to load additional files.

Init File Syntax

There are only a few basic constructs allowed in the Readline init file:

Readline configuration variables

You can modify the behavior of Readline by altering the values of configuration variables in Readline using the set command within the init file. The syntax is simple:

set variable value

Here, for example, is how to change from the default Emacs-like key binding to use vi line editing commands:

set editing-mode vi

Variable names and values, where appropriate, are recognized without regard to case. Unrecognized variable names are ignored.

Boolean variables (those that can be set to on or off) are set to on if the value is null or empty, on (case-insensitive), or 1. Any other value results in the variable being set to off.

Variable Description
bell-style Controls what happens when Readline wants to ring the terminal bell. If set to "none", Readline never rings the bell. If set to "visible" (the default in Clink), Readline uses a visible bell if one is available. If set to "audible", Readline attempts to ring the terminal's bell.
blink-matching-paren If set to "on", Readline attempts to briefly move the cursor to an opening parenthesis when a closing parenthesis is inserted. The default is "off".
colored-completion-prefix If set to "on", when listing completions, Readline displays the common prefix of the set of possible completions using a different color. The color definitions are taken from the value of the %LS_COLORS% environment variable. The default is "off".
colored-stats If set to "on", Readline displays possible completions using different colors to indicate their file type. The color definitions are taken from the value of the %LS_COLORS% environment variable. The default is "off".
comment-begin The string to insert at the beginning of the line when the insert-comment command is executed. The default value is "::".
completion-display-width The number of screen columns used to display possible matches when performing completion. The value is ignored if it is less than 0 or greater than the terminal screen width. A value of 0 will cause matches to be displayed one per line. The default value is -1.
completion-ignore-case If set to "on", Readline performs filename matching and completion in a case-insensitive fashion. The default value is "on".
completion-prefix-display-length The length in characters of the common prefix of a list of possible completions that is displayed without modification. When set to a value greater than zero, common prefixes longer than this value are replaced with an ellipsis when displaying possible completions.
completion-query-items The number of possible completions that determines when the user is asked whether the list of possibilities should be displayed. If the number of possible completions is greater than or equal to this value, Readline will ask whether or not the user wishes to view them; otherwise, they are simply listed. This variable must be set to an integer value greater than or equal to 0. A negative value means Readline should never ask. The default limit is 100.
echo-control-characters When set to "on", on operating systems that indicate they support it, readline echoes a character corresponding to a signal generated from the keyboard. The default is "on".
editing-mode This controls which Readline input mode is used by default. When set to "emacs" (the default), Readline starts up in Emacs editing mode, where keystrokes are most similar to Emacs. When set to "vi", then vi input mode is used.
emacs-mode-string If the show-mode-in-prompt variable is enabled, this string is displayed immediately before the last line of the primary prompt when emacs editing mode is active. The value is expanded like a key binding, so the standard set of meta- and control prefixes and backslash escape sequences is available. Use the "\1" and "\2" escapes to begin and end sequences of non-printing characters, which can be used to embed a terminal control sequence into the mode string. The default is "@".
enable-bracketed-paste When set to "on", Readline will configure the terminal in a way that will enable it to insert each paste into the editing buffer as a single string of characters, instead of treating each character as if it had been read from the keyboard. This can prevent pasted characters from being interpreted as editing commands. The default is "on".
expand-tilde If set to "on", tilde expansion is performed when Readline attempts word completion. The default is "off".
history-preserve-point If set to "on", the history code attempts to place the point (the current cursor position) at the same location on each history line retrieved with previous-history or next-history. The default is "off".
horizontal-scroll-mode This variable can be set to either "on" or "off". Setting it to "on" means that the text of the lines being edited will scroll horizontally on a single screen line when they are longer than the width of the screen, instead of wrapping onto a new screen line. This variable is automatically set to "on" for terminals of height 1. By default, this variable is set to "off".
isearch-terminators The string of characters that should terminate an incremental search without subsequently executing the character as a command (see Searching for Commands in the History). If this variable has not been given a value, the characters Esc and Ctrl-j will terminate an incremental search.
keymap Sets Readline's idea of the current keymap for key binding commands. Built-in keymap names are emacs, emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move, vi-command, and vi-insert. vi is equivalent to vi-command (vi-move is also a synonym); emacs is equivalent to emacs-standard. The default value is emacs. The value of the editing-mode variable also affects the default keymap.
mark-directories If set to "on", completed directory names have a slash appended. The default is "on".
mark-modified-lines This variable, when set to "on", causes Readline to display an asterisk (*) at the start of history lines which have been modified. This variable is "off" by default.
mark-symlinked-directories If set to "on", completed names which are symbolic links to directories have a slash appended (subject to the value of mark-directories). The default is "off".
match-hidden-files This variable, when set to "on", causes Readline to match files whose names begin with a . (hidden files on Unix and Linux) when performing filename completion. If set to "off", the leading . must be supplied by the user in the filename to be completed. This variable is "on" by default.
menu-complete-display-prefix If set to "on", menu completion displays the common prefix of the list of possible completions (which may be empty) before cycling through the list. The default is "off".
page-completions If set to "on", Readline uses an internal more-like pager to display a screenful of possible completions at a time. This variable is "on" by default.
print-completions-horizontally If set to "on", Readline will display completions with matches sorted horizontally in alphabetical order, rather than down the screen. The default is "off".
show-all-if-ambiguous This alters the default behavior of the completion functions. If set to "on", words which have more than one possible completion cause the matches to be listed immediately instead of ringing the bell. The default value is "off".
show-all-if-unmodified This alters the default behavior of the completion functions in a fashion similar to show-all-if-ambiguous. If set to "on", words which have more than one possible completion without any possible partial completion (the possible completions don't share a common prefix) cause the matches to be listed immediately instead of ringing the bell. The default value is "off".
show-mode-in-prompt If set to "on", add a string to the beginning of the prompt indicating the editing mode: emacs, vi command, or vi insertion. The mode strings are user-settable (e.g., emacs-mode-string). The default value is "off".
skip-completed-text If set to "on", this alters the default completion behavior when inserting a single match into the line. It's only active when performing completion in the middle of a word. If enabled, Readline does not insert characters from the completion that match characters after point (the cursor position) in the word being completed, so portions of the word following the cursor are not duplicated. For instance, if this is enabled, attempting completion when the cursor is after the e in "Makefile" will result in "Makefile" rather than "Makefilefile", assuming there is a single possible completion. The default value is "off".
vi-cmd-mode-string If the show-mode-in-prompt variable is enabled, this string is displayed immediately before the last line of the primary prompt when vi editing mode is active and in command mode. The value is expanded like a key binding, so the standard set of meta- and control prefixes and backslash escape sequences is available. Use the "\1" and "\2" escapes to begin and end sequences of non-printing characters, which can be used to embed a terminal control sequence into the mode string. The default is "(cmd)".
vi-ins-mode-string If the show-mode-in-prompt variable is enabled, this string is displayed immediately before the last line of the primary prompt when vi editing mode is active and in insertion mode. The value is expanded like a key binding, so the standard set of meta- and control prefixes and backslash escape sequences is available. Use the "\1" and "\2" escapes to begin and end sequences of non-printing characters, which can be used to embed a terminal control sequence into the mode string. The default is "(ins)".
visible-stats If set to "on", a character denoting a file's type is appended to the filename when listing possible completions. The default is "off".

Clink adds some new configuration variables for Readline:

Variable Description
completion-auto-query-items If set to "on", automatically prompts before displaying completions if they won't fit without scrolling (this overrules the completion-query-items variable). The default is "on".
history-point-at-end-of-anchored-search If set to "on", this puts the cursor at the end of the line when using history-search-forward or history-search-backward. The default is "off".
menu-complete-wraparound If this is "on", the menu-complete family of commands wraps around when reaching the end of the possible completions. The default is "on".
search-ignore-case Controls whether the history search commands ignore case. The default is "on".

Some configuration variables are deprecated in Clink:

Variable Description
bind-tty-special-chars Clink doesn't need or use this.
completion-map-case Instead, use the match.ignore_case Clink setting (see the relaxed mode).
convert-meta Clink requires this to be "on", and sets it to "on".
disable-completion If set to "on", Readline will inhibit word completion. Completion characters will be inserted into the line as if they had been mapped to self-insert. The default is "off".
enable-meta-key Clink requires this to be "on", and sets it to "on".
history-size Instead, use the history.max_lines Clink setting.
input-meta Clink requires this to be "on", and sets it to "on".
keyseq-timeout Clink does not support this.
output-meta Clink requires this to be "on", and sets it to "on".
revert-all-at-newline Clink always reverts all in-memory changes to history lines each time a new input prompt starts.

Readline key bindings

The syntax for controlling key bindings in the init file is simple. First you need to find the name of the command that you want to change. The following sections contain tables of the command name, the default keybinding, if any, and a short description of what the command does (see Bindable Commands).

Once you know the name of the command, simply place on a line in the init file the name of the key you wish to bind the command to, a colon, and then the name of the command. There can be no space between the key name and the colon (any space will be interpreted as part of the key name). The name of the key can be expressed in different ways, depending on what you find most comfortable.

In addition to command names, Readline allows keys to be bound to a string that is inserted when the key is pressed (a macro).

LineDescription
keyname: commandBinds a named command to a key.
keyname: "literal text"Binds a macro to a key. A macro inserts the literal text into the input line.
keyname: "luafunc:lua_function_name"Binds a named Lua function to a key. See Lua key bindings for more information.

Key names
Key names can be a name or a sequence. Names are not quoted, and sequences are quoted.

Names can be used to refer to simple keys like Space, Return, Tab, letters and digits (A, b, 1, ...), and most punctuation (!, @, ., _, ...). Names can also include modifier prefixes C- or Control- for the Ctrl key, or M- or Meta- for the Meta or Alt key. However, modifier prefixes don't work with simple key names; you can't use C-Space, instead a sequence is needed for special keys like that.

Sequences are surrounded by double quotes, and specify an entire sequence of input characters. Some special escape codes can be used:

Code Description
\C- Prefix meaning Ctrl.
\M- Prefix meaning Meta or Alt.
\e The literal ESC (escape) character code, which is the first character code in most special key sequences.
Note: the ESC code isn't necessarily the same as the Esc key; see terminal.raw_esc.
\\ Backslash.
\" ", a double quotation mark.
\' ', a single quote or apostrophe.
\a Alert (bell).
\b Backspace.
\d Delete. (Note: this is not very useful for Clink; it is not the Del key.)
\f Form feed.
\n Newline.
\r Carriage return.
\t Horizontal tab.
\v Vertical tab.
<span class="arg">nnn The eight-bit character whose value is the octal value nnn (one to three digits)
\xHH The eight-bit character whose value is the hexadecimal value HH (one or two hex digits)

Here are some examples to illustrate the differences between names and sequences:

Name Sequence Description
C-a "\C-a" Both refer to Ctrl-a.
M-a "\M-a" Both refer to Alt-a.
M-C-a "\M-\C-a" Both refer to Alt-Ctrl-a.
hello It's just h. It is not quoted, so it is a name. The ello part is a syntax error and is silently discarded by Readline.
"hello" The series of five keys h e l l o.
Space The Space key.
"Space" The series of five keys S p a c e.

Special keys like Up are represented by VT220 escape codes such as"\e[A". See Discovering Clink key sequences and Binding special keys for how to find the keyname for the key you want to bind.

Key bindings
Key bindings can be either functions or macros (literal text). Functions are not quoted, and macros are quoted.

When entering the text of a macro, single or double quotes must be used to indicate a macro definition. Unquoted text is assumed to be a function name. In the macro body, the backslash escapes described above are expanded. Backslash will quote any other character in the macro text, including " and '. For example, the following binding will make pressing Ctrl-x \ insert a single \ into the line:

"\C-x\\": "\\"

Examples
# Using key names.
C-u: universal-argument         # Bind Ctrl-u to invoke the universal-argument command.
C-o: "> output"                 # Bind Ctrl-o to insert the text "> output" into the line.

# Using key sequences.
"\C-u": universal-argument      # Bind Ctrl-u to invoke the universal-argument command.
"\C-x\C-r": clink-reload        # Bind Ctrl-x,Ctrl-r to reload the configuration and Lua scripts for Clink.
"\eOP": clink-popup-show-help   # Bind F1 to invoke the clink-popup-show-help command.

See Customizing Key Bindings for more information about binding keys in Clink.

Conditional init constructs

Readline implements a facility similar in spirit to the conditional compilation features of the C preprocessor which allows key bindings and variable settings to be performed as the result of tests. There are four parser directives used.

$if

The $if construct allows bindings to be made based on the editing mode, the terminal being used, or the application using Readline. The text of the test, after any comparison operator, extends to the end of the line; unless otherwise noted, no characters are required to isolate it.

The $if mode= form of the $if directive is used to test whether Readline is in emacs or vi mode. This may be used in conjunction with the "set keymap" command, for instance, to set bindings in the emacs-standard and emacs-ctlx keymaps only if Readline is starting out in emacs mode. (The directive is only tested during startup.)

$if mode == emacs
set show-mode-in-prompt on
$endif

The $if term= form may be used to include terminal-specific key bindings, perhaps to bind the key sequences output by the terminal's function keys. The word on the right side of the "=" is tested against both the full name of the terminal and the portion of the terminal name before the first "-". This allows sun to match both sun and sun-cmd, for instance. This is not useful with Clink, because Clink has its own terminal driver.

The $if version test may be used to perform comparisons against specific Readline versions. The version expands to the current Readline version. The set of comparison operators includes = (and ==), !=, <=, >=, <, and >. The version number supplied on the right side of the operator consists of a major version number, an optional decimal point, and an optional minor version (e.g., "7.1"). If the minor version is omitted, it is assumed to be "0". The operator may be separated from the string version and from the version number argument by whitespace. The following example sets a variable if the Readline version being used is 7.0 or newer:

$if version >= 7.0
set show-mode-in-prompt on
$endif

The $if application construct is used to include application-specific settings. Each program using the Readline library sets the application name, and you can test for a particular value. This could be used to bind key sequences to functions useful for a specific program. For instance, the following command adds a key sequence that quotes the current or previous word, but only in Clink:

$if clink
# Quote the current or previous word
"\C-xq": "\eb\"\ef\""
$endif

The $if variable construct provides simple equality tests for Readline variables and values. The permitted comparison operators are =, ==, and !=. The variable name must be separated from the comparison operator by whitespace; the operator may be separated from the value on the right hand side by whitespace. Both string and boolean variables may be tested. Boolean variables must be tested against the values on and off. The following example is equivalent to the mode=emacs test described above:

$if editing-mode == emacs
set show-mode-in-prompt on
$endif

$endif

This command, as seen in the previous example, terminates an $if command.

$else

Commands in this branch of the $if directive are executed if the test fails.

$include

This directive takes a single filename as an argument and reads commands and bindings from that file. For example, the following directive reads from "c:\dir\inputrc":

$include c:\dir\inputrc

Sample .inputrc file

Here is a sample .inputrc file with some of the variables and key bindings that I use:

$if clink           # begin clink-only section

set colored-completion-prefix                       on
set colored-stats                                   on
set mark-symlinked-directories                      on
set visible-stats                                   off
set completion-auto-query-items                     on
set history-point-at-end-of-anchored-search         on
set menu-complete-wraparound                        off
set search-ignore-case                              on

# The following key bindings are for emacs mode.
set keymap emacs

"\e[27;8;72~":      clink-popup-show-help           # Alt-Ctrl-Shift-H

# Completion key bindings.
"\t":               old-menu-complete               # Tab
"\e[Z":             old-menu-complete-backward      # Shift-Tab
"\e[27;5;32~":      clink-select-complete           # Ctrl-Space

# Some key bindings I got used to from 4Dos/4NT/Take Command.
C-b:                                                # Ctrl-B (cleared because I redefined Ctrl-F)
C-d:                remove-history                  # Ctrl-D (replaces `delete-char`)
C-f:                clink-expand-doskey-alias       # Ctrl-F (replaces `forward-char`)
C-k:                add-history                     # Ctrl-K (replaces `kill-line`)
"\e[A":             history-search-backward         # Up (replaces `previous-history`)
"\e[B":             history-search-forward          # Down (replaces `next-history`)
"\e[5~":            clink-popup-history             # PgUp (replaces `history-search-backward`)
"\e[6~":                                            # PgDn (cleared because I redefined PgUp)
"\e[1;5F":          end-of-line                     # Ctrl-End (replaces `kill-line`)
"\e[1;5H":          beginning-of-line               # Ctrl-Home (replaces `backward-kill-line`)

# Some key bindings handy in default (conhost) console windows.
M-b:                                                # Alt-B (cleared because I redefined Alt-F)
M-f:                clink-find-conhost              # Alt-F for "Find..." from the console's system menu
M-m:                clink-mark-conhost              # Alt-M for "Mark" from the console's system menu

# Some key bindings for interrogating the Readline configuration.
"\C-x\C-f":         dump-functions                  # Ctrl-X, Ctrl-F
"\C-x\C-m":         dump-macros                     # Ctrl-X, Ctrl-M
"\C-x\C-v":         dump-variables                  # Ctrl-X, Ctrl-V

# Misc other key bindings.
"\e[27;2;32~":      clink-magic-suggest-space       # Shift-Space
"\e[5;6~":          clink-popup-directories         # Ctrl-Shift-PgUp
C-_:                kill-line                       # Ctrl-- (replaces `undo`)

$endif              # end clink-only section

Bindable Commands

Commands For Moving

Command Key Description
beginning-of-line Home Move to the start of the current line.
end-of-line End Move to the end of the line.
forward-char Right Move forward a character.
backward-char Left Move back a character.
forward-word Ctrl-Right Move forward to the end of the next word. Words are composed of letters and digits.
backward-word Ctrl-Left Move back to the start of the current or previous word. Words are composed of letters and digits.
previous-screen-line Attempt to move point to the same physical screen column on the previous physical screen line. This will not have the desired effect if the current Readline line does not take up more than one physical line or if point is not greater than the length of the prompt plus the screen width.
next-screen-line Attempt to move point to the same physical screen column on the next physical screen line. This will not have the desired effect if the current Readline line does not take up more than one physical line or if the length of the current Readline line is not greater than the length of the prompt plus the screen width.
clear-display Alt-Ctrl-l Clear the screen and, if possible, the terminal's scrollback buffer, then redraw the current line, leaving the current line at the top of the screen.
clear-screen Ctrl-l Clear the screen, then redraw the current line, leaving the current line at the top of the screen.
redraw-current-line Refresh the current line. By default, this is unbound.

Commands For Manipulating The History

Command Key Description
accept-line Enter Accept the line regardless of where the cursor is. If this line is non-empty, it may be added to the history list for future recall.
previous-history Ctrl-p Move "back" through the history list, fetching the previous command.
next-history Ctrl-n Move "forward" through the history list, fetching the next command.
beginning-of-history Alt-< Move to the first line in the history.
end-of-history Alt-> Move to the end of the input history, i.e., the line currently being entered.
reverse-search-history Ctrl-r Search backward starting at the current line and moving "up" through the history as necessary. This is an incremental search. This command sets the region to the matched text and activates the mark.
forward-search-history Ctrl-s Search forward starting at the current line and moving "down" through the history as necessary. This is an incremental search. This command sets the region to the matched text and activates the mark.
non-incremental-reverse-search-history Alt-p Search backward starting at the current line and moving "up" through the history as necessary using a non-incremental search for a string supplied by the user. The search string may match anywhere in a history line.
non-incremental-forward-search-history Alt-n Search forward starting at the current line and moving "down" through the history as necessary using a non-incremental search for a string supplied by the user. The search string may match anywhere in a history line.
history-search-forward Search forward through the history for the string of characters between the start of the current line and the point. The search string must match at the beginning of a history line. This is a non-incremental search. By default, this command is unbound.
history-search-backward Search backward through the history for the string of characters between the start of the current line and the point. The search string must match at the beginning of a history line. This is a non-incremental search. By default, this command is unbound.
history-substring-search-forward Search forward through the history for the string of characters between the start of the current line and the point. The search string may match anywhere in a history line. This is a non-incremental search. By default, this command is unbound.
history-substring-search-backward Search backward through the history for the string of characters between the start of the current line and the point. The search string may match anywhere in a history line. This is a non-incremental search. By default, this command is unbound.
yank-nth-arg Alt-Ctrl-y Insert the first argument to the previous command (usually the second word on the previous line) at point. With an argument n, insert the nth word from the previous command (the words in the previous command begin with word 0). A negative argument inserts the nth word from the end of the previous command. Once the argument n is computed, the argument is extracted as if the "!n" history expansion had been specified.
yank-last-arg Alt-. or Alt-_ Insert last argument to the previous command (the last word of the previous history entry). With a numeric argument, behave exactly like yank-nth-arg. Successive calls to yank-last-arg move back through the history list, inserting the last word (or the word specified by the argument to the first call) of each line in turn. Any numeric argument supplied to these successive calls determines the direction to move through the history. A negative argument switches the direction through the history (back or forward). The history expansion facilities are used to extract the last argument, as if the "!$" history expansion had been specified.
operate-and-get-next Ctrl-o Accept the current line for return to the calling application as if a newline had been entered, and fetch the next line relative to the current line from the history for editing. A numeric argument, if supplied, specifies the history entry to use instead of the current line.

Commands For Changing Text

Command Key Description
delete-char Ctrl-d Delete the character at point.
Note: also see the cmd.ctrld_exits setting.
backward-delete-char Backspace Delete the character behind the cursor. A numeric argument means to kill the characters instead of deleting them.
forward-backward-delete-char Delete the character under the cursor, unless the cursor is at the end of the line, in which case the character behind the cursor is deleted. By default, this is not bound to a key.
quoted-insert Ctrl-q Add the next character typed to the line verbatim. This is how to insert key sequences like Ctrl-h or Tab, for example.
tab-insert Alt-Ctrl-i Insert a tab character.
self-insert a, b, A, 1, !, etc Insert the key itself.
bracketed-paste-begin This function is intended to be bound to the "bracketed paste" escape sequence sent by some terminals, and such a binding is assigned by default. It allows Readline to insert the pasted text as a single unit without treating each character as if it had been read from the keyboard. The characters are inserted as if each one was bound to self-insert instead of executing any editing commands.
Bracketed paste sets the region (the characters between point and the mark) to the inserted text. It uses the concept of an active mark: when the mark is active, Readline redisplay uses the terminal's standout mode to denote the region.
transpose-chars Ctrl-t Drag the character before the cursor forward over the character at the cursor, moving the cursor forward as well. If the insertion point is at the end of the line, then this transposes the last two characters of the line. Negative arguments have no effect.
transpose-words Alt-t Drag the word before point past the word after point, moving point past that word as well. If the insertion point is at the end of the line, this transposes the last two words on the line.
upcase-word Alt-u Uppercase the current (or following) word. With a negative argument, uppercase the previous word, but do not move the cursor.
downcase-word Alt-l Lowercase the current (or following) word. With a negative argument, lowercase the previous word, but do not move the cursor.
capitalize-word Capitalize the current (or following) word. With a negative argument, capitalize the previous word, but do not move the cursor.
overwrite-mode Toggle overwrite mode. With an explicit positive numeric argument, switches to overwrite mode. With an explicit non-positive numeric argument, switches to insert mode. This command affects only emacs mode; vi mode does overwrite differently. Each new command line prompt starts in insert mode.
In overwrite mode, characters bound to self-insert replace the text at point rather than pushing the text to the right. Characters bound to backward-delete-char replace the character before point with a space.
By default, this command is unbound.

Killing And Yanking

Command Key Description
kill-line Ctrl-k Kill the text from point to the end of the line. With a negative numeric argument, kill backward from the cursor to the beginning of the current line.
backward-kill-line Ctrl-x Ctrl-Backspace Kill backward from the cursor to the beginning of the current line. With a negative numeric argument, kill forward from the cursor to the end of the current line.
unix-line-discard Ctrl-u Kill backward from the cursor to the beginning of the current line.
kill-whole-line Kill all characters on the current line, no matter where point is. By default, this is unbound.
kill-word Alt-d Kill from point to the end of the current word, or if between words, to the end of the next word. Word boundaries are the same as forward-word.
backward-kill-word Alt-Ctrl-Backspace Kill the word behind point. Word boundaries are the same as backward-word.
unix-word-rubout Ctrl-w Kill the word behind point, using white space as a word boundary. The killed text is saved on the kill-ring.
unix-filename-rubout Kill the word behind point, using white space and the slash character as the word boundaries. The killed text is saved on the kill-ring.
delete-horizontal-space Delete all spaces and tabs around point. By default, this is unbound.
kill-region Kill the text in the current region. By default, this command is unbound.
copy-region-as-kill Copy the text in the region to the kill buffer, so it can be yanked right away. By default, this command is unbound.
copy-backward-word Copy the word before point to the kill buffer. The word boundaries are the same as backward-word. By default, this command is unbound.
copy-forward-word Copy the word following point to the kill buffer. The word boundaries are the same as forward-word. By default, this command is unbound.
yank Ctrl-y Yank the top of the kill ring into the buffer at point.
yank-pop Alt-y Rotate the kill-ring, and yank the new top. You can only do this if the prior command is yank or yank-pop.

Specifying Numeric Arguments

Command Key Description
digit-argument Alt-digit or Alt-- Add this digit to the argument already accumulating, or start a new argument. Alt-- starts a negative argument.
universal-argument This is another way to specify an argument. If this command is followed by one or more digits, optionally with a leading minus sign, those digits define the argument. If the command is followed by digits, executing universal-argument again ends the numeric argument, but is otherwise ignored. As a special case, if this command is immediately followed by a character that is neither a digit nor minus sign, the argument count for the next command is multiplied by four. The argument count is initially one, so executing this function the first time makes the argument count four, a second time makes the argument count sixteen, and so on. By default, this is not bound to a key.

Completion Commands

Command Key Description
complete Tab Attempt to perform completion on the text before point.
possible-completions Alt-= List the possible completions of the text before point. When displaying completions, Readline sets the number of columns used for display to the value of completion-display-width, the value of the environment variable %COLUMNS%, or the screen width, in that order.
insert-completions Alt-* Insert all completions of the text before point that would have been generated by possible-completions.
menu-complete Similar to complete, but replaces the word to be completed with a single match from the list of possible completions. Repeated execution of menu-complete steps through the list of possible completions, inserting each match in turn. At the end of the list of completions, the bell is rung (subject to the setting of bell-style) and the original text is restored. An argument of n moves n positions forward in the list of matches; a negative argument may be used to move backward through the list. This command is intended to be bound to TAB, but is unbound by default.
menu-complete-backward Identical to menu-complete, but moves backward through the list of possible completions, as if menu-complete had been given a negative argument.
old-menu-complete Similar to menu-complete but isn't limited by completion-query-items and doesn't include the common prefix of the possible completions. This behaves like the default completion in cmd.exe on Windows.
delete-char-or-list Deletes the character under the cursor if not at the beginning or end of the line (like delete-char). If at the end of the line, behaves identically to possible-completions. This command is unbound by default.

Keyboard Macros

Command Key Description
start-kbd-macro Ctrl-x ( Begin saving the characters typed into the current keyboard macro.
end-kbd-macro Ctrl-x ) Stop saving the characters typed into the current keyboard macro and save the definition.
call-last-kbd-macro Ctrl-x e Re-execute the last keyboard macro defined, by making the characters in the macro appear as if typed at the keyboard.
print-last-kbd-macro Print the last keboard macro defined in a format suitable for the inputrc file.

Some Miscellaneous Commands

Command Key Description
re-read-init-file Ctrl-x Ctrl-r Read in the contents of the inputrc file, and incorporate any bindings or variable assignments found there.
abort Ctrl-g Abort the current editing command and ring the terminal's bell (subject to the setting of bell-style).
do-lowercase-version Alt-X, etc If the key X is an upper case letter, run the command that is bound to the corresponding Alt-x lower case letter. The behavior is undefined if x is already lower case.
undo Ctrl-z or Ctrl-_ Incremental undo, separately remembered for each line.
revert-line Alt-r Undo all changes made to this line. This is like executing the undo command enough times to get back to the beginning.
tilde-expand Alt-~ Perform tilde expansion on the current word.
set-mark Ctrl-@ Set the mark to the point. If a numeric argument is supplied, the mark is set to that position.
exchange-point-and-mark Ctrl-x Ctrl-x Swap the point with the mark. The current cursor position is set to the saved position, and the old cursor position is saved as the mark.
character-search Ctrl-] A character is read and point is moved to the next occurrence of that character. A negative count searches for previous occurrences.
character-search-backward Alt-Ctrl-] A character is read and point is moved to the previous occurrence of that character. A negative count searches for subsequent occurrences.
insert-comment Alt-# Without a numeric argument, the value of the comment-begin variable is inserted at the beginning of the current line. If a numeric argument is supplied, this command acts as a toggle: if the characters at the beginning of the line do not match the value of comment-begin, the value is inserted, otherwise the characters in comment-begin are deleted from the beginning of the line. In either case, the line is accepted as if a newline had been typed.
dump-functions Print all of the functions and their key bindings to the Readline output stream. If a numeric argument is supplied, the output is formatted in such a way that it can be made part of an inputrc file. This command is unbound by default.
dump-variables Print all of the settable variables and their values to the Readline output stream. If a numeric argument is supplied, the output is formatted in such a way that it can be made part of an inputrc file. This command is unbound by default.
dump-macros Print all of the Readline key sequences bound to macros and the strings they output. If a numeric argument is supplied, the output is formatted in such a way that it can be made part of an inputrc file. This command is unbound by default.

Readline vi Mode

While the Readline library does not have a full set of vi editing functions, it does contain enough to allow simple editing of the line. The Readline vi mode behaves as specified in the POSIX standard.

In order to switch interactively between emacs and vi editing modes, use the command Alt-Ctrl-j (bound to emacs-editing-mode when in vi mode and to vi-editing-mode in emacs mode). The Readline default is emacs mode.

When you enter a line in vi mode, you are already placed in "insertion" mode, as if you had typed an "i". Pressing Esc switches you into "command" mode, where you can edit the text of the line with the standard vi movement keys, move to previous history lines with "k" and subsequent lines with "j", and so forth.

Command Key Description
emacs-editing-mode Ctrl-e When in vi command mode, this causes a switch to emacs editing mode.
vi-editing-mode Alt-Ctrl-j When in emacs editing mode, this causes a switch to vi editing mode.

Other Readline Commands

These other commands are not very useful in Clink, but exist nevertheless.

Command Key Description
prefix-meta "Metafy" the next character typed. This is for keyboards without an Alt meta key. Typing a key bound to prefix-meta and then f is equivalent to typing Alt-f. By default this is bound to Esc, but only when the terminal.raw_esc Clink setting is enabled.
skip-csi-sequence This has no effect unless the terminal.raw_esc Clink setting is enabled. Reads enough characters to consume a multi-key sequence such as those defined for keys like Home and End. Such sequences begin with a Control Sequence Indicator (CSI), which is ESC [. If this sequence is bound to "\e[", keys producing such sequences will have no effect unless explicitly bound to a readline command, instead of inserting stray characters into the editing buffer. This is unbound by default.

Clink also adds some new commands, beyond what's normally provided by Readline.

Command Key Description
add-history Alt-Ctrl-k Adds the current line to the history without executing it, and clears the editing line.
alias-expand-line A synonym for clink-expand-doskey-alias.
clink-accept-suggested-line If there is a suggestion, insert the suggestion and accept the input line (like accept-line).
clink-complete-numbers Like complete, but for numbers from the console screen (3 digits or more, up to hexadecimal).
clink-copy-cwd Alt-c Copy the current working directory to the clipboard.
clink-copy-line Alt-Ctrl-c Copy the current line to the clipboard.
clink-copy-word Alt-Ctrl-w Copy the word at the cursor to the clipboard, or copies the nth word if a numeric argument is provided via the digit-argument keys.
clink-ctrl-c Ctrl-c Discards the current line and starts a new one (like Ctrl-C in CMD.EXE).
clink-diagnostics Ctrl-x Ctrl-z Show internal diagnostic information.
clink-exit Alt-F4 Replaces the current line with exit and executes it (exits the shell instance).
clink-expand-doskey-alias Alt-Ctrl-f Expand the doskey alias (if any) at the beginning of the line.
clink-expand-env-var Expand the environment variable (e.g. %FOOBAR%) at the cursor.
clink-expand-history Alt-^ Perform history expansion in the current input line.
clink-expand-history-and-alias Perform history and doskey alias expansion in the current input line.
clink-expand-line Alt-Ctrl-e Perform history, doskey alias, and environment variable expansion in the current input line.
clink-find-conhost Activates the "Find" dialog when running in a standard console window (hosted by the OS conhost). This is equivalent to picking "Find..." from the console window's system menu. When clink.default_bindings is enabled, this is bound to Ctrl-f.
clink-insert-dot-dot Alt-a Inserts ..\ at the cursor.
clink-insert-suggested-full-word If there is a suggestion, insert the next full word from the suggested line.
clink-insert-suggested-line If there is a suggestion, insert the suggested line.
clink-insert-suggested-word If there is a suggestion, insert the next word from the suggested line.
clink-magic-suggest-space Inserts the next full word of the suggestion (if any) up to a space, and also inserts a space.
clink-mark-conhost Activates the "Mark" mode when running in a standard console window (hosted by the OS conhost). This is equivalent to picking "Mark" from the console window's system menu. When clink.default_bindings is enabled, this is bound to Ctrl-m.
clink-menu-complete-numbers Like menu-complete, but for numbers from the console screen (3 digits or more, up to hexadecimal).
clink-menu-complete-numbers-backward Like menu-complete-backward, but for numbers from the console screen (3 digits or more, up to hexadecimal).
clink-old-menu-complete-numbers Alt-Ctrl-n Like old-menu-complete, but for numbers from the console screen (3 digits or more, up to hexadecimal).
clink-old-menu-complete-numbers-backward Like old-menu-complete-backward, but for numbers from the console screen (3 digits or more, up to hexadecimal).
clink-paste Ctrl-v Paste the clipboard at the cursor.
clink-popup-complete A synonym for clink-select-complete.
clink-popup-complete-numbers Alt-Ctrl-Shift-N Like clink-select-complete, but for numbers from the console screen (3 digits or more, up to hexadecimal).
clink-popup-directories Alt-Ctrl-PgUp Show a popup window of recent current working directories. In the popup, use Enter to cd /d to the highlighted directory.
clink-popup-history Show a popup window that lists the command history (if any text precedes the cursor then it uses an anchored search to filter the list). In the popup, use Enter to execute the highlighted command.
clink-popup-show-help Show a popup window that lists the currently active key bindings, and can invoke a selected key binding. The default key binding for this is Ctrl-Alt-H.
clink-reload Ctrl-x Ctrl-r Reloads the .inputrc file and the Lua scripts.
clink-reset-line Esc Clears the current line.
clink-scroll-bottom Alt-End Scroll the console window to the bottom (the current input line).
clink-scroll-line-down Alt-Down Scroll the console window down one line.
clink-scroll-line-up Alt-Up Scroll the console window up one line.
clink-scroll-page-down Alt-PgDn Scroll the console window down one page.
clink-scroll-page-up Alt-PgUp Scroll the console window up one page.
clink-scroll-top Alt-Home Scroll the console window to the top.
clink-select-complete Ctrl-Space Like complete, but shows interactive menu of matches and responds to arrow keys and typing to filter the matches. While completing, F1 toggles showing match descriptions at the bottom vs next to each match.
clink-selectall-conhost Mimics the "Select All" command when running in a standard console window (hosted by the OS conhots). Selects the input line text. If already selected, then it invokes the "Select All" command from the console window's system menu and selects the entire screen buffer's contents. When clink.default_bindings is enabled, this is bound to Ctrl-a.
clink-shift-space Shift-Space Invokes the normal Space key binding, so that Shift-Space behaves the same as Space.
clink-show-help Alt-h Lists the currently active key bindings using friendly key names. A numeric argument affects showing categories and descriptions: 0 for neither, 1 for categories, 2 for descriptions, 3 for categories and descriptions (the default), 4 for all commands (even if not bound to a key).
clink-show-help-raw Lists the currently active key bindings using raw key sequences. A numeric argument affects showing categories and descriptions: 0 for neither, 1 for categories, 2 for descriptions, 3 for categories and descriptions (the default), 4 for all commands (even if not bound to a key).
clink-up-directory Ctrl-PgUp Changes to the parent directory.
clink-what-is Alt-Shift-/ Show the key binding for the next key sequence that is input.
cua-backward-char Shift-Left Extends the selection and moves back a character.
cua-backward-word Ctrl-Shift-Left Extends the selection and moves back a word.
cua-beg-of-line Shift-Home Extends the selection and moves to the start of the current line.
cua-copy Shift-Ins Copies the selection to the clipboard.
cua-cut Shift-Del Cuts the selection to the clipboard.
cua-end-of-line Shift-End Extends the selection and moves to the end of the line.
cua-forward-char Shift-Right Extends the selection and moves forward a character, or inserts the next full suggested word up to a space.
cua-forward-word Ctrl-Shift-Right Extends the selection and moves forward a word.
cua-next-screen-line Shift-Down Extends the selection down one line.
cua-previous-screen-line Shift-Up Extends the selection up one line.
cua-select-all Extends the selection to the entire current line.
cua-select-word Selects the word at the cursor.
edit-and-execute-command Ctrl-x Ctrl-e Invoke an editor on the current input line, and execute the result as commands. This attempts to invoke %VISUAL%, %EDITOR%, or notepad.exe as the editor, in that order.
glob-complete-word Alt-g Perform wildcard completion on the text before the cursor point, with a * implicitly appended.
glob-expand-word Ctrl-x * Insert all the wildcard completions that glob-list-expansions would list. If a numeric argument is supplied, a * is implicitly appended before completion.
glob-list-expansions Ctrl-x g List the possible wildcard completions of the text before the cursor point. If a numeric argument is supplied, a * is implicitly appended before completion.
history-and-alias-expand-line A synonym for clink-expand-history-and-alias.
history-expand-line A synonym for clink-expand-history.
insert-last-argument A synonym for yank-last-arg.
magic-space Perform history expansion on the text before the cursor position and insert a space.
old-menu-complete-backward Like old-menu-complete, but in reverse.
remove-history Alt-Ctrl-d While searching history, removes the current line from the history.
shell-expand-line Alt-Ctrl-e A synonym for clink-expand-line.
win-copy-history-number F9 Enter a history number and replace the input line with the history line (mimics Windows console F9).
win-copy-up-to-char F2 Enter a character and copy up to it from the previous command (mimics Windows console F2).
win-copy-up-to-end F3 Copy the rest of the previous command (mimics Windows console F3).
win-cursor-forward F1 Move cursor forward, or at end of line copy character from previous command, or insert suggestion (mimics Windows console F1 and Right).
win-delete-up-to-char F4 Enter a character and delete up to it in the input line (mimics Windows console F4).
win-history-list F7 Executes a history entry from a list (mimics Windows console F7).
win-insert-eof F6 Insert ^Z (mimics Windows console F6).

Completion Colors

The %LS_COLORS% environment variable provides color definitions as a series of color definitions separated by colons (:). Each definition is a either a two character type id or a file extension, followed by an equals sign and then the SGR parameters for an ANSI escape code. The two character type ids are listed below.

When the colored-completion-prefix Readline setting is configured to on, then the "so" color from %LS_COLORS% is used to color the common prefix when displaying possible completions. The default for "so" is magenta, but for example set LS_COLORS=so=90 sets the color to bright black (which shows up as a dark gray).

When colored-stats is configured to on, then the color definitions from %LS_COLORS% are used to color file completions according to their file type or extension. Multiple definitions are separated by colons. Also, since %LS_COLORS% doesn't cover readonly files, hidden files, doskey aliases, or shell commands the color.readonly, color.hidden, color.doskey, and color.cmd Clink settings exist to cover those.

Type Description Default
di Directories. 01;34 (bright blue)
ex Executable files. 01;32 (bright green)
fi Normal files.
ln Symlinks. When ln=target then symlinks are colored according to the target of the symlink. target
mi Missing file or directory.
no Normal color. This is used for anything not covered by one of the other types.
It may be overridden by various other Clink color settings as appropriate depending on the completion type.
or Orphaned symlink (the target of the symlink is missing).
so Common prefix for possible completions. 01;35 (bright magenta)

Here is an example where %LS_COLORS% defines colors for various types.

set LS_COLORS=so=90:fi=97:di=93:ex=92:*.pdf=30;105:*.md=4

Some commands show a searchable popup window that lists the available completions, directory history, or command history.

For example, win-history-list (F7) and clink-popup-directories (Ctrl-Alt-PgUp) show popup windows.

Here's how the popup windows work:

Key Description
Escape Cancels the popup.
Enter Inserts the highlighted completion, changes to the highlighted directory, or executes the highlighted command.
Shift-Enter Inserts the highlighted completion, inserts the highlighted directory, or jumps to the highlighted command history entry without executing it.
Ctrl-Enter Same as Shift-Enter.
Del In a command history popup, Del deletes the selected history entry.

Most of the popup windows also have incremental search:

Key Description
Typing Typing does an incremental search.
F3 Go to the next match.
Ctrl-L Go to the next match.
Shift-F3 Go to the previous match.
Ctrl-Shift-L Go to the previous match.

The win-history-list command has a different search feature. Typing digits 0-9 jumps to the numbered history entry, or typing a letter jumps to the preceding history entry that begins with the typed letter. This is for compatibility with the F7 behavior built into Windows console prompts. Use the clink-popup-history command instead if you prefer for typing to do an incremental search.

Extending Clink With Lua

Clink can be extended with Lua scripts to customize startup actions, create completion matches, customize the prompt, and more. The following sections describe these in more detail and show some examples.

Location of Lua ScriptsLocations from which scripts are loaded.
Match GeneratorsHow to write match generators, or custom completion providers.
Argument CompletionHow to give commands contextual match generators for their arguments.
Coloring the Input TextHow to make a match generator or argument matcher override the input coloring.
Customizing the PromptHow to write custom prompt filters.
Customizing SuggestionsHow to write custom suggestion generators.

Location of Lua Scripts

Clink loads all Lua scripts it finds in these directories:

  1. All directories listed in the clink.path setting, separated by semicolons.
  2. If clink.path is not set, then the DLL directory and the profile directory are used (see File Locations for info about the profile directory).
  3. All directories listed in the %CLINK_PATH% environment variable, separated by semicolons.
  4. All directories registered by the clink installscripts command.

Lua scripts are loaded once and are only reloaded if forced because the scripts locations change, the clink-reload command is invoked (Ctrl-X,Ctrl-R), or the lua.reload_scripts setting changes (or is True).

Run clink info to see the script paths for the current session.

Notes:

  • "completions" is a special reserved directory name: a "completions" directory under any of the Lua script directories listed in clink info has special meaning, and should not contain scripts unless they are specially written to be put in a "completions" directory. See Completion directories for more information.
  • Clink performs tilde expansion on the Lua script directory names. If the path begins with ~\ then it is replaced with the current user's home directory (%HOMEDRIVE%%HOMEPATH% or %USERPROFILE%).

Completion directories

You may optionally put Lua completion scripts in a completions directory. That prevents them from being loaded when Clink starts, and instead they are only loaded when needed. That can make Clink load faster if you have a large quantity of Lua scripts that define argmatchers.

When a command name is typed, if a corresponding argmatcher is not already loaded then the completions directories are searched for a Lua script by the same name. If found, then the Lua script is loaded. This is similar to how completion scripts work in shells like bash, zsh, and fish.

For example, if you type xyz and an argmatcher for xyz is not yet loaded, then if xyz.lua exists in one of the completions directories it will be loaded.

Clink looks for completion scripts in these directories:

  1. Any directories listed in the %CLINK_COMPLETIONS_DIR% environment variable (multiple directories may be separated by semicolons).
  2. A completions subdirectory under each scripts directory listed by clink info (see Location of Lua Scripts).

Note: If you download scripts, then don't put them in a "completions" directory unless they specifically say they can be put there.

If a script defines more than an argmatcher, then putting it in a completions directory may cause its other functionality to not work until a command is typed with the same name as the script. For example, if a script in a completions directory defines an argmatcher and also a prompt filter, the prompt filter won't be loaded until the corresponding command name is typed. Whether that is desirable depends on the script and on your preference.

For example, the scripts from the clink-completions project belong in a normal script directory, because they have other functionality besides just completions, and they won't work correctly in a "completions" directory.

Tips for starting to write Lua scripts

The following sections describe these in more detail and show some examples.

Match Generators

These are Lua functions that are called as part of Readline's completion process (for example when pressing Tab).

The BasicsA quick example to show the basics.
More Advanced Stuff
Filtering Match CompletionsHow to modify how completion happens.
Filtering the Match DisplayHow to modify how possible completions are displayed.

The Basics

First create a match generator object:

local my_generator = clink.generator(priority)

The priority argument is a number that influences when the generator gets called, with lower numbers going before higher numbers.

The :generate() Function

Next define a match generator function on the object, taking the following form:

function my_generator:generate(line_state, match_builder)
    -- Use the line_state object to examine the current line and create matches.
    -- Submit matches to Clink using the match_builder object.
    -- Return true or false.
end

line_state is a line_state object that has information about the current line.

match_builder is a builder object to which matches can be added.

If no further match generators need to be called then the function should return true. Returning false or nil continues letting other match generators get called.

Here is an example script that supplies git branch names as matches for git checkout. This example doesn't handle git aliases, but that could be added with additional script code.

local git_branch_autocomplete = clink.generator(1)

local function starts_with(str, start)
    return string.sub(str, 1, string.len(start)) == start
end

local function is_checkout_ac(text)
    if starts_with(text, "git checkout") then
        return true
    end
    return false
end

local function get_branches()
    -- Run git command to get branches.
    local handle = io.popen("git branch -a 2>&1")
    local result = handle:read("*a")
    handle:close()
    -- Parse the branches from the output.
    local branches = {}
    if starts_with(result, "fatal") == false then
        for branch in string.gmatch(result, "  %S+") do
            branch = string.gsub(branch, "  ", "")
            if branch ~= "HEAD" then
                table.insert(branches, branch)
            end
        end
    end
    return branches
end

function git_branch_autocomplete:generate(line_state, match_builder)
    -- Check if it's a checkout command.
    if not is_checkout_ac(line_state:getline()) then
        return false
    end
    -- Get branches and add them (does nothing if not in a git repo).
    local matchCount = 0
    for _, branch in ipairs(get_branches()) do
        match_builder:addmatch(branch)
        matchCount = matchCount + 1
    end
    -- If we found branches, then stop other match generators.
    return matchCount > 0
end

The :getwordbreakinfo() Function

If needed, a generator can optionally influence word breaking for the end word by defining a :getwordbreakinfo() function.

The function takes a line_state line_state object that has information about the current line. If it returns nil or 0, the end word is truncated to 0 length. This is the normal behavior, which allows Clink to collect and cache all matches and then filter them based on typing. Or it can return two numbers: word break length and an optional end word length. The end word is split at the word break length: one word contains the first word break length characters from the end word (if 0 length then it's discarded), and the next word contains the rest of the end word truncated to the optional word length (0 if omitted).

A good example to look at is Clink's own built-in environment variable match generator. It has a :getwordbreakinfo() function that understands the % syntax of environment variables and produces word break info accordingly.

When the environment variable match generator's :getwordbreakinfo() function sees the end word is abc%USER it returns 3,1 so that the last two words become "abc" and "%" so that its generator knows it can do environment variable matching. But when it sees abc%FOO%def it returns 8,0 so that the last two words become "abc%FOO%" and "" so that its generator won't do environment variable matching, and also so other generators can produce matches for what follows, since "%FOO%" is an already-completed environment variable and therefore should behave like a word break. In other words, it breaks the end word differently depending on whether the number of percent signs is odd or even, to account for environent variable syntax rules.

And when an argmatcher sees the end word begins with a flag character it returns 0,1 so the end word contains only the flag character in order to switch from argument matching to flag matching.

Note: The :getwordbreakinfo() function is called very often, so it needs to be very fast or it can cause responsiveness problems while typing.

local envvar_generator = clink.generator(10)

function envvar_generator:generate(line_state, match_builder)
    -- Does the word end with a percent sign?
    local word = line_state:getendword()
    if word:sub(-1) ~= "%" then
        return false
    end

    -- Add env vars as matches.
    for _, i in ipairs(os.getenvnames()) do
        match_builder:addmatch("%"..i.."%", "word")
    end

    match_builder:setsuppressappend()   -- Don't append a space character.
    match_builder:setsuppressquoting()  -- Don't quote envvars.
    return true
end

function envvar_generator:getwordbreakinfo(line_state)
    local word = line_state:getendword()
    local in_out = false
    local index = nil

    -- Paired percent signs denote already-completed environment variables.
    -- So use envvar completion for abc%foo%def%USER but not for abc%foo%USER.
    for i = 1, #word do
        if word:sub(i, i) == "%" then
            in_out = not in_out
            if in_out then
                index = i - 1
            else
                index = i
            end
        end
    end

    -- If there were any percent signs, return word break info to influence the
    -- match generators.
    if index then
        return index, (in_out and 1) or 0
    end
end

More Advanced Stuff

Filtering Match Completions

A match generator or luafunc: key binding can use clink.onfiltermatches() to register a function that will be called after matches are generated but before they are displayed or inserted.

The function receives a table argument containing the matches to be displayed, a string argument indicating the completion type, and a boolean argument indicating whether filename completion is desired. The table argument has a match string field and a type string field; these are the same as in builder:addmatch().

The possible completion types are:

Type Description Example
"?" List the possible completions. possible-completions or popup-complete
"*" Insert all of the possible completions. insert-completions
"\t" Do standard completion. complete
"!" Do standard completion, and list all possible completions if there is more than one. complete (when the show-all-if-ambiguous config variable is set)
"@" Do standard completion, and list all possible completions if there is more than one and partial completion is not possible. complete (when the show-all-if-unmodified config variable is set)
"%" Do menu completion (cycle through possible completions). menu-complete or old-menu-complete

The return value is a table with the input matches filtered as desired. The match filter function can remove matches, but cannot add matches (use a match generator instead). If only one match remains after filtering, then many commands will insert the match without displaying it. This makes it possible to spawn a process (such as fzf) to perform enhanced completion by interactively filtering the matches and keeping only one selected match.

settings.add("fzf.height", "40%", "Height to use for the --height flag")
settings.add("fzf.exe_location", "", "Location of fzf.exe if not on the PATH")

-- Build a command line to launch fzf.
local function get_fzf()
    local height = settings.get("fzf.height")
    local command = settings.get("fzf.exe_location")
    if not command or command == "" then
        command = "fzf.exe"
    else
        command = os.getshortname(command)
    end
    if height and height ~= "" then
        command = command..' --height '..height
    end
    return command
end

local fzf_complete_intercept = false

-- Sample key binding in .inputrc:
--      M-C-x: "luafunc:fzf_complete"
function fzf_complete(rl_buffer)
    fzf_complete_intercept = true
    rl.invokecommand("complete")
    if fzf_complete_intercept then
        rl_buffer:ding()
    end
    fzf_complete_intercept = false
    rl_buffer:refreshline()
end

local function filter_matches(matches, completion_type, filename_completion_desired)
    if not fzf_complete_intercept then
        return
    end
    -- Start fzf.
    local r,w = io.popenrw(get_fzf()..' --layout=reverse-list')
    if not r or not w then
        return
    end
    -- Write matches to the write pipe.
    for _,m in ipairs(matches) do
        w:write(m.match.."\n")
    end
    w:close()
    -- Read filtered matches.
    local ret = {}
    while (true) do
        local line = r:read('*line')
        if not line then
            break
        end
        for _,m in ipairs(matches) do
            if m.match == line then
                table.insert(ret, m)
            end
        end
    end
    r:close()
    -- Yay, successful; clear it to not ding.
    fzf_complete_intercept = false
    return ret
end

local interceptor = clink.generator(0)
function interceptor:generate(line_state, match_builder)
    -- Only intercept when the specific command was used.
    if fzf_complete_intercept then
        clink.onfiltermatches(filter_matches)
    end
    return false
end

Filtering the Match Display

In some instances it may be preferable to display different text when listing potential matches versus when inserting a match in the input line, or to display a description next to a match. For example, it might be desirable to display a * next to some matches, or to show additional information about some matches.

The simplest way to do that is just include the display and/or description fields when using builder:addmatch(). Refer to that function's documentation for usage details.

However, older versions of Clink don't support those fields. And in some cases it may be desirable to display a list of possible completions that includes extra matches, or omits some matches (but that's discouraged because it can be confusing to users).

A match generator can alternatively use clink.ondisplaymatches() to register a function that will be called before matches are displayed (this is reset every time match generation is invoked).

The function receives a table argument containing the matches to be displayed, and a boolean argument indicating whether they'll be displayed in a popup window. The table argument has a match string field and a type string field; these are the same as in builder:addmatch(). The return value is a table with the input matches filtered as required by the match generator.

The returned table can also optionally include a display string field and a description string field. When present, display will be displayed instead of the match field, and description will be displayed next to the match. Putting the description in a separate field enables Clink to align the descriptions in a column.

Filtering the match display can affect completing matches: the match field is what gets inserted. It can also affect displaying matches: the display field is displayed if present, otherwise the match field is displayed.

If a match's type is "none" or its match field is different from its display field then the match is displayed using the color specified by the color.filtered Clink setting, otherwise normal completion coloring is applied. The display and description fields can include ANSI escape codes to apply other colors if desired.

local function my_filter(matches, popup)
    local new_matches = {}
    local magenta = "\x1b[35m"
    local filtered = settings.get("color.filtered")
    for _,m in ipairs(matches) do
        if m.match:find("[0-9]") then
            -- Ignore matches with one or more digits.
        else
            -- Keep the match, and also add a magenta * prefix to directory matches.
            if m.type:find("^dir") then
                m.display = magenta.."*"..filtered..m.match
            end
            table.insert(new_matches, m)
        end
    end
    return new_matches
end

function my_match_generator:generate(line_state, match_builder)
    ...
    clink.ondisplaymatches(my_filter)
end

Note: In v1.3.1 and higher, the table received by the registered ondisplaymatches function includes all the match fields (such as display, description, appendchar, etc), and the returned table can also include any of these fields. In other words, in v1.3.1 and higher match filtering supports all the same fields as builder:addmatch().

Argument Completion

Clink provides a framework for writing complex argument match generators in Lua. It works by creating a parser object that describes a command's arguments and flags and associating the parser with one or more commands. When Clink detects a parser is associated with the command being edited, it uses the parser to generate matches.

The BasicsA quick example to show the basics.
Automatic Filename CompletionBy default, filename completion is used.
Descriptions for Flags and ArgumentsHow to add descriptive text.
More Advanced Stuff
Linking ParsersHow to link a parser to a word or flag.
Functions As Argument OptionsUsing a function to provide completions.
Generate Matches From HistoryProviding completions from the history.
Disable Sorting MatchesHow to disable auto-sorted completions.
Fully Qualified PathnamesHow to make different argmatchers for programs with the same name.
Delimited ArgumentsHow to allow multiple completions in the same argument slot (e.g. file1;file2;file3).
Adaptive ArgmatchersHow an argmatcher can define or modify itself on the fly.
Responding to Arguments in ArgmatchersWhen argument slots need to influence one another.
ShorthandAlternative syntax for defining argmatchers.

The Basics

Here is an example of a simple parser for the command foobar;

clink.argmatcher("foobar")
:addarg({ "hello", "hi" })               -- Completions for arg #1.
:addarg({ "world", "wombles", "xyzzy" }) -- Completions for arg #2.
:addflags("-foo", "-bar")                -- Flags.

This parser describes a command that has two arguments, and some flags.

Arguments are positional. Each :addarg() adds a new argument position and defines the possible completions for that argument position.

Flags are position independent. Any :addflags() add to the set of possible flag completions. Any word that begins with the flag prefix character (in this example -) is considered to be a flag, even if it is not listed as a possible completion. The flags may be input at any position; before arguments, between arguments, and after arguments.

On the command line completion would look something like this, if Alt-= were pressed at the end of each input line below:

C:\>foobar -
-bar  -foo
C:\>foobar -bar hello
wombles  world  xyzzy
C:\>foobar -bar hello wo
wombles  world
C:\>foobar -bar hello wombles -
-bar -foo
C:\>foobar -bar hello wombles -foo _

When displaying possible completions, flag matches are only shown if the flag character has been input. So foobar and Alt-= would list matches for the first argument position, or foobar some_word and Alt-= would list matches for the second argument position, or foobar - and Alt-= would list only flag matches.

If a command doesn't have an argmatcher but is a doskey macro, Clink automatically expands the doskey macro and looks for an argmatcher for the expanded command. A macro like gco=git checkout $* automatically reuses a git argmatcher and produces completions for its checkout argument. However, it only expands the doskey macro up to the first $, so complex aliases like foo=app 2$gnul text $* or foo=$2 $1 might behave strangely.

Also see clink.argmatcher(), :addflags() and :addarg().

Automatic Filename Completion

A fresh, empty argmatcher provides no completions.

clink.argmatcher("foobar")               -- The "foobar" command provides no completions.

Once any flags or argument positions have been added to an argmatcher, then the argmatcher will provide completions.

clink.argmatcher("foobar")
:addarg({ "hello", "hi" })               -- Completions for arg #1.
:addarg({ "world", "wombles", "xyzzy" }) -- Completions for arg #2.
:addflags("-foo", "-bar")                -- Flags.

When completing a word that doesn't have a corresponding argument position the argmatcher will automatically use filename completion. For example, the foobar argmatcher has two argument positions, and completing a third word uses filename completion.

C:\>foobar hello world pro
Program Files\  Program Files(x86)\  ProgramData\
C:\>foobar hello world pro_

Use _argmatcher:nofiles() if you want to disable the automatic filename completion and "dead end" an argmatcher for extra words. This stops all further parsing for the command.

clink.argmatcher("foobar")
:addarg({ "hello", "hi" })               -- Completions for arg #1
:addarg({ "world", "wombles", "xyzzy" }) -- Completions for arg #2
:addflags("-foo", "-bar")                -- Flags
:nofiles()                               -- Using :nofiles() prevents further completions.

Descriptions for Flags and Arguments

Flags and arguments may optionally have descriptions associated with them. The descriptions, if any, are displayed when listing possible completions.

Use _argmatcher:adddescriptions() to add descriptions for flags and/or arguments. Refer to its documentation for further details about how to use it, including how to also show arguments that a flag accepts.

For example, with the following matcher, typing foo -Alt-= will list all of the flags, plus descriptions for each.

clink.argmatcher("foo")
:addflags("-?", "-h", "-n", "-v", "--help", "--nothing", "--verbose")
:addarg("print", "delete")
:addarg(clink.filematches)
:nofiles()
:adddescriptions(
    { "-n", "--nothing",    description = "Do nothing; show what would happen without doing it" },
    { "-v", "--verbose",    description = "Verbose output" },
    { "-h", "--help", "-?", description = "Show help text" },
    { "print",              description = "Print the specified file" },
    { "delete",             description = "Delete the specified file" },
)

More Advanced Stuff

Linking Parsers

There are often situations where the parsing of a command's arguments is dependent on the previous words (git merge ... compared to git log ... for example). For these scenarios Clink allows you to link parsers to arguments' words using Lua's concatenation operator.

local a_parser = clink.argmatcher():addarg({ "foo", "bar" })
local b_parser = clink.argmatcher():addarg({ "abc", "123" })
local c_parser = clink.argmatcher()
c_parser:addarg({ "foobar" .. a_parser })   -- Arg #1 is "foobar", which has args "foo" or "bar".
c_parser:addarg({ b_parser })               -- Arg #2 is "abc" or "123".

As the example above shows, it is also possible to use a parser without concatenating it to a word.

When Clink follows a link to a parser it will only return to the previous parser when the linked parser runs out of arguments. Using :nofiles() prevents returning to the previous parser.

Flags With Arguments

Parsers can be concatenated with flags, too.

Here's an example of a flag that takes an argument:

clink.argmatcher("git")
:addarg({
    "merge"..clink.argmatcher():addflags({
        "--strategy"..clink.argmatcher():addarg({
            "resolve",
            "recursive",
            "ours",
            "octopus",
            "subtree",
        })
    })
})

A : or = at the end of a flag indicates the flag takes an argument but requires no space between the flag and its argument. If such a flag is not linked to a parser, then it automatically gets linked to a parser to match files. Here's an example with a few flags that take arguments without a space in between:

clink.argmatcher("findstr")
:addflags({
    "/b", "/e", "/l", "/r", "/s", "/i", "/x", "/v", "/n", "/m", "/o", "/p", "/offline",
    "/a:"..clink.argmatcher():addarg( "attr" ),
    "/f:"..clink.argmatcher():addarg( clink.filematches ),
    "/c:"..clink.argmatcher():addarg( "search_string" ),
    "/g:", -- This is the same as linking with clink.argmatcher():addarg(clink.filematches).
    "/d:"..clink.argmatcher():addarg( clink.dirmatches )
})

Functions As Argument Options

Argument options are not limited solely to strings. Clink also accepts functions too so more context aware argument options can be used.

The function is called each time matches are generated for the argument position.

local function rainbow_function(word)
    return { "red", "white", "blue" }
end

local the_parser = clink.argmatcher()
the_parser:addarg({ "zippy", "bungle", "george" })
the_parser:addarg({ rainbow_function, "yellow", "green" })

The functions are passed five arguments, and should return a table of potential matches (strings). The table may optionally also contain tables that describe the matches; the format is the same as in builder:addmatches().

Compatibility Note: When a function argument uses the old v0.4.9 clink.match_display_filter approach, then the word argument will be the full word under the cursor, for compatibility with the v0.4.9 API.

Some built-in matcher functions are available:

Function Description
clink.dirmatches Generates directory matches.
clink.filematches Generates file matches.

Generate Matches From History

An argument position can collect matches from the history file. When an argument table contains fromhistory=true then additional matches are generated by parsing the history file to find values for that argument slot from commands in the history file.

This example generates matches for arguments to a --host flag by parsing the history file for host names used in the past, and also includes the current computer name.

local host_parser = clink.argmatcher():addarg({ fromhistory=true, os.getenv("COMPUTERNAME") })
clink.argmatcher("program"):addflags({ "--host"..host_parser })

Disable Sorting Matches

Match completions are normally listed in sorted order. In some cases it may be desirable to disable sorting and list match completions in a specific order. To disable sorting, include nosort=true in the argument table. When sorting is disabled, matches are listed in the order they were added.

local the_parser = clink.argmatcher()
the_parser:addarg({ nosort=true, "red", "orange", "yellow", "green", "blue", "indigo", "violet" })

Fully Qualified Pathnames

Sometimes there may be more than one program installed with the same name. For example, there might be multiple versions of grep installed.

In Clink v1.3.38 and higher, you can define argmatchers using fully qualified pathnames. For example, this makes it possible to define one argmatcher for c:\EmployerTools\grep.exe and another for d:\PersonalTools\grep.exe, and the corresponding argmatcher will be used when appropriate.

In the example above, you could define an argmatcher for c:\EmployerTools\grep.exe, and also define an argmatcher for grep (or have a grep.lua file in a completions directory). The plain grep one would be used whenever the typed grep doesn't resolve to the EmployerTools copy.

Delimited Arguments

In some cases an argument for programs may accept a list of values separated by ; or + or etc. Normally ; or + are argument separators (like space), and advance the argmatcher to the next argument slot.

In Clink v1.3.37 and higher, you can make them stay on the current argument slot by including loopchars=";" (or set loopchars= a list of value delimiters).

-- This argmatcher accepts syntax like "foo color filename".
-- Typing "foo red f" and pressing TAB generates completions for files.
-- Typing "foo red;" and pressing TAB generates completions for files.
clink.argmatcher("foo")
:addarg({"red", "green", "blue"})
:addarg(clink.filematches)

-- This argmatcher accepts syntax like "foo color[;color...] filename".
-- Typing "foo red f" and pressing TAB generates completions for files.
-- Typing "foo red;" and pressing TAB generates completions for colors (not files).
clink.argmatcher("foo")
:addarg({loopchars=";", "red", "green", "blue"})
:addarg(clink.filematches)

Adaptive Argmatchers

Some argmatchers may need to adapt on the fly. For example, a program may have different features available depending on the current directory, or may want to define its arguments and flags by parsing the --help text from running a program.

An argmatcher can define a "delayed initialization" callback function that gets calls when the argmatcher gets used, allowing it to defer potentially expensive initialization work until it's actually needed. An argmatcher can also define a separate "delayed initialization" function for each argument position.

Delayed initialization for the argmatcher

You can use _argmatcher:setdelayinit() to set a function that performs delayed initialization for the argmatcher. The function receives one parameter:

If the definition needs to adapt based on the current directory or other criteria, then the callback function should first test whether the definition needs to change. If so, first reset the argmatcher and then initialize it. To reset the argmatcher, use _argmatcher:reset() which resets it back to an empty, freshly created state.

local prev_dir = ""

-- Initialize the argmatcher.
-- v1.3.12 and higher receive a command_word parameter as well, which is the
-- word in the command line that matched this argmatcher.
local function init(argmatcher, command_word)
    local r = io.popen("some_command --help 2>nul")
    for line in r:lines() do
        -- PUT PARSING CODE HERE.
        -- Use the Lua string functions to parse the lines.
        -- Use argmatcher:addflags(), argmatcher:addarg(), etc to initialize the argmatcher.
    end
    r:close()
end

-- This function has the opportunity to reset and (re)initialize the argmatcher.
local function ondelayinit(argmatcher)
    local dir = os.getcwd()
    if prev_dir ~= dir then  -- When current directory has changed,
        prev_dir = dir      -- Remember the new current directory,
        argmatcher:reset()  -- Reset the argmatcher,
        init(argmatcher)    -- And re-initialize it.
    end
end

-- Create the argmatcher and set up delayed initialization.
local m = clink.argmatcher("some_command")
if m.setdelayinit then        -- Can't use setdelayinit before Clink v1.3.10.
    m:setdelayinit(ondelayinit)
end

Delayed initialization for an argument position

If the overall flags and meaning of the argument positions don't need to be updated, and only the possible values need to be updated within certain argument positions, then you can include delayinit=function in the argument table.

The function should return a table of matches which will be added to the values for the argument position. The table of matches supports the same syntax as _argmatcher:addarg(). The function receives two parameters:

The function is called only once, the first time the argument position is used. The only way for the function to be called again for that argmatcher is to use Delayed initialization for the argmatcher and reset the argmatcher and then re-initialize it.

Delayed initialization for an argument position is different from Functions As Argument Options. The delayinit function is called the first time the argmatcher is used, and the results are added to the matches for the rest of the Clink session. But a function as an argument option is called every time matches are generated for the argument position, and it is never called when applying input line coloring.

-- A function to delay-initialize argument values.
-- This function is used to delay-initialize two different argument positions,
-- and so it gets called up to two separate times (once for each position where
-- it is specified).
-- If the function needs to behave slightly differently for different
-- argmatchers or argument positions, it can use the two parameters it receives
-- to identify the specific context in which it is being called.
local function sc_init_dirs(argmatcher, argindex)
    return {
        path.join(os.getenv("USERPROFILE"), "Documents"),
        path.join(os.getenv("USERPROFILE"), "Pictures")
    }
end

-- A function to delay-initialize flag values.
local function sc_init_flags(argmatcher)
    -- This calls sc_init_dirs() when the '--dir=' flag is used.
    return { "--dir=" .. clink.argmatcher():addarg({ delayinit=sc_init_dirs }) }
end

-- Define an argmatcher with two argument positions, and the second one uses
-- delayed initialization.
local m = clink.argmatcher("some_command")
m:addarg({ "abc", "def", "ghi" })
m:addarg({ delayinit=sc_init_dirs }) -- This sc_init_dirs() when the second arg position is used.

-- You can also use delayinit with flags, but you must set the flag prefix
-- character(s) so that Clink can know when to call the delayinit function.
m:addflags({ delayinit=sc_init_flags })
m:setflagprefix("-")

Responding to Arguments in Argmatchers

Argmatchers can be more involved in parsing the command line, if they wish.

An argmatcher can supply an "on arg" function to be called when the argmatcher parses an argument position. The function can influence parsing the rest of the input line. For example, the presence of a flag --only-dirs might change what match completions should be provided somewhere else in the input line.

Supply an "on arg" function by including onarg=function in the argument table with _argmatcher:addarg(). The function is passed five arguments, and it doesn't return anything (the function receives the same arguments as Functions As Argument Options).

When parsing begins, the user_data is an empty table. Each time a flag or argument links to another argmatcher, the new argmatcher gets a separate new empty user_data table. Your "on arg" functions can set data from the table, and then can also get data that was set earlier by your "on arg" functions.

An "on arg" function can also use os.chdir() to set the current directory. Generating match completions saves and restores the current directory when finished, so argmatcher "on arg" functions can set the current directory and thus cause match completion later in the input line to complete file names relative to the change directory. For example, the built-in cd and pushd argmatches use an "on arg" function so that pushd \other_dir & program Tab can complete file names from \other_dir instead of the (real) current directory.

local function onarg_pushd(arg_index, word, word_index, line_state, user_data)
    -- Match generation after this is relative to the new directory.
    if word ~= "" then
        os.chdir(word)
    end
end

clink.argmatcher("pushd")
:addarg({
    onarg=onarg_pushd,  -- Chdir to the directory argument.
    clink.dirmatches,   -- Generate directory matches.
})
:nofiles()

Shorthand

It is also possible to omit the addarg and addflags function calls and use a more declarative shorthand form:

-- Shorthand form; requires tables.
clink.argmatcher()
    { "one", "won" }                -- Arg #1
    { "two", "too" }                -- Arg #2
    { "-a", "-b", "/?", "/h" }      -- Flags

-- Normal form:
clink.argmatcher()
:addarg({ "one", "won" })           -- Arg #1
:addarg({ "two", "too" })           -- Arg #2
:addflags("-a", "-b", "/?", "/h")   -- Flags

With the shorthand form flags are implied rather than declared. When a shorthand table's first value is a string starting with - or / then the table is interpreted as flags. Note that it's still possible with shorthand form to mix flag prefixes, and even add additional flag prefixes, such as { '-a', '/b', '=c' }.

Coloring the Input Text

When the clink.colorize_input setting is disabled, then the entire input line is colored by the color.input setting. When the setting is enabled, then argmatchers automatically apply colors to the input text as they parse it.

Coloring the Command WordHow the command word is colored.
Coloring Command Separators and RedirectionHow special characters are colored.
Coloring Other Input TextHow other text is colored.
More Advanced Stuff
Setting a classifier function in an argmatcherHow to apply colors for arguments.
Setting a classifier function for the whole input lineHow to apply colors anywhere in the line.

Coloring the Command Word

The command word is colored based on the command type, in priority order:

  1. Commands that have an argmatcher defined use color.argmatcher.
  2. Built-in CMD commands use color.cmd.
  3. Doskey aliases use color.doskey.
  4. Recognized executable files use color.executable if it is set.
  5. Unrecognized command words use color.unrecognized if it is set.
  6. If none of the above apply, then color.input is used.

Here are examples, using the colors from the Use enhanced defaults installation option:

c:\dir>clink'clink' has an argmatcher
c:\dir>attrib'attrib' is a CMD command
c:\dir>myaliasif 'myalias' is a doskey alias
c:\dir>control'control' is an executable
c:\dir>xyzabc123unrecognized
c:\dir>whateverif executable and unrecognized colors are not set

Coloring Command Separators and Redirection

Command separators and redirection are colored accordingly:

Here are examples, using the colors from the Use enhanced defaults installation option:

c:\dir>pushd & popd'&' is the command separator
c:\dir>set >fileredirecting 'set' to 'file'

Coloring Other Input Text

Other input words are colored based on how argmatchers parse the input text.

Here are examples, using the colors from the Use enhanced defaults installation option:

c:\dir>clink --help'--help' is defined as a flag for 'clink'
c:\dir>clink set'set' is defined as an argument for 'clink'
c:\dir>clink set color.arg'color.arg' is defined as an argument for 'clink set'
c:\dir>clink set abc.xyz'abc.xyz' is not a recognized argument for 'clink set'
c:\dir>findstr /s needle haystack\*if 'findstr' has no argmatcher, all words use 'color.input'

More Advanced Stuff

Setting a classifier function in an argmatcher

In cases where an argmatcher isn't able to color the input text in the desired manner, it's possible to supply a classifier function that overrides how the argmatcher colors the input text. An argmatcher's classifier function is called once for each word the argmatcher parses, but it can classify any words (not just the word it was called for). Each argmatcher can have its own classifier function, so when there are linked argmatchers more than one function may be invoked.

Words are colored by classifying the words, and each classification has an associated color. See word_classifications:classifyword() for the available classification codes.

The clink set command has different syntax depending on the setting type, so the argmatcher for clink needs help in order to get everything right. A custom generator function parses the input text to provide appropriate matches, and a custom classifier function applies appropriate coloring.

-- In this example, the argmatcher matches a directory as the first argument and
-- a file as the second argument.  It uses a word classifier function to classify
-- directories (words that end with a path separator) as "unexpected" in the
-- second argument position.

local function classify_handler(arg_index, word, word_index, line_state, classifications)
    -- `arg_index` is the argument position in the argmatcher.
    -- In this example only position 2 needs special treatent.
    if arg_index ~= 2 then
        return
    end

    -- `arg_index` is the argument position in the argmatcher.
    -- `word_index` is the word position in the `line_state`.
    -- Ex1: in `samp dir file` for the word `dir` the argument index is 1 and
    -- the word index is 2.
    -- Ex2: in `samp --help dir file` for the word `dir` the argument index is
    -- still 1, but the word index is 3.

    -- `word` is the word the classifier function was called for and `word_index`
    -- is its position in the line.  Because `line_state` is also provided, the
    -- function can examine any words in the input line.
    if word:sub(-1) == "\\" then
        -- The word appears to be a directory, but this example expects only
        -- files in argument position 2.  Here the word gets classified as "n"
        -- (unexpected) so it gets colored differently.
        classifications:classifyword(word_index, "n")
    end
end

local matcher = clink.argmatcher("samp")
:addflags("--help")
:addarg({ clink.dirmatches })
:addarg({ clink.filematches })
:setclassifier(classify_handler)

Setting a classifier function for the whole input line

In some cases it may be desireable to use a custom classifier to apply coloring in an input line.

First create a classifier object:

local my_classifier = clink.classifier(priority)

The priority argument is a number that influences when the classifier gets called, with lower numbers going before higher numbers.

Next define a classify function on the object, taking the following form:

function my_classifier:classify(commands)
    -- See further below for how to use the commands argument.
    -- Returning true stops any further classifiers from being called, or
    -- returning false or nil continues letting other classifiers get called.
end

commands is a table of tables, with the following scheme:

-- commands[n].line_state           [line_state] Contains the words for the Nth command.
-- commands[n].classifications      [word_classifications] Use this to classify the words.

The line_state field is a line_state object that contains the words for the associated command line.

The classifications field is a word_classifications object to use for classifying the words in the associated command line.

-- In this example, a custom classifier applies colors to environment variables
-- in the input line.
local envvar_classifier = clink.classifier(50)
function envvar_classifier:classify(commands)
    -- This example doesn't need to parse words within commands, it just wants
    -- to parse the whole line.
    --
    -- So it can simply use the first command's `classifications` object because
    -- the `classifications:applycolor()` method can apply color anywhere in the
    -- entire input line.
    --
    -- (Note that the `classifications:classifyword()` method can only affect
    -- the words for its corresponding command.)
    if commands[1] then
        local line_state = commands[1].line_state
        local classifications = commands[1].classifications
        local line = line_state:getline()
        local len = #line

        -- Loop through the line looking for environment variables, starting at
        -- the first character of the line.
        local idx = 1
        while (idx <= len) do
            -- Find the next percent sign (idx is walking through the line).
            local pos = line:find('%', idx, true--[[plain]])
            if not pos then
                -- No more?  Then all done.
                break
            end

            -- Find the next percent sign (which would close the possible
            -- environment variable).
            local posend = line:find('%', pos + 1, true--[[plain]])
            if not posend then
                -- No close?  Then all done.
                break
            end

            -- Extract the text between the percent signs and check if there
            -- is an environment variable by that name.
            local name = line:sub(pos + 1, posend - 1)
            if name == '' then
                -- Skip a double percent.  It's an escaped percent sign, not an
                -- environment variable.
                idx = posend + 1
            elseif os.getenv(name) then
                -- Apply a color to the environment variable.
                classifications:applycolor(pos, posend - pos + 1, "95")
                idx = posend + 1
            else
                -- Ignore the percent sign, but continue looking for more.
                idx = idx + 1
            end
        end
    end
end

Customizing the Prompt

Before Clink displays the prompt it filters the prompt through Lua so that the prompt can be customized. This happens each and every time that the prompt is shown which allows for context sensitive customizations (such as showing the current branch of a git repository).

The BasicsA quick example to show the basics.
ANSI escape codes in the prompt stringHow special characters are colored.
More Advanced Stuff
Right Side PromptHow to add prompt text at the right edge of the terminal.
Asynchronous Prompt FilteringHow to make the prompt show up instantly.
Transient PromptHow to display completed prompts differently than the current prompt.

The Basics

Writing a prompt filter is straightforward:

  1. Create a new prompt filter by calling clink.promptfilter() along with a priority id which dictates the order in which filters are called. Lower priority ids are called first.
  2. Define a :filter() function on the returned prompt filter.

The filter function takes a string argument that contains the filtered prompt so far. If the filter function returns nil, it has no effect. If the filter function returns a string, that string is used as the new filtered prompt (and may be further modified by other prompt filters with higher priority ids). If the filter function returns a string and a boolean, then if the boolean is false the prompt filtering is done and no further filter functions are called.

local p = clink.promptfilter(30)
function p:filter(prompt)
    return "new prefix "..prompt.." new suffix" -- Add ,false to stop filtering.
end

The following example illustrates setting the prompt, modifying the prompt, using ANSI escape code for colors, running a git command to find the current branch, and stopping any further processing.

local green  = "\x1b[92m"
local yellow = "\x1b[93m"
local cyan   = "\x1b[36m"
local normal = "\x1b[m"

-- A prompt filter that discards any prompt so far and sets the
-- prompt to the current working directory.  An ANSI escape code
-- colors it yellow.
local cwd_prompt = clink.promptfilter(30)
function cwd_prompt:filter(prompt)
    return yellow..os.getcwd()..normal
end

-- A prompt filter that inserts the date at the beginning of the
-- the prompt.  An ANSI escape code colors the date green.
local date_prompt = clink.promptfilter(40)
function date_prompt:filter(prompt)
    return green..os.date("%a %H:%M")..normal.." "..prompt
end

-- A prompt filter that may stop further prompt filtering.
-- This is a silly example, but on Wednesdays, it stops the
-- filtering, which in this example prevents git branch
-- detection and the line feed and angle bracket.
local wednesday_silliness = clink.promptfilter(60)
function wednesday_silliness:filter(prompt)
    if os.date("%a") == "Wed" then
        -- The ,false stops any further filtering.
        return prompt.." HAPPY HUMP DAY! ", false
    end
end

-- A prompt filter that appends the current git branch.
local git_branch_prompt = clink.promptfilter(65)
function git_branch_prompt:filter(prompt)
    local line = io.popen("git branch --show-current 2>nul"):read("*a")
    local branch = line:match("(.+)\n")
    if branch then
        return prompt.." "..cyan.."["..branch.."]"..normal
    end
end

-- A prompt filter that adds a line feed and angle bracket.
local bracket_prompt = clink.promptfilter(150)
function bracket_prompt:filter(prompt)
    return prompt.."\n> "
end

The resulting prompt will look like this:

Wed 12:54 c:\dir [master]
> _

...except on Wednesdays, when it will look like this:

Wed 12:54 c:\dir HAPPY HUMP DAY! _

ANSI escape codes in the prompt string

Readline needs to be told which characters in the prompt are unprintable or invisible. To help with that, Clink automatically detects most standard ANSI escape codes (and most of ConEmu's non-standard escape codes) and the BEL character (^G, audible bell) and surrounds them with \001 (^A) and \002 (^B) characters. For any other unprintable characters, the \001 and \002 characters need to be added manually. Otherwise Readline misinterprets the length of the prompt and can display the prompt and input line incorrectly in some cases (especially if the input line wraps onto a second line).

Here are a couple of links with more information about ANSI escape codes:

More Advanced Stuff

Right Side Prompt

In addition to the normal prompt filtering, Clink can also show a prompt on the right side of the first line of input. The right side prompt defaults to the value of the %CLINK_RPROMPT% environment variable, if set, otherwise it is blank. This right side prompt is automatically hidden if the input line text reaches it.

Clink expands CMD prompt $ codes in %CLINK_RPROMPT%, with a few exceptions: $+ is not supported, $_ ends the prompt string (it can't be more than one line), and $V is not supported. Additionally, if %CLINK_RPROMPT% ends with $M then trailing spaces are trimmed from the expanded string, to maintain right alignment since $M includes a space if the current drive is a network drive (so e.g. $t $d $m is right-aligned regardless whether the current drive has a remote name).

The right side prompt can be filtered through Lua just like the normal prompt can be. Simply define a :rightfilter() function on the prompt filter returned by a call to clink.promptfilter(). A prompt filter can define both :filter() and :rightfilter(), or can define only :filter().

The :rightfilter() function works the same as the :filter() function, except that it operates on the right side prompt. It takes a string argument that contains the filtered right side prompt so far. If the rightfilter function returns nil, it has no effect. If the rightfilter function returns a string, that string is used as the new filtered right side prompt (and may be further modified by other prompt filters with higher priority ids). If either the rightfilter function or the normal filter function returns a string and a boolean, then if the boolean is false the prompt filtering is done and no further filter functions are called.

This example modifies the right side prompt by prepending the current date:

local p = clink.promptfilter(30)
function p:filter(prompt)
    -- The :filter() function must be defined.  But if the prompt filter is
    -- only interested in modifying the right side prompt, then the :filter()
    -- function may do nothing.
end
function p:rightfilter(prompt)
    local sep = #prompt > 0 and "  " or ""
    return os.date()..sep..prompt
end

Notes:

  • If the console font and encoding are mismatched, or if some kinds of emoji are present, then the right side prompt might show up positioned incorrectly. If that happens, try adjusting the font or encoding (e.g. sometimes running chcp utf-8 can resolve positioning issues).
  • If the :filter() function returns a string and false to stop filtering, then the :rightfilter() is not called (because no further filter functions are called). If you want to stop filtering but have both a left and right side prompt, then return only a string from :filter() and return a string and false from :rightfilter().

Asynchronous Prompt Filtering

Prompt filtering needs to be fast, or it can interfere with using the shell (e.g. git status can be slow in a large repo).

Clink provides a way for prompt filters to do some initial work and set the prompt, continue doing work in the background, and then refresh the prompt again when the background work is finished. This is accomplished by using Lua coroutines, but Clink simplifies and streamlines the process.

A prompt filter can call clink.promptcoroutine(my_func) to run my_func() inside a coroutine. Clink will automatically resume the coroutine repeatedly while input line editing is idle. When my_func() completes, Clink will automatically refresh the prompt by triggering prompt filtering again.

Typically the motivation to use asynchronous prompt filtering is that one or more io.popen("some slow command") calls take too long. They can be replaced with io.popenyield() calls inside the prompt coroutine to let them run in the background.

Global data: If my_func() needs to use any global data, then it's important to use clink.onbeginedit() to register an event handler that can reset the global data for each new input line session. Otherwise the data may accidentally "bleed" across different input line sessions.

Backward compatibility: A prompt filter must handle backward compatibility itself if it needs to run on versions of Clink that don't support asynchronous prompt filtering (v1.2.9 and lower). E.g. you can use if clink.promptcoroutine then to test whether the API exists.

The following example illustrates running git status in the background. It also remembers the status from the previous input line, so that it can reduce flicker by using the color from last time until the background status operation completes.

local prev_dir      -- Most recent git repo visited.
local prev_info     -- Most recent info retrieved by the coroutine.

local function get_git_dir(dir)
    -- Check if the current directory is in a git repo.
    local child
    repeat
        if os.isdir(path.join(dir, ".git")) then
            return dir
        end
        -- Walk up one level to the parent directory.
        dir,child = path.toparent(dir)
        -- If child is empty, we've reached the top.
    until (not child or child == "")
    return nil
end

local function get_git_branch()
    -- Get the current git branch name.
    local file = io.popen("git branch --show-current 2>nul")
    local branch = file:read("*a"):match("(.+)\n")
    file:close()
    return branch
end

local function get_git_status()
    -- The io.popenyield API is like io.popen, but it yields until the output is
    -- ready to be read.
    local file = io.popenyield("git --no-optional-locks status --porcelain 2>nul")
    local status = false
    for line in file:lines() do
        -- If there's any output, the status is not clean.  Since this example
        -- doesn't analyze the details, it can stop once it knows there's any
        -- output at all.
        status = true
        break
    end
    file:close()
    return status
end

local function get_git_conflict()
    -- The io.popenyield API is like io.popen, but it yields until the output is
    -- ready to be read.
    local file = io.popenyield("git diff --name-only --diff-filter=U 2>nul")
    local conflict = false
    for line in file:lines() do
        -- If there's any output, there's a conflict.
        conflict = true
        break
    end
    file:close()
    return conflict
end

local function collect_git_info()
    -- This is run inside the coroutine, which happens while idle while waiting
    -- for keyboard input.
    local info = {}
    info.status = get_git_status()
    info.conflict = get_git_conflict()
    -- Until this returns, the call to clink.promptcoroutine() will keep
    -- returning nil.  After this returns, subsequent calls to
    -- clink.promptcoroutine() will keep returning this return value, until a
    -- new input line begins.
    return info
end

local git_prompt = clink.promptfilter(55)
function git_prompt:filter(prompt)
    -- Do nothing if not a git repo.
    local dir = get_git_dir(os.getcwd())
    if not dir then
        return
    end
    -- Reset the cached status if in a different repo.
    if prev_dir ~= dir then
        prev_info = nil
        prev_dir = dir
    end
    -- Do nothing if git branch not available.  Getting the branch name is fast,
    -- so it can run outside the coroutine.  That way the branch name is visible
    -- even while the coroutine is running.
    local branch = get_git_branch()
    if not branch or branch == "" then
        return
    end
    -- Start a coroutine to collect various git info in the background.  The
    -- clink.promptcoroutine() call returns nil immediately, and the
    -- coroutine runs in the background.  After the coroutine finishes, prompt
    -- filtering is triggered again, and subsequent clink.promptcoroutine()
    -- calls from this prompt filter immediately return whatever the
    -- collect_git_info() function returned when it completed.  When a new input
    -- line begins, the coroutine results are reset to nil to allow new results.
    local info = clink.promptcoroutine(collect_git_info)
    -- If no status yet, use the status from the previous prompt.
    if info == nil then
        info = prev_info or {}
    else
        prev_info = info
    end
    -- Choose color for the git branch name:  green if status is clean, yellow
    -- if status is not clean, red if conflict is present, or default color if
    -- status isn't known yet.
    local sgr = "37;1"
    if info.conflict then
        sgr = "31;1"
    elseif info.status ~= nil then
        sgr = info.status and "33;1" or "32;1"
    end
    -- Prefix the prompt with "[branch]" using the status color.
    return "\x1b["..sgr.."m["..branch.."]\x1b[m  "..prompt
end

Transient Prompt

Clink can replace a past prompt with a differently formatted "transient" prompt. For example, if your normal prompt contains many bits of information that don't need to be seen later, then it may be desirable to replace past prompts with a simpler prompt. Or it may be useful to update the timestamp in a prompt to indicate when the prompt was completed, rather than when it was first shown.

The %CLINK_TRANSIENT_PROMPT% environment variable provides the initial prompt string for the transient prompt.

Turn on the transient prompt with clink set prompt.transient always. Or use same_dir instead of always to only use a transient prompt when the current directory is the same as the previous prompt.

The transient prompt can be customized by a prompt filter:

  1. Create a new prompt filter by calling clink.promptfilter() along with a priority id which dictates the order in which filters are called. Lower priority ids are called first.
  2. Define a :transientfilter() function on the returned prompt filter.

The transient filter function takes a string argument that contains the filtered prompt so far. If the filter function returns nil, it has no effect. If the filter function returns a string, that string is used as the new filtered prompt (and may be further modified by other prompt filters with higher priority ids). If the filter function returns a string and a boolean, then if the boolean is false the prompt filtering is done and no further filter functions are called.

A transient right side prompt is also possible (similar to the usual right side prompt). The %CLINK_TRANSIENT_RPROMPT% environment variable (note the R in _RPROMPT) provides the initial prompt string for the transient right side prompt, which can be customized by a :transientrightfilter() function on a prompt filter.

A prompt filter must have a :filter() function defined on it, and may in addition have any combination of :rightfilter(), :transientfilter(), and :transientrightfilter() functions defined on it.

The next example shows how to make a prompt that shows:

  1. The current directory and > on the left, and the date and time on the right.
  2. Just > on the left, for past commands.
-- Colors for the prompt strings.
local cwd_color  = "\x1b[0;1;37;44m"
local symbol_color = "\x1b[0;1;34m"
local date_color = "\x1b[0;36m"
local normal = "\x1b[m"

-- Create prompt filter.
local pf = clink.promptfilter(10)

-- Customize the normal prompt.
function pf:filter(prompt)
    -- Don't return false yet; let rightfilter have a chance.
    return cwd_color.." "..os.getcwd().." "..symbol_color.." > "..normal
end

-- Customize the normal right side prompt.
function pf:rightfilter(prompt)
    -- Returns false to stop filtering.
    return date_color..os.date(), false
end

-- Customize the transient prompt.
function pf:transientfilter(prompt)
    -- Don't return false yet; let transientrightfilter have a chance.
    return symbol_color.."> "..normal
end

-- Customize the transient right side prompt.
function pf:transientrightfilter(prompt)
    -- Returns false to stop filtering.
    return "", false
end

-- Show a reminder to turn on the transient prompt, to try out the example.
if settings.get("prompt.transient") == "off" then
    print("Use 'clink set prompt.transient same_dir' to enable the transient prompt.")
end

Customizing Suggestions

Clink can offer suggestions how to complete a command as you type, and you can select how it generates suggestions.

Turn on automatic suggestions with clink set autosuggest.enable true. Once enabled, Clink will show suggestions in a muted color after the end of the typed command. Accept the whole suggestion with the Right arrow or End key, accept the next word of the suggestion with Ctrl-Right, or accept the next full word of the suggestion up to a space with Shift-Right. You can ignore the suggestion if it isn't what you want; suggestions have no effect unless you accept them first.

Scripts can provide custom suggestion generators, in addition to the built-in options:

  1. Create a new suggestion generator by calling clink.suggester() along with a name that identifies the suggestion generator, and can be added to the autosuggest.strategy setting.
  2. Define a :suggest() function on the returned suggestion generator.

The function takes a line_state argument that contains the input line, and a matches argument that contains the possible matches from the completion engine. If the function returns nil, the next generator listed in the strategy is called. If the function returns a string (even an empty string), then the string is used as the suggestion.

The function can optionally return a string and an offset to where the suggestion begins in the input line. This makes it easier to return suggestions in some cases, and also makes it possible to update the capitalization of the whole accepted suggestion (even the part that's already been typed).

This example illustrates how to make a suggestion generator that returns the longest common prefix of the possible matches.

local prefix_suggestor = clink.suggester("completion_prefix")

function prefix_suggestor:suggest(line_state, matches)
    -- If the input line is empty or only spaces, don't suggest anything.
    if not line_state:getline():match("[^ ]") then
        return
    end

    -- If there is no common prefix, don't suggest anything.
    local prefix = matches:getprefix()
    if prefix == "" then
        return
    end

    -- Return the common prefix as the suggestion.
    local info = line_state:getwordinfo(line_state:getwordcount())
    return prefix, info.offset
end

Miscellaneous

These sections provide more information about various aspects of Clink:

Customizing Key BindingsHow to customize key bindings.
Saved Command HistoryHow the saved command history works.
Using History ExpansionHow to use history expansion.
Directory ShortcutsConvenient shortcut for changing the current directory.
Popular ScriptsSome popular scripts to enhance Clink.
Terminal SupportInformation about how Clink's terminal support works.
Troubleshooting TipsHow to troubleshoot and report problems.
PrivacyPrivacy statement for Clink.

Customizing Key Bindings

Key bindings are defined in .inputrc files.

The clink-show-help command is bound to Alt-H and lists all currently active key bindings. The list displays "friendly" key names, and these names are generally not suitable for use in .inputrc files. For example "Up" is the friendly name for "\e[A", and "A-C-F2" is the friendly name for "\e\e[1;5Q". To see key sequence strings suitable for use in .inputrc files use clink echo as described below.

The .inputrc fileWhere to find the .inputrc file, and more information about it.
Discovering Clink key sequencesHow to find key names to use for key bindings.
Binding special keysA table of special key names.
Lua key bindingsHow to bind keys to Lua functions.
I do not have a Meta or Alt keyWhat to do if your keyboard doesn't have any Alt or Meta keys.

The .inputrc file

You can use clink info to find the directories and configuration files for the current Clink session, including where the .inputrc file is located, or can be located. See the Readline Init File section for detailed information about .inputrc files.

Note: Third party console hosts such as ConEmu may have their own key bindings that supersede Clink. They usually have documentation for how to change or disable their key bindings to allow console programs to handle the keys instead.

Clink provides an easy way to find the key sequence for any key combination that Clink supports. Run clink echo and then press key combinations; the associated key binding sequence is printed to the console output and can be used for a key binding in the inputrc file.

A chord can be formed by concatenating multiple key binding sequences. For example, "\C-X" and "\e[H" can be concatenated to form "\C-X\e[H" representing the chord Ctrl-X,Home.

When finished, press Ctrl-C to exit from clink echo.

Note: With non-US keyboard layouts, clink echo is not able to ignore dead key input (accent keys, for example). It prints the key sequence for the dead key itself, which is not useful. You can ignore that and press the next key, and then it prints the correct key sequence to use in key bindings.

Binding special keys

Here is a table of the key binding sequences for the special keys. Clink primarily uses VT220 emulation for keyboard input, but also uses some Xterm extended key sequences.

Normal Shift Ctrl Ctrl-Shift Alt Alt-Shift Alt-Ctrl Alt-Ctrl-Shift
Up \e[A \e[1;2A \e[1;5A \e[1;6A \e[1;3A \e[1;4A \e[1;7A \e[1;8A
Down \e[B \e[1;2B \e[1;5B \e[1;6B \e[1;3B \e[1;4B \e[1;7B \e[1;8B
Left \e[D \e[1;2D \e[1;5D \e[1;6D \e[1;3D \e[1;4D \e[1;7D \e[1;8D
Right \e[C \e[1;2C \e[1;5C \e[1;6C \e[1;3C \e[1;4C \e[1;7C \e[1;8C
Insert \e[2~ \e[2;2~ \e[2;5~ \e[2;6~ \e[2;3~ \e[2;4~ \e[2;7~ \e[2;8~
Delete \e[3~ \e[3;2~ \e[3;5~ \e[3;6~ \e[3;3~ \e[3;4~ \e[3;7~ \e[3;8~
Home \e[H \e[1;2H \e[1;5H \e[1;6H \e[1;3H \e[1;4H \e[1;7H \e[1;8H
End \e[F \e[1;2F \e[1;5F \e[1;6F \e[1;3F \e[1;4F \e[1;7F \e[1;8F
PgUp \e[5~ \e[5;2~ \e[5;5~ \e[5;6~ \e[5;3~ \e[5;4~ \e[5;7~ \e[5;8~
PgDn \e[6~ \e[6;2~ \e[6;5~ \e[6;6~ \e[6;3~ \e[6;4~ \e[6;7~ \e[6;8~
Tab \t \e[Z \e[27;5;9~ \e[27;6;9~ - - - -
Space Space \e[27;2;32~ \e[27;5;32~ \e[27;6;32~ - - \e[27;7;32~ \e[27;8;32~
Backspace ^h \e[27;2;8~ Rubout \e[27;6;8~ \e^h \e[27;4;8~ \eRubout \e[27;8;8~
F1 \eOP \e[1;2P \e[1;5P \e[1;6P \e\eOP \e\e[1;2P \e\e[1;5P \e\e[1;6P
F2 \eOQ \e[1;2Q \e[1;5Q \e[1;6Q \e\eOQ \e\e[1;2Q \e\e[1;5Q \e\e[1;6Q
F3 \eOR \e[1;2R \e[1;5R \e[1;6R \e\eOR \e\e[1;2R \e\e[1;5R \e\e[1;6R
F4 \eOS \e[1;2S \e[1;5S \e[1;6S \e\eOS \e\e[1;2S \e\e[1;5S \e\e[1;6S
F5 \e[15~ \e[15;2~ \e[15;5~ \e[15;6~ \e\e[15~ \e\e[15;2~ \e\e[15;5~ \e\e[15;6~
F6 \e[17~ \e[17;2~ \e[17;5~ \e[17;6~ \e\e[17~ \e\e[17;2~ \e\e[17;5~ \e\e[17;6~
F7 \e[18~ \e[18;2~ \e[18;5~ \e[18;6~ \e\e[18~ \e\e[18;2~ \e\e[18;5~ \e\e[18;6~
F8 \e[19~ \e[19;2~ \e[19;5~ \e[19;6~ \e\e[19~ \e\e[19;2~ \e\e[19;5~ \e\e[19;6~
F9 \e[20~ \e[20;2~ \e[20;5~ \e[20;6~ \e\e[20~ \e\e[20;2~ \e\e[20;5~ \e\e[20;6~
F10 \e[21~ \e[21;2~ \e[21;5~ \e[21;6~ \e\e[21~ \e\e[21;2~ \e\e[21;5~ \e\e[21;6~
F11 \e[23~ \e[23;2~ \e[23;5~ \e[23;6~ \e\e[23~ \e\e[23;2~ \e\e[23;5~ \e\e[23;6~
F12 \e[24~ \e[24;2~ \e[24;5~ \e[24;6~ \e\e[24~ \e\e[24;2~ \e\e[24;5~ \e\e[24;6~

When the terminal.differentiate_keys setting is enabled then the following key bindings are also available:

Ctrl Ctrl-Shift Alt Alt-Shift Alt-Ctrl Alt-Ctrl-Shift
H \e[27;5;72~ \e[27;6;72~ \eh \eH \e[27;7;72~ \e[27;8;72~
I \e[27;5;73~ \e[27;6;73~ \ei \eI \e[27;7;73~ \e[27;8;73~
M \e[27;5;77~ \e[27;6;77~ \em \eM \e[27;7;77~ \e[27;8;77~
[ \e[27;5;219~ \e[27;6;219~ \e[27;3;219~ \e[27;4;219~ \e[27;7;219~ \e[27;8;219~

The terminal.raw_esc setting controls the binding sequence for the Esc key and a couple of other keys:

terminal.raw_esc Setting Value Esc Alt-[ Alt-Shift-O
False (the default) \e[27;27~ \e[27;3;91~ \e[27;4;79~
True (replicate Unix terminal input quirks and issues) \e \e[ \eO

Lua key bindings

You can bind a key to a Lua function by binding it to a macro that begins with "luafunc:". Clink will invoke the named Lua function when the key binding is input. Function names can include periods (such as foo.bar) but cannot include any other punctuation.

The Lua function receives two arguments:

rl_buffer gives it access to the input buffer.

line_state gives it access to the same line state that a match generator receives.

Lua functions can print output, but should first call rl_buffer:beginoutput() so that the output doesn't overwrite the displayed input line.

Notes:

  • The line_state is nil if not using Clink v1.2.34 or higher.
  • The end word is always empty for generators. So to get the word at the cursor use:
    local info = line_state:getwordinfo(line_state:getwordcount())
    local word_at_cursor = line_state:getline():sub(info.offset, line_state:getcursor())
    

Basic example

Example of a Lua function key binding in a .inputrc file:

M-C-y:          "luafunc:insert_date"
M-C-z:          "luafunc:print_date"

Example functions to go with that:

function insert_date(rl_buffer)
    rl_buffer:insert(os.date("%x %X"))
end

function print_date(rl_buffer)
    rl_buffer:beginoutput()
    print(os.date("%A %B %d, %Y   %I:%M %p"))
end

Advanced example

Here is an example that makes F7/F8 jump to the previous/next screen line containing "error" or "warn" colored red or yellow, and makes Shift-F7/Shift-F8 jump to the previous/next prompt line.

One way to use these is when reviewing compiler errors after building a project at the command line. Press Shift-F7 to jump to the previous prompt line, and then use F8 repeatedly to jump to each next compiler warning or error listed on the screen.

Example key bindings for the .inputrc file:

"\e[18~":       "luafunc:find_prev_colored_line"
"\e[19~":       "luafunc:find_next_colored_line"
"\e[18;2~":     "luafunc:find_prev_prompt"
"\e[19;2~":     "luafunc:find_next_prompt"

Example functions to go in a Lua script file:

local max_recent_prompts = 10   -- Keep track of up to this many recent prompts.
local min_match_text = 10       -- Minimum length of text to count as a match.

local recent_prompts = {}       -- Queue of recent prompt match strings.
local scroll_stack = {}         -- Stack of found scroll positions.

-- Remember our most recent scroll position, so that if something else scrolls
-- the screen we can reset the find_prev_prompt/find_next_prompt stack.
local was_top

local function add_recent_prompt(text)
    -- Escape characters that have special meaning in regular expressions.
    text = "^"..text:gsub("([!-/:-@[-`{-~])", "\\%1")

    -- Add new entry at the beginning of the queue.
    table.insert(recent_prompts, 1, text)

    -- Discard excess entries from the end of the queue.
    while #recent_prompts > max_recent_prompts do
        table.remove(recent_prompts)
    end
end

local function reset_prompt_scroll_stack()
    was_top = nil
    scroll_stack = {}
end

local function update_recent_prompt_queue()
    -- Offset minus one because onendedit happens after the cursor moves down
    -- past the end of the input area, which skews the info returned from
    -- rl.getpromptinfo().
    local offset = -1
    local info = rl.getpromptinfo()
    local line = info.promptline + offset
    local last_line = console.getnumlines()

    -- Find a long enough string to be considered part of the prompt.
    while line <= last_line do
        local text = console.getlinetext(line)
        text = text:gsub("%s+$", "")
        if #text >= min_match_text then
            add_recent_prompt(text)
            break
        end
        line = line + 1
    end
end

-- Register for events to maintain the scroll stack and recent prompt queue.
clink.onbeginedit(reset_prompt_scroll_stack)
clink.onendedit(update_recent_prompt_queue)

-- Jumps to the previous prompt on the screen (i.e. move upward, searching for
-- preceding recent prompts).
function find_prev_prompt(rl_buffer)
    local height = console.getheight()
    local offset = math.modf((height - 1) / 2)

    local top = console.gettop()
    if was_top and was_top ~= top then
        reset_prompt_scroll_stack()
    end
    if not was_top then
        was_top = top
    end

    if top <= 1 then
        console.scroll("absolute", 1)
        return
    end

    -- Init the stack if it's empty.
    if #scroll_stack == 0 then
        local info = rl.getpromptinfo()
        scroll_stack[1] = info.promptline
    end

    local count = #scroll_stack
    local start = scroll_stack[count] - 1
    local text = recent_prompts[count]

    if not text then
        if count == 1 then
            -- Only ding if there are none; otherwise visual bell will
            -- scroll back to the bottom.
            rl_buffer:ding()
        else
            -- No more recent prompts?  Maintain the scroll position.
            console.scroll("absolute", scroll_stack[count] - offset)
            was_top = console.gettop()
        end
        return
    end

    -- Search upwards for the next most recent prompt.
    local match
    repeat
        match = console.findprevline(start, text, "regex", {})
        if match <= 0 then
            -- Can't find it?  Maintain the scroll position.
            console.scroll("absolute", scroll_stack[count] - offset)
            was_top = console.gettop()
            return
        end
        start = match - 1
    until match - offset < was_top

    -- Add the found prompt to the stack.
    table.insert(scroll_stack, match)

    -- Scroll to the prompt position
    console.scroll("absolute", match - offset)
    was_top = console.gettop()
end

-- Jump to the next prompt on the screen (i.e. move downward, backtracking over
-- the prompts already visited by find_prev_prompt).
function find_next_prompt(rl_buffer)
    local height = console.getheight()
    local offset = math.modf((height - 1) / 2)

    -- Pop the last found prompt.  If the stack is empty, ding.
    if #scroll_stack > 0 then
        table.remove(scroll_stack)
    end
    if #scroll_stack == 0 then
        rl_buffer:ding()
        return
    end

    -- Get the scroll position of the next to last found prompt.
    local top = scroll_stack[#scroll_stack] - offset
    if #scroll_stack == 1 then
        -- If it's the last prompt, pop it to reset the stack.
        top = console.getnumlines()
        table.remove(scroll_stack, #scroll_stack)
    end

    -- Scroll to the prompt position.
    console.scroll("absolute", top)
    was_top = console.gettop()
end

-- Searches upwards for a line containing "warn" or "error"
-- colored red or yellow.
function find_prev_colored_line(rl_buffer)
    local height = console.getheight()
    local cur_top = console.gettop()
    local offset = math.modf((height - 1) / 2) -- For vertically centering the found line.
    local start = cur_top + offset
    local found_index

    -- Only search if there's still room to scroll up.
    if start - offset > 1 then
        local match = console.findprevline(start - 1, "warn|error", "regex", {4,12,14}, "fore")
        if match ~= nil and match > 0 then
            found_index = match
        end
    end

    -- If scrolled up but no more matches, maintain the scroll position.
    if found_index == nil and cur_top <= console.getnumlines() - height then
        found_index = start
    end

    if found_index ~= nil then
        console.scroll("absolute", found_index - offset)
    else
        rl_buffer:ding()
    end
end

-- Searches downwards for a line containing "warn" or "error"
-- colored red or yellow.
function find_next_colored_line(rl_buffer)
    local height = console.getheight()
    local cur_top = console.gettop()
    local bottom = console.getnumlines()
    local offset = math.modf((height - 1) / 2) -- For vertically centering the found line.
    local start = cur_top + offset
    local found_index

    if cur_top > bottom - height then
        rl_buffer:ding()
        return
    end

    -- Only search if there's still room to scroll down.
    if start - offset + height - 1 < bottom then
        local match = console.findnextline(start + 1, "warn|error", "regex", {4,12,14}, "fore")
        if match ~= nil and match > 0 then
            found_index = match
        end
    end

    if found_index ~= nil then
        console.scroll("absolute", found_index - offset)
    else
        rl_buffer:ding()
    end
end

I do not have a Meta or Alt key

If you do not have a Meta or Alt key, or another key working as a Meta key, there is another way to generate "metafied" keystrokes such as M-k.

You can configure clink set terminal.raw_esc true to make the Esc work as it does in Unix and Linux, and then you can type Esc followed by k. This is known as "metafying" the k key.

Clink is a Windows program, and so by default it makes the Esc key reset the input state, since that's how Esc generally works on Windows. When you enable the terminal.raw_esc Clink setting, the Esc key changes its behavior, and pressing unbound special keys can land you in all of the same strange "stuck input" situations as in Unix and Linux.

But it might be more convenient to acquire a keyboard that has an Alt key.

Saved Command History

Clink has a list of commands from the current session, and it can be saved and loaded across sessions.

A line won't be added to history if either of the following are true:

To prevent doskey alias expansion while still adding the line to history, you can start the line with a semicolon.

Line Description
somecmd Expands doskey alias and adds to history.
 somecmd Doesn't expand doskey alias and doesn't add to history.
;somecmd Doesn't expand doskey alias but does add to history.

There are several settings that control how history works. Run clink set history* to see them.

The master history file

When the history.saved setting is enabled, then the command history is loaded and saved as follows (or when the setting is disabled, then it isn't saved between sessions).

Every time a new input line starts, Clink reloads the master history list and prunes it not to exceed the history.max_lines setting.

For performance reasons, deleting a history line marks the line as deleted without rewriting the history file. When the number of deleted lines gets too large (exceeding the max lines or 200, whichever is larger) then the history file is compacted: the file is rewritten with the deleted lines removed.

You can force the history file to be compacted regardless of the number of deleted lines by running history compact.

Shared command history

When the history.shared setting is enabled, then all instances of Clink update the master history file and reload it every time a new input line starts. This gives the effect that all instances of Clink share the same history -- a command entered in one instance will appear in other instances' history the next time they start an input line.

When the setting is disabled, then each instance of Clink loads the master file but doesn't append its own history back to the master file until after it exits, giving the effect that once an instance starts its history is isolated from other instances' history.

Multiple master history files

Normally Clink saves a single saved master history list. All instances of Clink load and save the same master history list.

It's also possible to make one or more instances of Clink use a different saved master history list by setting the %CLINK_HISTORY_LABEL% environment variable. This can be up to 32 alphanumeric characters, and is appended to the master history file name. Changing the %CLINK_HISTORY_LABEL% environment variable takes effect at the next input line.

History timestamps

History items can optionally save the timestamp when they were added, and the timestamps can be shown in the history command.

Use clink set history.time_stamp off to not save or show timestamps for history items (this is the default). Turning off timestamps doesn't remove existing timestamps.

Use clink set history.time_stamp save to save timestamps for each history item but only show them in the history command when the --show-time flag is used.

Use clink set history.time_stamp show to save timestamps for each history item and show them in the history command unless the --bare flag is used.

Use clink set history.time_format format to specify the format for showing timestamps (the default format is %F %T  ).

The format string may contain regular characters and special format specifiers. Format specifiers begin with a percent sign (%), and are expanded to their corresponding values. For a list of possible format specifiers, refer to the C++ strftime() documentation.

Some common format specifiers are:

Specifier Expands To
%a Abbreviated weekday name for the locale (e.g. Thu).
%b Abbreviated month name for the locale (e.g. Aug).
%c Date and time representation for the locale.
%D Short MM/DD/YY date (e.g. 08/23/01).
%F Short YYYY/MM/DD date (e.g. 2001-08-23).
%H Hour in 24-hour format (00 - 23).
%I Hour in 12-hour format (01 - 12).
%m Month (01 - 12).
%M Minutes (00 - 59).
%p AM or PM indicator for the locale.
%r 12-hour clock time for the locale (e.g. 02:55:41 pm).
%R 24-hour clock time (e.g. 14:55).
%S Seconds (00 - 59).
%T ISO 8601 time format HH:MM:SS (e.g. 14:55:41).
%x Date representation for the locale.
%X Time representation for the locale.
%y Year without century (00 - 99).
%Y Year with century (e.g. 2001).
%% A % sign.

Using History Expansion

Clink uses Readline's History library to add history expansion capabilities. If these are undesirable, they can be turned off by running clink set history.auto_expand off or clink set history.expand_mode off.

The History library provides a history expansion feature that is similar to the history expansion provided by csh. This section describes the syntax used to manipulate the history information.

History expansions introduce words from the history list into the input stream, making it easy to repeat commands, insert the arguments to a previous command into the current input line, or fix errors in previous commands quickly.

History expansion takes place in two parts. The first is to determine which line from the history list should be used during substitution. The second is to select portions of that line for inclusion into the current one. The line selected from the history is called the "event", and the portions of that line that are acted upon are called "words". Various "modifiers" are available to manipulate the selected words. The line is broken into words in the same fashion that Bash does, so that several words surrounded by quotes are considered one word. History expansions are introduced by the appearance of the history expansion character, which is !.

History expansion implements shell-like quoting conventions: a backslash can be used to remove the special handling for the next character; single quotes enclose verbatim sequences of characters, and can be used to inhibit history expansion; and characters enclosed within double quotes may be subject to history expansion, since backslash can escape the history expansion character, but single quotes may not, since they are not treated specially within double quotes.

Event DesignatorsHow to specify which history line to use.
Word DesignatorsSpecifying which words are of interest.
ModifiersModifying the results of substitution.

Event Designators

An event designator is a reference to a command line entry in the history list. Unless the reference is absolute, events are relative to the current position in the history list.

! Start a history substitution, except when followed by a space, tab, the end of the line, or =.
!n Refer to command line n.
!-n Refer to the command n lines back.
!! Refer to the previous command. This is a synonym for !-1.
!string Refer to the most recent command preceding the current position in the history list starting with string.
!?string[?] Refer to the most recent command preceding the current position in the history list containing string. The trailing ? may be omitted if the string is followed immediately by a newline. If string is missing, the string from the most recent search is used; it is an error if there is no previous search string.
^string1^string2^ Quick Substitution. Repeat the last command, replacing string1 with string2. Equivalent to !!:s^string1^string2^.
!# The entire command line typed so far.

Word Designators

Word designators are used to select desired words from the event. A : separates the event specification from the word designator. It may be omitted if the word designator begins with a ^, $, *, -, or %. Words are numbered from the beginning of the line, with the first word being denoted by 0 (zero). Words are inserted into the current line separated by single spaces.

For example,

!! designates the preceding command. When you type this, the preceding command is repeated in toto.
!!:$ designates the last argument of the preceding command. This may be shortened to !$.
!fi:2 designates the second argument of the most recent command starting with the letters fi.

Here are the word designators:

0 (zero) The 0th word. For many applications, this is the command word.
n The nth word.
^ The first argument; that is, word 1.
$ The last argument.
% The first word matched by the most recent !?string? search, if the search string begins with a character that is part of a word.
x-y A range of words; -y abbreviates 0-y.
* All of the words, except the 0th. This is a synonym for 1-$. It is not an error to use * if there is just one word in the event; the empty string is returned in that case.
x* Abbreviates x-$
x- Abbreviates x-$ like x*, but omits the last word. If x is missing, it defaults to 0.

If a word designator is supplied without an event specification, the previous command is used as the event.

Modifiers

After the optional word designator, you can add a sequence of one or more of the following modifiers, each preceded by a :. These modify, or edit, the word or words selected from the history event.

h Remove a trailing pathname component, leaving only the head.
t Remove all leading pathname components, leaving the tail.
r Remove a trailing suffix of the form .suffix, leaving the basename.
e Remove all but the trailing suffix.
p Print the new command but do not execute it.
s/old/new/ Substitute new for the first occurrence of old in the event line. Any character may be used as the delimiter in place of /. The delimiter may be quoted in old and new with a single backslash. If & appears in new, it is replaced by old. A single backslash will quote the &. If old is empty, it is set to the last old substituted, or, if no previous history substitutions took place, the last string in a !?string? search. If new is empty, each matching old is deleted. The final delimiter is optional if it is the last character on the input line.
& Repeat the previous substitution.
g
Cause changes to be applied over the entire event line. Used in conjunction with s, as in gs/old/new/, or with &.
a
The same as g.
G Apply the following s or & modifier once to each word in the event.

Directory Shortcuts

Clink provides some typing savers for changing the current directory.

These shortcuts only work in the interactive command line; they do not work in batch scripts.

Here are some popular scripts that show off what can be done with Clink.

The clink-completions collection of scripts has a bunch of argument matchers and completion generators for things like git, mercurial, npm, and more.

The clink-flex-prompt script is similar to the zsh powerlevel10k theme. It gives Clink a very customizable prompt, with many style options. It's extensible so you can add your own segments.

It also takes advantage of Clink's asynchronous prompt refresh to make prompts show up instantly, even in large git repos, for example.

The clink-fzf script integrates the popular fzf "fuzzy finder" tool with Clink.

The clink-gizmos collection of scripts has several handy scripts such as:

oh-my-posh

The oh-my-posh program can generate fancy prompts. Refer to its documentation for how to configure it, and for sample themes.

Integrating oh-my-posh with Clink is easy: just save the following text to an oh-my-posh.lua file in your Clink scripts directory (run clink info to find that), and make sure the oh-my-posh.exe program is in a directory listed in the %PATH% environment variable (or edit the script below to provide a fully qualified path to the oh-my-posh.exe program). Replace the config with your own configuration and you're good to go.

-- oh-my-posh.lua
load(io.popen('oh-my-posh.exe --config="C:/Users/me/jandedobbeleer.omp.json" --init --shell cmd'):read("*a"))()

starship

The starship program can also generate fancy prompts. Refer to its documentation for how to configure it.

Integrating starship with Clink is just as easy: save the following text to a starship.lua file in your Clink scripts directory (run clink info to find that), and make sure the starship.exe program is in a directory listed in the %PATH% environment variable (or edit the script below to provide a fully qualified path to the starship.exe program). The config file for starship is located at C:\Users\<username>\.config\starship.toml.

-- starship.lua
load(io.popen('starship.exe init cmd'):read("*a"))()

z.lua

The z.lua tool is a faster way to navigate directories, and it integrates with Clink.

Terminal Support

Windows programs generally don't need to worry about terminal support. But the Readline library used by Clink comes from Unix, where there are many different kinds of terminals, and the library requires certain kinds of terminal support.

Clink's keyboard driver generally produces VT220 style key sequences, but it also includes many extensions from Xterm and other sources. Use clink echo to find key sequences for specific inputs.

Clink's terminal output driver is designed for use with Windows and its console subsystem. Clink can optionally handle output itself instead, and emulate terminal output support when the terminal.emulation setting is emulate, or when auto and Clink is running on an older version of Windows that doesn't support ANSI escape codes. In emulation mode, 8 bit and 24 bit color escape codes are mapped to the nearest 4 bit colors.

By default Clink sets the cursor style to a blinking horizontal partial-height block, or to a blink full-height solid block. Some terminals support escape codes to select alternative cursor styles. Clink provides environment variables where you may optionally provide escape codes to override the cursor style. %CLINK_TERM_VE% selects the style for the normal cursor (insert mode), %CLINK_TERM_VS% selects the style for the enhanced cursor (overwrite mode).

Special codes recognized in the cursor style escape code strings:

CodeDescription
\eTranslated to the ESC character (27 decimal, 0x1b hex).
\xHHTranslated to the character matching the hex HH value.
E.g. \x1b is the same as \e, or \x08 is a backspace, etc.
\\Translated to the \ character.
\cAny other backslash is translate to whatever character immediately follows it.
E.g. \a becomes a.

Refer to the documentation for individual terminal programs to find what (if any) escape codes they may support. The default console in Windows 10 supports the DECSCUSR escape codes for selecting cursor shape.

This .cmd script sets the normal cursor to a blinking vertical bar, and the enhanced cursor to a non-blinking solid box:

set CLINK_TERM_VE=\e[5 q
set CLINK_TERM_VS=\e[2 q

Or this .cmd script sets the normal cursor to blink, and the enhanced cursor to not blink:

set CLINK_TERM_VE=\e[?12h
set CLINK_TERM_VS=\e[?12l

Troubleshooting Tips

If something seems to malfunction, here are some things to try that often help track down what's going wrong:

When reporting an issue, please include the following which saves time by answering in advance the usual questions:

Privacy

Clink does not collect user data. Clink writes diagnostic information to its local log file, and does not transmit the log file off the local computer. For the location of the log file, refer to File Locations or run clink info.

Lua API Reference

This section describes the Clink Lua API extensions. Also see Lua Documentation and the Lua 5.2 Manual for more information about the Lua programming language.

API groups

_argmatcher
( choices...:string|table ) : self
v1.0.0 and newer

This adds a new argument position with the matches given by choices. Arguments can be a string, a string linked to another parser by the concatenation operator, a table of arguments, or a function that returns a table of arguments. See Argument Completion for more information.

local my_parser = clink.argmatcher("make_color_shape")
:addarg("red", "green", "blue")             -- 1st argument is a color
:addarg("circle", "square", "triangle")     -- 2nd argument is a shape

When providing a table of arguments, the table can contain some special entries:

EntryMore InfoVersion
delayinit=functionSee Delayed initialization for an argument position.v1.3.10 and newer
fromhistory=trueSee Generate Matches From History.v1.3.9 and newer
loopchars="characters"See Delimited Arguments.v1.3.37 and newer
nosort=trueSee Disable Sorting Matches.v1.3.3 and newer
onarg=functionSee Responding to Arguments in Argmatchers.v1.3.13 and newer

Note: Arguments are positional in an argmatcher. Using :addarg() multiple times adds multiple argument positions, in the order they are specified.


( choices...:string|table ) : self
v1.3.3 and newer

This is the same as _argmatcher:addarg except that this disables sorting the matches.


( [descriptions...:table] ) : self
v1.2.38 and newer

Adds descriptions for arg matches and/or flag matches. Descriptions are displayed for their associated args or flags whenever possible completions are listed, for example by the complete or clink-select-complete or possible-completions commands.

Any number of descriptions tables may be passed to the function, and each table must use one of the following schemes:

  • One or more string values that are args or flags, and a description field that is the associated description string.
  • Key/value pairs where each key is an arg or flag, and its value is either a description string or a table containing an optional arguments string and a description string. If an arguments string is provided, it is appended to the arg or flag string when listing possible completions. For example, ["--user"] = { " name", "Specify username"} gets printed as:

     --user name    Specify username 

local foo = clink.argmatcher("foo")
foo:addflags("-h", "--help", "--user")
foo:addarg("info", "set")
-- Example using first scheme and one table per description:
foo:adddescriptions(
    { "-h", "--help",   description = "Show help" },
    { "--user",         description = "Specify user name" },
    { "info",           description = "Prints information" },
    { "set",            description = "Show or change settings" },
)
-- Example using second scheme and just one table:
foo:adddescriptions( {
    ["-h"]              = "Show help",
    ["--help"]          = "Show help",
    ["--user"]          = { " name", "Specify user name" },
    ["info"]            = { "Prints information" },
    ["set"]             = { " var[=value]", "Show or change settings" },
} )

You can make your scripts backward compatible with older Clink versions by adding a helper function. The following is the safest and simplest way to support backward compatibility:

-- Helper function to add descriptions, when possible.
local function maybe_adddescriptions(matcher, ...)
    if matcher and matcher.adddescriptions then
        matcher:adddescriptions(...)
    end
end

-- This adds descriptions only if the Clink version being used
-- supports them, otherwise it does nothing.
maybe_adddescriptions(foo, {
    ["-h"] = "Show help",
    -- etc
})

( flags...:string ) : self
v1.0.0 and newer

This adds flag matches. Flags are separate from arguments: When listing possible completions for an empty word, only arguments are listed. But when the word being completed starts with the first character of any of the flags, then only flags are listed. See Argument Completion for more information.

local my_parser = clink.argmatcher("git")
:addarg({ "add", "status", "commit", "checkout" })
:addflags("-a", "-g", "-p", "--help")

When providing a table of flags, the table can contain some special entries:

EntryMore InfoVersion
delayinit=functionSee Delayed initialization for an argument position.v1.3.10 and newer
fromhistory=trueSee Generate Matches From History.v1.3.9 and newer
nosort=trueSee Disable Sorting Matches.v1.3.3 and newer
onarg=functionSee Responding to Arguments in Argmatchers.v1.3.13 and newer

Note: Flags are not positional in an argmatcher. Using :addarg() multiple times with different flags is the same as using :addarg() once with all of the flags.


( flags...:string ) : self
v1.3.3 and newer

This is the same as _argmatcher:addflags except that this also disables sorting for flags.


() : self
v1.3.13 and newer

This makes the rest of the line be parsed as a separate command, after the argmatcher reaches the end of its defined argument positions. You can use it to "chain" from one parser to another.

For example, cmd.exe program arg is example of a line where one command can have another command within it. :chaincommand() enables program arg to be parsed separately. If program has an argmatcher, then it takes over and parses the rest of the input line.

An example that chains in a linked argmatcher:

clink.argmatcher("program"):addflags("/x", "/y")
clink.argmatcher("cmd"):addflags(
    "/c" .. clink.argmatcher():chaincommand(),
    "/k" .. clink.argmatcher():chaincommand()
):nofiles()
-- Consider the following input:
--    cmd /c program /
-- "cmd" is colored as an argmatcher.
-- "/c" is colored as a flag (by the "cmd" argmatcher).
-- "program" is colored as an argmatcher.
-- "/" generates completions "/x" and "/y".

Examples that chain at the end of their argument positions:

clink.argmatcher("program"):addflags("-x", "-y")
clink.argmatcher("sometool"):addarg(
    "exec" .. clink.argmatcher()
                :addflags("-a", "-b")
                :addarg("profile1", "profile2")
                :chaincommand()
)
-- Consider the following input:
--    sometool exec profile1 program -
-- "sometool" is colored as an argmatcher.
-- "exec" is colored as an argument (for "sometool").
-- "profile1" is colored as an argument (for "exec").
-- "program" is colored as an argmatcher.
-- "-" generates completions "-x" and "-y".

( flags...:string ) : self
v1.3.3 and newer

This hides the specified flags when displaying possible completions (the flags are still recognized).

This is intended for use when there are several synonyms for a flag, so that input coloring and linked argmatchers work, without cluttering the possible completion list.

local dirs = clink.argmatcher():addarg(clink.dirmatches)
local my_parser = clink.argmatcher("mycommand")
:addflags("-a", "--a", "--al", "--all",
          "-d"..dirs, "--d"..dirs, "--di"..dirs, "--dir"..dirs)
:hideflags("--a", "--al", "--all",      -- Only "-a" is displayed.
           "-d", "--d", "--di")         -- Only "--dir" is displayed.

( [index:integer] ) : self
v0.4.9 and newer

This makes the parser loop back to argument position index when it runs out of positional sets of arguments (if index is omitted it loops back to argument position 1).

clink.argmatcher("xyzzy")
:addarg("zero", "cero")     -- first arg can be zero or cero
:addarg("one", "uno")       -- second arg can be one or uno
:addarg("two", "dos")       -- third arg can be two or dos
:loop(2)    -- fourth arg loops back to position 2, for one or uno, and so on

() : self
v1.0.0 and newer

This makes the parser prevent invoking match generators. You can use it to "dead end" a parser and suggest no completions.


() : self
v1.3.10 and newer

Resets the argmatcher to an empty state. All flags, arguments, and settings are cleared and reset back to a freshly-created state.

See Adaptive Argmatchers for more information.


( func:function ) : self
v1.1.18 and newer

This registers a function that gets called for each word the argmatcher handles, to classify the word as part of coloring the input text. See Coloring the Input Text for more information.


( func:function ) : self
v1.3.10 and newer

This registers a function that gets called the first time the argmatcher is used in each edit line session. See Adaptive Argmatchers for more information.


( [endofflags:string|boolean] ) : self
v1.3.12 and newer

When endofflags is a string, it is a special flag that signals the end of flags. When endflags is true or nil, then "--" is used as the end of flags string. Otherwise, the end of flags string is cleared.


( [prefixes...:string] ) : self
v1.0.0 and newer

This is almost never needed, because :addflags() automatically identifies flag prefix characters.

However, any flags generated by functions can't influence the automatic flag prefix character(s) detection. So in some cases it may be necessary to directly set the flag prefix.

Note: :setflagprefix() behaves differently in different versions of Clink:
VersionDescription
v1.0.0 through v1.1.3Sets the flag prefix characters.
v1.1.4 through v1.2.35Only sets flag prefix characters in an argmatcher created using the deprecated clink.arg.register_parser() function. Otherwise it has no effect.
v1.2.36 through v1.3.8Does nothing.
v1.3.9 onwardAdds flag prefix characters, in addition to the ones automatically identified.

local function make_flags()
    return { '-a', '-b', '-c' }
end

clink.argmatcher('some_command')
:addflags(make_flags)   -- Only a function is added, so flag prefix characters cannot be determined automatically.
:setflagprefix('-')     -- Force '-' to be considered as a flag prefix character.

( anywhere:boolean ) : self
v1.3.12 and newer

When anywhere is false, flags are only recognized until an argument is encountered. Otherwise they are recognized anywhere (which is the default).


builder
( match:string|table, [type:string] ) : boolean
v1.0.0 and newer

Adds a match.

The match argument is the match string to add.

The type argument is the optional match type, or "none" if omitted (see below for the possible match types).

Alternatively, the match argument can be a table with the following scheme:

{
    match           = "..."    -- [string] The match text.
    display         = "..."    -- [string] OPTIONAL; alternative text to display when listing possible completions.
    description     = "..."    -- [string] OPTIONAL; a description for the match.
    type            = "..."    -- [string] OPTIONAL; the match type.
    appendchar      = "..."    -- [string] OPTIONAL; character to append after the match.
    suppressappend  = t_or_f   -- [boolean] OPTIONAL; whether to suppress appending a character after the match.
}

  • The display field is optional, and is displayed instead of the match field when listing possible completions. It can even include ANSI escape codes for colors, etc. (Requires v1.2.38 or greater.)
  • The description field is optional, and is displayed in addition to match or display when listing possible completions. (Requires v1.2.38 or greater.)
  • The type field is optional. If omitted, then the type argument is used for that element.
  • The appendchar field is optional, and overrides the normal behavior for only this match. (Requires v1.3.1 or greater.)
  • The suppressappend field is optional, and overrides the normal behavior for only this match. (Requires v1.3.1 or greater.)

The match type affects how the match is inserted, displayed, and colored. Some type modifiers may be combined with a match type.

TypeDescription
"word"Shows the whole word even if it contains slashes.
"arg"Avoids appending a space if the match ends with a colon or equal sign.
"command"Displays the match using color.cmd.
"alias"Displays the match using color.doskey.
"file"Shows only the last path component, with appropriate file coloring.
"dir"Shows only the last path component and adds a trailing path separator, with appropriate directory coloring.
"none"For backward compatibility the match is treated like "file", unless it ends with a path separator in which case it's treated like "dir".

ModifierDescription
"hidden"This can be combined with "file" or "dir" to use color.hidden (e.g. "file,hidden").
"readonly"This can be combined with "file" or "dir" to use color.readonly (e.g. "file,readonly").
"link"This can be combined with "file" or "dir" to appropriate symlink coloring (e.g. "file,link").
"orphaned"This can be combined with "link" to use appropriate orphaned symlink coloring (e.g. "file,link,orphaned").

See Completion Colors and Color Settings for more information about colors.

builder:addmatch("hello") -- type is "none"
builder:addmatch("some_word", "word")
builder:addmatch("/flag", "arg")
builder:addmatch("abbrev", "alias")
builder:addmatch({ match="foo.cpp", type="file" })
builder:addmatch({ match="bar", type="dir" })
builder:addmatch({ match=".git", type="dir,hidden" })

( matches:table, [type:string] ) : integer, boolean
v1.0.0 and newer

This is the equivalent of calling builder:addmatch() in a for-loop. Returns the number of matches added and a boolean indicating if all matches were added successfully.

The matches argument can be a table of match strings, or a table of tables describing the matches.

The type argument is used as the type when a match doesn't explicitly include a type, and is "none" if omitted.

builder:addmatches({"abc", "def"}) -- Adds two matches of type "none"
builder:addmatches({"abc", "def"}, "file") -- Adds two matches of type "file"
builder:addmatches({
    -- Same table scheme per entry here as in builder:addmatch()
    { match="remote/origin/master", type="word" },
    { match="remote/origin/topic", type="word" }
})

() : boolean
v1.3.9 and newer

Returns whether the match builder is empty. It is empty when no matches have been added yet.


( [append:string] ) : nil
v1.1.2 and newer

Sets character to append after matches. For example the set match generator uses this to append "=" when completing matches, so that completing set USER becomes set USERDOMAIN= (rather than set USERDOMAIN ).


() : nil
v1.3.3 and newer

Turns off sorting the matches.


( [state:boolean] ) : nil
v1.1.2 and newer

Sets whether to suppress appending anything after the match except a possible closing quote. For example the env var match generator uses this.


( [state:integer] ) : nil
v1.1.2 and newer

Sets whether to suppress quoting for the matches. Set to 0 for normal quoting, or 1 to suppress quoting, or 2 to suppress end quotes. For example the env var match generator sets this to 1 to overcome the quoting that would normally happen for "%" characters in filenames.


() : nil
v1.3.37 and newer

Forces the generated matches to be used only once.

Normally Clink tries to reuse the most recently generated list of matches, if possible. It is an optimization, to avoid doing potentally expensive work multiple times in a row to generate the same list of matches when nothing has changed. Normally the optimization is beneficial, and typing more letters in a word can simply filter the existing list of matches.

But sometimes an argument may have special syntax. For example, an email address argument might want to generate matches for names until the word contains a @, and then it might want to generate matches for domain names. The optimization interferes with situations where parsing the word produces a completely different list of possible matches.

Making the generated matches volatile ensures matches are generated anew each time completion is invoked.


clink
( [priority:integer], commands...:string ) : _argmatcher
v1.0.0 and newer

Creates and returns a new argument matcher parser object. Use :addarg() and etc to add arguments, flags, other parsers, and more. See Argument Completion for more information.

If one command is provided and there is already an argmatcher for it, then this returns the existing parser rather than creating a new parser. Using :addarg() starts at arg position 1, making it possible to merge new args and etc into the existing parser.

In Clink v1.3.38 and higher, if a command is a fully qualified path, then it is only used when the typed command expands to the same fully qualified path. This makes it possible to create one argmatcher for c:\general\program.exe and another for c:\special\program.exe. For example, aliases may be used to make both programs runnable, or the system PATH might be changed temporarily while working in a particular context.

Note: Merging linked argmatchers only merges the first argument position. The merge is simple, but should be sufficient for common simple cases.


( [priority:integer] ) : table
v1.1.49 and newer

Creates and returns a new word classifier object. Define on the object a :classify() function which gets called in increasing priority order (low values to high values) when classifying words for coloring the input. See Coloring the Input Text for more information.


( word:string ) : table
v1.1.18 and newer

You can use this function in an argmatcher to supply directory matches. This automatically handles Readline tilde completion.

-- Make "cd" generate directory matches (no files).
clink.argmatcher("cd")
:addflags("/d")
:addarg({ clink.dirmatches })

( word:string ) : table
v1.1.18 and newer

You can use this function in an argmatcher to supply file matches. This automatically handles Readline tilde completion.

Argmatchers default to matching files, so it's unusual to need this function. However, some exceptions are when a flag needs to accept file matches but other flags and arguments don't, or when matches need to include more than files.

-- Make "foo --file" generate file matches, but other flags and args don't.
-- And the third argument can be a file or $stdin or $stdout.
clink.argmatcher("foo")
:addflags(
    "--help",
    "--file"..clink.argmatcher():addarg({ clink.filematches })
)
:addarg({ "one", "won" })
:addarg({ "two", "too" })
:addarg({ clink.filematches, "$stdin", "$stdout" })

( [priority:integer] ) : table
v1.0.0 and newer

Creates and returns a new match generator object. Define on the object a :generate() function which gets called in increasing priority order (low values to high values) when generating matches for completion. See Match Generators for more information.


() : string
v1.1.48 and newer

Returns a string indicating who Clink thinks will currently handle ANSI escape codes. This can change based on the terminal.emulation setting. This always returns "unknown" until the first edit prompt (see clink.onbeginedit()).

This can be useful in choosing what kind of ANSI escape codes to use, but it is a best guess and is not necessarily 100% reliable.

ReturnDescription
"unknown"Clink doesn't know.
"clink"Clink is emulating ANSI support. 256 color and 24 bit color escape codes are mapped to the nearest of the 16 basic colors.
"conemu"Clink thinks ANSI escape codes will be handled by ConEmu.
"ansicon"Clink thinks ANSI escape codes will be handled by ANSICON.
"winterminal"Clink thinks ANSI escape codes will be handled by Windows Terminal.
"winconsole"Clink thinks ANSI escape codes will be handled by the default console support in Windows, but Clink detected a terminal replacement that won't support 256 color or 24 bit color.
"winconsolev2"Clink thinks ANSI escape codes will be handled by the default console support in Windows, or it might be handled by a terminal replacement that Clink wasn't able to detect.


( find:string|line_state ) : argmatcher|nil
v1.3.12 and newer

Finds the argmatcher registered to handle a command, if any.

When find is a string it is interpreted as the name of a command, and this looks up the argmatcher for the named command.

When find is a line_state this looks up the argmatcher for the command line.

If no argmatcher is found, this returns nil.


() : string
v1.1.44 and newer

Returns the current Clink session id.

This is needed when using io.popen() (or similar functions) to invoke clink history or clink info while Clink is installed for autorun. The popen API spawns a new CMD.exe, which gets a new Clink instance injected, so the history or info command will use the new session unless explicitly directed to use the calling session.

local c = os.getalias("clink")
local r = io.popen(c.." --session "..clink.getsession().." history")

( text:string ) : string
v0.4.9 and newer

This API correctly converts UTF8 strings to lowercase, with international linguistic awareness.

clink.lower("Hello World") -- returns "hello world"

( func:function ) : nil
v1.2.50 and newer

Registers func to be called after every editing command (key binding).


( func:function ) : nil
v1.1.11 and newer

Registers func to be called when Clink's edit prompt is activated. The function receives no arguments and has no return values.

Starting in v1.3.18 func may optionally return a string. If a string is returned, it is executed as a command line without showing a prompt and without invoking the input line editor.

Note: Be very careful if you return a string; this has the potential to interfere with the user's ability to use CMD. Mistakes in the command string can have the potential to cause damage to the system very quickly. It is also possible for a script to cause an infinite loop, and therefore Ctrl-Break causes the next string to be ignored.


( func:function ) : nil
v1.3.12 and newer

Registers func to be called when the command word changes in the edit line.

The function receives 2 arguments: the line_state for the command, and a table with the following scheme:

{
    command =   -- [string] The command.
    quoted  =   -- [boolean] Whether the command is quoted in the command line.
    type    =   -- [string] "unrecognized", "executable", or "command" (a CMD command name).
    file    =   -- [string] The file that would be executed, or an empty string.
}

The function has no return values.


( func:function ) : nil
v1.1.12 and newer

Registers func to be called when Clink is about to display matches. See Filtering the Match Display for more information.

local function my_filter(matches, popup)
    local new_matches = {}
    for _,m in ipairs(matches) do
        if m.match:find("[0-9]") then
            -- Ignore matches with one or more digits.
        else
            -- Keep the match, and also add * prefix to directory matches.
            if m.type:find("^dir") then
                m.display = "*"..m.match
            end
            table.insert(new_matches, m)
        end
    end
    return new_matches
end

function my_match_generator:generate(line_state, match_builder)
    ...
    clink.ondisplaymatches(my_filter)
end

( func:function ) : nil
v1.1.20 and newer

Registers func to be called when Clink's edit prompt ends. The function receives a string argument containing the input text from the edit prompt.

Breaking Change in v1.2.16: The ability to replace the user's input has been moved to a separate onfilterinput event.


( func:function ) : nil
v1.2.16 and newer

Registers func to be called after Clink's edit prompt ends (it is called after the onendedit event). The function receives a string argument containing the input text from the edit prompt. The function returns up to two values. If the first is not nil then it's a string that replaces the edit prompt text. If the second is not nil and is false then it stops further onfilterinput handlers from running.

Starting in v1.3.13 func may return a table of strings, and each is executed as a command line.

Note: Be very careful if you replace the text; this has the potential to interfere with or even ruin the user's ability to enter command lines for CMD to process.


( func:function ) : nil
v1.1.41 and newer

Registers func to be called after Clink generates matches for completion. See Filtering Match Completions for more information.


( func:function ) : nil
v1.1.21 and newer

Registers func to be called when Clink is injected into a CMD process. The function is called only once per session.


( func:function ) : nil | string
v1.3.18 and newer

Registers func to be called after the onbeginedit event but before the input line editor starts. If func returns a string, it is executed as a command line without showing a prompt. The input line editor is skipped, and the onendedit and onfilterinput events happen immediately.

Note: Be very careful when returning a string; this can interfere with the user's ability to use CMD. Mistakes in the command string can have potential to cause damage to the system very quickly. It is also possible for a script to cause an infinite loop, and therefore Ctrl-Break skips the next onprovideline event, allowing the user to regain control.


( line:string ) : table
v1.3.37 and newer

This parses the line string into a table of commands, with one line_state for each command parsed from the line string.

The returned table of tables has the following scheme:

local commands = clink.parseline("echo hello & echo world")
-- commands[1].line_state corresponds to "echo hello".
-- commands[2].line_state corresponds to "echo world".

( title:string, items:table, [index:integer], [del_callback:function] ) : string, boolean, integer
v1.2.17 and newer

Displays a popup list and returns the selected item. May only be used within a luafunc: key binding.

title is required and captions the popup list.

items is a table of strings to display.

index optionally specifies the default item (or 1 if omitted).

del_callback optionally specifies a callback function to be called when Del is pressed. The function receives the index of the selected item. If the function returns true then the item is deleted from the popup list. This requires Clink v1.3.41 or higher.

The function returns one of the following:

  • nil if the popup is canceled or an error occurs.
  • Three values:
    • string indicating the value field from the selected item (or the display field if no value field is present).
    • boolean which is true if the item was selected with Shift or Ctrl pressed.
    • integer indicating the index of the selected item in the original items table.

Alternatively, the items argument can be a table of tables with the following scheme:

{
    {
        value       = "...",   -- Required; this is returned if the item is chosen.
        display     = "...",   -- Optional; displayed instead of value.
        description = "...",   -- Optional; displayed in a dimmed color in a second column.
    },
    ...
}

The value field is returned if the item is chosen.

The optional display field is displayed in the popup list instead of the value field.

The optional description field is displayed in a dimmed color in a second column. If it contains tab characters ("\t") the description string is split into multiple columns (up to 3).

Starting in v1.3.18, if any description contains a tab character, then the descriptions are automatically aligned in a column.

Otherwise, the descriptions follow immediately after the display field. They can be aligned in a column by making all of the display fields be the same number of character cells.


( ... ) : nil
v1.2.11 and newer

This works like print(), but this supports ANSI escape codes and Unicode.

If the special value NONL is included anywhere in the argument list then the usual trailing newline is omitted. This can sometimes be useful particularly when printing certain ANSI escape codes.

Note: In Clink versions before v1.2.11 the clink.print() API exists (undocumented) but accepts exactly one string argument and is therefore not fully compatible with normal print() syntax. If you use fewer or more than 1 argument or if the argument is not a string, then first checking the Clink version (e.g. clink.version_encoded) can avoid runtime errors.

clink.print("\x1b[32mgreen\x1b[m \x1b[35mmagenta\x1b[m")
-- Outputs green in green, a space, and magenta in magenta.

local a = "hello"
local world = 73
clink.print("a", a, "world", world)
-- Outputs a       hello   world   73.

clink.print("hello", NONL)
clink.print("world")
-- Outputs helloworld.

( func:function ) : [return value from func]
v1.2.10 and newer

Creates a coroutine to run the func function in the background. Clink will automatically resume the coroutine repeatedly while input line editing is idle. When the func function completes, Clink will automatically refresh the prompt by triggering prompt filtering again.

A coroutine is only created the first time each prompt filter calls this API during a given input line session. Subsequent calls reuse the already-created coroutine. (E.g. pressing Enter ends an input line session.)

The API returns nil until the func function has finished. After that, the API returns whatever the func function returned. The API returns one value; if multiple return values are needed, return them in a table.

If the prompt.async setting is disabled, then the coroutine runs to completion immediately before returning. Otherwise, the coroutine runs during idle while editing the input line. The func function receives one argument: true if it's running in the background, or false if it's running immediately.

See Asynchronous Prompt Filtering for more information.

Note: each prompt filter can have at most one prompt coroutine.


( [priority:integer] ) : table
v1.0.0 and newer

Creates and returns a new promptfilter object that is applied in increasing priority order (low values to high values). Define on the object a :filter() function that takes a string argument which contains the filtered prompt so far. The function can return nil to have no effect, or can return a new prompt string. It can optionally stop further prompt filtering by also returning false. See Customizing the Prompt for more information.

local foo_prompt = clink.promptfilter(80)
function foo_prompt:filter(prompt)
    -- Insert the date at the beginning of the prompt.
    return os.date("%a %H:%M").." "..prompt
end

() : nil
v1.3.9 and newer

Reclassify the input line text again and refresh the input line display.


( [line:string], word:string, [quoted:boolean] ) : word_class:string, ready:boolean, file:string
v1.3.38 and newer

This reports the input line coloring word classification to use for a command word. The return value can be passed into word_classifications:classifyword() as its word_class argument.

This is intended for advanced input line coloring purposes. For example if a script uses clink.onfilterinput() to modify the input text, then it can use this function inside a custom classifier to look up the color appropriate for the modified input text.

The line is optional and may be an empty string or omitted. When present, it is parsed to check if it would be processed as a directory shortcut.

The word is a string indicating the word to be analyzed.

The quoted is optional. When true, it indicates the word is quoted and any ^ characters are taken as-is, rather than treating them as the usual CMD escape character.

The possible return values for word_class are:

CodeClassificationClink Color Setting
"x"Executable; used for the first word when it is not a command or doskey alias, but is an executable name that exists.color.executable
"u"Unrecognized; used for the first word when it is not a command, doskey alias, or recognized executable name.color.unrecognized
"o"Other; used for file names and words that don't fit any of the other classifications.color.input

The possible return values for ready are:

  • True if the analysis has completed.
  • False if the analysis has not yet completed (and the returned word class may be a temporary placeholder).

The return value for file is the fully qualified path to the found executable file, if any, or nil.

Note: This always returns immediately, and it uses a background thread to analyze the word asynchronously. When the background thread finishes analyzing the word, Clink automatically redisplays the input line, giving classifiers a chance to call this function again and get the final word_class result.


() : nil
v1.2.46 and newer

Invoke the prompt filters again and refresh the prompt.

Note: this can potentially be expensive; call this only infrequently.


() : nil
v1.2.29 and newer

Reloads Lua scripts and Readline config file at the next prompt.


( coroutine:coroutine ) : nil
v1.3.5 and newer

By default, a coroutine is canceled if it doesn't complete before an edit line ends. In some cases it may be necessary for a coroutine to run until it completes, even if it spans multiple edit lines.

Note: Use with caution. This can potentially cause performance problems or cause prompt filtering to experience delays.


( coroutine:coroutine, [interval:number] ) : nil
v1.3.1 and newer

Overrides the interval at which a coroutine is resumed. All coroutines are automatically added with an interval of 0 by default, so calling this is only needed when you want to change the interval.

Coroutines are automatically resumed while waiting for input while editing the input line.

If a coroutine's interval is less than 5 seconds and the coroutine has been alive for more than 5 seconds, then the coroutine is throttled to run no more often than once every 5 seconds (regardless how much total time is has spent running). Throttling is meant to prevent long-running coroutines from draining battery power, interfering with responsiveness, or other potential problems.


( coroutine:coroutine, name:string ) : nil
v1.3.1 and newer

Sets a name for the coroutine. This is purely for diagnostic purposes.


( name:string ) : table
v1.2.47 and newer

Creates and returns a new suggester object. Suggesters are consulted in the order their names are listed in the autosuggest.strategy setting.

Define on the object a :suggest() function that takes a line_state argument which contains the input line, and a matches argument which contains the possible completions. The function can return nil to give the next suggester a chance, or can return a suggestion (or an empty string) to stop looking for suggestions.

In Clink v1.2.51 and higher, the function may return a suggestion and an offset where the suggestion begins in the line. This is useful if the suggester wants to be able to insert the suggestion using the original casing. For example if you type "set varn" and a history entry is "set VARNAME" then returning "set VARNAME", 1 or "VARNAME", 5 can accept "set VARNAME" instead of "set varnAME".

See Customizing Suggestions for more information.

local doskeyarg = clink.suggester("doskeyarg")
function doskeyarg:suggest(line, matches)
    if line:getword(1) == "doskey" and
            line:getline():match("[ \t][^ \t/][^ \t]+=") and
            not line:getline():match("%$%*") then
        -- If the line looks like it defines a macro and doesn't yet add all
        -- arguments, suggest adding all arguments.
        if line:getline():sub(#line:getline()) == " " then
            return "$*"
        else
            return " $*"
        end
    end
end

( [mode:integer] ) : integer
v1.2.7 and newer

This overrides how Clink translates slashes in completion matches, which is normally determined by the match.translate_slashes setting.

This is reset every time match generation is invoked, so use a generator to set this.

The mode specifies how to translate slashes when generators add matches:
ModeDescription
0No translation.
1Translate using the system path separator (backslash on Windows).
2Translate to slashes (/).
3Translate to backslashes (\).

If mode is omitted, then the function returns the current slash translation mode without changing it.

Note: Clink always generates file matches using the system path separator (backslash on Windows), regardless what path separator may have been typed as input. Setting this to 0 does not disable normalizing typed input paths when invoking completion; it only disables translating slashes in custom generators.

-- This example affects all match generators, by using priority -1 to
-- run first and returning false to let generators continue.
-- To instead affect only one generator, call clink.translateslashes()
-- in its :generate() function and return true.
local force_slashes = clink.generator(-1)
function force_slashes:generate()
    clink.translateslashes(2)  -- Convert to slashes.
    return false               -- Allow generators to continue.
end

( text:string ) : string
v1.1.5 and newer

This API correctly converts UTF8 strings to uppercase, with international linguistic awareness.

clink.upper("Hello World") -- returns "HELLO WORLD"

string variable
v1.1.10 and newer

The commit part of the Clink version number. For v1.2.3.a0f14d the commit part is a0f14d.


integer variable
v1.1.10 and newer

The Clink version number encoded as a single integer following the format Mmmmpppp where M is the major part, m is the minor part, and p is the patch part of the version number.

For example, Clink v95.6.723 would be 950060723.

This format makes it easy to test for feature availability by encoding version numbers from the release notes.


integer variable
v1.1.10 and newer

The major part of the Clink version number. For v1.2.3.a0f14d the major version is 1.


integer variable
v1.1.10 and newer

The minor part of the Clink version number. For v1.2.3.a0f14d the minor version is 2.


integer variable
v1.1.10 and newer

The patch part of the Clink version number. For v1.2.3.a0f14d the patch version is 3.


console
( text:string ) : integer
v1.2.5 and newer

Returns the count of visible character cells that would be consumed if the text string were output to the console, accounting for any ANSI escape codes that may be present in the text.

Note: backspace characters and line endings are counted as visible character cells and will skew the resulting count.


( [timeout:number] ) : boolean
v1.3.42 and newer

Checks whether input is available.

The optional timeout is the number of seconds to wait for input to be available (use a floating point number for fractional seconds). The default is 0 seconds, which returns immediately if input is not available.

If input is available before the timeout is reached, the return value is true. Use console.readinput() to read the available input.

Note: Mouse input is not supported.

if console.checkinput() then
    local key = console.readinput() -- Returns immediately since input is available.
    if key == "\x03" or key == "\x1b[27;27~" or key == "\x1b" then
        -- Ctrl-C or ESC was pressed.
    end
end

( starting_line:integer, [text:string], [mode:string], [attr:integer], [attrs:table of integers], [mask:string] ) : integer
v1.1.21 and newer

Searches downwards (forwards) for a line containing the specified text and/or attributes, starting at line starting_line. The matching line number is returned, or 0 if no matching line is found.

This behaves the same as console.findprevline() except that it searches in the opposite direction.


( starting_line:integer, [text:string], [mode:string], [attr:integer], [attrs:table of integers], [mask:string] ) : integer
v1.1.21 and newer

Searches upwards (backwards) for a line containing the specified text and/or attributes, starting at line starting_line. The matching line number is returned, or 0 if no matching line is found, or -1 if an invalid regular expression is provided.

You can search for text, attributes, or both. Include the text argument to search for text, and include either the attr or attrs argument to search for attributes. If both text and attribute(s) are passed, then the attribute(s) must be found within the found text. If only attribute(s) are passed, then they must be found anywhere in the line. See console.linehascolor() for more information about the color codes.

The mode argument selects how the search behaves. To use a regular expression, pass "regex". To use a case insensitive search, pass "icase". These can be combined by separating them with a comma. The regular expression syntax is the ECMAScript syntax described here.

Any trailing whitespace is ignored when searching. This especially affects the $ (end of line) regex operator.

mask is optional and can be "fore" or "back" to only match foreground or background colors, respectively.

Note: Although most of the arguments are optional, the order of provided arguments is important.

For more information, see this example of using this in some luafunc: macros.


() : integer
v1.1.20 and newer

Returns the number of visible lines of the console screen buffer.


( line:integer ) : string
v1.1.20 and newer

Returns the text from line number line, from 1 to console.getnumlines().

Any trailing whitespace is stripped before returning the text.


() : integer
v1.1.20 and newer

Returns the total number of lines in the console screen buffer.


() : string
v1.1.32 and newer

Returns the console title text.


() : integer
v1.1.20 and newer

Returns the current top line (scroll position) in the console screen buffer.


() : integer
v1.1.20 and newer

Returns the width of the console screen buffer in characters.


( line:integer ) : boolean
v1.1.20 and newer

Returns whether line number line uses only the default text color.


( line:integer, [attr:integer], [attrs:table of integers], [mask:string] ) : boolean
v1.1.21 and newer

Returns whether line number line contains the DOS color code attr, or any of the DOS color codes in attrs (either an integer or a table of integers must be provided, but not both). mask is optional and can be "fore" or "back" to only match foreground or background colors, respectively.

The low 4 bits of the color code are the foreground color, and the high 4 bits of the color code are the background color. This refers to the default 16 color palette used by console windows. When 256 color or 24-bit color ANSI escape codes have been used, the closest of the 16 colors is used.

To build a color code, add the corresponding Foreground color and the Background color values from this table:

ForegroundBackgroundColor
00
 
Black
116
 
Dark Blue
232
 
Dark Green
348
 
Dark Cyan
464
 
Dark Red
580
 
Dark Magenta
696
 
Dark Yellow
7112
 
Gray
8128
 
Dark Gray
9144
 
Bright Blue
10160
 
Bright Green
11176
 
Bright Cyan
12192
 
Bright Red
13208
 
Bright Magenta
14224
 
Bright Yellow
15240
 
White


( text:string ) : string, integer
v1.2.5 and newer

Returns the input text with ANSI escape codes removed, and the count of visible character cells that would be consumed if the text were output to the console.

Note: backspace characters and line endings are counted as visible character cells and will skew the resulting count.


( no_cursor:boolean ) : string | nil
v1.2.29 and newer

Reads one key sequence from the console input. If no input is available, it waits until input becomes available.

This returns the full key sequence string for the pressed key. For example, A is "A" and Home is "\027[A", etc. Nil is returned when an interrupt occurs by pressing Ctrl-Break.

See Discovering Key Sequences for information on how to find the key sequence for a key.

In Clink v1.3.42 and higher, passing true for no_cursor avoids modifying the cursor visibility or position.

Note: Mouse input is not supported.


( candidate_pattern:string, accept_pattern:string ) : table
v1.1.40 and newer

Uses the provided Lua string patterns to collect text from the current console screen and returns a table of matching text snippets. The snippets are ordered by distance from the input line.

For example candidate_pattern could specify a pattern that identifies words, and accept_pattern could specify a pattern that matches words composed of hexadecimal digits.

local matches = console.screengrab(
        "[^%w]*(%w%w[%w]+)",   -- Words with 3 or more letters are candidates.
        "^%x+$")               -- A candidate containing only hexadecimal digits is a match.

( mode:string, amount:integer ) : integer
v1.1.20 and newer

Scrolls the console screen buffer and returns the number of lines scrolled up (negative) or down (positive).

The mode specifies how to scroll:
ModeDescription
"line"Scrolls by amount lines; negative is up and positive is down.
"page"Scrolls by amount pages; negative is up and positive is down.
"end"Scrolls to the top if amount is negative, or to the bottom if positive.
"absolute"Scrolls to line amount, from 1 to console.getnumlines().


( title:string ) : nil
v1.1.32 and newer

Sets the console title text.


io
( filename:string, [mode:string] ) : file
v0.0.1 and newer

This function opens a file named by filename, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message and error number.

The mode string can be any of the following:

  • "r": read mode (the default);
  • "w": write mode;
  • "wx": write mode, but fail if the file already exists (requires v1.3.18 or higher);
  • "a": append mode;
  • "r+": update mode, all previous data is preserved;
  • "w+": update mode, all previous data is erased;
  • "w+x": update mode, all previous data is erased, but fail if the file already exists (requires v1.3.18 or higher);
  • "a+": append update mode, previous data is preserved, writing is only allowed at the end of file.

The mode string can also have a 'b' at the end to open the file in binary mode.

The 'x' modes are Clink extensions to Lua.


( command:string, [mode:string] ) : file, file
v1.1.42 and newer

Runs command and returns two file handles: a file handle for reading output from the command, and a file handle for writing input to the command.

mode can be "t" for text mode (the default if omitted) or "b" for binary mode.

If the function fails it returns nil, an error message, and an error number.

Warning This can result in deadlocks unless the command fully reads all of its input before writing any output. This is because Lua uses blocking IO to read and write file handles. If the write buffer fills (or the read buffer is empty) then the write (or read) will block and can only become unblocked if the command correspondingly reads (or writes). But the other command can easily experience the same blocking IO problem on its end, resulting in a deadlock: process 1 is blocked from writing more until process 2 reads, but process 2 can't read because it is blocked from writing until process 1 reads.

local r,w = io.popenrw("fzf.exe --height 40%")

w:write("hello\n")
w:write("world\n")
w:close()

while (true) do
    local line = r:read("*line")
    if not line then
        break
    end
    print(line)
end
r:close()

( command:string, [mode:string] ) : file, function (see remarks below)
v1.2.10 and newer

This behaves similar to io.popen() except that it only supports read mode and when used in a coroutine it yields until the command has finished.

The command argument is the command to run.

The mode argument is the optional mode to use. It can contain "r" (read mode) and/or either "t" for text mode (the default if omitted) or "b" for binary mode. Write mode is not supported, so it cannot contain "w".

This runs the specified command and returns a read file handle for reading output from the command. It yields until the command has finished and the complete output is ready to be read without blocking.

In v1.3.31 and higher, it may also return a function. If the second return value is a function then it can be used to get the exit status for the command. The function returns the same values as os.execute(). The function may be used only once, and it closes the read file handle, so if the function is used then do not use file:close(). Or, if the second return value is not a function, then the exit status may be retrieved from calling file:close() on the returned file handle.

Compatibility Note: when io.popen() is used in a coroutine, it is automatically redirected to io.popenyield(). This means on success the second return value from io.popen() in a coroutine may not be nil as callers might normally expect.

Note: if the prompt.async setting is disabled, or while a transient prompt filter is executing, or if used outside of a coroutine, then this behaves like io.popen() instead.

local file = io.popenyield("git status")

while (true) do
    local line = file:read("*line")
    if not line then
        break
    end
    do_things_with(line)
end
file:close()

Here is an example showing how to get the exit status, if desired:

-- Clink v1.3.31 and higher return a pclose function, for optional use.
local file, pclose = io.popenyield("kubectl.exe")
if file then
    local ok, what, code = pclose()
end

( filename:string, [mode:string], [deny:string] ) : file
v1.3.18 and newer

This is the same as io.open(), but adds an optional deny argument that specifies the type of sharing allowed.

This function opens a file named by filename, in the mode specified in the string mode. It returns a new file handle, or, in case of errors, nil plus an error message and error number.

The mode string can be any of the following:

  • "r": read mode (the default);
  • "w": write mode;
  • "wx": write mode, but fail if the file already exists;
  • "a": append mode;
  • "r+": update mode, all previous data is preserved;
  • "w+": update mode, all previous data is erased;
  • "w+x": update mode, all previous data is erased, but fail if the file already exists;
  • "a+": append update mode, previous data is preserved, writing is only allowed at the end of file.

The mode string can also have a 'b' at the end to open the file in binary mode.

The deny string can be any of the following:

  • "r" denies read access;
  • "w" denies write access;
  • "rw" denies read and write access;
  • "" permits read and write access (the default).


( file:file ) : integer
v1.3.41 and newer

This function truncates the file previously opened by io.open or io.sopen. When used on a pipe or other file handle that doesn't refer to an actual file, the behavior is undefined.

If successful, the return value is the position at which the file was truncated. If an error occurs, the return values are nil, an error message, and an error code.


line_state
() : integer
v1.0.0 and newer

Returns the offset to the start of the delimited command in the line that's being effectively edited. Note that this may not be the offset of the first command of the line unquoted as whitespace isn't considered for words.

-- Given the following line; abc&123
-- where commands are separated by & symbols.
line_state:getcommandoffset() == 5

The command offset points to the beginning of the command, but that might be a space character. Two spaces after a command separator is like one space at the beginning of a line; it disables doskey alias expansion. So, if the command offset points at a space, then you know the first word will not be treated as a doskey alias.

-- Given the following line; abc&  123
-- where commands are separated by & symbols.
line_state:getcommandoffset() == 6

() : integer
v1.2.27 and newer

Returns the index of the command word. Usually the index is 1, but if a redirection symbol occurs before the command name then the index can be greater than 1.

-- Given the following line; >x abc
-- the first word is "x" and is an argument to the redirection symbol,
-- and the second word is "abc" and is the command word.
line_state:getcommandwordindex() == 2

() : integer
v1.0.0 and newer

Returns the position of the cursor.


() : string
v1.0.0 and newer

Returns the last word of the line. This is the word that matches are being generated for.

Note: The returned word omits any quotes. This helps generators naturally complete "foo\"ba to "foo\bar". The raw word including quotes can be obtained using the offset and length fields from line_state:getwordinfo() to extract a substring from the line returned by line_state:getline().

line_state:getword(line_state:getwordcount()) == line_state:getendword()

() : string
v1.0.0 and newer

Returns the current line in its entirety.


( index:integer ) : string
v1.0.0 and newer

Returns the word of the line at index.

Note: The returned word omits any quotes. This helps generators naturally complete "foo\"ba to "foo\bar". The raw word including quotes can be obtained using the offset and length fields from line_state:getwordinfo() to extract a substring from the line returned by line_state:getline().


() : integer
v1.0.0 and newer

Returns the number of words in the current line.


( index:integer ) : table
v1.0.0 and newer

Returns a table of information about the Nth word in the line.

Note: The length refers to the substring in the line; it omits leading and trailing quotes, but includes embedded quotes. line_state:getword() conveniently strips embedded quotes to help generators naturally complete "foo\"ba to "foo\bar".

The table returned has the following scheme:

local t = line_state:getwordinfo(word_index)
-- t.offset     [integer] Offset where the word starts in the line_state:getline() string.
-- t.length     [integer] Length of the word (includes embedded quotes).
-- t.quoted     [boolean] Indicates whether the word is quoted.
-- t.delim      [string] The delimiter character, or an empty string.
-- t.alias      [boolean | nil] true if the word is a doskey alias, otherwise nil.
-- t.redir      [boolean | nil] true if the word is a redirection arg, otherwise nil.

log
( message:string ) : nil
v1.1.3 and newer

Writes info message to the Clink log file. Use this sparingly, or it could cause performance problems or disk space problems.


matches
() : integer
v1.2.47 and newer

Returns the number of available matches.


( index:integer ) : string
v1.2.47 and newer

Returns the match text for the index match.


() : string
v1.2.47 and newer

Returns the longest common prefix of the available matches.


matches_lua
( index:integer ) : string
v1.2.47 and newer

Returns the match type for the index match.


os
( path:string ) : boolean
v1.0.0 and newer

Changes the current directory to path and returns whether it was successful. If unsuccessful it returns false, an error message, and the error number.


() : number
v1.2.30 and newer

This returns the number of seconds since the program started.

Normally, Lua's os.clock() has millisecond precision until the program has been running for almost 25 days, and then it suddenly breaks and starts always returning -0.001 seconds.

Clink's version of os.clock() has microsecond precision until the program has been running for many weeks. It maintains at least millisecond precision until the program has been running for many years.

It was necessary to replace os.clock() in order for asynchronous prompt filtering to continue working when CMD has been running for more than 25 days.


( src:string, dest:string ) : boolean
v1.0.0 and newer

Copies the src file to the dest file. If unsuccessful it returns false, an error message, and the error number.


( [prefix:string], [ext:string], [path:string], [mode:string] ) : file, string
v1.1.42 and newer

Creates a uniquely named file, intended for use as a temporary file. The name pattern is "location \ prefix _ processId _ uniqueNum extension".

prefix optionally specifies a prefix for the file name and defaults to "tmp".

ext optionally specifies a suffix for the file name and defaults to "" (if ext starts with a period "." then it is a filename extension).

path optionally specifies a path location in which to create the file. The default is the system TEMP directory.

mode optionally specifies "t" for text mode (line endings are translated) or "b" for binary mode (untranslated IO). The default is "t".

When successful, the function returns a file handle and the file name. If unsuccessful it returns nil, an error message, and the error number.

Note: Be sure to delete the file when finished, or it will be leaked.


( ... ) : nil
v1.2.20 and newer

This works like print() but writes the output via the OS OutputDebugString() API.

This function has no effect if the lua.debug Clink setting is off.

clink.debugprint("my variable = "..myvar)

( value:string ) : string
v1.2.5 and newer

Returns value with any %name% environment variables expanded. Names are case insensitive. Special CMD syntax is not supported (e.g. %name:str1=str2% or %name:~offset,length%).

Note: See os.getenv() for a list of special variable names.


( name:string ) : string | nil
v1.1.4 and newer

Returns command string for doskey alias name, or nil if the named alias does not exist.


() : table
v1.0.0 and newer

Returns doskey alias names in a table of strings.


() : table
v1.1.17 and newer

Returns a table containing the battery status for the device, or nil if an error occurs. The returned table has the following scheme:

local t = os.getbatterystatus()
-- t.level              [integer] The battery life from 0 to 100, or -1 if error or no battery.
-- t.acpower            [boolean] Whether the device is connected to AC power.
-- t.charging           [boolean] Whether the battery is charging.
-- t.batterysaver       [boolean] Whether Battery Saver mode is active.

() : string | nil
v1.2.32 and newer

This returns the text from the system clipboard, or nil if there is no text on the system clipboard.


() : string
v1.0.0 and newer

Returns the current directory.


( path:string ) : string
v1.3.37 and newer

Returns the drive type for the drive associated with the specified path.

Relative paths automatically use the current drive. Absolute paths use the specified drive. UNC paths are always reported as remote drives.

The possible drive types are:

TypeDescription
"unknown"The drive type could not be determined.
"invalid"The drive type is invalid; for example, there is no volume mounted at the specified path.
"removable"Floppy disk drive, thumb drive, flash card reader, CD-ROM, etc.
"fixed"Hard drive, solid state drive, etc.
"ramdisk"RAM disk.
"remote"Remote (network) drive.

local t = os.getdrivetype("c:")
if t == "remote" then
    -- Network paths are often slow, and code may want to detect and skip them.
end

( name:string ) : string | nil
v1.0.0 and newer

Returns the value of the named environment variable, or nil if it doesn't exist.

Note: Certain environment variable names receive special treatment:

NameSpecial Behavior
"CD"If %CD% is not set then a return value is synthesized from the current working directory path name.
"CMDCMDLINE"If %CMDCMDLINE% is not set then this returns the command line that started the CMD process.
"ERRORLEVEL"If %ERRORLEVEL% is not set and the cmd.get_errorlevel setting is enabled (it is off by default) this returns the most recent exit code, just like the echo %ERRORLEVEL% command displays. Otherwise this returns 0.
"HOME"If %HOME% is not set then a return value is synthesized from %HOMEDRIVE% and %HOMEPATH%, or from %USERPROFILE%.
"RANDOM"If %RANDOM% is not set then this returns a random integer.


() : table
v1.0.0 and newer

Returns all environment variables in a table with the following scheme:

local t = os.getenvnames()
-- t[index].name        [string] The environment variable's name.
-- t[index].value       [string] The environment variable's value.

() : integer
v1.2.14 and newer

Returns the last command's exit code, if the cmd.get_errorlevel setting is enabled (it is disabled by default). Otherwise it returns 0.


( path:string ) : string
v1.1.42 and newer

Returns the full path name for path. If unsuccessful it returns nil, an error message, and the error number.


() : string
v1.0.0 and newer

Returns the fully qualified file name of the host process. Currently only CMD.EXE can host Clink.


( path:string ) : string
v1.1.42 and newer

Returns the long path name for path. If unsuccessful it returns nil, an error message, and the error number.


( path:string ) : string
v1.2.27 and newer

Returns the remote name associated with path, or an empty string if it's not a network drive. If unsuccessful it returns nil, an error message, and the error number.


() : integer
v1.1.41 and newer

Returns the CMD.EXE process ID. This is mainly intended to help with salting unique resource names (for example named pipes).


() : table
v1.1.2 and newer

Returns dimensions of the terminal's buffer and visible window. The returned table has the following scheme:

local info = os.getscreeninfo()
-- info.bufwidth        [integer] Width of the screen buffer.
-- info.bufheight       [integer] Height of the screen buffer.
-- info.winwidth        [integer] Width of the visible window.
-- info.winheight       [integer] Height of the visible window.

( path:string ) : string
v1.1.42 and newer

Returns the 8.3 short path name for path. This may return the input path if an 8.3 short path name is not available. If unsuccessful it returns nil, an error message, and the error number.


() : string
v1.3.18 and newer

Returns the path of the system temporary directory. If unsuccessful it returns nil, an error message, and the error number.


( globpattern:string, [extrainfo:integer|boolean] ) : table
v1.0.0 and newer

Collects directories matching globpattern and returns them in a table of strings.

The optional extrainfo argument can return a table of tables instead, where each sub-table corresponds to one directory and has the following scheme:

local t = os.globdirs(pattern, extrainfo)
-- Included when extrainfo is true or >= 1 (requires v1.1.7 or higher):
--   t[index].name      -- [string] The directory name.
--   t[index].type      -- [string] The match type (see below).
-- Included when extrainfo is 2 (requires v1.2.31 or higher):
--   t[index].size      -- [number] The file size, in bytes.
--   t[index].atime     -- [number] The access time, compatible with os.time().
--   t[index].mtime     -- [number] The modified time, compatible with os.time().
--   t[index].ctime     -- [number] The creation time, compatible with os.time().

The type string is "dir", and may also contain ",hidden", ",readonly", ",link", and ",orphaned" depending on the attributes (making it usable as a match type for builder:addmatch()).

Starting in v1.3.1, when this is used in a coroutine it automatically yields periodically.

Note: any quotation marks (") in globpattern are stripped.


( globpattern:string, [extrainfo:integer|boolean] ) : table
v1.0.0 and newer

Collects files and/or directories matching globpattern and returns them in a table of strings.

The optional extrainfo argument can return a table of tables instead, where each sub-table corresponds to one file or directory and has the following scheme:

local t = os.globfiles(pattern, extrainfo)
-- Included when extrainfo is true or >= 1 (requires v1.1.7 or higher):
--   t[index].name      -- [string] The file or directory name.
--   t[index].type      -- [string] The match type (see below).
-- Included when extrainfo is 2 (requires v1.2.31 or higher):
--   t[index].size      -- [number] The file size, in bytes.
--   t[index].atime     -- [number] The access time, compatible with os.time().
--   t[index].mtime     -- [number] The modified time, compatible with os.time().
--   t[index].ctime     -- [number] The creation time, compatible with os.time().

The type string can be "file" or "dir", and may also contain ",hidden", ",readonly", ",link", and ",orphaned" depending on the attributes (making it usable as a match type for builder:addmatch()).

Starting in v1.3.1, when this is used in a coroutine it automatically yields periodically.

Note: any quotation marks (") in globpattern are stripped.


( path:string ) : boolean
v1.0.0 and newer

Returns whether path is a directory.


( path:string ) : boolean
v1.0.0 and newer

Returns whether path is a file.


() : boolean
v1.3.14 and newer

Returns whether a Ctrl+Break has been received. Scripts may use this to decide when to end work early.


( path:string ) : boolean
v1.0.0 and newer

Creates the directory path and returns whether it was successful. If unsuccessful it returns false, an error message, and the error number.


( src:string, dest:string ) : boolean
v1.0.0 and newer

Moves the src file to the dest file. If unsuccessful it returns false, an error message, and the error number.


( text:string ) : table|nil
v1.3.12 and newer

Identifies whether text begins with a doskey alias, and expands the doskey alias.

Returns a table of strings, or nil if there is no associated doskey alias. The return type is a table of strings because doskey aliases can be defined to expand into multiple command lines: one entry in the table per resolved command line. Most commonly, the table will contain one string.


( path:string ) : boolean
v1.0.0 and newer

Removes the directory path and returns whether it was successful. If unsuccessful it returns false, an error message, and the error number.


() : boolean
v1.2.32 and newer

This sets the text onto the system clipboard, and returns whether it was successful.


( name:string, value:string ) : boolean
v1.0.0 and newer

Sets the name environment variable to value and returns whether it was successful. If unsuccessful it returns false, an error message, and the error number.


( seconds:number ) : nil
v1.3.16 and newer

Sleeps for the indicated duration, in seconds, with millisecond granularity.

os.sleep(0.01)  -- Sleep for 10 milliseconds.

( path:string, [atime:number], [mtime:number] ) : boolean
v1.2.31 and newer

Sets the access and modified times for path, and returns whether it was successful. If unsuccessful it returns false, an error message, and the error number.

The second argument is atime and is a time to set as the file's access time. If omitted, the current time is used. If present, the value must use the same format as os.time().

The third argument is mtime and is a time to set as the file's modified time. If omitted, the atime value is used (or the current time). If present, the value must use the same format as os.time(). In order to pass mtime it is necessary to also pass atime.


( path:string ) : boolean
v1.0.0 and newer

Deletes the file path and returns whether it was successful. If unsuccessful it returns false, an error message, and the error number.


path
( path:string ) : string
v1.1.0 and newer

path.getbasename("/foo/bar.ext")    -- returns "bar"
path.getbasename("")                -- returns ""

( path:string ) : nil or string
v1.1.0 and newer

This is similar to path.toparent() but can behave differently when the input path ends with a path separator. This is the recommended API for parsing a path into its component pieces, but is not recommended for walking up through parent directories.

path.getdirectory("foo")                -- returns nil
path.getdirectory("\foo")               -- returns "\"
path.getdirectory("c:foo")              -- returns "c:"
path.getdirectory([[c:\]])              -- returns "c:\"
path.getdirectory("c:\foo")             -- returns "c:\"
path.getdirectory("c:\foo\bar")         -- returns "c:\foo"
path.getdirectory("\\foo\bar")          -- returns "\\foo\bar"
path.getdirectory("\\foo\bar\dir")      -- returns "\\foo\bar"
path.getdirectory("")                   -- returns nil

-- These split the path components differently than path.toparent().
path.getdirectory([[c:\foo\bar\]])      -- returns "c:\foo\bar"
path.getdirectory([[\\foo\bar\dir\]])   -- returns "\\foo\bar\dir"

( path:string ) : nil or string
v1.1.0 and newer

path.getdrive("e:/foo/bar")     -- returns "e:"
path.getdrive("foo/bar")        -- returns nil
path.getdrive("")               -- returns nil

( path:string ) : string
v1.1.0 and newer

path.getextension("bar.ext")    -- returns ".ext"
path.getextension("bar")        -- returns ""
path.getextension("")           -- returns ""

( path:string ) : string
v1.1.0 and newer

path.getname("/foo/bar.ext")    -- returns "bar.ext"
path.getname("")                -- returns ""

( path:string ) : boolean
v1.1.5 and newer

Examines the extension of the path name. Returns true if the extension is listed in %PATHEXT%. This caches the extensions in a map so that it's more efficient than getting and parsing %PATHEXT% each time.

path.isexecext("program.exe")   -- returns true
path.isexecext("file.doc")      -- returns false
path.isexecext("")              -- returns false

( left:string, right:string ) : string
v1.1.0 and newer

If right is a relative path, this joins left and right.

If right is not a relative path, this returns right.

path.join("/foo", "bar")        -- returns "/foo\bar"
path.join("", "bar")            -- returns "bar"
path.join("/foo", "")           -- returns "/foo\"
path.join("/foo", "/bar/xyz")   -- returns "/bar/xyz"

( path:string, [separator:string] ) : string
v1.1.0 and newer

Cleans path by normalising separators and removing "." and ".." elements. If separator is provided it is used to delimit path elements, otherwise a system-specific delimiter is used.

path.normalise("a////b/\\/c/")  -- returns "a\b\c\"
path.normalise("")              -- returns ""

( path:string ) : parent:string, child:string
v1.1.20 and newer

Splits the last path component from path, if possible. Returns the result and the component that was split, if any.

This is similar to path.getdirectory() but can behave differently when the input path ends with a path separator. This is the recommended API for walking up through parent directories.

local parent,child
parent,child = path.toparent("foo")             -- returns "", "foo"
parent,child = path.toparent("\foo")            -- returns "\", "foo"
parent,child = path.toparent("c:foo")           -- returns "c:", "foo"
parent,child = path.toparent([[c:\]])           -- returns "c:\", ""
parent,child = path.toparent("c:\foo")          -- returns "c:\", "foo"
parent,child = path.toparent("c:\foo\bar")      -- returns "c:\foo", "bar"
parent,child = path.toparent("\\foo\bar")       -- returns "\\foo\bar", ""
parent,child = path.toparent("\\foo\bar\dir")   -- returns "\\foo\bar", "dir"
parent,child = path.toparent("")                -- returns "", ""

-- These split the path components differently than path.getdirectory().
parent,child = path.toparent([[c:\foo\bar\]])   -- returns "c:\foo", "bar"
parent,child = path.toparent([[\\foo\bar\dir\]])-- returns "\\foo\bar", "dir"

rl
( path:string, [force:boolean] ) : string
v1.1.6 and newer

Undoes Readline tilde expansion. See rl.expandtilde() for more information.

rl.collapsetilde("C:\Users\yourusername\Documents")
 
-- The return value depends on the expand-tilde configuration variable:
-- When "on", the function returns "C:\Users\yourusername\Documents".
-- When "off", the function returns "~\Documents".
 
-- Or when force is true, the function returns "~\Documents".

( macro:string, description:string ) : nil
v1.3.41 and newer

This associates description with macro, to be displayed in the clink-show-help and clink-what-is commands.

This may be used to add a description for a luafunc: macro, or for a keyboard macro.

The macro string should include quotes, just like in rl.setbinding(). If quotes are not present, they are added automatically.

rl.describemacro([["luafunc:mycommand"]], "Does whatever mycommand does")
rl.describemacro([["\e[Hrem "]], "Insert 'rem ' at the beginning of the line")
rl.setbinding([["\C-o"]], [["luafunc:mycommand"]])
rl.setbinding([["\C-r"]], [["\e[Hrem "]])
-- Press Alt-H to see the list of key bindings and descriptions.

( path:string, [whole_line:boolean] ) : string, boolean
v1.1.6 and newer

Performs Readline tilde expansion.

When generating filename matches for a word, use the rl.expandtilde() and rl.collapsetilde() helper functions to perform tilde completion expansion according to Readline's configuration.

An optional whole_line argument selects whether to expand tildes everywhere in the input string (pass true), or to expand only a tilde at the beginning of the input string (pass false or omit the second argument). See the Compatibility Note below for more information.

Use rl.expandtilde() to do tilde expansion before collecting file matches (e.g. via os.globfiles()). If it indicates that it expanded the string, then use rl.collapsetilde() to put back the tilde before returning a match.

local result, expanded = rl.expandtilde("~\Documents")
-- result is "C:\Users\yourusername\Documents"
-- expanded is true

-- This dir_matches function demonstrates efficient use of rl.expandtilde()
-- and rl.collapsetilde() to generate directory matches from the file system.
function dir_matches(match_word, word_index, line_state)
    -- Expand tilde before scanning file system.
    local word = line_state:getword(word_index)
    local expanded
    word, expanded = rl.expandtilde(word)

    -- Get the directory from 'word', and collapse tilde before generating
    -- matches.  Notice that collapsetilde() only needs to be called once!
    local root = path.getdirectory(word) or ""
    if expanded then
        root = rl.collapsetilde(root)
    end

    local matches = {}
    for _, d in ipairs(os.globdirs(word.."*", true)) do
        -- Join the filename with the input directory (might have a tilde).
        local dir = path.join(root, d.name)
        table.insert(matches, { match = dir, type = d.type })
    end
    return matches
end

Compatibility Note: The original intended usage for this function was to expand tildes in a single word. But sometimes it may be convenient to expand tildes for an entire command line all at once.

Prior to v1.3.36, this function simply asked the Readline library to expand tildes, but that mode of operation doesn't respect quotes and has quirks that can produce unexpected results when the input is a single pathname (which was the documented supported usage).

In v1.3.36 this function fixed that problem, and expands tildes correctly a single pathname as the input (and also accepts quotes). But that broke an undocumented quirk that could expand tildes for a whole command line as the input.

In v1.3.37 and newer, this function accepts a boolean second argument which selects whether to expand for a whole input line using the quirky Readline tilde expansion (pass true), or to expand for a single pathname as the input (pass false or omit the second argument).

Passing true for the second argument causes any version of Clink (except v1.3.36) to expand the input as a whole command line.


( key:string, [keymap:string] ) : binding:string, type:string
v1.2.46 and newer

Returns the command or macro bound to key, and the type of the binding.

If nothing is bound to the specified key sequence, the returned binding will be nil.

The returned type can be "function", "macro", or "keymap" (if key is an incomplete key sequence).

If an error occurs, only nil is returned.

The key sequence string is the same format as from clink echo. See Discovering Clink key sindings for more information.

An optional keymap may be specified as well. If it is omitted or nil, then the current keymap is searched. Otherwise it may refer to one of the three built in keymaps:
KeymapDescription
"emacs"The Emacs keymap, which is the default keymap.
"vi", "vi-move", or "vi-command"The VI command mode keymap.
"vi-insert"The VI insertion mode keymap.

The return value can be passed as input to rl.setbinding() or rl.invokecommand().

local b,t = rl.getbinding([["\e[H"]], "emacs")
if b then
    print("Home is bound to "..b.." ("..t..") in emacs mode.")
else
    print("Home is not bound in emacs mode.")
end

() : integer
v1.3.18 and newer

Returns the number of history items.


() : start:integer
v1.3.18 and newer

Returns a table of history items.

The first history item is 1, and the last history item is rl.gethistorycount(). For best performance, use start and end to request only the range of history items that will be needed.

Each history item is a table with the following scheme:

local h = rl.gethistoryitems(1, rl.gethistorycount())
-- h.line       [string] The item's command line string.
-- h.time       [integer or nil] The item's time, compatible with os.time().

Note: the time field is omitted if the history item does not have an associated time.


( raw:boolean, [mode:integer] ) : table
v1.2.16 and newer

Returns key bindings in a table with the following scheme:

local t = rl.getkeybindings()
-- t[index].key         [string] Key name.
-- t[index].binding     [string] Command or macro bound to the key.
-- t[index].desc        [string] Description of the command.
-- t[index].category    [string] Category of the command.

When raw is true, the key names are the literal key sequences without being converted to user-friendly key names.

The optional mode specifies bit flags that control how the returned table is sorted, and whether it includes commands that are not bound to any key.

ModeDescription
0Key bindings, sorted by key (this is the default).
1Key bindings, sorted by category and then key.
4All commands, sorted by key.
5All commands, sorted by category and then key.

The following example demonstrates using this function in a luafunc: key binding to invoke clink.popuplist() to show a searchable list of key bindings, and then invoke whichever key binding is selected.

function luafunc_showkeybindings(rl_buffer)
    local bindings = rl.getkeybindings()
    if #bindings <= 0 then
        rl_buffer:refreshline()
        return
    end

    local items = {}
    for _,kb in ipairs(bindings) do
        table.insert(items, {
            value = kb.binding,     -- Return the binding when selected, so it can be invoked.
            display = kb.key,       -- Display the key name.
            description = kb.binding.."\t"..kb.desc -- Also display the command and description.
        })
    end

    -- Show a popup that lists the items from above.
    local binding, _, index = clink.popuplist("Key Bindings", items)
    rl_buffer:refreshline()
    if binding then
        -- Invoke the selected binding (a command or macro).
        rl.invokecommand(binding)
    end
end

() : string, function
v1.1.40 and newer

Returns two values:

  • The name of the last Readline command invoked by a key binding.
  • The name of the last Lua function invoked by a key binding.

If the last key binding invoked a Lua function, then the first return value is an empty string unless the Lua function used rl.invokecommand() to also internally invoke a Readline command. If the last key binding did not invoke a Lua function, then the second return value is an empty string.

local last_rl_func, last_lua_func = rl.getlastcommand()

( match:string|table, [type:string] ) : string
v1.3.4 and newer

Returns the color string associated with the match.

The arguments are the same as in builder:addmatch().


() : table
v1.2.28 and newer

Returns information about the current prompt and input line.

Note: the promptline and inputline fields may be skewed if any additional terminal output has occurred (for example if any print() calls have happened, or if rl.getpromptinfo() is used inside a clink.onendedit() event handler, or any other output that the Readline library wouldn't know about).

The returned table has the following scheme:

local info = rl.getpromptinfo()
-- info.promptprefix              [string] The prompt string, minus the last line of the prompt string.
-- info.promptprefixlinecount     [integer] Number of lines in the promptprefix string.
-- info.prompt                    [string] The last line of the prompt string.
-- info.rprompt                   [string or nil] The right side prompt (or nil if none).
-- info.promptline                [integer] Console line on which the prompt starts.
-- info.inputline                 [integer] Console line on which the input text starts.
-- info.inputlinecount            [integer] Number of lines in the input text.

( name:string ) : string | nil
v1.1.6 and newer

Returns the value of the named Readline configuration variable as a string, or nil if the variable name is not recognized.


( [insert:boolean] ) : boolean
v1.2.50 and newer

Returns true when typing insertion mode is on.

When the optional insert argument is passed, this also sets typing insertion mode on or off accordingly.


( command:string, [count:integer] ) : boolean | nil
v1.1.26 and newer

Invokes a Readline command named command. May only be used within a luafunc: key binding.

count is optional and defaults to 1 if omitted.

Returns true if the named command succeeds, false if the named command fails, or nil if the named command doesn't exist.

Warning: Invoking more than one Readline command in a luafunc: key binding could have unexpected results, depending on which commands are invoked.


() : boolean
v1.2.51 and newer

Returns true when the current input line is a history entry that has been modified (i.e. has an undo list).

This enables prompt filters to show a "modmark" of their own, as an alternative to the modmark shown when the mark-modified-lines Readline config setting is enabled.

The following sample illustrates a prompt filter that shows a "modified line" indicator when the current line is a history entry and has been modified.

local p = clink.promptfilter(10)
local normal = "\x1b[m"

local function get_settings_color(name)
    return "\x1b[" .. settings.get(name) .. "m"
end

function p:filter(prompt)
    prompt = os.getcwd()
    if rl.ismodifiedline() then
        -- If the current line is a history entry and has been modified,
        -- then show an indicator.
        prompt = get_settings_color("color.modmark") .. "*" .. normal .. " " .. prompt
    end
    prompt = prompt .. "\n$ "
    return prompt
end

local last_modmark = false

local function modmark_reset()
    -- Reset the remembered state at the beginning of each edit line.
    last_modmark = rl.ismodifiedline()

    -- Turn off `mark-modified-lines` to avoid two modmarks showing up.
    rl.setvariable("mark-modified-lines", "off")
end

local function modmark_refilter()
    -- If the modmark state has changed, refresh the prompt.
    if last_modmark ~= rl.ismodifiedline() then
        last_modmark = rl.ismodifiedline()
        clink.refilterprompt()
    end
end

clink.onbeginedit(modmark_reset)
clink.onaftercommand(modmark_refilter)

( name:string ) : boolean | nil
v1.1.6 and newer

Returns a boolean value indicating whether the named Readline configuration variable is set to true (on), or nil if the variable name is not recognized.


( key:string, binding:string | nil, [keymap:string] ) : boolean
v1.2.46 and newer

Binds key to invoke binding, and returns whether it was successful.

The key sequence string is the same format as from clink echo. See Discovering Clink key sindings for more information.

The binding is either the name of a Readline command, a quoted macro string (just like in the .inputrc config file), or nil to clear the key binding.

An optional keymap may be specified as well. If it is omitted or nil, then the current keymap is searched. Otherwise it may refer to one of the three built in keymaps:
KeymapDescription
"emacs"The Emacs keymap, which is the default keymap.
"vi", "vi-move", or "vi-command"The VI command mode keymap.
"vi-insert"The VI insertion mode keymap.

Using Lua's [[..]] string syntax conveniently lets you simply copy the key string exactly from the clink echo output, without needing to translate the quotes or backslashes.

Note: This does not write the value into a config file. Instead it updates the key binding in memory, temporarily overriding whatever is present in any config files. When config files are reloaded, they may replace the key binding again.

local old_space = rl.getbinding('" "')
function hijack_space(rl_buffer)
    rl.invokecommand("clink-expand-line")   -- Expand envvars, etc in the line.
    rl.invokecommand(old_space)             -- Then invoke whatever was previously bound to Space.
end
rl.setbinding([[" "]], [["luafunc:hijack_space"]])

-- The [[]] string syntax lets you copy key strings directly from 'clink echo'.
-- [["\e[H"]] is much easier than translating to "\"\\e[H\"", for example.
rl.setbinding([["\e[H"]], [[beginning-of-line]])

( matches:table, [type:string] ) : integer, boolean
v1.1.40 and newer

Provides an alternative set of matches for the current word. This discards any matches that may have already been collected and uses matches for subsequent Readline completion commands until any action that normally resets the matches (such as moving the cursor or editing the input line).

May only be used within a luafunc: key binding.

The syntax is the same as for builder:addmatches() with one addition: You can add a "nosort" key to the matches table to disable sorting the matches.

local matches = {}
matches["nosort"] = true
rl.setmatches(matches)

This function can be used by a luafunc: key binding to provide matches based on some special criteria. For example, a key binding could collect numbers from the current screen buffer (such as issue numbers, commit hashes, line numbers, etc) and provide them to Readline as matches, making it convenient to grab a number from the screen and insert it as a command line argument.

Match display filtering is also possible by using clink.ondisplaymatches() after setting the matches.

Example .inputrc key binding:

M-n:            "luafunc:completenumbers"       # Alt+N

Example Lua function:

function completenumbers()
    local _,last_luafunc = rl.getlastcommand()
    if last_luafunc ~= "completenumbers" then
        -- Collect numbers from the screen (minimum of three digits).
        -- The numbers can be any base up to hexadecimal (decimal, octal, etc).
        local matches = console.screengrab("[^%w]*(%w%w[%w]+)", "^%x+$")
        -- They're already sorted by distance from the input line.
        matches["nosort"] = true
        rl.setmatches(matches)
    end

    rl.invokecommand("old-menu-complete")
end

( name:string, value:string ) : boolean
v1.1.46 and newer

Temporarily overrides the named Readline configuration variable to the specified value. The return value reports whether it was successful, or is nil if the variable name is not recognized.

Note: This does not write the value into a config file. Instead it updates the variable in memory, temporarily overriding whatever is present in any config files. When config files are reloaded, they may replace the value again.


rl_buffer
() : nil
v1.1.20 and newer

Advances the output cursor to the next line after the Readline input buffer so that subsequent output doesn't overwrite the input buffer display.


() : nil
v1.1.20 and newer

Starts a new undo group. This is useful for grouping together multiple editing actions into a single undo operation.


() : nil
v1.1.20 and newer

Dings the bell. If the bell-style Readline variable is visible then it flashes the cursor instead.


() : nil
v1.1.20 and newer

Ends an undo group. This is useful for grouping together multiple editing actions into a single undo operation.

Note: all undo groups are automatically ended when a key binding finishes execution, so this function is only needed if a key binding needs to create more than one undo group.


() : integer | nil
v1.2.35 and newer

Returns the anchor position of the currently selected text in the input line, or nil if there is no selection. The value can be from 1 to rl_buffer:getlength() + 1. It can exceed the length of the input line because the anchor can be positioned just past the end of the input line.


() : integer | nil
v1.2.22 and newer

Returns any accumulated numeric argument (Alt+Digits, etc), or nil if no numeric argument has been entered.


() : string
v1.0.0 and newer

Returns the current input line.


() : integer
v1.1.20 and newer

Returns the cursor position in the input line. The value can be from 1 to rl_buffer:getlength() + 1. It can exceed the length of the input line because the cursor can be positioned just past the end of the input line.

Note: In v1.1.20 through v1.2.31 this accidentally returned 1 less than the actual cursor position. In v1.2.32 and higher it returns the correct cursor position.


() : integer
v1.1.20 and newer

Returns the length of the input line.


( text:string ) : nil
v1.1.20 and newer

Inserts text at the cursor position in the input line.


() : nil
v1.1.41 and newer

Redraws the input line.


( from:integer, to:integer ) : nil
v1.1.20 and newer

Removes text from the input line starting at cursor position from through to.

Note: the input line is UTF8, and removing only part of a multi-byte Unicode character may have undesirable results.


( argument:integer | nil ) : nil
v1.2.32 and newer

When argument is a number, it is set as the numeric argument for use by Readline commands (as entered using Alt+Digits, etc). When argument is nil, the numeric argument is cleared (having no numeric argument is different from having 0 as the numeric argument).


( cursor:integer ) : integer
v1.1.20 and newer

Sets the cursor position in the input line and returns the previous cursor position. cursor can be from 1 to rl_buffer:getlength() + 1. It can exceed the length of the input line because the cursor can be positioned just past the end of the input line.

Note: the input line is UTF8, and setting the cursor position inside a multi-byte Unicode character may have undesirable results.

Note: In v1.1.20 through v1.2.31 this accidentally returned 1 less than the actual cursor position. In v1.2.32 and higher it returns the correct cursor position.


settings
( name:string, default:..., [short_desc:string], [long_desc:string] ) : boolean
v1.0.0 and newer

Adds a setting to the list of Clink settings and includes it in clink set. The new setting is named name and has a default value default when the setting isn't explicitly set.

The type of default determines what kind of setting is added: boolean, integer, and string values add the corresponding setting type. Or if the type is table then an enum setting is added: the table defines the accepted values, and the first value is the default value. Or if it's a string type and the name starts with "color." then a color setting is added.

name can't be more than 32 characters.

short_desc is an optional quick summary description and can't be more than 48 characters.

long_desc is an optional long description.

settings.add("myscript.myabc", true, "Boolean setting")
settings.add("myscript.mydef", 100, "Number setting")
settings.add("myscript.myghi", "abc", "String setting")
settings.add("myscript.myjkl", {"x","y","z"}, "Enum setting")
settings.add("color.mymno", "bright magenta", "Color setting")

( name:string, [descriptive:boolean] ) : boolean or string or integer
v1.0.0 and newer

Returns the current value of the name Clink setting.

If it's a color setting and the optional descriptive parameter is true then the user friendly color name is returned.


( name:string, value:string ) : boolean
v1.0.0 and newer

Sets the name Clink setting to value and returns whether it was successful.

Note: Beginning in Clink v1.2.31 this updates the settings file. Prior to that, it was necessary to separately use clink set to update the settings file.


string
( a:string, [a_type:string], b:string, [b_type:string] ) : boolean
v1.3.41 and newer

Returns true if a sorts as "less than" b.

The a_type and b_type are optional, and affect the sort order accordingly when present.

This produces the same sort order as normally used for displaying matches. This can be used for manually sorting a subset of matches when a match builder has been told not to sort the list of matches.

local files = {
    { match="xyzFile", type="file" },
    { match="abcFile", type="file" },
}
local other = {
    { match="abc_branch", type="arg" },
    { match="xyz_branch", type="arg" },
    { match="mno_tag", type="alias" },
}

local function comparator(a, b)
    return string.comparematches(a.match, a.type, b.match, b.type)
end

-- Sort files.
table.sort(files, comparator)

-- Sort branches and tags together.
table.sort(other, comparator)

match_builder:setnosort()           -- Disable automatic sorting.
match_builder:addmatches(files)     -- Add the sorted files.
match_builder:addmatches(other)     -- Add the branches and tags files.

-- The overall sort order ends up listing all the files in sorted
-- order, followed by branches and tags sorted together.

( a:string, b:string ) : boolean
v1.1.20 and newer

Performs a case insensitive comparison of the strings with international linguistic awareness. This is more efficient than converting both strings to lowercase and comparing the results.


( text:string, [delims:string], [quote_pair:string] ) : table
v1.0.0 and newer

Splits text delimited by delims (or by spaces if not provided) and returns a table containing the substrings.

The optional quote_pair can provide a beginning quote character and an ending quote character. If only one character is provided it is used as both a beginning and ending quote character.


( text:string ) : integer
v1.0.0 and newer

Returns a hash of the input text.


( a:string, b:string ) : integer
v1.1.20 and newer

Returns how many characters match at the beginning of the strings, or -1 if the entire strings match. This respects the match.ignore_case and match.ignore_accents Clink settings.

string.matchlen("abx", "a")         -- returns 1
string.matchlen("abx", "aby")       -- returns 2
string.matchlen("abx", "abx")       -- returns -1

unicode
( text:string, [codepage:integer] ) : string | nil
v1.3.27 and newer

This converts text from the codepage encoding to UTF8.

When codepage is omitted, the current Active Code Page is used.

If the text cannot be converted, nil is returned.

Note: Clink uses UTF8 internally, and conversion to/from other encodings is intended for use with file input/output or network input/output.


( form:integer, text:string ) : boolean [, integer]
v1.3.26 and newer

Returns whether text is already normalized according to the Unicode normalization form:

  • 1 is Unicode normalization form C, canonical composition. Transforms each base character + combining characters into the precomposed equivalent. For example, A + umlaut becomes Ä.
  • 2 is Unicode normalization form D, canonical decomposition. Transforms each precomposed character into base character + combining characters. For example, Ä becomes A + umlaut.
  • 3 is Unicode normalization form KC, compatibility composition. Transforms each base character + combining characters into the precomposed equivalent, and transforms compatibility characters into their equivalents. For example, A + umlaut + ligature for "fi" becomes Ä + f + i.
  • 4 is Unicode normalization form KD, compatibility decomposition. Transforms each precomposed character into base character + combining characters, and transforms compatibility characters to their equivalents. For example, Ä + ligature for "fi" becomes A + umlaut + f + i.

If successful, true or false is returned.

If unsuccessful, false and an error code are returned.


( text:string ) : iterator
v1.3.26 and newer

This returns an iterator which steps through text one Unicode codepoint at a time. Each call to the iterator returns the string for the next codepoint, the numeric value of the codepoint, and a boolean indicating whether the codepoint is a combining mark.

-- UTF8 sample string:
-- Index by codepoint:   1       2       3           4       5
-- Unicode character:    à       é       ᴆ           õ       û
local text            = "\xc3\xa0\xc3\xa9\xe1\xb4\x86\xc3\xb5\xc3\xbb"
-- Index by byte:        1   2   3   4   5   6   7   8   9   10  11

for str, value, combining in unicode.iter(text) do
    -- Note that the default lua print() function is not fully aware
    -- of Unicode, so clink.print() is needed to print Unicode text.
    local bytes = ""
    for i = 1, #str do
        bytes = bytes .. string.format("\\x%02x", str:byte(i, i))
    end
    clink.print(str, value, combining, bytes)
end

-- The above prints the following:
--      à       224     false   \xc3\xa0
--      é       233     false   \xc3\xa9
--      ᴆ       7430    false   \xe1\xb4\x86
--      õ       245     false   \xc3\xb5
--      û       373     false   \xc3\xbb

( form:integer, text:string ) : string [, integer]
v1.3.26 and newer

Transforms the text according to the Unicode normalization form:

  • 1 is Unicode normalization form C, canonical composition. Transforms each base character + combining characters into the precomposed equivalent. For example, A + umlaut becomes Ä.
  • 2 is Unicode normalization form D, canonical decomposition. Transforms each precomposed character into base character + combining characters. For example, Ä becomes A + umlaut.
  • 3 is Unicode normalization form KC, compatibility composition. Transforms each base character + combining characters into the precomposed equivalent, and transforms compatibility characters into their equivalents. For example, A + umlaut + ligature for "fi" becomes Ä + f + i.
  • 4 is Unicode normalization form KD, compatibility decomposition. Transforms each precomposed character into base character + combining characters, and transforms compatibility characters to their equivalents. For example, Ä + ligature for "fi" becomes A + umlaut + f + i.

If successful, the resulting string is returned.

If unsuccessful, both the original string and an error code are returned.


( text:string, [codepage:integer] ) : string | nil
v1.3.27 and newer

This converts text from UTF8 to the codepage encoding.

When codepage is omitted, the current Active Code Page is used.

If the text cannot be converted, nil is returned.

Note: Clink uses UTF8 internally, and conversion to/from other encodings is intended for use with file input/output or network input/output.


word_classifications
( start:integer, length:integer, color:string, [overwrite:boolean] ) : nil
v1.1.49 and newer

Applies an ANSI SGR escape code to some characters in the input line.

start is where to begin applying the SGR code.

length is the number of characters to affect.

color is the SGR parameters sequence to apply (for example "7" is the code for reverse video, which swaps the foreground and background colors).

By default the color is applied to the characters even if some of them are already colored. But if overwrite is false each character is only colored if it hasn't been yet.

See Coloring the Input Text for more information.

Note: an input line can have up to 100 different unique color strings applied, and then this stops applying new colors. The counter gets reset when the onbeginedit event is sent.


( word_index:integer, word_class:string, [overwrite:boolean] ) : nil
v1.1.18 and newer

This classifies the indicated word so that it can be colored appropriately.

The word_class is one of the following codes:

CodeClassificationClink Color Setting
"a"Argument; used for words that match a list of preset argument matches.color.arg or color.input
"c"Shell command; used for CMD command names.color.cmd
"d"Doskey alias.color.doskey
"f"Flag; used for flags that match a list of preset flag matches.color.flag
"x"Executable; used for the first word when it is not a command or doskey alias, but is an executable name that exists.color.executable
"u"Unrecognized; used for the first word when it is not a command, doskey alias, or recognized executable name.color.unrecognized
"o"Other; used for file names and words that don't fit any of the other classifications.color.input
"n"None; used for words that aren't recognized as part of the expected input syntax.color.unexpected
"m"Prefix that can be combined with another code (for the first word) to indicate the command has an argmatcher (e.g. "mc" or "md").color.argmatcher or the other code's color

By default the classification is applied to the word even if the word has already been classified. But if overwrite is false the word is only classified if it hasn't been yet.

See Coloring the Input Text for more information.


[other]
( [message:string], [lines:integer], [force:boolean] ) : nil
v1.0.0 and newer

Breaks into the Lua debugger, if the lua.debug setting is enabled.

If pause() is used by itself, the debugger breaks on the line after the pause call.

The message argument can be a message the debugger will display, for example to differentiate between multiple pause calls.

The lines argument indicates how many lines to step further before breaking into the debugger. The default is nil, which breaks on the line immediately following the pause call. Passing an integer value will step some number of lines before breaking (this will produce confusing results and is discouraged).

When the force argument is true then it will break into the debugger even if the poff debugger command has been used to turn off the pause command.


Deprecated

Deprecated; don't use this. See _argmatcher:addarg for more information.

Adds one argument slot per table passed to it (as v0.4.9 did).

Note: v1.3.10 and lower :add_arguments() mistakenly added all arguments into the first argument slot.


Deprecated; don't use this. See _argmatcher:addflags for more information.


Deprecated; don't use this.


Deprecated; don't use this. See _argmatcher:nofiles for more information.


( choices...:string|table ) : self

Deprecated; don't use this. See _argmatcher:addarg for more information.

Sets one argument slot per table passed to it (as v0.4.9 did).

Note: v1.3.10 and lower :add_arguments() mistakenly set all arguments into the first argument slot.


( flags...:string ) : self

Deprecated; don't use this. See _argmatcher:addflags for more information.

Note: The new API has no way to remove flags that were previously added, so converting from :set_flags() to :addflags() may require the calling script to reorganize how and when it adds flags.


( match:string ) : nil

Deprecated; don't use this. See builder:addmatch for more information.

This is a shim that lets clink.register_match_generator continue to work for now, despite being obsolete.


( coroutine:coroutine, [interval:number] ) : nil
v1.2.10 and newer

Deprecated; don't use this. See clink.setcoroutineinterval for more information.

Prior to v1.3.1 this was undocumented, and coroutines had to be manually added in order to be scheduled for resume while waiting for input. Starting in v1.3.1 this is no longer necessary, but it can still be used to override the interval at which to resume the coroutine.


( ... ) : table

Deprecated; don't use this. See clink.argmatcher for more information.

Creates a new parser and adds ... to it.

-- Deprecated form:
local parser = clink.arg.new_parser(
  { "abc", "def" },       -- arg position 1
  { "ghi", "jkl" },       -- arg position 2
  "--flag1", "--flag2"    -- flags
)

-- Replace with form:
local parser = clink.argmatcher()
:addarg("abc", "def")               -- arg position 1
:addarg("ghi", "jkl")               -- arg position 2
:addflags("--flag1", "--flag2")     -- flags

( cmd:string, parser:table ) : table

Deprecated; don't use this. See clink.argmatcher for more information.

Adds parser to the argmatcher for cmd.

If there is already an argmatcher for cmd then the two argmatchers are merged. It is only a simple merge; a more sophisticated merge would be much slower and use much more memory. The simple merge should be sufficient for common simple cases.

Note: In v1.3.11, merging parsers should be a bit improved compared to how v0.4.9 merging worked. In v1.0 through v1.3.10, merging parsers doesn't work very well.

-- Deprecated form:
local parser1 = clink.arg.new_parser():set_arguments({ "abc", "def" }, { "old_second" })
local parser2 = clink.arg.new_parser():set_arguments({ "ghi", "jkl" }, { "new_second" })
clink.arg.register_parser("foo", parser1)
clink.arg.register_parser("foo", parser2)
-- In v0.4.9 that syntax only merged the first argument position, and "ghi" and
-- "jkl" ended up with no further arguments.  In v1.3.11 and higher that syntax
-- ends up with "ghi" and "jkl" having only "old_second" as a second argument.

-- Replace with new form:
clink.argmatcher("foo"):addarg(parser1)
clink.argmatcher("foo"):addarg(parser2)
-- In v1.3.11 and higher this syntax ends up with all 4 first argument strings
-- having both "old_second" and "new_second" as a second argument.

( text:string, matches:table ) : string

Deprecated; don't use this.

This is no longer supported, and always returns an empty string.


( index:integer ) : string

Deprecated; don't use this.

This is no longer supported, and always returns an empty string. If a script needs to access matches it added, the script should keep track of the matches itself.


( needle:string, candidate:string ) : boolean

Deprecated; don't use this. See clink.generator for more information.

This returns true if needle is a prefix of candidate with a case insensitive comparison.

Normally in Clink v1.x and higher the needle will be an empty string because the generators are no longer responsible for filtering matches. The match pipeline itself handles that internally now.


( matches:table ) : boolean

Deprecated; don't use this.

This is no longer supported, and always returns false.


() : integer

Deprecated; don't use this.

This is no longer supported, and always returns 0. If a script needs to know how many matches it added, the script should keep track of the count itself.


function variable

Deprecated; don't use this. See clink.ondisplaymatches for more information.

A match generator can set this varible to a filter function that is called before displaying matches. It is reset every time match generation is invoked. The filter function receives table argument containing the matches that are going to be displayed, and it returns a table filtered as required by the match generator.

See Filtering the Match Display for more information.


function variable

Deprecated; don't use this. See builder:addmatch for more information.

This is no longer used.

clink.match_display_filter = function(matches)
  -- Transform matches.
  return matches
end

( pattern:string, [full_path:boolean], [find_func:function] ) : nil

Deprecated; don't use this. See clink.filematches for more information.


( text:string, words:table ) : nil

Deprecated; don't use this. See builder:addmatches for more information.

This adds words that match the text.


( [files:boolean] ) : nil

Deprecated; don't use this. See builder:addmatch for more information.

This is only needed when using deprecated APIs. It's automatically inferred from the match type when using the current APIs.


( filter_func:function, [priority:integer] ) : table

Deprecated; don't use this. See clink.promptfilter for more information.

Registers a prompt filter function. The capabilities are the same as before but the syntax is changed.

-- Deprecated form:
function foo_prompt()
  clink.prompt.value = "FOO "..clink.prompt.value.." >>"
  --return true  -- Returning true stops further filtering.
end
clink.prompt.register_filter(foo_prompt, 10)

-- Replace with new form:
local foo_prompt = clink.promptfilter(10)
function foo_prompt:filter(prompt)
  return "FOO "..prompt.." >>" --,false  -- Adding ,false stops further filtering.
end

( str:string, ql:string, qr:string ) : table

Deprecated; don't use this.


( func:function, priority:integer ) : nil

Deprecated; don't use this. See clink.generator for more information.

Registers a generator function for producing matches. This behaves similarly to v0.4.8, but not identically. The Clink schema has changed significantly enough that there is no direct 1:1 translation; generators are called at a different time than before and have access to more information than before.

-- Deprecated form:
local function match_generator_func(text, first, last)
  -- `text` is the word text.
  -- `first` is the index of the beginning of the end word.
  -- `last` is the index of the end of the end word.
  -- `clink.add_match()` is used to add matches.
  -- return true if handled, or false to let another generator try.
end
clink.register_match_generator(match_generator_func, 10)

-- Replace with new form:
local g = clink.generator(10)
function g:generate(line_state, match_builder)
  -- `line_state` is a line_state object.
  -- `match_builder:addmatch()` is used to add matches.
  -- return true if handled, or false to let another generator try.
end

( index:integer, value:string ) : nil

Deprecated; don't use this.

This is no longer supported, and does nothing.


( type:integer ) : nil

Deprecated; don't use this. See clink.translateslashes for more information.

Controls how Clink will translate the path separating slashes for the current path being completed. Values for type are;
-1 - no translation
0 - to backslashes
1 - to forward slashes


( str:string, sep:string ) : table

Deprecated; don't use this. See string.explode for more information.


Deprecated; don't use this. See builder:setsuppressappend for more information.


Deprecated; don't use this. See builder:setsuppressquoting for more information.


( path:string ) : boolean

Deprecated; don't use this. See os.globfiles for more information.

Returns whether path has the hidden attribute set.


table variable

Deprecated; don't use this. See line_state for more information.

This is an obsolete global variable that was set while running match generators. It has been superseded by the line_state type parameter passed into match generator functions when using the new clink.generator() API.


Changes

v1.3.44

v1.3.43

v1.3.42

v1.3.41

v1.3.40

v1.3.39

v1.3.38

v1.3.37

v1.3.36

v1.3.35

v1.3.34

v1.3.33

v1.3.31

v1.3.30

v1.3.29

v1.3.28

v1.3.27

v1.3.26

v1.3.25

v1.3.24

v1.3.23

v1.3.22

v1.3.21

v1.3.20

v1.3.19

v1.3.18

v1.3.17

v1.3.16

v1.3.15

v1.3.14

v1.3.13

v1.3.12

v1.3.11

v1.3.10

v1.3.9

v1.3.8

v1.3.7

v1.3.6

v1.3.5

v1.3.4

v1.3.3

v1.3.2

v1.3.1

v1.3

v1.2.50

v1.2.49

v1.2.48

v1.2.47

v1.2.46

v1.2.45

v1.2.44

v1.2.43

v1.2.42

v1.2.41

v1.2.40

v1.2.39

v1.2.38

v1.2.37

v1.2.36

v1.2.35

v1.2.34

v1.2.33

v1.2.32

v1.2.31

v1.2.30

v1.2.29

v1.2.28

v1.2.27

v1.2.26

v1.2.25

v1.2.24

v1.2.23

v1.2.22

v1.2.21

v1.2.20

v1.2.19

v1.2.18

v1.2.17

v1.2.16

v1.2.15

v1.2.14

v1.2.13

v1.2.12

v1.2.11

v1.2.10

v1.2.9

v1.2.8

v1.2.7

v1.2.6

v1.2.5

v1.2.4

v1.2.3

v1.2.2

v1.2.1

v1.2

v1.1.49

v1.1.48

v1.1.47

v1.1.46

v1.1.45

v1.1.44

v1.1.43

v1.1.42

v1.1.41

v1.1.40

v1.1.39

v1.1.38

v1.1.37

v1.1.36

v1.1.35

v1.1.34

v1.1.33

v1.1.32

v1.1.31

v1.1.30

v1.1.29

v1.1.28

v1.1.27

v1.1.26

v1.1.25

v1.1.24

v1.1.23

v1.1.22

v1.1.21

v1.1.20

v1.1.19

v1.1.18

v1.1.17

v1.1.16

v1.1.15

v1.1.14

v1.1.13

v1.1.12

v1.1.11

v1.1.10

v1.1.9

v1.1.8

v1.1.7

v1.1.6

v1.1.5

v1.1.4

v1.1.3-alpha

v1.1.2-alpha

v1.1.1-alpha

v1.0.0a1 (alpha test release)

v1.0.0a0 (alpha test release)

v0.4.9

v0.4.8

v0.4.7

v0.4.6

v0.4.5

v0.4.4

v0.4.3

v0.4.2

v0.4.1

v0.4

v0.3

v0.2.1

v0.2

v0.1.1

v0.1

License

Clink is distributed under the terms of the GNU General Public License, version 3.

Credits

Clink

Clink was originally built by Martin Ridgers (https://github.com/mridgers/clink).
Copyright (c) 2012-2018 by Martin Ridgers.

Clink has been forked and renovated by Christopher Antos (https://github.com/chrisant996/clink).
Portions Copyright (c) 2020-2022 by Christopher Antos.

Libraries

GNU Readline library version 8.1 (https://tiswww.case.edu/php/chet/readline/rltop.html).
GNU Readline is distributed under the terms of the GNU General Public License, version 3.

Lua 5.2 (https://www.lua.org).

getopt library.
Copyright (c) 1997 Gregory Pietsch, placed in the public domain.

Detours library version 4.0.1 (https://github.com/microsoft/detours).
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the MIT License.

Match completion display uses column width calculations from GNU coreutils ls.c.
Licensed under the terms of the GNU General Public License, version 3.

Clink documentation embeds the highlight.js library (https://highlightjs.org).
Highlight.js is released under the BSD License.

Clink documentation embeds SVG artwork for a link icon from Bootstrap.
Licensed under the MIT License.

Special thanks to Alexandra Barros and Matthew Wild for (https://code.matthewwild.co.uk/luatraverse).
Originally from (http://lua-users.org/lists/lua-l/2006-07/msg00110.html).
The script was very useful in tracking down dangling references.