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 famous Unix shell Bash, the standard shell for Mac OS X and many Linux distributions.

Features

By default Clink binds Alt+H to display the current key bindings. More features can also be found in GNU's Readline and History libraries' manuals.

Usage

There are three ways to use Clink the first of which is to add Clink to cmd.exe's autorun registry entry. This can be selected when installing Clink using the installer and Clink also provides the ability to manage this autorun entry from the command line. Running clink autorun --help has more information.

The second alternative is to manually run Clink using the command clink inject from within a command prompt session to run Clink in that session.

The last option is to use the Clink shortcut that the installer adds to Windows' start menu. This is in essence a shortcut to the command cmd.exe /k clink inject.

How Clink Works

When running Clink via the methods above, Clink checks the parent process is supported and injects a DLL into it. The DLL then hooks the WriteConsole() and ReadConsole() Windows functions. The former is so that Clink can capture the current prompt, and the latter hook allows Clink to provide it's own Readline-powered command line editing.

Configuring Clink

The easiest way to configure Clink is to use Clink's set command line option. 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
clink.paste_crlf space What to do with CR and LF characters on paste. Set this to delete to delete them, or to space to replace them with spaces.
clink.path A list of paths to load Lua scripts. Multiple paths can be delimited semicolons.
clink.promptfilter True Enable prompt filtering by Lua scripts.
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 process when it is pressed on an empty line.
color.cmd bold Used when Clink displays shell (CMD.EXE) command completions.
color.doskey bright cyan Used when Clink displays doskey alias completions.
color.filtered bold The default color for filtered completions (see Filtering the Match Display).
color.hidden Used when Clink displays file completions with the "hidden" attribute.
color.input Used when Clink displays the input line text.
color.interact bold Used when Clink displays text or prompts such as a pager's --More?-- prompt.
color.modmark Used when Clink displays the * mark on modified history lines when Readline's mark-modified-lines variable and Clink's color.input setting are both set. Falls back to color.input if not set.
color.readonly Used when Clink displays file completions with the "readonly" attribute.
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.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).
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.
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.
files.unc_paths False UNC (network) paths can cause Clink to stutter when it tries to generate matches. Enable this if matching UNC paths is required.
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 erase_prev. Setting it to ignore will not add duplicates to the history, and setting it to add will always add lines.
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 2500 The number of history lines to save if history.save is enabled (1 to 50000).
history.save True Saves history between sessions.
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.
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.traceback_on_error False Prints stack trace on Lua errors.
match.ignore_case relaxed Controls case sensitivity in string comparisons. off = case sensitive, on = case insensitive, relaxed = case insensitive plus - and _ are considered equal.
match.sort_dirs with How to sort matching directory names. before = before files, with = with files, after = after files.
match.wild True Matches ? and * wildcards when using any of the menu-complete commands. Turn this off to behave how bash does.
readline.hide_stderr False Suppresses stderr from the Readline library. Enable this if Readline error messages are getting in the way.
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.
terminal.modify_other_keys True When enabled, pressing Space or Tab with modifier keys sends extended XTerm key sequences so they can be bound separately.

Compatibility Notes:

Color Settings

Friendly Color Names

The Clink color settings use the following syntax:

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

Optional attributes (can be abbreviated to 3 letters):

  • bold or dim adds or removes brightness (high intensity) to the default foreground color (if the default color is bright white, then dim uses normal white).
  • underline or nounderline adds or removes an underline.

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

  • default or normal uses the default color as defined by the current color theme in the console window.
  • black, red, green, yellow, blue, cyan, magenta, white are the basic colors names.
  • bright can be combined with any of the other color names to make them bright (high intensity).

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

  • bri yel for bright yellow foreground on default background color.
  • bold for bright default foreground on default background color.
  • underline bright black on white for dark gray (bright black) foreground on light gray (white) background.
  • default on blue for default foreground color on blue background.

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. The location of these files depends on which distribution of Clink was used. If you installed Clink using the .exe installer then Clink uses the current user's non-roaming application data directory. This user directory is usually found in one of the following locations;

  • Windows XP: c:\Documents and Settings\<username>\Local Settings\Application Data\clink
  • Windows Vista onwards: c:\Users\<username>\AppData\Local\clink

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.

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.

