mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
commit
7b0ceb3726
@ -48,7 +48,7 @@ version.api_compatible API is backwards-compatible with this level
|
|||||||
version.api_prerelease Declares the current API level as unstable >
|
version.api_prerelease Declares the current API level as unstable >
|
||||||
(version.api_prerelease && fn.since == version.api_level)
|
(version.api_prerelease && fn.since == version.api_level)
|
||||||
functions API function signatures
|
functions API function signatures
|
||||||
ui_events UI event signatures |rpc-remote-ui|
|
ui_events UI event signatures |ui|
|
||||||
{fn}.since API level where function {fn} was introduced
|
{fn}.since API level where function {fn} was introduced
|
||||||
{fn}.deprecated_since API level where function {fn} was deprecated
|
{fn}.deprecated_since API level where function {fn} was deprecated
|
||||||
types Custom handle types defined by Nvim
|
types Custom handle types defined by Nvim
|
||||||
|
@ -243,203 +243,4 @@ Even for statically compiled clients it is good practice to avoid hardcoding
|
|||||||
the type codes, because a client may be built against one Nvim version but
|
the type codes, because a client may be built against one Nvim version but
|
||||||
connect to another with different type codes.
|
connect to another with different type codes.
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
6. Remote UIs *rpc-remote-ui*
|
|
||||||
|
|
||||||
GUIs can be implemented as external processes communicating with Nvim over the
|
|
||||||
RPC API. The UI model consists of a terminal-like grid with a single,
|
|
||||||
monospace font size. Some elements (UI "widgets") can be drawn separately from
|
|
||||||
the grid ("externalized").
|
|
||||||
|
|
||||||
After connecting to Nvim (usually a spawned, embedded instance) use the
|
|
||||||
|nvim_ui_attach| API method to tell Nvim that your program wants to draw the
|
|
||||||
Nvim screen on a grid of width × height cells. `options` must be
|
|
||||||
a dictionary with these (optional) keys:
|
|
||||||
`rgb` Controls what color format to use.
|
|
||||||
Set to true (default) to use 24-bit rgb
|
|
||||||
colors.
|
|
||||||
Set to false to use terminal color codes (at
|
|
||||||
most 256 different colors).
|
|
||||||
`ext_popupmenu` Externalize the popupmenu. |ui-ext-popupmenu|
|
|
||||||
`ext_tabline` Externalize the tabline. |ui-ext-tabline|
|
|
||||||
Externalized widgets will not be drawn by
|
|
||||||
Nvim; only high-level data will be published
|
|
||||||
in new UI event kinds.
|
|
||||||
|
|
||||||
Nvim will then send msgpack-rpc notifications, with the method name "redraw"
|
|
||||||
and a single argument, an array of screen updates (described below). These
|
|
||||||
should be processed in order. Preferably the user should only be able to see
|
|
||||||
the screen state after all updates in the same "redraw" event are processed
|
|
||||||
(not any intermediate state after processing only a part of the array).
|
|
||||||
|
|
||||||
Future versions of Nvim may add new update kinds and may append new parameters
|
|
||||||
to existing update kinds. Clients must be prepared to ignore such extensions
|
|
||||||
to be forward-compatible. |api-contract|
|
|
||||||
|
|
||||||
Screen updates are tuples whose first element is the string name of the update
|
|
||||||
kind.
|
|
||||||
|
|
||||||
["resize", width, height]
|
|
||||||
The grid is resized to `width` and `height` cells.
|
|
||||||
|
|
||||||
["clear"]
|
|
||||||
Clear the screen.
|
|
||||||
|
|
||||||
["eol_clear"]
|
|
||||||
Clear from the cursor position to the end of the current line.
|
|
||||||
|
|
||||||
["cursor_goto", row, col]
|
|
||||||
Move the cursor to position (row, col). Currently, the same cursor is
|
|
||||||
used to define the position for text insertion and the visible cursor.
|
|
||||||
However, only the last cursor position, after processing the entire
|
|
||||||
array in the "redraw" event, is intended to be a visible cursor
|
|
||||||
position.
|
|
||||||
|
|
||||||
["update_fg", color]
|
|
||||||
["update_bg", color]
|
|
||||||
["update_sp", color]
|
|
||||||
Set the default foreground, background and special colors
|
|
||||||
respectively.
|
|
||||||
|
|
||||||
["highlight_set", attrs]
|
|
||||||
Set the attributes that the next text put on the screen will have.
|
|
||||||
`attrs` is a dict with the keys below. Any absent key is reset
|
|
||||||
to its default value. Color defaults are set by the `update_fg` etc
|
|
||||||
updates. All boolean keys default to false.
|
|
||||||
|
|
||||||
`foreground`: foreground color.
|
|
||||||
`background`: backround color.
|
|
||||||
`special`: color to use for underline and undercurl, when present.
|
|
||||||
`reverse`: reverse video. Foreground and background colors are
|
|
||||||
switched.
|
|
||||||
`italic`: italic text.
|
|
||||||
`bold`: bold text.
|
|
||||||
`underline`: underlined text. The line has `special` color.
|
|
||||||
`undercurl`: undercurled text. The curl has `special` color.
|
|
||||||
|
|
||||||
["put", text]
|
|
||||||
The (utf-8 encoded) string `text` is put at the cursor position
|
|
||||||
(and the cursor is advanced), with the highlights as set by the
|
|
||||||
last `highlight_set` update.
|
|
||||||
|
|
||||||
["set_scroll_region", top, bot, left, right]
|
|
||||||
Define the scroll region used by `scroll` below.
|
|
||||||
|
|
||||||
["scroll", count]
|
|
||||||
Scroll the text in the scroll region. The diagrams below illustrate
|
|
||||||
what will happen, depending on the scroll direction. "=" is used to
|
|
||||||
represent the SR(scroll region) boundaries and "-" the moved rectangles.
|
|
||||||
Note that dst and src share a common region.
|
|
||||||
|
|
||||||
If count is bigger than 0, move a rectangle in the SR up, this can
|
|
||||||
happen while scrolling down.
|
|
||||||
>
|
|
||||||
+-------------------------+
|
|
||||||
| (clipped above SR) | ^
|
|
||||||
|=========================| dst_top |
|
|
||||||
| dst (still in SR) | |
|
|
||||||
+-------------------------+ src_top |
|
|
||||||
| src (moved up) and dst | |
|
|
||||||
|-------------------------| dst_bot |
|
|
||||||
| src (cleared) | |
|
|
||||||
+=========================+ src_bot
|
|
||||||
<
|
|
||||||
If count is less than zero, move a rectangle in the SR down, this can
|
|
||||||
happen while scrolling up.
|
|
||||||
>
|
|
||||||
+=========================+ src_top
|
|
||||||
| src (cleared) | |
|
|
||||||
|------------------------ | dst_top |
|
|
||||||
| src (moved down) and dst| |
|
|
||||||
+-------------------------+ src_bot |
|
|
||||||
| dst (still in SR) | |
|
|
||||||
|=========================| dst_bot |
|
|
||||||
| (clipped below SR) | v
|
|
||||||
+-------------------------+
|
|
||||||
<
|
|
||||||
["set_title", title]
|
|
||||||
["set_icon", icon]
|
|
||||||
Set the window title, and icon (minimized) window title, respectively.
|
|
||||||
In windowing systems not distinguishing between the two, "set_icon"
|
|
||||||
can be ignored.
|
|
||||||
|
|
||||||
["mouse_on"]
|
|
||||||
["mouse_off"]
|
|
||||||
Tells the client whether mouse support, as determined by |'mouse'|
|
|
||||||
option, is considered to be active in the current mode. This is mostly
|
|
||||||
useful for a terminal frontend, or other situations where nvim mouse
|
|
||||||
would conflict with other usages of the mouse. It is safe for a client
|
|
||||||
to ignore this and always send mouse events.
|
|
||||||
|
|
||||||
["busy_on"]
|
|
||||||
["busy_off"]
|
|
||||||
Nvim started or stopped being busy, and possibly not responsible to user
|
|
||||||
input. This could be indicated to the user by hiding the cursor.
|
|
||||||
|
|
||||||
["suspend"]
|
|
||||||
|:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other
|
|
||||||
client where it makes sense) could suspend itself. Other clients can
|
|
||||||
safely ignore it.
|
|
||||||
|
|
||||||
["bell"]
|
|
||||||
["visual_bell"]
|
|
||||||
Notify the user with an audible or visual bell, respectively.
|
|
||||||
|
|
||||||
["update_menu"]
|
|
||||||
The menu mappings changed.
|
|
||||||
|
|
||||||
["mode_info_set", cursor_style_enabled, mode_info]
|
|
||||||
`cursor_style_enabled` is a boolean indicating if the UI should set the cursor
|
|
||||||
style. `mode_info` is a list of mode property maps. The current mode is given
|
|
||||||
by the `mode_idx` field of the `mode_change` event.
|
|
||||||
|
|
||||||
Each mode property map may contain these keys:
|
|
||||||
KEY DESCRIPTION ~
|
|
||||||
`cursor_shape`: "block", "horizontal", "vertical"
|
|
||||||
`cell_percentage`: Cell % occupied by the cursor.
|
|
||||||
`blinkwait`, `blinkon`, `blinkoff`: See |cursor-blinking|.
|
|
||||||
`hl_id`: Cursor highlight group.
|
|
||||||
`hl_lm`: Cursor highlight group if 'langmap' is active.
|
|
||||||
`short_name`: Mode code name, see 'guicursor'.
|
|
||||||
`name`: Mode descriptive name.
|
|
||||||
`mouse_shape`: (To be implemented.)
|
|
||||||
|
|
||||||
Some keys are missing in some modes.
|
|
||||||
|
|
||||||
["mode_change", mode, mode_idx]
|
|
||||||
The mode changed. The first parameter `mode` is a string representing the
|
|
||||||
current mode. `mode_idx` is an index into the array received in the
|
|
||||||
`mode_info_set` event. UIs should change the cursor style according to the
|
|
||||||
properties specified in the corresponding item. The set of modes reported will
|
|
||||||
change in new versions of Nvim, for instance more submodes and temporary
|
|
||||||
states might be represented as separate modes.
|
|
||||||
|
|
||||||
*ui-ext-popupmenu*
|
|
||||||
["popupmenu_show", items, selected, row, col]
|
|
||||||
When `popupmenu_external` is set to true, nvim will not draw the
|
|
||||||
popupmenu on the grid, instead when the popupmenu is to be displayed
|
|
||||||
this update is sent. `items` is an array of the items to show, the
|
|
||||||
items are themselves arrays of the form [word, kind, menu, info]
|
|
||||||
as defined at |complete-items|, except that `word` is replaced by
|
|
||||||
`abbr` if present. `selected` is the initially selected item, either a
|
|
||||||
zero-based index into the array of items, or -1 if no item is
|
|
||||||
selected. `row` and `col` is the anchor position, where the first
|
|
||||||
character of the completed word will be.
|
|
||||||
|
|
||||||
["popupmenu_select", selected]
|
|
||||||
An item in the currently displayed popupmenu is selected. `selected`
|
|
||||||
is either a zero-based index into the array of items from the last
|
|
||||||
`popupmenu_show` event, or -1 if no item is selected.
|
|
||||||
|
|
||||||
["popupmenu_hide"]
|
|
||||||
The popupmenu is hidden.
|
|
||||||
|
|
||||||
*ui-ext-tabline*
|
|
||||||
["tabline_update", curtab, tabs]
|
|
||||||
Tabline was updated. UIs should present this data in a custom tabline
|
|
||||||
widget.
|
|
||||||
curtab: Current Tabpage
|
|
||||||
tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...]
|
|
||||||
|
|
||||||
==============================================================================
|
|
||||||
vim:tw=78:ts=8:noet:ft=help:norl:
|
|
||||||
|
290
runtime/doc/ui.txt
Normal file
290
runtime/doc/ui.txt
Normal file
@ -0,0 +1,290 @@
|
|||||||
|
*ui.txt* Nvim
|
||||||
|
|
||||||
|
|
||||||
|
NVIM REFERENCE MANUAL
|
||||||
|
|
||||||
|
|
||||||
|
Nvim UI protocol *ui*
|
||||||
|
|
||||||
|
Type |gO| to see the table of contents.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Introduction *ui-intro*
|
||||||
|
|
||||||
|
GUIs can be implemented as external processes communicating with Nvim over the
|
||||||
|
RPC API. The UI model consists of a terminal-like grid with a single,
|
||||||
|
monospace font size. Some elements (UI "widgets") can be drawn separately from
|
||||||
|
the grid ("externalized").
|
||||||
|
|
||||||
|
*ui-options*
|
||||||
|
After connecting to Nvim (usually a spawned, embedded instance) use the
|
||||||
|
|nvim_ui_attach| API method to tell Nvim that your program wants to draw the
|
||||||
|
Nvim screen grid with a size of width × height cells. `options` must be
|
||||||
|
a dictionary with these (optional) keys:
|
||||||
|
`rgb` Decides the color format.
|
||||||
|
Set true (default) for 24-bit RGB colors.
|
||||||
|
Set false for terminal colors (max of 256).
|
||||||
|
*ui-ext-options*
|
||||||
|
`ext_popupmenu` Externalize the popupmenu. |ui-popupmenu|
|
||||||
|
`ext_tabline` Externalize the tabline. |ui-tabline|
|
||||||
|
`ext_cmdline` Externalize the cmdline. |ui-cmdline|
|
||||||
|
|
||||||
|
Nvim will then send msgpack-rpc notifications, with the method name "redraw"
|
||||||
|
and a single argument, an array of screen update events.
|
||||||
|
Update events are tuples whose first element is the event name and remaining
|
||||||
|
elements the event parameters.
|
||||||
|
|
||||||
|
Events must be handled in order. The user should only see the updated screen
|
||||||
|
state after all events in the same "redraw" batch are processed (not any
|
||||||
|
intermediate state after processing only part of the array).
|
||||||
|
|
||||||
|
Nvim sends |ui-global| and |ui-grid| events unconditionally; these suffice to
|
||||||
|
implement a terminal-like interface.
|
||||||
|
|
||||||
|
Nvim optionally sends screen elements "semantically" as structured events
|
||||||
|
instead of raw grid-lines. Then the UI must decide how to present those
|
||||||
|
elements itself; Nvim will not draw those elements on the grid. This is
|
||||||
|
controlled by the |ui-ext-options|.
|
||||||
|
|
||||||
|
Future versions of Nvim may add new update kinds and may append new parameters
|
||||||
|
to existing update kinds. Clients must be prepared to ignore such extensions
|
||||||
|
to be forward-compatible. |api-contract|
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Global Events *ui-global*
|
||||||
|
|
||||||
|
["set_title", title]
|
||||||
|
["set_icon", icon]
|
||||||
|
Set the window title, and icon (minimized) window title, respectively.
|
||||||
|
In windowing systems not distinguishing between the two, "set_icon"
|
||||||
|
can be ignored.
|
||||||
|
|
||||||
|
["mode_info_set", cursor_style_enabled, mode_info]
|
||||||
|
`cursor_style_enabled` is a boolean indicating if the UI should set
|
||||||
|
the cursor style. `mode_info` is a list of mode property maps. The
|
||||||
|
current mode is given by the `mode_idx` field of the `mode_change`
|
||||||
|
event.
|
||||||
|
|
||||||
|
Each mode property map may contain these keys:
|
||||||
|
|
||||||
|
KEY DESCRIPTION ~
|
||||||
|
`cursor_shape`: "block", "horizontal", "vertical"
|
||||||
|
`cell_percentage`: Cell % occupied by the cursor.
|
||||||
|
`blinkwait`, `blinkon`, `blinkoff`: See |cursor-blinking|.
|
||||||
|
`hl_id`: Cursor highlight group.
|
||||||
|
`hl_lm`: Cursor highlight group if 'langmap' is active.
|
||||||
|
`short_name`: Mode code name, see 'guicursor'.
|
||||||
|
`name`: Mode descriptive name.
|
||||||
|
`mouse_shape`: (To be implemented.)
|
||||||
|
|
||||||
|
Some keys are missing in some modes.
|
||||||
|
|
||||||
|
["mode_change", mode, mode_idx]
|
||||||
|
The mode changed. The first parameter `mode` is a string representing
|
||||||
|
the current mode. `mode_idx` is an index into the array received in
|
||||||
|
the `mode_info_set` event. UIs should change the cursor style
|
||||||
|
according to the properties specified in the corresponding item. The
|
||||||
|
set of modes reported will change in new versions of Nvim, for
|
||||||
|
instance more submodes and temporary states might be represented as
|
||||||
|
separate modes.
|
||||||
|
|
||||||
|
["mouse_on"]
|
||||||
|
["mouse_off"]
|
||||||
|
Tells the client whether mouse support, as determined by |'mouse'|
|
||||||
|
option, is considered to be active in the current mode. This is mostly
|
||||||
|
useful for a terminal frontend, or other situations where nvim mouse
|
||||||
|
would conflict with other usages of the mouse. It is safe for a client
|
||||||
|
to ignore this and always send mouse events.
|
||||||
|
|
||||||
|
["busy_on"]
|
||||||
|
["busy_off"]
|
||||||
|
Nvim started or stopped being busy, and possibly not responsive to
|
||||||
|
user input. This could be indicated to the user by hiding the cursor.
|
||||||
|
|
||||||
|
["suspend"]
|
||||||
|
|:suspend| command or |Ctrl-Z| mapping is used. A terminal client (or other
|
||||||
|
client where it makes sense) could suspend itself. Other clients can
|
||||||
|
safely ignore it.
|
||||||
|
|
||||||
|
["update_menu"]
|
||||||
|
The menu mappings changed.
|
||||||
|
|
||||||
|
["bell"]
|
||||||
|
["visual_bell"]
|
||||||
|
Notify the user with an audible or visual bell, respectively.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Grid Events *ui-grid*
|
||||||
|
|
||||||
|
["resize", width, height]
|
||||||
|
The grid is resized to `width` and `height` cells.
|
||||||
|
|
||||||
|
["clear"]
|
||||||
|
Clear the grid.
|
||||||
|
|
||||||
|
["eol_clear"]
|
||||||
|
Clear from the cursor position to the end of the current line.
|
||||||
|
|
||||||
|
["cursor_goto", row, col]
|
||||||
|
Move the cursor to position (row, col). Currently, the same cursor is
|
||||||
|
used to define the position for text insertion and the visible cursor.
|
||||||
|
However, only the last cursor position, after processing the entire
|
||||||
|
array in the "redraw" event, is intended to be a visible cursor
|
||||||
|
position.
|
||||||
|
|
||||||
|
["update_fg", color]
|
||||||
|
["update_bg", color]
|
||||||
|
["update_sp", color]
|
||||||
|
Set the default foreground, background and special colors
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
*ui-event-highlight_set*
|
||||||
|
["highlight_set", attrs]
|
||||||
|
Set the attributes that the next text put on the grid will have.
|
||||||
|
`attrs` is a dict with the keys below. Any absent key is reset
|
||||||
|
to its default value. Color defaults are set by the `update_fg` etc
|
||||||
|
updates. All boolean keys default to false.
|
||||||
|
|
||||||
|
`foreground`: foreground color.
|
||||||
|
`background`: backround color.
|
||||||
|
`special`: color to use for underline and undercurl, when present.
|
||||||
|
`reverse`: reverse video. Foreground and background colors are
|
||||||
|
switched.
|
||||||
|
`italic`: italic text.
|
||||||
|
`bold`: bold text.
|
||||||
|
`underline`: underlined text. The line has `special` color.
|
||||||
|
`undercurl`: undercurled text. The curl has `special` color.
|
||||||
|
|
||||||
|
["put", text]
|
||||||
|
The (utf-8 encoded) string `text` is put at the cursor position
|
||||||
|
(and the cursor is advanced), with the highlights as set by the
|
||||||
|
last `highlight_set` update.
|
||||||
|
|
||||||
|
["set_scroll_region", top, bot, left, right]
|
||||||
|
Define the scroll region used by `scroll` below.
|
||||||
|
|
||||||
|
["scroll", count]
|
||||||
|
Scroll the text in the scroll region. The diagrams below illustrate
|
||||||
|
what will happen, depending on the scroll direction. "=" is used to
|
||||||
|
represent the SR(scroll region) boundaries and "-" the moved rectangles.
|
||||||
|
Note that dst and src share a common region.
|
||||||
|
|
||||||
|
If count is bigger than 0, move a rectangle in the SR up, this can
|
||||||
|
happen while scrolling down.
|
||||||
|
>
|
||||||
|
+-------------------------+
|
||||||
|
| (clipped above SR) | ^
|
||||||
|
|=========================| dst_top |
|
||||||
|
| dst (still in SR) | |
|
||||||
|
+-------------------------+ src_top |
|
||||||
|
| src (moved up) and dst | |
|
||||||
|
|-------------------------| dst_bot |
|
||||||
|
| src (cleared) | |
|
||||||
|
+=========================+ src_bot
|
||||||
|
<
|
||||||
|
If count is less than zero, move a rectangle in the SR down, this can
|
||||||
|
happen while scrolling up.
|
||||||
|
>
|
||||||
|
+=========================+ src_top
|
||||||
|
| src (cleared) | |
|
||||||
|
|------------------------ | dst_top |
|
||||||
|
| src (moved down) and dst| |
|
||||||
|
+-------------------------+ src_bot |
|
||||||
|
| dst (still in SR) | |
|
||||||
|
|=========================| dst_bot |
|
||||||
|
| (clipped below SR) | v
|
||||||
|
+-------------------------+
|
||||||
|
<
|
||||||
|
==============================================================================
|
||||||
|
Popupmenu Events *ui-popupmenu*
|
||||||
|
|
||||||
|
Only sent if `ext_popupmenu` option is set in |ui-options|
|
||||||
|
|
||||||
|
["popupmenu_show", items, selected, row, col]
|
||||||
|
`items` is an array of the items to show, the
|
||||||
|
items are themselves arrays of the form [word, kind, menu, info]
|
||||||
|
as defined at |complete-items|, except that `word` is replaced by
|
||||||
|
`abbr` if present. `selected` is the initially selected item, either a
|
||||||
|
zero-based index into the array of items, or -1 if no item is
|
||||||
|
selected. `row` and `col` is the anchor position, where the first
|
||||||
|
character of the completed word will be.
|
||||||
|
|
||||||
|
["popupmenu_select", selected]
|
||||||
|
An item in the currently displayed popupmenu is selected. `selected`
|
||||||
|
is either a zero-based index into the array of items from the last
|
||||||
|
`popupmenu_show` event, or -1 if no item is selected.
|
||||||
|
|
||||||
|
["popupmenu_hide"]
|
||||||
|
The popupmenu is hidden.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Tabline Events *ui-tabline*
|
||||||
|
|
||||||
|
Only sent if `ext_tabline` option is set in |ui-options|
|
||||||
|
|
||||||
|
["tabline_update", curtab, tabs]
|
||||||
|
Tabline was updated. UIs should present this data in a custom tabline
|
||||||
|
widget.
|
||||||
|
curtab: Current Tabpage
|
||||||
|
tabs: List of Dicts [{ "tab": Tabpage, "name": String }, ...]
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
Cmdline Events *ui-cmdline*
|
||||||
|
|
||||||
|
Only sent if `ext_cmdline` option is set in |ui-options|
|
||||||
|
|
||||||
|
["cmdline_show", content, pos, firstc, prompt, indent, level]
|
||||||
|
content: List of [attrs, string]
|
||||||
|
[[{}, "t"], [attrs, "est"], ...]
|
||||||
|
|
||||||
|
Triggered when the user types in the cmdline.
|
||||||
|
The `content` is the full content that should be displayed in the
|
||||||
|
cmdline, and the `pos` is the position of the cursor that in the
|
||||||
|
cmdline. The content is divided into chunks with different highlight
|
||||||
|
attributes represented as a dict (see |ui-event-highlight_set|).
|
||||||
|
|
||||||
|
`firstc` and `prompt` are text, that if non-empty should be
|
||||||
|
displayed in front of the command line. `firstc` always indicates
|
||||||
|
built-in command lines such as `:` (ex command) and `/` `?` (search),
|
||||||
|
while `prompt` is an |input()| prompt. `indent` tells how many spaces
|
||||||
|
the content should be indented.
|
||||||
|
|
||||||
|
The Nvim command line can be invoked recursively, for instance by
|
||||||
|
typing `<c-r>=` at the command line prompt. The `level` field is used
|
||||||
|
to distinguish different command lines active at the same time. The
|
||||||
|
first invoked command line has level 1, the next recursively-invoked
|
||||||
|
prompt has level 2. A command line invoked from the |cmd-line-window|
|
||||||
|
has a higher level than than the edited command line.
|
||||||
|
|
||||||
|
["cmdline_pos", pos, level]
|
||||||
|
Change the cursor position in the cmdline.
|
||||||
|
|
||||||
|
["cmdline_special_char", c, shift, level]
|
||||||
|
Display a special char in the cmdline at the cursor position. This is
|
||||||
|
typically used to indicate a pending state, e.g. after |c_CTRL-V|. If
|
||||||
|
`shift` is true the text after the cursor should be shifted, otherwise
|
||||||
|
it should overwrite the char at the cursor.
|
||||||
|
|
||||||
|
Should be hidden at next cmdline_pos.
|
||||||
|
|
||||||
|
["cmdline_hide"]
|
||||||
|
Hide the cmdline.
|
||||||
|
|
||||||
|
["cmdline_block_show", lines]
|
||||||
|
Show a block of context to the current command line. For example if
|
||||||
|
the user defines a |:function| interactively: >
|
||||||
|
:function Foo()
|
||||||
|
: echo "foo"
|
||||||
|
:
|
||||||
|
<
|
||||||
|
`lines` is a list of lines of highlighted chunks, in the same form as
|
||||||
|
the "cmdline_show" `contents` parameter.
|
||||||
|
|
||||||
|
["cmdline_block_append", line]
|
||||||
|
Append a line at the end of the currently shown block.
|
||||||
|
|
||||||
|
["cmdline_block_hide"]
|
||||||
|
Hide the block.
|
||||||
|
|
||||||
|
==============================================================================
|
||||||
|
vim:tw=78:ts=8:noet:ft=help:norl:
|
@ -667,6 +667,22 @@ tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err)
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allocates a String consisting of a single char. Does not support multibyte
|
||||||
|
/// characters. The resulting string is also NUL-terminated, to facilitate
|
||||||
|
/// interoperating with code using C strings.
|
||||||
|
///
|
||||||
|
/// @param char the char to convert
|
||||||
|
/// @return the resulting String, if the input char was NUL, an
|
||||||
|
/// empty String is returned
|
||||||
|
String cchar_to_string(char c)
|
||||||
|
{
|
||||||
|
char buf[] = { c, NUL };
|
||||||
|
return (String) {
|
||||||
|
.data = xmemdupz(buf, 1),
|
||||||
|
.size = (c != NUL) ? 1 : 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Copies a C string into a String (binary safe string, characters + length).
|
/// Copies a C string into a String (binary safe string, characters + length).
|
||||||
/// The resulting string is also NUL-terminated, to facilitate interoperating
|
/// The resulting string is also NUL-terminated, to facilitate interoperating
|
||||||
/// with code using C strings.
|
/// with code using C strings.
|
||||||
@ -687,6 +703,23 @@ String cstr_to_string(const char *str)
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Copies buffer to an allocated String.
|
||||||
|
/// The resulting string is also NUL-terminated, to facilitate interoperating
|
||||||
|
/// with code using C strings.
|
||||||
|
///
|
||||||
|
/// @param buf the buffer to copy
|
||||||
|
/// @param size length of the buffer
|
||||||
|
/// @return the resulting String, if the input string was NULL, an
|
||||||
|
/// empty String is returned
|
||||||
|
String cbuf_to_string(const char *buf, size_t size)
|
||||||
|
FUNC_ATTR_NONNULL_ALL
|
||||||
|
{
|
||||||
|
return (String) {
|
||||||
|
.data = xmemdupz(buf, size),
|
||||||
|
.size = size
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a String using the given C string. Unlike
|
/// Creates a String using the given C string. Unlike
|
||||||
/// cstr_to_string this function DOES NOT copy the C string.
|
/// cstr_to_string this function DOES NOT copy the C string.
|
||||||
///
|
///
|
||||||
|
@ -68,4 +68,20 @@ void popupmenu_select(Integer selected)
|
|||||||
void tabline_update(Tabpage current, Array tabs)
|
void tabline_update(Tabpage current, Array tabs)
|
||||||
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
|
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
|
||||||
|
|
||||||
|
void cmdline_show(Array content, Integer pos, String firstc, String prompt,
|
||||||
|
Integer indent, Integer level)
|
||||||
|
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
|
||||||
|
void cmdline_pos(Integer pos, Integer level)
|
||||||
|
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
|
||||||
|
void cmdline_special_char(String c, Boolean shift, Integer level)
|
||||||
|
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
|
||||||
|
void cmdline_hide(Integer level)
|
||||||
|
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
|
||||||
|
void cmdline_block_show(Array lines)
|
||||||
|
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
|
||||||
|
void cmdline_block_append(Array lines)
|
||||||
|
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
|
||||||
|
void cmdline_block_hide(void)
|
||||||
|
FUNC_API_SINCE(3) FUNC_API_REMOTE_ONLY;
|
||||||
|
|
||||||
#endif // NVIM_API_UI_EVENTS_IN_H
|
#endif // NVIM_API_UI_EVENTS_IN_H
|
||||||
|
@ -11147,17 +11147,18 @@ void get_user_input(const typval_T *const argvars,
|
|||||||
|
|
||||||
cmd_silent = false; // Want to see the prompt.
|
cmd_silent = false; // Want to see the prompt.
|
||||||
// Only the part of the message after the last NL is considered as
|
// Only the part of the message after the last NL is considered as
|
||||||
// prompt for the command line.
|
// prompt for the command line, unlsess cmdline is externalized
|
||||||
const char *p = strrchr(prompt, '\n');
|
const char *p = prompt;
|
||||||
if (p == NULL) {
|
if (!ui_is_external(kUICmdline)) {
|
||||||
p = prompt;
|
const char *lastnl = strrchr(prompt, '\n');
|
||||||
} else {
|
if (lastnl != NULL) {
|
||||||
p++;
|
p = lastnl+1;
|
||||||
msg_start();
|
msg_start();
|
||||||
msg_clr_eos();
|
msg_clr_eos();
|
||||||
msg_puts_attr_len(prompt, p - prompt, echo_attr);
|
msg_puts_attr_len(prompt, p - prompt, echo_attr);
|
||||||
msg_didout = false;
|
msg_didout = false;
|
||||||
msg_starthere();
|
msg_starthere();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cmdline_row = msg_row;
|
cmdline_row = msg_row;
|
||||||
|
|
||||||
@ -19643,6 +19644,7 @@ void ex_function(exarg_T *eap)
|
|||||||
int todo;
|
int todo;
|
||||||
hashitem_T *hi;
|
hashitem_T *hi;
|
||||||
int sourcing_lnum_off;
|
int sourcing_lnum_off;
|
||||||
|
bool show_block = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ":function" without argument: list functions.
|
* ":function" without argument: list functions.
|
||||||
@ -19816,6 +19818,11 @@ void ex_function(exarg_T *eap)
|
|||||||
goto errret_2;
|
goto errret_2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (KeyTyped && ui_is_external(kUICmdline)) {
|
||||||
|
show_block = true;
|
||||||
|
ui_ext_cmdline_block_append(0, (const char *)eap->cmd);
|
||||||
|
}
|
||||||
|
|
||||||
// find extra arguments "range", "dict", "abort" and "closure"
|
// find extra arguments "range", "dict", "abort" and "closure"
|
||||||
for (;; ) {
|
for (;; ) {
|
||||||
p = skipwhite(p);
|
p = skipwhite(p);
|
||||||
@ -19868,7 +19875,9 @@ void ex_function(exarg_T *eap)
|
|||||||
if (!eap->skip && did_emsg)
|
if (!eap->skip && did_emsg)
|
||||||
goto erret;
|
goto erret;
|
||||||
|
|
||||||
msg_putchar('\n'); /* don't overwrite the function name */
|
if (!ui_is_external(kUICmdline)) {
|
||||||
|
msg_putchar('\n'); // don't overwrite the function name
|
||||||
|
}
|
||||||
cmdline_row = msg_row;
|
cmdline_row = msg_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19902,6 +19911,9 @@ void ex_function(exarg_T *eap)
|
|||||||
EMSG(_("E126: Missing :endfunction"));
|
EMSG(_("E126: Missing :endfunction"));
|
||||||
goto erret;
|
goto erret;
|
||||||
}
|
}
|
||||||
|
if (show_block) {
|
||||||
|
ui_ext_cmdline_block_append(indent, (const char *)theline);
|
||||||
|
}
|
||||||
|
|
||||||
/* Detect line continuation: sourcing_lnum increased more than one. */
|
/* Detect line continuation: sourcing_lnum increased more than one. */
|
||||||
if (sourcing_lnum > sourcing_lnum_off + 1)
|
if (sourcing_lnum > sourcing_lnum_off + 1)
|
||||||
@ -20194,6 +20206,9 @@ ret_free:
|
|||||||
xfree(name);
|
xfree(name);
|
||||||
did_emsg |= saved_did_emsg;
|
did_emsg |= saved_did_emsg;
|
||||||
need_wait_return |= saved_wait_return;
|
need_wait_return |= saved_wait_return;
|
||||||
|
if (show_block) {
|
||||||
|
ui_ext_cmdline_block_leave();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a function name, translating "<SID>" and "<SNR>".
|
/// Get a function name, translating "<SID>" and "<SNR>".
|
||||||
|
@ -67,6 +67,30 @@
|
|||||||
#include "nvim/api/private/helpers.h"
|
#include "nvim/api/private/helpers.h"
|
||||||
#include "nvim/highlight_defs.h"
|
#include "nvim/highlight_defs.h"
|
||||||
|
|
||||||
|
/// Command-line colors: one chunk
|
||||||
|
///
|
||||||
|
/// Defines a region which has the same highlighting.
|
||||||
|
typedef struct {
|
||||||
|
int start; ///< Colored chunk start.
|
||||||
|
int end; ///< Colored chunk end (exclusive, > start).
|
||||||
|
int attr; ///< Highlight attr.
|
||||||
|
} CmdlineColorChunk;
|
||||||
|
|
||||||
|
/// Command-line colors
|
||||||
|
///
|
||||||
|
/// Holds data about all colors.
|
||||||
|
typedef kvec_t(CmdlineColorChunk) CmdlineColors;
|
||||||
|
|
||||||
|
/// Command-line coloring
|
||||||
|
///
|
||||||
|
/// Holds both what are the colors and what have been colored. Latter is used to
|
||||||
|
/// suppress unnecessary calls to coloring callbacks.
|
||||||
|
typedef struct {
|
||||||
|
unsigned prompt_id; ///< ID of the prompt which was colored last.
|
||||||
|
char *cmdbuff; ///< What exactly was colored last time or NULL.
|
||||||
|
CmdlineColors colors; ///< Last colors.
|
||||||
|
} ColoredCmdline;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Variables shared between getcmdline(), redrawcmdline() and others.
|
* Variables shared between getcmdline(), redrawcmdline() and others.
|
||||||
* These need to be saved when using CTRL-R |, that's why they are in a
|
* These need to be saved when using CTRL-R |, that's why they are in a
|
||||||
@ -91,6 +115,11 @@ struct cmdline_info {
|
|||||||
int input_fn; // when TRUE Invoked for input() function
|
int input_fn; // when TRUE Invoked for input() function
|
||||||
unsigned prompt_id; ///< Prompt number, used to disable coloring on errors.
|
unsigned prompt_id; ///< Prompt number, used to disable coloring on errors.
|
||||||
Callback highlight_callback; ///< Callback used for coloring user input.
|
Callback highlight_callback; ///< Callback used for coloring user input.
|
||||||
|
ColoredCmdline last_colors; ///< Last cmdline colors
|
||||||
|
int level; // current cmdline level
|
||||||
|
struct cmdline_info *prev_ccline; ///< pointer to saved cmdline state
|
||||||
|
char special_char; ///< last putcmdline char (used for redraws)
|
||||||
|
bool special_shift; ///< shift of last putcmdline char
|
||||||
};
|
};
|
||||||
/// Last value of prompt_id, incremented when doing new prompt
|
/// Last value of prompt_id, incremented when doing new prompt
|
||||||
static unsigned last_prompt_id = 0;
|
static unsigned last_prompt_id = 0;
|
||||||
@ -143,36 +172,6 @@ typedef struct command_line_state {
|
|||||||
struct cmdline_info save_ccline;
|
struct cmdline_info save_ccline;
|
||||||
} CommandLineState;
|
} CommandLineState;
|
||||||
|
|
||||||
/// Command-line colors: one chunk
|
|
||||||
///
|
|
||||||
/// Defines a region which has the same highlighting.
|
|
||||||
typedef struct {
|
|
||||||
int start; ///< Colored chunk start.
|
|
||||||
int end; ///< Colored chunk end (exclusive, > start).
|
|
||||||
int attr; ///< Highlight attr.
|
|
||||||
} CmdlineColorChunk;
|
|
||||||
|
|
||||||
/// Command-line colors
|
|
||||||
///
|
|
||||||
/// Holds data about all colors.
|
|
||||||
typedef kvec_t(CmdlineColorChunk) CmdlineColors;
|
|
||||||
|
|
||||||
/// Command-line coloring
|
|
||||||
///
|
|
||||||
/// Holds both what are the colors and what have been colored. Latter is used to
|
|
||||||
/// suppress unnecessary calls to coloring callbacks.
|
|
||||||
typedef struct {
|
|
||||||
unsigned prompt_id; ///< ID of the prompt which was colored last.
|
|
||||||
char *cmdbuff; ///< What exactly was colored last time or NULL.
|
|
||||||
CmdlineColors colors; ///< Last colors.
|
|
||||||
} ColoredCmdline;
|
|
||||||
|
|
||||||
/// Last command-line colors.
|
|
||||||
ColoredCmdline last_ccline_colors = {
|
|
||||||
.cmdbuff = NULL,
|
|
||||||
.colors = KV_INITIAL_VALUE
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct cmdline_info CmdlineInfo;
|
typedef struct cmdline_info CmdlineInfo;
|
||||||
|
|
||||||
/* The current cmdline_info. It is initialized in getcmdline() and after that
|
/* The current cmdline_info. It is initialized in getcmdline() and after that
|
||||||
@ -185,6 +184,8 @@ static int cmd_showtail; /* Only show path tail in lists ? */
|
|||||||
|
|
||||||
static int new_cmdpos; /* position set by set_cmdline_pos() */
|
static int new_cmdpos; /* position set by set_cmdline_pos() */
|
||||||
|
|
||||||
|
static Array cmdline_block; ///< currently displayed block of context
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Type used by call_user_expand_func
|
* Type used by call_user_expand_func
|
||||||
*/
|
*/
|
||||||
@ -239,6 +240,7 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
}
|
}
|
||||||
|
|
||||||
ccline.prompt_id = last_prompt_id++;
|
ccline.prompt_id = last_prompt_id++;
|
||||||
|
ccline.level++;
|
||||||
ccline.overstrike = false; // always start in insert mode
|
ccline.overstrike = false; // always start in insert mode
|
||||||
clearpos(&s->match_end);
|
clearpos(&s->match_end);
|
||||||
s->save_cursor = curwin->w_cursor; // may be restored later
|
s->save_cursor = curwin->w_cursor; // may be restored later
|
||||||
@ -258,6 +260,9 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
ccline.cmdlen = ccline.cmdpos = 0;
|
ccline.cmdlen = ccline.cmdpos = 0;
|
||||||
ccline.cmdbuff[0] = NUL;
|
ccline.cmdbuff[0] = NUL;
|
||||||
|
|
||||||
|
ccline.last_colors = (ColoredCmdline){ .cmdbuff = NULL,
|
||||||
|
.colors = KV_INITIAL_VALUE };
|
||||||
|
|
||||||
// autoindent for :insert and :append
|
// autoindent for :insert and :append
|
||||||
if (s->firstc <= 0) {
|
if (s->firstc <= 0) {
|
||||||
memset(ccline.cmdbuff, ' ', s->indent);
|
memset(ccline.cmdbuff, ' ', s->indent);
|
||||||
@ -408,12 +413,19 @@ static uint8_t *command_line_enter(int firstc, long count, int indent)
|
|||||||
setmouse();
|
setmouse();
|
||||||
ui_cursor_shape(); // may show different cursor shape
|
ui_cursor_shape(); // may show different cursor shape
|
||||||
xfree(s->save_p_icm);
|
xfree(s->save_p_icm);
|
||||||
|
xfree(ccline.last_colors.cmdbuff);
|
||||||
|
kv_destroy(ccline.last_colors.colors);
|
||||||
|
|
||||||
{
|
{
|
||||||
char_u *p = ccline.cmdbuff;
|
char_u *p = ccline.cmdbuff;
|
||||||
|
|
||||||
// Make ccline empty, getcmdline() may try to use it.
|
// Make ccline empty, getcmdline() may try to use it.
|
||||||
ccline.cmdbuff = NULL;
|
ccline.cmdbuff = NULL;
|
||||||
|
|
||||||
|
if (ui_is_external(kUICmdline)) {
|
||||||
|
ui_call_cmdline_hide(ccline.level);
|
||||||
|
}
|
||||||
|
ccline.level--;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -804,7 +816,9 @@ static int command_line_execute(VimState *state, int key)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!cmd_silent) {
|
if (!cmd_silent) {
|
||||||
ui_cursor_goto(msg_row, 0);
|
if (!ui_is_external(kUICmdline)) {
|
||||||
|
ui_cursor_goto(msg_row, 0);
|
||||||
|
}
|
||||||
ui_flush();
|
ui_flush();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@ -1134,7 +1148,7 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
|
|
||||||
xfree(ccline.cmdbuff); // no commandline to return
|
xfree(ccline.cmdbuff); // no commandline to return
|
||||||
ccline.cmdbuff = NULL;
|
ccline.cmdbuff = NULL;
|
||||||
if (!cmd_silent) {
|
if (!cmd_silent && !ui_is_external(kUICmdline)) {
|
||||||
if (cmdmsg_rl) {
|
if (cmdmsg_rl) {
|
||||||
msg_col = Columns;
|
msg_col = Columns;
|
||||||
} else {
|
} else {
|
||||||
@ -1586,9 +1600,14 @@ static int command_line_handle_key(CommandLineState *s)
|
|||||||
s->do_abbr = false; // don't do abbreviation now
|
s->do_abbr = false; // don't do abbreviation now
|
||||||
// may need to remove ^ when composing char was typed
|
// may need to remove ^ when composing char was typed
|
||||||
if (enc_utf8 && utf_iscomposing(s->c) && !cmd_silent) {
|
if (enc_utf8 && utf_iscomposing(s->c) && !cmd_silent) {
|
||||||
draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
|
if (ui_is_external(kUICmdline)) {
|
||||||
msg_putchar(' ');
|
// TODO(bfredl): why not make unputcmdline also work with true?
|
||||||
cursorcmd();
|
unputcmdline();
|
||||||
|
} else {
|
||||||
|
draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
|
||||||
|
msg_putchar(' ');
|
||||||
|
cursorcmd();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -2346,8 +2365,7 @@ enum { MAX_CB_ERRORS = 1 };
|
|||||||
/// Should use built-in command parser or user-specified one. Currently only the
|
/// Should use built-in command parser or user-specified one. Currently only the
|
||||||
/// latter is supported.
|
/// latter is supported.
|
||||||
///
|
///
|
||||||
/// @param[in] colored_ccline Command-line to color.
|
/// @param[in,out] colored_ccline Command-line to color. Also holds a cache:
|
||||||
/// @param[out] ret_ccline_colors What should be colored. Also holds a cache:
|
|
||||||
/// if ->prompt_id and ->cmdbuff values happen
|
/// if ->prompt_id and ->cmdbuff values happen
|
||||||
/// to be equal to those from colored_cmdline it
|
/// to be equal to those from colored_cmdline it
|
||||||
/// will just do nothing, assuming that ->colors
|
/// will just do nothing, assuming that ->colors
|
||||||
@ -2357,11 +2375,11 @@ enum { MAX_CB_ERRORS = 1 };
|
|||||||
///
|
///
|
||||||
/// @return true if draw_cmdline may proceed, false if it does not need anything
|
/// @return true if draw_cmdline may proceed, false if it does not need anything
|
||||||
/// to do.
|
/// to do.
|
||||||
static bool color_cmdline(const CmdlineInfo *const colored_ccline,
|
static bool color_cmdline(CmdlineInfo *colored_ccline)
|
||||||
ColoredCmdline *const ret_ccline_colors)
|
|
||||||
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
bool printed_errmsg = false;
|
bool printed_errmsg = false;
|
||||||
|
|
||||||
#define PRINT_ERRMSG(...) \
|
#define PRINT_ERRMSG(...) \
|
||||||
do { \
|
do { \
|
||||||
msg_putchar('\n'); \
|
msg_putchar('\n'); \
|
||||||
@ -2370,19 +2388,21 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline,
|
|||||||
} while (0)
|
} while (0)
|
||||||
bool ret = true;
|
bool ret = true;
|
||||||
|
|
||||||
|
ColoredCmdline *ccline_colors = &colored_ccline->last_colors;
|
||||||
|
|
||||||
// Check whether result of the previous call is still valid.
|
// Check whether result of the previous call is still valid.
|
||||||
if (ret_ccline_colors->prompt_id == colored_ccline->prompt_id
|
if (ccline_colors->prompt_id == colored_ccline->prompt_id
|
||||||
&& ret_ccline_colors->cmdbuff != NULL
|
&& ccline_colors->cmdbuff != NULL
|
||||||
&& STRCMP(ret_ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) {
|
&& STRCMP(ccline_colors->cmdbuff, colored_ccline->cmdbuff) == 0) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
kv_size(ret_ccline_colors->colors) = 0;
|
kv_size(ccline_colors->colors) = 0;
|
||||||
|
|
||||||
if (colored_ccline->cmdbuff == NULL || *colored_ccline->cmdbuff == NUL) {
|
if (colored_ccline->cmdbuff == NULL || *colored_ccline->cmdbuff == NUL) {
|
||||||
// Nothing to do, exiting.
|
// Nothing to do, exiting.
|
||||||
xfree(ret_ccline_colors->cmdbuff);
|
xfree(ccline_colors->cmdbuff);
|
||||||
ret_ccline_colors->cmdbuff = NULL;
|
ccline_colors->cmdbuff = NULL;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2395,7 +2415,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline,
|
|||||||
|
|
||||||
static unsigned prev_prompt_id = UINT_MAX;
|
static unsigned prev_prompt_id = UINT_MAX;
|
||||||
static int prev_prompt_errors = 0;
|
static int prev_prompt_errors = 0;
|
||||||
Callback color_cb = { .type = kCallbackNone };
|
Callback color_cb = CALLBACK_NONE;
|
||||||
bool can_free_cb = false;
|
bool can_free_cb = false;
|
||||||
TryState tstate;
|
TryState tstate;
|
||||||
Error err = ERROR_INIT;
|
Error err = ERROR_INIT;
|
||||||
@ -2504,7 +2524,7 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline,
|
|||||||
goto color_cmdline_error;
|
goto color_cmdline_error;
|
||||||
}
|
}
|
||||||
if (start != prev_end) {
|
if (start != prev_end) {
|
||||||
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
|
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
|
||||||
.start = prev_end,
|
.start = prev_end,
|
||||||
.end = start,
|
.end = start,
|
||||||
.attr = 0,
|
.attr = 0,
|
||||||
@ -2533,14 +2553,14 @@ static bool color_cmdline(const CmdlineInfo *const colored_ccline,
|
|||||||
}
|
}
|
||||||
const int id = syn_name2id((char_u *)group);
|
const int id = syn_name2id((char_u *)group);
|
||||||
const int attr = (id == 0 ? 0 : syn_id2attr(id));
|
const int attr = (id == 0 ? 0 : syn_id2attr(id));
|
||||||
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
|
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
|
||||||
.start = start,
|
.start = start,
|
||||||
.end = end,
|
.end = end,
|
||||||
.attr = attr,
|
.attr = attr,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
if (prev_end < colored_ccline->cmdlen) {
|
if (prev_end < colored_ccline->cmdlen) {
|
||||||
kv_push(ret_ccline_colors->colors, ((CmdlineColorChunk) {
|
kv_push(ccline_colors->colors, ((CmdlineColorChunk) {
|
||||||
.start = prev_end,
|
.start = prev_end,
|
||||||
.end = colored_ccline->cmdlen,
|
.end = colored_ccline->cmdlen,
|
||||||
.attr = 0,
|
.attr = 0,
|
||||||
@ -2552,14 +2572,14 @@ color_cmdline_end:
|
|||||||
if (can_free_cb) {
|
if (can_free_cb) {
|
||||||
callback_free(&color_cb);
|
callback_free(&color_cb);
|
||||||
}
|
}
|
||||||
xfree(ret_ccline_colors->cmdbuff);
|
xfree(ccline_colors->cmdbuff);
|
||||||
// Note: errors “output” is cached just as well as regular results.
|
// Note: errors “output” is cached just as well as regular results.
|
||||||
ret_ccline_colors->prompt_id = colored_ccline->prompt_id;
|
ccline_colors->prompt_id = colored_ccline->prompt_id;
|
||||||
if (arg_allocated) {
|
if (arg_allocated) {
|
||||||
ret_ccline_colors->cmdbuff = (char *)arg.vval.v_string;
|
ccline_colors->cmdbuff = (char *)arg.vval.v_string;
|
||||||
} else {
|
} else {
|
||||||
ret_ccline_colors->cmdbuff = xmemdupz((const char *)colored_ccline->cmdbuff,
|
ccline_colors->cmdbuff = xmemdupz((const char *)colored_ccline->cmdbuff,
|
||||||
(size_t)colored_ccline->cmdlen);
|
(size_t)colored_ccline->cmdlen);
|
||||||
}
|
}
|
||||||
tv_clear(&tv);
|
tv_clear(&tv);
|
||||||
return ret;
|
return ret;
|
||||||
@ -2572,7 +2592,7 @@ color_cmdline_error:
|
|||||||
(void)printed_errmsg;
|
(void)printed_errmsg;
|
||||||
|
|
||||||
prev_prompt_errors++;
|
prev_prompt_errors++;
|
||||||
kv_size(ret_ccline_colors->colors) = 0;
|
kv_size(ccline_colors->colors) = 0;
|
||||||
redrawcmdline();
|
redrawcmdline();
|
||||||
ret = false;
|
ret = false;
|
||||||
goto color_cmdline_end;
|
goto color_cmdline_end;
|
||||||
@ -2585,7 +2605,13 @@ color_cmdline_error:
|
|||||||
*/
|
*/
|
||||||
static void draw_cmdline(int start, int len)
|
static void draw_cmdline(int start, int len)
|
||||||
{
|
{
|
||||||
if (!color_cmdline(&ccline, &last_ccline_colors)) {
|
if (!color_cmdline(&ccline)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui_is_external(kUICmdline)) {
|
||||||
|
ccline.special_char = NUL;
|
||||||
|
ui_ext_cmdline_show(&ccline);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2687,9 +2713,9 @@ static void draw_cmdline(int start, int len)
|
|||||||
msg_outtrans_len(arshape_buf, newlen);
|
msg_outtrans_len(arshape_buf, newlen);
|
||||||
} else {
|
} else {
|
||||||
draw_cmdline_no_arabicshape:
|
draw_cmdline_no_arabicshape:
|
||||||
if (kv_size(last_ccline_colors.colors)) {
|
if (kv_size(ccline.last_colors.colors)) {
|
||||||
for (size_t i = 0; i < kv_size(last_ccline_colors.colors); i++) {
|
for (size_t i = 0; i < kv_size(ccline.last_colors.colors); i++) {
|
||||||
CmdlineColorChunk chunk = kv_A(last_ccline_colors.colors, i);
|
CmdlineColorChunk chunk = kv_A(ccline.last_colors.colors, i);
|
||||||
if (chunk.end <= start) {
|
if (chunk.end <= start) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2704,6 +2730,107 @@ draw_cmdline_no_arabicshape:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ui_ext_cmdline_show(CmdlineInfo *line)
|
||||||
|
{
|
||||||
|
Array content = ARRAY_DICT_INIT;
|
||||||
|
if (cmdline_star) {
|
||||||
|
size_t len = 0;
|
||||||
|
for (char_u *p = ccline.cmdbuff; *p; mb_ptr_adv(p)) {
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
char *buf = xmallocz(len);
|
||||||
|
memset(buf, '*', len);
|
||||||
|
Array item = ARRAY_DICT_INIT;
|
||||||
|
ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
|
||||||
|
ADD(item, STRING_OBJ(((String) { .data = buf, .size = len })));
|
||||||
|
ADD(content, ARRAY_OBJ(item));
|
||||||
|
} else if (kv_size(line->last_colors.colors)) {
|
||||||
|
for (size_t i = 0; i < kv_size(line->last_colors.colors); i++) {
|
||||||
|
CmdlineColorChunk chunk = kv_A(line->last_colors.colors, i);
|
||||||
|
Array item = ARRAY_DICT_INIT;
|
||||||
|
|
||||||
|
if (chunk.attr) {
|
||||||
|
attrentry_T *aep = syn_cterm_attr2entry(chunk.attr);
|
||||||
|
// TODO(bfredl): this desicion could be delayed by making attr_code a
|
||||||
|
// recognized type
|
||||||
|
HlAttrs rgb_attrs = attrentry2hlattrs(aep, true);
|
||||||
|
ADD(item, DICTIONARY_OBJ(hlattrs2dict(rgb_attrs)));
|
||||||
|
} else {
|
||||||
|
ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
|
||||||
|
}
|
||||||
|
ADD(item, STRING_OBJ(cbuf_to_string((char *)line->cmdbuff + chunk.start,
|
||||||
|
chunk.end-chunk.start)));
|
||||||
|
ADD(content, ARRAY_OBJ(item));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Array item = ARRAY_DICT_INIT;
|
||||||
|
ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
|
||||||
|
ADD(item, STRING_OBJ(cstr_to_string((char *)(line->cmdbuff))));
|
||||||
|
ADD(content, ARRAY_OBJ(item));
|
||||||
|
}
|
||||||
|
ui_call_cmdline_show(content, line->cmdpos,
|
||||||
|
cchar_to_string((char)line->cmdfirstc),
|
||||||
|
cstr_to_string((char *)(line->cmdprompt)),
|
||||||
|
line->cmdindent,
|
||||||
|
line->level);
|
||||||
|
if (line->special_char) {
|
||||||
|
ui_call_cmdline_special_char(cchar_to_string((char)(line->special_char)),
|
||||||
|
line->special_shift,
|
||||||
|
line->level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_ext_cmdline_block_append(int indent, const char *line)
|
||||||
|
{
|
||||||
|
char *buf = xmallocz(indent + strlen(line));
|
||||||
|
memset(buf, ' ', indent);
|
||||||
|
memcpy(buf+indent, line, strlen(line));
|
||||||
|
|
||||||
|
Array item = ARRAY_DICT_INIT;
|
||||||
|
ADD(item, DICTIONARY_OBJ((Dictionary)ARRAY_DICT_INIT));
|
||||||
|
ADD(item, STRING_OBJ(cstr_as_string(buf)));
|
||||||
|
Array content = ARRAY_DICT_INIT;
|
||||||
|
ADD(content, ARRAY_OBJ(item));
|
||||||
|
ADD(cmdline_block, ARRAY_OBJ(content));
|
||||||
|
if (cmdline_block.size > 1) {
|
||||||
|
ui_call_cmdline_block_append(copy_array(content));
|
||||||
|
} else {
|
||||||
|
ui_call_cmdline_block_show(copy_array(cmdline_block));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_ext_cmdline_block_leave(void)
|
||||||
|
{
|
||||||
|
api_free_array(cmdline_block);
|
||||||
|
ui_call_cmdline_block_hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Extra redrawing needed for redraw! and on ui_attach
|
||||||
|
/// assumes "redrawcmdline()" will already be invoked
|
||||||
|
void cmdline_screen_cleared(void)
|
||||||
|
{
|
||||||
|
if (!ui_is_external(kUICmdline)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmdline_block.size) {
|
||||||
|
ui_call_cmdline_block_show(copy_array(cmdline_block));
|
||||||
|
}
|
||||||
|
|
||||||
|
int prev_level = ccline.level-1;
|
||||||
|
CmdlineInfo *prev_ccline = ccline.prev_ccline;
|
||||||
|
while (prev_level > 0 && prev_ccline) {
|
||||||
|
if (prev_ccline->level == prev_level) {
|
||||||
|
// don't redraw a cmdline already shown in the cmdline window
|
||||||
|
if (prev_level != cmdwin_level) {
|
||||||
|
ui_ext_cmdline_show(prev_ccline);
|
||||||
|
}
|
||||||
|
prev_level--;
|
||||||
|
}
|
||||||
|
prev_ccline = prev_ccline->prev_ccline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Put a character on the command line. Shifts the following text to the
|
* Put a character on the command line. Shifts the following text to the
|
||||||
* right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc.
|
* right when "shift" is TRUE. Used for CTRL-V, CTRL-K, etc.
|
||||||
@ -2711,33 +2838,39 @@ draw_cmdline_no_arabicshape:
|
|||||||
*/
|
*/
|
||||||
void putcmdline(int c, int shift)
|
void putcmdline(int c, int shift)
|
||||||
{
|
{
|
||||||
if (cmd_silent)
|
if (cmd_silent) {
|
||||||
return;
|
return;
|
||||||
msg_no_more = TRUE;
|
}
|
||||||
msg_putchar(c);
|
if (!ui_is_external(kUICmdline)) {
|
||||||
if (shift)
|
msg_no_more = true;
|
||||||
draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
|
msg_putchar(c);
|
||||||
msg_no_more = FALSE;
|
if (shift) {
|
||||||
|
draw_cmdline(ccline.cmdpos, ccline.cmdlen - ccline.cmdpos);
|
||||||
|
}
|
||||||
|
msg_no_more = false;
|
||||||
|
} else {
|
||||||
|
ccline.special_char = c;
|
||||||
|
ccline.special_shift = shift;
|
||||||
|
ui_call_cmdline_special_char(cchar_to_string((char)(c)), shift,
|
||||||
|
ccline.level);
|
||||||
|
}
|
||||||
cursorcmd();
|
cursorcmd();
|
||||||
ui_cursor_shape();
|
ui_cursor_shape();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/// Undo a putcmdline(c, FALSE).
|
||||||
* Undo a putcmdline(c, FALSE).
|
|
||||||
*/
|
|
||||||
void unputcmdline(void)
|
void unputcmdline(void)
|
||||||
{
|
{
|
||||||
if (cmd_silent)
|
if (cmd_silent) {
|
||||||
return;
|
return;
|
||||||
msg_no_more = TRUE;
|
}
|
||||||
if (ccline.cmdlen == ccline.cmdpos)
|
msg_no_more = true;
|
||||||
|
if (ccline.cmdlen == ccline.cmdpos && !ui_is_external(kUICmdline)) {
|
||||||
msg_putchar(' ');
|
msg_putchar(' ');
|
||||||
else if (has_mbyte)
|
} else {
|
||||||
draw_cmdline(ccline.cmdpos,
|
draw_cmdline(ccline.cmdpos, mb_ptr2len(ccline.cmdbuff + ccline.cmdpos));
|
||||||
(*mb_ptr2len)(ccline.cmdbuff + ccline.cmdpos));
|
}
|
||||||
else
|
msg_no_more = false;
|
||||||
draw_cmdline(ccline.cmdpos, 1);
|
|
||||||
msg_no_more = FALSE;
|
|
||||||
cursorcmd();
|
cursorcmd();
|
||||||
ui_cursor_shape();
|
ui_cursor_shape();
|
||||||
}
|
}
|
||||||
@ -2871,9 +3004,6 @@ void put_on_cmdline(char_u *str, int len, int redraw)
|
|||||||
msg_check();
|
msg_check();
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cmdline_info prev_ccline;
|
|
||||||
static int prev_ccline_used = FALSE;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save ccline, because obtaining the "=" register may execute "normal :cmd"
|
* Save ccline, because obtaining the "=" register may execute "normal :cmd"
|
||||||
* and overwrite it. But get_cmdline_str() may need it, thus make it
|
* and overwrite it. But get_cmdline_str() may need it, thus make it
|
||||||
@ -2881,15 +3011,12 @@ static int prev_ccline_used = FALSE;
|
|||||||
*/
|
*/
|
||||||
static void save_cmdline(struct cmdline_info *ccp)
|
static void save_cmdline(struct cmdline_info *ccp)
|
||||||
{
|
{
|
||||||
if (!prev_ccline_used) {
|
*ccp = ccline;
|
||||||
memset(&prev_ccline, 0, sizeof(struct cmdline_info));
|
ccline.prev_ccline = ccp;
|
||||||
prev_ccline_used = TRUE;
|
|
||||||
}
|
|
||||||
*ccp = prev_ccline;
|
|
||||||
prev_ccline = ccline;
|
|
||||||
ccline.cmdbuff = NULL;
|
ccline.cmdbuff = NULL;
|
||||||
ccline.cmdprompt = NULL;
|
ccline.cmdprompt = NULL;
|
||||||
ccline.xpc = NULL;
|
ccline.xpc = NULL;
|
||||||
|
ccline.special_char = NUL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2897,8 +3024,7 @@ static void save_cmdline(struct cmdline_info *ccp)
|
|||||||
*/
|
*/
|
||||||
static void restore_cmdline(struct cmdline_info *ccp)
|
static void restore_cmdline(struct cmdline_info *ccp)
|
||||||
{
|
{
|
||||||
ccline = prev_ccline;
|
ccline = *ccp;
|
||||||
prev_ccline = *ccp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3066,17 +3192,25 @@ static void redrawcmdprompt(void)
|
|||||||
|
|
||||||
if (cmd_silent)
|
if (cmd_silent)
|
||||||
return;
|
return;
|
||||||
if (ccline.cmdfirstc != NUL)
|
if (ui_is_external(kUICmdline)) {
|
||||||
|
ui_ext_cmdline_show(&ccline);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (ccline.cmdfirstc != NUL) {
|
||||||
msg_putchar(ccline.cmdfirstc);
|
msg_putchar(ccline.cmdfirstc);
|
||||||
|
}
|
||||||
if (ccline.cmdprompt != NULL) {
|
if (ccline.cmdprompt != NULL) {
|
||||||
msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr);
|
msg_puts_attr((const char *)ccline.cmdprompt, ccline.cmdattr);
|
||||||
ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
|
ccline.cmdindent = msg_col + (msg_row - cmdline_row) * Columns;
|
||||||
/* do the reverse of set_cmdspos() */
|
// do the reverse of set_cmdspos()
|
||||||
if (ccline.cmdfirstc != NUL)
|
if (ccline.cmdfirstc != NUL) {
|
||||||
--ccline.cmdindent;
|
ccline.cmdindent--;
|
||||||
} else
|
}
|
||||||
for (i = ccline.cmdindent; i > 0; --i)
|
} else {
|
||||||
|
for (i = ccline.cmdindent; i > 0; i--) {
|
||||||
msg_putchar(' ');
|
msg_putchar(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3087,6 +3221,11 @@ void redrawcmd(void)
|
|||||||
if (cmd_silent)
|
if (cmd_silent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ui_is_external(kUICmdline)) {
|
||||||
|
draw_cmdline(0, ccline.cmdlen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* when 'incsearch' is set there may be no command line while redrawing */
|
/* when 'incsearch' is set there may be no command line while redrawing */
|
||||||
if (ccline.cmdbuff == NULL) {
|
if (ccline.cmdbuff == NULL) {
|
||||||
ui_cursor_goto(cmdline_row, 0);
|
ui_cursor_goto(cmdline_row, 0);
|
||||||
@ -3130,6 +3269,11 @@ static void cursorcmd(void)
|
|||||||
if (cmd_silent)
|
if (cmd_silent)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (ui_is_external(kUICmdline)) {
|
||||||
|
ui_call_cmdline_pos(ccline.cmdpos, ccline.level);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (cmdmsg_rl) {
|
if (cmdmsg_rl) {
|
||||||
msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1));
|
msg_row = cmdline_row + (ccline.cmdspos / (int)(Columns - 1));
|
||||||
msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1;
|
msg_col = (int)Columns - (ccline.cmdspos % (int)(Columns - 1)) - 1;
|
||||||
@ -3147,6 +3291,9 @@ static void cursorcmd(void)
|
|||||||
|
|
||||||
void gotocmdline(int clr)
|
void gotocmdline(int clr)
|
||||||
{
|
{
|
||||||
|
if (ui_is_external(kUICmdline)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
msg_start();
|
msg_start();
|
||||||
if (cmdmsg_rl)
|
if (cmdmsg_rl)
|
||||||
msg_col = Columns - 1;
|
msg_col = Columns - 1;
|
||||||
@ -5204,13 +5351,15 @@ int get_history_idx(int histype)
|
|||||||
*/
|
*/
|
||||||
static struct cmdline_info *get_ccline_ptr(void)
|
static struct cmdline_info *get_ccline_ptr(void)
|
||||||
{
|
{
|
||||||
if ((State & CMDLINE) == 0)
|
if ((State & CMDLINE) == 0) {
|
||||||
return NULL;
|
return NULL;
|
||||||
if (ccline.cmdbuff != NULL)
|
} else if (ccline.cmdbuff != NULL) {
|
||||||
return &ccline;
|
return &ccline;
|
||||||
if (prev_ccline_used && prev_ccline.cmdbuff != NULL)
|
} else if (ccline.prev_ccline && ccline.prev_ccline->cmdbuff != NULL) {
|
||||||
return &prev_ccline;
|
return ccline.prev_ccline;
|
||||||
return NULL;
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -5646,6 +5795,7 @@ static int ex_window(void)
|
|||||||
return K_IGNORE;
|
return K_IGNORE;
|
||||||
}
|
}
|
||||||
cmdwin_type = get_cmdline_type();
|
cmdwin_type = get_cmdline_type();
|
||||||
|
cmdwin_level = ccline.level;
|
||||||
|
|
||||||
// Create empty command-line buffer.
|
// Create empty command-line buffer.
|
||||||
buf_open_scratch(0, "[Command Line]");
|
buf_open_scratch(0, "[Command Line]");
|
||||||
@ -5698,6 +5848,9 @@ static int ex_window(void)
|
|||||||
curwin->w_cursor.col = ccline.cmdpos;
|
curwin->w_cursor.col = ccline.cmdpos;
|
||||||
changed_line_abv_curs();
|
changed_line_abv_curs();
|
||||||
invalidate_botline();
|
invalidate_botline();
|
||||||
|
if (ui_is_external(kUICmdline)) {
|
||||||
|
ui_call_cmdline_hide(ccline.level);
|
||||||
|
}
|
||||||
redraw_later(SOME_VALID);
|
redraw_later(SOME_VALID);
|
||||||
|
|
||||||
// Save the command line info, can be used recursively.
|
// Save the command line info, can be used recursively.
|
||||||
@ -5740,6 +5893,7 @@ static int ex_window(void)
|
|||||||
// Restore the command line info.
|
// Restore the command line info.
|
||||||
restore_cmdline(&save_ccline);
|
restore_cmdline(&save_ccline);
|
||||||
cmdwin_type = 0;
|
cmdwin_type = 0;
|
||||||
|
cmdwin_level = 0;
|
||||||
|
|
||||||
exmode_active = save_exmode;
|
exmode_active = save_exmode;
|
||||||
|
|
||||||
@ -5974,3 +6128,4 @@ static void set_search_match(pos_T *t)
|
|||||||
coladvance((colnr_T)MAXCOL);
|
coladvance((colnr_T)MAXCOL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -981,9 +981,10 @@ EXTERN int fill_diff INIT(= '-');
|
|||||||
EXTERN int km_stopsel INIT(= FALSE);
|
EXTERN int km_stopsel INIT(= FALSE);
|
||||||
EXTERN int km_startsel INIT(= FALSE);
|
EXTERN int km_startsel INIT(= FALSE);
|
||||||
|
|
||||||
EXTERN int cedit_key INIT(= -1); /* key value of 'cedit' option */
|
EXTERN int cedit_key INIT(= -1); ///< key value of 'cedit' option
|
||||||
EXTERN int cmdwin_type INIT(= 0); /* type of cmdline window or 0 */
|
EXTERN int cmdwin_type INIT(= 0); ///< type of cmdline window or 0
|
||||||
EXTERN int cmdwin_result INIT(= 0); /* result of cmdline window or 0 */
|
EXTERN int cmdwin_result INIT(= 0); ///< result of cmdline window or 0
|
||||||
|
EXTERN int cmdwin_level INIT(= 0); ///< cmdline recursion level
|
||||||
|
|
||||||
EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--"));
|
EXTERN char_u no_lines_msg[] INIT(= N_("--No lines in buffer--"));
|
||||||
|
|
||||||
|
@ -345,8 +345,9 @@ void update_screen(int type)
|
|||||||
if (need_highlight_changed)
|
if (need_highlight_changed)
|
||||||
highlight_changed();
|
highlight_changed();
|
||||||
|
|
||||||
if (type == CLEAR) { /* first clear screen */
|
if (type == CLEAR) { // first clear screen
|
||||||
screenclear(); /* will reset clear_cmdline */
|
screenclear(); // will reset clear_cmdline
|
||||||
|
cmdline_screen_cleared(); // clear external cmdline state
|
||||||
type = NOT_VALID;
|
type = NOT_VALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
525
test/functional/ui/cmdline_spec.lua
Normal file
525
test/functional/ui/cmdline_spec.lua
Normal file
@ -0,0 +1,525 @@
|
|||||||
|
local helpers = require('test.functional.helpers')(after_each)
|
||||||
|
local Screen = require('test.functional.ui.screen')
|
||||||
|
local clear, feed, eq = helpers.clear, helpers.feed, helpers.eq
|
||||||
|
local source = helpers.source
|
||||||
|
local ok = helpers.ok
|
||||||
|
local command = helpers.command
|
||||||
|
|
||||||
|
describe('external cmdline', function()
|
||||||
|
local screen
|
||||||
|
local last_level = 0
|
||||||
|
local cmdline = {}
|
||||||
|
local block = nil
|
||||||
|
|
||||||
|
before_each(function()
|
||||||
|
clear()
|
||||||
|
cmdline, block = {}, nil
|
||||||
|
screen = Screen.new(25, 5)
|
||||||
|
screen:attach({rgb=true, ext_cmdline=true})
|
||||||
|
screen:set_on_event_handler(function(name, data)
|
||||||
|
if name == "cmdline_show" then
|
||||||
|
local content, pos, firstc, prompt, indent, level = unpack(data)
|
||||||
|
ok(level > 0)
|
||||||
|
cmdline[level] = {content=content, pos=pos, firstc=firstc,
|
||||||
|
prompt=prompt, indent=indent}
|
||||||
|
last_level = level
|
||||||
|
elseif name == "cmdline_hide" then
|
||||||
|
local level = data[1]
|
||||||
|
cmdline[level] = nil
|
||||||
|
elseif name == "cmdline_special_char" then
|
||||||
|
local char, shift, level = unpack(data)
|
||||||
|
cmdline[level].special = {char, shift}
|
||||||
|
elseif name == "cmdline_pos" then
|
||||||
|
local pos, level = unpack(data)
|
||||||
|
cmdline[level].pos = pos
|
||||||
|
elseif name == "cmdline_block_show" then
|
||||||
|
block = data[1]
|
||||||
|
elseif name == "cmdline_block_append" then
|
||||||
|
block[#block+1] = data[1]
|
||||||
|
elseif name == "cmdline_block_hide" then
|
||||||
|
block = nil
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
after_each(function()
|
||||||
|
screen:detach()
|
||||||
|
end)
|
||||||
|
|
||||||
|
local function expect_cmdline(level, expected)
|
||||||
|
local attr_ids = screen._default_attr_ids
|
||||||
|
local attr_ignore = screen._default_attr_ignore
|
||||||
|
local actual = ''
|
||||||
|
for _, chunk in ipairs(cmdline[level] and cmdline[level].content or {}) do
|
||||||
|
local attrs, text = chunk[1], chunk[2]
|
||||||
|
if screen:_equal_attrs(attrs, {}) then
|
||||||
|
actual = actual..text
|
||||||
|
else
|
||||||
|
local attr_id = screen:_get_attr_id(attr_ids, attr_ignore, attrs)
|
||||||
|
actual = actual..'{' .. attr_id .. ':' .. text .. '}'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
eq(expected, actual)
|
||||||
|
end
|
||||||
|
|
||||||
|
it('works', function()
|
||||||
|
feed(':')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq(1, last_level)
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 0,
|
||||||
|
prompt = ""
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed('sign')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "sign" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 4,
|
||||||
|
prompt = ""
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed('<Left>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "sign" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 3,
|
||||||
|
prompt = ""
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed('<bs>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "sin" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 2,
|
||||||
|
prompt = ""
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed('<Esc>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({}, cmdline)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with input()", function()
|
||||||
|
feed(':call input("input", "default")<cr>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "default" } },
|
||||||
|
firstc = "",
|
||||||
|
indent = 0,
|
||||||
|
pos = 7,
|
||||||
|
prompt = "input"
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
feed('<cr>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with special chars and nested cmdline", function()
|
||||||
|
feed(':xx<c-r>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "xx" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 2,
|
||||||
|
prompt = "",
|
||||||
|
special = {'"', true},
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed('=')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "xx" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 2,
|
||||||
|
prompt = "",
|
||||||
|
special = {'"', true},
|
||||||
|
},{
|
||||||
|
content = { { {}, "" } },
|
||||||
|
firstc = "=",
|
||||||
|
indent = 0,
|
||||||
|
pos = 0,
|
||||||
|
prompt = "",
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed('1+2')
|
||||||
|
local expectation = {{
|
||||||
|
content = { { {}, "xx" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 2,
|
||||||
|
prompt = "",
|
||||||
|
special = {'"', true},
|
||||||
|
},{
|
||||||
|
content = { { {}, "1+2" } },
|
||||||
|
firstc = "=",
|
||||||
|
indent = 0,
|
||||||
|
pos = 3,
|
||||||
|
prompt = "",
|
||||||
|
}}
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq(expectation, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- erase information, so we check if it is retransmitted
|
||||||
|
cmdline = {}
|
||||||
|
command("redraw!")
|
||||||
|
-- redraw! forgets cursor position. Be OK with that, as UI should indicate
|
||||||
|
-- focus is at external cmdline anyway.
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
^ |
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq(expectation, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
feed('<cr>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
^ |
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "xx3" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 3,
|
||||||
|
prompt = "",
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed('<esc>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({}, cmdline)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with function definitions", function()
|
||||||
|
feed(':function Foo()<cr>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 2,
|
||||||
|
pos = 0,
|
||||||
|
prompt = "",
|
||||||
|
}}, cmdline)
|
||||||
|
eq({{{{}, 'function Foo()'}}}, block)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed('line1<cr>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{{{}, 'function Foo()'}},
|
||||||
|
{{{}, ' line1'}}}, block)
|
||||||
|
end)
|
||||||
|
|
||||||
|
block = {}
|
||||||
|
command("redraw!")
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
^ |
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{{{}, 'function Foo()'}},
|
||||||
|
{{{}, ' line1'}}}, block)
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
feed('endfunction<cr>')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq(nil, block)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it("works with cmdline window", function()
|
||||||
|
feed(':make')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "make" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 4,
|
||||||
|
prompt = ""
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed('<c-f>')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
[No Name] |
|
||||||
|
:make^ |
|
||||||
|
[Command Line] |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- nested cmdline
|
||||||
|
feed(':yank')
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
[No Name] |
|
||||||
|
:make^ |
|
||||||
|
[Command Line] |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({nil, {
|
||||||
|
content = { { {}, "yank" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 4,
|
||||||
|
prompt = ""
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
cmdline = {}
|
||||||
|
command("redraw!")
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
[No Name] |
|
||||||
|
:make |
|
||||||
|
[Command Line] |
|
||||||
|
^ |
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({nil, {
|
||||||
|
content = { { {}, "yank" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 4,
|
||||||
|
prompt = ""
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed("<c-c>")
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
[No Name] |
|
||||||
|
:make^ |
|
||||||
|
[Command Line] |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
feed("<c-c>")
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
[No Name] |
|
||||||
|
:make^ |
|
||||||
|
[Command Line] |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "make" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 4,
|
||||||
|
prompt = ""
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
|
||||||
|
cmdline = {}
|
||||||
|
command("redraw!")
|
||||||
|
screen:expect([[
|
||||||
|
|
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
^ |
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "make" } },
|
||||||
|
firstc = ":",
|
||||||
|
indent = 0,
|
||||||
|
pos = 4,
|
||||||
|
prompt = ""
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('works with inputsecret()', function()
|
||||||
|
feed(":call inputsecret('secret:')<cr>abc123")
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
~ |
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
eq({{
|
||||||
|
content = { { {}, "******" } },
|
||||||
|
firstc = "",
|
||||||
|
indent = 0,
|
||||||
|
pos = 6,
|
||||||
|
prompt = "secret:"
|
||||||
|
}}, cmdline)
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
|
||||||
|
it('works with highlighted cmdline', function()
|
||||||
|
source([[
|
||||||
|
highlight RBP1 guibg=Red
|
||||||
|
highlight RBP2 guibg=Yellow
|
||||||
|
highlight RBP3 guibg=Green
|
||||||
|
highlight RBP4 guibg=Blue
|
||||||
|
let g:NUM_LVLS = 4
|
||||||
|
function RainBowParens(cmdline)
|
||||||
|
let ret = []
|
||||||
|
let i = 0
|
||||||
|
let lvl = 0
|
||||||
|
while i < len(a:cmdline)
|
||||||
|
if a:cmdline[i] is# '('
|
||||||
|
call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
|
||||||
|
let lvl += 1
|
||||||
|
elseif a:cmdline[i] is# ')'
|
||||||
|
let lvl -= 1
|
||||||
|
call add(ret, [i, i + 1, 'RBP' . ((lvl % g:NUM_LVLS) + 1)])
|
||||||
|
endif
|
||||||
|
let i += 1
|
||||||
|
endwhile
|
||||||
|
return ret
|
||||||
|
endfunction
|
||||||
|
map <f5> :let x = input({'prompt':'>','highlight':'RainBowParens'})<cr>
|
||||||
|
"map <f5> :let x = input({'prompt':'>'})<cr>
|
||||||
|
]])
|
||||||
|
screen:set_default_attr_ids({
|
||||||
|
RBP1={background = Screen.colors.Red},
|
||||||
|
RBP2={background = Screen.colors.Yellow},
|
||||||
|
RBP3={background = Screen.colors.Green},
|
||||||
|
RBP4={background = Screen.colors.Blue},
|
||||||
|
EOB={bold = true, foreground = Screen.colors.Blue1},
|
||||||
|
ERR={foreground = Screen.colors.Grey100, background = Screen.colors.Red},
|
||||||
|
SK={foreground = Screen.colors.Blue},
|
||||||
|
PE={bold = true, foreground = Screen.colors.SeaGreen4}
|
||||||
|
})
|
||||||
|
feed('<f5>(a(b)a)')
|
||||||
|
screen:expect([[
|
||||||
|
^ |
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
{EOB:~ }|
|
||||||
|
|
|
||||||
|
]], nil, nil, function()
|
||||||
|
expect_cmdline(1, '{RBP1:(}a{RBP2:(}b{RBP2:)}a{RBP1:)}')
|
||||||
|
end)
|
||||||
|
end)
|
||||||
|
end)
|
Loading…
Reference in New Issue
Block a user