clink autorun
Manages Clink's entry in CMD.EXE's autorun section, which can automatically inject Clink when starting CMD.EXE.
See clink autorun --help for more information.

clink set
clink set by itself lists all settings and their values.
clink set setting_name describes the setting 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 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.

Configuring Readline

Readline itself can also be configured to add custom keybindings and macros by creating a Readline init file. There is excellent documentation for all the options available to configure Readline in Readline's manual.

Clink searches in the directories referenced by the following environment variables and loads any .inputrc or _inputrc files present, in the order listed here:

Configuration in files loaded earlier can be overridden by files loaded later.

Other software that also uses Readline 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.

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 also adds some new commands and configuration variables in addition to what's covered in the Readline documentation.

New Configuration Variables

Name Default Description
completion-auto-query-items on Automatically prompts before displaying completions if they need more than half a screen page.
history-point-at-end-of-anchored-search off Puts the cursor at the end of the line when using history-search-forward or history-search-backward.
search-ignore-case off Controls whether the history search commands ignore case.

New Commands

Name Description
add-history Adds the current line to the history without executing it, and clears the editing line.
clink-copy-cwd Copy the current working directory to the clipboard.
clink-copy-line Copy the current line to the clipboard.
clink-copy-word Copy the word at the cursor to the clipboard.
clink-ctrl-c Discards the current line and starts a new one (like Ctrl+C in CMD.EXE).
clink-exit Replaces the current line with exit and executes it (exits the shell instance).
clink-expand-doskey-alias Expand the doskey alias (if any) at the beginning of the line.
clink-expand-env-vars Expand the environment variable (e.g. %FOOBAR%) at the cursor.
clink-insert-dot-dot Inserts ..\ at the cursor.
clink-paste Paste the clipboard at the cursor.
clink-popup-complete Show a popup window that lists the available completions.
clink-popup-directories Show a popup window of recent current working directories. In the popup, use Enter to cd /d to the highlighted directory. See below more about the popup window.
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. See below for more about the popup window.
clink-reset-line Clears the current line.
clink-scroll-bottom Scroll the console window to the bottom (the current input line).
clink-scroll-line-down Scroll the console window down one line.
clink-scroll-line-up Scroll the console window up one line.
clink-scroll-page-down Scroll the console window down one page.
clink-scroll-page-up Scroll the console window up one page.
clink-scroll-top Scroll the console window to the top.
clink-show-help Lists the currently active key bindings using friendly key names.
clink-show-help-raw Lists the currently active key bindings using raw key sequences.
clink-up-directory Changes to the parent directory.
old-menu-complete-backward Like old-menu-complete, but in reverse.
remove-history While searching history, removes the current line from the history.

Completion Colors

When colored-completion-prefix 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% (using ANSI escape codes) are used to color file completions according to their file type or extension. 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. 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.

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

Let's break that down:

The clink-popup-complete, clink-popup-directories, and clink-popup-history commands show a popup window that lists the available completions, directory history, or command history. Here's how it works:

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.
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.

Extending Clink

The Readline library allows clients to offer an alternative path for creating completion matches. Clink uses this to hook Lua into the completion process making it possible to script the generation of matches with Lua scripts. The following sections describe this in more detail and show some examples.

The 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.

Lua scripts are reloaded each time the edit prompt is activated.

Match Generators

These are Lua functions that are called as part of Readline's completion process.

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 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. It's based on git_branch_autocomplete.lua from collink.clink-git-extensions. The version here is updated for the new Clink Lua API, and for illustration purposes it's been simplified to not support git aliases.

local git_branch_autocomplete = clink.generator(1)

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

local function is_checkout_ac(text)
    if string.starts(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 string.starts(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
    return matchCount > 0 -- If we found branches, then stop other match generators.
end

The :getwordbreakinfo() Function

A generator can influence word breaking for the end word by defining a :getwordbreakinfo() function. The function takes a line_state line 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).

For example, when the environment variable match generator 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.

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

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 then registering the parser with Clink. When Clink detects the command is being entered on the current command line being edited, it uses the parser to generate matches.

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

clink.argmatcher("foobar")
:addflags("-foo", "-bar")
:addarg(
    { "hello", "hi" },
    { "world", "wombles" }
)

This parser describes a command that has two positional arguments each with two potential options. It also has two flags which the parser considers to be position independent meaning that provided the word being completed starts with a certain prefix the parser with attempt to match the from the set of flags.

On the command line completion would look something like this:

C:\>foobar hello -foo wo
world   wombles
C:\>foobar hello -foo wo_

When displaying possible completions, flag matches are only shown if the flag character has been input (so command and Alt+= would list only non-flag matches, or command - and Alt+= would list only flag matches).

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. Parsers can also be concatenated with flags too.

a_parser = clink.argmatcher():addarg({ "foo", "bar" })
b_parser = clink.argmatcher():addarg({ "abc", "123" })
c_parser = clink.argmatcher()
c_parser:addarg({ "foobar" .. b_parser })
c_parser:addarg({ c_parser })

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 is permanent and it will not return to the previous parser.

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.

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

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

The functions take a single argument which is a word from the command line being edited (or partial word if it is the one under the cursor). Functions should return a table of potential matches.

Some built-in matcher functions are available:

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

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()
&nbsp; { "one", "won" }
&nbsp; { "two", "too" }
&nbsp; { "-a", "-b", "/?", "/h" }

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

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' }.

Filtering The Match Display

In some instances it may be preferable to display potential matches in an alternative form than the generated matches passed to and used internally by Readline. For example, it might be desirable to display a * next to some matches, or to show additional information about each match. Filtering the match display only affects what is displayed; it doesn't affect completing matches.

To facilitate custom match generators that may wish to do this there is the clink.match_display_filter variable. This can be set to a function that will then be called before matches are to be displayed.

function my_display_filter(matches)
    new_matches = {}

    for _, m in ipairs(matches) do
        local _, _, n = m:find("\\([^\\]+)$")
        table.insert(new_matches, n)
    end

    return new_matches
end

function my_match_generator(text, first, last)
    ...

    clink.match_display_filter = my_display_filter
    return true
end

The function's single argument matches is a table containing what Clink is going to display. The return value is a table with the input matches filtered as required by the match generator. The value of clink.match_display_filter is reset every time match generation is invoked.

Compatibility Note: When a match display filter has been set, it changes how match generation behaves.

  • Normally match generation only happens at the start of a new word. The full set of potential matches is remembered and dynamically filtered based on further typing.
  • When a match display filter is set, then match generation is also re-run whenever matches are displayed. This is necessary for backward compatibility with how generators and match display filters were able to influence each other.
  • This means if a match generator made contextual decisions other than just filtering then it could potentially behave differently in Clink v1.x than it did in v0.x.

Customising The Prompt

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

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(45)
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(50)
function git_branch_prompt:filter(prompt)
    for line in io.popen("git branch 2>nul"):lines() do
        local branch = line:match("%* (.+)$")
        if branch then
            return prompt.." "..cyan.."["..branch.."]"..normal
        end
    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! _

Miscellaneous

Key bindings

Binding special keys

Due to differences between Windows and Linux, escape codes for keys like PageUp/Down and the arrow keys are different in Clink.

Normal Shift Ctrl Ctrl+Shift Alt Alt+Shift Ctrl+Alt Ctrl+Alt+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;5;32~ \e[27;6;32~ - - \e[27;7;32~ \e[27;8;32~
Backspace ^h - Rubout - \e^h - \eRubout -
Escape \e[27;27~ - - - - - - -

Here is an example line from an inputrc file that binds Shift-End to the Readline transpose-word function;

"\e[1;2F": transpose-word

Binding function keys

For function keys the full escape sequences are listed. The last four columns (Alt+) are the same as the first four columns prefixed with an extra \e.

Normal Shift Ctrl Ctrl+Shift Alt Alt+Shift Alt+Ctrl Alt+Ctrl+Shift
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~

Here is an example line from an inputrc file that binds Alt+Shift+F3 to the Readline history-substring-search-backward function;

"\e\e[1;2R": history-substring-search-backward

An easy way to find the key sequence for any key combination that Clink supports is to use Clink's echo command line option. Run clink echo and then press key combinations; the associated key binding sequence is printed to the console output.

Saved command history

Here's how the saved history works:

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, which is larger) then the history file is compacted: the file is rewritten with the deleted lines removed.

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.

Lua API Reference

This section describes the Clink Lua API extensions. Also see
Lua Documentation for more information about the Lua programming language.
_argmatcher
(choices...:string|table) : self

This adds argument matches. 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("git")
:addarg("add", "status", "commit", "checkout")

(flags...:string) : self

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")

([index:integer]) : self

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

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


([prefixes...:string]) : self

Deprecated; don't use this. See _argmatcher:addflags for more information.

This overrides the default flag prefix (-). The flag prefixes are used to switch between matching arguments versus matching flags. When listing possible completions for an empty word (e.g. command _ where the cursor is at the _), only arguments are listed. And only flags are listed when the word starts with one of the flag prefixes. Each flag prefix must be a single character, but there can be multiple prefixes.

This is no longer needed because :addflags() does it automatically.

local my_parser = clink.argmatcher()
:setflagprefix("-", "/", "+")
:addflags("--help", "/?", "+mode")

builder
(match:string|table, [type:string]) : boolean

Adds a match. If match is a string, it's added as a match and type is the optional match type.

Or match can be a table with the following scheme: { match:string, [type:string] }. If a table element is missing the type field, then the type argument is used for that element.

If the type argument is omitted, "none" is assumed.

The match type can affect how the match is inserted, displayed, and colored:

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.
"link"Shows only the last path component, with appropriate symlink coloring. Not supported yet.
"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").

See Completion Coloring 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

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.

matches can be a table of match strings, or a table of tables describing the matches.
type 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" }
})

([append:string]) : nil

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 ).


([state:boolean]) : nil

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

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.


clink
(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.


([priority:integer], commands...:string) : _argmatcher

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 an argument matcher parser object is already associated with the command, 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.


(word:string) : table

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")
:argarg(({ clink.dirmatches })

(word:string) : table

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

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.


(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.


(text:string) : string

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

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

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

function variable

This variable can be set to a filter function. See Filtering the Match Display for more information.


([files:boolean]) : nil

Deprecated; don't use this. See builder:addmatch for more information.

This is no longer needed, because now it's inferred from the match type when adding matches.


([priority:integer]) : table

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 Customising 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

(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, match_builder)
  -- `text` is the line 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 object.
  -- `match_builder:addmatch()` is used to add matches.
  -- return true if handled, or false to let another generator try.
end

(text:string) : string

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

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

string variable

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


integer variable

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.

-- Make sure the version is high enough to support the "color.filtered" setting.
local color_filtered = ""
if clink.version_encoded ~= nil and clink.version_encoded >= 10010009 then
  color_filtered = "\x1b["..settings.get("color.filtered").."m"
end

integer variable

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


integer variable

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


integer variable

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


clink.arg
(...) : 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 first argmatcher for cmd. 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. Calling clink.arg.register_parser repeatedly with the same command to merge parsers is not supported anymore.

-- Deprecated form:
local parser1 = clink.arg.new_parser("abc", "def")
local parser2 = clink.arg.new_parser("ghi", "jkl")
clink.arg.register_parser("foo", parser1)
clink.arg.register_parser("foo", parser2)

-- Replace with new form:
clink.argmatcher("foo"):addarg(parser1, parser2)

-- Warning:  Note that the following are NOT the same as above!
-- This replaces parser1 with parser2:
clink.argmatcher("foo"):addarg(parser1)
clink.argmatcher("foo"):addarg(parser2)
-- This uses only parser2 if/when parser1 finishes parsing args:
clink.argmatcher("foo"):addarg(parser1):addarg(parser2)

clink.prompt
(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

line
() : integer

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:getcommandoffset() == 4

() : integer

Returns the position of the cursor.


() : string

Returns the last word of the line. This is the word that matches are being generated for.

line:getword(line:getwordcount()) == line:getendword()

() : string

Returns the current line in its entirety.


(index:integer) : string

Returns the word of the line at index.


() : integer

Returns the number of words in the current line.


(index:integer) : table

Returns a table of information about the Nth word in the line. The table returned has the following scheme:

{
  offset,  -- [integer] offset where the word starts in the line:getline() string.
  length,  -- [integer] length of the word.
  quoted,  -- [boolean] indicates whether the word is quoted.
  delim,   -- [string] the delimiter character, or an empty string.
}

log
(message:string) : nil

Writes info message to the Clink log file. Use this sparingly, or it could cause performance problems or disk space problems.


os
(path:string) : boolean

Changes the current directory to path and returns whether it was successful.


(src:string, dest:string) : boolean

Copies the src file to the dest file.


(name:string) : string

Returns command string for doskey alias name.


() : table

Returns doskey aliases in a table with the following scheme: { {name:string, command:string}, ... }.


() : string

Returns the current directory.


(name:string) : string|nil

Returns the value of the named environment variable, or nil if it doesn't exist.


() : table

Returns all environment variables in a table with the following scheme: { {name:string, value:string}, ... }.


() : string

Returns the fully qualified file name of the host process. Currently only CMD.EXE can host Clink.


() : table

Returns dimensions of the terminal's buffer and visible window. The returned table has the following scheme:

{
  bufwidth,     -- [integer] width of the screen buffer
  bufheight,    -- [integer] height of the screen buffer
  winwidth,     -- [integer] width of the visible window
  winheight,    -- [integer] height of the visible window
}

(globpattern:string, [extrainfo:boolean]) : table

Collects directories matching globpattern and returns them in a table of strings.

When extrainfo is true, then the returned table has the following scheme: { {name:string, type:string}, ... }.

The type string can be "file" or "dir", and may also contain ",hidden" and ",readonly" depending on the attributes (making it usable as a match type for builder:addmatch()).


(globpattern:string, [extrainfo:boolean]) : table

Collects files and/or directories matching globpattern and returns them in a table of strings.

When extrainfo is true, then the returned table has the following scheme: { {name:string, type:string}, ... }.

The type string can be "file" or "dir", and may also contain ",hidden" and ",readonly" depending on the attributes (making it usable as a match type for builder:addmatch()).


(path:string) : boolean

Returns whether path is a directory.


(path:string) : boolean

Returns whether path is a file.


(path:string) : boolean

Returns whether path has the hidden attribute set.


(path:string) : boolean

Creates the directory path and returns whether it was successful.


(src:string, dest:string) : boolean

Moves the src file to the dest file.


(path:string) : boolean

Removes the directory path and returns whether it was successful.


(name:string, value:string) : boolean

Sets the name environment variable to value and returns whether it was successful.


(path:string) : boolean

Deletes the file path and returns whether it was successful.


path
(path:string) : string

path.getbasename("/foo/bar.ext") -- returns "bar"

(path:string) : nil or string

path.getdirectory("/foo/bar") -- returns "/foo/"
path.getdirectory("bar") -- returns nil

(path:string) : nil or string

path.getdrive("e:/foo/bar") -- returns "e:"
path.getdrive("foo/bar") -- returns nil

(path:string) : string

path.getextension("bar.ext") -- returns ".ext"
path.getextension("bar") -- returns ""

(path:string) : string

path.getname("/foo/bar.ext") -- returns "bar.ext"

(path:string) : boolean

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

(left:string, right:string) : string

path.join("/foo", "bar") -- returns "/foo\bar"

(path:string, [separator:string]) : string

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\"

rl
(path:string, [force:boolean]) : string

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".

(path:string) : string, boolean

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.

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

(name:string) : string|nil

Returns the value of the named Readline configuration variable as a string, or nil if the variable name is not recognized.


(name:string) : boolean|nil

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.


settings
(name:string, default:..., [short_desc:string], [long_desc:string]) : boolean

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 31 characters.
short_desc is an optional quick summary description and can't be more than 47 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

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

Sets the name Clink setting to value and returns whether it was successful.


string
(text:string, [delims:string]) : table

Splits text delimited by delims (or by spaces if not provided) and returns a table containing the substrings.


(text:string) : integer

Returns a hash of the input text.


[other]
table variable

Deprecated; don't use this. See line for more information.

This is an obsolete global variable that was set while running match generators. It has been superseded by the line type parameter passed into match generator functions when using the new clink.generator API.


Changes

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 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 by Christopher Antos.

Libraries

GNU Readline library version 8.0 (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.

Clink documentation embeds the highlight.js library (https://highlightjs.org).
Highlight.js is released under the BSD License.