aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/api.txt59
-rw-r--r--runtime/doc/arabic.txt2
-rw-r--r--runtime/doc/diagnostic.txt8
-rw-r--r--runtime/doc/lsp.txt80
-rw-r--r--runtime/doc/lua.txt28
-rw-r--r--runtime/doc/options.txt28
-rw-r--r--runtime/doc/remote.txt2
-rw-r--r--runtime/doc/syntax.txt4
-rw-r--r--runtime/doc/treesitter.txt6
-rw-r--r--runtime/doc/usr_08.txt2
-rw-r--r--runtime/doc/vim_diff.txt6
-rw-r--r--runtime/doc/windows.txt2
-rw-r--r--runtime/lua/vim/keymap.lua4
-rw-r--r--runtime/lua/vim/lsp.lua2
-rw-r--r--runtime/lua/vim/shared.lua2
-rwxr-xr-xscripts/gen_vimdoc.py71
-rwxr-xr-xscripts/vim-patch.sh4
-rwxr-xr-x[-rw-r--r--]src/nvim/CMakeLists.txt4
-rw-r--r--src/nvim/api/extmark.c4
-rw-r--r--src/nvim/api/private/converter.c17
-rw-r--r--src/nvim/api/private/helpers.c6
-rw-r--r--src/nvim/api/ui_events.in.h4
-rw-r--r--src/nvim/api/vim.c10
-rw-r--r--src/nvim/api/win_config.c3
-rw-r--r--src/nvim/api/window.c2
-rw-r--r--src/nvim/autocmd.c2
-rw-r--r--src/nvim/buffer.c7
-rw-r--r--src/nvim/buffer_defs.h9
-rw-r--r--src/nvim/change.c2
-rw-r--r--src/nvim/cursor_shape.c6
-rw-r--r--src/nvim/decoration.c2
-rw-r--r--src/nvim/edit.c9
-rw-r--r--src/nvim/eval.c1
-rw-r--r--src/nvim/eval/funcs.c9
-rw-r--r--src/nvim/ex_cmds.c208
-rw-r--r--src/nvim/ex_cmds2.c53
-rw-r--r--src/nvim/ex_docmd.c3
-rw-r--r--src/nvim/ex_getln.c7
-rw-r--r--src/nvim/ex_session.c2
-rw-r--r--src/nvim/fold.c402
-rw-r--r--src/nvim/generators/c_grammar.lua1
-rwxr-xr-x[-rw-r--r--]src/nvim/generators/gen_api_ui_events.lua74
-rw-r--r--src/nvim/globals.h5
-rw-r--r--src/nvim/hardcopy.c1
-rw-r--r--src/nvim/highlight.c2
-rw-r--r--src/nvim/highlight_defs.h6
-rw-r--r--src/nvim/highlight_group.c2799
-rw-r--r--src/nvim/highlight_group.h19
-rw-r--r--src/nvim/lua/converter.c16
-rw-r--r--src/nvim/lua/executor.c17
-rw-r--r--src/nvim/main.c13
-rw-r--r--src/nvim/map.c1
-rw-r--r--src/nvim/map.h2
-rw-r--r--src/nvim/memory.c1
-rw-r--r--src/nvim/message.c323
-rw-r--r--src/nvim/msgpack_rpc/channel.c8
-rw-r--r--src/nvim/option.c67
-rw-r--r--src/nvim/os/pty_process_unix.c2
-rw-r--r--src/nvim/os/pty_process_win.c2
-rw-r--r--src/nvim/quickfix.c4
-rw-r--r--src/nvim/screen.c309
-rw-r--r--src/nvim/screen.h8
-rw-r--r--src/nvim/search.c2
-rw-r--r--src/nvim/sign.c9
-rw-r--r--src/nvim/syntax.c2824
-rw-r--r--src/nvim/syntax.h6
-rw-r--r--src/nvim/terminal.c4
-rw-r--r--src/nvim/testdir/test_highlight.vim4
-rw-r--r--src/nvim/tui/input.c26
-rw-r--r--src/nvim/ui.c17
-rw-r--r--src/nvim/ui_client.c163
-rw-r--r--src/nvim/ui_client.h4
-rw-r--r--src/nvim/ui_compositor.c2
-rw-r--r--src/nvim/window.c335
-rw-r--r--test/functional/lua/overrides_spec.lua38
-rw-r--r--test/functional/lua/vim_spec.lua98
-rw-r--r--test/functional/terminal/channel_spec.lua4
-rw-r--r--test/functional/ui/cursor_spec.lua4
-rw-r--r--test/functional/ui/global_statusline_spec.lua233
-rw-r--r--test/functional/ui/hlstate_spec.lua2
-rw-r--r--test/unit/viml/expressions/parser_spec.lua1
81 files changed, 4681 insertions, 3857 deletions
diff --git a/runtime/doc/api.txt b/runtime/doc/api.txt
index 9c3c143045..4af13a3bbf 100644
--- a/runtime/doc/api.txt
+++ b/runtime/doc/api.txt
@@ -594,7 +594,8 @@ nvim__id_float({flt}) *nvim__id_float()*
its argument.
nvim__inspect_cell({grid}, {row}, {col}) *nvim__inspect_cell()*
- TODO: Documentation
+ NB: if your UI doesn't use hlstate, this will not return
+ hlstate first time.
nvim__runtime_inspect() *nvim__runtime_inspect()*
TODO: Documentation
@@ -709,7 +710,7 @@ nvim_call_atomic({calls}) *nvim_call_atomic()*
be returned.
nvim_chan_send({chan}, {data}) *nvim_chan_send()*
- Send data to channel `id` . For a job, it writes it to the
+ Send data to channel `id`. For a job, it writes it to the
stdin of the process. For the stdio channel |channel-stdio|,
it writes to Nvim's stdout. For an internal terminal instance
(|nvim_open_term()|) it writes directly to terminal output.
@@ -849,7 +850,7 @@ nvim_exec_lua({code}, {args}) *nvim_exec_lua()*
inside the chunk. The chunk can return a value.
Only statements are executed. To evaluate an expression,
- prefix it with `return` : return my_function(...)
+ prefix it with `return`: return my_function(...)
Parameters: ~
{code} Lua code to execute
@@ -1132,13 +1133,13 @@ nvim_get_option_value({name}, {*opts}) *nvim_get_option_value()*
Option value
nvim_get_proc({pid}) *nvim_get_proc()*
- Gets info describing process `pid` .
+ Gets info describing process `pid`.
Return: ~
Map of process properties, or NIL if process not found.
nvim_get_proc_children({pid}) *nvim_get_proc_children()*
- Gets the immediate children of process `pid` .
+ Gets the immediate children of process `pid`.
Return: ~
Array of child process ids, empty if process not found.
@@ -1247,8 +1248,8 @@ nvim_input_mouse({button}, {action}, {modifier}, {grid}, {row}, {col})
nvim_list_bufs() *nvim_list_bufs()*
Gets the current list of buffer handles
- Includes unlisted (unloaded/deleted) buffers, like `:ls!` .
- Use |nvim_buf_is_loaded()| to check if a buffer is loaded.
+ Includes unlisted (unloaded/deleted) buffers, like `:ls!`. Use
+ |nvim_buf_is_loaded()| to check if a buffer is loaded.
Return: ~
List of buffer handles
@@ -1357,7 +1358,7 @@ nvim_paste({data}, {crlf}, {phase}) *nvim_paste()*
Errors ('nomodifiable', `vim.paste()` failure, …) are
reflected in `err` but do not affect the return value (which
- is strictly decided by `vim.paste()` ). On error, subsequent
+ is strictly decided by `vim.paste()`). On error, subsequent
calls are ignored ("drained") until the next paste is
initiated (phase 1 or -1).
@@ -1434,7 +1435,7 @@ nvim_select_popupmenu_item({item}, {insert}, {finish}, {opts})
{insert} Whether the selection should be inserted in the
buffer.
{finish} Finish the completion and dismiss the popupmenu.
- Implies `insert` .
+ Implies `insert`.
{opts} Optional parameters. Reserved for future use.
*nvim_set_client_info()*
@@ -1547,18 +1548,21 @@ nvim_set_hl({ns_id}, {name}, {*val}) *nvim_set_hl()*
Sets a highlight group.
Parameters: ~
- {ns_id} Namespace id for this highlight |nvim_create_namespace()|.
- Use 0 to set a highlight group globally |:highlight|.
+ {ns_id} Namespace id for this highlight
+ |nvim_create_namespace()|. Use 0 to set a
+ highlight group globally |:highlight|.
{name} Highlight group name, e.g. "ErrorMsg"
{val} Highlight definition map, like |synIDattr()|. In
addition, the following keys are recognized:
- • default: Don't override existing definition |:hi-default|
- • ctermfg: Sets foreground of cterm color |highlight-ctermfg|
- • ctermbg: Sets background of cterm color |highlight-ctermbg|
+ • default: Don't override existing definition
+ |:hi-default|
+ • ctermfg: Sets foreground of cterm color
+ |highlight-ctermfg|
+ • ctermbg: Sets background of cterm color
+ |highlight-ctermbg|
• cterm: cterm attribute map, like
- |highlight-args|.
- Note: Attributes default to those set for `gui`
- if not set.
+ |highlight-args|. Note: Attributes default to
+ those set for `gui` if not set.
nvim_set_keymap({mode}, {lhs}, {rhs}, {*opts}) *nvim_set_keymap()*
Sets a global |mapping| for the given mode.
@@ -1627,7 +1631,7 @@ nvim_set_vvar({name}, {value}) *nvim_set_vvar()*
{value} Variable value
nvim_strwidth({text}) *nvim_strwidth()*
- Calculates the number of display cells occupied by `text` .
+ Calculates the number of display cells occupied by `text`.
<Tab> counts as one cell.
Parameters: ~
@@ -1879,9 +1883,10 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
{buffer} Buffer handle, or 0 for current buffer
{send_buffer} True if the initial notification should
contain the whole buffer: first
- notification will be `nvim_buf_lines_event`
- . Else the first notification will be
- `nvim_buf_changedtick_event` . Not for Lua
+ notification will be
+ `nvim_buf_lines_event`. Else the first
+ notification will be
+ `nvim_buf_changedtick_event`. Not for Lua
callbacks.
{opts} Optional parameters.
• on_lines: Lua callback invoked on change.
@@ -1937,7 +1942,7 @@ nvim_buf_attach({buffer}, {send_buffer}, {opts}) *nvim_buf_attach()*
• utf_sizes: include UTF-32 and UTF-16 size
of the replaced region, as args to
- `on_lines` .
+ `on_lines`.
• preview: also attach to command preview
(i.e. 'inccommand') events.
@@ -2352,7 +2357,7 @@ nvim_buf_add_highlight({buffer}, {ns_id}, {hl_group}, {line}, {col_start},
namespace. All highlights in the same namespace can then be
cleared with single call to |nvim_buf_clear_namespace()|. If
the highlight never will be deleted by an API call, pass
- `ns_id = -1` .
+ `ns_id = -1`.
As a shorthand, `ns_id = 0` can be used to create a new
namespace for the highlight, the allocated id is then
@@ -2432,8 +2437,8 @@ nvim_buf_get_extmarks({buffer}, {ns_id}, {start}, {end}, {opts})
nvim_buf_get_extmarks(0, my_ns, [0,0], [-1,-1], {})
<
- If `end` is less than `start` , traversal works backwards.
- (Useful with `limit` , to get the first marks prior to a given
+ If `end` is less than `start`, traversal works backwards.
+ (Useful with `limit`, to get the first marks prior to a given
position.)
Example:
@@ -2780,7 +2785,7 @@ nvim_win_hide({window}) *nvim_win_hide()*
|:hide| with a |window-ID|).
Like |:hide| the buffer becomes hidden unless another window
- is editing it, or 'bufhidden' is `unload` , `delete` or `wipe`
+ is editing it, or 'bufhidden' is `unload`, `delete` or `wipe`
as opposed to |:close| or |nvim_win_close|, which will close
the buffer.
@@ -3028,7 +3033,7 @@ nvim_win_set_config({window}, {*config}) *nvim_win_set_config()*
layouts).
When reconfiguring a floating window, absent option keys will
- not be changed. `row` / `col` and `relative` must be
+ not be changed. `row`/`col` and `relative` must be
reconfigured together.
Parameters: ~
diff --git a/runtime/doc/arabic.txt b/runtime/doc/arabic.txt
index 5d3bf7a761..0df861111c 100644
--- a/runtime/doc/arabic.txt
+++ b/runtime/doc/arabic.txt
@@ -175,7 +175,7 @@ o Enable Arabic settings [short-cut]
vertical separator like "l" or "𝖨" may be used. It may also be
hidden by changing its color to the foreground color: >
:set fillchars=vert:l
- :hi VertSplit ctermbg=White
+ :hi WinSeparator ctermbg=White
< Note that this is a workaround, not a proper solution.
If, on the other hand, you'd like to be verbose and explicit and
diff --git a/runtime/doc/diagnostic.txt b/runtime/doc/diagnostic.txt
index e33c786482..32936a7ee6 100644
--- a/runtime/doc/diagnostic.txt
+++ b/runtime/doc/diagnostic.txt
@@ -328,11 +328,11 @@ config({opts}, {namespace}) *vim.diagnostic.config()*
Note:
Each of the configuration options below accepts one of the
following:
- • `false` : Disable this feature
- • `true` : Enable this feature, use default settings.
- • `table` : Enable this feature with overrides. Use an
+ • `false`: Disable this feature
+ • `true`: Enable this feature, use default settings.
+ • `table`: Enable this feature with overrides. Use an
empty table to use default values.
- • `function` : Function with signature (namespace, bufnr)
+ • `function`: Function with signature (namespace, bufnr)
that returns any of the above.
Parameters: ~
diff --git a/runtime/doc/lsp.txt b/runtime/doc/lsp.txt
index 54c648e171..a9ebcd27ae 100644
--- a/runtime/doc/lsp.txt
+++ b/runtime/doc/lsp.txt
@@ -563,7 +563,7 @@ buf_request_all({bufnr}, {method}, {params}, {callback})
Return: ~
(function) A function that will cancel all requests which
- is the same as the one returned from `buf_request` .
+ is the same as the one returned from `buf_request`.
*vim.lsp.buf_request_sync()*
buf_request_sync({bufnr}, {method}, {params}, {timeout_ms})
@@ -600,9 +600,9 @@ client() *vim.lsp.client*
{handler} is not specified, If one is not found there,
then an error will occur. Returns: {status},
{[client_id]}. {status} is a boolean indicating if the
- notification was successful. If it is `false` , then it
+ notification was successful. If it is `false`, then it
will always be `false` (the client has shutdown). If
- {status} is `true` , the function returns {request_id} as
+ {status} is `true`, the function returns {request_id} as
the second result. You can use this with
`client.cancel_request(request_id)` to cancel the request.
• request_sync(method, params, timeout_ms, bufnr) Sends a
@@ -612,13 +612,13 @@ client() *vim.lsp.client*
`err` and `result` come from the |lsp-handler|. On
timeout, cancel or error, returns `(nil, err)` where `err`
is a string describing the failure reason. If the request
- was unsuccessful returns `nil` .
+ was unsuccessful returns `nil`.
• notify(method, params) Sends a notification to an LSP
server. Returns: a boolean to indicate if the notification
was successful. If it is false, then it will always be
false (the client has shutdown).
• cancel_request(id) Cancels a request with a given request
- id. Returns: same as `notify()` .
+ id. Returns: same as `notify()`.
• stop([force]) Stops a client, optionally with force. By
default, it will just ask the server to shutdown without
force. If you request to stop a client which has
@@ -639,14 +639,14 @@ client() *vim.lsp.client*
interaction with the client. See |vim.lsp.rpc.start()|.
• {offset_encoding} (string): The encoding used for
communicating with the server. You can modify this in the
- `config` 's `on_init` method before text is sent to the
+ `config`'s `on_init` method before text is sent to the
server.
• {handlers} (table): The handlers used by the client as
described in |lsp-handler|.
• {requests} (table): The current pending requests in flight
to the server. Entries are key-value pairs with the key
being the request ID while the value is a table with
- `type` , `bufnr` , and `method` key-value pairs. `type` is
+ `type`, `bufnr`, and `method` key-value pairs. `type` is
either "pending" for an active request, or "cancel" for a
cancel request.
• {config} (table): copy of the table that was passed by the
@@ -655,7 +655,7 @@ client() *vim.lsp.client*
sent on `initialize` describing the server's capabilities.
• {resolved_capabilities} (table): Normalized table of
capabilities that we have detected based on the initialize
- response from the server in `server_capabilities` .
+ response from the server in `server_capabilities`.
client_is_stopped({client_id}) *vim.lsp.client_is_stopped()*
Checks whether a client is stopped.
@@ -775,7 +775,7 @@ start_client({config}) *vim.lsp.start_client()*
initiates the LSP client.
{cmd_cwd} (string, default=|getcwd()|)
Directory to launch the `cmd`
- process. Not related to `root_dir` .
+ process. Not related to `root_dir`.
{cmd_env} (table) Environment flags to pass to
the LSP on spawn. Can be specified
using keys like a map or as a list
@@ -800,15 +800,15 @@ start_client({config}) *vim.lsp.start_client()*
its result.
• Note: To send an empty dictionary
use
- `{[vim.type_idx]=vim.types.dictionary}`
- , else it will be encoded as an
+ `{[vim.type_idx]=vim.types.dictionary}`,
+ else it will be encoded as an
array.
{handlers} Map of language server method names
to |lsp-handler|
{settings} Map with language server specific
settings. These are returned to the
language server if requested via
- `workspace/configuration` . Keys are
+ `workspace/configuration`. Keys are
case-sensitive.
{commands} table Table that maps string of
clientside commands to user-defined
@@ -821,7 +821,7 @@ start_client({config}) *vim.lsp.start_client()*
action, code lenses, ...) triggers
the command.
{init_options} Values to pass in the initialization
- request as `initializationOptions` .
+ request as `initializationOptions`.
See `initialize` in the LSP spec.
{name} (string, default=client-id) Name in
log messages.
@@ -976,7 +976,7 @@ code_action({context}) *vim.lsp.buf.code_action()*
• only: (string|nil) LSP `CodeActionKind` used
to filter the code actions. Most language
servers support values like `refactor` or
- `quickfix` .
+ `quickfix`.
See also: ~
https://microsoft.github.io/language-server-protocol/specifications/specification-current/#textDocument_codeAction
@@ -1007,7 +1007,7 @@ definition() *vim.lsp.buf.definition()*
document_highlight() *vim.lsp.buf.document_highlight()*
Send request to the server to resolve document highlights for
the current text document position. This request can be
- triggered by a key mapping or by events such as `CursorHold` ,
+ triggered by a key mapping or by events such as `CursorHold`,
e.g.:
>
autocmd CursorHold <buffer> lua vim.lsp.buf.document_highlight()
@@ -1124,7 +1124,7 @@ range_code_action({context}, {start_pos}, {end_pos})
• only: (string|nil) LSP `CodeActionKind`
used to filter the code actions. Most
language servers support values like
- `refactor` or `quickfix` .
+ `refactor` or `quickfix`.
{start_pos} ({number, number}, optional) mark-indexed
position. Defaults to the start of the last
visual selection.
@@ -1246,8 +1246,8 @@ display({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.display()*
Display the lenses using virtual text
Parameters: ~
- {lenses} table of lenses to display ( `CodeLens[] |
- null` )
+ {lenses} table of lenses to display (`CodeLens[] |
+ null`)
{bufnr} number
{client_id} number
@@ -1259,7 +1259,7 @@ get({bufnr}) *vim.lsp.codelens.get()*
current buffer.
Return: ~
- table ( `CodeLens[]` )
+ table (`CodeLens[]`)
*vim.lsp.codelens.on_codelens()*
on_codelens({err}, {result}, {ctx}, {_})
@@ -1281,8 +1281,8 @@ save({lenses}, {bufnr}, {client_id}) *vim.lsp.codelens.save()*
Store lenses for a specific buffer and client
Parameters: ~
- {lenses} table of lenses to store ( `CodeLens[] |
- null` )
+ {lenses} table of lenses to store (`CodeLens[] |
+ null`)
{bufnr} number
{client_id} number
@@ -1333,7 +1333,7 @@ Lua module: vim.lsp.util *lsp-util*
*vim.lsp.util.apply_text_document_edit()*
apply_text_document_edit({text_document_edit}, {index}, {offset_encoding})
- Applies a `TextDocumentEdit` , which is a list of changes to a
+ Applies a `TextDocumentEdit`, which is a list of changes to a
single document.
Parameters: ~
@@ -1360,7 +1360,7 @@ apply_text_edits({text_edits}, {bufnr}, {offset_encoding})
*vim.lsp.util.apply_workspace_edit()*
apply_workspace_edit({workspace_edit}, {offset_encoding})
- Applies a `WorkspaceEdit` .
+ Applies a `WorkspaceEdit`.
Parameters: ~
{workspace_edit} table `WorkspaceEdit`
@@ -1408,13 +1408,13 @@ convert_input_to_markdown_lines({input}, {contents})
Converts any of `MarkedString` | `MarkedString[]` |
`MarkupContent` into a list of lines containing valid
markdown. Useful to populate the hover window for
- `textDocument/hover` , for parsing the result of
- `textDocument/signatureHelp` , and potentially others.
+ `textDocument/hover`, for parsing the result of
+ `textDocument/signatureHelp`, and potentially others.
Parameters: ~
- {input} ( `MarkedString` | `MarkedString[]` |
- `MarkupContent` )
- {contents} (table, optional, default `{}` ) List of
+ {input} (`MarkedString` | `MarkedString[]` |
+ `MarkupContent`)
+ {contents} (table, optional, default `{}`) List of
strings to extend with converted lines
Return: ~
@@ -1475,7 +1475,7 @@ jump_to_location({location}, {offset_encoding})
Jumps to a location.
Parameters: ~
- {location} table ( `Location` | `LocationLink` )
+ {location} table (`Location`|`LocationLink`)
{offset_encoding} string utf-8|utf-16|utf-32 (required)
Return: ~
@@ -1491,8 +1491,8 @@ locations_to_items({locations}, {offset_encoding})
|setqflist()| or |setloclist()|.
Parameters: ~
- {locations} table list of `Location` s or
- `LocationLink` s
+ {locations} table list of `Location`s or
+ `LocationLink`s
{offset_encoding} string offset_encoding for locations
utf-8|utf-16|utf-32
@@ -1526,7 +1526,7 @@ make_floating_popup_options({width}, {height}, {opts})
• border (string or table) override `border`
• focusable (string or table) override
`focusable`
- • zindex (string or table) override `zindex` ,
+ • zindex (string or table) override `zindex`,
defaults to 50
Return: ~
@@ -1566,7 +1566,7 @@ make_given_range_params({start_pos}, {end_pos}, {bufnr}, {offset_encoding})
Return: ~
{ textDocument = { uri = `current_file_uri` }, range = {
- start = `start_position` , end = `end_position` } }
+ start = `start_position`, end = `end_position` } }
*vim.lsp.util.make_position_params()*
make_position_params({window}, {offset_encoding})
@@ -1590,9 +1590,9 @@ make_position_params({window}, {offset_encoding})
make_range_params({window}, {offset_encoding})
Using the current position in the current buffer, creates an
object that can be used as a building block for several LSP
- requests, such as `textDocument/codeAction` ,
- `textDocument/colorPresentation` ,
- `textDocument/rangeFormatting` .
+ requests, such as `textDocument/codeAction`,
+ `textDocument/colorPresentation`,
+ `textDocument/rangeFormatting`.
Parameters: ~
{window} (optional, number): window handle or 0
@@ -1603,7 +1603,7 @@ make_range_params({window}, {offset_encoding})
Return: ~
{ textDocument = { uri = `current_file_uri` }, range = {
- start = `current_position` , end = `current_position` } }
+ start = `current_position`, end = `current_position` } }
*vim.lsp.util.make_text_document_params()*
make_text_document_params({bufnr})
@@ -1657,8 +1657,8 @@ open_floating_preview({contents}, {syntax}, {opts})
closes the floating window
• focusable: (boolean, default true) Make
float focusable
- • focus: (boolean, default true) If `true` ,
- and if {focusable} is also `true` , focus an
+ • focus: (boolean, default true) If `true`,
+ and if {focusable} is also `true`, focus an
existing floating window with the same
{focus_id}
@@ -1757,7 +1757,7 @@ text_document_completion_list_to_complete_items({result}, {prefix})
Parameters: ~
{result} The result of a `textDocument/completion` call,
e.g. from |vim.lsp.buf.completion()|, which may
- be one of `CompletionItem[]` , `CompletionList`
+ be one of `CompletionItem[]`, `CompletionList`
or `null`
{prefix} (string) the prefix to filter the completion
items
diff --git a/runtime/doc/lua.txt b/runtime/doc/lua.txt
index 11629332ae..93386ddfe9 100644
--- a/runtime/doc/lua.txt
+++ b/runtime/doc/lua.txt
@@ -1418,7 +1418,7 @@ deep_equal({a}, {b}) *vim.deep_equal()*
{b} second value
Return: ~
- `true` if values are equals, else `false` .
+ `true` if values are equals, else `false`.
deepcopy({orig}) *vim.deepcopy()*
Returns a deep copy of the given object. Non-table objects are
@@ -1435,7 +1435,7 @@ deepcopy({orig}) *vim.deepcopy()*
New table of copied keys and (nested) values.
endswith({s}, {suffix}) *vim.endswith()*
- Tests if `s` ends with `suffix` .
+ Tests if `s` ends with `suffix`.
Parameters: ~
{s} (string) a string
@@ -1539,7 +1539,7 @@ split({s}, {sep}, {kwargs}) *vim.split()*
|vim.gsplit()|
startswith({s}, {prefix}) *vim.startswith()*
- Tests if `s` starts with `prefix` .
+ Tests if `s` starts with `prefix`.
Parameters: ~
{s} (string) a string
@@ -1556,7 +1556,7 @@ tbl_add_reverse_lookup({o}) *vim.tbl_add_reverse_lookup()*
{o} table The table to add the reverse to.
tbl_contains({t}, {value}) *vim.tbl_contains()*
- Checks if a list-like (vector) table contains `value` .
+ Checks if a list-like (vector) table contains `value`.
Parameters: ~
{t} Table to check
@@ -1566,7 +1566,7 @@ tbl_contains({t}, {value}) *vim.tbl_contains()*
true if `t` contains `value`
tbl_count({t}) *vim.tbl_count()*
- Counts the number of non-nil values in table `t` .
+ Counts the number of non-nil values in table `t`.
>
vim.tbl_count({ a=1, b=2 }) => 2
@@ -1651,7 +1651,7 @@ tbl_islist({t}) *vim.tbl_islist()*
{t} Table
Return: ~
- `true` if array-like table, else `false` .
+ `true` if array-like table, else `false`.
tbl_keys({t}) *vim.tbl_keys()*
Return a list of all keys used in a table. However, the order
@@ -1813,7 +1813,7 @@ input({opts}, {on_confirm}) *vim.ui.input()*
Parameters: ~
{opts} table Additional options. See |input()|
• prompt (string|nil) Text of the prompt.
- Defaults to `Input:` .
+ Defaults to `Input:`.
• default (string|nil) Default reply to the
input
• completion (string|nil) Specifies type of
@@ -1856,16 +1856,16 @@ select({items}, {opts}, {on_choice}) *vim.ui.select()*
Defaults to `Select one of:`
• format_item (function item -> text)
Function to format an individual item from
- `items` . Defaults to `tostring` .
+ `items`. Defaults to `tostring`.
• kind (string|nil) Arbitrary hint string
indicating the item shape. Plugins
reimplementing `vim.ui.select` may wish to
use this to infer the structure or
- semantics of `items` , or the context in
+ semantics of `items`, or the context in
which select() was called.
{on_choice} function ((item|nil, idx|nil) -> ()) Called
once the user made a choice. `idx` is the
- 1-based index of `item` within `item` . `nil`
+ 1-based index of `item` within `item`. `nil`
if the user aborted the dialog.
@@ -1990,9 +1990,9 @@ set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()*
vim.keymap.set('n', 'asdf', require('jkl').my_fun)
<
- the require('jkl') gets evaluated during this call in order to
- access the function. If you want to avoid this cost at startup
- you can wrap it in a function, for example: >
+ the require('jkl )` gets evaluated during this call in order to access the
+ function. If you want to avoid this cost at startup you can
+ wrap it in a function, for example: >
vim.keymap.set('n', 'asdf', function() return require('jkl').my_fun() end)
<
@@ -2014,7 +2014,7 @@ set({mode}, {lhs}, {rhs}, {opts}) *vim.keymap.set()*
result of Lua expr maps.
• remap: (boolean) Make the mapping recursive.
This is the inverse of the "noremap" option from
- |nvim_set_keymap()|. Default `false` .
+ |nvim_set_keymap()|. Default `false`.
See also: ~
|nvim_set_keymap()|
diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index 82214a2527..b2bbf5ddad 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -2441,7 +2441,14 @@ A jump table for the options with a short description can be found at |Q_op|.
item default Used for ~
stl:c ' ' or '^' statusline of the current window
stlnc:c ' ' or '=' statusline of the non-current windows
+ horiz:c '─' or '-' horizontal separators |:split|
+ horizup:c '┴' or '-' upwards facing horizontal separator
+ horizdown:c '┬' or '-' downwards facing horizontal separator
vert:c '│' or '|' vertical separators |:vsplit|
+ vertleft:c '┤' or '|' left facing vertical separator
+ vertright:c '├' or '|' right facing vertical separator
+ verthoriz:c '┼' or '+' overlapping vertical and horizontal
+ separator
fold:c '·' or '-' filling 'foldtext'
foldopen:c '-' mark the beginning of a fold
foldclose:c '+' show a closed fold
@@ -2454,8 +2461,13 @@ A jump table for the options with a short description can be found at |Q_op|.
"stlnc" the space will be used when there is highlighting, '^' or '='
otherwise.
- If 'ambiwidth' is "double" then "vert", "foldsep" and "fold" default to
- single-byte alternatives.
+ Note that "horiz", "horizup", "horizdown", "vertleft", "vertright" and
+ "verthoriz" are only used when 'laststatus' is 3, since only vertical
+ window separators are used otherwise.
+
+ If 'ambiwidth' is "double" then "horiz", "horizup", "horizdown",
+ "vert", "vertleft", "vertright", "verthoriz", "foldsep" and "fold"
+ default to single-byte alternatives.
Example: >
:set fillchars=stl:^,stlnc:=,vert:│,fold:·,diff:-
@@ -2469,7 +2481,13 @@ A jump table for the options with a short description can be found at |Q_op|.
item highlight group ~
stl:c StatusLine |hl-StatusLine|
stlnc:c StatusLineNC |hl-StatusLineNC|
- vert:c VertSplit |hl-VertSplit|
+ horiz:c WinSeparator |hl-WinSeparator|
+ horizup:c WinSeparator |hl-WinSeparator|
+ horizdown:c WinSeparator |hl-WinSeparator|
+ vert:c WinSeparator |hl-WinSeparator|
+ vertleft:c WinSeparator |hl-WinSeparator|
+ vertright:c WinSeparator |hl-WinSeparator|
+ verthoriz:c WinSeparator |hl-WinSeparator|
fold:c Folded |hl-Folded|
diff:c DiffDelete |hl-DiffDelete|
eob:c EndOfBuffer |hl-EndOfBuffer|
@@ -3652,6 +3670,8 @@ A jump table for the options with a short description can be found at |Q_op|.
0: never
1: only if there are at least two windows
2: always
+ 3: have a global statusline at the bottom instead of one for
+ each window
The screen looks nicer with a status line if you have several
windows, but it takes another screen line. |status-line|
@@ -5929,7 +5949,7 @@ A jump table for the options with a short description can be found at |Q_op|.
empty to avoid further errors. Otherwise screen updating would loop.
Note that the only effect of 'ruler' when this option is set (and
- 'laststatus' is 2) is controlling the output of |CTRL-G|.
+ 'laststatus' is 2 or 3) is controlling the output of |CTRL-G|.
field meaning ~
- Left justify the item. The default is right justified
diff --git a/runtime/doc/remote.txt b/runtime/doc/remote.txt
index b8991be738..0c1e3438de 100644
--- a/runtime/doc/remote.txt
+++ b/runtime/doc/remote.txt
@@ -86,7 +86,7 @@ You can not put options there!
2. Missing functionality *E5600* *clientserver-missing*
Vim supports additional functionality in clientserver that's not yet
-implemented in Nvim. In particular, none of the 'wait' variants are supported
+implemented in Nvim. In particular, none of the "wait" variants are supported
yet. The following command line arguments are not yet available:
argument meaning ~
diff --git a/runtime/doc/syntax.txt b/runtime/doc/syntax.txt
index c5f93fd66f..0ff31e81ab 100644
--- a/runtime/doc/syntax.txt
+++ b/runtime/doc/syntax.txt
@@ -5119,8 +5119,8 @@ TermCursor cursor in a focused terminal
TermCursorNC cursor in an unfocused terminal
*hl-ErrorMsg*
ErrorMsg error messages on the command line
- *hl-VertSplit*
-VertSplit the column separating vertically split windows
+ *hl-WinSeparator*
+WinSeparator separators between window splits
*hl-Folded*
Folded line used for closed folds
*hl-FoldColumn*
diff --git a/runtime/doc/treesitter.txt b/runtime/doc/treesitter.txt
index 02be20c5e8..a9d9f81849 100644
--- a/runtime/doc/treesitter.txt
+++ b/runtime/doc/treesitter.txt
@@ -468,7 +468,7 @@ parse_query({lang}, {query}) *parse_query()*
Exposes `info` and `captures` with additional context about {query}.
• `captures` contains the list of unique capture names defined
- in {query}. - `info.captures` also points to `captures` .
+ in {query}. -`info.captures` also points to `captures`.
• `info.patterns` contains information about predicates.
Parameters: ~
@@ -528,8 +528,8 @@ Query:iter_matches({self}, {node}, {source}, {start}, {stop})
a table mapping capture indices to nodes, and metadata from
any directives processing the match. If the query has more
than one pattern the capture table might be sparse, and e.g.
- `pairs()` method should be used over `ipairs` . Here an
- example iterating over all captures in every match:
+ `pairs()` method should be used over `ipairs`. Here an example
+ iterating over all captures in every match:
>
for pattern, match, metadata in cquery:iter_matches(tree:root(), bufnr, first, last) do
diff --git a/runtime/doc/usr_08.txt b/runtime/doc/usr_08.txt
index 8ccaa73006..1d20913a14 100644
--- a/runtime/doc/usr_08.txt
+++ b/runtime/doc/usr_08.txt
@@ -482,6 +482,8 @@ statusline:
0 never
1 only when there are split windows (the default)
2 always
+ 3 have a global statusline at the bottom instead of one for each
+ window
Many commands that edit another file have a variant that splits the window.
For Command-line commands this is done by prepending an "s". For example:
diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt
index 7f944bbfe6..9ca5faf112 100644
--- a/runtime/doc/vim_diff.txt
+++ b/runtime/doc/vim_diff.txt
@@ -211,6 +211,7 @@ Highlight groups:
|hl-Substitute|
|hl-TermCursor|
|hl-TermCursorNC|
+ |hl-WinSeparator| highlights window separators
|hl-Whitespace| highlights 'listchars' whitespace
Input/Mappings:
@@ -227,9 +228,11 @@ Options:
'cpoptions' flags: |cpo-_|
'display' flags: "msgsep" minimizes scrolling when showing messages
'guicursor' works in the terminal
- 'fillchars' flags: "msgsep" (see 'display')
+ 'fillchars' flags: "msgsep" (see 'display'), "horiz", "horizup",
+ "horizdown", "vertleft", "vertright", "verthoriz"
'foldcolumn' supports up to 9 dynamic/fixed columns
'inccommand' shows interactive results for |:substitute|-like commands
+ 'laststatus' global statusline support
'pumblend' pseudo-transparent popupmenu
'scrollback'
'signcolumn' supports up to 9 dynamic/fixed columns
@@ -348,6 +351,7 @@ Highlight groups:
|hl-ColorColumn|, |hl-CursorColumn| are lower priority than most other
groups
|hl-CursorLine| is low-priority unless foreground color is set
+ *hl-VertSplit* superseded by |hl-WinSeparator|
Macro/|recording| behavior
Replay of a macro recorded during :lmap produces the same actions as when it
diff --git a/runtime/doc/windows.txt b/runtime/doc/windows.txt
index bd29cd1d7a..cd5425336f 100644
--- a/runtime/doc/windows.txt
+++ b/runtime/doc/windows.txt
@@ -104,6 +104,8 @@ when the last window also has a status line:
'laststatus' = 0 never a status line
'laststatus' = 1 status line if there is more than one window
'laststatus' = 2 always a status line
+ 'laststatus' = 3 have a global statusline at the bottom instead
+ of one for each window
You can change the contents of the status line with the 'statusline' option.
This option can be local to the window, so that you can have a different
diff --git a/runtime/lua/vim/keymap.lua b/runtime/lua/vim/keymap.lua
index 7f12372502..1be40b0081 100644
--- a/runtime/lua/vim/keymap.lua
+++ b/runtime/lua/vim/keymap.lua
@@ -25,8 +25,8 @@ local keymap = {}
--- vim.keymap.set('n', 'asdf', require('jkl').my_fun)
--- </pre>
---
---- the `require('jkl')` gets evaluated during this call in order to access the function. If you want to
---- avoid this cost at startup you can wrap it in a function, for example:
+--- the ``require('jkl')`` gets evaluated during this call in order to access the function.
+--- If you want to avoid this cost at startup you can wrap it in a function, for example:
--- <pre>
--- vim.keymap.set('n', 'asdf', function() return require('jkl').my_fun() end)
--- </pre>
diff --git a/runtime/lua/vim/lsp.lua b/runtime/lua/vim/lsp.lua
index 8d11b4621c..105e7c4621 100644
--- a/runtime/lua/vim/lsp.lua
+++ b/runtime/lua/vim/lsp.lua
@@ -1689,7 +1689,7 @@ end
---
--- Currently only supports a single client. This can be set via
--- `setlocal formatexpr=v:lua.vim.lsp.formatexpr()` but will typically or in `on_attach`
---- via `vim.api.nvim_buf_set_option(bufnr, 'formatexpr', 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})')`.
+--- via ``vim.api.nvim_buf_set_option(bufnr, 'formatexpr', 'v:lua.vim.lsp.formatexpr(#{timeout_ms:250})')``.
---
---@param opts table options for customizing the formatting expression which takes the
--- following optional keys:
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 8124b23eb1..3eb332279a 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -331,7 +331,7 @@ end
--- Add the reverse lookup values to an existing table.
--- For example:
---- `tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }`
+--- ``tbl_add_reverse_lookup { A = 1 } == { [1] = 'A', A = 1 }``
--
--Do note that it *modifies* the input.
---@param o table The table to add the reverse to.
diff --git a/scripts/gen_vimdoc.py b/scripts/gen_vimdoc.py
index af49d57492..7152f1005f 100755
--- a/scripts/gen_vimdoc.py
+++ b/scripts/gen_vimdoc.py
@@ -84,8 +84,6 @@ CONFIG = {
'api': {
'mode': 'c',
'filename': 'api.txt',
- # String used to find the start of the generated part of the doc.
- 'section_start_token': '*api-global*',
# Section ordering.
'section_order': [
'vim.c',
@@ -98,8 +96,8 @@ CONFIG = {
'autocmd.c',
'ui.c',
],
- # List of files/directories for doxygen to read, separated by blanks
- 'files': os.path.join(base_dir, 'src/nvim/api'),
+ # List of files/directories for doxygen to read, relative to `base_dir`
+ 'files': ['src/nvim/api'],
# file patterns used by doxygen
'file_patterns': '*.h *.c',
# Only function with this prefix are considered
@@ -122,7 +120,6 @@ CONFIG = {
'lua': {
'mode': 'lua',
'filename': 'lua.txt',
- 'section_start_token': '*lua-vim*',
'section_order': [
'_editor.lua',
'shared.lua',
@@ -131,14 +128,14 @@ CONFIG = {
'filetype.lua',
'keymap.lua',
],
- 'files': ' '.join([
- os.path.join(base_dir, 'runtime/lua/vim/_editor.lua'),
- os.path.join(base_dir, 'runtime/lua/vim/shared.lua'),
- os.path.join(base_dir, 'runtime/lua/vim/uri.lua'),
- os.path.join(base_dir, 'runtime/lua/vim/ui.lua'),
- os.path.join(base_dir, 'runtime/lua/vim/filetype.lua'),
- os.path.join(base_dir, 'runtime/lua/vim/keymap.lua'),
- ]),
+ 'files': [
+ 'runtime/lua/vim/_editor.lua',
+ 'runtime/lua/vim/shared.lua',
+ 'runtime/lua/vim/uri.lua',
+ 'runtime/lua/vim/ui.lua',
+ 'runtime/lua/vim/filetype.lua',
+ 'runtime/lua/vim/keymap.lua',
+ ],
'file_patterns': '*.lua',
'fn_name_prefix': '',
'section_name': {
@@ -171,7 +168,6 @@ CONFIG = {
'lsp': {
'mode': 'lua',
'filename': 'lsp.txt',
- 'section_start_token': '*lsp-core*',
'section_order': [
'lsp.lua',
'buf.lua',
@@ -185,10 +181,10 @@ CONFIG = {
'sync.lua',
'protocol.lua',
],
- 'files': ' '.join([
- os.path.join(base_dir, 'runtime/lua/vim/lsp'),
- os.path.join(base_dir, 'runtime/lua/vim/lsp.lua'),
- ]),
+ 'files': [
+ 'runtime/lua/vim/lsp',
+ 'runtime/lua/vim/lsp.lua',
+ ],
'file_patterns': '*.lua',
'fn_name_prefix': '',
'section_name': {'lsp.lua': 'lsp'},
@@ -214,11 +210,10 @@ CONFIG = {
'diagnostic': {
'mode': 'lua',
'filename': 'diagnostic.txt',
- 'section_start_token': '*diagnostic-api*',
'section_order': [
'diagnostic.lua',
],
- 'files': os.path.join(base_dir, 'runtime/lua/vim/diagnostic.lua'),
+ 'files': ['runtime/lua/vim/diagnostic.lua'],
'file_patterns': '*.lua',
'fn_name_prefix': '',
'section_name': {'diagnostic.lua': 'diagnostic'},
@@ -231,7 +226,6 @@ CONFIG = {
'treesitter': {
'mode': 'lua',
'filename': 'treesitter.txt',
- 'section_start_token': '*lua-treesitter-core*',
'section_order': [
'treesitter.lua',
'language.lua',
@@ -239,10 +233,10 @@ CONFIG = {
'highlighter.lua',
'languagetree.lua',
],
- 'files': ' '.join([
- os.path.join(base_dir, 'runtime/lua/vim/treesitter.lua'),
- os.path.join(base_dir, 'runtime/lua/vim/treesitter/'),
- ]),
+ 'files': [
+ 'runtime/lua/vim/treesitter.lua',
+ 'runtime/lua/vim/treesitter/',
+ ],
'file_patterns': '*.lua',
'fn_name_prefix': '',
'section_name': {},
@@ -349,14 +343,6 @@ def self_or_child(n):
return n.childNodes[0]
-def clean_text(text):
- """Cleans text.
-
- Only cleans superfluous whitespace at the moment.
- """
- return ' '.join(text.split()).strip()
-
-
def clean_lines(text):
"""Removes superfluous lines.
@@ -377,12 +363,12 @@ def get_text(n, preformatted=False):
if n.nodeName == 'computeroutput':
for node in n.childNodes:
text += get_text(node)
- return '`{}` '.format(text)
+ return '`{}`'.format(text)
for node in n.childNodes:
if node.nodeType == node.TEXT_NODE:
- text += node.data if preformatted else clean_text(node.data)
+ text += node.data
elif node.nodeType == node.ELEMENT_NODE:
- text += ' ' + get_text(node, preformatted)
+ text += get_text(node, preformatted)
return text
@@ -849,7 +835,9 @@ def extract_from_xml(filename, target, width):
'seealso': [],
}
if fmt_vimhelp:
- fn['desc_node'] = desc # HACK :(
+ # HACK :(
+ fn['desc_node'] = desc
+ fn['brief_desc_node'] = brief_desc
for m in paras:
if 'text' in m:
@@ -897,6 +885,8 @@ def fmt_doxygen_xml_as_vimhelp(filename, target):
# Generate Vim :help for parameters.
if fn['desc_node']:
doc = fmt_node_as_vimhelp(fn['desc_node'])
+ if not doc and fn['brief_desc_node']:
+ doc = fmt_node_as_vimhelp(fn['brief_desc_node'])
if not doc:
doc = 'TODO: Documentation'
@@ -1006,7 +996,8 @@ def main(config, args):
stderr=(subprocess.STDOUT if debug else subprocess.DEVNULL))
p.communicate(
config.format(
- input=CONFIG[target]['files'],
+ input=' '.join(
+ [f'"{file}"' for file in CONFIG[target]['files']]),
output=output_dir,
filter=filter_cmd,
file_patterns=CONFIG[target]['file_patterns'])
@@ -1096,6 +1087,7 @@ def main(config, args):
raise RuntimeError(
'found new modules "{}"; update the "section_order" map'.format(
set(sections).difference(CONFIG[target]['section_order'])))
+ first_section_tag = sections[CONFIG[target]['section_order'][0]][1]
docs = ''
@@ -1121,7 +1113,8 @@ def main(config, args):
doc_file = os.path.join(base_dir, 'runtime', 'doc',
CONFIG[target]['filename'])
- delete_lines_below(doc_file, CONFIG[target]['section_start_token'])
+ if os.path.exists(doc_file):
+ delete_lines_below(doc_file, first_section_tag)
with open(doc_file, 'ab') as fp:
fp.write(docs.encode('utf8'))
diff --git a/scripts/vim-patch.sh b/scripts/vim-patch.sh
index 591c658e6b..c68ab3a751 100755
--- a/scripts/vim-patch.sh
+++ b/scripts/vim-patch.sh
@@ -236,6 +236,10 @@ preprocess_patch() {
LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/session\(\.[ch]\)/\1\/ex_session\2/g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
+ # Rename highlight.c to highlight_group.c
+ LC_ALL=C sed -e 's/\( [ab]\/src\/nvim\)\/highlight\(\.[ch]\)/\1\/highlight_group\2/g' \
+ "$file" > "$file".tmp && mv "$file".tmp "$file"
+
# Rename test_urls.vim to check_urls.vim
LC_ALL=C sed -e 's@\( [ab]\)/runtime/doc/test\(_urls.vim\)@\1/scripts/check\2@g' \
"$file" > "$file".tmp && mv "$file".tmp "$file"
diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt
index 96e5d1e77c..8e17f94abc 100644..100755
--- a/src/nvim/CMakeLists.txt
+++ b/src/nvim/CMakeLists.txt
@@ -39,6 +39,7 @@ set(GENERATED_UI_EVENTS ${GENERATED_DIR}/ui_events.generated.h)
set(GENERATED_UI_EVENTS_CALL ${GENERATED_DIR}/ui_events_call.generated.h)
set(GENERATED_UI_EVENTS_REMOTE ${GENERATED_DIR}/ui_events_remote.generated.h)
set(GENERATED_UI_EVENTS_BRIDGE ${GENERATED_DIR}/ui_events_bridge.generated.h)
+set(GENERATED_UI_EVENTS_CLIENT ${GENERATED_DIR}/ui_events_client.generated.h)
set(GENERATED_UI_EVENTS_METADATA ${GENERATED_DIR}/api/private/ui_events_metadata.generated.h)
set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h)
set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h)
@@ -271,6 +272,7 @@ foreach(sfile ${NVIM_SOURCES}
"${GENERATED_UI_EVENTS_REMOTE}"
"${GENERATED_UI_EVENTS_BRIDGE}"
"${GENERATED_KEYSETS}"
+ "${GENERATED_UI_EVENTS_CLIENT}"
)
get_filename_component(full_d ${sfile} PATH)
file(RELATIVE_PATH d "${CMAKE_CURRENT_LIST_DIR}" "${full_d}")
@@ -368,6 +370,7 @@ add_custom_command(
${GENERATED_UI_EVENTS_REMOTE}
${GENERATED_UI_EVENTS_BRIDGE}
${GENERATED_UI_EVENTS_METADATA}
+ ${GENERATED_UI_EVENTS_CLIENT}
COMMAND ${LUA_PRG} ${API_UI_EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}
${CMAKE_CURRENT_LIST_DIR}/api/ui_events.in.h
${GENERATED_UI_EVENTS}
@@ -375,6 +378,7 @@ add_custom_command(
${GENERATED_UI_EVENTS_REMOTE}
${GENERATED_UI_EVENTS_BRIDGE}
${GENERATED_UI_EVENTS_METADATA}
+ ${GENERATED_UI_EVENTS_CLIENT}
DEPENDS
${API_UI_EVENTS_GENERATOR}
${GENERATOR_C_GRAMMAR}
diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c
index e355f82f4d..c02688a815 100644
--- a/src/nvim/api/extmark.c
+++ b/src/nvim/api/extmark.c
@@ -10,10 +10,10 @@
#include "nvim/api/private/helpers.h"
#include "nvim/decoration_provider.h"
#include "nvim/extmark.h"
+#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
#include "nvim/memline.h"
#include "nvim/screen.h"
-#include "nvim/syntax.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/extmark.c.generated.h"
@@ -856,7 +856,7 @@ Integer nvim_buf_add_highlight(Buffer buffer, Integer ns_id, String hl_group, In
int hl_id = 0;
if (hl_group.size > 0) {
- hl_id = syn_check_group(hl_group.data, (int)hl_group.size);
+ hl_id = syn_check_group(hl_group.data, hl_group.size);
} else {
return ns_id;
}
diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c
index 49e3cf7df7..82ec1ad0d8 100644
--- a/src/nvim/api/private/converter.c
+++ b/src/nvim/api/private/converter.c
@@ -64,7 +64,14 @@ typedef struct {
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
do { \
- TYPVAL_ENCODE_CONV_NIL(tv); \
+ ufunc_T *fp = find_func(fun); \
+ assert(fp != NULL); \
+ if (fp->uf_cb == nlua_CFunction_func_call) { \
+ LuaRef ref = api_new_luaref(((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); \
+ kvi_push(edata->stack, LUAREF_OBJ(ref)); \
+ } else { \
+ TYPVAL_ENCODE_CONV_NIL(tv); \
+ } \
goto typval_encode_stop_converting_one_item; \
} while (0)
@@ -231,14 +238,6 @@ static inline void typval_encode_dict_end(EncodedData *const edata)
/// @return The converted value
Object vim_to_object(typval_T *obj)
{
- if (obj->v_type == VAR_FUNC) {
- ufunc_T *fp = find_func(obj->vval.v_string);
- assert(fp != NULL);
- if (fp->uf_cb == nlua_CFunction_func_call) {
- LuaRef ref = api_new_luaref(((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref);
- return LUAREF_OBJ(ref);
- }
- }
EncodedData edata;
kvi_init(edata.stack);
const int evo_ret = encode_vim_to_object(&edata, obj,
diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c
index 9f41393c6b..88954a1aa2 100644
--- a/src/nvim/api/private/helpers.c
+++ b/src/nvim/api/private/helpers.c
@@ -22,6 +22,7 @@
#include "nvim/extmark.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/highlight_group.h"
#include "nvim/lib/kvec.h"
#include "nvim/lua/executor.h"
#include "nvim/map.h"
@@ -32,7 +33,6 @@
#include "nvim/msgpack_rpc/helpers.h"
#include "nvim/option.h"
#include "nvim/option_defs.h"
-#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/version.h"
#include "nvim/vim.h"
@@ -1293,7 +1293,7 @@ int object_to_hl_id(Object obj, const char *what, Error *err)
{
if (obj.type == kObjectTypeString) {
String str = obj.data.string;
- return str.size ? syn_check_group(str.data, (int)str.size) : 0;
+ return str.size ? syn_check_group(str.data, str.size) : 0;
} else if (obj.type == kObjectTypeInteger) {
return MAX((int)obj.data.integer, 0);
} else {
@@ -1327,7 +1327,7 @@ HlMessage parse_hl_msg(Array chunks, Error *err)
String hl = chunk.items[1].data.string;
if (hl.size > 0) {
// TODO(bfredl): use object_to_hl_id and allow integer
- int hl_id = syn_check_group(hl.data, (int)hl.size);
+ int hl_id = syn_check_group(hl.data, hl.size);
attr = hl_id > 0 ? syn_id2attr(hl_id) : 0;
}
}
diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h
index 03fe5c5058..db348359eb 100644
--- a/src/nvim/api/ui_events.in.h
+++ b/src/nvim/api/ui_events.in.h
@@ -78,13 +78,13 @@ void hl_attr_define(Integer id, HlAttrs rgb_attrs, HlAttrs cterm_attrs,
void hl_group_set(String name, Integer id)
FUNC_API_SINCE(6) FUNC_API_BRIDGE_IMPL;
void grid_resize(Integer grid, Integer width, Integer height)
- FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
+ FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL FUNC_API_CLIENT_IMPL;
void grid_clear(Integer grid)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL;
void grid_cursor_goto(Integer grid, Integer row, Integer col)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
void grid_line(Integer grid, Integer row, Integer col_start, Array data)
- FUNC_API_SINCE(5) FUNC_API_REMOTE_ONLY;
+ FUNC_API_SINCE(5) FUNC_API_REMOTE_ONLY FUNC_API_CLIENT_IMPL;
void grid_scroll(Integer grid, Integer top, Integer bot,
Integer left, Integer right, Integer rows, Integer cols)
FUNC_API_SINCE(5) FUNC_API_REMOTE_IMPL FUNC_API_COMPOSITOR_IMPL;
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 3292ee2ef8..bdeac1a9f4 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -35,6 +35,7 @@
#include "nvim/globals.h"
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
+#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
@@ -50,7 +51,6 @@
#include "nvim/popupmnu.h"
#include "nvim/screen.h"
#include "nvim/state.h"
-#include "nvim/syntax.h"
#include "nvim/types.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -112,7 +112,7 @@ Dictionary nvim_get_hl_by_id(Integer hl_id, Boolean rgb, Error *err)
Integer nvim_get_hl_id_by_name(String name)
FUNC_API_SINCE(7)
{
- return syn_check_group(name.data, (int)name.size);
+ return syn_check_group(name.data, name.size);
}
Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
@@ -127,7 +127,7 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
///
/// Note: Unlike the `:highlight` command which can update a highlight group,
/// this function completely replaces the definition. For example:
-/// `nvim_set_hl(0, 'Visual', {})` will clear the highlight group 'Visual'.
+/// ``nvim_set_hl(0, 'Visual', {})`` will clear the highlight group 'Visual'.
///
/// @param ns_id Namespace id for this highlight |nvim_create_namespace()|.
/// Use 0 to set a highlight group globally |:highlight|.
@@ -147,7 +147,7 @@ Dictionary nvim__get_hl_defs(Integer ns_id, Error *err)
void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err)
FUNC_API_SINCE(7)
{
- int hl_id = syn_check_group(name.data, (int)name.size);
+ int hl_id = syn_check_group(name.data, name.size);
int link_id = -1;
HlAttrs attrs = dict2hlattrs(val, true, &link_id, err);
@@ -2329,7 +2329,7 @@ Dictionary nvim_eval_statusline(String str, Dict(eval_statusline) *opts, Error *
maxwidth = (int)opts->maxwidth.data.integer;
} else {
- maxwidth = use_tabline ? Columns : wp->w_width;
+ maxwidth = (use_tabline || global_stl_height() > 0) ? Columns : wp->w_width;
}
char buf[MAXPATHL];
diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c
index ceb7f71423..b0267f5ed0 100644
--- a/src/nvim/api/win_config.c
+++ b/src/nvim/api/win_config.c
@@ -10,6 +10,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/api/win_config.h"
#include "nvim/ascii.h"
+#include "nvim/highlight_group.h"
#include "nvim/option.h"
#include "nvim/screen.h"
#include "nvim/strings.h"
@@ -131,7 +132,7 @@
/// An empty string can be used to turn off a specific border, for instance,
/// [ "", "", "", ">", "", "", "", "<" ]
/// will only make vertical borders but not horizontal ones.
-/// By default, `FloatBorder` highlight is used, which links to `VertSplit`
+/// By default, `FloatBorder` highlight is used, which links to `WinSeparator`
/// when not defined. It could also be specified by character:
/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ].
/// - noautocmd: If true then no buffer-related autocommand events such as
diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c
index 9c473ff724..be43708604 100644
--- a/src/nvim/api/window.c
+++ b/src/nvim/api/window.c
@@ -71,7 +71,7 @@ ArrayOf(Integer, 2) nvim_win_get_cursor(Window window, Error *err)
}
/// Sets the (1,0)-indexed cursor position in the window. |api-indexing|
-/// Unlike |win_execute()| this scrolls the window.
+/// This scrolls the window even if it is not the current one.
///
/// @param window Window handle, or 0 for current window
/// @param pos (row, col) tuple representing the new position
diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c
index 8e4b043169..df336d8703 100644
--- a/src/nvim/autocmd.c
+++ b/src/nvim/autocmd.c
@@ -397,7 +397,7 @@ int augroup_add(char *name)
}
/// Delete the augroup that matches name.
-/// @param stupid_legacy_mode bool: This paremeter determines whether to run the augroup
+/// @param stupid_legacy_mode bool: This parameter determines whether to run the augroup
/// deletion in the same fashion as `:augroup! {name}` where if there are any remaining
/// autocmds left in the augroup, it will change the name of the augroup to `--- DELETED ---`
/// but leave the autocmds existing. These are _separate_ augroups, so if you do this for
diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c
index 3fdc111b6f..1293edb1da 100644
--- a/src/nvim/buffer.c
+++ b/src/nvim/buffer.c
@@ -51,6 +51,7 @@
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/main.h"
@@ -4947,8 +4948,8 @@ void ex_buffer_all(exarg_T *eap)
wpnext = wp->w_next;
if ((wp->w_buffer->b_nwindows > 1
|| ((cmdmod.split & WSP_VERT)
- ? wp->w_height + wp->w_status_height < Rows - p_ch
- - tabline_height()
+ ? wp->w_height + wp->w_hsep_height + wp->w_status_height < Rows - p_ch
+ - tabline_height() - global_stl_height()
: wp->w_width != Columns)
|| (had_tab > 0 && wp != firstwin))
&& !ONE_WINDOW
@@ -5481,6 +5482,7 @@ void buf_signcols_add_check(buf_T *buf, sign_entry_T *added)
buf->b_signcols.max++;
}
buf->b_signcols.size++;
+ redraw_buf_later(buf, NOT_VALID);
return;
}
@@ -5501,6 +5503,7 @@ void buf_signcols_add_check(buf_T *buf, sign_entry_T *added)
buf->b_signcols.size = linesum;
buf->b_signcols.max = linesum;
buf->b_signcols.sentinel = added->se_lnum;
+ redraw_buf_later(buf, NOT_VALID);
}
}
diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h
index 7acb646980..f9541a55a3 100644
--- a/src/nvim/buffer_defs.h
+++ b/src/nvim/buffer_defs.h
@@ -1232,7 +1232,13 @@ struct window_S {
struct {
int stl;
int stlnc;
+ int horiz;
+ int horizup;
+ int horizdown;
int vert;
+ int vertleft;
+ int vertright;
+ int verthoriz;
int fold;
int foldopen; ///< when fold is open
int foldclosed; ///< when fold is closed
@@ -1278,7 +1284,8 @@ struct window_S {
int w_status_height; // number of status lines (0 or 1)
int w_wincol; // Leftmost column of window in screen.
int w_width; // Width of window, excluding separation.
- int w_vsep_width; // Number of separator columns (0 or 1).
+ int w_hsep_height; // Number of horizontal separator rows (0 or 1)
+ int w_vsep_width; // Number of vertical separator columns (0 or 1).
pos_save_T w_save_cursor; // backup of cursor pos and topline
// inner size of window, which can be overridden by external UI
diff --git a/src/nvim/change.c b/src/nvim/change.c
index 607414ac3c..6c3dbf72e4 100644
--- a/src/nvim/change.c
+++ b/src/nvim/change.c
@@ -408,7 +408,7 @@ void deleted_lines(linenr_T lnum, long count)
/// be triggered to display the cursor.
void deleted_lines_mark(linenr_T lnum, long count)
{
- // if we deleted the entire buffer, we need to implicity add a new empty line
+ // if we deleted the entire buffer, we need to implicitly add a new empty line
bool made_empty = (count > 0) && curbuf->b_ml.ml_flags & ML_EMPTY;
mark_adjust(lnum, (linenr_T)(lnum + count - 1), (long)MAXLNUM,
diff --git a/src/nvim/cursor_shape.c b/src/nvim/cursor_shape.c
index cb8c8cddf6..0e4a4bcfb0 100644
--- a/src/nvim/cursor_shape.c
+++ b/src/nvim/cursor_shape.c
@@ -9,8 +9,8 @@
#include "nvim/charset.h"
#include "nvim/cursor_shape.h"
#include "nvim/ex_getln.h"
+#include "nvim/highlight_group.h"
#include "nvim/strings.h"
-#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -226,11 +226,11 @@ char *parse_shape_opt(int what)
slashp = vim_strchr(p, '/');
if (slashp != NULL && slashp < endp) {
// "group/langmap_group"
- i = syn_check_group((char *)p, (int)(slashp - p));
+ i = syn_check_group((char *)p, (size_t)(slashp - p));
p = slashp + 1;
}
if (round == 2) {
- shape_table[idx].id = syn_check_group((char *)p, (int)(endp - p));
+ shape_table[idx].id = syn_check_group((char *)p, (size_t)(endp - p));
shape_table[idx].id_lm = shape_table[idx].id;
if (slashp != NULL && slashp < endp) {
shape_table[idx].id = i;
diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c
index 94bf1feeee..fb709d12ff 100644
--- a/src/nvim/decoration.c
+++ b/src/nvim/decoration.c
@@ -5,10 +5,10 @@
#include "nvim/decoration.h"
#include "nvim/extmark.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
#include "nvim/move.h"
#include "nvim/screen.h"
-#include "nvim/syntax.h"
#include "nvim/vim.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
diff --git a/src/nvim/edit.c b/src/nvim/edit.c
index 095e082f61..c087948810 100644
--- a/src/nvim/edit.c
+++ b/src/nvim/edit.c
@@ -26,6 +26,7 @@
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/getchar.h"
+#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
#include "nvim/keymap.h"
@@ -5116,10 +5117,10 @@ static int ins_complete(int c, bool enable_pum)
|| ctrl_x_mode == CTRL_X_PATH_PATTERNS
|| ctrl_x_mode == CTRL_X_PATH_DEFINES) {
if (compl_startpos.lnum != curwin->w_cursor.lnum) {
- /* line (probably) wrapped, set compl_startpos to the
- * first non_blank in the line, if it is not a wordchar
- * include it to get a better pattern, but then we don't
- * want the "\\<" prefix, check it bellow */
+ // line (probably) wrapped, set compl_startpos to the
+ // first non_blank in the line, if it is not a wordchar
+ // include it to get a better pattern, but then we don't
+ // want the "\\<" prefix, check it below.
compl_col = (colnr_T)getwhitecols(line);
compl_startpos.col = compl_col;
compl_startpos.lnum = curwin->w_cursor.lnum;
diff --git a/src/nvim/eval.c b/src/nvim/eval.c
index f4ce6e3b39..af7c3d4985 100644
--- a/src/nvim/eval.c
+++ b/src/nvim/eval.c
@@ -33,6 +33,7 @@
#include "nvim/ex_session.h"
#include "nvim/fileio.h"
#include "nvim/getchar.h"
+#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c
index 738ed7f85e..6e98f229b2 100644
--- a/src/nvim/eval/funcs.c
+++ b/src/nvim/eval/funcs.c
@@ -31,6 +31,7 @@
#include "nvim/fileio.h"
#include "nvim/fold.h"
#include "nvim/globals.h"
+#include "nvim/highlight_group.h"
#include "nvim/if_cscope.h"
#include "nvim/indent.h"
#include "nvim/indent_c.h"
@@ -1500,7 +1501,7 @@ static void f_ctxsize(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// Set the cursor position.
-/// If 'charcol' is true, then use the column number as a character offet.
+/// If 'charcol' is true, then use the column number as a character offset.
/// Otherwise use the column number as a byte offset.
static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol)
{
@@ -3745,7 +3746,7 @@ static void f_getmousepos(typval_T *argvars, typval_T *rettv, FunPtr fptr)
wp = mouse_find_win(&grid, &row, &col);
if (wp != NULL) {
- int height = wp->w_height + wp->w_status_height;
+ int height = wp->w_height + wp->w_hsep_height + wp->w_status_height;
// The height is adjusted by 1 when there is a bottom border. This is not
// necessary for a top border since `row` starts at -1 in that case.
if (row < height + wp->w_border_adj[2]) {
@@ -7781,7 +7782,7 @@ static void f_reverse(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
}
-/// "reduce(list, { accumlator, element -> value } [, initial])" function
+/// "reduce(list, { accumulator, element -> value } [, initial])" function
static void f_reduce(typval_T *argvars, typval_T *rettv, FunPtr fptr)
{
if (argvars[0].v_type != VAR_LIST && argvars[0].v_type != VAR_BLOB) {
@@ -8885,7 +8886,7 @@ static void f_setbufvar(typval_T *argvars, typval_T *rettv, FunPtr fptr)
}
/// Set the cursor or mark position.
-/// If 'charpos' is TRUE, then use the column number as a character offet.
+/// If 'charpos' is TRUE, then use the column number as a character offset.
/// Otherwise use the column number as a byte offset.
static void set_position(typval_T *argvars, typval_T *rettv, bool charpos)
{
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index c7910e148d..ff803c3553 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -38,6 +38,7 @@
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/input.h"
#include "nvim/log.h"
@@ -225,9 +226,7 @@ void do_ascii(const exarg_T *const eap)
msg((char *)IObuff);
}
-/*
- * ":left", ":center" and ":right": align text.
- */
+/// ":left", ":center" and ":right": align text.
void ex_align(exarg_T *eap)
{
pos_T save_curpos;
@@ -324,9 +323,7 @@ void ex_align(exarg_T *eap)
beginline(BL_WHITE | BL_FIX);
}
-/*
- * Get the length of the current line, excluding trailing white space.
- */
+/// @return the length of the current line, excluding trailing white space.
static int linelen(int *has_tab)
{
char_u *line;
@@ -452,7 +449,7 @@ static int sort_compare(const void *s1, const void *s2)
return result;
}
-// ":sort".
+/// ":sort".
void ex_sort(exarg_T *eap)
{
regmatch_T regmatch;
@@ -723,9 +720,7 @@ sortend:
}
}
-/*
- * ":retab".
- */
+/// ":retab".
void ex_retab(exarg_T *eap)
{
linenr_T lnum;
@@ -907,11 +902,9 @@ void ex_retab(exarg_T *eap)
u_clearline();
}
-/*
- * :move command - move lines line1-line2 to line dest
- *
- * return FAIL for failure, OK otherwise
- */
+/// :move command - move lines line1-line2 to line dest
+///
+/// @return FAIL for failure, OK otherwise
int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
{
char_u *str;
@@ -1062,9 +1055,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest)
return OK;
}
-/*
- * ":copy"
- */
+/// ":copy"
void ex_copy(linenr_T line1, linenr_T line2, linenr_T n)
{
linenr_T count;
@@ -1132,11 +1123,9 @@ void free_prev_shellcmd(void)
#endif
-/*
- * Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd"
- * Bangs in the argument are replaced with the previously entered command.
- * Remember the argument.
- */
+/// Handle the ":!cmd" command. Also for ":r !cmd" and ":w !cmd"
+/// Bangs in the argument are replaced with the previously entered command.
+/// Remember the argument.
void do_bang(int addr_count, exarg_T *eap, bool forceit, bool do_in, bool do_out)
FUNC_ATTR_NONNULL_ALL
{
@@ -1684,9 +1673,7 @@ void print_line_no_prefix(linenr_T lnum, int use_number, int list)
msg_prt_line(ml_get(lnum), list);
}
-/*
- * Print a text line. Also in silent mode ("ex -s").
- */
+/// Print a text line. Also in silent mode ("ex -s").
void print_line(linenr_T lnum, int use_number, int list)
{
int save_silent = silent_mode;
@@ -1754,9 +1741,7 @@ int rename_buffer(char_u *new_fname)
return OK;
}
-/*
- * ":file[!] [fname]".
- */
+/// ":file[!] [fname]".
void ex_file(exarg_T *eap)
{
// ":0file" removes the file name. Check for illegal uses ":3file",
@@ -1782,9 +1767,7 @@ void ex_file(exarg_T *eap)
}
}
-/*
- * ":update".
- */
+/// ":update".
void ex_update(exarg_T *eap)
{
if (curbufIsChanged()) {
@@ -1792,9 +1775,7 @@ void ex_update(exarg_T *eap)
}
}
-/*
- * ":write" and ":saveas".
- */
+/// ":write" and ":saveas".
void ex_write(exarg_T *eap)
{
if (eap->cmdidx == CMD_saveas) {
@@ -1810,14 +1791,12 @@ void ex_write(exarg_T *eap)
}
}
-/*
- * write current buffer to file 'eap->arg'
- * if 'eap->append' is TRUE, append to the file
- *
- * if *eap->arg == NUL write to current file
- *
- * return FAIL for failure, OK otherwise
- */
+/// write current buffer to file 'eap->arg'
+/// if 'eap->append' is TRUE, append to the file
+///
+/// if *eap->arg == NUL write to current file
+///
+/// @return FAIL for failure, OK otherwise
int do_write(exarg_T *eap)
{
int other;
@@ -2070,9 +2049,7 @@ int check_overwrite(exarg_T *eap, buf_T *buf, char_u *fname, char_u *ffname, int
return OK;
}
-/*
- * Handle ":wnext", ":wNext" and ":wprevious" commands.
- */
+/// Handle ":wnext", ":wNext" and ":wprevious" commands.
void ex_wnext(exarg_T *eap)
{
int i;
@@ -2089,9 +2066,7 @@ void ex_wnext(exarg_T *eap)
}
}
-/*
- * ":wall", ":wqall" and ":xall": Write all changed files (and exit).
- */
+/// ":wall", ":wqall" and ":xall": Write all changed files (and exit).
void do_wqall(exarg_T *eap)
{
int error = 0;
@@ -2149,8 +2124,9 @@ void do_wqall(exarg_T *eap)
}
}
-// Check the 'write' option.
-// Return true and give a message when it's not st.
+/// Check the 'write' option.
+///
+/// @return true and give a message when it's not st.
bool not_writing(void)
{
if (p_write) {
@@ -2160,11 +2136,9 @@ bool not_writing(void)
return true;
}
-/*
- * Check if a buffer is read-only (either 'readonly' option is set or file is
- * read-only). Ask for overruling in a dialog. Return TRUE and give an error
- * message when the buffer is readonly.
- */
+/// Check if a buffer is read-only (either 'readonly' option is set or file is
+/// read-only). Ask for overruling in a dialog. Return TRUE and give an error
+/// message when the buffer is readonly.
static int check_readonly(int *forceit, buf_T *buf)
{
// Handle a file being readonly when the 'readonly' option is set or when
@@ -2205,15 +2179,16 @@ static int check_readonly(int *forceit, buf_T *buf)
return FALSE;
}
-// Try to abandon the current file and edit a new or existing file.
-// "fnum" is the number of the file, if zero use "ffname_arg"/"sfname_arg".
-// "lnum" is the line number for the cursor in the new file (if non-zero).
-//
-// Return:
-// GETFILE_ERROR for "normal" error,
-// GETFILE_NOT_WRITTEN for "not written" error,
-// GETFILE_SAME_FILE for success
-// GETFILE_OPEN_OTHER for successfully opening another file.
+/// Try to abandon the current file and edit a new or existing file.
+///
+/// @param fnum the number of the file, if zero use "ffname_arg"/"sfname_arg".
+/// @param lnum the line number for the cursor in the new file (if non-zero).
+///
+/// @return:
+/// GETFILE_ERROR for "normal" error,
+/// GETFILE_NOT_WRITTEN for "not written" error,
+/// GETFILE_SAME_FILE for success
+/// GETFILE_OPEN_OTHER for successfully opening another file.
int getfile(int fnum, char_u *ffname_arg, char_u *sfname_arg, int setpm, linenr_T lnum, int forceit)
{
char_u *ffname = ffname_arg;
@@ -2934,9 +2909,7 @@ static void delbuf_msg(char_u *name)
static int append_indent = 0; // autoindent for first line
-/*
- * ":insert" and ":append", also used by ":change"
- */
+/// ":insert" and ":append", also used by ":change"
void ex_append(exarg_T *eap)
{
char_u *theline;
@@ -3078,9 +3051,7 @@ void ex_append(exarg_T *eap)
ex_no_reprint = true;
}
-/*
- * ":change"
- */
+/// ":change"
void ex_change(exarg_T *eap)
{
linenr_T lnum;
@@ -3247,9 +3218,9 @@ void ex_z(exarg_T *eap)
ex_no_reprint = true;
}
-// Check if the secure flag is set (.exrc or .vimrc in current directory).
-// If so, give an error message and return true.
-// Otherwise, return false.
+/// @return true if the secure flag is set (.exrc or .vimrc in current directory)
+/// and also give an error message.
+/// Otherwise, return false.
bool check_secure(void)
{
if (secure) {
@@ -4533,22 +4504,20 @@ static void global_exe_one(char_u *const cmd, const linenr_T lnum)
}
}
-/*
- * Execute a global command of the form:
- *
- * g/pattern/X : execute X on all lines where pattern matches
- * v/pattern/X : execute X on all lines where pattern does not match
- *
- * where 'X' is an EX command
- *
- * The command character (as well as the trailing slash) is optional, and
- * is assumed to be 'p' if missing.
- *
- * This is implemented in two passes: first we scan the file for the pattern and
- * set a mark for each line that (not) matches. Secondly we execute the command
- * for each line that has a mark. This is required because after deleting
- * lines we do not know where to search for the next match.
- */
+/// Execute a global command of the form:
+///
+/// g/pattern/X : execute X on all lines where pattern matches
+/// v/pattern/X : execute X on all lines where pattern does not match
+///
+/// where 'X' is an EX command
+///
+/// The command character (as well as the trailing slash) is optional, and
+/// is assumed to be 'p' if missing.
+///
+/// This is implemented in two passes: first we scan the file for the pattern and
+/// set a mark for each line that (not) matches. Secondly we execute the command
+/// for each line that has a mark. This is required because after deleting
+/// lines we do not know where to search for the next match.
void ex_global(exarg_T *eap)
{
linenr_T lnum; // line number according to old situation
@@ -4764,9 +4733,7 @@ bool prepare_tagpreview(bool undo_sync)
}
-/*
- * ":help": open a read-only window on a help file
- */
+/// ":help": open a read-only window on a help file
void ex_help(exarg_T *eap)
{
char_u *arg;
@@ -4949,11 +4916,10 @@ erret:
}
-/*
- * In an argument search for a language specifiers in the form "@xx".
- * Changes the "@" to NUL if found, and returns a pointer to "xx".
- * Returns NULL if not found.
- */
+/// In an argument search for a language specifiers in the form "@xx".
+/// Changes the "@" to NUL if found, and returns a pointer to "xx".
+///
+/// @return NULL if not found.
char_u *check_help_lang(char_u *arg)
{
int len = (int)STRLEN(arg);
@@ -5019,10 +4985,8 @@ int help_heuristic(char_u *matched_string, int offset, int wrong_case)
return (int)(100 * num_letters + STRLEN(matched_string) + offset);
}
-/*
- * Compare functions for qsort() below, that checks the help heuristics number
- * that has been put after the tagname by find_tags().
- */
+/// Compare functions for qsort() below, that checks the help heuristics number
+/// that has been put after the tagname by find_tags().
static int help_compare(const void *s1, const void *s2)
{
char *p1;
@@ -5033,10 +4997,10 @@ static int help_compare(const void *s1, const void *s2)
return strcmp(p1, p2);
}
-// Find all help tags matching "arg", sort them and return in matches[], with
-// the number of matches in num_matches.
-// The matches will be sorted with a "best" match algorithm.
-// When "keep_lang" is true try keeping the language of the current buffer.
+/// Find all help tags matching "arg", sort them and return in matches[], with
+/// the number of matches in num_matches.
+/// The matches will be sorted with a "best" match algorithm.
+/// When "keep_lang" is true try keeping the language of the current buffer.
int find_help_tags(const char_u *arg, int *num_matches, char_u ***matches, bool keep_lang)
{
int i;
@@ -5308,10 +5272,8 @@ static void prepare_help_buffer(void)
set_buflisted(FALSE);
}
-/*
- * After reading a help file: May cleanup a help buffer when syntax
- * highlighting is not used.
- */
+/// After reading a help file: May cleanup a help buffer when syntax
+/// highlighting is not used.
void fix_help_buffer(void)
{
linenr_T lnum;
@@ -5507,17 +5469,13 @@ void fix_help_buffer(void)
}
}
-/*
- * ":exusage"
- */
+/// ":exusage"
void ex_exusage(exarg_T *eap)
{
do_cmdline_cmd("help ex-cmd-index");
}
-/*
- * ":viusage"
- */
+/// ":viusage"
void ex_viusage(exarg_T *eap)
{
do_cmdline_cmd("help normal-index");
@@ -5826,9 +5784,7 @@ static void helptags_cb(char_u *fname, void *cookie)
do_helptags(fname, *(bool *)cookie, true);
}
-/*
- * ":helptags"
- */
+/// ":helptags"
void ex_helptags(exarg_T *eap)
{
expand_T xpc;
@@ -5857,9 +5813,7 @@ void ex_helptags(exarg_T *eap)
}
}
-/*
- * ":helpclose": Close one help window
- */
+/// ":helpclose": Close one help window
void ex_helpclose(exarg_T *eap)
{
FOR_ALL_WINDOWS_IN_TAB(win, curtab) {
@@ -5873,7 +5827,7 @@ void ex_helpclose(exarg_T *eap)
/// Tries to enter to an existing window of given buffer. If no existing buffer
/// is found, creates a new split.
///
-/// Returns OK/FAIL.
+/// @return OK/FAIL.
int sub_preview_win(buf_T *preview_buf)
{
if (preview_buf != NULL) {
@@ -6115,9 +6069,11 @@ void ex_substitute(exarg_T *eap)
/// Skip over the pattern argument of ":vimgrep /pat/[g][j]".
/// Put the start of the pattern in "*s", unless "s" is NULL.
-/// If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP.
-/// If "s" is not NULL terminate the pattern with a NUL.
-/// Return a pointer to the char just past the pattern plus flags.
+///
+/// @param flags if not NULL, put the flags in it: VGR_GLOBAL, VGR_NOJUMP.
+/// @param s if not NULL, terminate the pattern with a NUL.
+///
+/// @return a pointer to the char just past the pattern plus flags.
char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags)
{
int c;
diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c
index 5c040adc1c..fe1dec7298 100644
--- a/src/nvim/ex_cmds2.c
+++ b/src/nvim/ex_cmds2.c
@@ -436,8 +436,8 @@ static void script_dump_profile(FILE *fd)
}
}
-/// Return true when a function defined in the current script should be
-/// profiled.
+/// @return true when a function defined in the current script should be
+/// profiled.
bool prof_def_func(void)
{
if (current_sctx.sc_sid > 0) {
@@ -492,7 +492,7 @@ void autowrite_all(void)
}
}
-/// Return true if buffer was changed and cannot be abandoned.
+/// @return true if buffer was changed and cannot be abandoned.
/// For flags use the CCGD_ values.
bool check_changed(buf_T *buf, int flags)
{
@@ -616,7 +616,7 @@ bool dialog_close_terminal(buf_T *buf)
return ret == VIM_YES;
}
-/// Return true if the buffer "buf" can be abandoned, either by making it
+/// @return true if the buffer "buf" can be abandoned, either by making it
/// hidden, autowriting it or unloading it.
bool can_abandon(buf_T *buf, int forceit)
{
@@ -771,8 +771,8 @@ theend:
return ret;
}
-/// Return FAIL if there is no file name, OK if there is one.
-/// Give error message for FAIL.
+/// @return FAIL if there is no file name, OK if there is one.
+/// Give error message for FAIL.
int check_fname(void)
{
if (curbuf->b_ffname == NULL) {
@@ -784,7 +784,7 @@ int check_fname(void)
/// Flush the contents of a buffer, unless it has no file name.
///
-/// @return FAIL for failure, OK otherwise
+/// @return FAIL for failure, OK otherwise
int buf_write_all(buf_T *buf, int forceit)
{
int retval;
@@ -808,7 +808,8 @@ int buf_write_all(buf_T *buf, int forceit)
/// Isolate one argument, taking backticks.
/// Changes the argument in-place, puts a NUL after it. Backticks remain.
-/// Return a pointer to the start of the next argument.
+///
+/// @return a pointer to the start of the next argument.
static char_u *do_one_arg(char_u *str)
{
char_u *p;
@@ -859,7 +860,7 @@ static void get_arglist(garray_T *gap, char_u *str, int escaped)
/// Parse a list of arguments (file names), expand them and return in
/// "fnames[fcountp]". When "wig" is true, removes files matching 'wildignore'.
///
-/// @return FAIL or OK.
+/// @return FAIL or OK.
int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig)
{
garray_T ga;
@@ -889,7 +890,7 @@ int get_arglist_exp(char_u *str, int *fcountp, char_u ***fnamesp, bool wig)
/// 0 means before first one
/// @param will_edit will edit added argument
///
-/// @return FAIL for failure, OK otherwise.
+/// @return FAIL for failure, OK otherwise.
static int do_arglist(char_u *str, int what, int after, bool will_edit)
FUNC_ATTR_NONNULL_ALL
{
@@ -988,8 +989,8 @@ static void alist_check_arg_idx(void)
}
}
-/// Return true if window "win" is editing the file at the current argument
-/// index.
+/// @return true if window "win" is editing the file at the current argument
+/// index.
static bool editing_arg_idx(win_T *win)
{
return !(win->w_arg_idx >= WARGCOUNT(win)
@@ -1717,13 +1718,13 @@ linenr_T *source_breakpoint(void *cookie)
return &((struct source_cookie *)cookie)->breakpoint;
}
-/// Return the address holding the debug tick for a source cookie.
+/// @return the address holding the debug tick for a source cookie.
int *source_dbg_tick(void *cookie)
{
return &((struct source_cookie *)cookie)->dbg_tick;
}
-/// Return the nesting level for a source cookie.
+/// @return the nesting level for a source cookie.
int source_level(void *cookie)
{
return ((struct source_cookie *)cookie)->level;
@@ -1788,7 +1789,8 @@ static char_u *get_str_line(int c, void *cookie, int indent, bool do_concat)
///
/// @param name File name of the script. NULL for anonymous :source.
/// @param[out] sid_out SID of the new item.
-/// @return pointer to the created script item.
+///
+/// @return pointer to the created script item.
scriptitem_T *new_script_item(char_u *const name, scid_T *const sid_out)
{
static scid_T last_current_SID = 0;
@@ -1896,7 +1898,7 @@ int do_source_str(const char *cmd, const char *traceback_name)
/// @param check_other check for .vimrc and _vimrc
/// @param is_vimrc DOSO_ value
///
-/// @return FAIL if file could not be opened, OK otherwise
+/// @return FAIL if file could not be opened, OK otherwise
int do_source(char *fname, int check_other, int is_vimrc)
{
struct source_cookie cookie;
@@ -2145,6 +2147,7 @@ theend:
/// Check if fname was sourced before to finds its SID.
/// If it's new, generate a new SID.
+///
/// @param[in] fname file path of script
/// @param[out] ret_sctx sctx of this script
scriptitem_T *get_current_script_id(char_u *fname, sctx_T *ret_sctx)
@@ -2614,9 +2617,9 @@ void do_finish(exarg_T *eap, int reanimate)
}
-/// Return true when a sourced file had the ":finish" command: Don't give error
-/// message for missing ":endif".
-/// Return false when not sourcing a file.
+/// @return true when a sourced file had the ":finish" command: Don't give error
+/// message for missing ":endif".
+/// false when not sourcing a file.
bool source_finished(LineGetter fgetline, void *cookie)
{
return getline_equal(fgetline, cookie, getsourceline)
@@ -2653,8 +2656,8 @@ static char *get_locale_val(int what)
}
#endif
-// Return true when "lang" starts with a valid language name.
-// Rejects NULL, empty string, "C", "C.UTF-8" and others.
+/// @return true when "lang" starts with a valid language name.
+/// Rejects NULL, empty string, "C", "C.UTF-8" and others.
static bool is_valid_mess_lang(char *lang)
{
return lang != NULL && ASCII_ISALPHA(lang[0]) && ASCII_ISALPHA(lang[1]);
@@ -2757,11 +2760,10 @@ void set_lang_var(void)
}
#ifdef HAVE_WORKING_LIBINTL
-///
+
/// ":language": Set the language (locale).
///
/// @param eap
-///
void ex_language(exarg_T *eap)
{
char *loc;
@@ -2870,8 +2872,9 @@ static char_u **locales = NULL; // Array of all available locales
# ifndef WIN32
static bool did_init_locales = false;
-/// Return an array of strings for all available locales + NULL for the
-/// last element. Return NULL in case of error.
+/// @return an array of strings for all available locales + NULL for the
+/// last element or,
+/// NULL in case of error.
static char_u **find_locales(void)
{
garray_T locales_ga;
diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c
index 76bf4d60c1..511dd44c9f 100644
--- a/src/nvim/ex_docmd.c
+++ b/src/nvim/ex_docmd.c
@@ -38,6 +38,7 @@
#include "nvim/getchar.h"
#include "nvim/globals.h"
#include "nvim/hardcopy.h"
+#include "nvim/highlight_group.h"
#include "nvim/if_cscope.h"
#include "nvim/input.h"
#include "nvim/keymap.h"
@@ -9475,7 +9476,7 @@ static void ex_filetype(exarg_T *eap)
/// Source ftplugin.vim and indent.vim to create the necessary FileType
/// autocommands. We do this separately from filetype.vim so that these
-/// autocommands will always fire first (and thus can be overriden) while still
+/// autocommands will always fire first (and thus can be overridden) while still
/// allowing general filetype detection to be disabled in the user's init file.
void filetype_plugin_enable(void)
{
diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c
index f52f3afe7d..84fca137d2 100644
--- a/src/nvim/ex_getln.c
+++ b/src/nvim/ex_getln.c
@@ -35,6 +35,7 @@
#include "nvim/getchar.h"
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
+#include "nvim/highlight_group.h"
#include "nvim/if_cscope.h"
#include "nvim/indent.h"
#include "nvim/keymap.h"
@@ -231,7 +232,7 @@ static int compl_selected;
/// |:checkhealth| completion items
///
-/// Regenerates on every new command line prompt, to accomodate changes on the
+/// Regenerates on every new command line prompt, to accommodate changes on the
/// runtime files.
typedef struct {
garray_T names; // healthcheck names
@@ -632,7 +633,7 @@ static void may_do_incsearch_highlighting(int firstc, long count, incsearch_stat
validate_cursor();
// May redraw the status line to show the cursor position.
- if (p_ru && curwin->w_status_height > 0) {
+ if (p_ru && (curwin->w_status_height > 0 || global_stl_height() > 0)) {
curwin->w_redr_status = true;
}
@@ -3631,7 +3632,7 @@ void compute_cmdrow(void)
} else {
win_T *wp = lastwin_nofloating();
cmdline_row = wp->w_winrow + wp->w_height
- + wp->w_status_height;
+ + wp->w_hsep_height + wp->w_status_height + global_stl_height();
}
lines_left = cmdline_row;
}
diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c
index e398c1ee64..0e2b7c0ece 100644
--- a/src/nvim/ex_session.c
+++ b/src/nvim/ex_session.c
@@ -72,7 +72,7 @@ static int ses_winsizes(FILE *fd, int restore_size, win_T *tab_firstwin)
n++;
// restore height when not full height
- if (wp->w_height + wp->w_status_height < topframe->fr_height
+ if (wp->w_height + wp->w_hsep_height + wp->w_status_height < topframe->fr_height
&& (fprintf(fd,
"exe '%dresize ' . ((&lines * %" PRId64
" + %" PRId64 ") / %" PRId64 ")\n",
diff --git a/src/nvim/fold.c b/src/nvim/fold.c
index 546345eeac..54430d46af 100644
--- a/src/nvim/fold.c
+++ b/src/nvim/fold.c
@@ -121,9 +121,7 @@ static size_t foldendmarkerlen;
// Exported folding functions. {{{1
// copyFoldingState() {{{2
-/*
- * Copy that folding state from window "wp_from" to window "wp_to".
- */
+/// Copy that folding state from window "wp_from" to window "wp_to".
void copyFoldingState(win_T *wp_from, win_T *wp_to)
{
wp_to->w_fold_manual = wp_from->w_fold_manual;
@@ -132,9 +130,7 @@ void copyFoldingState(win_T *wp_from, win_T *wp_to)
}
// hasAnyFolding() {{{2
-/*
- * Return TRUE if there may be folded lines in the current window.
- */
+/// @return TRUE if there may be folded lines in the current window.
int hasAnyFolding(win_T *win)
{
// very simple now, but can become more complex later
@@ -259,9 +255,7 @@ bool hasFoldingWin(win_T *const win, const linenr_T lnum, linenr_T *const firstp
}
// foldLevel() {{{2
-/*
- * Return fold level at line number "lnum" in the current window.
- */
+/// @return fold level at line number "lnum" in the current window.
int foldLevel(linenr_T lnum)
{
// While updating the folds lines between invalid_top and invalid_bot have
@@ -283,15 +277,16 @@ int foldLevel(linenr_T lnum)
}
// lineFolded() {{{2
-// Low level function to check if a line is folded. Doesn't use any caching.
-// Return true if line is folded.
-// Return false if line is not folded.
+/// Low level function to check if a line is folded. Doesn't use any caching.
+///
+/// @return true if line is folded or,
+/// false if line is not folded.
bool lineFolded(win_T *const win, const linenr_T lnum)
{
return fold_info(win, lnum).fi_lines != 0;
}
-/// fold_info() {{{2
+// fold_info() {{{2
///
/// Count the number of lines that are folded at line number "lnum".
/// Normally "lnum" is the first line of a possible fold, and the returned
@@ -316,61 +311,49 @@ foldinfo_T fold_info(win_T *win, linenr_T lnum)
}
// foldmethodIsManual() {{{2
-/*
- * Return TRUE if 'foldmethod' is "manual"
- */
+/// @return TRUE if 'foldmethod' is "manual"
int foldmethodIsManual(win_T *wp)
{
return wp->w_p_fdm[3] == 'u';
}
// foldmethodIsIndent() {{{2
-/*
- * Return TRUE if 'foldmethod' is "indent"
- */
+/// @return TRUE if 'foldmethod' is "indent"
int foldmethodIsIndent(win_T *wp)
{
return wp->w_p_fdm[0] == 'i';
}
// foldmethodIsExpr() {{{2
-/*
- * Return TRUE if 'foldmethod' is "expr"
- */
+/// @return TRUE if 'foldmethod' is "expr"
int foldmethodIsExpr(win_T *wp)
{
return wp->w_p_fdm[1] == 'x';
}
// foldmethodIsMarker() {{{2
-/*
- * Return TRUE if 'foldmethod' is "marker"
- */
+/// @return TRUE if 'foldmethod' is "marker"
int foldmethodIsMarker(win_T *wp)
{
return wp->w_p_fdm[2] == 'r';
}
// foldmethodIsSyntax() {{{2
-/*
- * Return TRUE if 'foldmethod' is "syntax"
- */
+/// @return TRUE if 'foldmethod' is "syntax"
int foldmethodIsSyntax(win_T *wp)
{
return wp->w_p_fdm[0] == 's';
}
// foldmethodIsDiff() {{{2
-/*
- * Return TRUE if 'foldmethod' is "diff"
- */
+/// @return TRUE if 'foldmethod' is "diff"
int foldmethodIsDiff(win_T *wp)
{
return wp->w_p_fdm[0] == 'd';
}
// closeFold() {{{2
-/// Close fold for current window at line "lnum".
+/// Close fold for current window at position "pos".
/// Repeat "count" times.
void closeFold(pos_T pos, long count)
{
@@ -378,9 +361,7 @@ void closeFold(pos_T pos, long count)
}
// closeFoldRecurse() {{{2
-/*
- * Close fold for current window at line "lnum" recursively.
- */
+/// Close fold for current window at position `pos` recursively.
void closeFoldRecurse(pos_T pos)
{
(void)setManualFold(pos, false, true, NULL);
@@ -427,28 +408,22 @@ void opFoldRange(pos_T firstpos, pos_T lastpos, int opening, int recurse, int ha
}
// openFold() {{{2
-/*
- * Open fold for current window at line "lnum".
- * Repeat "count" times.
- */
+/// Open fold for current window at position "pos".
+/// Repeat "count" times.
void openFold(pos_T pos, long count)
{
setFoldRepeat(pos, count, true);
}
// openFoldRecurse() {{{2
-/*
- * Open fold for current window at line "lnum" recursively.
- */
+/// Open fold for current window at position `pos` recursively.
void openFoldRecurse(pos_T pos)
{
(void)setManualFold(pos, true, true, NULL);
}
// foldOpenCursor() {{{2
-/*
- * Open folds until the cursor line is not in a closed fold.
- */
+/// Open folds until the cursor line is not in a closed fold.
void foldOpenCursor(void)
{
int done;
@@ -466,9 +441,7 @@ void foldOpenCursor(void)
}
// newFoldLevel() {{{2
-/*
- * Set new foldlevel for current window.
- */
+/// Set new foldlevel for current window.
void newFoldLevel(void)
{
newFoldLevelWin(curwin);
@@ -505,9 +478,7 @@ static void newFoldLevelWin(win_T *wp)
}
// foldCheckClose() {{{2
-/*
- * Apply 'foldlevel' to all folds that don't contain the cursor.
- */
+/// Apply 'foldlevel' to all folds that don't contain the cursor.
void foldCheckClose(void)
{
if (*p_fcl != NUL) { // can only be "all" right now
@@ -543,8 +514,8 @@ static int checkCloseRec(garray_T *gap, linenr_T lnum, int level)
}
// foldCreateAllowed() {{{2
-/// Return TRUE if it's allowed to manually create or delete a fold.
-/// Give an error message and return FALSE if not.
+/// @return TRUE if it's allowed to manually create or delete a fold or,
+/// give an error message and return FALSE if not.
int foldManualAllowed(bool create)
{
if (foldmethodIsManual(curwin) || foldmethodIsMarker(curwin)) {
@@ -790,9 +761,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const
}
// clearFolding() {{{2
-/*
- * Remove all folding for window "win".
- */
+/// Remove all folding for window "win".
void clearFolding(win_T *win)
{
deleteFoldRecurse(win->w_buffer, &win->w_folds);
@@ -800,12 +769,10 @@ void clearFolding(win_T *win)
}
// foldUpdate() {{{2
-/*
- * Update folds for changes in the buffer of a window.
- * Note that inserted/deleted lines must have already been taken care of by
- * calling foldMarkAdjust().
- * The changes in lines from top to bot (inclusive).
- */
+/// Update folds for changes in the buffer of a window.
+/// Note that inserted/deleted lines must have already been taken care of by
+/// calling foldMarkAdjust().
+/// The changes in lines from top to bot (inclusive).
void foldUpdate(win_T *wp, linenr_T top, linenr_T bot)
{
if (compl_busy || State & INSERT) {
@@ -856,12 +823,10 @@ void foldUpdateAfterInsert(void)
}
// foldUpdateAll() {{{2
-/*
- * Update all lines in a window for folding.
- * Used when a fold setting changes or after reloading the buffer.
- * The actual updating is postponed until fold info is used, to avoid doing
- * every time a setting is changed or a syntax item is added.
- */
+/// Update all lines in a window for folding.
+/// Used when a fold setting changes or after reloading the buffer.
+/// The actual updating is postponed until fold info is used, to avoid doing
+/// every time a setting is changed or a syntax item is added.
void foldUpdateAll(win_T *win)
{
win->w_foldinvalid = true;
@@ -992,21 +957,18 @@ int foldMoveTo(const bool updown, const int dir, const long count)
}
// foldInitWin() {{{2
-/*
- * Init the fold info in a new window.
- */
+/// Init the fold info in a new window.
void foldInitWin(win_T *new_win)
{
ga_init(&new_win->w_folds, (int)sizeof(fold_T), 10);
}
// find_wl_entry() {{{2
-/*
- * Find an entry in the win->w_lines[] array for buffer line "lnum".
- * Only valid entries are considered (for entries where wl_valid is FALSE the
- * line number can be wrong).
- * Returns index of entry or -1 if not found.
- */
+/// Find an entry in the win->w_lines[] array for buffer line "lnum".
+/// Only valid entries are considered (for entries where wl_valid is FALSE the
+/// line number can be wrong).
+///
+/// @return index of entry or -1 if not found.
int find_wl_entry(win_T *win, linenr_T lnum)
{
int i;
@@ -1025,9 +987,7 @@ int find_wl_entry(win_T *win, linenr_T lnum)
}
// foldAdjustVisual() {{{2
-/*
- * Adjust the Visual area to include any fold at the start or end completely.
- */
+/// Adjust the Visual area to include any fold at the start or end completely.
void foldAdjustVisual(void)
{
pos_T *start, *end;
@@ -1059,9 +1019,7 @@ void foldAdjustVisual(void)
}
// cursor_foldstart() {{{2
-/*
- * Move the cursor to the first line of a closed fold.
- */
+/// Move the cursor to the first line of a closed fold.
void foldAdjustCursor(void)
{
(void)hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL);
@@ -1069,9 +1027,7 @@ void foldAdjustCursor(void)
// Internal functions for "fold_T" {{{1
// cloneFoldGrowArray() {{{2
-/*
- * Will "clone" (i.e deep copy) a garray_T of folds.
- */
+/// Will "clone" (i.e deep copy) a garray_T of folds.
void cloneFoldGrowArray(garray_T *from, garray_T *to)
{
fold_T *from_p;
@@ -1143,9 +1099,7 @@ static bool foldFind(const garray_T *gap, linenr_T lnum, fold_T **fpp)
}
// foldLevelWin() {{{2
-/*
- * Return fold level at line number "lnum" in window "wp".
- */
+/// @return fold level at line number "lnum" in window "wp".
static int foldLevelWin(win_T *wp, linenr_T lnum)
{
fold_T *fp;
@@ -1169,9 +1123,7 @@ static int foldLevelWin(win_T *wp, linenr_T lnum)
}
// checkupdate() {{{2
-/*
- * Check if the folds in window "wp" are invalid and update them if needed.
- */
+/// Check if the folds in window "wp" are invalid and update them if needed.
static void checkupdate(win_T *wp)
{
if (wp->w_foldinvalid) {
@@ -1181,10 +1133,8 @@ static void checkupdate(win_T *wp)
}
// setFoldRepeat() {{{2
-/*
- * Open or close fold for current window at line "lnum".
- * Repeat "count" times.
- */
+/// Open or close fold for current window at position `pos`.
+/// Repeat "count" times.
static void setFoldRepeat(pos_T pos, long count, int do_open)
{
int done;
@@ -1204,7 +1154,6 @@ static void setFoldRepeat(pos_T pos, long count, int do_open)
}
// setManualFold() {{{2
-///
/// Open or close the fold in the current window which contains "lnum".
/// Also does this for other windows in diff mode when needed.
///
@@ -1344,9 +1293,7 @@ static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, int opening, int recu
}
// foldOpenNested() {{{2
-/*
- * Open all nested folds in fold "fpr" recursively.
- */
+/// Open all nested folds in fold "fpr" recursively.
static void foldOpenNested(fold_T *fpr)
{
fold_T *fp;
@@ -1359,9 +1306,10 @@ static void foldOpenNested(fold_T *fpr)
}
// deleteFoldEntry() {{{2
-// Delete fold "idx" from growarray "gap".
-// When "recursive" is true also delete all the folds contained in it.
-// When "recursive" is false contained folds are moved one level up.
+/// Delete fold "idx" from growarray "gap".
+///
+/// @param recursive when true, also delete all the folds contained in it.
+/// when false, contained folds are moved one level up.
static void deleteFoldEntry(win_T *const wp, garray_T *const gap, const int idx,
const bool recursive)
{
@@ -1408,9 +1356,7 @@ static void deleteFoldEntry(win_T *const wp, garray_T *const gap, const int idx,
}
// deleteFoldRecurse() {{{2
-/*
- * Delete nested folds in a fold.
- */
+/// Delete nested folds in a fold.
void deleteFoldRecurse(buf_T *bp, garray_T *gap)
{
#define DELETE_FOLD_NESTED(fd) deleteFoldRecurse(bp, &((fd)->fd_nested))
@@ -1418,9 +1364,7 @@ void deleteFoldRecurse(buf_T *bp, garray_T *gap)
}
// foldMarkAdjust() {{{2
-/*
- * Update line numbers of folds for inserted/deleted lines.
- */
+/// Update line numbers of folds for inserted/deleted lines.
void foldMarkAdjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after)
{
// If deleting marks from line1 to line2, but not deleting all those
@@ -1538,10 +1482,8 @@ static void foldMarkAdjustRecurse(win_T *wp, garray_T *gap, linenr_T line1, line
}
// getDeepestNesting() {{{2
-/*
- * Get the lowest 'foldlevel' value that makes the deepest nested fold in the
- * current window open.
- */
+/// Get the lowest 'foldlevel' value that makes the deepest nested fold in
+/// window `wp`.
int getDeepestNesting(win_T *wp)
{
checkupdate(wp);
@@ -1633,7 +1575,7 @@ static void checkSmall(win_T *const wp, fold_T *const fp, const linenr_T lnum_of
}
// setSmallMaybe() {{{2
-// Set small flags in "gap" to kNone.
+/// Set small flags in "gap" to kNone.
static void setSmallMaybe(garray_T *gap)
{
fold_T *fp = (fold_T *)gap->ga_data;
@@ -1643,10 +1585,8 @@ static void setSmallMaybe(garray_T *gap)
}
// foldCreateMarkers() {{{2
-/*
- * Create a fold from line "start" to line "end" (inclusive) in the current
- * window by adding markers.
- */
+/// Create a fold from line "start" to line "end" (inclusive) in window `wp`
+/// by adding markers.
static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end)
{
buf_T *buf = wp->w_buffer;
@@ -1672,9 +1612,7 @@ static void foldCreateMarkers(win_T *wp, pos_T start, pos_T end)
}
// foldAddMarker() {{{2
-/*
- * Add "marker[markerlen]" in 'commentstring' to line "lnum".
- */
+/// Add "marker[markerlen]" in 'commentstring' to position `pos`.
static void foldAddMarker(buf_T *buf, pos_T pos, const char_u *marker, size_t markerlen)
{
char_u *cms = buf->b_p_cms;
@@ -1731,11 +1669,10 @@ static void deleteFoldMarkers(win_T *wp, fold_T *fp, int recursive, linenr_T lnu
}
// foldDelMarker() {{{2
-//
-// Delete marker "marker[markerlen]" at the end of line "lnum".
-// Delete 'commentstring' if it matches.
-// If the marker is not found, there is no error message. Could be a missing
-// close-marker.
+/// Delete marker "marker[markerlen]" at the end of line "lnum".
+/// Delete 'commentstring' if it matches.
+/// If the marker is not found, there is no error message. Could be a missing
+/// close-marker.
static void foldDelMarker(buf_T *buf, linenr_T lnum, char_u *marker, size_t markerlen)
{
char_u *newline;
@@ -1892,9 +1829,7 @@ char_u *get_foldtext(win_T *wp, linenr_T lnum, linenr_T lnume, foldinfo_T foldin
}
// foldtext_cleanup() {{{2
-/*
- * Remove 'foldmarker' and 'commentstring' from "str" (in-place).
- */
+/// Remove 'foldmarker' and 'commentstring' from "str" (in-place).
void foldtext_cleanup(char_u *str)
{
char_u *s;
@@ -1974,10 +1909,8 @@ void foldtext_cleanup(char_u *str)
// Function declarations. {{{2
// foldUpdateIEMS() {{{2
-/*
- * Update the folding for window "wp", at least from lines "top" to "bot".
- * IEMS = "Indent Expr Marker Syntax"
- */
+/// Update the folding for window "wp", at least from lines "top" to "bot".
+/// IEMS = "Indent Expr Marker Syntax"
static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot)
{
fline_T fline;
@@ -2640,9 +2573,7 @@ static linenr_T foldUpdateIEMSRecurse(garray_T *const gap, const int level,
}
// foldInsert() {{{2
-/*
- * Insert a new fold in "gap" at position "i".
- */
+/// Insert a new fold in "gap" at position "i".
static void foldInsert(garray_T *gap, int i)
{
fold_T *fp;
@@ -2658,13 +2589,11 @@ static void foldInsert(garray_T *gap, int i)
}
// foldSplit() {{{2
-/*
- * Split the "i"th fold in "gap", which starts before "top" and ends below
- * "bot" in two pieces, one ending above "top" and the other starting below
- * "bot".
- * The caller must first have taken care of any nested folds from "top" to
- * "bot"!
- */
+/// Split the "i"th fold in "gap", which starts before "top" and ends below
+/// "bot" in two pieces, one ending above "top" and the other starting below
+/// "bot".
+/// The caller must first have taken care of any nested folds from "top" to
+/// "bot"!
static void foldSplit(buf_T *buf, garray_T *const gap, const int i, const linenr_T top,
const linenr_T bot)
{
@@ -2704,24 +2633,22 @@ static void foldSplit(buf_T *buf, garray_T *const gap, const int i, const linenr
}
// foldRemove() {{{2
-/*
- * Remove folds within the range "top" to and including "bot".
- * Check for these situations:
- * 1 2 3
- * 1 2 3
- * top 2 3 4 5
- * 2 3 4 5
- * bot 2 3 4 5
- * 3 5 6
- * 3 5 6
- *
- * 1: not changed
- * 2: truncate to stop above "top"
- * 3: split in two parts, one stops above "top", other starts below "bot".
- * 4: deleted
- * 5: made to start below "bot".
- * 6: not changed
- */
+/// Remove folds within the range "top" to and including "bot".
+/// Check for these situations:
+/// 1 2 3
+/// 1 2 3
+/// top 2 3 4 5
+/// 2 3 4 5
+/// bot 2 3 4 5
+/// 3 5 6
+/// 3 5 6
+///
+/// 1: not changed
+/// 2: truncate to stop above "top"
+/// 3: split in two parts, one stops above "top", other starts below "bot".
+/// 4: deleted
+/// 5: made to start below "bot".
+/// 6: not changed
static void foldRemove(win_T *const wp, garray_T *gap, linenr_T top, linenr_T bot)
{
fold_T *fp = NULL;
@@ -2786,35 +2713,35 @@ static void foldReverseOrder(garray_T *gap, const linenr_T start_arg, const line
}
// foldMoveRange() {{{2
-// Move folds within the inclusive range "line1" to "line2" to after "dest"
-// require "line1" <= "line2" <= "dest"
-//
-// There are the following situations for the first fold at or below line1 - 1.
-// 1 2 3 4
-// 1 2 3 4
-// line1 2 3 4
-// 2 3 4 5 6 7
-// line2 3 4 5 6 7
-// 3 4 6 7 8 9
-// dest 4 7 8 9
-// 4 7 8 10
-// 4 7 8 10
-//
-// In the following descriptions, "moved" means moving in the buffer, *and* in
-// the fold array.
-// Meanwhile, "shifted" just means moving in the buffer.
-// 1. not changed
-// 2. truncated above line1
-// 3. length reduced by line2 - line1, folds starting between the end of 3 and
-// dest are truncated and shifted up
-// 4. internal folds moved (from [line1, line2] to dest)
-// 5. moved to dest.
-// 6. truncated below line2 and moved.
-// 7. length reduced by line2 - dest, folds starting between line2 and dest are
-// removed, top is moved down by move_len.
-// 8. truncated below dest and shifted up.
-// 9. shifted up
-// 10. not changed
+/// Move folds within the inclusive range "line1" to "line2" to after "dest"
+/// require "line1" <= "line2" <= "dest"
+///
+/// There are the following situations for the first fold at or below line1 - 1.
+/// 1 2 3 4
+/// 1 2 3 4
+/// line1 2 3 4
+/// 2 3 4 5 6 7
+/// line2 3 4 5 6 7
+/// 3 4 6 7 8 9
+/// dest 4 7 8 9
+/// 4 7 8 10
+/// 4 7 8 10
+///
+/// In the following descriptions, "moved" means moving in the buffer, *and* in
+/// the fold array.
+/// Meanwhile, "shifted" just means moving in the buffer.
+/// 1. not changed
+/// 2. truncated above line1
+/// 3. length reduced by line2 - line1, folds starting between the end of 3 and
+/// dest are truncated and shifted up
+/// 4. internal folds moved (from [line1, line2] to dest)
+/// 5. moved to dest.
+/// 6. truncated below line2 and moved.
+/// 7. length reduced by line2 - dest, folds starting between line2 and dest are
+/// removed, top is moved down by move_len.
+/// 8. truncated below dest and shifted up.
+/// 9. shifted up
+/// 10. not changed
static void truncate_fold(win_T *const wp, fold_T *fp, linenr_T end)
{
// I want to stop *at here*, foldRemove() stops *above* top
@@ -2929,13 +2856,11 @@ void foldMoveRange(win_T *const wp, garray_T *gap, const linenr_T line1, const l
#undef FOLD_INDEX
// foldMerge() {{{2
-/*
- * Merge two adjacent folds (and the nested ones in them).
- * This only works correctly when the folds are really adjacent! Thus "fp1"
- * must end just above "fp2".
- * The resulting fold is "fp1", nested folds are moved from "fp2" to "fp1".
- * Fold entry "fp2" in "gap" is deleted.
- */
+/// Merge two adjacent folds (and the nested ones in them).
+/// This only works correctly when the folds are really adjacent! Thus "fp1"
+/// must end just above "fp2".
+/// The resulting fold is "fp1", nested folds are moved from "fp2" to "fp1".
+/// Fold entry "fp2" in "gap" is deleted.
static void foldMerge(win_T *const wp, fold_T *fp1, garray_T *gap, fold_T *fp2)
{
fold_T *fp3;
@@ -2968,11 +2893,10 @@ static void foldMerge(win_T *const wp, fold_T *fp1, garray_T *gap, fold_T *fp2)
}
// foldlevelIndent() {{{2
-/*
- * Low level function to get the foldlevel for the "indent" method.
- * Doesn't use any caching.
- * Returns a level of -1 if the foldlevel depends on surrounding lines.
- */
+/// Low level function to get the foldlevel for the "indent" method.
+/// Doesn't use any caching.
+///
+/// @return a level of -1 if the foldlevel depends on surrounding lines.
static void foldlevelIndent(fline_T *flp)
{
char_u *s;
@@ -3000,10 +2924,8 @@ static void foldlevelIndent(fline_T *flp)
}
// foldlevelDiff() {{{2
-/*
- * Low level function to get the foldlevel for the "diff" method.
- * Doesn't use any caching.
- */
+/// Low level function to get the foldlevel for the "diff" method.
+/// Doesn't use any caching.
static void foldlevelDiff(fline_T *flp)
{
if (diff_infold(flp->wp, flp->lnum + flp->off)) {
@@ -3014,11 +2936,10 @@ static void foldlevelDiff(fline_T *flp)
}
// foldlevelExpr() {{{2
-/*
- * Low level function to get the foldlevel for the "expr" method.
- * Doesn't use any caching.
- * Returns a level of -1 if the foldlevel depends on surrounding lines.
- */
+/// Low level function to get the foldlevel for the "expr" method.
+/// Doesn't use any caching.
+///
+/// @return a level of -1 if the foldlevel depends on surrounding lines.
static void foldlevelExpr(fline_T *flp)
{
win_T *win;
@@ -3113,11 +3034,9 @@ static void foldlevelExpr(fline_T *flp)
}
// parseMarker() {{{2
-/*
- * Parse 'foldmarker' and set "foldendmarker", "foldstartmarkerlen" and
- * "foldendmarkerlen".
- * Relies on the option value to have been checked for correctness already.
- */
+/// Parse 'foldmarker' and set "foldendmarker", "foldstartmarkerlen" and
+/// "foldendmarkerlen".
+/// Relies on the option value to have been checked for correctness already.
static void parseMarker(win_T *wp)
{
foldendmarker = vim_strchr(wp->w_p_fmr, ',');
@@ -3126,15 +3045,13 @@ static void parseMarker(win_T *wp)
}
// foldlevelMarker() {{{2
-/*
- * Low level function to get the foldlevel for the "marker" method.
- * "foldendmarker", "foldstartmarkerlen" and "foldendmarkerlen" must have been
- * set before calling this.
- * Requires that flp->lvl is set to the fold level of the previous line!
- * Careful: This means you can't call this function twice on the same line.
- * Doesn't use any caching.
- * Sets flp->start when a start marker was found.
- */
+/// Low level function to get the foldlevel for the "marker" method.
+/// "foldendmarker", "foldstartmarkerlen" and "foldendmarkerlen" must have been
+/// set before calling this.
+/// Requires that flp->lvl is set to the fold level of the previous line!
+/// Careful: This means you can't call this function twice on the same line.
+/// Doesn't use any caching.
+/// Sets flp->start when a start marker was found.
static void foldlevelMarker(fline_T *flp)
{
char_u *startmarker;
@@ -3205,10 +3122,8 @@ static void foldlevelMarker(fline_T *flp)
}
// foldlevelSyntax() {{{2
-/*
- * Low level function to get the foldlevel for the "syntax" method.
- * Doesn't use any caching.
- */
+/// Low level function to get the foldlevel for the "syntax" method.
+/// Doesn't use any caching.
static void foldlevelSyntax(fline_T *flp)
{
linenr_T lnum = flp->lnum + flp->off;
@@ -3228,11 +3143,9 @@ static void foldlevelSyntax(fline_T *flp)
// functions for storing the fold state in a View {{{1
// put_folds() {{{2
-
-/*
- * Write commands to "fd" to restore the manual folds in window "wp".
- * Return FAIL if writing fails.
- */
+/// Write commands to "fd" to restore the manual folds in window "wp".
+///
+/// @return FAIL if writing fails.
int put_folds(FILE *fd, win_T *wp)
{
if (foldmethodIsManual(wp)) {
@@ -3252,10 +3165,9 @@ int put_folds(FILE *fd, win_T *wp)
}
// put_folds_recurse() {{{2
-/*
- * Write commands to "fd" to recreate manually created folds.
- * Returns FAIL when writing failed.
- */
+/// Write commands to "fd" to recreate manually created folds.
+///
+/// @return FAIL when writing failed.
static int put_folds_recurse(FILE *fd, garray_T *gap, linenr_T off)
{
fold_T *fp = (fold_T *)gap->ga_data;
@@ -3276,10 +3188,9 @@ static int put_folds_recurse(FILE *fd, garray_T *gap, linenr_T off)
}
// put_foldopen_recurse() {{{2
-/*
- * Write commands to "fd" to open and close manually opened/closed folds.
- * Returns FAIL when writing failed.
- */
+/// Write commands to "fd" to open and close manually opened/closed folds.
+///
+/// @return FAIL when writing failed.
static int put_foldopen_recurse(FILE *fd, win_T *wp, garray_T *gap, linenr_T off)
{
int level;
@@ -3325,10 +3236,9 @@ static int put_foldopen_recurse(FILE *fd, win_T *wp, garray_T *gap, linenr_T off
}
// put_fold_open_close() {{{2
-/*
- * Write the open or close command to "fd".
- * Returns FAIL when writing failed.
- */
+/// Write the open or close command to "fd".
+///
+/// @return FAIL when writing failed.
static int put_fold_open_close(FILE *fd, fold_T *fp, linenr_T off)
{
if (fprintf(fd, "%" PRId64, (int64_t)(fp->fd_top + off)) < 0
diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua
index f35817c466..70a7be86b5 100644
--- a/src/nvim/generators/c_grammar.lua
+++ b/src/nvim/generators/c_grammar.lua
@@ -49,6 +49,7 @@ local c_proto = Ct(
(fill * Cg((P('FUNC_API_REMOTE_IMPL') * Cc(true)), 'remote_impl') ^ -1) *
(fill * Cg((P('FUNC_API_BRIDGE_IMPL') * Cc(true)), 'bridge_impl') ^ -1) *
(fill * Cg((P('FUNC_API_COMPOSITOR_IMPL') * Cc(true)), 'compositor_impl') ^ -1) *
+ (fill * Cg((P('FUNC_API_CLIENT_IMPL') * Cc(true)), 'client_impl') ^ -1) *
fill * P(';')
)
diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua
index 3cb117d8b5..5e70442dce 100644..100755
--- a/src/nvim/generators/gen_api_ui_events.lua
+++ b/src/nvim/generators/gen_api_ui_events.lua
@@ -3,13 +3,14 @@ local mpack = require('mpack')
local nvimdir = arg[1]
package.path = nvimdir .. '/?.lua;' .. package.path
-assert(#arg == 7)
+assert(#arg == 8)
local input = io.open(arg[2], 'rb')
local proto_output = io.open(arg[3], 'wb')
local call_output = io.open(arg[4], 'wb')
local remote_output = io.open(arg[5], 'wb')
local bridge_output = io.open(arg[6], 'wb')
local metadata_output = io.open(arg[7], 'wb')
+local client_output = io.open(arg[8], 'wb')
local c_grammar = require('generators.c_grammar')
local events = c_grammar.grammar:match(input:read('*all'))
@@ -50,6 +51,52 @@ local function write_arglist(output, ev, need_copy)
end
end
+local function call_ui_event_method(output, ev)
+ output:write('void ui_client_event_'..ev.name..'(Array args)\n{\n')
+
+ local hlattrs_args_count = 0
+ if #ev.parameters > 0 then
+ output:write(' if (args.size < '..(#ev.parameters))
+ for j = 1, #ev.parameters do
+ local kind = ev.parameters[j][1]
+ if kind ~= "Object" then
+ if kind == 'HlAttrs' then kind = 'Dictionary' end
+ output:write('\n || args.items['..(j-1)..'].type != kObjectType'..kind..'')
+ end
+ end
+ output:write(') {\n')
+ output:write(' ELOG("Error handling ui event \''..ev.name..'\'");\n')
+ output:write(' return;\n')
+ output:write(' }\n')
+ end
+
+ for j = 1, #ev.parameters do
+ local param = ev.parameters[j]
+ local kind = param[1]
+ output:write(' '..kind..' arg_'..j..' = ')
+ if kind == 'HlAttrs' then
+ -- The first HlAttrs argument is rgb_attrs and second is cterm_attrs
+ output:write('ui_client_dict2hlattrs(args.items['..(j-1)..'].data.dictionary, '..(hlattrs_args_count == 0 and 'true' or 'false')..');\n')
+ hlattrs_args_count = hlattrs_args_count + 1
+ elseif kind == 'Object' then
+ output:write('args.items['..(j-1)..'];\n')
+ else
+ output:write('args.items['..(j-1)..'].data.'..string.lower(kind)..';\n')
+ end
+ end
+
+ output:write(' ui_call_'..ev.name..'(')
+ for j = 1, #ev.parameters do
+ output:write('arg_'..j)
+ if j ~= #ev.parameters then
+ output:write(', ')
+ end
+ end
+ output:write(');\n')
+
+ output:write('}\n\n')
+end
+
for i = 1, #events do
local ev = events[i]
assert(ev.return_type == 'void')
@@ -160,12 +207,35 @@ for i = 1, #events do
call_output:write(";\n")
call_output:write("}\n\n")
end
+
+ if (not ev.remote_only) and (not ev.noexport) and (not ev.client_impl) then
+ call_ui_event_method(client_output, ev)
+ end
end
+-- Generate the map_init method for client handlers
+client_output:write([[
+void ui_client_methods_table_init(void)
+{
+
+]])
+
+for i = 1, #events do
+ local fn = events[i]
+ if (not fn.noexport) and ((not fn.remote_only) or fn.client_impl) then
+ client_output:write(' add_ui_client_event_handler('..
+ '(String) {.data = "'..fn.name..'", '..
+ '.size = sizeof("'..fn.name..'") - 1}, '..
+ '(UIClientHandler) ui_client_event_'..fn.name..');\n')
+ end
+end
+
+client_output:write('\n}\n\n')
+
proto_output:close()
call_output:close()
remote_output:close()
-bridge_output:close()
+client_output:close()
-- don't expose internal attributes like "impl_name" in public metadata
local exported_attributes = {'name', 'parameters',
diff --git a/src/nvim/globals.h b/src/nvim/globals.h
index cbd67afb09..605a2183f3 100644
--- a/src/nvim/globals.h
+++ b/src/nvim/globals.h
@@ -361,6 +361,11 @@ EXTERN int provider_call_nesting INIT(= 0);
EXTERN int t_colors INIT(= 256); // int value of T_CCO
+// Flags to indicate an additional string for highlight name completion.
+EXTERN int include_none INIT(= 0); // when 1 include "None"
+EXTERN int include_default INIT(= 0); // when 1 include "default"
+EXTERN int include_link INIT(= 0); // when 2 include "link" and "clear"
+
// When highlight_match is true, highlight a match, starting at the cursor
// position. Search_match_lines is the number of lines after the match (0 for
// a match within one line), search_match_endcol the column number of the
diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c
index 93c8c53e33..575b239f5a 100644
--- a/src/nvim/hardcopy.c
+++ b/src/nvim/hardcopy.c
@@ -22,6 +22,7 @@
#include "nvim/fileio.h"
#include "nvim/garray.h"
#include "nvim/hardcopy.h"
+#include "nvim/highlight_group.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
#include "nvim/memory.h"
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index abbda1e9fa..7d91f38d56 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -8,13 +8,13 @@
#include "nvim/decoration_provider.h"
#include "nvim/highlight.h"
#include "nvim/highlight_defs.h"
+#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
#include "nvim/map.h"
#include "nvim/message.h"
#include "nvim/option.h"
#include "nvim/popupmnu.h"
#include "nvim/screen.h"
-#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index dcfb9358bb..e0ee649013 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -74,7 +74,8 @@ typedef enum {
HLF_R, // return to continue message and yes/no questions
HLF_S, // status lines
HLF_SNC, // status lines of not-current windows
- HLF_C, // column to separate vertically split windows
+ HLF_C, // window split separators
+ HLF_VSP, // VertSplit
HLF_T, // Titles for output from ":set all", ":autocmd" etc.
HLF_V, // Visual mode
HLF_VNC, // Visual mode, autoselecting and not clipboard owner
@@ -133,10 +134,11 @@ EXTERN const char *hlf_names[] INIT(= {
[HLF_R] = "Question",
[HLF_S] = "StatusLine",
[HLF_SNC] = "StatusLineNC",
- [HLF_C] = "VertSplit",
+ [HLF_C] = "WinSeparator",
[HLF_T] = "Title",
[HLF_V] = "Visual",
[HLF_VNC] = "VisualNC",
+ [HLF_VSP] = "VertSplit",
[HLF_W] = "WarningMsg",
[HLF_WM] = "WildMenu",
[HLF_FL] = "Folded",
diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c
new file mode 100644
index 0000000000..f342ada3db
--- /dev/null
+++ b/src/nvim/highlight_group.c
@@ -0,0 +1,2799 @@
+// This is an open source non-commercial project. Dear PVS-Studio, please check
+// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
+
+// highlight_group.c: code for managing highlight groups
+
+#include "nvim/autocmd.h"
+#include "nvim/api/private/helpers.h"
+#include "nvim/charset.h"
+#include "nvim/cursor_shape.h"
+#include "nvim/ex_docmd.h"
+#include "nvim/garray.h"
+#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
+#include "nvim/lua/executor.h"
+#include "nvim/map.h"
+#include "nvim/option.h"
+#include "nvim/runtime.h"
+#include "nvim/screen.h"
+
+/// \addtogroup SG_SET
+/// @{
+#define SG_CTERM 2 // cterm has been set
+#define SG_GUI 4 // gui has been set
+#define SG_LINK 8 // link has been set
+/// @}
+
+#define MAX_SYN_NAME 200
+
+// builtin |highlight-groups|
+static garray_T highlight_ga = GA_EMPTY_INIT_VALUE;
+
+Map(cstr_t, int) highlight_unames = MAP_INIT;
+
+/// The "term", "cterm" and "gui" arguments can be any combination of the
+/// following names, separated by commas (but no spaces!).
+static char *(hl_name_table[]) =
+ { "bold", "standout", "underline", "underlineline", "undercurl", "underdot",
+ "underdash", "italic", "reverse", "inverse", "strikethrough", "nocombine", "NONE" };
+static int hl_attr_table[] =
+ { HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERLINELINE, HL_UNDERCURL, HL_UNDERDOT, HL_UNDERDASH,
+ HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_STRIKETHROUGH, HL_NOCOMBINE, 0 };
+
+/// Structure that stores information about a highlight group.
+/// The ID of a highlight group is also called group ID. It is the index in
+/// the highlight_ga array PLUS ONE.
+typedef struct {
+ char_u *sg_name; ///< highlight group name
+ char *sg_name_u; ///< uppercase of sg_name
+ bool sg_cleared; ///< "hi clear" was used
+ int sg_attr; ///< Screen attr @see ATTR_ENTRY
+ int sg_link; ///< link to this highlight group ID
+ int sg_deflink; ///< default link; restored in highlight_clear()
+ int sg_set; ///< combination of flags in \ref SG_SET
+ sctx_T sg_deflink_sctx; ///< script where the default link was set
+ sctx_T sg_script_ctx; ///< script in which the group was last set
+ // for terminal UIs
+ int sg_cterm; ///< "cterm=" highlighting attr
+ ///< (combination of \ref HlAttrFlags)
+ int sg_cterm_fg; ///< terminal fg color number + 1
+ int sg_cterm_bg; ///< terminal bg color number + 1
+ bool sg_cterm_bold; ///< bold attr was set for light color
+ // for RGB UIs
+ int sg_gui; ///< "gui=" highlighting attributes
+ ///< (combination of \ref HlAttrFlags)
+ RgbValue sg_rgb_fg; ///< RGB foreground color
+ RgbValue sg_rgb_bg; ///< RGB background color
+ RgbValue sg_rgb_sp; ///< RGB special color
+ char *sg_rgb_fg_name; ///< RGB foreground color name
+ char *sg_rgb_bg_name; ///< RGB background color name
+ char *sg_rgb_sp_name; ///< RGB special color name
+
+ int sg_blend; ///< blend level (0-100 inclusive), -1 if unset
+} HlGroup;
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "highlight_group.c.generated.h"
+#endif
+
+static inline HlGroup *HL_TABLE(void)
+{
+ return ((HlGroup *)((highlight_ga.ga_data)));
+}
+
+// The default highlight groups. These are compiled-in for fast startup and
+// they still work when the runtime files can't be found.
+//
+// When making changes here, also change runtime/colors/default.vim!
+
+static const char *highlight_init_both[] = {
+ "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey",
+ "Cursor guibg=fg guifg=bg",
+ "lCursor guibg=fg guifg=bg",
+ "DiffText cterm=bold ctermbg=Red gui=bold guibg=Red",
+ "ErrorMsg ctermbg=DarkRed ctermfg=White guibg=Red guifg=White",
+ "IncSearch cterm=reverse gui=reverse",
+ "ModeMsg cterm=bold gui=bold",
+ "NonText ctermfg=Blue gui=bold guifg=Blue",
+ "Normal cterm=NONE gui=NONE",
+ "PmenuSbar ctermbg=Grey guibg=Grey",
+ "StatusLine cterm=reverse,bold gui=reverse,bold",
+ "StatusLineNC cterm=reverse gui=reverse",
+ "TabLineFill cterm=reverse gui=reverse",
+ "TabLineSel cterm=bold gui=bold",
+ "TermCursor cterm=reverse gui=reverse",
+ "VertSplit cterm=reverse gui=reverse",
+ "WildMenu ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
+ "default link WinSeparator VertSplit",
+ "default link EndOfBuffer NonText",
+ "default link LineNrAbove LineNr",
+ "default link LineNrBelow LineNr",
+ "default link QuickFixLine Search",
+ "default link CursorLineSign SignColumn",
+ "default link CursorLineFold FoldColumn",
+ "default link Substitute Search",
+ "default link Whitespace NonText",
+ "default link MsgSeparator StatusLine",
+ "default link NormalFloat Pmenu",
+ "default link FloatBorder WinSeparator",
+ "default FloatShadow blend=80 guibg=Black",
+ "default FloatShadowThrough blend=100 guibg=Black",
+ "RedrawDebugNormal cterm=reverse gui=reverse",
+ "RedrawDebugClear ctermbg=Yellow guibg=Yellow",
+ "RedrawDebugComposed ctermbg=Green guibg=Green",
+ "RedrawDebugRecompose ctermbg=Red guibg=Red",
+ "Error term=reverse cterm=NONE ctermfg=White ctermbg=Red gui=NONE guifg=White guibg=Red",
+ "Todo term=standout cterm=NONE ctermfg=Black ctermbg=Yellow gui=NONE guifg=Blue guibg=Yellow",
+ "default link String Constant",
+ "default link Character Constant",
+ "default link Number Constant",
+ "default link Boolean Constant",
+ "default link Float Number",
+ "default link Function Identifier",
+ "default link Conditional Statement",
+ "default link Repeat Statement",
+ "default link Label Statement",
+ "default link Operator Statement",
+ "default link Keyword Statement",
+ "default link Exception Statement",
+ "default link Include PreProc",
+ "default link Define PreProc",
+ "default link Macro PreProc",
+ "default link PreCondit PreProc",
+ "default link StorageClass Type",
+ "default link Structure Type",
+ "default link Typedef Type",
+ "default link Tag Special",
+ "default link SpecialChar Special",
+ "default link Delimiter Special",
+ "default link SpecialComment Special",
+ "default link Debug Special",
+ "default DiagnosticError ctermfg=1 guifg=Red",
+ "default DiagnosticWarn ctermfg=3 guifg=Orange",
+ "default DiagnosticInfo ctermfg=4 guifg=LightBlue",
+ "default DiagnosticHint ctermfg=7 guifg=LightGrey",
+ "default DiagnosticUnderlineError cterm=underline gui=underline guisp=Red",
+ "default DiagnosticUnderlineWarn cterm=underline gui=underline guisp=Orange",
+ "default DiagnosticUnderlineInfo cterm=underline gui=underline guisp=LightBlue",
+ "default DiagnosticUnderlineHint cterm=underline gui=underline guisp=LightGrey",
+ "default link DiagnosticVirtualTextError DiagnosticError",
+ "default link DiagnosticVirtualTextWarn DiagnosticWarn",
+ "default link DiagnosticVirtualTextInfo DiagnosticInfo",
+ "default link DiagnosticVirtualTextHint DiagnosticHint",
+ "default link DiagnosticFloatingError DiagnosticError",
+ "default link DiagnosticFloatingWarn DiagnosticWarn",
+ "default link DiagnosticFloatingInfo DiagnosticInfo",
+ "default link DiagnosticFloatingHint DiagnosticHint",
+ "default link DiagnosticSignError DiagnosticError",
+ "default link DiagnosticSignWarn DiagnosticWarn",
+ "default link DiagnosticSignInfo DiagnosticInfo",
+ "default link DiagnosticSignHint DiagnosticHint",
+ NULL
+};
+
+// Default colors only used with a light background.
+static const char *highlight_init_light[] = {
+ "ColorColumn ctermbg=LightRed guibg=LightRed",
+ "CursorColumn ctermbg=LightGrey guibg=Grey90",
+ "CursorLine cterm=underline guibg=Grey90",
+ "CursorLineNr cterm=underline ctermfg=Brown gui=bold guifg=Brown",
+ "DiffAdd ctermbg=LightBlue guibg=LightBlue",
+ "DiffChange ctermbg=LightMagenta guibg=LightMagenta",
+ "DiffDelete ctermfg=Blue ctermbg=LightCyan gui=bold guifg=Blue guibg=LightCyan",
+ "Directory ctermfg=DarkBlue guifg=Blue",
+ "FoldColumn ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue",
+ "Folded ctermbg=Grey ctermfg=DarkBlue guibg=LightGrey guifg=DarkBlue",
+ "LineNr ctermfg=Brown guifg=Brown",
+ "MatchParen ctermbg=Cyan guibg=Cyan",
+ "MoreMsg ctermfg=DarkGreen gui=bold guifg=SeaGreen",
+ "Pmenu ctermbg=LightMagenta ctermfg=Black guibg=LightMagenta",
+ "PmenuSel ctermbg=LightGrey ctermfg=Black guibg=Grey",
+ "PmenuThumb ctermbg=Black guibg=Black",
+ "Question ctermfg=DarkGreen gui=bold guifg=SeaGreen",
+ "Search ctermbg=Yellow ctermfg=NONE guibg=Yellow guifg=NONE",
+ "SignColumn ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue",
+ "SpecialKey ctermfg=DarkBlue guifg=Blue",
+ "SpellBad ctermbg=LightRed guisp=Red gui=undercurl",
+ "SpellCap ctermbg=LightBlue guisp=Blue gui=undercurl",
+ "SpellLocal ctermbg=Cyan guisp=DarkCyan gui=undercurl",
+ "SpellRare ctermbg=LightMagenta guisp=Magenta gui=undercurl",
+ "TabLine cterm=underline ctermfg=black ctermbg=LightGrey gui=underline guibg=LightGrey",
+ "Title ctermfg=DarkMagenta gui=bold guifg=Magenta",
+ "Visual guibg=LightGrey",
+ "WarningMsg ctermfg=DarkRed guifg=Red",
+ "Comment term=bold cterm=NONE ctermfg=DarkBlue ctermbg=NONE gui=NONE guifg=Blue guibg=NONE",
+ "Constant term=underline cterm=NONE ctermfg=DarkRed ctermbg=NONE gui=NONE guifg=Magenta guibg=NONE",
+ "Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a5acd guibg=NONE",
+ "Identifier term=underline cterm=NONE ctermfg=DarkCyan ctermbg=NONE gui=NONE guifg=DarkCyan guibg=NONE",
+ "Statement term=bold cterm=NONE ctermfg=Brown ctermbg=NONE gui=bold guifg=Brown guibg=NONE",
+ "PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a0dad guibg=NONE",
+ "Type term=underline cterm=NONE ctermfg=DarkGreen ctermbg=NONE gui=bold guifg=SeaGreen guibg=NONE",
+ "Underlined term=underline cterm=underline ctermfg=DarkMagenta gui=underline guifg=SlateBlue",
+ "Ignore term=NONE cterm=NONE ctermfg=white ctermbg=NONE gui=NONE guifg=bg guibg=NONE",
+ NULL
+};
+
+// Default colors only used with a dark background.
+static const char *highlight_init_dark[] = {
+ "ColorColumn ctermbg=DarkRed guibg=DarkRed",
+ "CursorColumn ctermbg=DarkGrey guibg=Grey40",
+ "CursorLine cterm=underline guibg=Grey40",
+ "CursorLineNr cterm=underline ctermfg=Yellow gui=bold guifg=Yellow",
+ "DiffAdd ctermbg=DarkBlue guibg=DarkBlue",
+ "DiffChange ctermbg=DarkMagenta guibg=DarkMagenta",
+ "DiffDelete ctermfg=Blue ctermbg=DarkCyan gui=bold guifg=Blue guibg=DarkCyan",
+ "Directory ctermfg=LightCyan guifg=Cyan",
+ "FoldColumn ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan",
+ "Folded ctermbg=DarkGrey ctermfg=Cyan guibg=DarkGrey guifg=Cyan",
+ "LineNr ctermfg=Yellow guifg=Yellow",
+ "MatchParen ctermbg=DarkCyan guibg=DarkCyan",
+ "MoreMsg ctermfg=LightGreen gui=bold guifg=SeaGreen",
+ "Pmenu ctermbg=Magenta ctermfg=Black guibg=Magenta",
+ "PmenuSel ctermbg=Black ctermfg=DarkGrey guibg=DarkGrey",
+ "PmenuThumb ctermbg=White guibg=White",
+ "Question ctermfg=LightGreen gui=bold guifg=Green",
+ "Search ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
+ "SignColumn ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan",
+ "SpecialKey ctermfg=LightBlue guifg=Cyan",
+ "SpellBad ctermbg=Red guisp=Red gui=undercurl",
+ "SpellCap ctermbg=Blue guisp=Blue gui=undercurl",
+ "SpellLocal ctermbg=Cyan guisp=Cyan gui=undercurl",
+ "SpellRare ctermbg=Magenta guisp=Magenta gui=undercurl",
+ "TabLine cterm=underline ctermfg=white ctermbg=DarkGrey gui=underline guibg=DarkGrey",
+ "Title ctermfg=LightMagenta gui=bold guifg=Magenta",
+ "Visual guibg=DarkGrey",
+ "WarningMsg ctermfg=LightRed guifg=Red",
+ "Comment term=bold cterm=NONE ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#80a0ff guibg=NONE",
+ "Constant term=underline cterm=NONE ctermfg=Magenta ctermbg=NONE gui=NONE guifg=#ffa0a0 guibg=NONE",
+ "Special term=bold cterm=NONE ctermfg=LightRed ctermbg=NONE gui=NONE guifg=Orange guibg=NONE",
+ "Identifier term=underline cterm=bold ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#40ffff guibg=NONE",
+ "Statement term=bold cterm=NONE ctermfg=Yellow ctermbg=NONE gui=bold guifg=#ffff60 guibg=NONE",
+ "PreProc term=underline cterm=NONE ctermfg=LightBlue ctermbg=NONE gui=NONE guifg=#ff80ff guibg=NONE",
+ "Type term=underline cterm=NONE ctermfg=LightGreen ctermbg=NONE gui=bold guifg=#60ff60 guibg=NONE",
+ "Underlined term=underline cterm=underline ctermfg=LightBlue gui=underline guifg=#80a0ff",
+ "Ignore term=NONE cterm=NONE ctermfg=black ctermbg=NONE gui=NONE guifg=bg guibg=NONE",
+ NULL
+};
+
+const char *const highlight_init_cmdline[] = {
+ // XXX When modifying a list modify it in both valid and invalid halves.
+ // TODO(ZyX-I): merge valid and invalid groups via a macros.
+
+ // NvimInternalError should appear only when highlighter has a bug.
+ "NvimInternalError ctermfg=Red ctermbg=Red guifg=Red guibg=Red",
+
+ // Highlight groups (links) used by parser:
+
+ "default link NvimAssignment Operator",
+ "default link NvimPlainAssignment NvimAssignment",
+ "default link NvimAugmentedAssignment NvimAssignment",
+ "default link NvimAssignmentWithAddition NvimAugmentedAssignment",
+ "default link NvimAssignmentWithSubtraction NvimAugmentedAssignment",
+ "default link NvimAssignmentWithConcatenation NvimAugmentedAssignment",
+
+ "default link NvimOperator Operator",
+
+ "default link NvimUnaryOperator NvimOperator",
+ "default link NvimUnaryPlus NvimUnaryOperator",
+ "default link NvimUnaryMinus NvimUnaryOperator",
+ "default link NvimNot NvimUnaryOperator",
+
+ "default link NvimBinaryOperator NvimOperator",
+ "default link NvimComparison NvimBinaryOperator",
+ "default link NvimComparisonModifier NvimComparison",
+ "default link NvimBinaryPlus NvimBinaryOperator",
+ "default link NvimBinaryMinus NvimBinaryOperator",
+ "default link NvimConcat NvimBinaryOperator",
+ "default link NvimConcatOrSubscript NvimConcat",
+ "default link NvimOr NvimBinaryOperator",
+ "default link NvimAnd NvimBinaryOperator",
+ "default link NvimMultiplication NvimBinaryOperator",
+ "default link NvimDivision NvimBinaryOperator",
+ "default link NvimMod NvimBinaryOperator",
+
+ "default link NvimTernary NvimOperator",
+ "default link NvimTernaryColon NvimTernary",
+
+ "default link NvimParenthesis Delimiter",
+ "default link NvimLambda NvimParenthesis",
+ "default link NvimNestingParenthesis NvimParenthesis",
+ "default link NvimCallingParenthesis NvimParenthesis",
+
+ "default link NvimSubscript NvimParenthesis",
+ "default link NvimSubscriptBracket NvimSubscript",
+ "default link NvimSubscriptColon NvimSubscript",
+ "default link NvimCurly NvimSubscript",
+
+ "default link NvimContainer NvimParenthesis",
+ "default link NvimDict NvimContainer",
+ "default link NvimList NvimContainer",
+
+ "default link NvimIdentifier Identifier",
+ "default link NvimIdentifierScope NvimIdentifier",
+ "default link NvimIdentifierScopeDelimiter NvimIdentifier",
+ "default link NvimIdentifierName NvimIdentifier",
+ "default link NvimIdentifierKey NvimIdentifier",
+
+ "default link NvimColon Delimiter",
+ "default link NvimComma Delimiter",
+ "default link NvimArrow Delimiter",
+
+ "default link NvimRegister SpecialChar",
+ "default link NvimNumber Number",
+ "default link NvimFloat NvimNumber",
+ "default link NvimNumberPrefix Type",
+
+ "default link NvimOptionSigil Type",
+ "default link NvimOptionName NvimIdentifier",
+ "default link NvimOptionScope NvimIdentifierScope",
+ "default link NvimOptionScopeDelimiter NvimIdentifierScopeDelimiter",
+
+ "default link NvimEnvironmentSigil NvimOptionSigil",
+ "default link NvimEnvironmentName NvimIdentifier",
+
+ "default link NvimString String",
+ "default link NvimStringBody NvimString",
+ "default link NvimStringQuote NvimString",
+ "default link NvimStringSpecial SpecialChar",
+
+ "default link NvimSingleQuote NvimStringQuote",
+ "default link NvimSingleQuotedBody NvimStringBody",
+ "default link NvimSingleQuotedQuote NvimStringSpecial",
+
+ "default link NvimDoubleQuote NvimStringQuote",
+ "default link NvimDoubleQuotedBody NvimStringBody",
+ "default link NvimDoubleQuotedEscape NvimStringSpecial",
+
+ "default link NvimFigureBrace NvimInternalError",
+ "default link NvimSingleQuotedUnknownEscape NvimInternalError",
+
+ "default link NvimSpacing Normal",
+
+ // NvimInvalid groups:
+
+ "default link NvimInvalidSingleQuotedUnknownEscape NvimInternalError",
+
+ "default link NvimInvalid Error",
+
+ "default link NvimInvalidAssignment NvimInvalid",
+ "default link NvimInvalidPlainAssignment NvimInvalidAssignment",
+ "default link NvimInvalidAugmentedAssignment NvimInvalidAssignment",
+ "default link NvimInvalidAssignmentWithAddition NvimInvalidAugmentedAssignment",
+ "default link NvimInvalidAssignmentWithSubtraction NvimInvalidAugmentedAssignment",
+ "default link NvimInvalidAssignmentWithConcatenation NvimInvalidAugmentedAssignment",
+
+ "default link NvimInvalidOperator NvimInvalid",
+
+ "default link NvimInvalidUnaryOperator NvimInvalidOperator",
+ "default link NvimInvalidUnaryPlus NvimInvalidUnaryOperator",
+ "default link NvimInvalidUnaryMinus NvimInvalidUnaryOperator",
+ "default link NvimInvalidNot NvimInvalidUnaryOperator",
+
+ "default link NvimInvalidBinaryOperator NvimInvalidOperator",
+ "default link NvimInvalidComparison NvimInvalidBinaryOperator",
+ "default link NvimInvalidComparisonModifier NvimInvalidComparison",
+ "default link NvimInvalidBinaryPlus NvimInvalidBinaryOperator",
+ "default link NvimInvalidBinaryMinus NvimInvalidBinaryOperator",
+ "default link NvimInvalidConcat NvimInvalidBinaryOperator",
+ "default link NvimInvalidConcatOrSubscript NvimInvalidConcat",
+ "default link NvimInvalidOr NvimInvalidBinaryOperator",
+ "default link NvimInvalidAnd NvimInvalidBinaryOperator",
+ "default link NvimInvalidMultiplication NvimInvalidBinaryOperator",
+ "default link NvimInvalidDivision NvimInvalidBinaryOperator",
+ "default link NvimInvalidMod NvimInvalidBinaryOperator",
+
+ "default link NvimInvalidTernary NvimInvalidOperator",
+ "default link NvimInvalidTernaryColon NvimInvalidTernary",
+
+ "default link NvimInvalidDelimiter NvimInvalid",
+
+ "default link NvimInvalidParenthesis NvimInvalidDelimiter",
+ "default link NvimInvalidLambda NvimInvalidParenthesis",
+ "default link NvimInvalidNestingParenthesis NvimInvalidParenthesis",
+ "default link NvimInvalidCallingParenthesis NvimInvalidParenthesis",
+
+ "default link NvimInvalidSubscript NvimInvalidParenthesis",
+ "default link NvimInvalidSubscriptBracket NvimInvalidSubscript",
+ "default link NvimInvalidSubscriptColon NvimInvalidSubscript",
+ "default link NvimInvalidCurly NvimInvalidSubscript",
+
+ "default link NvimInvalidContainer NvimInvalidParenthesis",
+ "default link NvimInvalidDict NvimInvalidContainer",
+ "default link NvimInvalidList NvimInvalidContainer",
+
+ "default link NvimInvalidValue NvimInvalid",
+
+ "default link NvimInvalidIdentifier NvimInvalidValue",
+ "default link NvimInvalidIdentifierScope NvimInvalidIdentifier",
+ "default link NvimInvalidIdentifierScopeDelimiter NvimInvalidIdentifier",
+ "default link NvimInvalidIdentifierName NvimInvalidIdentifier",
+ "default link NvimInvalidIdentifierKey NvimInvalidIdentifier",
+
+ "default link NvimInvalidColon NvimInvalidDelimiter",
+ "default link NvimInvalidComma NvimInvalidDelimiter",
+ "default link NvimInvalidArrow NvimInvalidDelimiter",
+
+ "default link NvimInvalidRegister NvimInvalidValue",
+ "default link NvimInvalidNumber NvimInvalidValue",
+ "default link NvimInvalidFloat NvimInvalidNumber",
+ "default link NvimInvalidNumberPrefix NvimInvalidNumber",
+
+ "default link NvimInvalidOptionSigil NvimInvalidIdentifier",
+ "default link NvimInvalidOptionName NvimInvalidIdentifier",
+ "default link NvimInvalidOptionScope NvimInvalidIdentifierScope",
+ "default link NvimInvalidOptionScopeDelimiter NvimInvalidIdentifierScopeDelimiter",
+
+ "default link NvimInvalidEnvironmentSigil NvimInvalidOptionSigil",
+ "default link NvimInvalidEnvironmentName NvimInvalidIdentifier",
+
+ // Invalid string bodies and specials are still highlighted as valid ones to
+ // minimize the red area.
+ "default link NvimInvalidString NvimInvalidValue",
+ "default link NvimInvalidStringBody NvimStringBody",
+ "default link NvimInvalidStringQuote NvimInvalidString",
+ "default link NvimInvalidStringSpecial NvimStringSpecial",
+
+ "default link NvimInvalidSingleQuote NvimInvalidStringQuote",
+ "default link NvimInvalidSingleQuotedBody NvimInvalidStringBody",
+ "default link NvimInvalidSingleQuotedQuote NvimInvalidStringSpecial",
+
+ "default link NvimInvalidDoubleQuote NvimInvalidStringQuote",
+ "default link NvimInvalidDoubleQuotedBody NvimInvalidStringBody",
+ "default link NvimInvalidDoubleQuotedEscape NvimInvalidStringSpecial",
+ "default link NvimInvalidDoubleQuotedUnknownEscape NvimInvalidValue",
+
+ "default link NvimInvalidFigureBrace NvimInvalidDelimiter",
+
+ "default link NvimInvalidSpacing ErrorMsg",
+
+ // Not actually invalid, but we highlight user that he is doing something
+ // wrong.
+ "default link NvimDoubleQuotedUnknownEscape NvimInvalidValue",
+ NULL,
+};
+
+/// Returns the number of highlight groups.
+int highlight_num_groups(void)
+{
+ return highlight_ga.ga_len;
+}
+
+/// Returns the name of a highlight group.
+char_u *highlight_group_name(int id)
+{
+ return HL_TABLE()[id].sg_name;
+}
+
+/// Returns the ID of the link to a highlight group.
+int highlight_link_id(int id)
+{
+ return HL_TABLE()[id].sg_link;
+}
+
+/// Create default links for Nvim* highlight groups used for cmdline coloring
+void syn_init_cmdline_highlight(bool reset, bool init)
+{
+ for (size_t i = 0; highlight_init_cmdline[i] != NULL; i++) {
+ do_highlight(highlight_init_cmdline[i], reset, init);
+ }
+}
+
+/// Load colors from a file if "g:colors_name" is set, otherwise load builtin
+/// colors
+///
+/// @param both include groups where 'bg' doesn't matter
+/// @param reset clear groups first
+void init_highlight(bool both, bool reset)
+{
+ static int had_both = false;
+
+ // Try finding the color scheme file. Used when a color file was loaded
+ // and 'background' or 't_Co' is changed.
+ char_u *p = get_var_value("g:colors_name");
+ if (p != NULL) {
+ // Value of g:colors_name could be freed in load_colors() and make
+ // p invalid, so copy it.
+ char_u *copy_p = vim_strsave(p);
+ bool okay = load_colors(copy_p);
+ xfree(copy_p);
+ if (okay) {
+ return;
+ }
+ }
+
+ // Didn't use a color file, use the compiled-in colors.
+ if (both) {
+ had_both = true;
+ const char *const *const pp = highlight_init_both;
+ for (size_t i = 0; pp[i] != NULL; i++) {
+ do_highlight(pp[i], reset, true);
+ }
+ } else if (!had_both) {
+ // Don't do anything before the call with both == true from main().
+ // Not everything has been setup then, and that call will overrule
+ // everything anyway.
+ return;
+ }
+
+ const char *const *const pp = ((*p_bg == 'l')
+ ? highlight_init_light
+ : highlight_init_dark);
+ for (size_t i = 0; pp[i] != NULL; i++) {
+ do_highlight(pp[i], reset, true);
+ }
+
+ // Reverse looks ugly, but grey may not work for 8 colors. Thus let it
+ // depend on the number of colors available.
+ // With 8 colors brown is equal to yellow, need to use black for Search fg
+ // to avoid Statement highlighted text disappears.
+ // Clear the attributes, needed when changing the t_Co value.
+ if (t_colors > 8) {
+ do_highlight((*p_bg == 'l'
+ ? "Visual cterm=NONE ctermbg=LightGrey"
+ : "Visual cterm=NONE ctermbg=DarkGrey"), false, true);
+ } else {
+ do_highlight("Visual cterm=reverse ctermbg=NONE", false, true);
+ if (*p_bg == 'l') {
+ do_highlight("Search ctermfg=black", false, true);
+ }
+ }
+
+ syn_init_cmdline_highlight(false, false);
+}
+
+/// Load color file "name".
+/// Return OK for success, FAIL for failure.
+int load_colors(char_u *name)
+{
+ char_u *buf;
+ int retval = FAIL;
+ static bool recursive = false;
+
+ // When being called recursively, this is probably because setting
+ // 'background' caused the highlighting to be reloaded. This means it is
+ // working, thus we should return OK.
+ if (recursive) {
+ return OK;
+ }
+
+ recursive = true;
+ size_t buflen = STRLEN(name) + 12;
+ buf = xmalloc(buflen);
+ apply_autocmds(EVENT_COLORSCHEMEPRE, name, curbuf->b_fname, false, curbuf);
+ snprintf((char *)buf, buflen, "colors/%s.vim", name);
+ retval = source_runtime((char *)buf, DIP_START + DIP_OPT);
+ if (retval == FAIL) {
+ snprintf((char *)buf, buflen, "colors/%s.lua", name);
+ retval = source_runtime((char *)buf, DIP_START + DIP_OPT);
+ }
+ xfree(buf);
+ apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, false, curbuf);
+
+ recursive = false;
+
+ return retval;
+}
+
+static char *(color_names[28]) = {
+ "Black", "DarkBlue", "DarkGreen", "DarkCyan",
+ "DarkRed", "DarkMagenta", "Brown", "DarkYellow",
+ "Gray", "Grey", "LightGray", "LightGrey",
+ "DarkGray", "DarkGrey",
+ "Blue", "LightBlue", "Green", "LightGreen",
+ "Cyan", "LightCyan", "Red", "LightRed", "Magenta",
+ "LightMagenta", "Yellow", "LightYellow", "White", "NONE"
+};
+// indices:
+// 0, 1, 2, 3,
+// 4, 5, 6, 7,
+// 8, 9, 10, 11,
+// 12, 13,
+// 14, 15, 16, 17,
+// 18, 19, 20, 21, 22,
+// 23, 24, 25, 26, 27
+static int color_numbers_16[28] = { 0, 1, 2, 3,
+ 4, 5, 6, 6,
+ 7, 7, 7, 7,
+ 8, 8,
+ 9, 9, 10, 10,
+ 11, 11, 12, 12, 13,
+ 13, 14, 14, 15, -1 };
+// for xterm with 88 colors...
+static int color_numbers_88[28] = { 0, 4, 2, 6,
+ 1, 5, 32, 72,
+ 84, 84, 7, 7,
+ 82, 82,
+ 12, 43, 10, 61,
+ 14, 63, 9, 74, 13,
+ 75, 11, 78, 15, -1 };
+// for xterm with 256 colors...
+static int color_numbers_256[28] = { 0, 4, 2, 6,
+ 1, 5, 130, 3,
+ 248, 248, 7, 7,
+ 242, 242,
+ 12, 81, 10, 121,
+ 14, 159, 9, 224, 13,
+ 225, 11, 229, 15, -1 };
+// for terminals with less than 16 colors...
+static int color_numbers_8[28] = { 0, 4, 2, 6,
+ 1, 5, 3, 3,
+ 7, 7, 7, 7,
+ 0+8, 0+8,
+ 4+8, 4+8, 2+8, 2+8,
+ 6+8, 6+8, 1+8, 1+8, 5+8,
+ 5+8, 3+8, 3+8, 7+8, -1 };
+
+// Lookup the "cterm" value to be used for color with index "idx" in
+// color_names[].
+// "boldp" will be set to TRUE or FALSE for a foreground color when using 8
+// colors, otherwise it will be unchanged.
+int lookup_color(const int idx, const bool foreground, TriState *const boldp)
+{
+ int color = color_numbers_16[idx];
+
+ // Use the _16 table to check if it's a valid color name.
+ if (color < 0) {
+ return -1;
+ }
+
+ if (t_colors == 8) {
+ // t_Co is 8: use the 8 colors table
+ color = color_numbers_8[idx];
+ if (foreground) {
+ // set/reset bold attribute to get light foreground
+ // colors (on some terminals, e.g. "linux")
+ if (color & 8) {
+ *boldp = kTrue;
+ } else {
+ *boldp = kFalse;
+ }
+ }
+ color &= 7; // truncate to 8 colors
+ } else if (t_colors == 16) {
+ color = color_numbers_8[idx];
+ } else if (t_colors == 88) {
+ color = color_numbers_88[idx];
+ } else if (t_colors >= 256) {
+ color = color_numbers_256[idx];
+ }
+ return color;
+}
+
+void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id)
+{
+ int idx = id - 1; // Index is ID minus one.
+
+ bool is_default = attrs.rgb_ae_attr & HL_DEFAULT;
+
+ // Return if "default" was used and the group already has settings
+ if (is_default && hl_has_settings(idx, true)) {
+ return;
+ }
+
+ HlGroup *g = &HL_TABLE()[idx];
+
+ if (link_id > 0) {
+ g->sg_cleared = false;
+ g->sg_link = link_id;
+ g->sg_script_ctx = current_sctx;
+ g->sg_script_ctx.sc_lnum += sourcing_lnum;
+ g->sg_set |= SG_LINK;
+ if (is_default) {
+ g->sg_deflink = link_id;
+ g->sg_deflink_sctx = current_sctx;
+ g->sg_deflink_sctx.sc_lnum += sourcing_lnum;
+ }
+ return;
+ }
+
+ g->sg_cleared = false;
+ g->sg_link = 0;
+ g->sg_gui = attrs.rgb_ae_attr;
+
+ g->sg_rgb_fg = attrs.rgb_fg_color;
+ g->sg_rgb_bg = attrs.rgb_bg_color;
+ g->sg_rgb_sp = attrs.rgb_sp_color;
+
+ struct {
+ char **dest; RgbValue val; Object name;
+ } cattrs[] = {
+ { &g->sg_rgb_fg_name, g->sg_rgb_fg, HAS_KEY(dict->fg) ? dict->fg : dict->foreground },
+ { &g->sg_rgb_bg_name, g->sg_rgb_bg, HAS_KEY(dict->bg) ? dict->bg : dict->background },
+ { &g->sg_rgb_sp_name, g->sg_rgb_sp, HAS_KEY(dict->sp) ? dict->sp : dict->special },
+ { NULL, -1, NIL },
+ };
+
+ char hex_name[8];
+ char *name;
+
+ for (int j = 0; cattrs[j].dest; j++) {
+ if (cattrs[j].val < 0) {
+ XFREE_CLEAR(*cattrs[j].dest);
+ continue;
+ }
+
+ if (cattrs[j].name.type == kObjectTypeString && cattrs[j].name.data.string.size) {
+ name = cattrs[j].name.data.string.data;
+ } else {
+ snprintf(hex_name, sizeof(hex_name), "#%06x", cattrs[j].val);
+ name = hex_name;
+ }
+
+ if (!*cattrs[j].dest
+ || STRCMP(*cattrs[j].dest, name) != 0) {
+ xfree(*cattrs[j].dest);
+ *cattrs[j].dest = xstrdup(name);
+ }
+ }
+
+ g->sg_cterm = attrs.cterm_ae_attr;
+ g->sg_cterm_bg = attrs.cterm_bg_color;
+ g->sg_cterm_fg = attrs.cterm_fg_color;
+ g->sg_cterm_bold = g->sg_cterm & HL_BOLD;
+ g->sg_blend = attrs.hl_blend;
+
+ g->sg_script_ctx = current_sctx;
+ g->sg_script_ctx.sc_lnum += sourcing_lnum;
+
+ // 'Normal' is special
+ if (STRCMP(g->sg_name_u, "NORMAL") == 0) {
+ cterm_normal_fg_color = g->sg_cterm_fg;
+ cterm_normal_bg_color = g->sg_cterm_bg;
+ normal_fg = g->sg_rgb_fg;
+ normal_bg = g->sg_rgb_bg;
+ normal_sp = g->sg_rgb_sp;
+ ui_default_colors_set();
+ } else {
+ g->sg_attr = hl_get_syn_attr(0, id, attrs);
+
+ // a cursor style uses this syn_id, make sure its attribute is updated.
+ if (cursor_mode_uses_syn_id(id)) {
+ ui_mode_info_set();
+ }
+ }
+}
+
+/// Handle ":highlight" command
+///
+/// When using ":highlight clear" this is called recursively for each group with
+/// forceit and init being both true.
+///
+/// @param[in] line Command arguments.
+/// @param[in] forceit True when bang is given, allows to link group even if
+/// it has its own settings.
+/// @param[in] init True when initializing.
+void do_highlight(const char *line, const bool forceit, const bool init)
+ FUNC_ATTR_NONNULL_ALL
+{
+ const char *name_end;
+ const char *linep;
+ const char *key_start;
+ const char *arg_start;
+ int off;
+ int len;
+ int attr;
+ int id;
+ int idx;
+ HlGroup item_before;
+ bool did_change = false;
+ bool dodefault = false;
+ bool doclear = false;
+ bool dolink = false;
+ bool error = false;
+ int color;
+ bool is_normal_group = false; // "Normal" group
+ bool did_highlight_changed = false;
+
+ // If no argument, list current highlighting.
+ if (ends_excmd((uint8_t)(*line))) {
+ for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
+ // TODO(brammool): only call when the group has attributes set
+ highlight_list_one(i);
+ }
+ return;
+ }
+
+ // Isolate the name.
+ name_end = (const char *)skiptowhite((const char_u *)line);
+ linep = (const char *)skipwhite((const char_u *)name_end);
+
+ // Check for "default" argument.
+ if (strncmp(line, "default", (size_t)(name_end - line)) == 0) {
+ dodefault = true;
+ line = linep;
+ name_end = (const char *)skiptowhite((const char_u *)line);
+ linep = (const char *)skipwhite((const char_u *)name_end);
+ }
+
+ // Check for "clear" or "link" argument.
+ if (strncmp(line, "clear", (size_t)(name_end - line)) == 0) {
+ doclear = true;
+ } else if (strncmp(line, "link", (size_t)(name_end - line)) == 0) {
+ dolink = true;
+ }
+
+ // ":highlight {group-name}": list highlighting for one group.
+ if (!doclear && !dolink && ends_excmd((uint8_t)(*linep))) {
+ id = syn_name2id_len((const char_u *)line, (size_t)(name_end - line));
+ if (id == 0) {
+ semsg(_("E411: highlight group not found: %s"), line);
+ } else {
+ highlight_list_one(id);
+ }
+ return;
+ }
+
+ // Handle ":highlight link {from} {to}" command.
+ if (dolink) {
+ const char *from_start = linep;
+ const char *from_end;
+ const char *to_start;
+ const char *to_end;
+ int from_id;
+ int to_id;
+ HlGroup *hlgroup = NULL;
+
+ from_end = (const char *)skiptowhite((const char_u *)from_start);
+ to_start = (const char *)skipwhite((const char_u *)from_end);
+ to_end = (const char *)skiptowhite((const char_u *)to_start);
+
+ if (ends_excmd((uint8_t)(*from_start))
+ || ends_excmd((uint8_t)(*to_start))) {
+ semsg(_("E412: Not enough arguments: \":highlight link %s\""),
+ from_start);
+ return;
+ }
+
+ if (!ends_excmd(*skipwhite((const char_u *)to_end))) {
+ semsg(_("E413: Too many arguments: \":highlight link %s\""), from_start);
+ return;
+ }
+
+ from_id = syn_check_group(from_start, (size_t)(from_end - from_start));
+ if (strncmp(to_start, "NONE", 4) == 0) {
+ to_id = 0;
+ } else {
+ to_id = syn_check_group(to_start, (size_t)(to_end - to_start));
+ }
+
+ if (from_id > 0) {
+ hlgroup = &HL_TABLE()[from_id - 1];
+ if (dodefault && (forceit || hlgroup->sg_deflink == 0)) {
+ hlgroup->sg_deflink = to_id;
+ hlgroup->sg_deflink_sctx = current_sctx;
+ hlgroup->sg_deflink_sctx.sc_lnum += sourcing_lnum;
+ nlua_set_sctx(&hlgroup->sg_deflink_sctx);
+ }
+ }
+
+ if (from_id > 0 && (!init || hlgroup->sg_set == 0)) {
+ // Don't allow a link when there already is some highlighting
+ // for the group, unless '!' is used
+ if (to_id > 0 && !forceit && !init
+ && hl_has_settings(from_id - 1, dodefault)) {
+ if (sourcing_name == NULL && !dodefault) {
+ emsg(_("E414: group has settings, highlight link ignored"));
+ }
+ } else if (hlgroup->sg_link != to_id
+ || hlgroup->sg_script_ctx.sc_sid != current_sctx.sc_sid
+ || hlgroup->sg_cleared) {
+ if (!init) {
+ hlgroup->sg_set |= SG_LINK;
+ }
+ hlgroup->sg_link = to_id;
+ hlgroup->sg_script_ctx = current_sctx;
+ hlgroup->sg_script_ctx.sc_lnum += sourcing_lnum;
+ nlua_set_sctx(&hlgroup->sg_script_ctx);
+ hlgroup->sg_cleared = false;
+ redraw_all_later(SOME_VALID);
+
+ // Only call highlight changed() once after multiple changes
+ need_highlight_changed = true;
+ }
+ }
+
+ return;
+ }
+
+ if (doclear) {
+ // ":highlight clear [group]" command.
+ line = linep;
+ if (ends_excmd((uint8_t)(*line))) {
+ do_unlet(S_LEN("colors_name"), true);
+ restore_cterm_colors();
+
+ // Clear all default highlight groups and load the defaults.
+ for (int j = 0; j < highlight_ga.ga_len; j++) {
+ highlight_clear(j);
+ }
+ init_highlight(true, true);
+ highlight_changed();
+ redraw_all_later(NOT_VALID);
+ return;
+ }
+ name_end = (const char *)skiptowhite((const char_u *)line);
+ linep = (const char *)skipwhite((const char_u *)name_end);
+ }
+
+ // Find the group name in the table. If it does not exist yet, add it.
+ id = syn_check_group(line, (size_t)(name_end - line));
+ if (id == 0) { // Failed (out of memory).
+ return;
+ }
+ idx = id - 1; // Index is ID minus one.
+
+ // Return if "default" was used and the group already has settings
+ if (dodefault && hl_has_settings(idx, true)) {
+ return;
+ }
+
+ // Make a copy so we can check if any attribute actually changed
+ item_before = HL_TABLE()[idx];
+ is_normal_group = (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0);
+
+ // Clear the highlighting for ":hi clear {group}" and ":hi clear".
+ if (doclear || (forceit && init)) {
+ highlight_clear(idx);
+ if (!doclear) {
+ HL_TABLE()[idx].sg_set = 0;
+ }
+ }
+
+ char *key = NULL;
+ char *arg = NULL;
+ if (!doclear) {
+ while (!ends_excmd((uint8_t)(*linep))) {
+ key_start = linep;
+ if (*linep == '=') {
+ semsg(_("E415: unexpected equal sign: %s"), key_start);
+ error = true;
+ break;
+ }
+
+ // Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg",
+ // "guibg" or "guisp").
+ while (*linep && !ascii_iswhite(*linep) && *linep != '=') {
+ linep++;
+ }
+ xfree(key);
+ key = (char *)vim_strnsave_up((const char_u *)key_start,
+ (size_t)(linep - key_start));
+ linep = (const char *)skipwhite((const char_u *)linep);
+
+ if (strcmp(key, "NONE") == 0) {
+ if (!init || HL_TABLE()[idx].sg_set == 0) {
+ if (!init) {
+ HL_TABLE()[idx].sg_set |= SG_CTERM+SG_GUI;
+ }
+ highlight_clear(idx);
+ }
+ continue;
+ }
+
+ // Check for the equal sign.
+ if (*linep != '=') {
+ semsg(_("E416: missing equal sign: %s"), key_start);
+ error = true;
+ break;
+ }
+ linep++;
+
+ // Isolate the argument.
+ linep = (const char *)skipwhite((const char_u *)linep);
+ if (*linep == '\'') { // guifg='color name'
+ arg_start = ++linep;
+ linep = strchr(linep, '\'');
+ if (linep == NULL) {
+ semsg(_(e_invarg2), key_start);
+ error = true;
+ break;
+ }
+ } else {
+ arg_start = linep;
+ linep = (const char *)skiptowhite((const char_u *)linep);
+ }
+ if (linep == arg_start) {
+ semsg(_("E417: missing argument: %s"), key_start);
+ error = true;
+ break;
+ }
+ xfree(arg);
+ arg = xstrndup(arg_start, (size_t)(linep - arg_start));
+
+ if (*linep == '\'') {
+ linep++;
+ }
+
+ // Store the argument.
+ if (strcmp(key, "TERM") == 0
+ || strcmp(key, "CTERM") == 0
+ || strcmp(key, "GUI") == 0) {
+ attr = 0;
+ off = 0;
+ int i;
+ while (arg[off] != NUL) {
+ for (i = ARRAY_SIZE(hl_attr_table); --i >= 0;) {
+ len = (int)STRLEN(hl_name_table[i]);
+ if (STRNICMP(arg + off, hl_name_table[i], len) == 0) {
+ attr |= hl_attr_table[i];
+ off += len;
+ break;
+ }
+ }
+ if (i < 0) {
+ semsg(_("E418: Illegal value: %s"), arg);
+ error = true;
+ break;
+ }
+ if (arg[off] == ',') { // Another one follows.
+ off++;
+ }
+ }
+ if (error) {
+ break;
+ }
+ if (*key == 'C') {
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) {
+ if (!init) {
+ HL_TABLE()[idx].sg_set |= SG_CTERM;
+ }
+ HL_TABLE()[idx].sg_cterm = attr;
+ HL_TABLE()[idx].sg_cterm_bold = false;
+ }
+ } else if (*key == 'G') {
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
+ if (!init) {
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+ }
+ HL_TABLE()[idx].sg_gui = attr;
+ }
+ }
+ } else if (STRCMP(key, "FONT") == 0) {
+ // in non-GUI fonts are simply ignored
+ } else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) {
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) {
+ if (!init) {
+ HL_TABLE()[idx].sg_set |= SG_CTERM;
+ }
+
+ // When setting the foreground color, and previously the "bold"
+ // flag was set for a light color, reset it now
+ if (key[5] == 'F' && HL_TABLE()[idx].sg_cterm_bold) {
+ HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
+ HL_TABLE()[idx].sg_cterm_bold = false;
+ }
+
+ if (ascii_isdigit(*arg)) {
+ color = atoi(arg);
+ } else if (STRICMP(arg, "fg") == 0) {
+ if (cterm_normal_fg_color) {
+ color = cterm_normal_fg_color - 1;
+ } else {
+ emsg(_("E419: FG color unknown"));
+ error = true;
+ break;
+ }
+ } else if (STRICMP(arg, "bg") == 0) {
+ if (cterm_normal_bg_color > 0) {
+ color = cterm_normal_bg_color - 1;
+ } else {
+ emsg(_("E420: BG color unknown"));
+ error = true;
+ break;
+ }
+ } else {
+ // Reduce calls to STRICMP a bit, it can be slow.
+ off = TOUPPER_ASC(*arg);
+ int i;
+ for (i = ARRAY_SIZE(color_names); --i >= 0;) {
+ if (off == color_names[i][0]
+ && STRICMP(arg + 1, color_names[i] + 1) == 0) {
+ break;
+ }
+ }
+ if (i < 0) {
+ semsg(_("E421: Color name or number not recognized: %s"),
+ key_start);
+ error = true;
+ break;
+ }
+
+ TriState bold = kNone;
+ color = lookup_color(i, key[5] == 'F', &bold);
+
+ // set/reset bold attribute to get light foreground
+ // colors (on some terminals, e.g. "linux")
+ if (bold == kTrue) {
+ HL_TABLE()[idx].sg_cterm |= HL_BOLD;
+ HL_TABLE()[idx].sg_cterm_bold = true;
+ } else if (bold == kFalse) {
+ HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
+ }
+ }
+ // Add one to the argument, to avoid zero. Zero is used for
+ // "NONE", then "color" is -1.
+ if (key[5] == 'F') {
+ HL_TABLE()[idx].sg_cterm_fg = color + 1;
+ if (is_normal_group) {
+ cterm_normal_fg_color = color + 1;
+ }
+ } else {
+ HL_TABLE()[idx].sg_cterm_bg = color + 1;
+ if (is_normal_group) {
+ cterm_normal_bg_color = color + 1;
+ if (!ui_rgb_attached()) {
+ if (color >= 0) {
+ int dark = -1;
+
+ if (t_colors < 16) {
+ dark = (color == 0 || color == 4);
+ } else if (color < 16) {
+ // Limit the heuristic to the standard 16 colors
+ dark = (color < 7 || color == 8);
+ }
+ // Set the 'background' option if the value is
+ // wrong.
+ if (dark != -1
+ && dark != (*p_bg == 'd')
+ && !option_was_set("bg")) {
+ set_option_value("bg", 0L, (dark ? "dark" : "light"), 0);
+ reset_option_was_set("bg");
+ }
+ }
+ }
+ }
+ }
+ }
+ } else if (strcmp(key, "GUIFG") == 0) {
+ char **namep = &HL_TABLE()[idx].sg_rgb_fg_name;
+
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
+ if (!init) {
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+ }
+
+ if (*namep == NULL || STRCMP(*namep, arg) != 0) {
+ xfree(*namep);
+ if (strcmp(arg, "NONE") != 0) {
+ *namep = xstrdup(arg);
+ HL_TABLE()[idx].sg_rgb_fg = name_to_color(arg);
+ } else {
+ *namep = NULL;
+ HL_TABLE()[idx].sg_rgb_fg = -1;
+ }
+ did_change = true;
+ }
+ }
+
+ if (is_normal_group) {
+ normal_fg = HL_TABLE()[idx].sg_rgb_fg;
+ }
+ } else if (STRCMP(key, "GUIBG") == 0) {
+ char **const namep = &HL_TABLE()[idx].sg_rgb_bg_name;
+
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
+ if (!init) {
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+ }
+
+ if (*namep == NULL || STRCMP(*namep, arg) != 0) {
+ xfree(*namep);
+ if (STRCMP(arg, "NONE") != 0) {
+ *namep = xstrdup(arg);
+ HL_TABLE()[idx].sg_rgb_bg = name_to_color(arg);
+ } else {
+ *namep = NULL;
+ HL_TABLE()[idx].sg_rgb_bg = -1;
+ }
+ did_change = true;
+ }
+ }
+
+ if (is_normal_group) {
+ normal_bg = HL_TABLE()[idx].sg_rgb_bg;
+ }
+ } else if (strcmp(key, "GUISP") == 0) {
+ char **const namep = &HL_TABLE()[idx].sg_rgb_sp_name;
+
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
+ if (!init) {
+ HL_TABLE()[idx].sg_set |= SG_GUI;
+ }
+
+ if (*namep == NULL || STRCMP(*namep, arg) != 0) {
+ xfree(*namep);
+ if (strcmp(arg, "NONE") != 0) {
+ *namep = xstrdup(arg);
+ HL_TABLE()[idx].sg_rgb_sp = name_to_color(arg);
+ } else {
+ *namep = NULL;
+ HL_TABLE()[idx].sg_rgb_sp = -1;
+ }
+ did_change = true;
+ }
+ }
+
+ if (is_normal_group) {
+ normal_sp = HL_TABLE()[idx].sg_rgb_sp;
+ }
+ } else if (strcmp(key, "START") == 0 || strcmp(key, "STOP") == 0) {
+ // Ignored for now
+ } else if (strcmp(key, "BLEND") == 0) {
+ if (strcmp(arg, "NONE") != 0) {
+ HL_TABLE()[idx].sg_blend = (int)strtol(arg, NULL, 10);
+ } else {
+ HL_TABLE()[idx].sg_blend = -1;
+ }
+ } else {
+ semsg(_("E423: Illegal argument: %s"), key_start);
+ error = true;
+ break;
+ }
+ HL_TABLE()[idx].sg_cleared = false;
+
+ // When highlighting has been given for a group, don't link it.
+ if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK)) {
+ HL_TABLE()[idx].sg_link = 0;
+ }
+
+ // Continue with next argument.
+ linep = (const char *)skipwhite((const char_u *)linep);
+ }
+ }
+
+ // If there is an error, and it's a new entry, remove it from the table.
+ if (error && idx == highlight_ga.ga_len) {
+ syn_unadd_group();
+ } else {
+ if (!error && is_normal_group) {
+ // Need to update all groups, because they might be using "bg" and/or
+ // "fg", which have been changed now.
+ highlight_attr_set_all();
+
+ if (!ui_has(kUILinegrid) && starting == 0) {
+ // Older UIs assume that we clear the screen after normal group is
+ // changed
+ ui_refresh();
+ } else {
+ // TUI and newer UIs will repaint the screen themselves. NOT_VALID
+ // redraw below will still handle usages of guibg=fg etc.
+ ui_default_colors_set();
+ }
+ did_highlight_changed = true;
+ redraw_all_later(NOT_VALID);
+ } else {
+ set_hl_attr(idx);
+ }
+ HL_TABLE()[idx].sg_script_ctx = current_sctx;
+ HL_TABLE()[idx].sg_script_ctx.sc_lnum += sourcing_lnum;
+ nlua_set_sctx(&HL_TABLE()[idx].sg_script_ctx);
+ }
+ xfree(key);
+ xfree(arg);
+
+ // Only call highlight_changed() once, after a sequence of highlight
+ // commands, and only if an attribute actually changed
+ if ((did_change
+ || memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0)
+ && !did_highlight_changed) {
+ // Do not trigger a redraw when highlighting is changed while
+ // redrawing. This may happen when evaluating 'statusline' changes the
+ // StatusLine group.
+ if (!updating_screen) {
+ redraw_all_later(NOT_VALID);
+ }
+ need_highlight_changed = true;
+ }
+}
+
+#if defined(EXITFREE)
+void free_highlight(void)
+{
+ for (int i = 0; i < highlight_ga.ga_len; i++) {
+ highlight_clear(i);
+ xfree(HL_TABLE()[i].sg_name);
+ xfree(HL_TABLE()[i].sg_name_u);
+ }
+ ga_clear(&highlight_ga);
+ map_destroy(cstr_t, int)(&highlight_unames);
+}
+
+#endif
+
+/// Reset the cterm colors to what they were before Vim was started, if
+/// possible. Otherwise reset them to zero.
+void restore_cterm_colors(void)
+{
+ normal_fg = -1;
+ normal_bg = -1;
+ normal_sp = -1;
+ cterm_normal_fg_color = 0;
+ cterm_normal_bg_color = 0;
+}
+
+/// @param check_link if true also check for an existing link.
+///
+/// @return TRUE if highlight group "idx" has any settings.
+static int hl_has_settings(int idx, bool check_link)
+{
+ return HL_TABLE()[idx].sg_cleared == 0
+ && (HL_TABLE()[idx].sg_attr != 0
+ || HL_TABLE()[idx].sg_cterm_fg != 0
+ || HL_TABLE()[idx].sg_cterm_bg != 0
+ || HL_TABLE()[idx].sg_rgb_fg_name != NULL
+ || HL_TABLE()[idx].sg_rgb_bg_name != NULL
+ || HL_TABLE()[idx].sg_rgb_sp_name != NULL
+ || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK)));
+}
+
+/// Clear highlighting for one group.
+static void highlight_clear(int idx)
+{
+ HL_TABLE()[idx].sg_cleared = true;
+
+ HL_TABLE()[idx].sg_attr = 0;
+ HL_TABLE()[idx].sg_cterm = 0;
+ HL_TABLE()[idx].sg_cterm_bold = false;
+ HL_TABLE()[idx].sg_cterm_fg = 0;
+ HL_TABLE()[idx].sg_cterm_bg = 0;
+ HL_TABLE()[idx].sg_gui = 0;
+ HL_TABLE()[idx].sg_rgb_fg = -1;
+ HL_TABLE()[idx].sg_rgb_bg = -1;
+ HL_TABLE()[idx].sg_rgb_sp = -1;
+ XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_fg_name);
+ XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_bg_name);
+ XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_sp_name);
+ HL_TABLE()[idx].sg_blend = -1;
+ // Restore default link and context if they exist. Otherwise clears.
+ HL_TABLE()[idx].sg_link = HL_TABLE()[idx].sg_deflink;
+ // Since we set the default link, set the location to where the default
+ // link was set.
+ HL_TABLE()[idx].sg_script_ctx = HL_TABLE()[idx].sg_deflink_sctx;
+}
+
+/// \addtogroup LIST_XXX
+/// @{
+#define LIST_ATTR 1
+#define LIST_STRING 2
+#define LIST_INT 3
+/// @}
+
+static void highlight_list_one(const int id)
+{
+ const HlGroup *sgp = &HL_TABLE()[id - 1]; // index is ID minus one
+ bool didh = false;
+
+ if (message_filtered(sgp->sg_name)) {
+ return;
+ }
+
+ didh = highlight_list_arg(id, didh, LIST_ATTR,
+ sgp->sg_cterm, NULL, "cterm");
+ didh = highlight_list_arg(id, didh, LIST_INT,
+ sgp->sg_cterm_fg, NULL, "ctermfg");
+ didh = highlight_list_arg(id, didh, LIST_INT,
+ sgp->sg_cterm_bg, NULL, "ctermbg");
+
+ didh = highlight_list_arg(id, didh, LIST_ATTR,
+ sgp->sg_gui, NULL, "gui");
+ didh = highlight_list_arg(id, didh, LIST_STRING,
+ 0, sgp->sg_rgb_fg_name, "guifg");
+ didh = highlight_list_arg(id, didh, LIST_STRING,
+ 0, sgp->sg_rgb_bg_name, "guibg");
+ didh = highlight_list_arg(id, didh, LIST_STRING,
+ 0, sgp->sg_rgb_sp_name, "guisp");
+
+ didh = highlight_list_arg(id, didh, LIST_INT,
+ sgp->sg_blend+1, NULL, "blend");
+
+ if (sgp->sg_link && !got_int) {
+ (void)syn_list_header(didh, 0, id, true);
+ didh = true;
+ msg_puts_attr("links to", HL_ATTR(HLF_D));
+ msg_putchar(' ');
+ msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
+ }
+
+ if (!didh) {
+ highlight_list_arg(id, didh, LIST_STRING, 0, "cleared", "");
+ }
+ if (p_verbose > 0) {
+ last_set_msg(sgp->sg_script_ctx);
+ }
+}
+
+Dictionary get_global_hl_defs(void)
+{
+ Dictionary rv = ARRAY_DICT_INIT;
+ for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
+ Dictionary attrs = ARRAY_DICT_INIT;
+ HlGroup *h = &HL_TABLE()[i - 1];
+ if (h->sg_attr > 0) {
+ attrs = hlattrs2dict(syn_attr2entry(h->sg_attr), true);
+ } else if (h->sg_link > 0) {
+ const char *link = (const char *)HL_TABLE()[h->sg_link - 1].sg_name;
+ PUT(attrs, "link", STRING_OBJ(cstr_to_string(link)));
+ }
+ PUT(rv, (const char *)h->sg_name, DICTIONARY_OBJ(attrs));
+ }
+
+ return rv;
+}
+
+/// Outputs a highlight when doing ":hi MyHighlight"
+///
+/// @param type one of \ref LIST_XXX
+/// @param iarg integer argument used if \p type == LIST_INT
+/// @param sarg string used if \p type == LIST_STRING
+static bool highlight_list_arg(const int id, bool didh, const int type, int iarg, char *const sarg,
+ const char *const name)
+{
+ char buf[100];
+
+ if (got_int) {
+ return false;
+ }
+ if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0)) {
+ char *ts = buf;
+ if (type == LIST_INT) {
+ snprintf((char *)buf, sizeof(buf), "%d", iarg - 1);
+ } else if (type == LIST_STRING) {
+ ts = sarg;
+ } else { // type == LIST_ATTR
+ buf[0] = NUL;
+ for (int i = 0; hl_attr_table[i] != 0; i++) {
+ if (iarg & hl_attr_table[i]) {
+ if (buf[0] != NUL) {
+ xstrlcat(buf, ",", 100);
+ }
+ xstrlcat(buf, hl_name_table[i], 100);
+ iarg &= ~hl_attr_table[i]; // don't want "inverse"
+ }
+ }
+ }
+
+ (void)syn_list_header(didh, (int)(vim_strsize((char_u *)ts) + (int)STRLEN(name)
+ + 1), id, false);
+ didh = true;
+ if (!got_int) {
+ if (*name != NUL) {
+ msg_puts_attr(name, HL_ATTR(HLF_D));
+ msg_puts_attr("=", HL_ATTR(HLF_D));
+ }
+ msg_outtrans((char_u *)ts);
+ }
+ }
+ return didh;
+}
+
+/// Check whether highlight group has attribute
+///
+/// @param[in] id Highlight group to check.
+/// @param[in] flag Attribute to check.
+/// @param[in] modec 'g' for GUI, 'c' for term.
+///
+/// @return "1" if highlight group has attribute, NULL otherwise.
+const char *highlight_has_attr(const int id, const int flag, const int modec)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
+{
+ int attr;
+
+ if (id <= 0 || id > highlight_ga.ga_len) {
+ return NULL;
+ }
+
+ if (modec == 'g') {
+ attr = HL_TABLE()[id - 1].sg_gui;
+ } else {
+ attr = HL_TABLE()[id - 1].sg_cterm;
+ }
+
+ return (attr & flag) ? "1" : NULL;
+}
+
+/// Return color name of the given highlight group
+///
+/// @param[in] id Highlight group to work with.
+/// @param[in] what What to return: one of "font", "fg", "bg", "sp", "fg#",
+/// "bg#" or "sp#".
+/// @param[in] modec 'g' for GUI, 'c' for cterm and 't' for term.
+///
+/// @return color name, possibly in a static buffer. Buffer will be overwritten
+/// on next highlight_color() call. May return NULL.
+const char *highlight_color(const int id, const char *const what, const int modec)
+ FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ static char name[20];
+ int n;
+ bool fg = false;
+ bool sp = false;
+ bool font = false;
+
+ if (id <= 0 || id > highlight_ga.ga_len) {
+ return NULL;
+ }
+
+ if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'g') {
+ fg = true;
+ } else if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'o'
+ && TOLOWER_ASC(what[2]) == 'n' && TOLOWER_ASC(what[3]) == 't') {
+ font = true;
+ } else if (TOLOWER_ASC(what[0]) == 's' && TOLOWER_ASC(what[1]) == 'p') {
+ sp = true;
+ } else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g')) {
+ return NULL;
+ }
+ if (modec == 'g') {
+ if (what[2] == '#' && ui_rgb_attached()) {
+ if (fg) {
+ n = HL_TABLE()[id - 1].sg_rgb_fg;
+ } else if (sp) {
+ n = HL_TABLE()[id - 1].sg_rgb_sp;
+ } else {
+ n = HL_TABLE()[id - 1].sg_rgb_bg;
+ }
+ if (n < 0 || n > 0xffffff) {
+ return NULL;
+ }
+ snprintf(name, sizeof(name), "#%06x", n);
+ return name;
+ }
+ if (fg) {
+ return (const char *)HL_TABLE()[id - 1].sg_rgb_fg_name;
+ }
+ if (sp) {
+ return (const char *)HL_TABLE()[id - 1].sg_rgb_sp_name;
+ }
+ return (const char *)HL_TABLE()[id - 1].sg_rgb_bg_name;
+ }
+ if (font || sp) {
+ return NULL;
+ }
+ if (modec == 'c') {
+ if (fg) {
+ n = HL_TABLE()[id - 1].sg_cterm_fg - 1;
+ } else {
+ n = HL_TABLE()[id - 1].sg_cterm_bg - 1;
+ }
+ if (n < 0) {
+ return NULL;
+ }
+ snprintf(name, sizeof(name), "%d", n);
+ return name;
+ }
+ // term doesn't have color.
+ return NULL;
+}
+
+/// Output the syntax list header.
+///
+/// @param did_header did header already
+/// @param outlen length of string that comes
+/// @param id highlight group id
+/// @param force_newline always start a new line
+/// @return true when started a new line.
+bool syn_list_header(const bool did_header, const int outlen, const int id,
+ bool force_newline)
+{
+ int endcol = 19;
+ bool newline = true;
+ int name_col = 0;
+ bool adjust = true;
+
+ if (!did_header) {
+ msg_putchar('\n');
+ if (got_int) {
+ return true;
+ }
+ msg_outtrans(HL_TABLE()[id - 1].sg_name);
+ name_col = msg_col;
+ endcol = 15;
+ } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) {
+ msg_putchar(' ');
+ adjust = false;
+ } else if (msg_col + outlen + 1 >= Columns || force_newline) {
+ msg_putchar('\n');
+ if (got_int) {
+ return true;
+ }
+ } else {
+ if (msg_col >= endcol) { // wrap around is like starting a new line
+ newline = false;
+ }
+ }
+
+ if (adjust) {
+ if (msg_col >= endcol) {
+ // output at least one space
+ endcol = msg_col + 1;
+ }
+
+ msg_advance(endcol);
+ }
+
+ // Show "xxx" with the attributes.
+ if (!did_header) {
+ if (endcol == Columns - 1 && endcol <= name_col) {
+ msg_putchar(' ');
+ }
+ msg_puts_attr("xxx", syn_id2attr(id));
+ msg_putchar(' ');
+ }
+
+ return newline;
+}
+
+/// Set the attribute numbers for a highlight group.
+/// Called after one of the attributes has changed.
+/// @param idx corrected highlight index
+static void set_hl_attr(int idx)
+{
+ HlAttrs at_en = HLATTRS_INIT;
+ HlGroup *sgp = HL_TABLE() + idx;
+
+ at_en.cterm_ae_attr = (int16_t)sgp->sg_cterm;
+ at_en.cterm_fg_color = sgp->sg_cterm_fg;
+ at_en.cterm_bg_color = sgp->sg_cterm_bg;
+ at_en.rgb_ae_attr = (int16_t)sgp->sg_gui;
+ // FIXME(tarruda): The "unset value" for rgb is -1, but since hlgroup is
+ // initialized with 0(by garray functions), check for sg_rgb_{f,b}g_name
+ // before setting attr_entry->{f,g}g_color to a other than -1
+ at_en.rgb_fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1;
+ at_en.rgb_bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1;
+ at_en.rgb_sp_color = sgp->sg_rgb_sp_name ? sgp->sg_rgb_sp : -1;
+ at_en.hl_blend = sgp->sg_blend;
+
+ sgp->sg_attr = hl_get_syn_attr(0, idx+1, at_en);
+
+ // a cursor style uses this syn_id, make sure its attribute is updated.
+ if (cursor_mode_uses_syn_id(idx+1)) {
+ ui_mode_info_set();
+ }
+}
+
+int syn_name2id(const char *name)
+ FUNC_ATTR_NONNULL_ALL
+{
+ return syn_name2id_len((char_u *)name, STRLEN(name));
+}
+
+/// Lookup a highlight group name and return its ID.
+///
+/// @param highlight name e.g. 'Cursor', 'Normal'
+/// @return the highlight id, else 0 if \p name does not exist
+int syn_name2id_len(const char_u *name, size_t len)
+ FUNC_ATTR_NONNULL_ALL
+{
+ char name_u[MAX_SYN_NAME + 1];
+
+ if (len == 0 || len > MAX_SYN_NAME) {
+ return 0;
+ }
+
+ // Avoid using stricmp() too much, it's slow on some systems */
+ // Avoid alloc()/free(), these are slow too.
+ memcpy(name_u, name, len);
+ name_u[len] = '\0';
+ vim_strup((char_u *)name_u);
+
+ // map_get(..., int) returns 0 when no key is present, which is
+ // the expected value for missing highlight group.
+ return map_get(cstr_t, int)(&highlight_unames, name_u);
+}
+
+/// Lookup a highlight group name and return its attributes.
+/// Return zero if not found.
+int syn_name2attr(const char_u *name)
+ FUNC_ATTR_NONNULL_ALL
+{
+ int id = syn_name2id((char *)name);
+
+ if (id != 0) {
+ return syn_id2attr(id);
+ }
+ return 0;
+}
+
+/// Return TRUE if highlight group "name" exists.
+int highlight_exists(const char *name)
+{
+ return syn_name2id(name) > 0;
+}
+
+/// Return the name of highlight group "id".
+/// When not a valid ID return an empty string.
+char_u *syn_id2name(int id)
+{
+ if (id <= 0 || id > highlight_ga.ga_len) {
+ return (char_u *)"";
+ }
+ return HL_TABLE()[id - 1].sg_name;
+}
+
+/// Find highlight group name in the table and return its ID.
+/// If it doesn't exist yet, a new entry is created.
+///
+/// @param pp Highlight group name
+/// @param len length of \p pp
+///
+/// @return 0 for failure else the id of the group
+int syn_check_group(const char *name, size_t len)
+{
+ if (len > MAX_SYN_NAME) {
+ emsg(_(e_highlight_group_name_too_long));
+ return 0;
+ }
+ int id = syn_name2id_len((char_u *)name, len);
+ if (id == 0) { // doesn't exist yet
+ return syn_add_group(vim_strnsave((char_u *)name, len));
+ }
+ return id;
+}
+
+/// Add new highlight group and return its ID.
+///
+/// @param name must be an allocated string, it will be consumed.
+/// @return 0 for failure, else the allocated group id
+/// @see syn_check_group syn_unadd_group
+static int syn_add_group(char_u *name)
+{
+ char_u *p;
+
+ // Check that the name is ASCII letters, digits and underscore.
+ for (p = name; *p != NUL; p++) {
+ if (!vim_isprintc(*p)) {
+ emsg(_("E669: Unprintable character in group name"));
+ xfree(name);
+ return 0;
+ } else if (!ASCII_ISALNUM(*p) && *p != '_') {
+ // This is an error, but since there previously was no check only give a warning.
+ msg_source(HL_ATTR(HLF_W));
+ msg(_("W18: Invalid character in group name"));
+ break;
+ }
+ }
+
+ // First call for this growarray: init growing array.
+ if (highlight_ga.ga_data == NULL) {
+ highlight_ga.ga_itemsize = sizeof(HlGroup);
+ ga_set_growsize(&highlight_ga, 10);
+ }
+
+ if (highlight_ga.ga_len >= MAX_HL_ID) {
+ emsg(_("E849: Too many highlight and syntax groups"));
+ xfree(name);
+ return 0;
+ }
+
+ char *const name_up = (char *)vim_strsave_up(name);
+
+ // Append another syntax_highlight entry.
+ HlGroup *hlgp = GA_APPEND_VIA_PTR(HlGroup, &highlight_ga);
+ memset(hlgp, 0, sizeof(*hlgp));
+ hlgp->sg_name = name;
+ hlgp->sg_rgb_bg = -1;
+ hlgp->sg_rgb_fg = -1;
+ hlgp->sg_rgb_sp = -1;
+ hlgp->sg_blend = -1;
+ hlgp->sg_name_u = name_up;
+
+ int id = highlight_ga.ga_len; // ID is index plus one
+
+ map_put(cstr_t, int)(&highlight_unames, name_up, id);
+
+ return id;
+}
+
+/// When, just after calling syn_add_group(), an error is discovered, this
+/// function deletes the new name.
+static void syn_unadd_group(void)
+{
+ highlight_ga.ga_len--;
+ HlGroup *item = &HL_TABLE()[highlight_ga.ga_len];
+ map_del(cstr_t, int)(&highlight_unames, item->sg_name_u);
+ xfree(item->sg_name);
+ xfree(item->sg_name_u);
+}
+
+/// Translate a group ID to highlight attributes.
+/// @see syn_attr2entry
+int syn_id2attr(int hl_id)
+{
+ hl_id = syn_get_final_id(hl_id);
+ HlGroup *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
+
+ int attr = ns_get_hl(-1, hl_id, false, sgp->sg_set);
+ if (attr >= 0) {
+ return attr;
+ }
+ return sgp->sg_attr;
+}
+
+/// Translate a group ID to the final group ID (following links).
+int syn_get_final_id(int hl_id)
+{
+ int count;
+
+ if (hl_id > highlight_ga.ga_len || hl_id < 1) {
+ return 0; // Can be called from eval!!
+ }
+
+ // Follow links until there is no more.
+ // Look out for loops! Break after 100 links.
+ for (count = 100; --count >= 0;) {
+ HlGroup *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
+
+ // ACHTUNG: when using "tmp" attribute (no link) the function might be
+ // called twice. it needs be smart enough to remember attr only to
+ // syn_id2attr time
+ int check = ns_get_hl(-1, hl_id, true, sgp->sg_set);
+ if (check == 0) {
+ return hl_id; // how dare! it broke the link!
+ } else if (check > 0) {
+ hl_id = check;
+ continue;
+ }
+
+
+ if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len) {
+ break;
+ }
+ hl_id = sgp->sg_link;
+ }
+
+ return hl_id;
+}
+
+/// Refresh the color attributes of all highlight groups.
+void highlight_attr_set_all(void)
+{
+ for (int idx = 0; idx < highlight_ga.ga_len; idx++) {
+ HlGroup *sgp = &HL_TABLE()[idx];
+ if (sgp->sg_rgb_bg_name != NULL) {
+ sgp->sg_rgb_bg = name_to_color(sgp->sg_rgb_bg_name);
+ }
+ if (sgp->sg_rgb_fg_name != NULL) {
+ sgp->sg_rgb_fg = name_to_color(sgp->sg_rgb_fg_name);
+ }
+ if (sgp->sg_rgb_sp_name != NULL) {
+ sgp->sg_rgb_sp = name_to_color(sgp->sg_rgb_sp_name);
+ }
+ set_hl_attr(idx);
+ }
+}
+
+// Apply difference between User[1-9] and HLF_S to HLF_SNC.
+static void combine_stl_hlt(int id, int id_S, int id_alt, int hlcnt, int i, int hlf, int *table)
+ FUNC_ATTR_NONNULL_ALL
+{
+ HlGroup *const hlt = HL_TABLE();
+
+ if (id_alt == 0) {
+ memset(&hlt[hlcnt + i], 0, sizeof(HlGroup));
+ hlt[hlcnt + i].sg_cterm = highlight_attr[hlf];
+ hlt[hlcnt + i].sg_gui = highlight_attr[hlf];
+ } else {
+ memmove(&hlt[hlcnt + i], &hlt[id_alt - 1], sizeof(HlGroup));
+ }
+ hlt[hlcnt + i].sg_link = 0;
+
+ hlt[hlcnt + i].sg_cterm ^= hlt[id - 1].sg_cterm ^ hlt[id_S - 1].sg_cterm;
+ if (hlt[id - 1].sg_cterm_fg != hlt[id_S - 1].sg_cterm_fg) {
+ hlt[hlcnt + i].sg_cterm_fg = hlt[id - 1].sg_cterm_fg;
+ }
+ if (hlt[id - 1].sg_cterm_bg != hlt[id_S - 1].sg_cterm_bg) {
+ hlt[hlcnt + i].sg_cterm_bg = hlt[id - 1].sg_cterm_bg;
+ }
+ hlt[hlcnt + i].sg_gui ^= hlt[id - 1].sg_gui ^ hlt[id_S - 1].sg_gui;
+ if (hlt[id - 1].sg_rgb_fg != hlt[id_S - 1].sg_rgb_fg) {
+ hlt[hlcnt + i].sg_rgb_fg = hlt[id - 1].sg_rgb_fg;
+ }
+ if (hlt[id - 1].sg_rgb_bg != hlt[id_S - 1].sg_rgb_bg) {
+ hlt[hlcnt + i].sg_rgb_bg = hlt[id - 1].sg_rgb_bg;
+ }
+ if (hlt[id - 1].sg_rgb_sp != hlt[id_S - 1].sg_rgb_sp) {
+ hlt[hlcnt + i].sg_rgb_sp = hlt[id - 1].sg_rgb_sp;
+ }
+ highlight_ga.ga_len = hlcnt + i + 1;
+ set_hl_attr(hlcnt + i); // At long last we can apply
+ table[i] = syn_id2attr(hlcnt + i + 1);
+}
+
+/// Translate highlight groups into attributes in highlight_attr[] and set up
+/// the user highlights User1..9. A set of corresponding highlights to use on
+/// top of HLF_SNC is computed. Called only when nvim starts and upon first
+/// screen redraw after any :highlight command.
+void highlight_changed(void)
+{
+ int id;
+ char userhl[30]; // use 30 to avoid compiler warning
+ int id_S = -1;
+ int id_SNC = 0;
+ int hlcnt;
+
+ need_highlight_changed = false;
+
+ /// Translate builtin highlight groups into attributes for quick lookup.
+ for (int hlf = 0; hlf < HLF_COUNT; hlf++) {
+ id = syn_check_group(hlf_names[hlf], STRLEN(hlf_names[hlf]));
+ if (id == 0) {
+ abort();
+ }
+ int final_id = syn_get_final_id(id);
+ if (hlf == HLF_SNC) {
+ id_SNC = final_id;
+ } else if (hlf == HLF_S) {
+ id_S = final_id;
+ }
+
+ highlight_attr[hlf] = hl_get_ui_attr(hlf, final_id,
+ hlf == HLF_INACTIVE);
+
+ if (highlight_attr[hlf] != highlight_attr_last[hlf]) {
+ if (hlf == HLF_MSG) {
+ clear_cmdline = true;
+ }
+ ui_call_hl_group_set(cstr_as_string((char *)hlf_names[hlf]),
+ highlight_attr[hlf]);
+ highlight_attr_last[hlf] = highlight_attr[hlf];
+ }
+ }
+
+ //
+ // Setup the user highlights
+ //
+ // Temporarily utilize 10 more hl entries:
+ // 9 for User1-User9 combined with StatusLineNC
+ // 1 for StatusLine default
+ // Must to be in there simultaneously in case of table overflows in
+ // get_attr_entry()
+ ga_grow(&highlight_ga, 10);
+ hlcnt = highlight_ga.ga_len;
+ if (id_S == -1) {
+ // Make sure id_S is always valid to simplify code below. Use the last entry
+ memset(&HL_TABLE()[hlcnt + 9], 0, sizeof(HlGroup));
+ id_S = hlcnt + 10;
+ }
+ for (int i = 0; i < 9; i++) {
+ snprintf(userhl, sizeof(userhl), "User%d", i + 1);
+ id = syn_name2id(userhl);
+ if (id == 0) {
+ highlight_user[i] = 0;
+ highlight_stlnc[i] = 0;
+ } else {
+ highlight_user[i] = syn_id2attr(id);
+ combine_stl_hlt(id, id_S, id_SNC, hlcnt, i, HLF_SNC, highlight_stlnc);
+ }
+ }
+ highlight_ga.ga_len = hlcnt;
+}
+
+/// Handle command line completion for :highlight command.
+void set_context_in_highlight_cmd(expand_T *xp, const char *arg)
+{
+ // Default: expand group names.
+ xp->xp_context = EXPAND_HIGHLIGHT;
+ xp->xp_pattern = (char_u *)arg;
+ include_link = 2;
+ include_default = 1;
+
+ // (part of) subcommand already typed
+ if (*arg != NUL) {
+ const char *p = (const char *)skiptowhite((const char_u *)arg);
+ if (*p != NUL) { // Past "default" or group name.
+ include_default = 0;
+ if (strncmp("default", arg, (unsigned)(p - arg)) == 0) {
+ arg = (const char *)skipwhite((const char_u *)p);
+ xp->xp_pattern = (char_u *)arg;
+ p = (const char *)skiptowhite((const char_u *)arg);
+ }
+ if (*p != NUL) { // past group name
+ include_link = 0;
+ if (arg[1] == 'i' && arg[0] == 'N') {
+ highlight_list();
+ }
+ if (strncmp("link", arg, (unsigned)(p - arg)) == 0
+ || strncmp("clear", arg, (unsigned)(p - arg)) == 0) {
+ xp->xp_pattern = skipwhite((const char_u *)p);
+ p = (const char *)skiptowhite(xp->xp_pattern);
+ if (*p != NUL) { // Past first group name.
+ xp->xp_pattern = skipwhite((const char_u *)p);
+ p = (const char *)skiptowhite(xp->xp_pattern);
+ }
+ }
+ if (*p != NUL) { // Past group name(s).
+ xp->xp_context = EXPAND_NOTHING;
+ }
+ }
+ }
+ }
+}
+
+/// List highlighting matches in a nice way.
+static void highlight_list(void)
+{
+ int i;
+
+ for (i = 10; --i >= 0;) {
+ highlight_list_two(i, HL_ATTR(HLF_D));
+ }
+ for (i = 40; --i >= 0;) {
+ highlight_list_two(99, 0);
+ }
+}
+
+static void highlight_list_two(int cnt, int attr)
+{
+ msg_puts_attr(&("N \bI \b! \b"[cnt / 11]), attr);
+ msg_clr_eos();
+ ui_flush();
+ os_delay(cnt == 99 ? 40L : (uint64_t)cnt * 50L, false);
+}
+
+/// Function given to ExpandGeneric() to obtain the list of group names.
+const char *get_highlight_name(expand_T *const xp, int idx)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ return get_highlight_name_ext(xp, idx, true);
+}
+
+/// Obtain a highlight group name.
+///
+/// @param skip_cleared if true don't return a cleared entry.
+const char *get_highlight_name_ext(expand_T *xp, int idx, bool skip_cleared)
+ FUNC_ATTR_WARN_UNUSED_RESULT
+{
+ if (idx < 0) {
+ return NULL;
+ }
+
+ // Items are never removed from the table, skip the ones that were cleared.
+ if (skip_cleared && idx < highlight_ga.ga_len && HL_TABLE()[idx].sg_cleared) {
+ return "";
+ }
+
+ if (idx == highlight_ga.ga_len && include_none != 0) {
+ return "none";
+ } else if (idx == highlight_ga.ga_len + include_none
+ && include_default != 0) {
+ return "default";
+ } else if (idx == highlight_ga.ga_len + include_none + include_default
+ && include_link != 0) {
+ return "link";
+ } else if (idx == highlight_ga.ga_len + include_none + include_default + 1
+ && include_link != 0) {
+ return "clear";
+ } else if (idx >= highlight_ga.ga_len) {
+ return NULL;
+ }
+ return (const char *)HL_TABLE()[idx].sg_name;
+}
+
+color_name_table_T color_name_table[] = {
+ // Colors from rgb.txt
+ { "AliceBlue", RGB_(0xf0, 0xf8, 0xff) },
+ { "AntiqueWhite", RGB_(0xfa, 0xeb, 0xd7) },
+ { "AntiqueWhite1", RGB_(0xff, 0xef, 0xdb) },
+ { "AntiqueWhite2", RGB_(0xee, 0xdf, 0xcc) },
+ { "AntiqueWhite3", RGB_(0xcd, 0xc0, 0xb0) },
+ { "AntiqueWhite4", RGB_(0x8b, 0x83, 0x78) },
+ { "Aqua", RGB_(0x00, 0xff, 0xff) },
+ { "Aquamarine", RGB_(0x7f, 0xff, 0xd4) },
+ { "Aquamarine1", RGB_(0x7f, 0xff, 0xd4) },
+ { "Aquamarine2", RGB_(0x76, 0xee, 0xc6) },
+ { "Aquamarine3", RGB_(0x66, 0xcd, 0xaa) },
+ { "Aquamarine4", RGB_(0x45, 0x8b, 0x74) },
+ { "Azure", RGB_(0xf0, 0xff, 0xff) },
+ { "Azure1", RGB_(0xf0, 0xff, 0xff) },
+ { "Azure2", RGB_(0xe0, 0xee, 0xee) },
+ { "Azure3", RGB_(0xc1, 0xcd, 0xcd) },
+ { "Azure4", RGB_(0x83, 0x8b, 0x8b) },
+ { "Beige", RGB_(0xf5, 0xf5, 0xdc) },
+ { "Bisque", RGB_(0xff, 0xe4, 0xc4) },
+ { "Bisque1", RGB_(0xff, 0xe4, 0xc4) },
+ { "Bisque2", RGB_(0xee, 0xd5, 0xb7) },
+ { "Bisque3", RGB_(0xcd, 0xb7, 0x9e) },
+ { "Bisque4", RGB_(0x8b, 0x7d, 0x6b) },
+ { "Black", RGB_(0x00, 0x00, 0x00) },
+ { "BlanchedAlmond", RGB_(0xff, 0xeb, 0xcd) },
+ { "Blue", RGB_(0x00, 0x00, 0xff) },
+ { "Blue1", RGB_(0x0, 0x0, 0xff) },
+ { "Blue2", RGB_(0x0, 0x0, 0xee) },
+ { "Blue3", RGB_(0x0, 0x0, 0xcd) },
+ { "Blue4", RGB_(0x0, 0x0, 0x8b) },
+ { "BlueViolet", RGB_(0x8a, 0x2b, 0xe2) },
+ { "Brown", RGB_(0xa5, 0x2a, 0x2a) },
+ { "Brown1", RGB_(0xff, 0x40, 0x40) },
+ { "Brown2", RGB_(0xee, 0x3b, 0x3b) },
+ { "Brown3", RGB_(0xcd, 0x33, 0x33) },
+ { "Brown4", RGB_(0x8b, 0x23, 0x23) },
+ { "BurlyWood", RGB_(0xde, 0xb8, 0x87) },
+ { "Burlywood1", RGB_(0xff, 0xd3, 0x9b) },
+ { "Burlywood2", RGB_(0xee, 0xc5, 0x91) },
+ { "Burlywood3", RGB_(0xcd, 0xaa, 0x7d) },
+ { "Burlywood4", RGB_(0x8b, 0x73, 0x55) },
+ { "CadetBlue", RGB_(0x5f, 0x9e, 0xa0) },
+ { "CadetBlue1", RGB_(0x98, 0xf5, 0xff) },
+ { "CadetBlue2", RGB_(0x8e, 0xe5, 0xee) },
+ { "CadetBlue3", RGB_(0x7a, 0xc5, 0xcd) },
+ { "CadetBlue4", RGB_(0x53, 0x86, 0x8b) },
+ { "ChartReuse", RGB_(0x7f, 0xff, 0x00) },
+ { "Chartreuse1", RGB_(0x7f, 0xff, 0x0) },
+ { "Chartreuse2", RGB_(0x76, 0xee, 0x0) },
+ { "Chartreuse3", RGB_(0x66, 0xcd, 0x0) },
+ { "Chartreuse4", RGB_(0x45, 0x8b, 0x0) },
+ { "Chocolate", RGB_(0xd2, 0x69, 0x1e) },
+ { "Chocolate1", RGB_(0xff, 0x7f, 0x24) },
+ { "Chocolate2", RGB_(0xee, 0x76, 0x21) },
+ { "Chocolate3", RGB_(0xcd, 0x66, 0x1d) },
+ { "Chocolate4", RGB_(0x8b, 0x45, 0x13) },
+ { "Coral", RGB_(0xff, 0x7f, 0x50) },
+ { "Coral1", RGB_(0xff, 0x72, 0x56) },
+ { "Coral2", RGB_(0xee, 0x6a, 0x50) },
+ { "Coral3", RGB_(0xcd, 0x5b, 0x45) },
+ { "Coral4", RGB_(0x8b, 0x3e, 0x2f) },
+ { "CornFlowerBlue", RGB_(0x64, 0x95, 0xed) },
+ { "Cornsilk", RGB_(0xff, 0xf8, 0xdc) },
+ { "Cornsilk1", RGB_(0xff, 0xf8, 0xdc) },
+ { "Cornsilk2", RGB_(0xee, 0xe8, 0xcd) },
+ { "Cornsilk3", RGB_(0xcd, 0xc8, 0xb1) },
+ { "Cornsilk4", RGB_(0x8b, 0x88, 0x78) },
+ { "Crimson", RGB_(0xdc, 0x14, 0x3c) },
+ { "Cyan", RGB_(0x00, 0xff, 0xff) },
+ { "Cyan1", RGB_(0x0, 0xff, 0xff) },
+ { "Cyan2", RGB_(0x0, 0xee, 0xee) },
+ { "Cyan3", RGB_(0x0, 0xcd, 0xcd) },
+ { "Cyan4", RGB_(0x0, 0x8b, 0x8b) },
+ { "DarkBlue", RGB_(0x00, 0x00, 0x8b) },
+ { "DarkCyan", RGB_(0x00, 0x8b, 0x8b) },
+ { "DarkGoldenRod", RGB_(0xb8, 0x86, 0x0b) },
+ { "DarkGoldenrod1", RGB_(0xff, 0xb9, 0xf) },
+ { "DarkGoldenrod2", RGB_(0xee, 0xad, 0xe) },
+ { "DarkGoldenrod3", RGB_(0xcd, 0x95, 0xc) },
+ { "DarkGoldenrod4", RGB_(0x8b, 0x65, 0x8) },
+ { "DarkGray", RGB_(0xa9, 0xa9, 0xa9) },
+ { "DarkGreen", RGB_(0x00, 0x64, 0x00) },
+ { "DarkGrey", RGB_(0xa9, 0xa9, 0xa9) },
+ { "DarkKhaki", RGB_(0xbd, 0xb7, 0x6b) },
+ { "DarkMagenta", RGB_(0x8b, 0x00, 0x8b) },
+ { "DarkOliveGreen", RGB_(0x55, 0x6b, 0x2f) },
+ { "DarkOliveGreen1", RGB_(0xca, 0xff, 0x70) },
+ { "DarkOliveGreen2", RGB_(0xbc, 0xee, 0x68) },
+ { "DarkOliveGreen3", RGB_(0xa2, 0xcd, 0x5a) },
+ { "DarkOliveGreen4", RGB_(0x6e, 0x8b, 0x3d) },
+ { "DarkOrange", RGB_(0xff, 0x8c, 0x00) },
+ { "DarkOrange1", RGB_(0xff, 0x7f, 0x0) },
+ { "DarkOrange2", RGB_(0xee, 0x76, 0x0) },
+ { "DarkOrange3", RGB_(0xcd, 0x66, 0x0) },
+ { "DarkOrange4", RGB_(0x8b, 0x45, 0x0) },
+ { "DarkOrchid", RGB_(0x99, 0x32, 0xcc) },
+ { "DarkOrchid1", RGB_(0xbf, 0x3e, 0xff) },
+ { "DarkOrchid2", RGB_(0xb2, 0x3a, 0xee) },
+ { "DarkOrchid3", RGB_(0x9a, 0x32, 0xcd) },
+ { "DarkOrchid4", RGB_(0x68, 0x22, 0x8b) },
+ { "DarkRed", RGB_(0x8b, 0x00, 0x00) },
+ { "DarkSalmon", RGB_(0xe9, 0x96, 0x7a) },
+ { "DarkSeaGreen", RGB_(0x8f, 0xbc, 0x8f) },
+ { "DarkSeaGreen1", RGB_(0xc1, 0xff, 0xc1) },
+ { "DarkSeaGreen2", RGB_(0xb4, 0xee, 0xb4) },
+ { "DarkSeaGreen3", RGB_(0x9b, 0xcd, 0x9b) },
+ { "DarkSeaGreen4", RGB_(0x69, 0x8b, 0x69) },
+ { "DarkSlateBlue", RGB_(0x48, 0x3d, 0x8b) },
+ { "DarkSlateGray", RGB_(0x2f, 0x4f, 0x4f) },
+ { "DarkSlateGray1", RGB_(0x97, 0xff, 0xff) },
+ { "DarkSlateGray2", RGB_(0x8d, 0xee, 0xee) },
+ { "DarkSlateGray3", RGB_(0x79, 0xcd, 0xcd) },
+ { "DarkSlateGray4", RGB_(0x52, 0x8b, 0x8b) },
+ { "DarkSlateGrey", RGB_(0x2f, 0x4f, 0x4f) },
+ { "DarkTurquoise", RGB_(0x00, 0xce, 0xd1) },
+ { "DarkViolet", RGB_(0x94, 0x00, 0xd3) },
+ { "DarkYellow", RGB_(0xbb, 0xbb, 0x00) },
+ { "DeepPink", RGB_(0xff, 0x14, 0x93) },
+ { "DeepPink1", RGB_(0xff, 0x14, 0x93) },
+ { "DeepPink2", RGB_(0xee, 0x12, 0x89) },
+ { "DeepPink3", RGB_(0xcd, 0x10, 0x76) },
+ { "DeepPink4", RGB_(0x8b, 0xa, 0x50) },
+ { "DeepSkyBlue", RGB_(0x00, 0xbf, 0xff) },
+ { "DeepSkyBlue1", RGB_(0x0, 0xbf, 0xff) },
+ { "DeepSkyBlue2", RGB_(0x0, 0xb2, 0xee) },
+ { "DeepSkyBlue3", RGB_(0x0, 0x9a, 0xcd) },
+ { "DeepSkyBlue4", RGB_(0x0, 0x68, 0x8b) },
+ { "DimGray", RGB_(0x69, 0x69, 0x69) },
+ { "DimGrey", RGB_(0x69, 0x69, 0x69) },
+ { "DodgerBlue", RGB_(0x1e, 0x90, 0xff) },
+ { "DodgerBlue1", RGB_(0x1e, 0x90, 0xff) },
+ { "DodgerBlue2", RGB_(0x1c, 0x86, 0xee) },
+ { "DodgerBlue3", RGB_(0x18, 0x74, 0xcd) },
+ { "DodgerBlue4", RGB_(0x10, 0x4e, 0x8b) },
+ { "Firebrick", RGB_(0xb2, 0x22, 0x22) },
+ { "Firebrick1", RGB_(0xff, 0x30, 0x30) },
+ { "Firebrick2", RGB_(0xee, 0x2c, 0x2c) },
+ { "Firebrick3", RGB_(0xcd, 0x26, 0x26) },
+ { "Firebrick4", RGB_(0x8b, 0x1a, 0x1a) },
+ { "FloralWhite", RGB_(0xff, 0xfa, 0xf0) },
+ { "ForestGreen", RGB_(0x22, 0x8b, 0x22) },
+ { "Fuchsia", RGB_(0xff, 0x00, 0xff) },
+ { "Gainsboro", RGB_(0xdc, 0xdc, 0xdc) },
+ { "GhostWhite", RGB_(0xf8, 0xf8, 0xff) },
+ { "Gold", RGB_(0xff, 0xd7, 0x00) },
+ { "Gold1", RGB_(0xff, 0xd7, 0x0) },
+ { "Gold2", RGB_(0xee, 0xc9, 0x0) },
+ { "Gold3", RGB_(0xcd, 0xad, 0x0) },
+ { "Gold4", RGB_(0x8b, 0x75, 0x0) },
+ { "GoldenRod", RGB_(0xda, 0xa5, 0x20) },
+ { "Goldenrod1", RGB_(0xff, 0xc1, 0x25) },
+ { "Goldenrod2", RGB_(0xee, 0xb4, 0x22) },
+ { "Goldenrod3", RGB_(0xcd, 0x9b, 0x1d) },
+ { "Goldenrod4", RGB_(0x8b, 0x69, 0x14) },
+ { "Gray", RGB_(0x80, 0x80, 0x80) },
+ { "Gray0", RGB_(0x0, 0x0, 0x0) },
+ { "Gray1", RGB_(0x3, 0x3, 0x3) },
+ { "Gray10", RGB_(0x1a, 0x1a, 0x1a) },
+ { "Gray100", RGB_(0xff, 0xff, 0xff) },
+ { "Gray11", RGB_(0x1c, 0x1c, 0x1c) },
+ { "Gray12", RGB_(0x1f, 0x1f, 0x1f) },
+ { "Gray13", RGB_(0x21, 0x21, 0x21) },
+ { "Gray14", RGB_(0x24, 0x24, 0x24) },
+ { "Gray15", RGB_(0x26, 0x26, 0x26) },
+ { "Gray16", RGB_(0x29, 0x29, 0x29) },
+ { "Gray17", RGB_(0x2b, 0x2b, 0x2b) },
+ { "Gray18", RGB_(0x2e, 0x2e, 0x2e) },
+ { "Gray19", RGB_(0x30, 0x30, 0x30) },
+ { "Gray2", RGB_(0x5, 0x5, 0x5) },
+ { "Gray20", RGB_(0x33, 0x33, 0x33) },
+ { "Gray21", RGB_(0x36, 0x36, 0x36) },
+ { "Gray22", RGB_(0x38, 0x38, 0x38) },
+ { "Gray23", RGB_(0x3b, 0x3b, 0x3b) },
+ { "Gray24", RGB_(0x3d, 0x3d, 0x3d) },
+ { "Gray25", RGB_(0x40, 0x40, 0x40) },
+ { "Gray26", RGB_(0x42, 0x42, 0x42) },
+ { "Gray27", RGB_(0x45, 0x45, 0x45) },
+ { "Gray28", RGB_(0x47, 0x47, 0x47) },
+ { "Gray29", RGB_(0x4a, 0x4a, 0x4a) },
+ { "Gray3", RGB_(0x8, 0x8, 0x8) },
+ { "Gray30", RGB_(0x4d, 0x4d, 0x4d) },
+ { "Gray31", RGB_(0x4f, 0x4f, 0x4f) },
+ { "Gray32", RGB_(0x52, 0x52, 0x52) },
+ { "Gray33", RGB_(0x54, 0x54, 0x54) },
+ { "Gray34", RGB_(0x57, 0x57, 0x57) },
+ { "Gray35", RGB_(0x59, 0x59, 0x59) },
+ { "Gray36", RGB_(0x5c, 0x5c, 0x5c) },
+ { "Gray37", RGB_(0x5e, 0x5e, 0x5e) },
+ { "Gray38", RGB_(0x61, 0x61, 0x61) },
+ { "Gray39", RGB_(0x63, 0x63, 0x63) },
+ { "Gray4", RGB_(0xa, 0xa, 0xa) },
+ { "Gray40", RGB_(0x66, 0x66, 0x66) },
+ { "Gray41", RGB_(0x69, 0x69, 0x69) },
+ { "Gray42", RGB_(0x6b, 0x6b, 0x6b) },
+ { "Gray43", RGB_(0x6e, 0x6e, 0x6e) },
+ { "Gray44", RGB_(0x70, 0x70, 0x70) },
+ { "Gray45", RGB_(0x73, 0x73, 0x73) },
+ { "Gray46", RGB_(0x75, 0x75, 0x75) },
+ { "Gray47", RGB_(0x78, 0x78, 0x78) },
+ { "Gray48", RGB_(0x7a, 0x7a, 0x7a) },
+ { "Gray49", RGB_(0x7d, 0x7d, 0x7d) },
+ { "Gray5", RGB_(0xd, 0xd, 0xd) },
+ { "Gray50", RGB_(0x7f, 0x7f, 0x7f) },
+ { "Gray51", RGB_(0x82, 0x82, 0x82) },
+ { "Gray52", RGB_(0x85, 0x85, 0x85) },
+ { "Gray53", RGB_(0x87, 0x87, 0x87) },
+ { "Gray54", RGB_(0x8a, 0x8a, 0x8a) },
+ { "Gray55", RGB_(0x8c, 0x8c, 0x8c) },
+ { "Gray56", RGB_(0x8f, 0x8f, 0x8f) },
+ { "Gray57", RGB_(0x91, 0x91, 0x91) },
+ { "Gray58", RGB_(0x94, 0x94, 0x94) },
+ { "Gray59", RGB_(0x96, 0x96, 0x96) },
+ { "Gray6", RGB_(0xf, 0xf, 0xf) },
+ { "Gray60", RGB_(0x99, 0x99, 0x99) },
+ { "Gray61", RGB_(0x9c, 0x9c, 0x9c) },
+ { "Gray62", RGB_(0x9e, 0x9e, 0x9e) },
+ { "Gray63", RGB_(0xa1, 0xa1, 0xa1) },
+ { "Gray64", RGB_(0xa3, 0xa3, 0xa3) },
+ { "Gray65", RGB_(0xa6, 0xa6, 0xa6) },
+ { "Gray66", RGB_(0xa8, 0xa8, 0xa8) },
+ { "Gray67", RGB_(0xab, 0xab, 0xab) },
+ { "Gray68", RGB_(0xad, 0xad, 0xad) },
+ { "Gray69", RGB_(0xb0, 0xb0, 0xb0) },
+ { "Gray7", RGB_(0x12, 0x12, 0x12) },
+ { "Gray70", RGB_(0xb3, 0xb3, 0xb3) },
+ { "Gray71", RGB_(0xb5, 0xb5, 0xb5) },
+ { "Gray72", RGB_(0xb8, 0xb8, 0xb8) },
+ { "Gray73", RGB_(0xba, 0xba, 0xba) },
+ { "Gray74", RGB_(0xbd, 0xbd, 0xbd) },
+ { "Gray75", RGB_(0xbf, 0xbf, 0xbf) },
+ { "Gray76", RGB_(0xc2, 0xc2, 0xc2) },
+ { "Gray77", RGB_(0xc4, 0xc4, 0xc4) },
+ { "Gray78", RGB_(0xc7, 0xc7, 0xc7) },
+ { "Gray79", RGB_(0xc9, 0xc9, 0xc9) },
+ { "Gray8", RGB_(0x14, 0x14, 0x14) },
+ { "Gray80", RGB_(0xcc, 0xcc, 0xcc) },
+ { "Gray81", RGB_(0xcf, 0xcf, 0xcf) },
+ { "Gray82", RGB_(0xd1, 0xd1, 0xd1) },
+ { "Gray83", RGB_(0xd4, 0xd4, 0xd4) },
+ { "Gray84", RGB_(0xd6, 0xd6, 0xd6) },
+ { "Gray85", RGB_(0xd9, 0xd9, 0xd9) },
+ { "Gray86", RGB_(0xdb, 0xdb, 0xdb) },
+ { "Gray87", RGB_(0xde, 0xde, 0xde) },
+ { "Gray88", RGB_(0xe0, 0xe0, 0xe0) },
+ { "Gray89", RGB_(0xe3, 0xe3, 0xe3) },
+ { "Gray9", RGB_(0x17, 0x17, 0x17) },
+ { "Gray90", RGB_(0xe5, 0xe5, 0xe5) },
+ { "Gray91", RGB_(0xe8, 0xe8, 0xe8) },
+ { "Gray92", RGB_(0xeb, 0xeb, 0xeb) },
+ { "Gray93", RGB_(0xed, 0xed, 0xed) },
+ { "Gray94", RGB_(0xf0, 0xf0, 0xf0) },
+ { "Gray95", RGB_(0xf2, 0xf2, 0xf2) },
+ { "Gray96", RGB_(0xf5, 0xf5, 0xf5) },
+ { "Gray97", RGB_(0xf7, 0xf7, 0xf7) },
+ { "Gray98", RGB_(0xfa, 0xfa, 0xfa) },
+ { "Gray99", RGB_(0xfc, 0xfc, 0xfc) },
+ { "Green", RGB_(0x00, 0x80, 0x00) },
+ { "Green1", RGB_(0x0, 0xff, 0x0) },
+ { "Green2", RGB_(0x0, 0xee, 0x0) },
+ { "Green3", RGB_(0x0, 0xcd, 0x0) },
+ { "Green4", RGB_(0x0, 0x8b, 0x0) },
+ { "GreenYellow", RGB_(0xad, 0xff, 0x2f) },
+ { "Grey", RGB_(0x80, 0x80, 0x80) },
+ { "Grey0", RGB_(0x0, 0x0, 0x0) },
+ { "Grey1", RGB_(0x3, 0x3, 0x3) },
+ { "Grey10", RGB_(0x1a, 0x1a, 0x1a) },
+ { "Grey100", RGB_(0xff, 0xff, 0xff) },
+ { "Grey11", RGB_(0x1c, 0x1c, 0x1c) },
+ { "Grey12", RGB_(0x1f, 0x1f, 0x1f) },
+ { "Grey13", RGB_(0x21, 0x21, 0x21) },
+ { "Grey14", RGB_(0x24, 0x24, 0x24) },
+ { "Grey15", RGB_(0x26, 0x26, 0x26) },
+ { "Grey16", RGB_(0x29, 0x29, 0x29) },
+ { "Grey17", RGB_(0x2b, 0x2b, 0x2b) },
+ { "Grey18", RGB_(0x2e, 0x2e, 0x2e) },
+ { "Grey19", RGB_(0x30, 0x30, 0x30) },
+ { "Grey2", RGB_(0x5, 0x5, 0x5) },
+ { "Grey20", RGB_(0x33, 0x33, 0x33) },
+ { "Grey21", RGB_(0x36, 0x36, 0x36) },
+ { "Grey22", RGB_(0x38, 0x38, 0x38) },
+ { "Grey23", RGB_(0x3b, 0x3b, 0x3b) },
+ { "Grey24", RGB_(0x3d, 0x3d, 0x3d) },
+ { "Grey25", RGB_(0x40, 0x40, 0x40) },
+ { "Grey26", RGB_(0x42, 0x42, 0x42) },
+ { "Grey27", RGB_(0x45, 0x45, 0x45) },
+ { "Grey28", RGB_(0x47, 0x47, 0x47) },
+ { "Grey29", RGB_(0x4a, 0x4a, 0x4a) },
+ { "Grey3", RGB_(0x8, 0x8, 0x8) },
+ { "Grey30", RGB_(0x4d, 0x4d, 0x4d) },
+ { "Grey31", RGB_(0x4f, 0x4f, 0x4f) },
+ { "Grey32", RGB_(0x52, 0x52, 0x52) },
+ { "Grey33", RGB_(0x54, 0x54, 0x54) },
+ { "Grey34", RGB_(0x57, 0x57, 0x57) },
+ { "Grey35", RGB_(0x59, 0x59, 0x59) },
+ { "Grey36", RGB_(0x5c, 0x5c, 0x5c) },
+ { "Grey37", RGB_(0x5e, 0x5e, 0x5e) },
+ { "Grey38", RGB_(0x61, 0x61, 0x61) },
+ { "Grey39", RGB_(0x63, 0x63, 0x63) },
+ { "Grey4", RGB_(0xa, 0xa, 0xa) },
+ { "Grey40", RGB_(0x66, 0x66, 0x66) },
+ { "Grey41", RGB_(0x69, 0x69, 0x69) },
+ { "Grey42", RGB_(0x6b, 0x6b, 0x6b) },
+ { "Grey43", RGB_(0x6e, 0x6e, 0x6e) },
+ { "Grey44", RGB_(0x70, 0x70, 0x70) },
+ { "Grey45", RGB_(0x73, 0x73, 0x73) },
+ { "Grey46", RGB_(0x75, 0x75, 0x75) },
+ { "Grey47", RGB_(0x78, 0x78, 0x78) },
+ { "Grey48", RGB_(0x7a, 0x7a, 0x7a) },
+ { "Grey49", RGB_(0x7d, 0x7d, 0x7d) },
+ { "Grey5", RGB_(0xd, 0xd, 0xd) },
+ { "Grey50", RGB_(0x7f, 0x7f, 0x7f) },
+ { "Grey51", RGB_(0x82, 0x82, 0x82) },
+ { "Grey52", RGB_(0x85, 0x85, 0x85) },
+ { "Grey53", RGB_(0x87, 0x87, 0x87) },
+ { "Grey54", RGB_(0x8a, 0x8a, 0x8a) },
+ { "Grey55", RGB_(0x8c, 0x8c, 0x8c) },
+ { "Grey56", RGB_(0x8f, 0x8f, 0x8f) },
+ { "Grey57", RGB_(0x91, 0x91, 0x91) },
+ { "Grey58", RGB_(0x94, 0x94, 0x94) },
+ { "Grey59", RGB_(0x96, 0x96, 0x96) },
+ { "Grey6", RGB_(0xf, 0xf, 0xf) },
+ { "Grey60", RGB_(0x99, 0x99, 0x99) },
+ { "Grey61", RGB_(0x9c, 0x9c, 0x9c) },
+ { "Grey62", RGB_(0x9e, 0x9e, 0x9e) },
+ { "Grey63", RGB_(0xa1, 0xa1, 0xa1) },
+ { "Grey64", RGB_(0xa3, 0xa3, 0xa3) },
+ { "Grey65", RGB_(0xa6, 0xa6, 0xa6) },
+ { "Grey66", RGB_(0xa8, 0xa8, 0xa8) },
+ { "Grey67", RGB_(0xab, 0xab, 0xab) },
+ { "Grey68", RGB_(0xad, 0xad, 0xad) },
+ { "Grey69", RGB_(0xb0, 0xb0, 0xb0) },
+ { "Grey7", RGB_(0x12, 0x12, 0x12) },
+ { "Grey70", RGB_(0xb3, 0xb3, 0xb3) },
+ { "Grey71", RGB_(0xb5, 0xb5, 0xb5) },
+ { "Grey72", RGB_(0xb8, 0xb8, 0xb8) },
+ { "Grey73", RGB_(0xba, 0xba, 0xba) },
+ { "Grey74", RGB_(0xbd, 0xbd, 0xbd) },
+ { "Grey75", RGB_(0xbf, 0xbf, 0xbf) },
+ { "Grey76", RGB_(0xc2, 0xc2, 0xc2) },
+ { "Grey77", RGB_(0xc4, 0xc4, 0xc4) },
+ { "Grey78", RGB_(0xc7, 0xc7, 0xc7) },
+ { "Grey79", RGB_(0xc9, 0xc9, 0xc9) },
+ { "Grey8", RGB_(0x14, 0x14, 0x14) },
+ { "Grey80", RGB_(0xcc, 0xcc, 0xcc) },
+ { "Grey81", RGB_(0xcf, 0xcf, 0xcf) },
+ { "Grey82", RGB_(0xd1, 0xd1, 0xd1) },
+ { "Grey83", RGB_(0xd4, 0xd4, 0xd4) },
+ { "Grey84", RGB_(0xd6, 0xd6, 0xd6) },
+ { "Grey85", RGB_(0xd9, 0xd9, 0xd9) },
+ { "Grey86", RGB_(0xdb, 0xdb, 0xdb) },
+ { "Grey87", RGB_(0xde, 0xde, 0xde) },
+ { "Grey88", RGB_(0xe0, 0xe0, 0xe0) },
+ { "Grey89", RGB_(0xe3, 0xe3, 0xe3) },
+ { "Grey9", RGB_(0x17, 0x17, 0x17) },
+ { "Grey90", RGB_(0xe5, 0xe5, 0xe5) },
+ { "Grey91", RGB_(0xe8, 0xe8, 0xe8) },
+ { "Grey92", RGB_(0xeb, 0xeb, 0xeb) },
+ { "Grey93", RGB_(0xed, 0xed, 0xed) },
+ { "Grey94", RGB_(0xf0, 0xf0, 0xf0) },
+ { "Grey95", RGB_(0xf2, 0xf2, 0xf2) },
+ { "Grey96", RGB_(0xf5, 0xf5, 0xf5) },
+ { "Grey97", RGB_(0xf7, 0xf7, 0xf7) },
+ { "Grey98", RGB_(0xfa, 0xfa, 0xfa) },
+ { "Grey99", RGB_(0xfc, 0xfc, 0xfc) },
+ { "Honeydew", RGB_(0xf0, 0xff, 0xf0) },
+ { "Honeydew1", RGB_(0xf0, 0xff, 0xf0) },
+ { "Honeydew2", RGB_(0xe0, 0xee, 0xe0) },
+ { "Honeydew3", RGB_(0xc1, 0xcd, 0xc1) },
+ { "Honeydew4", RGB_(0x83, 0x8b, 0x83) },
+ { "HotPink", RGB_(0xff, 0x69, 0xb4) },
+ { "HotPink1", RGB_(0xff, 0x6e, 0xb4) },
+ { "HotPink2", RGB_(0xee, 0x6a, 0xa7) },
+ { "HotPink3", RGB_(0xcd, 0x60, 0x90) },
+ { "HotPink4", RGB_(0x8b, 0x3a, 0x62) },
+ { "IndianRed", RGB_(0xcd, 0x5c, 0x5c) },
+ { "IndianRed1", RGB_(0xff, 0x6a, 0x6a) },
+ { "IndianRed2", RGB_(0xee, 0x63, 0x63) },
+ { "IndianRed3", RGB_(0xcd, 0x55, 0x55) },
+ { "IndianRed4", RGB_(0x8b, 0x3a, 0x3a) },
+ { "Indigo", RGB_(0x4b, 0x00, 0x82) },
+ { "Ivory", RGB_(0xff, 0xff, 0xf0) },
+ { "Ivory1", RGB_(0xff, 0xff, 0xf0) },
+ { "Ivory2", RGB_(0xee, 0xee, 0xe0) },
+ { "Ivory3", RGB_(0xcd, 0xcd, 0xc1) },
+ { "Ivory4", RGB_(0x8b, 0x8b, 0x83) },
+ { "Khaki", RGB_(0xf0, 0xe6, 0x8c) },
+ { "Khaki1", RGB_(0xff, 0xf6, 0x8f) },
+ { "Khaki2", RGB_(0xee, 0xe6, 0x85) },
+ { "Khaki3", RGB_(0xcd, 0xc6, 0x73) },
+ { "Khaki4", RGB_(0x8b, 0x86, 0x4e) },
+ { "Lavender", RGB_(0xe6, 0xe6, 0xfa) },
+ { "LavenderBlush", RGB_(0xff, 0xf0, 0xf5) },
+ { "LavenderBlush1", RGB_(0xff, 0xf0, 0xf5) },
+ { "LavenderBlush2", RGB_(0xee, 0xe0, 0xe5) },
+ { "LavenderBlush3", RGB_(0xcd, 0xc1, 0xc5) },
+ { "LavenderBlush4", RGB_(0x8b, 0x83, 0x86) },
+ { "LawnGreen", RGB_(0x7c, 0xfc, 0x00) },
+ { "LemonChiffon", RGB_(0xff, 0xfa, 0xcd) },
+ { "LemonChiffon1", RGB_(0xff, 0xfa, 0xcd) },
+ { "LemonChiffon2", RGB_(0xee, 0xe9, 0xbf) },
+ { "LemonChiffon3", RGB_(0xcd, 0xc9, 0xa5) },
+ { "LemonChiffon4", RGB_(0x8b, 0x89, 0x70) },
+ { "LightBlue", RGB_(0xad, 0xd8, 0xe6) },
+ { "LightBlue1", RGB_(0xbf, 0xef, 0xff) },
+ { "LightBlue2", RGB_(0xb2, 0xdf, 0xee) },
+ { "LightBlue3", RGB_(0x9a, 0xc0, 0xcd) },
+ { "LightBlue4", RGB_(0x68, 0x83, 0x8b) },
+ { "LightCoral", RGB_(0xf0, 0x80, 0x80) },
+ { "LightCyan", RGB_(0xe0, 0xff, 0xff) },
+ { "LightCyan1", RGB_(0xe0, 0xff, 0xff) },
+ { "LightCyan2", RGB_(0xd1, 0xee, 0xee) },
+ { "LightCyan3", RGB_(0xb4, 0xcd, 0xcd) },
+ { "LightCyan4", RGB_(0x7a, 0x8b, 0x8b) },
+ { "LightGoldenrod", RGB_(0xee, 0xdd, 0x82) },
+ { "LightGoldenrod1", RGB_(0xff, 0xec, 0x8b) },
+ { "LightGoldenrod2", RGB_(0xee, 0xdc, 0x82) },
+ { "LightGoldenrod3", RGB_(0xcd, 0xbe, 0x70) },
+ { "LightGoldenrod4", RGB_(0x8b, 0x81, 0x4c) },
+ { "LightGoldenRodYellow", RGB_(0xfa, 0xfa, 0xd2) },
+ { "LightGray", RGB_(0xd3, 0xd3, 0xd3) },
+ { "LightGreen", RGB_(0x90, 0xee, 0x90) },
+ { "LightGrey", RGB_(0xd3, 0xd3, 0xd3) },
+ { "LightMagenta", RGB_(0xff, 0xbb, 0xff) },
+ { "LightPink", RGB_(0xff, 0xb6, 0xc1) },
+ { "LightPink1", RGB_(0xff, 0xae, 0xb9) },
+ { "LightPink2", RGB_(0xee, 0xa2, 0xad) },
+ { "LightPink3", RGB_(0xcd, 0x8c, 0x95) },
+ { "LightPink4", RGB_(0x8b, 0x5f, 0x65) },
+ { "LightRed", RGB_(0xff, 0xbb, 0xbb) },
+ { "LightSalmon", RGB_(0xff, 0xa0, 0x7a) },
+ { "LightSalmon1", RGB_(0xff, 0xa0, 0x7a) },
+ { "LightSalmon2", RGB_(0xee, 0x95, 0x72) },
+ { "LightSalmon3", RGB_(0xcd, 0x81, 0x62) },
+ { "LightSalmon4", RGB_(0x8b, 0x57, 0x42) },
+ { "LightSeaGreen", RGB_(0x20, 0xb2, 0xaa) },
+ { "LightSkyBlue", RGB_(0x87, 0xce, 0xfa) },
+ { "LightSkyBlue1", RGB_(0xb0, 0xe2, 0xff) },
+ { "LightSkyBlue2", RGB_(0xa4, 0xd3, 0xee) },
+ { "LightSkyBlue3", RGB_(0x8d, 0xb6, 0xcd) },
+ { "LightSkyBlue4", RGB_(0x60, 0x7b, 0x8b) },
+ { "LightSlateBlue", RGB_(0x84, 0x70, 0xff) },
+ { "LightSlateGray", RGB_(0x77, 0x88, 0x99) },
+ { "LightSlateGrey", RGB_(0x77, 0x88, 0x99) },
+ { "LightSteelBlue", RGB_(0xb0, 0xc4, 0xde) },
+ { "LightSteelBlue1", RGB_(0xca, 0xe1, 0xff) },
+ { "LightSteelBlue2", RGB_(0xbc, 0xd2, 0xee) },
+ { "LightSteelBlue3", RGB_(0xa2, 0xb5, 0xcd) },
+ { "LightSteelBlue4", RGB_(0x6e, 0x7b, 0x8b) },
+ { "LightYellow", RGB_(0xff, 0xff, 0xe0) },
+ { "LightYellow1", RGB_(0xff, 0xff, 0xe0) },
+ { "LightYellow2", RGB_(0xee, 0xee, 0xd1) },
+ { "LightYellow3", RGB_(0xcd, 0xcd, 0xb4) },
+ { "LightYellow4", RGB_(0x8b, 0x8b, 0x7a) },
+ { "Lime", RGB_(0x00, 0xff, 0x00) },
+ { "LimeGreen", RGB_(0x32, 0xcd, 0x32) },
+ { "Linen", RGB_(0xfa, 0xf0, 0xe6) },
+ { "Magenta", RGB_(0xff, 0x00, 0xff) },
+ { "Magenta1", RGB_(0xff, 0x0, 0xff) },
+ { "Magenta2", RGB_(0xee, 0x0, 0xee) },
+ { "Magenta3", RGB_(0xcd, 0x0, 0xcd) },
+ { "Magenta4", RGB_(0x8b, 0x0, 0x8b) },
+ { "Maroon", RGB_(0x80, 0x00, 0x00) },
+ { "Maroon1", RGB_(0xff, 0x34, 0xb3) },
+ { "Maroon2", RGB_(0xee, 0x30, 0xa7) },
+ { "Maroon3", RGB_(0xcd, 0x29, 0x90) },
+ { "Maroon4", RGB_(0x8b, 0x1c, 0x62) },
+ { "MediumAquamarine", RGB_(0x66, 0xcd, 0xaa) },
+ { "MediumBlue", RGB_(0x00, 0x00, 0xcd) },
+ { "MediumOrchid", RGB_(0xba, 0x55, 0xd3) },
+ { "MediumOrchid1", RGB_(0xe0, 0x66, 0xff) },
+ { "MediumOrchid2", RGB_(0xd1, 0x5f, 0xee) },
+ { "MediumOrchid3", RGB_(0xb4, 0x52, 0xcd) },
+ { "MediumOrchid4", RGB_(0x7a, 0x37, 0x8b) },
+ { "MediumPurple", RGB_(0x93, 0x70, 0xdb) },
+ { "MediumPurple1", RGB_(0xab, 0x82, 0xff) },
+ { "MediumPurple2", RGB_(0x9f, 0x79, 0xee) },
+ { "MediumPurple3", RGB_(0x89, 0x68, 0xcd) },
+ { "MediumPurple4", RGB_(0x5d, 0x47, 0x8b) },
+ { "MediumSeaGreen", RGB_(0x3c, 0xb3, 0x71) },
+ { "MediumSlateBlue", RGB_(0x7b, 0x68, 0xee) },
+ { "MediumSpringGreen", RGB_(0x00, 0xfa, 0x9a) },
+ { "MediumTurquoise", RGB_(0x48, 0xd1, 0xcc) },
+ { "MediumVioletRed", RGB_(0xc7, 0x15, 0x85) },
+ { "MidnightBlue", RGB_(0x19, 0x19, 0x70) },
+ { "MintCream", RGB_(0xf5, 0xff, 0xfa) },
+ { "MistyRose", RGB_(0xff, 0xe4, 0xe1) },
+ { "MistyRose1", RGB_(0xff, 0xe4, 0xe1) },
+ { "MistyRose2", RGB_(0xee, 0xd5, 0xd2) },
+ { "MistyRose3", RGB_(0xcd, 0xb7, 0xb5) },
+ { "MistyRose4", RGB_(0x8b, 0x7d, 0x7b) },
+ { "Moccasin", RGB_(0xff, 0xe4, 0xb5) },
+ { "NavajoWhite", RGB_(0xff, 0xde, 0xad) },
+ { "NavajoWhite1", RGB_(0xff, 0xde, 0xad) },
+ { "NavajoWhite2", RGB_(0xee, 0xcf, 0xa1) },
+ { "NavajoWhite3", RGB_(0xcd, 0xb3, 0x8b) },
+ { "NavajoWhite4", RGB_(0x8b, 0x79, 0x5e) },
+ { "Navy", RGB_(0x00, 0x00, 0x80) },
+ { "NavyBlue", RGB_(0x0, 0x0, 0x80) },
+ { "OldLace", RGB_(0xfd, 0xf5, 0xe6) },
+ { "Olive", RGB_(0x80, 0x80, 0x00) },
+ { "OliveDrab", RGB_(0x6b, 0x8e, 0x23) },
+ { "OliveDrab1", RGB_(0xc0, 0xff, 0x3e) },
+ { "OliveDrab2", RGB_(0xb3, 0xee, 0x3a) },
+ { "OliveDrab3", RGB_(0x9a, 0xcd, 0x32) },
+ { "OliveDrab4", RGB_(0x69, 0x8b, 0x22) },
+ { "Orange", RGB_(0xff, 0xa5, 0x00) },
+ { "Orange1", RGB_(0xff, 0xa5, 0x0) },
+ { "Orange2", RGB_(0xee, 0x9a, 0x0) },
+ { "Orange3", RGB_(0xcd, 0x85, 0x0) },
+ { "Orange4", RGB_(0x8b, 0x5a, 0x0) },
+ { "OrangeRed", RGB_(0xff, 0x45, 0x00) },
+ { "OrangeRed1", RGB_(0xff, 0x45, 0x0) },
+ { "OrangeRed2", RGB_(0xee, 0x40, 0x0) },
+ { "OrangeRed3", RGB_(0xcd, 0x37, 0x0) },
+ { "OrangeRed4", RGB_(0x8b, 0x25, 0x0) },
+ { "Orchid", RGB_(0xda, 0x70, 0xd6) },
+ { "Orchid1", RGB_(0xff, 0x83, 0xfa) },
+ { "Orchid2", RGB_(0xee, 0x7a, 0xe9) },
+ { "Orchid3", RGB_(0xcd, 0x69, 0xc9) },
+ { "Orchid4", RGB_(0x8b, 0x47, 0x89) },
+ { "PaleGoldenRod", RGB_(0xee, 0xe8, 0xaa) },
+ { "PaleGreen", RGB_(0x98, 0xfb, 0x98) },
+ { "PaleGreen1", RGB_(0x9a, 0xff, 0x9a) },
+ { "PaleGreen2", RGB_(0x90, 0xee, 0x90) },
+ { "PaleGreen3", RGB_(0x7c, 0xcd, 0x7c) },
+ { "PaleGreen4", RGB_(0x54, 0x8b, 0x54) },
+ { "PaleTurquoise", RGB_(0xaf, 0xee, 0xee) },
+ { "PaleTurquoise1", RGB_(0xbb, 0xff, 0xff) },
+ { "PaleTurquoise2", RGB_(0xae, 0xee, 0xee) },
+ { "PaleTurquoise3", RGB_(0x96, 0xcd, 0xcd) },
+ { "PaleTurquoise4", RGB_(0x66, 0x8b, 0x8b) },
+ { "PaleVioletRed", RGB_(0xdb, 0x70, 0x93) },
+ { "PaleVioletRed1", RGB_(0xff, 0x82, 0xab) },
+ { "PaleVioletRed2", RGB_(0xee, 0x79, 0x9f) },
+ { "PaleVioletRed3", RGB_(0xcd, 0x68, 0x89) },
+ { "PaleVioletRed4", RGB_(0x8b, 0x47, 0x5d) },
+ { "PapayaWhip", RGB_(0xff, 0xef, 0xd5) },
+ { "PeachPuff", RGB_(0xff, 0xda, 0xb9) },
+ { "PeachPuff1", RGB_(0xff, 0xda, 0xb9) },
+ { "PeachPuff2", RGB_(0xee, 0xcb, 0xad) },
+ { "PeachPuff3", RGB_(0xcd, 0xaf, 0x95) },
+ { "PeachPuff4", RGB_(0x8b, 0x77, 0x65) },
+ { "Peru", RGB_(0xcd, 0x85, 0x3f) },
+ { "Pink", RGB_(0xff, 0xc0, 0xcb) },
+ { "Pink1", RGB_(0xff, 0xb5, 0xc5) },
+ { "Pink2", RGB_(0xee, 0xa9, 0xb8) },
+ { "Pink3", RGB_(0xcd, 0x91, 0x9e) },
+ { "Pink4", RGB_(0x8b, 0x63, 0x6c) },
+ { "Plum", RGB_(0xdd, 0xa0, 0xdd) },
+ { "Plum1", RGB_(0xff, 0xbb, 0xff) },
+ { "Plum2", RGB_(0xee, 0xae, 0xee) },
+ { "Plum3", RGB_(0xcd, 0x96, 0xcd) },
+ { "Plum4", RGB_(0x8b, 0x66, 0x8b) },
+ { "PowderBlue", RGB_(0xb0, 0xe0, 0xe6) },
+ { "Purple", RGB_(0x80, 0x00, 0x80) },
+ { "Purple1", RGB_(0x9b, 0x30, 0xff) },
+ { "Purple2", RGB_(0x91, 0x2c, 0xee) },
+ { "Purple3", RGB_(0x7d, 0x26, 0xcd) },
+ { "Purple4", RGB_(0x55, 0x1a, 0x8b) },
+ { "RebeccaPurple", RGB_(0x66, 0x33, 0x99) },
+ { "Red", RGB_(0xff, 0x00, 0x00) },
+ { "Red1", RGB_(0xff, 0x0, 0x0) },
+ { "Red2", RGB_(0xee, 0x0, 0x0) },
+ { "Red3", RGB_(0xcd, 0x0, 0x0) },
+ { "Red4", RGB_(0x8b, 0x0, 0x0) },
+ { "RosyBrown", RGB_(0xbc, 0x8f, 0x8f) },
+ { "RosyBrown1", RGB_(0xff, 0xc1, 0xc1) },
+ { "RosyBrown2", RGB_(0xee, 0xb4, 0xb4) },
+ { "RosyBrown3", RGB_(0xcd, 0x9b, 0x9b) },
+ { "RosyBrown4", RGB_(0x8b, 0x69, 0x69) },
+ { "RoyalBlue", RGB_(0x41, 0x69, 0xe1) },
+ { "RoyalBlue1", RGB_(0x48, 0x76, 0xff) },
+ { "RoyalBlue2", RGB_(0x43, 0x6e, 0xee) },
+ { "RoyalBlue3", RGB_(0x3a, 0x5f, 0xcd) },
+ { "RoyalBlue4", RGB_(0x27, 0x40, 0x8b) },
+ { "SaddleBrown", RGB_(0x8b, 0x45, 0x13) },
+ { "Salmon", RGB_(0xfa, 0x80, 0x72) },
+ { "Salmon1", RGB_(0xff, 0x8c, 0x69) },
+ { "Salmon2", RGB_(0xee, 0x82, 0x62) },
+ { "Salmon3", RGB_(0xcd, 0x70, 0x54) },
+ { "Salmon4", RGB_(0x8b, 0x4c, 0x39) },
+ { "SandyBrown", RGB_(0xf4, 0xa4, 0x60) },
+ { "SeaGreen", RGB_(0x2e, 0x8b, 0x57) },
+ { "SeaGreen1", RGB_(0x54, 0xff, 0x9f) },
+ { "SeaGreen2", RGB_(0x4e, 0xee, 0x94) },
+ { "SeaGreen3", RGB_(0x43, 0xcd, 0x80) },
+ { "SeaGreen4", RGB_(0x2e, 0x8b, 0x57) },
+ { "SeaShell", RGB_(0xff, 0xf5, 0xee) },
+ { "Seashell1", RGB_(0xff, 0xf5, 0xee) },
+ { "Seashell2", RGB_(0xee, 0xe5, 0xde) },
+ { "Seashell3", RGB_(0xcd, 0xc5, 0xbf) },
+ { "Seashell4", RGB_(0x8b, 0x86, 0x82) },
+ { "Sienna", RGB_(0xa0, 0x52, 0x2d) },
+ { "Sienna1", RGB_(0xff, 0x82, 0x47) },
+ { "Sienna2", RGB_(0xee, 0x79, 0x42) },
+ { "Sienna3", RGB_(0xcd, 0x68, 0x39) },
+ { "Sienna4", RGB_(0x8b, 0x47, 0x26) },
+ { "Silver", RGB_(0xc0, 0xc0, 0xc0) },
+ { "SkyBlue", RGB_(0x87, 0xce, 0xeb) },
+ { "SkyBlue1", RGB_(0x87, 0xce, 0xff) },
+ { "SkyBlue2", RGB_(0x7e, 0xc0, 0xee) },
+ { "SkyBlue3", RGB_(0x6c, 0xa6, 0xcd) },
+ { "SkyBlue4", RGB_(0x4a, 0x70, 0x8b) },
+ { "SlateBlue", RGB_(0x6a, 0x5a, 0xcd) },
+ { "SlateBlue1", RGB_(0x83, 0x6f, 0xff) },
+ { "SlateBlue2", RGB_(0x7a, 0x67, 0xee) },
+ { "SlateBlue3", RGB_(0x69, 0x59, 0xcd) },
+ { "SlateBlue4", RGB_(0x47, 0x3c, 0x8b) },
+ { "SlateGray", RGB_(0x70, 0x80, 0x90) },
+ { "SlateGray1", RGB_(0xc6, 0xe2, 0xff) },
+ { "SlateGray2", RGB_(0xb9, 0xd3, 0xee) },
+ { "SlateGray3", RGB_(0x9f, 0xb6, 0xcd) },
+ { "SlateGray4", RGB_(0x6c, 0x7b, 0x8b) },
+ { "SlateGrey", RGB_(0x70, 0x80, 0x90) },
+ { "Snow", RGB_(0xff, 0xfa, 0xfa) },
+ { "Snow1", RGB_(0xff, 0xfa, 0xfa) },
+ { "Snow2", RGB_(0xee, 0xe9, 0xe9) },
+ { "Snow3", RGB_(0xcd, 0xc9, 0xc9) },
+ { "Snow4", RGB_(0x8b, 0x89, 0x89) },
+ { "SpringGreen", RGB_(0x00, 0xff, 0x7f) },
+ { "SpringGreen1", RGB_(0x0, 0xff, 0x7f) },
+ { "SpringGreen2", RGB_(0x0, 0xee, 0x76) },
+ { "SpringGreen3", RGB_(0x0, 0xcd, 0x66) },
+ { "SpringGreen4", RGB_(0x0, 0x8b, 0x45) },
+ { "SteelBlue", RGB_(0x46, 0x82, 0xb4) },
+ { "SteelBlue1", RGB_(0x63, 0xb8, 0xff) },
+ { "SteelBlue2", RGB_(0x5c, 0xac, 0xee) },
+ { "SteelBlue3", RGB_(0x4f, 0x94, 0xcd) },
+ { "SteelBlue4", RGB_(0x36, 0x64, 0x8b) },
+ { "Tan", RGB_(0xd2, 0xb4, 0x8c) },
+ { "Tan1", RGB_(0xff, 0xa5, 0x4f) },
+ { "Tan2", RGB_(0xee, 0x9a, 0x49) },
+ { "Tan3", RGB_(0xcd, 0x85, 0x3f) },
+ { "Tan4", RGB_(0x8b, 0x5a, 0x2b) },
+ { "Teal", RGB_(0x00, 0x80, 0x80) },
+ { "Thistle", RGB_(0xd8, 0xbf, 0xd8) },
+ { "Thistle1", RGB_(0xff, 0xe1, 0xff) },
+ { "Thistle2", RGB_(0xee, 0xd2, 0xee) },
+ { "Thistle3", RGB_(0xcd, 0xb5, 0xcd) },
+ { "Thistle4", RGB_(0x8b, 0x7b, 0x8b) },
+ { "Tomato", RGB_(0xff, 0x63, 0x47) },
+ { "Tomato1", RGB_(0xff, 0x63, 0x47) },
+ { "Tomato2", RGB_(0xee, 0x5c, 0x42) },
+ { "Tomato3", RGB_(0xcd, 0x4f, 0x39) },
+ { "Tomato4", RGB_(0x8b, 0x36, 0x26) },
+ { "Turquoise", RGB_(0x40, 0xe0, 0xd0) },
+ { "Turquoise1", RGB_(0x0, 0xf5, 0xff) },
+ { "Turquoise2", RGB_(0x0, 0xe5, 0xee) },
+ { "Turquoise3", RGB_(0x0, 0xc5, 0xcd) },
+ { "Turquoise4", RGB_(0x0, 0x86, 0x8b) },
+ { "Violet", RGB_(0xee, 0x82, 0xee) },
+ { "VioletRed", RGB_(0xd0, 0x20, 0x90) },
+ { "VioletRed1", RGB_(0xff, 0x3e, 0x96) },
+ { "VioletRed2", RGB_(0xee, 0x3a, 0x8c) },
+ { "VioletRed3", RGB_(0xcd, 0x32, 0x78) },
+ { "VioletRed4", RGB_(0x8b, 0x22, 0x52) },
+ { "WebGray", RGB_(0x80, 0x80, 0x80) },
+ { "WebGreen", RGB_(0x0, 0x80, 0x0) },
+ { "WebGrey", RGB_(0x80, 0x80, 0x80) },
+ { "WebMaroon", RGB_(0x80, 0x0, 0x0) },
+ { "WebPurple", RGB_(0x80, 0x0, 0x80) },
+ { "Wheat", RGB_(0xf5, 0xde, 0xb3) },
+ { "Wheat1", RGB_(0xff, 0xe7, 0xba) },
+ { "Wheat2", RGB_(0xee, 0xd8, 0xae) },
+ { "Wheat3", RGB_(0xcd, 0xba, 0x96) },
+ { "Wheat4", RGB_(0x8b, 0x7e, 0x66) },
+ { "White", RGB_(0xff, 0xff, 0xff) },
+ { "WhiteSmoke", RGB_(0xf5, 0xf5, 0xf5) },
+ { "X11Gray", RGB_(0xbe, 0xbe, 0xbe) },
+ { "X11Green", RGB_(0x0, 0xff, 0x0) },
+ { "X11Grey", RGB_(0xbe, 0xbe, 0xbe) },
+ { "X11Maroon", RGB_(0xb0, 0x30, 0x60) },
+ { "X11Purple", RGB_(0xa0, 0x20, 0xf0) },
+ { "Yellow", RGB_(0xff, 0xff, 0x00) },
+ { "Yellow1", RGB_(0xff, 0xff, 0x0) },
+ { "Yellow2", RGB_(0xee, 0xee, 0x0) },
+ { "Yellow3", RGB_(0xcd, 0xcd, 0x0) },
+ { "Yellow4", RGB_(0x8b, 0x8b, 0x0) },
+ { "YellowGreen", RGB_(0x9a, 0xcd, 0x32) },
+ { NULL, 0 },
+};
+
+/// Translate to RgbValue if \p name is an hex value (e.g. #XXXXXX),
+/// else look into color_name_table to translate a color name to its
+/// hex value
+///
+/// @param[in] name string value to convert to RGB
+/// return the hex value or -1 if could not find a correct value
+RgbValue name_to_color(const char *name)
+{
+ if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2])
+ && isxdigit(name[3]) && isxdigit(name[4]) && isxdigit(name[5])
+ && isxdigit(name[6]) && name[7] == NUL) {
+ // rgb hex string
+ return (RgbValue)strtol((char *)(name + 1), NULL, 16);
+ } else if (!STRICMP(name, "bg") || !STRICMP(name, "background")) {
+ return normal_bg;
+ } else if (!STRICMP(name, "fg") || !STRICMP(name, "foreground")) {
+ return normal_fg;
+ }
+
+ for (int i = 0; color_name_table[i].name != NULL; i++) {
+ if (!STRICMP(name, color_name_table[i].name)) {
+ return color_name_table[i].color;
+ }
+ }
+
+ return -1;
+}
+
+int name_to_ctermcolor(const char *name)
+{
+ int i;
+ int off = TOUPPER_ASC(*name);
+ for (i = ARRAY_SIZE(color_names); --i >= 0;) {
+ if (off == color_names[i][0]
+ && STRICMP(name+1, color_names[i]+1) == 0) {
+ break;
+ }
+ }
+ if (i < 0) {
+ return -1;
+ }
+ TriState bold = kNone;
+ return lookup_color(i, false, &bold);
+}
diff --git a/src/nvim/highlight_group.h b/src/nvim/highlight_group.h
new file mode 100644
index 0000000000..325113a4ab
--- /dev/null
+++ b/src/nvim/highlight_group.h
@@ -0,0 +1,19 @@
+#ifndef NVIM_HIGHLIGHT_GROUP_H
+#define NVIM_HIGHLIGHT_GROUP_H
+
+#include "nvim/types.h"
+#include "nvim/eval.h"
+
+#define MAX_HL_ID 20000 // maximum value for a highlight ID.
+
+typedef struct {
+ char *name;
+ RgbValue color;
+} color_name_table_T;
+extern color_name_table_T color_name_table[];
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+# include "highlight_group.h.generated.h"
+#endif
+
+#endif // NVIM_HIGHLIGHT_GROUP_H
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index beea1959e1..0bb224c729 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -476,7 +476,13 @@ static bool typval_conv_special = false;
#define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun) \
do { \
- TYPVAL_ENCODE_CONV_NIL(tv); \
+ ufunc_T *fp = find_func(fun); \
+ assert(fp != NULL); \
+ if (fp->uf_cb == nlua_CFunction_func_call) { \
+ nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref); \
+ } else { \
+ TYPVAL_ENCODE_CONV_NIL(tv); \
+ } \
goto typval_encode_stop_converting_one_item; \
} while (0)
@@ -615,14 +621,6 @@ bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special)
semsg(_("E1502: Lua failed to grow stack to %i"), initial_size + 4);
return false;
}
- if (tv->v_type == VAR_FUNC) {
- ufunc_T *fp = find_func(tv->vval.v_string);
- assert(fp != NULL);
- if (fp->uf_cb == nlua_CFunction_func_call) {
- nlua_pushref(lstate, ((LuaCFunctionState *)fp->uf_cb_state)->lua_callable.func_ref);
- return true;
- }
- }
if (encode_vim_to_lua(lstate, tv, "nlua_push_typval argument") == FAIL) {
return false;
}
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 054f6c9483..21625854fb 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -92,7 +92,22 @@ static void nlua_error(lua_State *const lstate, const char *const msg)
FUNC_ATTR_NONNULL_ALL
{
size_t len;
- const char *const str = lua_tolstring(lstate, -1, &len);
+ const char *str = NULL;
+
+ if (luaL_getmetafield(lstate, -1, "__tostring")) {
+ if (lua_isfunction(lstate, -1) && luaL_callmeta(lstate, -2, "__tostring")) {
+ // call __tostring, convert the result and pop result.
+ str = lua_tolstring(lstate, -1, &len);
+ lua_pop(lstate, 1);
+ }
+ // pop __tostring.
+ lua_pop(lstate, 1);
+ }
+
+ if (!str) {
+ // defer to lua default conversion, this will render tables as [NULL].
+ str = lua_tolstring(lstate, -1, &len);
+ }
msg_ext_set_kind("lua_error");
semsg_multiline(msg, (int)len, str);
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 95ef306745..dec1ae93e7 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -25,6 +25,7 @@
#include "nvim/getchar.h"
#include "nvim/hashtab.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/iconv.h"
#include "nvim/if_cscope.h"
#include "nvim/lua/executor.h"
@@ -112,7 +113,6 @@ static const char *err_too_many_args = N_("Too many edit arguments");
static const char *err_extra_cmd =
N_("Too many \"+command\", \"-c command\" or \"--cmd command\" arguments");
-
void event_init(void)
{
loop_init(&main_loop, NULL);
@@ -344,6 +344,12 @@ int main(int argc, char **argv)
TIME_MSG("init screen for UI");
}
+ if (ui_client_channel_id) {
+ ui_client_init(ui_client_channel_id);
+ ui_client_execute(ui_client_channel_id);
+ abort(); // unreachable
+ }
+
init_default_mappings(); // Default mappings.
TIME_MSG("init default mappings");
@@ -840,9 +846,8 @@ static void remote_request(mparm_T *params, int remote_args,
exit(1);
}
- ui_client_init(chan);
- ui_client_execute(chan);
- abort(); // unreachable
+ ui_client_channel_id = chan;
+ return;
}
Array args = ARRAY_DICT_INIT;
diff --git a/src/nvim/map.c b/src/nvim/map.c
index 4e39eb8c07..b3f48ad5d6 100644
--- a/src/nvim/map.c
+++ b/src/nvim/map.c
@@ -179,6 +179,7 @@ MAP_IMPL(HlEntry, int, DEFAULT_INITIALIZER)
MAP_IMPL(String, handle_T, 0)
MAP_IMPL(String, int, DEFAULT_INITIALIZER)
MAP_IMPL(int, String, DEFAULT_INITIALIZER)
+MAP_IMPL(String, UIClientHandler, NULL)
MAP_IMPL(ColorKey, ColorItem, COLOR_ITEM_INITIALIZER)
diff --git a/src/nvim/map.h b/src/nvim/map.h
index 00f72386a7..693ef50127 100644
--- a/src/nvim/map.h
+++ b/src/nvim/map.h
@@ -8,6 +8,7 @@
#include "nvim/extmark_defs.h"
#include "nvim/highlight_defs.h"
#include "nvim/map_defs.h"
+#include "nvim/ui_client.h"
#if defined(__NetBSD__)
# undef uint64_t
@@ -48,6 +49,7 @@ MAP_DECLS(HlEntry, int)
MAP_DECLS(String, handle_T)
MAP_DECLS(String, int)
MAP_DECLS(int, String)
+MAP_DECLS(String, UIClientHandler)
MAP_DECLS(ColorKey, ColorItem)
diff --git a/src/nvim/memory.c b/src/nvim/memory.c
index d68ca6b62e..6cdc4f1fde 100644
--- a/src/nvim/memory.c
+++ b/src/nvim/memory.c
@@ -13,6 +13,7 @@
#include "nvim/decoration_provider.h"
#include "nvim/eval.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/lua/executor.h"
#include "nvim/memfile.h"
#include "nvim/memory.h"
diff --git a/src/nvim/message.c b/src/nvim/message.c
index b39450cdc6..b3fefbc0f4 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.c
@@ -206,11 +206,10 @@ void msg_grid_validate(void)
}
}
-/*
- * msg(s) - displays the string 's' on the status line
- * When terminal not initialized (yet) mch_errmsg(..) is used.
- * return TRUE if wait_return not called
- */
+/// Displays the string 's' on the status line
+/// When terminal not initialized (yet) mch_errmsg(..) is used.
+///
+/// @return TRUE if wait_return not called
int msg(char *s)
{
return msg_attr_keep(s, 0, false, false);
@@ -232,7 +231,7 @@ int msg_attr(const char *s, const int attr)
return msg_attr_keep(s, attr, false, false);
}
-/// similar to msg_outtrans_attr, but support newlines and tabs.
+/// Similar to msg_outtrans_attr, but support newlines and tabs.
void msg_multiline_attr(const char *s, int attr, bool check_int, bool *need_clear)
FUNC_ATTR_NONNULL_ALL
{
@@ -339,7 +338,8 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
}
/// Truncate a string such that it can be printed without causing a scroll.
-/// Returns an allocated string or NULL when no truncating is done.
+///
+/// @return an allocated string or NULL when no truncating is done.
///
/// @param force always truncate
char_u *msg_strtrunc(char_u *s, int force)
@@ -371,10 +371,8 @@ char_u *msg_strtrunc(char_u *s, int force)
return buf;
}
-/*
- * Truncate a string "s" to "buf" with cell width "room".
- * "s" and "buf" may be equal.
- */
+/// Truncate a string "s" to "buf" with cell width "room".
+/// "s" and "buf" may be equal.
void trunc_string(char_u *s, char_u *buf, int room_in, int buflen)
{
size_t room = room_in - 3; // "..." takes 3 chars
@@ -498,19 +496,15 @@ int smsg_attr_keep(int attr, const char *s, ...)
static int last_sourcing_lnum = 0;
static char_u *last_sourcing_name = NULL;
-/*
- * Reset the last used sourcing name/lnum. Makes sure it is displayed again
- * for the next error message;
- */
+/// Reset the last used sourcing name/lnum. Makes sure it is displayed again
+/// for the next error message;
void reset_last_sourcing(void)
{
XFREE_CLEAR(last_sourcing_name);
last_sourcing_lnum = 0;
}
-/*
- * Return TRUE if "sourcing_name" differs from "last_sourcing_name".
- */
+/// @return TRUE if "sourcing_name" differs from "last_sourcing_name".
static int other_sourcing_name(void)
{
if (sourcing_name != NULL) {
@@ -560,11 +554,9 @@ static char *get_emsg_lnum(void)
return NULL;
}
-/*
- * Display name and line number for the source of an error.
- * Remember the file name and line number, so that for the next error the info
- * is only displayed if it changed.
- */
+/// Display name and line number for the source of an error.
+/// Remember the file name and line number, so that for the next error the info
+/// is only displayed if it changed.
void msg_source(int attr)
{
no_wait_return++;
@@ -592,12 +584,10 @@ void msg_source(int attr)
--no_wait_return;
}
-/*
- * Return TRUE if not giving error messages right now:
- * If "emsg_off" is set: no error messages at the moment.
- * If "msg" is in 'debug': do error message but without side effects.
- * If "emsg_skip" is set: never do error messages.
- */
+/// @return TRUE if not giving error messages right now:
+/// If "emsg_off" is set: no error messages at the moment.
+/// If "msg" is in 'debug': do error message but without side effects.
+/// If "emsg_skip" is set: never do error messages.
int emsg_not_now(void)
{
if ((emsg_off > 0 && vim_strchr(p_debug, 'm') == NULL
@@ -840,10 +830,11 @@ void msg_schedule_semsg(const char *const fmt, ...)
multiqueue_put(main_loop.events, msg_semsg_event, 1, s);
}
-// Like msg(), but truncate to a single line if p_shm contains 't', or when
-// "force" is true. This truncates in another way as for normal messages.
-// Careful: The string may be changed by msg_may_trunc()!
-// Returns a pointer to the printed message, if wait_return() not called.
+/// Like msg(), but truncate to a single line if p_shm contains 't', or when
+/// "force" is true. This truncates in another way as for normal messages.
+/// Careful: The string may be changed by msg_may_trunc()!
+///
+/// @return a pointer to the printed message, if wait_return() not called.
char *msg_trunc_attr(char *s, bool force, int attr)
{
int n;
@@ -863,11 +854,11 @@ char *msg_trunc_attr(char *s, bool force, int attr)
return NULL;
}
-/*
- * Check if message "s" should be truncated at the start (for filenames).
- * Return a pointer to where the truncated message starts.
- * Note: May change the message by replacing a character with '<'.
- */
+/// Check if message "s" should be truncated at the start (for filenames).
+///
+/// @return a pointer to where the truncated message starts.
+///
+/// @note: May change the message by replacing a character with '<'.
char_u *msg_may_trunc(bool force, char_u *s)
{
int room;
@@ -967,10 +958,9 @@ static void add_msg_hist(const char *s, int len, int attr, bool multiline)
msg_hist_len++;
}
-/*
- * Delete the first (oldest) message from the history.
- * Returns FAIL if there are no messages.
- */
+/// Delete the first (oldest) message from the history.
+///
+/// @return FAIL if there are no messages.
int delete_first_msg(void)
{
struct msg_hist *p;
@@ -1056,10 +1046,8 @@ void ex_messages(void *const eap_p)
}
}
-/*
- * Call this after prompting the user. This will avoid a hit-return message
- * and a delay.
- */
+/// Call this after prompting the user. This will avoid a hit-return message
+/// and a delay.
void msg_end_prompt(void)
{
msg_ext_clear_later();
@@ -1073,9 +1061,9 @@ void msg_end_prompt(void)
/// Wait for the user to hit a key (normally Enter)
///
-/// If 'redraw' is true, redraw the entire screen NOT_VALID
-/// If 'redraw' is false, do a normal redraw
-/// If 'redraw' is -1, don't redraw at all
+/// @param redraw if true, redraw the entire screen NOT_VALID
+/// if false, do a normal redraw
+/// if -1, don't redraw at all
void wait_return(int redraw)
{
int c;
@@ -1265,9 +1253,7 @@ void wait_return(int redraw)
}
}
-/*
- * Write the hit-return prompt.
- */
+/// Write the hit-return prompt.
static void hit_return_msg(void)
{
int save_p_more = p_more;
@@ -1288,9 +1274,7 @@ static void hit_return_msg(void)
p_more = save_p_more;
}
-/*
- * Set "keep_msg" to "s". Free the old value and check for NULL pointer.
- */
+/// Set "keep_msg" to "s". Free the old value and check for NULL pointer.
void set_keep_msg(char *s, int attr)
{
xfree(keep_msg);
@@ -1357,9 +1341,7 @@ void msg_ext_set_kind(const char *msg_kind)
msg_ext_kind = msg_kind;
}
-/*
- * Prepare for outputting characters in the command line.
- */
+/// Prepare for outputting characters in the command line.
void msg_start(void)
{
int did_return = false;
@@ -1406,9 +1388,7 @@ void msg_start(void)
}
}
-/*
- * Note that the current msg position is where messages start.
- */
+/// Note that the current msg position is where messages start.
void msg_starthere(void)
{
lines_left = cmdline_row;
@@ -1462,12 +1442,11 @@ static void msg_home_replace_attr(char_u *fname, int attr)
xfree(name);
}
-/*
- * Output 'len' characters in 'str' (including NULs) with translation
- * if 'len' is -1, output up to a NUL character.
- * Use attributes 'attr'.
- * Return the number of characters it takes on the screen.
- */
+/// Output 'len' characters in 'str' (including NULs) with translation
+/// if 'len' is -1, output up to a NUL character.
+/// Use attributes 'attr'.
+///
+/// @return the number of characters it takes on the screen.
int msg_outtrans(char_u *str)
{
return msg_outtrans_attr(str, 0);
@@ -1483,10 +1462,10 @@ int msg_outtrans_len(const char_u *str, int len)
return msg_outtrans_len_attr(str, len, 0);
}
-/*
- * Output one character at "p". Return pointer to the next character.
- * Handles multi-byte characters.
- */
+/// Output one character at "p".
+/// Handles multi-byte characters.
+///
+/// @return pointer to the next character.
char_u *msg_outtrans_one(char_u *p, int attr)
{
int l;
@@ -1752,9 +1731,7 @@ void str2specialbuf(const char *sp, char *buf, size_t len)
*buf = NUL;
}
-/*
- * print line for :print or :list command
- */
+/// print line for :print or :list command
void msg_prt_line(char_u *s, int list)
{
int c;
@@ -1903,8 +1880,9 @@ void msg_prt_line(char_u *s, int list)
msg_clr_eos();
}
-// Use grid_puts() to output one multi-byte character.
-// Return the pointer "s" advanced to the next character.
+/// Use grid_puts() to output one multi-byte character.
+///
+/// @return the pointer "s" advanced to the next character.
static char_u *screen_puts_mbyte(char_u *s, int l, int attr)
{
int cw;
@@ -1936,10 +1914,8 @@ static char_u *screen_puts_mbyte(char_u *s, int l, int attr)
return s + l;
}
-/*
- * Output a string to the screen at position msg_row, msg_col.
- * Update msg_row and msg_col for the next message.
- */
+/// Output a string to the screen at position msg_row, msg_col.
+/// Update msg_row and msg_col for the next message.
void msg_puts(const char *s)
{
msg_puts_attr(s, 0);
@@ -1950,11 +1926,9 @@ void msg_puts_title(const char *s)
msg_puts_attr(s, HL_ATTR(HLF_T));
}
-/*
- * Show a message in such a way that it always fits in the line. Cut out a
- * part in the middle and replace it with "..." when necessary.
- * Does not handle multi-byte characters!
- */
+/// Show a message in such a way that it always fits in the line. Cut out a
+/// part in the middle and replace it with "..." when necessary.
+/// Does not handle multi-byte characters!
void msg_outtrans_long_attr(char_u *longstr, int attr)
{
msg_outtrans_long_len_attr(longstr, (int)STRLEN(longstr), attr);
@@ -1974,9 +1948,7 @@ void msg_outtrans_long_len_attr(char_u *longstr, int len, int attr)
msg_outtrans_len_attr(longstr + len - slen, slen, attr);
}
-/*
- * Basic function for writing a message with highlight attributes.
- */
+/// Basic function for writing a message with highlight attributes.
void msg_puts_attr(const char *const s, const int attr)
{
msg_puts_attr_len(s, -1, attr);
@@ -2078,10 +2050,8 @@ static void msg_ext_emit_chunk(void)
ADD(msg_ext_chunks, ARRAY_OBJ(chunk));
}
-/*
- * The display part of msg_puts_attr_len().
- * May be called recursively to display scroll-back text.
- */
+/// The display part of msg_puts_attr_len().
+/// May be called recursively to display scroll-back text.
static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurse)
{
const char_u *s = str;
@@ -2286,8 +2256,8 @@ static void msg_puts_display(const char_u *str, int maxlen, int attr, int recurs
msg_check();
}
-/// Return true when ":filter pattern" was used and "msg" does not match
-/// "pattern".
+/// @return true when ":filter pattern" was used and "msg" does not match
+/// "pattern".
bool message_filtered(char_u *msg)
{
if (cmdmod.filter_regmatch.regprog == NULL) {
@@ -2419,9 +2389,7 @@ void msg_reset_scroll(void)
msg_scrolled_at_flush = 0;
}
-/*
- * Increment "msg_scrolled".
- */
+/// Increment "msg_scrolled".
static void inc_msg_scrolled(void)
{
if (*get_vim_var_str(VV_SCROLLSTART) == NUL) {
@@ -2500,9 +2468,7 @@ static void store_sb_text(char_u **sb_str, char_u *s, int attr, int *sb_col, int
*sb_col = 0;
}
-/*
- * Finished showing messages, clear the scroll-back text on the next message.
- */
+/// Finished showing messages, clear the scroll-back text on the next message.
void may_clear_sb_text(void)
{
do_clear_sb_text = SB_CLEAR_ALL;
@@ -2545,9 +2511,7 @@ void clear_sb_text(int all)
}
}
-/*
- * "g<" command.
- */
+/// "g<" command.
void show_sb_text(void)
{
msgchunk_T *mp;
@@ -2563,9 +2527,7 @@ void show_sb_text(void)
}
}
-/*
- * Move to the start of screen line in already displayed text.
- */
+/// Move to the start of screen line in already displayed text.
static msgchunk_T *msg_sb_start(msgchunk_T *mps)
{
msgchunk_T *mp = mps;
@@ -2576,9 +2538,7 @@ static msgchunk_T *msg_sb_start(msgchunk_T *mps)
return mp;
}
-/*
- * Mark the last message chunk as finishing the line.
- */
+/// Mark the last message chunk as finishing the line.
void msg_sb_eol(void)
{
if (last_msgchunk != NULL) {
@@ -2586,10 +2546,9 @@ void msg_sb_eol(void)
}
}
-/*
- * Display a screen line from previously displayed text at row "row".
- * Returns a pointer to the text for the next line (can be NULL).
- */
+/// Display a screen line from previously displayed text at row "row".
+///
+/// @return a pointer to the text for the next line (can be NULL).
static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp)
{
msgchunk_T *mp = smp;
@@ -2612,9 +2571,7 @@ static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp)
return mp->sb_next;
}
-/*
- * Output any postponed text for msg_puts_attr_len().
- */
+/// Output any postponed text for msg_puts_attr_len().
static void t_puts(int *t_col, const char_u *t_s, const char_u *s, int attr)
{
attr = hl_combine_attr(HL_ATTR(HLF_MSG), attr);
@@ -2635,9 +2592,9 @@ static void t_puts(int *t_col, const char_u *t_s, const char_u *s, int attr)
}
}
-// Returns TRUE when messages should be printed to stdout/stderr:
-// - "batch mode" ("silent mode", -es/-Es)
-// - no UI and not embedded
+/// @return TRUE when messages should be printed to stdout/stderr:
+/// - "batch mode" ("silent mode", -es/-Es)
+/// - no UI and not embedded
int msg_use_printf(void)
{
return !embedded_mode && !ui_active();
@@ -2698,13 +2655,12 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
msg_didout = true; // assume that line is not empty
}
-/*
- * Show the more-prompt and handle the user response.
- * This takes care of scrolling back and displaying previously displayed text.
- * When at hit-enter prompt "typed_char" is the already typed character,
- * otherwise it's NUL.
- * Returns TRUE when jumping ahead to "confirm_msg_tail".
- */
+/// Show the more-prompt and handle the user response.
+/// This takes care of scrolling back and displaying previously displayed text.
+/// When at hit-enter prompt "typed_char" is the already typed character,
+/// otherwise it's NUL.
+///
+/// @return TRUE when jumping ahead to "confirm_msg_tail".
static int do_more_prompt(int typed_char)
{
static bool entered = false;
@@ -2962,7 +2918,7 @@ void mch_errmsg(char *str)
}
}
-// Give a message. To be used when the UI is not initialized yet.
+/// Give a message. To be used when the UI is not initialized yet.
void mch_msg(char *str)
{
assert(str != NULL);
@@ -2977,10 +2933,8 @@ void mch_msg(char *str)
}
#endif // WIN32
-/*
- * Put a character on the screen at the current message position and advance
- * to the next position. Only for printable ASCII!
- */
+/// Put a character on the screen at the current message position and advance
+/// to the next position. Only for printable ASCII!
static void msg_screen_putchar(int c, int attr)
{
attr = hl_combine_attr(HL_ATTR(HLF_MSG), attr);
@@ -3013,10 +2967,8 @@ void msg_moremsg(int full)
}
}
-/*
- * Repeat the message for the current mode: ASKMORE, EXTERNCMD, CONFIRM or
- * exmode_active.
- */
+/// Repeat the message for the current mode: ASKMORE, EXTERNCMD, CONFIRM or
+/// exmode_active.
void repeat_message(void)
{
if (State == ASKMORE) {
@@ -3041,10 +2993,8 @@ void repeat_message(void)
}
}
-/*
- * Clear from current message position to end of screen.
- * Skip this when ":silent" was used, no need to clear for redirection.
- */
+/// Clear from current message position to end of screen.
+/// Skip this when ":silent" was used, no need to clear for redirection.
void msg_clr_eos(void)
{
if (msg_silent == 0) {
@@ -3052,11 +3002,9 @@ void msg_clr_eos(void)
}
}
-/*
- * Clear from current message position to end of screen.
- * Note: msg_col is not updated, so we remember the end of the message
- * for msg_check().
- */
+/// Clear from current message position to end of screen.
+/// Note: msg_col is not updated, so we remember the end of the message
+/// for msg_check().
void msg_clr_eos_force(void)
{
if (ui_has(kUIMessages)) {
@@ -3083,9 +3031,7 @@ void msg_clr_eos_force(void)
}
}
-/*
- * Clear the command line.
- */
+/// Clear the command line.
void msg_clr_cmdline(void)
{
msg_row = cmdline_row;
@@ -3093,11 +3039,10 @@ void msg_clr_cmdline(void)
msg_clr_eos_force();
}
-/*
- * end putting a message on the screen
- * call wait_return if the message does not fit in the available space
- * return TRUE if wait_return not called.
- */
+/// end putting a message on the screen
+/// call wait_return if the message does not fit in the available space
+///
+/// @return TRUE if wait_return not called.
int msg_end(void)
{
/*
@@ -3187,10 +3132,8 @@ bool msg_ext_is_visible(void)
return ui_has(kUIMessages) && msg_ext_visible > 0;
}
-/*
- * If the written message runs into the shown command or ruler, we have to
- * wait for hit-return and redraw the window later.
- */
+/// If the written message runs into the shown command or ruler, we have to
+/// wait for hit-return and redraw the window later.
void msg_check(void)
{
if (ui_has(kUIMessages)) {
@@ -3202,10 +3145,9 @@ void msg_check(void)
}
}
-/*
- * May write a string to the redirection file.
- * When "maxlen" is -1 write the whole string, otherwise up to "maxlen" bytes.
- */
+/// May write a string to the redirection file.
+///
+/// @param maxlen if -1, write the whole string, otherwise up to "maxlen" bytes.
static void redir_write(const char *const str, const ptrdiff_t maxlen)
{
const char_u *s = (char_u *)str;
@@ -3290,10 +3232,8 @@ int redirecting(void)
|| redir_reg || redir_vname || capture_ga != NULL;
}
-/*
- * Before giving verbose message.
- * Must always be called paired with verbose_leave()!
- */
+/// Before giving verbose message.
+/// Must always be called paired with verbose_leave()!
void verbose_enter(void)
{
if (*p_vfile != NUL) {
@@ -3301,10 +3241,8 @@ void verbose_enter(void)
}
}
-/*
- * After giving verbose message.
- * Must always be called paired with verbose_enter()!
- */
+/// After giving verbose message.
+/// Must always be called paired with verbose_enter()!
void verbose_leave(void)
{
if (*p_vfile != NUL) {
@@ -3314,9 +3252,7 @@ void verbose_leave(void)
}
}
-/*
- * Like verbose_enter() and set msg_scroll when displaying the message.
- */
+/// Like verbose_enter() and set msg_scroll when displaying the message.
void verbose_enter_scroll(void)
{
if (*p_vfile != NUL) {
@@ -3327,9 +3263,7 @@ void verbose_enter_scroll(void)
}
}
-/*
- * Like verbose_leave() and set cmdline_row when displaying the message.
- */
+/// Like verbose_leave() and set cmdline_row when displaying the message.
void verbose_leave_scroll(void)
{
if (*p_vfile != NUL) {
@@ -3341,9 +3275,7 @@ void verbose_leave_scroll(void)
}
}
-/*
- * Called when 'verbosefile' is set: stop writing to the file.
- */
+/// Called when 'verbosefile' is set: stop writing to the file.
void verbose_stop(void)
{
if (verbose_fd != NULL) {
@@ -3353,10 +3285,9 @@ void verbose_stop(void)
verbose_did_open = FALSE;
}
-/*
- * Open the file 'verbosefile'.
- * Return FAIL or OK.
- */
+/// Open the file 'verbosefile'.
+///
+/// @return FAIL or OK.
int verbose_open(void)
{
if (verbose_fd == NULL && !verbose_did_open) {
@@ -3372,10 +3303,8 @@ int verbose_open(void)
return OK;
}
-/*
- * Give a warning message (for searching).
- * Use 'w' highlighting and may repeat the message after redrawing
- */
+/// Give a warning message (for searching).
+/// Use 'w' highlighting and may repeat the message after redrawing
void give_warning(char_u *message, bool hl) FUNC_ATTR_NONNULL_ARG(1)
{
// Don't do this for ":silent".
@@ -3414,9 +3343,7 @@ void give_warning2(char_u *const message, char_u *const a1, bool hl)
give_warning(IObuff, hl);
}
-/*
- * Advance msg cursor to column "col".
- */
+/// Advance msg cursor to column "col".
void msg_advance(int col)
{
if (msg_silent != 0) { // nothing to advance to
@@ -3626,15 +3553,13 @@ static char_u *console_dialog_alloc(const char_u *message, char_u *buttons, bool
return xmalloc(lenhotkey);
}
-/*
- * Format the dialog string, and display it at the bottom of
- * the screen. Return a string of hotkey chars (if defined) for
- * each 'button'. If a button has no hotkey defined, the first character of
- * the button is used.
- * The hotkeys can be multi-byte characters, but without combining chars.
- *
- * Returns an allocated string with hotkeys.
- */
+/// Format the dialog string, and display it at the bottom of
+/// the screen. Return a string of hotkey chars (if defined) for
+/// each 'button'. If a button has no hotkey defined, the first character of
+/// the button is used.
+/// The hotkeys can be multi-byte characters, but without combining chars.
+///
+/// @return an allocated string with hotkeys.
static char_u *msg_show_console_dialog(char_u *message, char_u *buttons, int dfltbutton)
FUNC_ATTR_NONNULL_RET
{
@@ -3727,9 +3652,7 @@ static void copy_hotkeys_and_msg(const char_u *message, char_u *buttons, int def
*msgp = NUL;
}
-/*
- * Display the ":confirm" message. Also called when screen resized.
- */
+/// Display the ":confirm" message. Also called when screen resized.
void display_confirm_msg(void)
{
// Avoid that 'q' at the more prompt truncates the message here.
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index f4e836fa81..48ecd5d0ea 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -547,12 +547,8 @@ void rpc_close(Channel *channel)
channel->rpc.closed = true;
channel_decref(channel);
- if (channel->id == ui_client_channel_id) {
- // TODO(bfredl): handle this in ui_client, where os_exit() is safe
- exit(0);
- }
-
- if (channel->streamtype == kChannelStreamStdio) {
+ if (channel->streamtype == kChannelStreamStdio
+ || channel->id == ui_client_channel_id) {
multiqueue_put(main_loop.fast_events, exit_event, 0);
}
}
diff --git a/src/nvim/option.c b/src/nvim/option.c
index 191b635dc0..ffd009be89 100644
--- a/src/nvim/option.c
+++ b/src/nvim/option.c
@@ -47,6 +47,7 @@
#include "nvim/getchar.h"
#include "nvim/hardcopy.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/indent_c.h"
#include "nvim/keymap.h"
#include "nvim/macros.h"
@@ -2910,7 +2911,7 @@ ambw_end:
|| check_opt_strings(curbuf->b_p_bt, p_buftype_values, false) != OK) {
errmsg = e_invarg;
} else {
- if (curwin->w_status_height) {
+ if (curwin->w_status_height || global_stl_height()) {
curwin->w_redr_status = true;
redraw_later(curwin, VALID);
}
@@ -3553,16 +3554,22 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
struct chars_tab *tab;
struct chars_tab fcs_tab[] = {
- { &wp->w_p_fcs_chars.stl, "stl", ' ' },
- { &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
- { &wp->w_p_fcs_chars.vert, "vert", 9474 }, // │
- { &wp->w_p_fcs_chars.fold, "fold", 183 }, // ·
- { &wp->w_p_fcs_chars.foldopen, "foldopen", '-' },
- { &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' },
- { &wp->w_p_fcs_chars.foldsep, "foldsep", 9474 }, // │
- { &wp->w_p_fcs_chars.diff, "diff", '-' },
- { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
- { &wp->w_p_fcs_chars.eob, "eob", '~' },
+ { &wp->w_p_fcs_chars.stl, "stl", ' ' },
+ { &wp->w_p_fcs_chars.stlnc, "stlnc", ' ' },
+ { &wp->w_p_fcs_chars.horiz, "horiz", 9472 }, // ─
+ { &wp->w_p_fcs_chars.horizup, "horizup", 9524 }, // ┴
+ { &wp->w_p_fcs_chars.horizdown, "horizdown", 9516 }, // ┬
+ { &wp->w_p_fcs_chars.vert, "vert", 9474 }, // │
+ { &wp->w_p_fcs_chars.vertleft, "vertleft", 9508 }, // ┤
+ { &wp->w_p_fcs_chars.vertright, "vertright", 9500 }, // ├
+ { &wp->w_p_fcs_chars.verthoriz, "verthoriz", 9532 }, // ┼
+ { &wp->w_p_fcs_chars.fold, "fold", 183 }, // ·
+ { &wp->w_p_fcs_chars.foldopen, "foldopen", '-' },
+ { &wp->w_p_fcs_chars.foldclosed, "foldclose", '+' },
+ { &wp->w_p_fcs_chars.foldsep, "foldsep", 9474 }, // │
+ { &wp->w_p_fcs_chars.diff, "diff", '-' },
+ { &wp->w_p_fcs_chars.msgsep, "msgsep", ' ' },
+ { &wp->w_p_fcs_chars.eob, "eob", '~' },
};
struct chars_tab lcs_tab[] = {
{ &wp->w_p_lcs_chars.eol, "eol", NUL },
@@ -3589,15 +3596,17 @@ static char *set_chars_option(win_T *wp, char_u **varp, bool set)
varp = &p_fcs;
}
if (*p_ambw == 'd') {
- // XXX: If ambiwidth=double then "|" and "·" take 2 columns, which is
- // forbidden (TUI limitation?). Set old defaults.
- fcs_tab[2].def = '|';
- fcs_tab[6].def = '|';
- fcs_tab[3].def = '-';
- } else {
- fcs_tab[2].def = 9474; // │
- fcs_tab[6].def = 9474; // │
- fcs_tab[3].def = 183; // ·
+ // XXX: If ambiwidth=double then some characters take 2 columns,
+ // which is forbidden (TUI limitation?). Set old defaults.
+ fcs_tab[2].def = '-';
+ fcs_tab[3].def = '-';
+ fcs_tab[4].def = '-';
+ fcs_tab[5].def = '|';
+ fcs_tab[6].def = '|';
+ fcs_tab[7].def = '|';
+ fcs_tab[8].def = '+';
+ fcs_tab[9].def = '-';
+ fcs_tab[12].def = '|';
}
}
@@ -3845,7 +3854,7 @@ static bool parse_winhl_opt(win_T *wp)
size_t nlen = (size_t)(colon-p);
char *hi = colon+1;
char *commap = xstrchrnul(hi, ',');
- int len = (int)(commap-hi);
+ size_t len = (size_t)(commap-hi);
int hl_id = len ? syn_check_group(hi, len) : -1;
if (strncmp("Normal", p, nlen) == 0) {
@@ -4475,6 +4484,20 @@ static char *set_num_option(int opt_idx, char_u *varp, long value, char *errbuf,
// 'winminwidth'
win_setminwidth();
} else if (pp == &p_ls) {
+ // When switching to global statusline, decrease topframe height
+ // Also clear the cmdline to remove the ruler if there is one
+ if (value == 3 && old_value != 3) {
+ frame_new_height(topframe, topframe->fr_height - STATUS_HEIGHT, false, false);
+ (void)win_comp_pos();
+ clear_cmdline = true;
+ }
+ // When switching from global statusline, increase height of topframe by STATUS_HEIGHT
+ // in order to to re-add the space that was previously taken by the global statusline
+ if (old_value == 3 && value != 3) {
+ frame_new_height(topframe, topframe->fr_height + STATUS_HEIGHT, false, false);
+ (void)win_comp_pos();
+ }
+
last_status(false); // (re)set last window status line.
} else if (pp == &p_stal) {
// (re)set tab page line
@@ -5646,7 +5669,7 @@ static int put_setbool(FILE *fd, char *cmd, char *name, int value)
void comp_col(void)
{
- int last_has_status = (p_ls == 2 || (p_ls == 1 && !ONE_WINDOW));
+ int last_has_status = (p_ls > 1 || (p_ls == 1 && !ONE_WINDOW));
sc_col = 0;
ru_col = 0;
diff --git a/src/nvim/os/pty_process_unix.c b/src/nvim/os/pty_process_unix.c
index 58cb1b8f84..4a49c0b162 100644
--- a/src/nvim/os/pty_process_unix.c
+++ b/src/nvim/os/pty_process_unix.c
@@ -86,7 +86,7 @@ static int openpty(int *amaster, int *aslave, char *name, struct termios *termp,
ioctl(slave, I_PUSH, "ptem");
// ldterm provides most of the termio terminal interface
ioctl(slave, I_PUSH, "ldterm");
- // ttcompat compatability with older terminal ioctls
+ // ttcompat compatibility with older terminal ioctls
ioctl(slave, I_PUSH, "ttcompat");
if (termp) {
diff --git a/src/nvim/os/pty_process_win.c b/src/nvim/os/pty_process_win.c
index ed9f4636e3..4fb9e30a96 100644
--- a/src/nvim/os/pty_process_win.c
+++ b/src/nvim/os/pty_process_win.c
@@ -307,7 +307,7 @@ static void pty_process_finish2(PtyProcess *ptyproc)
/// Build the command line to pass to CreateProcessW.
///
/// @param[in] argv Array with string arguments.
-/// @param[out] cmd_line Location where saved builded cmd line.
+/// @param[out] cmd_line Location where saved built cmd line.
///
/// @returns zero on success, or error code of MultiByteToWideChar function.
///
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index 72fd035cbd..d868fe8284 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -22,6 +22,7 @@
#include "nvim/ex_getln.h"
#include "nvim/fileio.h"
#include "nvim/fold.h"
+#include "nvim/highlight_group.h"
#include "nvim/mark.h"
#include "nvim/mbyte.h"
#include "nvim/memline.h"
@@ -39,7 +40,6 @@
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/strings.h"
-#include "nvim/syntax.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
#include "nvim/window.h"
@@ -3635,7 +3635,7 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz, bool vertsp
win_setwidth(sz);
}
} else if (sz != win->w_height
- && (win->w_height + win->w_status_height + tabline_height()
+ && (win->w_height + win->w_hsep_height + win->w_status_height + tabline_height()
< cmdline_row)) {
win_setheight(sz);
}
diff --git a/src/nvim/screen.c b/src/nvim/screen.c
index ac07e60632..60de4e479e 100644
--- a/src/nvim/screen.c
+++ b/src/nvim/screen.c
@@ -88,6 +88,7 @@
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/indent.h"
#include "nvim/lib/kvec.h"
#include "nvim/log.h"
@@ -286,7 +287,8 @@ void update_curbuf(int type)
void redraw_buf_status_later(buf_T *buf)
{
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_buffer == buf && wp->w_status_height) {
+ if (wp->w_buffer == buf
+ && (wp->w_status_height || (wp == curwin && global_stl_height()))) {
wp->w_redr_status = true;
if (must_redraw < VALID) {
must_redraw = VALID;
@@ -316,6 +318,7 @@ void redraw_win_signcol(win_T *wp)
int update_screen(int type)
{
static bool did_intro = false;
+ bool is_stl_global = global_stl_height() > 0;
// Don't do anything if the screen structures are (not yet) valid.
// A VimResized autocmd can invoke redrawing in the middle of a resize,
@@ -398,10 +401,13 @@ int update_screen(int type)
if (W_ENDROW(wp) > valid) {
wp->w_redr_type = MAX(wp->w_redr_type, NOT_VALID);
}
- if (W_ENDROW(wp) + wp->w_status_height > valid) {
+ if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height > valid) {
wp->w_redr_status = true;
}
}
+ if (is_stl_global && Rows - p_ch - 1 > valid) {
+ curwin->w_redr_status = true;
+ }
}
msg_grid_set_pos(Rows-p_ch, false);
msg_grid_invalid = false;
@@ -423,13 +429,15 @@ int update_screen(int type)
wp->w_redr_type = REDRAW_TOP;
} else {
wp->w_redr_type = NOT_VALID;
- if (W_ENDROW(wp) + wp->w_status_height
- <= msg_scrolled) {
- wp->w_redr_status = TRUE;
+ if (!is_stl_global && W_ENDROW(wp) + wp->w_status_height <= msg_scrolled) {
+ wp->w_redr_status = true;
}
}
}
}
+ if (is_stl_global && Rows - p_ch - 1 <= msg_scrolled) {
+ curwin->w_redr_status = true;
+ }
redraw_cmdline = true;
redraw_tabline = true;
}
@@ -740,8 +748,11 @@ static void win_update(win_T *wp, DecorProviders *providers)
wp->w_lines_valid = 0;
}
- // Window is zero-height: nothing to draw.
+ // Window is zero-height: Only need to draw the separator
if (wp->w_grid.Rows == 0) {
+ // draw the horizontal separator below this window
+ draw_hsep_win(wp);
+ draw_sep_connectors_win(wp);
wp->w_redr_type = 0;
return;
}
@@ -749,7 +760,8 @@ static void win_update(win_T *wp, DecorProviders *providers)
// Window is zero-width: Only need to draw the separator.
if (wp->w_grid.Columns == 0) {
// draw the vertical separator right of this window
- draw_vsep_win(wp, 0);
+ draw_vsep_win(wp);
+ draw_sep_connectors_win(wp);
wp->w_redr_type = 0;
return;
}
@@ -1664,7 +1676,9 @@ static void win_update(win_T *wp, DecorProviders *providers)
kvi_destroy(line_providers);
if (wp->w_redr_type >= REDRAW_TOP) {
- draw_vsep_win(wp, 0);
+ draw_vsep_win(wp);
+ draw_hsep_win(wp);
+ draw_sep_connectors_win(wp);
}
syn_set_timeout(NULL);
@@ -2609,9 +2623,6 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
}
next_search_hl(wp, shl, lnum, (colnr_T)v,
shl == &search_hl ? NULL : cur);
- if (wp->w_s->b_syn_slow) {
- has_syntax = false;
- }
// Need to get the line again, a multi-line regexp may have made it
// invalid.
@@ -3369,6 +3380,10 @@ static int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, bool noc
did_emsg = save_did_emsg;
}
+ if (wp->w_s->b_syn_slow) {
+ has_syntax = false;
+ }
+
// Need to get the line again, a multi-line regexp may
// have made it invalid.
line = ml_get_buf(wp->w_buffer, lnum, false);
@@ -4881,10 +4896,15 @@ void rl_mirror(char_u *str)
*/
void status_redraw_all(void)
{
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_status_height) {
- wp->w_redr_status = true;
- redraw_later(wp, VALID);
+ if (global_stl_height()) {
+ curwin->w_redr_status = true;
+ redraw_later(curwin, VALID);
+ } else {
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_status_height) {
+ wp->w_redr_status = true;
+ redraw_later(wp, VALID);
+ }
}
}
}
@@ -4898,10 +4918,15 @@ void status_redraw_curbuf(void)
/// Marks all status lines of the specified buffer for redraw.
void status_redraw_buf(buf_T *buf)
{
- FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
- if (wp->w_status_height != 0 && wp->w_buffer == buf) {
- wp->w_redr_status = true;
- redraw_later(wp, VALID);
+ if (global_stl_height() != 0 && curwin->w_buffer == buf) {
+ curwin->w_redr_status = true;
+ redraw_later(curwin, VALID);
+ } else {
+ FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
+ if (wp->w_status_height != 0 && wp->w_buffer == buf) {
+ wp->w_redr_status = true;
+ redraw_later(wp, VALID);
+ }
}
}
}
@@ -4943,10 +4968,8 @@ void win_redraw_last_status(const frame_T *frp)
}
}
-/*
- * Draw the verticap separator right of window "wp" starting with line "row".
- */
-static void draw_vsep_win(win_T *wp, int row)
+/// Draw the vertical separator right of window "wp"
+static void draw_vsep_win(win_T *wp)
{
int hl;
int c;
@@ -4954,15 +4977,97 @@ static void draw_vsep_win(win_T *wp, int row)
if (wp->w_vsep_width) {
// draw the vertical separator right of this window
c = fillchar_vsep(wp, &hl);
- grid_fill(&default_grid, wp->w_winrow + row, W_ENDROW(wp),
+ grid_fill(&default_grid, wp->w_winrow, W_ENDROW(wp),
W_ENDCOL(wp), W_ENDCOL(wp) + 1, c, ' ', hl);
}
}
+/// Draw the horizontal separator below window "wp"
+static void draw_hsep_win(win_T *wp)
+{
+ int hl;
+ int c;
-/*
- * Get the length of an item as it will be shown in the status line.
- */
+ if (wp->w_hsep_height) {
+ // draw the horizontal separator below this window
+ c = fillchar_hsep(wp, &hl);
+ grid_fill(&default_grid, W_ENDROW(wp), W_ENDROW(wp) + 1,
+ wp->w_wincol, W_ENDCOL(wp), c, c, hl);
+ }
+}
+
+/// Get the separator connector for specified window corner of window "wp"
+static int get_corner_sep_connector(win_T *wp, WindowCorner corner)
+{
+ // It's impossible for windows to be connected neither vertically nor horizontally
+ // So if they're not vertically connected, assume they're horizontally connected
+ if (vsep_connected(wp, corner)) {
+ if (hsep_connected(wp, corner)) {
+ return wp->w_p_fcs_chars.verthoriz;
+ } else if (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) {
+ return wp->w_p_fcs_chars.vertright;
+ } else {
+ return wp->w_p_fcs_chars.vertleft;
+ }
+ } else if (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) {
+ return wp->w_p_fcs_chars.horizdown;
+ } else {
+ return wp->w_p_fcs_chars.horizup;
+ }
+}
+
+/// Draw seperator connecting characters on the corners of window "wp"
+static void draw_sep_connectors_win(win_T *wp)
+{
+ // Don't draw separator connectors unless global statusline is enabled and the window has
+ // either a horizontal or vertical separator
+ if (global_stl_height() == 0 || !(wp->w_hsep_height == 1 || wp->w_vsep_width == 1)) {
+ return;
+ }
+
+ int hl = win_hl_attr(wp, HLF_C);
+
+ // Determine which edges of the screen the window is located on so we can avoid drawing separators
+ // on corners contained in those edges
+ bool win_at_top;
+ bool win_at_bottom = wp->w_hsep_height == 0;
+ bool win_at_left;
+ bool win_at_right = wp->w_vsep_width == 0;
+ frame_T *frp;
+
+ for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) {
+ if (frp->fr_parent->fr_layout == FR_COL && frp->fr_prev != NULL) {
+ break;
+ }
+ }
+ win_at_top = frp->fr_parent == NULL;
+ for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) {
+ if (frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL) {
+ break;
+ }
+ }
+ win_at_left = frp->fr_parent == NULL;
+
+ // Draw the appropriate separator connector in every corner where drawing them is necessary
+ if (!(win_at_top || win_at_left)) {
+ grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_TOP_LEFT),
+ wp->w_winrow - 1, wp->w_wincol - 1, hl);
+ }
+ if (!(win_at_top || win_at_right)) {
+ grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_TOP_RIGHT),
+ wp->w_winrow - 1, W_ENDCOL(wp), hl);
+ }
+ if (!(win_at_bottom || win_at_left)) {
+ grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_BOTTOM_LEFT),
+ W_ENDROW(wp), wp->w_wincol - 1, hl);
+ }
+ if (!(win_at_bottom || win_at_right)) {
+ grid_putchar(&default_grid, get_corner_sep_connector(wp, WC_BOTTOM_RIGHT),
+ W_ENDROW(wp), W_ENDCOL(wp), hl);
+ }
+}
+
+/// Get the length of an item as it will be shown in the status line.
static int status_match_len(expand_T *xp, char_u *s)
{
int len = 0;
@@ -5163,7 +5268,7 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
// Create status line if needed by setting 'laststatus' to 2.
// Set 'winminheight' to zero to avoid that the window is
// resized.
- if (lastwin->w_status_height == 0) {
+ if (lastwin->w_status_height == 0 && global_stl_height() == 0) {
save_p_ls = p_ls;
save_p_wmh = p_wmh;
p_ls = 2;
@@ -5199,12 +5304,15 @@ void win_redr_status_matches(expand_T *xp, int num_matches, char_u **matches, in
static void win_redr_status(win_T *wp)
{
int row;
+ int col;
char_u *p;
int len;
int fillchar;
int attr;
+ int width;
int this_ru_col;
- static int busy = FALSE;
+ bool is_stl_global = global_stl_height() > 0;
+ static int busy = false;
// May get here recursively when 'statusline' (indirectly)
// invokes ":redrawstatus". Simply ignore the call then.
@@ -5215,9 +5323,9 @@ static void win_redr_status(win_T *wp)
}
busy = true;
- wp->w_redr_status = FALSE;
- if (wp->w_status_height == 0) {
- // no status line, can only be last window
+ wp->w_redr_status = false;
+ if (wp->w_status_height == 0 && !(is_stl_global && wp == curwin)) {
+ // no status line, either global statusline is enabled or the window is a last window
redraw_cmdline = true;
} else if (!redrawing()) {
// Don't redraw right now, do it later. Don't update status line when
@@ -5228,6 +5336,7 @@ static void win_redr_status(win_T *wp)
redraw_custom_statusline(wp);
} else {
fillchar = fillchar_status(&attr, wp);
+ width = is_stl_global ? Columns : wp->w_width;
get_trans_bufname(wp->w_buffer);
p = NameBuff;
@@ -5256,9 +5365,9 @@ static void win_redr_status(win_T *wp)
// len += (int)STRLEN(p + len); // dead assignment
}
- this_ru_col = ru_col - (Columns - wp->w_width);
- if (this_ru_col < (wp->w_width + 1) / 2) {
- this_ru_col = (wp->w_width + 1) / 2;
+ this_ru_col = ru_col - (Columns - width);
+ if (this_ru_col < (width + 1) / 2) {
+ this_ru_col = (width + 1) / 2;
}
if (this_ru_col <= 1) {
p = (char_u *)"<"; // No room for file name!
@@ -5283,10 +5392,11 @@ static void win_redr_status(win_T *wp)
}
}
- row = W_ENDROW(wp);
- grid_puts(&default_grid, p, row, wp->w_wincol, attr);
- grid_fill(&default_grid, row, row + 1, len + wp->w_wincol,
- this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
+ row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
+ col = is_stl_global ? 0 : wp->w_wincol;
+ grid_puts(&default_grid, p, row, col, attr);
+ grid_fill(&default_grid, row, row + 1, len + col,
+ this_ru_col + col, fillchar, fillchar, attr);
if (get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)
&& this_ru_col - len > (int)(STRLEN(NameBuff) + 1)) {
@@ -5365,6 +5475,76 @@ bool stl_connected(win_T *wp)
return false;
}
+/// Check if horizontal separator of window "wp" at specified window corner is connected to the
+/// horizontal separator of another window
+/// Assumes global statusline is enabled
+static bool hsep_connected(win_T *wp, WindowCorner corner)
+{
+ bool before = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT);
+ int sep_row = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT)
+ ? wp->w_winrow - 1 : W_ENDROW(wp);
+ frame_T *fr = wp->w_frame;
+
+ while (fr->fr_parent != NULL) {
+ if (fr->fr_parent->fr_layout == FR_ROW && (before ? fr->fr_prev : fr->fr_next) != NULL) {
+ fr = before ? fr->fr_prev : fr->fr_next;
+ break;
+ }
+ fr = fr->fr_parent;
+ }
+ if (fr->fr_parent == NULL) {
+ return false;
+ }
+ while (fr->fr_layout != FR_LEAF) {
+ fr = fr->fr_child;
+ if (fr->fr_parent->fr_layout == FR_ROW && before) {
+ while (fr->fr_next != NULL) {
+ fr = fr->fr_next;
+ }
+ } else {
+ while (fr->fr_next != NULL && frame2win(fr)->w_winrow + fr->fr_height < sep_row) {
+ fr = fr->fr_next;
+ }
+ }
+ }
+
+ return (sep_row == fr->fr_win->w_winrow - 1 || sep_row == W_ENDROW(fr->fr_win));
+}
+
+/// Check if vertical separator of window "wp" at specified window corner is connected to the
+/// vertical separator of another window
+static bool vsep_connected(win_T *wp, WindowCorner corner)
+{
+ bool before = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT);
+ int sep_col = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT)
+ ? wp->w_wincol - 1 : W_ENDCOL(wp);
+ frame_T *fr = wp->w_frame;
+
+ while (fr->fr_parent != NULL) {
+ if (fr->fr_parent->fr_layout == FR_COL && (before ? fr->fr_prev : fr->fr_next) != NULL) {
+ fr = before ? fr->fr_prev : fr->fr_next;
+ break;
+ }
+ fr = fr->fr_parent;
+ }
+ if (fr->fr_parent == NULL) {
+ return false;
+ }
+ while (fr->fr_layout != FR_LEAF) {
+ fr = fr->fr_child;
+ if (fr->fr_parent->fr_layout == FR_COL && before) {
+ while (fr->fr_next != NULL) {
+ fr = fr->fr_next;
+ }
+ } else {
+ while (fr->fr_next != NULL && frame2win(fr)->w_wincol + fr->fr_width < sep_col) {
+ fr = fr->fr_next;
+ }
+ }
+ }
+
+ return (sep_col == fr->fr_win->w_wincol - 1 || sep_col == W_ENDCOL(fr->fr_win));
+}
/// Get the value to show for the language mappings, active 'keymap'.
///
@@ -5431,6 +5611,7 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
int use_sandbox = false;
win_T *ewp;
int p_crb_save;
+ bool is_stl_global = global_stl_height() > 0;
ScreenGrid *grid = &default_grid;
@@ -5452,9 +5633,9 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
maxwidth = Columns;
use_sandbox = was_set_insecurely(wp, "tabline", 0);
} else {
- row = W_ENDROW(wp);
+ row = is_stl_global ? (Rows - p_ch - 1) : W_ENDROW(wp);
fillchar = fillchar_status(&attr, wp);
- maxwidth = wp->w_width;
+ maxwidth = is_stl_global ? Columns : wp->w_width;
if (draw_ruler) {
stl = p_ruf;
@@ -5472,12 +5653,12 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
stl = p_ruf;
}
}
- col = ru_col - (Columns - wp->w_width);
- if (col < (wp->w_width + 1) / 2) {
- col = (wp->w_width + 1) / 2;
+ col = ru_col - (Columns - maxwidth);
+ if (col < (maxwidth + 1) / 2) {
+ col = (maxwidth + 1) / 2;
}
- maxwidth = wp->w_width - col;
- if (!wp->w_status_height) {
+ maxwidth = maxwidth - col;
+ if (!wp->w_status_height && !is_stl_global) {
grid = &msg_grid_adj;
row = Rows - 1;
maxwidth--; // writing in last column may cause scrolling
@@ -5495,7 +5676,7 @@ static void win_redr_custom(win_T *wp, bool draw_ruler)
use_sandbox = was_set_insecurely(wp, "statusline", *wp->w_p_stl == NUL ? 0 : OPT_LOCAL);
}
- col += wp->w_wincol;
+ col += is_stl_global ? 0 : wp->w_wincol;
}
if (maxwidth <= 0) {
@@ -7077,10 +7258,10 @@ int showmode(void)
clear_showcmd();
}
- // If the last window has no status line, the ruler is after the mode
- // message and must be redrawn
+ // If the last window has no status line and global statusline is disabled,
+ // the ruler is after the mode message and must be redrawn
win_T *last = lastwin_nofloating();
- if (redrawing() && last->w_status_height == 0) {
+ if (redrawing() && last->w_status_height == 0 && global_stl_height() == 0) {
win_redr_ruler(last, true);
}
redraw_cmdline = false;
@@ -7395,16 +7576,22 @@ int fillchar_status(int *attr, win_T *wp)
return '=';
}
-/*
- * Get the character to use in a separator between vertically split windows.
- * Get its attributes in "*attr".
- */
+/// Get the character to use in a separator between vertically split windows.
+/// Get its attributes in "*attr".
static int fillchar_vsep(win_T *wp, int *attr)
{
*attr = win_hl_attr(wp, HLF_C);
return wp->w_p_fcs_chars.vert;
}
+/// Get the character to use in a separator between horizontally split windows.
+/// Get its attributes in "*attr".
+static int fillchar_hsep(win_T *wp, int *attr)
+{
+ *attr = win_hl_attr(wp, HLF_C);
+ return wp->w_p_fcs_chars.horiz;
+}
+
/*
* Return TRUE if redrawing should currently be done.
*/
@@ -7430,7 +7617,8 @@ void showruler(bool always)
if (!always && !redrawing()) {
return;
}
- if ((*p_stl != NUL || *curwin->w_p_stl != NUL) && curwin->w_status_height) {
+ if ((*p_stl != NUL || *curwin->w_p_stl != NUL)
+ && (curwin->w_status_height || global_stl_height())) {
redraw_custom_statusline(curwin);
} else {
win_redr_ruler(curwin, always);
@@ -7449,6 +7637,7 @@ void showruler(bool always)
static void win_redr_ruler(win_T *wp, bool always)
{
+ bool is_stl_global = global_stl_height() > 0;
static bool did_show_ext_ruler = false;
// If 'ruler' off or redrawing disabled, don't do anything
@@ -7466,7 +7655,7 @@ static void win_redr_ruler(win_T *wp, bool always)
// Don't draw the ruler while doing insert-completion, it might overwrite
// the (long) mode message.
- if (wp == lastwin && lastwin->w_status_height == 0) {
+ if (wp == lastwin && lastwin->w_status_height == 0 && !is_stl_global) {
if (edit_submode != NULL) {
return;
}
@@ -7521,6 +7710,12 @@ static void win_redr_ruler(win_T *wp, bool always)
off = wp->w_wincol;
width = wp->w_width;
part_of_status = true;
+ } else if (is_stl_global) {
+ row = Rows - p_ch - 1;
+ fillchar = fillchar_status(&attr, wp);
+ off = 0;
+ width = Columns;
+ part_of_status = true;
} else {
row = Rows - 1;
fillchar = ' ';
@@ -7560,7 +7755,7 @@ static void win_redr_ruler(win_T *wp, bool always)
int i = (int)STRLEN(buffer);
get_rel_pos(wp, buffer + i + 1, RULER_BUF_LEN - i - 1);
int o = i + vim_strsize(buffer + i + 1);
- if (wp->w_status_height == 0) { // can't use last char of screen
+ if (wp->w_status_height == 0 && !is_stl_global) { // can't use last char of screen
o++;
}
int this_ru_col = ru_col - (Columns - width);
diff --git a/src/nvim/screen.h b/src/nvim/screen.h
index 9e8a034d93..d15e4b7e45 100644
--- a/src/nvim/screen.h
+++ b/src/nvim/screen.h
@@ -19,6 +19,14 @@
#define NOT_VALID 40 // buffer needs complete redraw
#define CLEAR 50 // screen messed up, clear it
+/// corner value flags for hsep_connected and vsep_connected
+typedef enum {
+ WC_TOP_LEFT = 0,
+ WC_TOP_RIGHT,
+ WC_BOTTOM_LEFT,
+ WC_BOTTOM_RIGHT
+} WindowCorner;
+
/// By default, all widows are draw on a single rectangular grid, represented by
/// this ScreenGrid instance. In multigrid mode each window will have its own
/// grid, then this is only used for global screen elements that hasn't been
diff --git a/src/nvim/search.c b/src/nvim/search.c
index cc7c2ecf06..a69bd641f8 100644
--- a/src/nvim/search.c
+++ b/src/nvim/search.c
@@ -5689,7 +5689,7 @@ search_line:
// we read a line, set "already" to check this "line" later
// if depth >= 0 we'll increase files[depth].lnum far
- // bellow -- Acevedo
+ // below -- Acevedo
already = aux = p = skipwhite(line);
p = find_word_start(p);
p = find_word_end(p);
diff --git a/src/nvim/sign.c b/src/nvim/sign.c
index 6d0ac30003..50400852b8 100644
--- a/src/nvim/sign.c
+++ b/src/nvim/sign.c
@@ -13,6 +13,7 @@
#include "nvim/edit.h"
#include "nvim/ex_docmd.h"
#include "nvim/fold.h"
+#include "nvim/highlight_group.h"
#include "nvim/move.h"
#include "nvim/option.h"
#include "nvim/screen.h"
@@ -954,7 +955,7 @@ int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text
if (*linehl == NUL) {
sp->sn_line_hl = 0;
} else {
- sp->sn_line_hl = syn_check_group((char *)linehl, (int)STRLEN(linehl));
+ sp->sn_line_hl = syn_check_group((char *)linehl, STRLEN(linehl));
}
}
@@ -962,7 +963,7 @@ int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text
if (*texthl == NUL) {
sp->sn_text_hl = 0;
} else {
- sp->sn_text_hl = syn_check_group((char *)texthl, (int)STRLEN(texthl));
+ sp->sn_text_hl = syn_check_group((char *)texthl, STRLEN(texthl));
}
}
@@ -970,7 +971,7 @@ int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text
if (*culhl == NUL) {
sp->sn_cul_hl = 0;
} else {
- sp->sn_cul_hl = syn_check_group((char *)culhl, (int)STRLEN(culhl));
+ sp->sn_cul_hl = syn_check_group((char *)culhl, STRLEN(culhl));
}
}
@@ -978,7 +979,7 @@ int sign_define_by_name(char_u *name, char_u *icon, char_u *linehl, char_u *text
if (*numhl == NUL) {
sp->sn_num_hl = 0;
} else {
- sp->sn_num_hl = syn_check_group(numhl, (int)STRLEN(numhl));
+ sp->sn_num_hl = syn_check_group(numhl, STRLEN(numhl));
}
}
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index 54fce3d968..f829b6a270 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -25,6 +25,7 @@
#include "nvim/garray.h"
#include "nvim/hashtab.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/indent_c.h"
#include "nvim/keymap.h"
#include "nvim/lua/executor.h"
@@ -51,56 +52,6 @@
static bool did_syntax_onoff = false;
-/// Structure that stores information about a highlight group.
-/// The ID of a highlight group is also called group ID. It is the index in
-/// the highlight_ga array PLUS ONE.
-typedef struct hl_group {
- char_u *sg_name; ///< highlight group name
- char *sg_name_u; ///< uppercase of sg_name
- bool sg_cleared; ///< "hi clear" was used
- int sg_attr; ///< Screen attr @see ATTR_ENTRY
- int sg_link; ///< link to this highlight group ID
- int sg_deflink; ///< default link; restored in highlight_clear()
- int sg_set; ///< combination of flags in \ref SG_SET
- sctx_T sg_deflink_sctx; ///< script where the default link was set
- sctx_T sg_script_ctx; ///< script in which the group was last set
- // for terminal UIs
- int sg_cterm; ///< "cterm=" highlighting attr
- ///< (combination of \ref HlAttrFlags)
- int sg_cterm_fg; ///< terminal fg color number + 1
- int sg_cterm_bg; ///< terminal bg color number + 1
- bool sg_cterm_bold; ///< bold attr was set for light color
- // for RGB UIs
- int sg_gui; ///< "gui=" highlighting attributes
- ///< (combination of \ref HlAttrFlags)
- RgbValue sg_rgb_fg; ///< RGB foreground color
- RgbValue sg_rgb_bg; ///< RGB background color
- RgbValue sg_rgb_sp; ///< RGB special color
- char *sg_rgb_fg_name; ///< RGB foreground color name
- char *sg_rgb_bg_name; ///< RGB background color name
- char *sg_rgb_sp_name; ///< RGB special color name
-
- int sg_blend; ///< blend level (0-100 inclusive), -1 if unset
-} HlGroup;
-
-/// \addtogroup SG_SET
-/// @{
-#define SG_CTERM 2 // cterm has been set
-#define SG_GUI 4 // gui has been set
-#define SG_LINK 8 // link has been set
-/// @}
-
-// builtin |highlight-groups|
-static garray_T highlight_ga = GA_EMPTY_INIT_VALUE;
-Map(cstr_t, int) highlight_unames = MAP_INIT;
-
-static inline struct hl_group *HL_TABLE(void)
-{
- return ((struct hl_group *)((highlight_ga.ga_data)));
-}
-
-#define MAX_HL_ID 20000 // maximum value for a highlight ID.
-
// different types of offsets that are possible
#define SPO_MS_OFF 0 // match start offset
#define SPO_ME_OFF 1 // match end offset
@@ -111,22 +62,6 @@ static inline struct hl_group *HL_TABLE(void)
#define SPO_LC_OFF 6 // leading context offset
#define SPO_COUNT 7
-// Flags to indicate an additional string for highlight name completion.
-static int include_none = 0; // when 1 include "nvim/None"
-static int include_default = 0; // when 1 include "nvim/default"
-static int include_link = 0; // when 2 include "nvim/link" and "clear"
-
-#define MAX_SYN_NAME 200
-
-/// The "term", "cterm" and "gui" arguments can be any combination of the
-/// following names, separated by commas (but no spaces!).
-static char *(hl_name_table[]) =
-{ "bold", "standout", "underline", "underlineline", "undercurl", "underdot",
- "underdash", "italic", "reverse", "inverse", "strikethrough", "nocombine", "NONE" };
-static int hl_attr_table[] =
-{ HL_BOLD, HL_STANDOUT, HL_UNDERLINE, HL_UNDERLINELINE, HL_UNDERCURL, HL_UNDERDOT, HL_UNDERDASH,
- HL_ITALIC, HL_INVERSE, HL_INVERSE, HL_STRIKETHROUGH, HL_NOCOMBINE, 0 };
-
static char e_illegal_arg[] = N_("E390: Illegal argument: %s");
// The patterns that are being searched for are stored in a syn_pattern.
@@ -3609,7 +3544,7 @@ static void syn_cmd_list(exarg_T *eap, int syncing)
/*
* No argument: List all group IDs and all syntax clusters.
*/
- for (int id = 1; id <= highlight_ga.ga_len && !got_int; id++) {
+ for (int id = 1; id <= highlight_num_groups() && !got_int; id++) {
syn_list_one(id, syncing, false);
}
for (int id = 0; id < curwin->w_s->b_syn_clusters.ga_len && !got_int; ++id) {
@@ -3767,8 +3702,8 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only)
}
msg_putchar(' ');
if (spp->sp_sync_idx >= 0) {
- msg_outtrans(HL_TABLE()[SYN_ITEMS(curwin->w_s)
- [spp->sp_sync_idx].sp_syn.id - 1].sg_name);
+ msg_outtrans(highlight_group_name(SYN_ITEMS(curwin->w_s)
+ [spp->sp_sync_idx].sp_syn.id - 1));
} else {
msg_puts("NONE");
}
@@ -3777,11 +3712,11 @@ static void syn_list_one(const int id, const bool syncing, const bool link_only)
}
// list the link, if there is one
- if (HL_TABLE()[id - 1].sg_link && (did_header || link_only) && !got_int) {
+ if (highlight_link_id(id - 1) && (did_header || link_only) && !got_int) {
(void)syn_list_header(did_header, 0, id, true);
msg_puts_attr("links to", attr);
msg_putchar(' ');
- msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
+ msg_outtrans(highlight_group_name(highlight_link_id(id - 1) - 1));
}
}
@@ -3845,7 +3780,7 @@ static void put_id_list(const char *const name, const int16_t *const list, const
msg_putchar('@');
msg_outtrans(SYN_CLSTR(curwin->w_s)[scl_id].scl_name);
} else {
- msg_outtrans(HL_TABLE()[*p - 1].sg_name);
+ msg_outtrans(highlight_group_name(*p - 1));
}
if (p[1]) {
msg_putchar(',');
@@ -3867,7 +3802,7 @@ static void put_pattern(const char *const s, const int c, const synpat_T *const
if (last_matchgroup == 0) {
msg_outtrans((char_u *)"NONE");
} else {
- msg_outtrans(HL_TABLE()[last_matchgroup - 1].sg_name);
+ msg_outtrans(highlight_group_name(last_matchgroup - 1));
}
msg_putchar(' ');
}
@@ -5459,8 +5394,8 @@ static int get_id_list(char_u **const arg, const int keylen, int16_t **const lis
regmatch.rm_ic = TRUE;
id = 0;
- for (int i = highlight_ga.ga_len; --i >= 0;) {
- if (vim_regexec(&regmatch, HL_TABLE()[i].sg_name, (colnr_T)0)) {
+ for (int i = highlight_num_groups(); --i >= 0;) {
+ if (vim_regexec(&regmatch, highlight_group_name(i), (colnr_T)0)) {
if (round == 2) {
// Got more items than expected; can happen
// when adding items that match:
@@ -6121,7 +6056,7 @@ static void syntime_report(void)
msg_puts(profile_msg(p->average));
msg_puts(" ");
msg_advance(50);
- msg_outtrans(HL_TABLE()[p->id - 1].sg_name);
+ msg_outtrans(highlight_group_name(p->id - 1));
msg_puts(" ");
msg_advance(69);
@@ -6146,2740 +6081,3 @@ static void syntime_report(void)
msg_puts("\n");
}
}
-
-/**************************************
-* Highlighting stuff *
-**************************************/
-
-// The default highlight groups. These are compiled-in for fast startup and
-// they still work when the runtime files can't be found.
-//
-// When making changes here, also change runtime/colors/default.vim!
-
-static const char *highlight_init_both[] = {
- "Conceal ctermbg=DarkGrey ctermfg=LightGrey guibg=DarkGrey guifg=LightGrey",
- "Cursor guibg=fg guifg=bg",
- "lCursor guibg=fg guifg=bg",
- "DiffText cterm=bold ctermbg=Red gui=bold guibg=Red",
- "ErrorMsg ctermbg=DarkRed ctermfg=White guibg=Red guifg=White",
- "IncSearch cterm=reverse gui=reverse",
- "ModeMsg cterm=bold gui=bold",
- "NonText ctermfg=Blue gui=bold guifg=Blue",
- "Normal cterm=NONE gui=NONE",
- "PmenuSbar ctermbg=Grey guibg=Grey",
- "StatusLine cterm=reverse,bold gui=reverse,bold",
- "StatusLineNC cterm=reverse gui=reverse",
- "TabLineFill cterm=reverse gui=reverse",
- "TabLineSel cterm=bold gui=bold",
- "TermCursor cterm=reverse gui=reverse",
- "VertSplit cterm=reverse gui=reverse",
- "WildMenu ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
- "default link EndOfBuffer NonText",
- "default link LineNrAbove LineNr",
- "default link LineNrBelow LineNr",
- "default link QuickFixLine Search",
- "default link CursorLineSign SignColumn",
- "default link CursorLineFold FoldColumn",
- "default link Substitute Search",
- "default link Whitespace NonText",
- "default link MsgSeparator StatusLine",
- "default link NormalFloat Pmenu",
- "default link FloatBorder VertSplit",
- "default FloatShadow blend=80 guibg=Black",
- "default FloatShadowThrough blend=100 guibg=Black",
- "RedrawDebugNormal cterm=reverse gui=reverse",
- "RedrawDebugClear ctermbg=Yellow guibg=Yellow",
- "RedrawDebugComposed ctermbg=Green guibg=Green",
- "RedrawDebugRecompose ctermbg=Red guibg=Red",
- "Error term=reverse cterm=NONE ctermfg=White ctermbg=Red gui=NONE guifg=White guibg=Red",
- "Todo term=standout cterm=NONE ctermfg=Black ctermbg=Yellow gui=NONE guifg=Blue guibg=Yellow",
- "default link String Constant",
- "default link Character Constant",
- "default link Number Constant",
- "default link Boolean Constant",
- "default link Float Number",
- "default link Function Identifier",
- "default link Conditional Statement",
- "default link Repeat Statement",
- "default link Label Statement",
- "default link Operator Statement",
- "default link Keyword Statement",
- "default link Exception Statement",
- "default link Include PreProc",
- "default link Define PreProc",
- "default link Macro PreProc",
- "default link PreCondit PreProc",
- "default link StorageClass Type",
- "default link Structure Type",
- "default link Typedef Type",
- "default link Tag Special",
- "default link SpecialChar Special",
- "default link Delimiter Special",
- "default link SpecialComment Special",
- "default link Debug Special",
- "default DiagnosticError ctermfg=1 guifg=Red",
- "default DiagnosticWarn ctermfg=3 guifg=Orange",
- "default DiagnosticInfo ctermfg=4 guifg=LightBlue",
- "default DiagnosticHint ctermfg=7 guifg=LightGrey",
- "default DiagnosticUnderlineError cterm=underline gui=underline guisp=Red",
- "default DiagnosticUnderlineWarn cterm=underline gui=underline guisp=Orange",
- "default DiagnosticUnderlineInfo cterm=underline gui=underline guisp=LightBlue",
- "default DiagnosticUnderlineHint cterm=underline gui=underline guisp=LightGrey",
- "default link DiagnosticVirtualTextError DiagnosticError",
- "default link DiagnosticVirtualTextWarn DiagnosticWarn",
- "default link DiagnosticVirtualTextInfo DiagnosticInfo",
- "default link DiagnosticVirtualTextHint DiagnosticHint",
- "default link DiagnosticFloatingError DiagnosticError",
- "default link DiagnosticFloatingWarn DiagnosticWarn",
- "default link DiagnosticFloatingInfo DiagnosticInfo",
- "default link DiagnosticFloatingHint DiagnosticHint",
- "default link DiagnosticSignError DiagnosticError",
- "default link DiagnosticSignWarn DiagnosticWarn",
- "default link DiagnosticSignInfo DiagnosticInfo",
- "default link DiagnosticSignHint DiagnosticHint",
- NULL
-};
-
-// Default colors only used with a light background.
-static const char *highlight_init_light[] = {
- "ColorColumn ctermbg=LightRed guibg=LightRed",
- "CursorColumn ctermbg=LightGrey guibg=Grey90",
- "CursorLine cterm=underline guibg=Grey90",
- "CursorLineNr cterm=underline ctermfg=Brown gui=bold guifg=Brown",
- "DiffAdd ctermbg=LightBlue guibg=LightBlue",
- "DiffChange ctermbg=LightMagenta guibg=LightMagenta",
- "DiffDelete ctermfg=Blue ctermbg=LightCyan gui=bold guifg=Blue guibg=LightCyan",
- "Directory ctermfg=DarkBlue guifg=Blue",
- "FoldColumn ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue",
- "Folded ctermbg=Grey ctermfg=DarkBlue guibg=LightGrey guifg=DarkBlue",
- "LineNr ctermfg=Brown guifg=Brown",
- "MatchParen ctermbg=Cyan guibg=Cyan",
- "MoreMsg ctermfg=DarkGreen gui=bold guifg=SeaGreen",
- "Pmenu ctermbg=LightMagenta ctermfg=Black guibg=LightMagenta",
- "PmenuSel ctermbg=LightGrey ctermfg=Black guibg=Grey",
- "PmenuThumb ctermbg=Black guibg=Black",
- "Question ctermfg=DarkGreen gui=bold guifg=SeaGreen",
- "Search ctermbg=Yellow ctermfg=NONE guibg=Yellow guifg=NONE",
- "SignColumn ctermbg=Grey ctermfg=DarkBlue guibg=Grey guifg=DarkBlue",
- "SpecialKey ctermfg=DarkBlue guifg=Blue",
- "SpellBad ctermbg=LightRed guisp=Red gui=undercurl",
- "SpellCap ctermbg=LightBlue guisp=Blue gui=undercurl",
- "SpellLocal ctermbg=Cyan guisp=DarkCyan gui=undercurl",
- "SpellRare ctermbg=LightMagenta guisp=Magenta gui=undercurl",
- "TabLine cterm=underline ctermfg=black ctermbg=LightGrey gui=underline guibg=LightGrey",
- "Title ctermfg=DarkMagenta gui=bold guifg=Magenta",
- "Visual guibg=LightGrey",
- "WarningMsg ctermfg=DarkRed guifg=Red",
- "Comment term=bold cterm=NONE ctermfg=DarkBlue ctermbg=NONE gui=NONE guifg=Blue guibg=NONE",
- "Constant term=underline cterm=NONE ctermfg=DarkRed ctermbg=NONE gui=NONE guifg=Magenta guibg=NONE",
- "Special term=bold cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a5acd guibg=NONE",
- "Identifier term=underline cterm=NONE ctermfg=DarkCyan ctermbg=NONE gui=NONE guifg=DarkCyan guibg=NONE",
- "Statement term=bold cterm=NONE ctermfg=Brown ctermbg=NONE gui=bold guifg=Brown guibg=NONE",
- "PreProc term=underline cterm=NONE ctermfg=DarkMagenta ctermbg=NONE gui=NONE guifg=#6a0dad guibg=NONE",
- "Type term=underline cterm=NONE ctermfg=DarkGreen ctermbg=NONE gui=bold guifg=SeaGreen guibg=NONE",
- "Underlined term=underline cterm=underline ctermfg=DarkMagenta gui=underline guifg=SlateBlue",
- "Ignore term=NONE cterm=NONE ctermfg=white ctermbg=NONE gui=NONE guifg=bg guibg=NONE",
- NULL
-};
-
-// Default colors only used with a dark background.
-static const char *highlight_init_dark[] = {
- "ColorColumn ctermbg=DarkRed guibg=DarkRed",
- "CursorColumn ctermbg=DarkGrey guibg=Grey40",
- "CursorLine cterm=underline guibg=Grey40",
- "CursorLineNr cterm=underline ctermfg=Yellow gui=bold guifg=Yellow",
- "DiffAdd ctermbg=DarkBlue guibg=DarkBlue",
- "DiffChange ctermbg=DarkMagenta guibg=DarkMagenta",
- "DiffDelete ctermfg=Blue ctermbg=DarkCyan gui=bold guifg=Blue guibg=DarkCyan",
- "Directory ctermfg=LightCyan guifg=Cyan",
- "FoldColumn ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan",
- "Folded ctermbg=DarkGrey ctermfg=Cyan guibg=DarkGrey guifg=Cyan",
- "LineNr ctermfg=Yellow guifg=Yellow",
- "MatchParen ctermbg=DarkCyan guibg=DarkCyan",
- "MoreMsg ctermfg=LightGreen gui=bold guifg=SeaGreen",
- "Pmenu ctermbg=Magenta ctermfg=Black guibg=Magenta",
- "PmenuSel ctermbg=Black ctermfg=DarkGrey guibg=DarkGrey",
- "PmenuThumb ctermbg=White guibg=White",
- "Question ctermfg=LightGreen gui=bold guifg=Green",
- "Search ctermbg=Yellow ctermfg=Black guibg=Yellow guifg=Black",
- "SignColumn ctermbg=DarkGrey ctermfg=Cyan guibg=Grey guifg=Cyan",
- "SpecialKey ctermfg=LightBlue guifg=Cyan",
- "SpellBad ctermbg=Red guisp=Red gui=undercurl",
- "SpellCap ctermbg=Blue guisp=Blue gui=undercurl",
- "SpellLocal ctermbg=Cyan guisp=Cyan gui=undercurl",
- "SpellRare ctermbg=Magenta guisp=Magenta gui=undercurl",
- "TabLine cterm=underline ctermfg=white ctermbg=DarkGrey gui=underline guibg=DarkGrey",
- "Title ctermfg=LightMagenta gui=bold guifg=Magenta",
- "Visual guibg=DarkGrey",
- "WarningMsg ctermfg=LightRed guifg=Red",
- "Comment term=bold cterm=NONE ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#80a0ff guibg=NONE",
- "Constant term=underline cterm=NONE ctermfg=Magenta ctermbg=NONE gui=NONE guifg=#ffa0a0 guibg=NONE",
- "Special term=bold cterm=NONE ctermfg=LightRed ctermbg=NONE gui=NONE guifg=Orange guibg=NONE",
- "Identifier term=underline cterm=bold ctermfg=Cyan ctermbg=NONE gui=NONE guifg=#40ffff guibg=NONE",
- "Statement term=bold cterm=NONE ctermfg=Yellow ctermbg=NONE gui=bold guifg=#ffff60 guibg=NONE",
- "PreProc term=underline cterm=NONE ctermfg=LightBlue ctermbg=NONE gui=NONE guifg=#ff80ff guibg=NONE",
- "Type term=underline cterm=NONE ctermfg=LightGreen ctermbg=NONE gui=bold guifg=#60ff60 guibg=NONE",
- "Underlined term=underline cterm=underline ctermfg=LightBlue gui=underline guifg=#80a0ff",
- "Ignore term=NONE cterm=NONE ctermfg=black ctermbg=NONE gui=NONE guifg=bg guibg=NONE",
- NULL
-};
-
-const char *const highlight_init_cmdline[] = {
- // XXX When modifying a list modify it in both valid and invalid halves.
- // TODO(ZyX-I): merge valid and invalid groups via a macros.
-
- // NvimInternalError should appear only when highlighter has a bug.
- "NvimInternalError ctermfg=Red ctermbg=Red guifg=Red guibg=Red",
-
- // Highlight groups (links) used by parser:
-
- "default link NvimAssignment Operator",
- "default link NvimPlainAssignment NvimAssignment",
- "default link NvimAugmentedAssignment NvimAssignment",
- "default link NvimAssignmentWithAddition NvimAugmentedAssignment",
- "default link NvimAssignmentWithSubtraction NvimAugmentedAssignment",
- "default link NvimAssignmentWithConcatenation NvimAugmentedAssignment",
-
- "default link NvimOperator Operator",
-
- "default link NvimUnaryOperator NvimOperator",
- "default link NvimUnaryPlus NvimUnaryOperator",
- "default link NvimUnaryMinus NvimUnaryOperator",
- "default link NvimNot NvimUnaryOperator",
-
- "default link NvimBinaryOperator NvimOperator",
- "default link NvimComparison NvimBinaryOperator",
- "default link NvimComparisonModifier NvimComparison",
- "default link NvimBinaryPlus NvimBinaryOperator",
- "default link NvimBinaryMinus NvimBinaryOperator",
- "default link NvimConcat NvimBinaryOperator",
- "default link NvimConcatOrSubscript NvimConcat",
- "default link NvimOr NvimBinaryOperator",
- "default link NvimAnd NvimBinaryOperator",
- "default link NvimMultiplication NvimBinaryOperator",
- "default link NvimDivision NvimBinaryOperator",
- "default link NvimMod NvimBinaryOperator",
-
- "default link NvimTernary NvimOperator",
- "default link NvimTernaryColon NvimTernary",
-
- "default link NvimParenthesis Delimiter",
- "default link NvimLambda NvimParenthesis",
- "default link NvimNestingParenthesis NvimParenthesis",
- "default link NvimCallingParenthesis NvimParenthesis",
-
- "default link NvimSubscript NvimParenthesis",
- "default link NvimSubscriptBracket NvimSubscript",
- "default link NvimSubscriptColon NvimSubscript",
- "default link NvimCurly NvimSubscript",
-
- "default link NvimContainer NvimParenthesis",
- "default link NvimDict NvimContainer",
- "default link NvimList NvimContainer",
-
- "default link NvimIdentifier Identifier",
- "default link NvimIdentifierScope NvimIdentifier",
- "default link NvimIdentifierScopeDelimiter NvimIdentifier",
- "default link NvimIdentifierName NvimIdentifier",
- "default link NvimIdentifierKey NvimIdentifier",
-
- "default link NvimColon Delimiter",
- "default link NvimComma Delimiter",
- "default link NvimArrow Delimiter",
-
- "default link NvimRegister SpecialChar",
- "default link NvimNumber Number",
- "default link NvimFloat NvimNumber",
- "default link NvimNumberPrefix Type",
-
- "default link NvimOptionSigil Type",
- "default link NvimOptionName NvimIdentifier",
- "default link NvimOptionScope NvimIdentifierScope",
- "default link NvimOptionScopeDelimiter NvimIdentifierScopeDelimiter",
-
- "default link NvimEnvironmentSigil NvimOptionSigil",
- "default link NvimEnvironmentName NvimIdentifier",
-
- "default link NvimString String",
- "default link NvimStringBody NvimString",
- "default link NvimStringQuote NvimString",
- "default link NvimStringSpecial SpecialChar",
-
- "default link NvimSingleQuote NvimStringQuote",
- "default link NvimSingleQuotedBody NvimStringBody",
- "default link NvimSingleQuotedQuote NvimStringSpecial",
-
- "default link NvimDoubleQuote NvimStringQuote",
- "default link NvimDoubleQuotedBody NvimStringBody",
- "default link NvimDoubleQuotedEscape NvimStringSpecial",
-
- "default link NvimFigureBrace NvimInternalError",
- "default link NvimSingleQuotedUnknownEscape NvimInternalError",
-
- "default link NvimSpacing Normal",
-
- // NvimInvalid groups:
-
- "default link NvimInvalidSingleQuotedUnknownEscape NvimInternalError",
-
- "default link NvimInvalid Error",
-
- "default link NvimInvalidAssignment NvimInvalid",
- "default link NvimInvalidPlainAssignment NvimInvalidAssignment",
- "default link NvimInvalidAugmentedAssignment NvimInvalidAssignment",
- "default link NvimInvalidAssignmentWithAddition NvimInvalidAugmentedAssignment",
- "default link NvimInvalidAssignmentWithSubtraction NvimInvalidAugmentedAssignment",
- "default link NvimInvalidAssignmentWithConcatenation NvimInvalidAugmentedAssignment",
-
- "default link NvimInvalidOperator NvimInvalid",
-
- "default link NvimInvalidUnaryOperator NvimInvalidOperator",
- "default link NvimInvalidUnaryPlus NvimInvalidUnaryOperator",
- "default link NvimInvalidUnaryMinus NvimInvalidUnaryOperator",
- "default link NvimInvalidNot NvimInvalidUnaryOperator",
-
- "default link NvimInvalidBinaryOperator NvimInvalidOperator",
- "default link NvimInvalidComparison NvimInvalidBinaryOperator",
- "default link NvimInvalidComparisonModifier NvimInvalidComparison",
- "default link NvimInvalidBinaryPlus NvimInvalidBinaryOperator",
- "default link NvimInvalidBinaryMinus NvimInvalidBinaryOperator",
- "default link NvimInvalidConcat NvimInvalidBinaryOperator",
- "default link NvimInvalidConcatOrSubscript NvimInvalidConcat",
- "default link NvimInvalidOr NvimInvalidBinaryOperator",
- "default link NvimInvalidAnd NvimInvalidBinaryOperator",
- "default link NvimInvalidMultiplication NvimInvalidBinaryOperator",
- "default link NvimInvalidDivision NvimInvalidBinaryOperator",
- "default link NvimInvalidMod NvimInvalidBinaryOperator",
-
- "default link NvimInvalidTernary NvimInvalidOperator",
- "default link NvimInvalidTernaryColon NvimInvalidTernary",
-
- "default link NvimInvalidDelimiter NvimInvalid",
-
- "default link NvimInvalidParenthesis NvimInvalidDelimiter",
- "default link NvimInvalidLambda NvimInvalidParenthesis",
- "default link NvimInvalidNestingParenthesis NvimInvalidParenthesis",
- "default link NvimInvalidCallingParenthesis NvimInvalidParenthesis",
-
- "default link NvimInvalidSubscript NvimInvalidParenthesis",
- "default link NvimInvalidSubscriptBracket NvimInvalidSubscript",
- "default link NvimInvalidSubscriptColon NvimInvalidSubscript",
- "default link NvimInvalidCurly NvimInvalidSubscript",
-
- "default link NvimInvalidContainer NvimInvalidParenthesis",
- "default link NvimInvalidDict NvimInvalidContainer",
- "default link NvimInvalidList NvimInvalidContainer",
-
- "default link NvimInvalidValue NvimInvalid",
-
- "default link NvimInvalidIdentifier NvimInvalidValue",
- "default link NvimInvalidIdentifierScope NvimInvalidIdentifier",
- "default link NvimInvalidIdentifierScopeDelimiter NvimInvalidIdentifier",
- "default link NvimInvalidIdentifierName NvimInvalidIdentifier",
- "default link NvimInvalidIdentifierKey NvimInvalidIdentifier",
-
- "default link NvimInvalidColon NvimInvalidDelimiter",
- "default link NvimInvalidComma NvimInvalidDelimiter",
- "default link NvimInvalidArrow NvimInvalidDelimiter",
-
- "default link NvimInvalidRegister NvimInvalidValue",
- "default link NvimInvalidNumber NvimInvalidValue",
- "default link NvimInvalidFloat NvimInvalidNumber",
- "default link NvimInvalidNumberPrefix NvimInvalidNumber",
-
- "default link NvimInvalidOptionSigil NvimInvalidIdentifier",
- "default link NvimInvalidOptionName NvimInvalidIdentifier",
- "default link NvimInvalidOptionScope NvimInvalidIdentifierScope",
- "default link NvimInvalidOptionScopeDelimiter "
- "NvimInvalidIdentifierScopeDelimiter",
-
- "default link NvimInvalidEnvironmentSigil NvimInvalidOptionSigil",
- "default link NvimInvalidEnvironmentName NvimInvalidIdentifier",
-
- // Invalid string bodies and specials are still highlighted as valid ones to
- // minimize the red area.
- "default link NvimInvalidString NvimInvalidValue",
- "default link NvimInvalidStringBody NvimStringBody",
- "default link NvimInvalidStringQuote NvimInvalidString",
- "default link NvimInvalidStringSpecial NvimStringSpecial",
-
- "default link NvimInvalidSingleQuote NvimInvalidStringQuote",
- "default link NvimInvalidSingleQuotedBody NvimInvalidStringBody",
- "default link NvimInvalidSingleQuotedQuote NvimInvalidStringSpecial",
-
- "default link NvimInvalidDoubleQuote NvimInvalidStringQuote",
- "default link NvimInvalidDoubleQuotedBody NvimInvalidStringBody",
- "default link NvimInvalidDoubleQuotedEscape NvimInvalidStringSpecial",
- "default link NvimInvalidDoubleQuotedUnknownEscape NvimInvalidValue",
-
- "default link NvimInvalidFigureBrace NvimInvalidDelimiter",
-
- "default link NvimInvalidSpacing ErrorMsg",
-
- // Not actually invalid, but we highlight user that he is doing something
- // wrong.
- "default link NvimDoubleQuotedUnknownEscape NvimInvalidValue",
- NULL,
-};
-
-/// Create default links for Nvim* highlight groups used for cmdline coloring
-void syn_init_cmdline_highlight(bool reset, bool init)
-{
- for (size_t i = 0; highlight_init_cmdline[i] != NULL; i++) {
- do_highlight(highlight_init_cmdline[i], reset, init);
- }
-}
-
-/// Load colors from a file if "g:colors_name" is set, otherwise load builtin
-/// colors
-///
-/// @param both include groups where 'bg' doesn't matter
-/// @param reset clear groups first
-void init_highlight(bool both, bool reset)
-{
- static int had_both = false;
-
- // Try finding the color scheme file. Used when a color file was loaded
- // and 'background' or 't_Co' is changed.
- char_u *p = get_var_value("g:colors_name");
- if (p != NULL) {
- // Value of g:colors_name could be freed in load_colors() and make
- // p invalid, so copy it.
- char_u *copy_p = vim_strsave(p);
- bool okay = load_colors(copy_p);
- xfree(copy_p);
- if (okay) {
- return;
- }
- }
-
- /*
- * Didn't use a color file, use the compiled-in colors.
- */
- if (both) {
- had_both = true;
- const char *const *const pp = highlight_init_both;
- for (size_t i = 0; pp[i] != NULL; i++) {
- do_highlight(pp[i], reset, true);
- }
- } else if (!had_both) {
- // Don't do anything before the call with both == true from main().
- // Not everything has been setup then, and that call will overrule
- // everything anyway.
- return;
- }
-
- const char *const *const pp = ((*p_bg == 'l')
- ? highlight_init_light
- : highlight_init_dark);
- for (size_t i = 0; pp[i] != NULL; i++) {
- do_highlight(pp[i], reset, true);
- }
-
- /* Reverse looks ugly, but grey may not work for 8 colors. Thus let it
- * depend on the number of colors available.
- * With 8 colors brown is equal to yellow, need to use black for Search fg
- * to avoid Statement highlighted text disappears.
- * Clear the attributes, needed when changing the t_Co value. */
- if (t_colors > 8) {
- do_highlight((*p_bg == 'l'
- ? "Visual cterm=NONE ctermbg=LightGrey"
- : "Visual cterm=NONE ctermbg=DarkGrey"), false, true);
- } else {
- do_highlight("Visual cterm=reverse ctermbg=NONE", false, true);
- if (*p_bg == 'l') {
- do_highlight("Search ctermfg=black", false, true);
- }
- }
-
- syn_init_cmdline_highlight(false, false);
-}
-
-/*
- * Load color file "name".
- * Return OK for success, FAIL for failure.
- */
-int load_colors(char_u *name)
-{
- char_u *buf;
- int retval = FAIL;
- static bool recursive = false;
-
- // When being called recursively, this is probably because setting
- // 'background' caused the highlighting to be reloaded. This means it is
- // working, thus we should return OK.
- if (recursive) {
- return OK;
- }
-
- recursive = true;
- size_t buflen = STRLEN(name) + 12;
- buf = xmalloc(buflen);
- apply_autocmds(EVENT_COLORSCHEMEPRE, name, curbuf->b_fname, false, curbuf);
- snprintf((char *)buf, buflen, "colors/%s.vim", name);
- retval = source_runtime((char *)buf, DIP_START + DIP_OPT);
- if (retval == FAIL) {
- snprintf((char *)buf, buflen, "colors/%s.lua", name);
- retval = source_runtime((char *)buf, DIP_START + DIP_OPT);
- }
- xfree(buf);
- apply_autocmds(EVENT_COLORSCHEME, name, curbuf->b_fname, false, curbuf);
-
- recursive = false;
-
- return retval;
-}
-
-static char *(color_names[28]) = {
- "Black", "DarkBlue", "DarkGreen", "DarkCyan",
- "DarkRed", "DarkMagenta", "Brown", "DarkYellow",
- "Gray", "Grey", "LightGray", "LightGrey",
- "DarkGray", "DarkGrey",
- "Blue", "LightBlue", "Green", "LightGreen",
- "Cyan", "LightCyan", "Red", "LightRed", "Magenta",
- "LightMagenta", "Yellow", "LightYellow", "White", "NONE"
-};
-// indices:
-// 0, 1, 2, 3,
-// 4, 5, 6, 7,
-// 8, 9, 10, 11,
-// 12, 13,
-// 14, 15, 16, 17,
-// 18, 19, 20, 21, 22,
-// 23, 24, 25, 26, 27
-static int color_numbers_16[28] = { 0, 1, 2, 3,
- 4, 5, 6, 6,
- 7, 7, 7, 7,
- 8, 8,
- 9, 9, 10, 10,
- 11, 11, 12, 12, 13,
- 13, 14, 14, 15, -1 };
-// for xterm with 88 colors...
-static int color_numbers_88[28] = { 0, 4, 2, 6,
- 1, 5, 32, 72,
- 84, 84, 7, 7,
- 82, 82,
- 12, 43, 10, 61,
- 14, 63, 9, 74, 13,
- 75, 11, 78, 15, -1 };
-// for xterm with 256 colors...
-static int color_numbers_256[28] = { 0, 4, 2, 6,
- 1, 5, 130, 3,
- 248, 248, 7, 7,
- 242, 242,
- 12, 81, 10, 121,
- 14, 159, 9, 224, 13,
- 225, 11, 229, 15, -1 };
-// for terminals with less than 16 colors...
-static int color_numbers_8[28] = { 0, 4, 2, 6,
- 1, 5, 3, 3,
- 7, 7, 7, 7,
- 0+8, 0+8,
- 4+8, 4+8, 2+8, 2+8,
- 6+8, 6+8, 1+8, 1+8, 5+8,
- 5+8, 3+8, 3+8, 7+8, -1 };
-
-// Lookup the "cterm" value to be used for color with index "idx" in
-// color_names[].
-// "boldp" will be set to TRUE or FALSE for a foreground color when using 8
-// colors, otherwise it will be unchanged.
-int lookup_color(const int idx, const bool foreground, TriState *const boldp)
-{
- int color = color_numbers_16[idx];
-
- // Use the _16 table to check if it's a valid color name.
- if (color < 0) {
- return -1;
- }
-
- if (t_colors == 8) {
- // t_Co is 8: use the 8 colors table
- color = color_numbers_8[idx];
- if (foreground) {
- // set/reset bold attribute to get light foreground
- // colors (on some terminals, e.g. "linux")
- if (color & 8) {
- *boldp = kTrue;
- } else {
- *boldp = kFalse;
- }
- }
- color &= 7; // truncate to 8 colors
- } else if (t_colors == 16) {
- color = color_numbers_8[idx];
- } else if (t_colors == 88) {
- color = color_numbers_88[idx];
- } else if (t_colors >= 256) {
- color = color_numbers_256[idx];
- }
- return color;
-}
-
-void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id)
-{
- int idx = id - 1; // Index is ID minus one.
-
- bool is_default = attrs.rgb_ae_attr & HL_DEFAULT;
-
- // Return if "default" was used and the group already has settings
- if (is_default && hl_has_settings(idx, true)) {
- return;
- }
-
- HlGroup *g = &HL_TABLE()[idx];
-
- if (link_id > 0) {
- g->sg_cleared = false;
- g->sg_link = link_id;
- g->sg_script_ctx = current_sctx;
- g->sg_script_ctx.sc_lnum += sourcing_lnum;
- g->sg_set |= SG_LINK;
- if (is_default) {
- g->sg_deflink = link_id;
- g->sg_deflink_sctx = current_sctx;
- g->sg_deflink_sctx.sc_lnum += sourcing_lnum;
- }
- return;
- }
-
- g->sg_cleared = false;
- g->sg_link = 0;
- g->sg_gui = attrs.rgb_ae_attr;
-
- g->sg_rgb_fg = attrs.rgb_fg_color;
- g->sg_rgb_bg = attrs.rgb_bg_color;
- g->sg_rgb_sp = attrs.rgb_sp_color;
-
- struct {
- char **dest; RgbValue val; Object name;
- } cattrs[] = {
- { &g->sg_rgb_fg_name, g->sg_rgb_fg, HAS_KEY(dict->fg) ? dict->fg : dict->foreground },
- { &g->sg_rgb_bg_name, g->sg_rgb_bg, HAS_KEY(dict->bg) ? dict->bg : dict->background },
- { &g->sg_rgb_sp_name, g->sg_rgb_sp, HAS_KEY(dict->sp) ? dict->sp : dict->special },
- { NULL, -1, NIL },
- };
-
- char hex_name[8];
- char *name;
-
- for (int j = 0; cattrs[j].dest; j++) {
- if (cattrs[j].val < 0) {
- XFREE_CLEAR(*cattrs[j].dest);
- continue;
- }
-
- if (cattrs[j].name.type == kObjectTypeString && cattrs[j].name.data.string.size) {
- name = cattrs[j].name.data.string.data;
- } else {
- snprintf(hex_name, sizeof(hex_name), "#%06x", cattrs[j].val);
- name = hex_name;
- }
-
- if (!*cattrs[j].dest
- || STRCMP(*cattrs[j].dest, name) != 0) {
- xfree(*cattrs[j].dest);
- *cattrs[j].dest = xstrdup(name);
- }
- }
-
- g->sg_cterm = attrs.cterm_ae_attr;
- g->sg_cterm_bg = attrs.cterm_bg_color;
- g->sg_cterm_fg = attrs.cterm_fg_color;
- g->sg_cterm_bold = g->sg_cterm & HL_BOLD;
- g->sg_blend = attrs.hl_blend;
-
- g->sg_script_ctx = current_sctx;
- g->sg_script_ctx.sc_lnum += sourcing_lnum;
-
- // 'Normal' is special
- if (STRCMP(g->sg_name_u, "NORMAL") == 0) {
- cterm_normal_fg_color = g->sg_cterm_fg;
- cterm_normal_bg_color = g->sg_cterm_bg;
- normal_fg = g->sg_rgb_fg;
- normal_bg = g->sg_rgb_bg;
- normal_sp = g->sg_rgb_sp;
- ui_default_colors_set();
- } else {
- g->sg_attr = hl_get_syn_attr(0, id, attrs);
-
- // a cursor style uses this syn_id, make sure its attribute is updated.
- if (cursor_mode_uses_syn_id(id)) {
- ui_mode_info_set();
- }
- }
-}
-
-
-/// Handle ":highlight" command
-///
-/// When using ":highlight clear" this is called recursively for each group with
-/// forceit and init being both true.
-///
-/// @param[in] line Command arguments.
-/// @param[in] forceit True when bang is given, allows to link group even if
-/// it has its own settings.
-/// @param[in] init True when initializing.
-void do_highlight(const char *line, const bool forceit, const bool init)
- FUNC_ATTR_NONNULL_ALL
-{
- const char *name_end;
- const char *linep;
- const char *key_start;
- const char *arg_start;
- long i;
- int off;
- int len;
- int attr;
- int id;
- int idx;
- struct hl_group item_before;
- bool did_change = false;
- bool dodefault = false;
- bool doclear = false;
- bool dolink = false;
- bool error = false;
- int color;
- bool is_normal_group = false; // "Normal" group
- bool did_highlight_changed = false;
-
- // If no argument, list current highlighting.
- if (ends_excmd((uint8_t)(*line))) {
- for (i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
- // TODO(brammool): only call when the group has attributes set
- highlight_list_one(i);
- }
- return;
- }
-
- // Isolate the name.
- name_end = (const char *)skiptowhite((const char_u *)line);
- linep = (const char *)skipwhite((const char_u *)name_end);
-
- // Check for "default" argument.
- if (strncmp(line, "default", name_end - line) == 0) {
- dodefault = true;
- line = linep;
- name_end = (const char *)skiptowhite((const char_u *)line);
- linep = (const char *)skipwhite((const char_u *)name_end);
- }
-
- // Check for "clear" or "link" argument.
- if (strncmp(line, "clear", name_end - line) == 0) {
- doclear = true;
- } else if (strncmp(line, "link", name_end - line) == 0) {
- dolink = true;
- }
-
- // ":highlight {group-name}": list highlighting for one group.
- if (!doclear && !dolink && ends_excmd((uint8_t)(*linep))) {
- id = syn_name2id_len((const char_u *)line, (int)(name_end - line));
- if (id == 0) {
- semsg(_("E411: highlight group not found: %s"), line);
- } else {
- highlight_list_one(id);
- }
- return;
- }
-
- // Handle ":highlight link {from} {to}" command.
- if (dolink) {
- const char *from_start = linep;
- const char *from_end;
- const char *to_start;
- const char *to_end;
- int from_id;
- int to_id;
- struct hl_group *hlgroup = NULL;
-
- from_end = (const char *)skiptowhite((const char_u *)from_start);
- to_start = (const char *)skipwhite((const char_u *)from_end);
- to_end = (const char *)skiptowhite((const char_u *)to_start);
-
- if (ends_excmd((uint8_t)(*from_start))
- || ends_excmd((uint8_t)(*to_start))) {
- semsg(_("E412: Not enough arguments: \":highlight link %s\""),
- from_start);
- return;
- }
-
- if (!ends_excmd(*skipwhite((const char_u *)to_end))) {
- semsg(_("E413: Too many arguments: \":highlight link %s\""), from_start);
- return;
- }
-
- from_id = syn_check_group(from_start, (int)(from_end - from_start));
- if (strncmp(to_start, "NONE", 4) == 0) {
- to_id = 0;
- } else {
- to_id = syn_check_group(to_start, (int)(to_end - to_start));
- }
-
- if (from_id > 0) {
- hlgroup = &HL_TABLE()[from_id - 1];
- if (dodefault && (forceit || hlgroup->sg_deflink == 0)) {
- hlgroup->sg_deflink = to_id;
- hlgroup->sg_deflink_sctx = current_sctx;
- hlgroup->sg_deflink_sctx.sc_lnum += sourcing_lnum;
- nlua_set_sctx(&hlgroup->sg_deflink_sctx);
- }
- }
-
- if (from_id > 0 && (!init || hlgroup->sg_set == 0)) {
- // Don't allow a link when there already is some highlighting
- // for the group, unless '!' is used
- if (to_id > 0 && !forceit && !init
- && hl_has_settings(from_id - 1, dodefault)) {
- if (sourcing_name == NULL && !dodefault) {
- emsg(_("E414: group has settings, highlight link ignored"));
- }
- } else if (hlgroup->sg_link != to_id
- || hlgroup->sg_script_ctx.sc_sid != current_sctx.sc_sid
- || hlgroup->sg_cleared) {
- if (!init) {
- hlgroup->sg_set |= SG_LINK;
- }
- hlgroup->sg_link = to_id;
- hlgroup->sg_script_ctx = current_sctx;
- hlgroup->sg_script_ctx.sc_lnum += sourcing_lnum;
- nlua_set_sctx(&hlgroup->sg_script_ctx);
- hlgroup->sg_cleared = false;
- redraw_all_later(SOME_VALID);
-
- // Only call highlight changed() once after multiple changes
- need_highlight_changed = true;
- }
- }
-
- return;
- }
-
- if (doclear) {
- // ":highlight clear [group]" command.
- line = linep;
- if (ends_excmd((uint8_t)(*line))) {
- do_unlet(S_LEN("colors_name"), true);
- restore_cterm_colors();
-
- // Clear all default highlight groups and load the defaults.
- for (int j = 0; j < highlight_ga.ga_len; j++) {
- highlight_clear(j);
- }
- init_highlight(true, true);
- highlight_changed();
- redraw_all_later(NOT_VALID);
- return;
- }
- name_end = (const char *)skiptowhite((const char_u *)line);
- linep = (const char *)skipwhite((const char_u *)name_end);
- }
-
- // Find the group name in the table. If it does not exist yet, add it.
- id = syn_check_group(line, (int)(name_end - line));
- if (id == 0) { // Failed (out of memory).
- return;
- }
- idx = id - 1; // Index is ID minus one.
-
- // Return if "default" was used and the group already has settings
- if (dodefault && hl_has_settings(idx, true)) {
- return;
- }
-
- // Make a copy so we can check if any attribute actually changed
- item_before = HL_TABLE()[idx];
- is_normal_group = (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0);
-
- // Clear the highlighting for ":hi clear {group}" and ":hi clear".
- if (doclear || (forceit && init)) {
- highlight_clear(idx);
- if (!doclear) {
- HL_TABLE()[idx].sg_set = 0;
- }
- }
-
- char *key = NULL;
- char *arg = NULL;
- if (!doclear) {
- while (!ends_excmd((uint8_t)(*linep))) {
- key_start = linep;
- if (*linep == '=') {
- semsg(_("E415: unexpected equal sign: %s"), key_start);
- error = true;
- break;
- }
-
- // Isolate the key ("term", "ctermfg", "ctermbg", "font", "guifg",
- // "guibg" or "guisp").
- while (*linep && !ascii_iswhite(*linep) && *linep != '=') {
- linep++;
- }
- xfree(key);
- key = (char *)vim_strnsave_up((const char_u *)key_start,
- linep - key_start);
- linep = (const char *)skipwhite((const char_u *)linep);
-
- if (strcmp(key, "NONE") == 0) {
- if (!init || HL_TABLE()[idx].sg_set == 0) {
- if (!init) {
- HL_TABLE()[idx].sg_set |= SG_CTERM+SG_GUI;
- }
- highlight_clear(idx);
- }
- continue;
- }
-
- // Check for the equal sign.
- if (*linep != '=') {
- semsg(_("E416: missing equal sign: %s"), key_start);
- error = true;
- break;
- }
- linep++;
-
- // Isolate the argument.
- linep = (const char *)skipwhite((const char_u *)linep);
- if (*linep == '\'') { // guifg='color name'
- arg_start = ++linep;
- linep = strchr(linep, '\'');
- if (linep == NULL) {
- semsg(_(e_invarg2), key_start);
- error = true;
- break;
- }
- } else {
- arg_start = linep;
- linep = (const char *)skiptowhite((const char_u *)linep);
- }
- if (linep == arg_start) {
- semsg(_("E417: missing argument: %s"), key_start);
- error = true;
- break;
- }
- xfree(arg);
- arg = xstrndup(arg_start, (size_t)(linep - arg_start));
-
- if (*linep == '\'') {
- linep++;
- }
-
- // Store the argument.
- if (strcmp(key, "TERM") == 0
- || strcmp(key, "CTERM") == 0
- || strcmp(key, "GUI") == 0) {
- attr = 0;
- off = 0;
- while (arg[off] != NUL) {
- for (i = ARRAY_SIZE(hl_attr_table); --i >= 0;) {
- len = (int)STRLEN(hl_name_table[i]);
- if (STRNICMP(arg + off, hl_name_table[i], len) == 0) {
- attr |= hl_attr_table[i];
- off += len;
- break;
- }
- }
- if (i < 0) {
- semsg(_("E418: Illegal value: %s"), arg);
- error = true;
- break;
- }
- if (arg[off] == ',') { // Another one follows.
- off++;
- }
- }
- if (error) {
- break;
- }
- if (*key == 'C') {
- if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) {
- if (!init) {
- HL_TABLE()[idx].sg_set |= SG_CTERM;
- }
- HL_TABLE()[idx].sg_cterm = attr;
- HL_TABLE()[idx].sg_cterm_bold = false;
- }
- } else if (*key == 'G') {
- if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
- if (!init) {
- HL_TABLE()[idx].sg_set |= SG_GUI;
- }
- HL_TABLE()[idx].sg_gui = attr;
- }
- }
- } else if (STRCMP(key, "FONT") == 0) {
- // in non-GUI fonts are simply ignored
- } else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0) {
- if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM)) {
- if (!init) {
- HL_TABLE()[idx].sg_set |= SG_CTERM;
- }
-
- /* When setting the foreground color, and previously the "bold"
- * flag was set for a light color, reset it now */
- if (key[5] == 'F' && HL_TABLE()[idx].sg_cterm_bold) {
- HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
- HL_TABLE()[idx].sg_cterm_bold = false;
- }
-
- if (ascii_isdigit(*arg)) {
- color = atoi(arg);
- } else if (STRICMP(arg, "fg") == 0) {
- if (cterm_normal_fg_color) {
- color = cterm_normal_fg_color - 1;
- } else {
- emsg(_("E419: FG color unknown"));
- error = true;
- break;
- }
- } else if (STRICMP(arg, "bg") == 0) {
- if (cterm_normal_bg_color > 0) {
- color = cterm_normal_bg_color - 1;
- } else {
- emsg(_("E420: BG color unknown"));
- error = true;
- break;
- }
- } else {
- // Reduce calls to STRICMP a bit, it can be slow.
- off = TOUPPER_ASC(*arg);
- for (i = ARRAY_SIZE(color_names); --i >= 0;) {
- if (off == color_names[i][0]
- && STRICMP(arg + 1, color_names[i] + 1) == 0) {
- break;
- }
- }
- if (i < 0) {
- semsg(_("E421: Color name or number not recognized: %s"),
- key_start);
- error = true;
- break;
- }
-
- TriState bold = kNone;
- color = lookup_color(i, key[5] == 'F', &bold);
-
- // set/reset bold attribute to get light foreground
- // colors (on some terminals, e.g. "linux")
- if (bold == kTrue) {
- HL_TABLE()[idx].sg_cterm |= HL_BOLD;
- HL_TABLE()[idx].sg_cterm_bold = true;
- } else if (bold == kFalse) {
- HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
- }
- }
- // Add one to the argument, to avoid zero. Zero is used for
- // "NONE", then "color" is -1.
- if (key[5] == 'F') {
- HL_TABLE()[idx].sg_cterm_fg = color + 1;
- if (is_normal_group) {
- cterm_normal_fg_color = color + 1;
- }
- } else {
- HL_TABLE()[idx].sg_cterm_bg = color + 1;
- if (is_normal_group) {
- cterm_normal_bg_color = color + 1;
- if (!ui_rgb_attached()) {
- if (color >= 0) {
- int dark = -1;
-
- if (t_colors < 16) {
- dark = (color == 0 || color == 4);
- } else if (color < 16) {
- // Limit the heuristic to the standard 16 colors
- dark = (color < 7 || color == 8);
- }
- // Set the 'background' option if the value is
- // wrong.
- if (dark != -1
- && dark != (*p_bg == 'd')
- && !option_was_set("bg")) {
- set_option_value("bg", 0L, (dark ? "dark" : "light"), 0);
- reset_option_was_set("bg");
- }
- }
- }
- }
- }
- }
- } else if (strcmp(key, "GUIFG") == 0) {
- char **namep = &HL_TABLE()[idx].sg_rgb_fg_name;
-
- if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
- if (!init) {
- HL_TABLE()[idx].sg_set |= SG_GUI;
- }
-
- if (*namep == NULL || STRCMP(*namep, arg) != 0) {
- xfree(*namep);
- if (strcmp(arg, "NONE") != 0) {
- *namep = xstrdup(arg);
- HL_TABLE()[idx].sg_rgb_fg = name_to_color(arg);
- } else {
- *namep = NULL;
- HL_TABLE()[idx].sg_rgb_fg = -1;
- }
- did_change = true;
- }
- }
-
- if (is_normal_group) {
- normal_fg = HL_TABLE()[idx].sg_rgb_fg;
- }
- } else if (STRCMP(key, "GUIBG") == 0) {
- char **const namep = &HL_TABLE()[idx].sg_rgb_bg_name;
-
- if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
- if (!init) {
- HL_TABLE()[idx].sg_set |= SG_GUI;
- }
-
- if (*namep == NULL || STRCMP(*namep, arg) != 0) {
- xfree(*namep);
- if (STRCMP(arg, "NONE") != 0) {
- *namep = xstrdup(arg);
- HL_TABLE()[idx].sg_rgb_bg = name_to_color(arg);
- } else {
- *namep = NULL;
- HL_TABLE()[idx].sg_rgb_bg = -1;
- }
- did_change = true;
- }
- }
-
- if (is_normal_group) {
- normal_bg = HL_TABLE()[idx].sg_rgb_bg;
- }
- } else if (strcmp(key, "GUISP") == 0) {
- char **const namep = &HL_TABLE()[idx].sg_rgb_sp_name;
-
- if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI)) {
- if (!init) {
- HL_TABLE()[idx].sg_set |= SG_GUI;
- }
-
- if (*namep == NULL || STRCMP(*namep, arg) != 0) {
- xfree(*namep);
- if (strcmp(arg, "NONE") != 0) {
- *namep = xstrdup(arg);
- HL_TABLE()[idx].sg_rgb_sp = name_to_color(arg);
- } else {
- *namep = NULL;
- HL_TABLE()[idx].sg_rgb_sp = -1;
- }
- did_change = true;
- }
- }
-
- if (is_normal_group) {
- normal_sp = HL_TABLE()[idx].sg_rgb_sp;
- }
- } else if (strcmp(key, "START") == 0 || strcmp(key, "STOP") == 0) {
- // Ignored for now
- } else if (strcmp(key, "BLEND") == 0) {
- if (strcmp(arg, "NONE") != 0) {
- HL_TABLE()[idx].sg_blend = strtol(arg, NULL, 10);
- } else {
- HL_TABLE()[idx].sg_blend = -1;
- }
- } else {
- semsg(_("E423: Illegal argument: %s"), key_start);
- error = true;
- break;
- }
- HL_TABLE()[idx].sg_cleared = false;
-
- // When highlighting has been given for a group, don't link it.
- if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK)) {
- HL_TABLE()[idx].sg_link = 0;
- }
-
- // Continue with next argument.
- linep = (const char *)skipwhite((const char_u *)linep);
- }
- }
-
- // If there is an error, and it's a new entry, remove it from the table.
- if (error && idx == highlight_ga.ga_len) {
- syn_unadd_group();
- } else {
- if (!error && is_normal_group) {
- // Need to update all groups, because they might be using "bg" and/or
- // "fg", which have been changed now.
- highlight_attr_set_all();
-
- if (!ui_has(kUILinegrid) && starting == 0) {
- // Older UIs assume that we clear the screen after normal group is
- // changed
- ui_refresh();
- } else {
- // TUI and newer UIs will repaint the screen themselves. NOT_VALID
- // redraw below will still handle usages of guibg=fg etc.
- ui_default_colors_set();
- }
- did_highlight_changed = true;
- redraw_all_later(NOT_VALID);
- } else {
- set_hl_attr(idx);
- }
- HL_TABLE()[idx].sg_script_ctx = current_sctx;
- HL_TABLE()[idx].sg_script_ctx.sc_lnum += sourcing_lnum;
- nlua_set_sctx(&HL_TABLE()[idx].sg_script_ctx);
- }
- xfree(key);
- xfree(arg);
-
- // Only call highlight_changed() once, after a sequence of highlight
- // commands, and only if an attribute actually changed
- if ((did_change
- || memcmp(&HL_TABLE()[idx], &item_before, sizeof(item_before)) != 0)
- && !did_highlight_changed) {
- // Do not trigger a redraw when highlighting is changed while
- // redrawing. This may happen when evaluating 'statusline' changes the
- // StatusLine group.
- if (!updating_screen) {
- redraw_all_later(NOT_VALID);
- }
- need_highlight_changed = true;
- }
-}
-
-#if defined(EXITFREE)
-void free_highlight(void)
-{
- for (int i = 0; i < highlight_ga.ga_len; ++i) {
- highlight_clear(i);
- xfree(HL_TABLE()[i].sg_name);
- xfree(HL_TABLE()[i].sg_name_u);
- }
- ga_clear(&highlight_ga);
- map_destroy(cstr_t, int)(&highlight_unames);
-}
-
-#endif
-
-/*
- * Reset the cterm colors to what they were before Vim was started, if
- * possible. Otherwise reset them to zero.
- */
-void restore_cterm_colors(void)
-{
- normal_fg = -1;
- normal_bg = -1;
- normal_sp = -1;
- cterm_normal_fg_color = 0;
- cterm_normal_bg_color = 0;
-}
-
-/// @param check_link if true also check for an existing link.
-///
-/// @return TRUE if highlight group "idx" has any settings.
-static int hl_has_settings(int idx, bool check_link)
-{
- return HL_TABLE()[idx].sg_cleared == 0
- && (HL_TABLE()[idx].sg_attr != 0
- || HL_TABLE()[idx].sg_cterm_fg != 0
- || HL_TABLE()[idx].sg_cterm_bg != 0
- || HL_TABLE()[idx].sg_rgb_fg_name != NULL
- || HL_TABLE()[idx].sg_rgb_bg_name != NULL
- || HL_TABLE()[idx].sg_rgb_sp_name != NULL
- || (check_link && (HL_TABLE()[idx].sg_set & SG_LINK)));
-}
-
-/*
- * Clear highlighting for one group.
- */
-static void highlight_clear(int idx)
-{
- HL_TABLE()[idx].sg_cleared = true;
-
- HL_TABLE()[idx].sg_attr = 0;
- HL_TABLE()[idx].sg_cterm = 0;
- HL_TABLE()[idx].sg_cterm_bold = false;
- HL_TABLE()[idx].sg_cterm_fg = 0;
- HL_TABLE()[idx].sg_cterm_bg = 0;
- HL_TABLE()[idx].sg_gui = 0;
- HL_TABLE()[idx].sg_rgb_fg = -1;
- HL_TABLE()[idx].sg_rgb_bg = -1;
- HL_TABLE()[idx].sg_rgb_sp = -1;
- XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_fg_name);
- XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_bg_name);
- XFREE_CLEAR(HL_TABLE()[idx].sg_rgb_sp_name);
- HL_TABLE()[idx].sg_blend = -1;
- // Restore default link and context if they exist. Otherwise clears.
- HL_TABLE()[idx].sg_link = HL_TABLE()[idx].sg_deflink;
- // Since we set the default link, set the location to where the default
- // link was set.
- HL_TABLE()[idx].sg_script_ctx = HL_TABLE()[idx].sg_deflink_sctx;
-}
-
-
-/// \addtogroup LIST_XXX
-/// @{
-#define LIST_ATTR 1
-#define LIST_STRING 2
-#define LIST_INT 3
-/// @}
-
-static void highlight_list_one(const int id)
-{
- struct hl_group *const sgp = &HL_TABLE()[id - 1]; // index is ID minus one
- bool didh = false;
-
- if (message_filtered(sgp->sg_name)) {
- return;
- }
-
- didh = highlight_list_arg(id, didh, LIST_ATTR,
- sgp->sg_cterm, NULL, "cterm");
- didh = highlight_list_arg(id, didh, LIST_INT,
- sgp->sg_cterm_fg, NULL, "ctermfg");
- didh = highlight_list_arg(id, didh, LIST_INT,
- sgp->sg_cterm_bg, NULL, "ctermbg");
-
- didh = highlight_list_arg(id, didh, LIST_ATTR,
- sgp->sg_gui, NULL, "gui");
- didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_rgb_fg_name, "guifg");
- didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_rgb_bg_name, "guibg");
- didh = highlight_list_arg(id, didh, LIST_STRING,
- 0, sgp->sg_rgb_sp_name, "guisp");
-
- didh = highlight_list_arg(id, didh, LIST_INT,
- sgp->sg_blend+1, NULL, "blend");
-
- if (sgp->sg_link && !got_int) {
- (void)syn_list_header(didh, 0, id, true);
- didh = true;
- msg_puts_attr("links to", HL_ATTR(HLF_D));
- msg_putchar(' ');
- msg_outtrans(HL_TABLE()[HL_TABLE()[id - 1].sg_link - 1].sg_name);
- }
-
- if (!didh) {
- highlight_list_arg(id, didh, LIST_STRING, 0, "cleared", "");
- }
- if (p_verbose > 0) {
- last_set_msg(sgp->sg_script_ctx);
- }
-}
-
-Dictionary get_global_hl_defs(void)
-{
- Dictionary rv = ARRAY_DICT_INIT;
- for (int i = 1; i <= highlight_ga.ga_len && !got_int; i++) {
- Dictionary attrs = ARRAY_DICT_INIT;
- struct hl_group *h = &HL_TABLE()[i - 1];
- if (h->sg_attr > 0) {
- attrs = hlattrs2dict(syn_attr2entry(h->sg_attr), true);
- } else if (h->sg_link > 0) {
- const char *link = (const char *)HL_TABLE()[h->sg_link - 1].sg_name;
- PUT(attrs, "link", STRING_OBJ(cstr_to_string(link)));
- }
- PUT(rv, (const char *)h->sg_name, DICTIONARY_OBJ(attrs));
- }
-
- return rv;
-}
-
-/// Outputs a highlight when doing ":hi MyHighlight"
-///
-/// @param type one of \ref LIST_XXX
-/// @param iarg integer argument used if \p type == LIST_INT
-/// @param sarg string used if \p type == LIST_STRING
-static bool highlight_list_arg(const int id, bool didh, const int type, int iarg, char *const sarg,
- const char *const name)
-{
- char buf[100];
-
- if (got_int) {
- return false;
- }
- if (type == LIST_STRING ? (sarg != NULL) : (iarg != 0)) {
- char *ts = buf;
- if (type == LIST_INT) {
- snprintf((char *)buf, sizeof(buf), "%d", iarg - 1);
- } else if (type == LIST_STRING) {
- ts = sarg;
- } else { // type == LIST_ATTR
- buf[0] = NUL;
- for (int i = 0; hl_attr_table[i] != 0; i++) {
- if (iarg & hl_attr_table[i]) {
- if (buf[0] != NUL) {
- xstrlcat(buf, ",", 100);
- }
- xstrlcat(buf, hl_name_table[i], 100);
- iarg &= ~hl_attr_table[i]; // don't want "inverse"
- }
- }
- }
-
- (void)syn_list_header(didh, (int)(vim_strsize((char_u *)ts) + STRLEN(name)
- + 1), id, false);
- didh = true;
- if (!got_int) {
- if (*name != NUL) {
- msg_puts_attr(name, HL_ATTR(HLF_D));
- msg_puts_attr("=", HL_ATTR(HLF_D));
- }
- msg_outtrans((char_u *)ts);
- }
- }
- return didh;
-}
-
-/// Check whether highlight group has attribute
-///
-/// @param[in] id Highlight group to check.
-/// @param[in] flag Attribute to check.
-/// @param[in] modec 'g' for GUI, 'c' for term.
-///
-/// @return "1" if highlight group has attribute, NULL otherwise.
-const char *highlight_has_attr(const int id, const int flag, const int modec)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_PURE
-{
- int attr;
-
- if (id <= 0 || id > highlight_ga.ga_len) {
- return NULL;
- }
-
- if (modec == 'g') {
- attr = HL_TABLE()[id - 1].sg_gui;
- } else {
- attr = HL_TABLE()[id - 1].sg_cterm;
- }
-
- return (attr & flag) ? "1" : NULL;
-}
-
-/// Return color name of the given highlight group
-///
-/// @param[in] id Highlight group to work with.
-/// @param[in] what What to return: one of "font", "fg", "bg", "sp", "fg#",
-/// "bg#" or "sp#".
-/// @param[in] modec 'g' for GUI, 'c' for cterm and 't' for term.
-///
-/// @return color name, possibly in a static buffer. Buffer will be overwritten
-/// on next highlight_color() call. May return NULL.
-const char *highlight_color(const int id, const char *const what, const int modec)
- FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
-{
- static char name[20];
- int n;
- bool fg = false;
- bool sp = false;
- bool font = false;
-
- if (id <= 0 || id > highlight_ga.ga_len) {
- return NULL;
- }
-
- if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'g') {
- fg = true;
- } else if (TOLOWER_ASC(what[0]) == 'f' && TOLOWER_ASC(what[1]) == 'o'
- && TOLOWER_ASC(what[2]) == 'n' && TOLOWER_ASC(what[3]) == 't') {
- font = true;
- } else if (TOLOWER_ASC(what[0]) == 's' && TOLOWER_ASC(what[1]) == 'p') {
- sp = true;
- } else if (!(TOLOWER_ASC(what[0]) == 'b' && TOLOWER_ASC(what[1]) == 'g')) {
- return NULL;
- }
- if (modec == 'g') {
- if (what[2] == '#' && ui_rgb_attached()) {
- if (fg) {
- n = HL_TABLE()[id - 1].sg_rgb_fg;
- } else if (sp) {
- n = HL_TABLE()[id - 1].sg_rgb_sp;
- } else {
- n = HL_TABLE()[id - 1].sg_rgb_bg;
- }
- if (n < 0 || n > 0xffffff) {
- return NULL;
- }
- snprintf(name, sizeof(name), "#%06x", n);
- return name;
- }
- if (fg) {
- return (const char *)HL_TABLE()[id - 1].sg_rgb_fg_name;
- }
- if (sp) {
- return (const char *)HL_TABLE()[id - 1].sg_rgb_sp_name;
- }
- return (const char *)HL_TABLE()[id - 1].sg_rgb_bg_name;
- }
- if (font || sp) {
- return NULL;
- }
- if (modec == 'c') {
- if (fg) {
- n = HL_TABLE()[id - 1].sg_cterm_fg - 1;
- } else {
- n = HL_TABLE()[id - 1].sg_cterm_bg - 1;
- }
- if (n < 0) {
- return NULL;
- }
- snprintf(name, sizeof(name), "%d", n);
- return name;
- }
- // term doesn't have color.
- return NULL;
-}
-
-/// Output the syntax list header.
-///
-/// @param did_header did header already
-/// @param outlen length of string that comes
-/// @param id highlight group id
-/// @param force_newline always start a new line
-/// @return true when started a new line.
-static bool syn_list_header(const bool did_header, const int outlen, const int id,
- bool force_newline)
-{
- int endcol = 19;
- bool newline = true;
- int name_col = 0;
- bool adjust = true;
-
- if (!did_header) {
- msg_putchar('\n');
- if (got_int) {
- return true;
- }
- msg_outtrans(HL_TABLE()[id - 1].sg_name);
- name_col = msg_col;
- endcol = 15;
- } else if ((ui_has(kUIMessages) || msg_silent) && !force_newline) {
- msg_putchar(' ');
- adjust = false;
- } else if (msg_col + outlen + 1 >= Columns || force_newline) {
- msg_putchar('\n');
- if (got_int) {
- return true;
- }
- } else {
- if (msg_col >= endcol) { // wrap around is like starting a new line
- newline = false;
- }
- }
-
- if (adjust) {
- if (msg_col >= endcol) {
- // output at least one space
- endcol = msg_col + 1;
- }
-
- msg_advance(endcol);
- }
-
- // Show "xxx" with the attributes.
- if (!did_header) {
- if (endcol == Columns - 1 && endcol <= name_col) {
- msg_putchar(' ');
- }
- msg_puts_attr("xxx", syn_id2attr(id));
- msg_putchar(' ');
- }
-
- return newline;
-}
-
-/// Set the attribute numbers for a highlight group.
-/// Called after one of the attributes has changed.
-/// @param idx corrected highlight index
-static void set_hl_attr(int idx)
-{
- HlAttrs at_en = HLATTRS_INIT;
- struct hl_group *sgp = HL_TABLE() + idx;
-
- at_en.cterm_ae_attr = sgp->sg_cterm;
- at_en.cterm_fg_color = sgp->sg_cterm_fg;
- at_en.cterm_bg_color = sgp->sg_cterm_bg;
- at_en.rgb_ae_attr = sgp->sg_gui;
- // FIXME(tarruda): The "unset value" for rgb is -1, but since hlgroup is
- // initialized with 0(by garray functions), check for sg_rgb_{f,b}g_name
- // before setting attr_entry->{f,g}g_color to a other than -1
- at_en.rgb_fg_color = sgp->sg_rgb_fg_name ? sgp->sg_rgb_fg : -1;
- at_en.rgb_bg_color = sgp->sg_rgb_bg_name ? sgp->sg_rgb_bg : -1;
- at_en.rgb_sp_color = sgp->sg_rgb_sp_name ? sgp->sg_rgb_sp : -1;
- at_en.hl_blend = sgp->sg_blend;
-
- sgp->sg_attr = hl_get_syn_attr(0, idx+1, at_en);
-
- // a cursor style uses this syn_id, make sure its attribute is updated.
- if (cursor_mode_uses_syn_id(idx+1)) {
- ui_mode_info_set();
- }
-}
-
-int syn_name2id(const char *name)
- FUNC_ATTR_NONNULL_ALL
-{
- return syn_name2id_len((char_u *)name, STRLEN(name));
-}
-
-/// Lookup a highlight group name and return its ID.
-///
-/// @param highlight name e.g. 'Cursor', 'Normal'
-/// @return the highlight id, else 0 if \p name does not exist
-int syn_name2id_len(const char_u *name, size_t len)
- FUNC_ATTR_NONNULL_ALL
-{
- char name_u[MAX_SYN_NAME + 1];
-
- if (len == 0 || len > MAX_SYN_NAME) {
- return 0;
- }
-
- // Avoid using stricmp() too much, it's slow on some systems */
- // Avoid alloc()/free(), these are slow too.
- memcpy(name_u, name, len);
- name_u[len] = '\0';
- vim_strup((char_u *)name_u);
-
- // map_get(..., int) returns 0 when no key is present, which is
- // the expected value for missing highlight group.
- return map_get(cstr_t, int)(&highlight_unames, name_u);
-}
-
-/// Lookup a highlight group name and return its attributes.
-/// Return zero if not found.
-int syn_name2attr(const char_u *name)
- FUNC_ATTR_NONNULL_ALL
-{
- int id = syn_name2id((char *)name);
-
- if (id != 0) {
- return syn_id2attr(id);
- }
- return 0;
-}
-
-/*
- * Return TRUE if highlight group "name" exists.
- */
-int highlight_exists(const char *name)
-{
- return syn_name2id(name) > 0;
-}
-
-/*
- * Return the name of highlight group "id".
- * When not a valid ID return an empty string.
- */
-char_u *syn_id2name(int id)
-{
- if (id <= 0 || id > highlight_ga.ga_len) {
- return (char_u *)"";
- }
- return HL_TABLE()[id - 1].sg_name;
-}
-
-
-/// Find highlight group name in the table and return its ID.
-/// If it doesn't exist yet, a new entry is created.
-///
-/// @param pp Highlight group name
-/// @param len length of \p pp
-///
-/// @return 0 for failure else the id of the group
-int syn_check_group(const char *name, int len)
-{
- if (len > MAX_SYN_NAME) {
- emsg(_(e_highlight_group_name_too_long));
- return 0;
- }
- int id = syn_name2id_len((char_u *)name, len);
- if (id == 0) { // doesn't exist yet
- return syn_add_group(vim_strnsave((char_u *)name, len));
- }
- return id;
-}
-
-/// Add new highlight group and return its ID.
-///
-/// @param name must be an allocated string, it will be consumed.
-/// @return 0 for failure, else the allocated group id
-/// @see syn_check_group syn_unadd_group
-static int syn_add_group(char_u *name)
-{
- char_u *p;
-
- // Check that the name is ASCII letters, digits and underscore.
- for (p = name; *p != NUL; ++p) {
- if (!vim_isprintc(*p)) {
- emsg(_("E669: Unprintable character in group name"));
- xfree(name);
- return 0;
- } else if (!ASCII_ISALNUM(*p) && *p != '_') {
- /* This is an error, but since there previously was no check only
- * give a warning. */
- msg_source(HL_ATTR(HLF_W));
- msg(_("W18: Invalid character in group name"));
- break;
- }
- }
-
- /*
- * First call for this growarray: init growing array.
- */
- if (highlight_ga.ga_data == NULL) {
- highlight_ga.ga_itemsize = sizeof(struct hl_group);
- ga_set_growsize(&highlight_ga, 10);
- }
-
- if (highlight_ga.ga_len >= MAX_HL_ID) {
- emsg(_("E849: Too many highlight and syntax groups"));
- xfree(name);
- return 0;
- }
-
- char *const name_up = (char *)vim_strsave_up(name);
-
- // Append another syntax_highlight entry.
- struct hl_group *hlgp = GA_APPEND_VIA_PTR(struct hl_group, &highlight_ga);
- memset(hlgp, 0, sizeof(*hlgp));
- hlgp->sg_name = name;
- hlgp->sg_rgb_bg = -1;
- hlgp->sg_rgb_fg = -1;
- hlgp->sg_rgb_sp = -1;
- hlgp->sg_blend = -1;
- hlgp->sg_name_u = name_up;
-
- int id = highlight_ga.ga_len; // ID is index plus one
-
- map_put(cstr_t, int)(&highlight_unames, name_up, id);
-
- return id;
-}
-
-/// When, just after calling syn_add_group(), an error is discovered, this
-/// function deletes the new name.
-static void syn_unadd_group(void)
-{
- highlight_ga.ga_len--;
- HlGroup *item = &HL_TABLE()[highlight_ga.ga_len];
- map_del(cstr_t, int)(&highlight_unames, item->sg_name_u);
- xfree(item->sg_name);
- xfree(item->sg_name_u);
-}
-
-
-/// Translate a group ID to highlight attributes.
-/// @see syn_attr2entry
-int syn_id2attr(int hl_id)
-{
- hl_id = syn_get_final_id(hl_id);
- struct hl_group *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
-
- int attr = ns_get_hl(-1, hl_id, false, sgp->sg_set);
- if (attr >= 0) {
- return attr;
- }
- return sgp->sg_attr;
-}
-
-
-/*
- * Translate a group ID to the final group ID (following links).
- */
-int syn_get_final_id(int hl_id)
-{
- int count;
-
- if (hl_id > highlight_ga.ga_len || hl_id < 1) {
- return 0; // Can be called from eval!!
- }
- /*
- * Follow links until there is no more.
- * Look out for loops! Break after 100 links.
- */
- for (count = 100; --count >= 0;) {
- struct hl_group *sgp = &HL_TABLE()[hl_id - 1]; // index is ID minus one
-
- // ACHTUNG: when using "tmp" attribute (no link) the function might be
- // called twice. it needs be smart enough to remember attr only to
- // syn_id2attr time
- int check = ns_get_hl(-1, hl_id, true, sgp->sg_set);
- if (check == 0) {
- return hl_id; // how dare! it broke the link!
- } else if (check > 0) {
- hl_id = check;
- continue;
- }
-
-
- if (sgp->sg_link == 0 || sgp->sg_link > highlight_ga.ga_len) {
- break;
- }
- hl_id = sgp->sg_link;
- }
-
- return hl_id;
-}
-
-/// Refresh the color attributes of all highlight groups.
-void highlight_attr_set_all(void)
-{
- for (int idx = 0; idx < highlight_ga.ga_len; idx++) {
- struct hl_group *sgp = &HL_TABLE()[idx];
- if (sgp->sg_rgb_bg_name != NULL) {
- sgp->sg_rgb_bg = name_to_color(sgp->sg_rgb_bg_name);
- }
- if (sgp->sg_rgb_fg_name != NULL) {
- sgp->sg_rgb_fg = name_to_color(sgp->sg_rgb_fg_name);
- }
- if (sgp->sg_rgb_sp_name != NULL) {
- sgp->sg_rgb_sp = name_to_color(sgp->sg_rgb_sp_name);
- }
- set_hl_attr(idx);
- }
-}
-
-// Apply difference between User[1-9] and HLF_S to HLF_SNC.
-static void combine_stl_hlt(int id, int id_S, int id_alt, int hlcnt, int i, int hlf, int *table)
- FUNC_ATTR_NONNULL_ALL
-{
- struct hl_group *const hlt = HL_TABLE();
-
- if (id_alt == 0) {
- memset(&hlt[hlcnt + i], 0, sizeof(struct hl_group));
- hlt[hlcnt + i].sg_cterm = highlight_attr[hlf];
- hlt[hlcnt + i].sg_gui = highlight_attr[hlf];
- } else {
- memmove(&hlt[hlcnt + i], &hlt[id_alt - 1], sizeof(struct hl_group));
- }
- hlt[hlcnt + i].sg_link = 0;
-
- hlt[hlcnt + i].sg_cterm ^= hlt[id - 1].sg_cterm ^ hlt[id_S - 1].sg_cterm;
- if (hlt[id - 1].sg_cterm_fg != hlt[id_S - 1].sg_cterm_fg) {
- hlt[hlcnt + i].sg_cterm_fg = hlt[id - 1].sg_cterm_fg;
- }
- if (hlt[id - 1].sg_cterm_bg != hlt[id_S - 1].sg_cterm_bg) {
- hlt[hlcnt + i].sg_cterm_bg = hlt[id - 1].sg_cterm_bg;
- }
- hlt[hlcnt + i].sg_gui ^= hlt[id - 1].sg_gui ^ hlt[id_S - 1].sg_gui;
- if (hlt[id - 1].sg_rgb_fg != hlt[id_S - 1].sg_rgb_fg) {
- hlt[hlcnt + i].sg_rgb_fg = hlt[id - 1].sg_rgb_fg;
- }
- if (hlt[id - 1].sg_rgb_bg != hlt[id_S - 1].sg_rgb_bg) {
- hlt[hlcnt + i].sg_rgb_bg = hlt[id - 1].sg_rgb_bg;
- }
- if (hlt[id - 1].sg_rgb_sp != hlt[id_S - 1].sg_rgb_sp) {
- hlt[hlcnt + i].sg_rgb_sp = hlt[id - 1].sg_rgb_sp;
- }
- highlight_ga.ga_len = hlcnt + i + 1;
- set_hl_attr(hlcnt + i); // At long last we can apply
- table[i] = syn_id2attr(hlcnt + i + 1);
-}
-
-/// Translate highlight groups into attributes in highlight_attr[] and set up
-/// the user highlights User1..9. A set of corresponding highlights to use on
-/// top of HLF_SNC is computed. Called only when nvim starts and upon first
-/// screen redraw after any :highlight command.
-void highlight_changed(void)
-{
- int id;
- char userhl[30]; // use 30 to avoid compiler warning
- int id_S = -1;
- int id_SNC = 0;
- int hlcnt;
-
- need_highlight_changed = false;
-
- /// Translate builtin highlight groups into attributes for quick lookup.
- for (int hlf = 0; hlf < HLF_COUNT; hlf++) {
- id = syn_check_group(hlf_names[hlf], STRLEN(hlf_names[hlf]));
- if (id == 0) {
- abort();
- }
- int final_id = syn_get_final_id(id);
- if (hlf == HLF_SNC) {
- id_SNC = final_id;
- } else if (hlf == HLF_S) {
- id_S = final_id;
- }
-
- highlight_attr[hlf] = hl_get_ui_attr(hlf, final_id,
- hlf == HLF_INACTIVE);
-
- if (highlight_attr[hlf] != highlight_attr_last[hlf]) {
- if (hlf == HLF_MSG) {
- clear_cmdline = true;
- }
- ui_call_hl_group_set(cstr_as_string((char *)hlf_names[hlf]),
- highlight_attr[hlf]);
- highlight_attr_last[hlf] = highlight_attr[hlf];
- }
- }
-
- //
- // Setup the user highlights
- //
- // Temporarily utilize 10 more hl entries:
- // 9 for User1-User9 combined with StatusLineNC
- // 1 for StatusLine default
- // Must to be in there simultaneously in case of table overflows in
- // get_attr_entry()
- ga_grow(&highlight_ga, 10);
- hlcnt = highlight_ga.ga_len;
- if (id_S == -1) {
- // Make sure id_S is always valid to simplify code below. Use the last entry
- memset(&HL_TABLE()[hlcnt + 9], 0, sizeof(struct hl_group));
- id_S = hlcnt + 10;
- }
- for (int i = 0; i < 9; i++) {
- snprintf(userhl, sizeof(userhl), "User%d", i + 1);
- id = syn_name2id(userhl);
- if (id == 0) {
- highlight_user[i] = 0;
- highlight_stlnc[i] = 0;
- } else {
- highlight_user[i] = syn_id2attr(id);
- combine_stl_hlt(id, id_S, id_SNC, hlcnt, i, HLF_SNC, highlight_stlnc);
- }
- }
- highlight_ga.ga_len = hlcnt;
-}
-
-
-/*
- * Handle command line completion for :highlight command.
- */
-void set_context_in_highlight_cmd(expand_T *xp, const char *arg)
-{
- // Default: expand group names.
- xp->xp_context = EXPAND_HIGHLIGHT;
- xp->xp_pattern = (char_u *)arg;
- include_link = 2;
- include_default = 1;
-
- // (part of) subcommand already typed
- if (*arg != NUL) {
- const char *p = (const char *)skiptowhite((const char_u *)arg);
- if (*p != NUL) { // Past "default" or group name.
- include_default = 0;
- if (strncmp("default", arg, p - arg) == 0) {
- arg = (const char *)skipwhite((const char_u *)p);
- xp->xp_pattern = (char_u *)arg;
- p = (const char *)skiptowhite((const char_u *)arg);
- }
- if (*p != NUL) { // past group name
- include_link = 0;
- if (arg[1] == 'i' && arg[0] == 'N') {
- highlight_list();
- }
- if (strncmp("link", arg, p - arg) == 0
- || strncmp("clear", arg, p - arg) == 0) {
- xp->xp_pattern = skipwhite((const char_u *)p);
- p = (const char *)skiptowhite(xp->xp_pattern);
- if (*p != NUL) { // Past first group name.
- xp->xp_pattern = skipwhite((const char_u *)p);
- p = (const char *)skiptowhite(xp->xp_pattern);
- }
- }
- if (*p != NUL) { // Past group name(s).
- xp->xp_context = EXPAND_NOTHING;
- }
- }
- }
- }
-}
-
-/*
- * List highlighting matches in a nice way.
- */
-static void highlight_list(void)
-{
- int i;
-
- for (i = 10; --i >= 0;) {
- highlight_list_two(i, HL_ATTR(HLF_D));
- }
- for (i = 40; --i >= 0;) {
- highlight_list_two(99, 0);
- }
-}
-
-static void highlight_list_two(int cnt, int attr)
-{
- msg_puts_attr(&("N \bI \b! \b"[cnt / 11]), attr);
- msg_clr_eos();
- ui_flush();
- os_delay(cnt == 99 ? 40L : (long)cnt * 50L, false);
-}
-
-
-/// Function given to ExpandGeneric() to obtain the list of group names.
-const char *get_highlight_name(expand_T *const xp, int idx)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- return get_highlight_name_ext(xp, idx, true);
-}
-
-
-/// Obtain a highlight group name.
-///
-/// @param skip_cleared if true don't return a cleared entry.
-const char *get_highlight_name_ext(expand_T *xp, int idx, bool skip_cleared)
- FUNC_ATTR_WARN_UNUSED_RESULT
-{
- if (idx < 0) {
- return NULL;
- }
-
- // Items are never removed from the table, skip the ones that were cleared.
- if (skip_cleared && idx < highlight_ga.ga_len && HL_TABLE()[idx].sg_cleared) {
- return "";
- }
-
- if (idx == highlight_ga.ga_len && include_none != 0) {
- return "none";
- } else if (idx == highlight_ga.ga_len + include_none
- && include_default != 0) {
- return "default";
- } else if (idx == highlight_ga.ga_len + include_none + include_default
- && include_link != 0) {
- return "link";
- } else if (idx == highlight_ga.ga_len + include_none + include_default + 1
- && include_link != 0) {
- return "clear";
- } else if (idx >= highlight_ga.ga_len) {
- return NULL;
- }
- return (const char *)HL_TABLE()[idx].sg_name;
-}
-
-color_name_table_T color_name_table[] = {
- // Colors from rgb.txt
- { "AliceBlue", RGB_(0xf0, 0xf8, 0xff) },
- { "AntiqueWhite", RGB_(0xfa, 0xeb, 0xd7) },
- { "AntiqueWhite1", RGB_(0xff, 0xef, 0xdb) },
- { "AntiqueWhite2", RGB_(0xee, 0xdf, 0xcc) },
- { "AntiqueWhite3", RGB_(0xcd, 0xc0, 0xb0) },
- { "AntiqueWhite4", RGB_(0x8b, 0x83, 0x78) },
- { "Aqua", RGB_(0x00, 0xff, 0xff) },
- { "Aquamarine", RGB_(0x7f, 0xff, 0xd4) },
- { "Aquamarine1", RGB_(0x7f, 0xff, 0xd4) },
- { "Aquamarine2", RGB_(0x76, 0xee, 0xc6) },
- { "Aquamarine3", RGB_(0x66, 0xcd, 0xaa) },
- { "Aquamarine4", RGB_(0x45, 0x8b, 0x74) },
- { "Azure", RGB_(0xf0, 0xff, 0xff) },
- { "Azure1", RGB_(0xf0, 0xff, 0xff) },
- { "Azure2", RGB_(0xe0, 0xee, 0xee) },
- { "Azure3", RGB_(0xc1, 0xcd, 0xcd) },
- { "Azure4", RGB_(0x83, 0x8b, 0x8b) },
- { "Beige", RGB_(0xf5, 0xf5, 0xdc) },
- { "Bisque", RGB_(0xff, 0xe4, 0xc4) },
- { "Bisque1", RGB_(0xff, 0xe4, 0xc4) },
- { "Bisque2", RGB_(0xee, 0xd5, 0xb7) },
- { "Bisque3", RGB_(0xcd, 0xb7, 0x9e) },
- { "Bisque4", RGB_(0x8b, 0x7d, 0x6b) },
- { "Black", RGB_(0x00, 0x00, 0x00) },
- { "BlanchedAlmond", RGB_(0xff, 0xeb, 0xcd) },
- { "Blue", RGB_(0x00, 0x00, 0xff) },
- { "Blue1", RGB_(0x0, 0x0, 0xff) },
- { "Blue2", RGB_(0x0, 0x0, 0xee) },
- { "Blue3", RGB_(0x0, 0x0, 0xcd) },
- { "Blue4", RGB_(0x0, 0x0, 0x8b) },
- { "BlueViolet", RGB_(0x8a, 0x2b, 0xe2) },
- { "Brown", RGB_(0xa5, 0x2a, 0x2a) },
- { "Brown1", RGB_(0xff, 0x40, 0x40) },
- { "Brown2", RGB_(0xee, 0x3b, 0x3b) },
- { "Brown3", RGB_(0xcd, 0x33, 0x33) },
- { "Brown4", RGB_(0x8b, 0x23, 0x23) },
- { "BurlyWood", RGB_(0xde, 0xb8, 0x87) },
- { "Burlywood1", RGB_(0xff, 0xd3, 0x9b) },
- { "Burlywood2", RGB_(0xee, 0xc5, 0x91) },
- { "Burlywood3", RGB_(0xcd, 0xaa, 0x7d) },
- { "Burlywood4", RGB_(0x8b, 0x73, 0x55) },
- { "CadetBlue", RGB_(0x5f, 0x9e, 0xa0) },
- { "CadetBlue1", RGB_(0x98, 0xf5, 0xff) },
- { "CadetBlue2", RGB_(0x8e, 0xe5, 0xee) },
- { "CadetBlue3", RGB_(0x7a, 0xc5, 0xcd) },
- { "CadetBlue4", RGB_(0x53, 0x86, 0x8b) },
- { "ChartReuse", RGB_(0x7f, 0xff, 0x00) },
- { "Chartreuse1", RGB_(0x7f, 0xff, 0x0) },
- { "Chartreuse2", RGB_(0x76, 0xee, 0x0) },
- { "Chartreuse3", RGB_(0x66, 0xcd, 0x0) },
- { "Chartreuse4", RGB_(0x45, 0x8b, 0x0) },
- { "Chocolate", RGB_(0xd2, 0x69, 0x1e) },
- { "Chocolate1", RGB_(0xff, 0x7f, 0x24) },
- { "Chocolate2", RGB_(0xee, 0x76, 0x21) },
- { "Chocolate3", RGB_(0xcd, 0x66, 0x1d) },
- { "Chocolate4", RGB_(0x8b, 0x45, 0x13) },
- { "Coral", RGB_(0xff, 0x7f, 0x50) },
- { "Coral1", RGB_(0xff, 0x72, 0x56) },
- { "Coral2", RGB_(0xee, 0x6a, 0x50) },
- { "Coral3", RGB_(0xcd, 0x5b, 0x45) },
- { "Coral4", RGB_(0x8b, 0x3e, 0x2f) },
- { "CornFlowerBlue", RGB_(0x64, 0x95, 0xed) },
- { "Cornsilk", RGB_(0xff, 0xf8, 0xdc) },
- { "Cornsilk1", RGB_(0xff, 0xf8, 0xdc) },
- { "Cornsilk2", RGB_(0xee, 0xe8, 0xcd) },
- { "Cornsilk3", RGB_(0xcd, 0xc8, 0xb1) },
- { "Cornsilk4", RGB_(0x8b, 0x88, 0x78) },
- { "Crimson", RGB_(0xdc, 0x14, 0x3c) },
- { "Cyan", RGB_(0x00, 0xff, 0xff) },
- { "Cyan1", RGB_(0x0, 0xff, 0xff) },
- { "Cyan2", RGB_(0x0, 0xee, 0xee) },
- { "Cyan3", RGB_(0x0, 0xcd, 0xcd) },
- { "Cyan4", RGB_(0x0, 0x8b, 0x8b) },
- { "DarkBlue", RGB_(0x00, 0x00, 0x8b) },
- { "DarkCyan", RGB_(0x00, 0x8b, 0x8b) },
- { "DarkGoldenRod", RGB_(0xb8, 0x86, 0x0b) },
- { "DarkGoldenrod1", RGB_(0xff, 0xb9, 0xf) },
- { "DarkGoldenrod2", RGB_(0xee, 0xad, 0xe) },
- { "DarkGoldenrod3", RGB_(0xcd, 0x95, 0xc) },
- { "DarkGoldenrod4", RGB_(0x8b, 0x65, 0x8) },
- { "DarkGray", RGB_(0xa9, 0xa9, 0xa9) },
- { "DarkGreen", RGB_(0x00, 0x64, 0x00) },
- { "DarkGrey", RGB_(0xa9, 0xa9, 0xa9) },
- { "DarkKhaki", RGB_(0xbd, 0xb7, 0x6b) },
- { "DarkMagenta", RGB_(0x8b, 0x00, 0x8b) },
- { "DarkOliveGreen", RGB_(0x55, 0x6b, 0x2f) },
- { "DarkOliveGreen1", RGB_(0xca, 0xff, 0x70) },
- { "DarkOliveGreen2", RGB_(0xbc, 0xee, 0x68) },
- { "DarkOliveGreen3", RGB_(0xa2, 0xcd, 0x5a) },
- { "DarkOliveGreen4", RGB_(0x6e, 0x8b, 0x3d) },
- { "DarkOrange", RGB_(0xff, 0x8c, 0x00) },
- { "DarkOrange1", RGB_(0xff, 0x7f, 0x0) },
- { "DarkOrange2", RGB_(0xee, 0x76, 0x0) },
- { "DarkOrange3", RGB_(0xcd, 0x66, 0x0) },
- { "DarkOrange4", RGB_(0x8b, 0x45, 0x0) },
- { "DarkOrchid", RGB_(0x99, 0x32, 0xcc) },
- { "DarkOrchid1", RGB_(0xbf, 0x3e, 0xff) },
- { "DarkOrchid2", RGB_(0xb2, 0x3a, 0xee) },
- { "DarkOrchid3", RGB_(0x9a, 0x32, 0xcd) },
- { "DarkOrchid4", RGB_(0x68, 0x22, 0x8b) },
- { "DarkRed", RGB_(0x8b, 0x00, 0x00) },
- { "DarkSalmon", RGB_(0xe9, 0x96, 0x7a) },
- { "DarkSeaGreen", RGB_(0x8f, 0xbc, 0x8f) },
- { "DarkSeaGreen1", RGB_(0xc1, 0xff, 0xc1) },
- { "DarkSeaGreen2", RGB_(0xb4, 0xee, 0xb4) },
- { "DarkSeaGreen3", RGB_(0x9b, 0xcd, 0x9b) },
- { "DarkSeaGreen4", RGB_(0x69, 0x8b, 0x69) },
- { "DarkSlateBlue", RGB_(0x48, 0x3d, 0x8b) },
- { "DarkSlateGray", RGB_(0x2f, 0x4f, 0x4f) },
- { "DarkSlateGray1", RGB_(0x97, 0xff, 0xff) },
- { "DarkSlateGray2", RGB_(0x8d, 0xee, 0xee) },
- { "DarkSlateGray3", RGB_(0x79, 0xcd, 0xcd) },
- { "DarkSlateGray4", RGB_(0x52, 0x8b, 0x8b) },
- { "DarkSlateGrey", RGB_(0x2f, 0x4f, 0x4f) },
- { "DarkTurquoise", RGB_(0x00, 0xce, 0xd1) },
- { "DarkViolet", RGB_(0x94, 0x00, 0xd3) },
- { "DarkYellow", RGB_(0xbb, 0xbb, 0x00) },
- { "DeepPink", RGB_(0xff, 0x14, 0x93) },
- { "DeepPink1", RGB_(0xff, 0x14, 0x93) },
- { "DeepPink2", RGB_(0xee, 0x12, 0x89) },
- { "DeepPink3", RGB_(0xcd, 0x10, 0x76) },
- { "DeepPink4", RGB_(0x8b, 0xa, 0x50) },
- { "DeepSkyBlue", RGB_(0x00, 0xbf, 0xff) },
- { "DeepSkyBlue1", RGB_(0x0, 0xbf, 0xff) },
- { "DeepSkyBlue2", RGB_(0x0, 0xb2, 0xee) },
- { "DeepSkyBlue3", RGB_(0x0, 0x9a, 0xcd) },
- { "DeepSkyBlue4", RGB_(0x0, 0x68, 0x8b) },
- { "DimGray", RGB_(0x69, 0x69, 0x69) },
- { "DimGrey", RGB_(0x69, 0x69, 0x69) },
- { "DodgerBlue", RGB_(0x1e, 0x90, 0xff) },
- { "DodgerBlue1", RGB_(0x1e, 0x90, 0xff) },
- { "DodgerBlue2", RGB_(0x1c, 0x86, 0xee) },
- { "DodgerBlue3", RGB_(0x18, 0x74, 0xcd) },
- { "DodgerBlue4", RGB_(0x10, 0x4e, 0x8b) },
- { "Firebrick", RGB_(0xb2, 0x22, 0x22) },
- { "Firebrick1", RGB_(0xff, 0x30, 0x30) },
- { "Firebrick2", RGB_(0xee, 0x2c, 0x2c) },
- { "Firebrick3", RGB_(0xcd, 0x26, 0x26) },
- { "Firebrick4", RGB_(0x8b, 0x1a, 0x1a) },
- { "FloralWhite", RGB_(0xff, 0xfa, 0xf0) },
- { "ForestGreen", RGB_(0x22, 0x8b, 0x22) },
- { "Fuchsia", RGB_(0xff, 0x00, 0xff) },
- { "Gainsboro", RGB_(0xdc, 0xdc, 0xdc) },
- { "GhostWhite", RGB_(0xf8, 0xf8, 0xff) },
- { "Gold", RGB_(0xff, 0xd7, 0x00) },
- { "Gold1", RGB_(0xff, 0xd7, 0x0) },
- { "Gold2", RGB_(0xee, 0xc9, 0x0) },
- { "Gold3", RGB_(0xcd, 0xad, 0x0) },
- { "Gold4", RGB_(0x8b, 0x75, 0x0) },
- { "GoldenRod", RGB_(0xda, 0xa5, 0x20) },
- { "Goldenrod1", RGB_(0xff, 0xc1, 0x25) },
- { "Goldenrod2", RGB_(0xee, 0xb4, 0x22) },
- { "Goldenrod3", RGB_(0xcd, 0x9b, 0x1d) },
- { "Goldenrod4", RGB_(0x8b, 0x69, 0x14) },
- { "Gray", RGB_(0x80, 0x80, 0x80) },
- { "Gray0", RGB_(0x0, 0x0, 0x0) },
- { "Gray1", RGB_(0x3, 0x3, 0x3) },
- { "Gray10", RGB_(0x1a, 0x1a, 0x1a) },
- { "Gray100", RGB_(0xff, 0xff, 0xff) },
- { "Gray11", RGB_(0x1c, 0x1c, 0x1c) },
- { "Gray12", RGB_(0x1f, 0x1f, 0x1f) },
- { "Gray13", RGB_(0x21, 0x21, 0x21) },
- { "Gray14", RGB_(0x24, 0x24, 0x24) },
- { "Gray15", RGB_(0x26, 0x26, 0x26) },
- { "Gray16", RGB_(0x29, 0x29, 0x29) },
- { "Gray17", RGB_(0x2b, 0x2b, 0x2b) },
- { "Gray18", RGB_(0x2e, 0x2e, 0x2e) },
- { "Gray19", RGB_(0x30, 0x30, 0x30) },
- { "Gray2", RGB_(0x5, 0x5, 0x5) },
- { "Gray20", RGB_(0x33, 0x33, 0x33) },
- { "Gray21", RGB_(0x36, 0x36, 0x36) },
- { "Gray22", RGB_(0x38, 0x38, 0x38) },
- { "Gray23", RGB_(0x3b, 0x3b, 0x3b) },
- { "Gray24", RGB_(0x3d, 0x3d, 0x3d) },
- { "Gray25", RGB_(0x40, 0x40, 0x40) },
- { "Gray26", RGB_(0x42, 0x42, 0x42) },
- { "Gray27", RGB_(0x45, 0x45, 0x45) },
- { "Gray28", RGB_(0x47, 0x47, 0x47) },
- { "Gray29", RGB_(0x4a, 0x4a, 0x4a) },
- { "Gray3", RGB_(0x8, 0x8, 0x8) },
- { "Gray30", RGB_(0x4d, 0x4d, 0x4d) },
- { "Gray31", RGB_(0x4f, 0x4f, 0x4f) },
- { "Gray32", RGB_(0x52, 0x52, 0x52) },
- { "Gray33", RGB_(0x54, 0x54, 0x54) },
- { "Gray34", RGB_(0x57, 0x57, 0x57) },
- { "Gray35", RGB_(0x59, 0x59, 0x59) },
- { "Gray36", RGB_(0x5c, 0x5c, 0x5c) },
- { "Gray37", RGB_(0x5e, 0x5e, 0x5e) },
- { "Gray38", RGB_(0x61, 0x61, 0x61) },
- { "Gray39", RGB_(0x63, 0x63, 0x63) },
- { "Gray4", RGB_(0xa, 0xa, 0xa) },
- { "Gray40", RGB_(0x66, 0x66, 0x66) },
- { "Gray41", RGB_(0x69, 0x69, 0x69) },
- { "Gray42", RGB_(0x6b, 0x6b, 0x6b) },
- { "Gray43", RGB_(0x6e, 0x6e, 0x6e) },
- { "Gray44", RGB_(0x70, 0x70, 0x70) },
- { "Gray45", RGB_(0x73, 0x73, 0x73) },
- { "Gray46", RGB_(0x75, 0x75, 0x75) },
- { "Gray47", RGB_(0x78, 0x78, 0x78) },
- { "Gray48", RGB_(0x7a, 0x7a, 0x7a) },
- { "Gray49", RGB_(0x7d, 0x7d, 0x7d) },
- { "Gray5", RGB_(0xd, 0xd, 0xd) },
- { "Gray50", RGB_(0x7f, 0x7f, 0x7f) },
- { "Gray51", RGB_(0x82, 0x82, 0x82) },
- { "Gray52", RGB_(0x85, 0x85, 0x85) },
- { "Gray53", RGB_(0x87, 0x87, 0x87) },
- { "Gray54", RGB_(0x8a, 0x8a, 0x8a) },
- { "Gray55", RGB_(0x8c, 0x8c, 0x8c) },
- { "Gray56", RGB_(0x8f, 0x8f, 0x8f) },
- { "Gray57", RGB_(0x91, 0x91, 0x91) },
- { "Gray58", RGB_(0x94, 0x94, 0x94) },
- { "Gray59", RGB_(0x96, 0x96, 0x96) },
- { "Gray6", RGB_(0xf, 0xf, 0xf) },
- { "Gray60", RGB_(0x99, 0x99, 0x99) },
- { "Gray61", RGB_(0x9c, 0x9c, 0x9c) },
- { "Gray62", RGB_(0x9e, 0x9e, 0x9e) },
- { "Gray63", RGB_(0xa1, 0xa1, 0xa1) },
- { "Gray64", RGB_(0xa3, 0xa3, 0xa3) },
- { "Gray65", RGB_(0xa6, 0xa6, 0xa6) },
- { "Gray66", RGB_(0xa8, 0xa8, 0xa8) },
- { "Gray67", RGB_(0xab, 0xab, 0xab) },
- { "Gray68", RGB_(0xad, 0xad, 0xad) },
- { "Gray69", RGB_(0xb0, 0xb0, 0xb0) },
- { "Gray7", RGB_(0x12, 0x12, 0x12) },
- { "Gray70", RGB_(0xb3, 0xb3, 0xb3) },
- { "Gray71", RGB_(0xb5, 0xb5, 0xb5) },
- { "Gray72", RGB_(0xb8, 0xb8, 0xb8) },
- { "Gray73", RGB_(0xba, 0xba, 0xba) },
- { "Gray74", RGB_(0xbd, 0xbd, 0xbd) },
- { "Gray75", RGB_(0xbf, 0xbf, 0xbf) },
- { "Gray76", RGB_(0xc2, 0xc2, 0xc2) },
- { "Gray77", RGB_(0xc4, 0xc4, 0xc4) },
- { "Gray78", RGB_(0xc7, 0xc7, 0xc7) },
- { "Gray79", RGB_(0xc9, 0xc9, 0xc9) },
- { "Gray8", RGB_(0x14, 0x14, 0x14) },
- { "Gray80", RGB_(0xcc, 0xcc, 0xcc) },
- { "Gray81", RGB_(0xcf, 0xcf, 0xcf) },
- { "Gray82", RGB_(0xd1, 0xd1, 0xd1) },
- { "Gray83", RGB_(0xd4, 0xd4, 0xd4) },
- { "Gray84", RGB_(0xd6, 0xd6, 0xd6) },
- { "Gray85", RGB_(0xd9, 0xd9, 0xd9) },
- { "Gray86", RGB_(0xdb, 0xdb, 0xdb) },
- { "Gray87", RGB_(0xde, 0xde, 0xde) },
- { "Gray88", RGB_(0xe0, 0xe0, 0xe0) },
- { "Gray89", RGB_(0xe3, 0xe3, 0xe3) },
- { "Gray9", RGB_(0x17, 0x17, 0x17) },
- { "Gray90", RGB_(0xe5, 0xe5, 0xe5) },
- { "Gray91", RGB_(0xe8, 0xe8, 0xe8) },
- { "Gray92", RGB_(0xeb, 0xeb, 0xeb) },
- { "Gray93", RGB_(0xed, 0xed, 0xed) },
- { "Gray94", RGB_(0xf0, 0xf0, 0xf0) },
- { "Gray95", RGB_(0xf2, 0xf2, 0xf2) },
- { "Gray96", RGB_(0xf5, 0xf5, 0xf5) },
- { "Gray97", RGB_(0xf7, 0xf7, 0xf7) },
- { "Gray98", RGB_(0xfa, 0xfa, 0xfa) },
- { "Gray99", RGB_(0xfc, 0xfc, 0xfc) },
- { "Green", RGB_(0x00, 0x80, 0x00) },
- { "Green1", RGB_(0x0, 0xff, 0x0) },
- { "Green2", RGB_(0x0, 0xee, 0x0) },
- { "Green3", RGB_(0x0, 0xcd, 0x0) },
- { "Green4", RGB_(0x0, 0x8b, 0x0) },
- { "GreenYellow", RGB_(0xad, 0xff, 0x2f) },
- { "Grey", RGB_(0x80, 0x80, 0x80) },
- { "Grey0", RGB_(0x0, 0x0, 0x0) },
- { "Grey1", RGB_(0x3, 0x3, 0x3) },
- { "Grey10", RGB_(0x1a, 0x1a, 0x1a) },
- { "Grey100", RGB_(0xff, 0xff, 0xff) },
- { "Grey11", RGB_(0x1c, 0x1c, 0x1c) },
- { "Grey12", RGB_(0x1f, 0x1f, 0x1f) },
- { "Grey13", RGB_(0x21, 0x21, 0x21) },
- { "Grey14", RGB_(0x24, 0x24, 0x24) },
- { "Grey15", RGB_(0x26, 0x26, 0x26) },
- { "Grey16", RGB_(0x29, 0x29, 0x29) },
- { "Grey17", RGB_(0x2b, 0x2b, 0x2b) },
- { "Grey18", RGB_(0x2e, 0x2e, 0x2e) },
- { "Grey19", RGB_(0x30, 0x30, 0x30) },
- { "Grey2", RGB_(0x5, 0x5, 0x5) },
- { "Grey20", RGB_(0x33, 0x33, 0x33) },
- { "Grey21", RGB_(0x36, 0x36, 0x36) },
- { "Grey22", RGB_(0x38, 0x38, 0x38) },
- { "Grey23", RGB_(0x3b, 0x3b, 0x3b) },
- { "Grey24", RGB_(0x3d, 0x3d, 0x3d) },
- { "Grey25", RGB_(0x40, 0x40, 0x40) },
- { "Grey26", RGB_(0x42, 0x42, 0x42) },
- { "Grey27", RGB_(0x45, 0x45, 0x45) },
- { "Grey28", RGB_(0x47, 0x47, 0x47) },
- { "Grey29", RGB_(0x4a, 0x4a, 0x4a) },
- { "Grey3", RGB_(0x8, 0x8, 0x8) },
- { "Grey30", RGB_(0x4d, 0x4d, 0x4d) },
- { "Grey31", RGB_(0x4f, 0x4f, 0x4f) },
- { "Grey32", RGB_(0x52, 0x52, 0x52) },
- { "Grey33", RGB_(0x54, 0x54, 0x54) },
- { "Grey34", RGB_(0x57, 0x57, 0x57) },
- { "Grey35", RGB_(0x59, 0x59, 0x59) },
- { "Grey36", RGB_(0x5c, 0x5c, 0x5c) },
- { "Grey37", RGB_(0x5e, 0x5e, 0x5e) },
- { "Grey38", RGB_(0x61, 0x61, 0x61) },
- { "Grey39", RGB_(0x63, 0x63, 0x63) },
- { "Grey4", RGB_(0xa, 0xa, 0xa) },
- { "Grey40", RGB_(0x66, 0x66, 0x66) },
- { "Grey41", RGB_(0x69, 0x69, 0x69) },
- { "Grey42", RGB_(0x6b, 0x6b, 0x6b) },
- { "Grey43", RGB_(0x6e, 0x6e, 0x6e) },
- { "Grey44", RGB_(0x70, 0x70, 0x70) },
- { "Grey45", RGB_(0x73, 0x73, 0x73) },
- { "Grey46", RGB_(0x75, 0x75, 0x75) },
- { "Grey47", RGB_(0x78, 0x78, 0x78) },
- { "Grey48", RGB_(0x7a, 0x7a, 0x7a) },
- { "Grey49", RGB_(0x7d, 0x7d, 0x7d) },
- { "Grey5", RGB_(0xd, 0xd, 0xd) },
- { "Grey50", RGB_(0x7f, 0x7f, 0x7f) },
- { "Grey51", RGB_(0x82, 0x82, 0x82) },
- { "Grey52", RGB_(0x85, 0x85, 0x85) },
- { "Grey53", RGB_(0x87, 0x87, 0x87) },
- { "Grey54", RGB_(0x8a, 0x8a, 0x8a) },
- { "Grey55", RGB_(0x8c, 0x8c, 0x8c) },
- { "Grey56", RGB_(0x8f, 0x8f, 0x8f) },
- { "Grey57", RGB_(0x91, 0x91, 0x91) },
- { "Grey58", RGB_(0x94, 0x94, 0x94) },
- { "Grey59", RGB_(0x96, 0x96, 0x96) },
- { "Grey6", RGB_(0xf, 0xf, 0xf) },
- { "Grey60", RGB_(0x99, 0x99, 0x99) },
- { "Grey61", RGB_(0x9c, 0x9c, 0x9c) },
- { "Grey62", RGB_(0x9e, 0x9e, 0x9e) },
- { "Grey63", RGB_(0xa1, 0xa1, 0xa1) },
- { "Grey64", RGB_(0xa3, 0xa3, 0xa3) },
- { "Grey65", RGB_(0xa6, 0xa6, 0xa6) },
- { "Grey66", RGB_(0xa8, 0xa8, 0xa8) },
- { "Grey67", RGB_(0xab, 0xab, 0xab) },
- { "Grey68", RGB_(0xad, 0xad, 0xad) },
- { "Grey69", RGB_(0xb0, 0xb0, 0xb0) },
- { "Grey7", RGB_(0x12, 0x12, 0x12) },
- { "Grey70", RGB_(0xb3, 0xb3, 0xb3) },
- { "Grey71", RGB_(0xb5, 0xb5, 0xb5) },
- { "Grey72", RGB_(0xb8, 0xb8, 0xb8) },
- { "Grey73", RGB_(0xba, 0xba, 0xba) },
- { "Grey74", RGB_(0xbd, 0xbd, 0xbd) },
- { "Grey75", RGB_(0xbf, 0xbf, 0xbf) },
- { "Grey76", RGB_(0xc2, 0xc2, 0xc2) },
- { "Grey77", RGB_(0xc4, 0xc4, 0xc4) },
- { "Grey78", RGB_(0xc7, 0xc7, 0xc7) },
- { "Grey79", RGB_(0xc9, 0xc9, 0xc9) },
- { "Grey8", RGB_(0x14, 0x14, 0x14) },
- { "Grey80", RGB_(0xcc, 0xcc, 0xcc) },
- { "Grey81", RGB_(0xcf, 0xcf, 0xcf) },
- { "Grey82", RGB_(0xd1, 0xd1, 0xd1) },
- { "Grey83", RGB_(0xd4, 0xd4, 0xd4) },
- { "Grey84", RGB_(0xd6, 0xd6, 0xd6) },
- { "Grey85", RGB_(0xd9, 0xd9, 0xd9) },
- { "Grey86", RGB_(0xdb, 0xdb, 0xdb) },
- { "Grey87", RGB_(0xde, 0xde, 0xde) },
- { "Grey88", RGB_(0xe0, 0xe0, 0xe0) },
- { "Grey89", RGB_(0xe3, 0xe3, 0xe3) },
- { "Grey9", RGB_(0x17, 0x17, 0x17) },
- { "Grey90", RGB_(0xe5, 0xe5, 0xe5) },
- { "Grey91", RGB_(0xe8, 0xe8, 0xe8) },
- { "Grey92", RGB_(0xeb, 0xeb, 0xeb) },
- { "Grey93", RGB_(0xed, 0xed, 0xed) },
- { "Grey94", RGB_(0xf0, 0xf0, 0xf0) },
- { "Grey95", RGB_(0xf2, 0xf2, 0xf2) },
- { "Grey96", RGB_(0xf5, 0xf5, 0xf5) },
- { "Grey97", RGB_(0xf7, 0xf7, 0xf7) },
- { "Grey98", RGB_(0xfa, 0xfa, 0xfa) },
- { "Grey99", RGB_(0xfc, 0xfc, 0xfc) },
- { "Honeydew", RGB_(0xf0, 0xff, 0xf0) },
- { "Honeydew1", RGB_(0xf0, 0xff, 0xf0) },
- { "Honeydew2", RGB_(0xe0, 0xee, 0xe0) },
- { "Honeydew3", RGB_(0xc1, 0xcd, 0xc1) },
- { "Honeydew4", RGB_(0x83, 0x8b, 0x83) },
- { "HotPink", RGB_(0xff, 0x69, 0xb4) },
- { "HotPink1", RGB_(0xff, 0x6e, 0xb4) },
- { "HotPink2", RGB_(0xee, 0x6a, 0xa7) },
- { "HotPink3", RGB_(0xcd, 0x60, 0x90) },
- { "HotPink4", RGB_(0x8b, 0x3a, 0x62) },
- { "IndianRed", RGB_(0xcd, 0x5c, 0x5c) },
- { "IndianRed1", RGB_(0xff, 0x6a, 0x6a) },
- { "IndianRed2", RGB_(0xee, 0x63, 0x63) },
- { "IndianRed3", RGB_(0xcd, 0x55, 0x55) },
- { "IndianRed4", RGB_(0x8b, 0x3a, 0x3a) },
- { "Indigo", RGB_(0x4b, 0x00, 0x82) },
- { "Ivory", RGB_(0xff, 0xff, 0xf0) },
- { "Ivory1", RGB_(0xff, 0xff, 0xf0) },
- { "Ivory2", RGB_(0xee, 0xee, 0xe0) },
- { "Ivory3", RGB_(0xcd, 0xcd, 0xc1) },
- { "Ivory4", RGB_(0x8b, 0x8b, 0x83) },
- { "Khaki", RGB_(0xf0, 0xe6, 0x8c) },
- { "Khaki1", RGB_(0xff, 0xf6, 0x8f) },
- { "Khaki2", RGB_(0xee, 0xe6, 0x85) },
- { "Khaki3", RGB_(0xcd, 0xc6, 0x73) },
- { "Khaki4", RGB_(0x8b, 0x86, 0x4e) },
- { "Lavender", RGB_(0xe6, 0xe6, 0xfa) },
- { "LavenderBlush", RGB_(0xff, 0xf0, 0xf5) },
- { "LavenderBlush1", RGB_(0xff, 0xf0, 0xf5) },
- { "LavenderBlush2", RGB_(0xee, 0xe0, 0xe5) },
- { "LavenderBlush3", RGB_(0xcd, 0xc1, 0xc5) },
- { "LavenderBlush4", RGB_(0x8b, 0x83, 0x86) },
- { "LawnGreen", RGB_(0x7c, 0xfc, 0x00) },
- { "LemonChiffon", RGB_(0xff, 0xfa, 0xcd) },
- { "LemonChiffon1", RGB_(0xff, 0xfa, 0xcd) },
- { "LemonChiffon2", RGB_(0xee, 0xe9, 0xbf) },
- { "LemonChiffon3", RGB_(0xcd, 0xc9, 0xa5) },
- { "LemonChiffon4", RGB_(0x8b, 0x89, 0x70) },
- { "LightBlue", RGB_(0xad, 0xd8, 0xe6) },
- { "LightBlue1", RGB_(0xbf, 0xef, 0xff) },
- { "LightBlue2", RGB_(0xb2, 0xdf, 0xee) },
- { "LightBlue3", RGB_(0x9a, 0xc0, 0xcd) },
- { "LightBlue4", RGB_(0x68, 0x83, 0x8b) },
- { "LightCoral", RGB_(0xf0, 0x80, 0x80) },
- { "LightCyan", RGB_(0xe0, 0xff, 0xff) },
- { "LightCyan1", RGB_(0xe0, 0xff, 0xff) },
- { "LightCyan2", RGB_(0xd1, 0xee, 0xee) },
- { "LightCyan3", RGB_(0xb4, 0xcd, 0xcd) },
- { "LightCyan4", RGB_(0x7a, 0x8b, 0x8b) },
- { "LightGoldenrod", RGB_(0xee, 0xdd, 0x82) },
- { "LightGoldenrod1", RGB_(0xff, 0xec, 0x8b) },
- { "LightGoldenrod2", RGB_(0xee, 0xdc, 0x82) },
- { "LightGoldenrod3", RGB_(0xcd, 0xbe, 0x70) },
- { "LightGoldenrod4", RGB_(0x8b, 0x81, 0x4c) },
- { "LightGoldenRodYellow", RGB_(0xfa, 0xfa, 0xd2) },
- { "LightGray", RGB_(0xd3, 0xd3, 0xd3) },
- { "LightGreen", RGB_(0x90, 0xee, 0x90) },
- { "LightGrey", RGB_(0xd3, 0xd3, 0xd3) },
- { "LightMagenta", RGB_(0xff, 0xbb, 0xff) },
- { "LightPink", RGB_(0xff, 0xb6, 0xc1) },
- { "LightPink1", RGB_(0xff, 0xae, 0xb9) },
- { "LightPink2", RGB_(0xee, 0xa2, 0xad) },
- { "LightPink3", RGB_(0xcd, 0x8c, 0x95) },
- { "LightPink4", RGB_(0x8b, 0x5f, 0x65) },
- { "LightRed", RGB_(0xff, 0xbb, 0xbb) },
- { "LightSalmon", RGB_(0xff, 0xa0, 0x7a) },
- { "LightSalmon1", RGB_(0xff, 0xa0, 0x7a) },
- { "LightSalmon2", RGB_(0xee, 0x95, 0x72) },
- { "LightSalmon3", RGB_(0xcd, 0x81, 0x62) },
- { "LightSalmon4", RGB_(0x8b, 0x57, 0x42) },
- { "LightSeaGreen", RGB_(0x20, 0xb2, 0xaa) },
- { "LightSkyBlue", RGB_(0x87, 0xce, 0xfa) },
- { "LightSkyBlue1", RGB_(0xb0, 0xe2, 0xff) },
- { "LightSkyBlue2", RGB_(0xa4, 0xd3, 0xee) },
- { "LightSkyBlue3", RGB_(0x8d, 0xb6, 0xcd) },
- { "LightSkyBlue4", RGB_(0x60, 0x7b, 0x8b) },
- { "LightSlateBlue", RGB_(0x84, 0x70, 0xff) },
- { "LightSlateGray", RGB_(0x77, 0x88, 0x99) },
- { "LightSlateGrey", RGB_(0x77, 0x88, 0x99) },
- { "LightSteelBlue", RGB_(0xb0, 0xc4, 0xde) },
- { "LightSteelBlue1", RGB_(0xca, 0xe1, 0xff) },
- { "LightSteelBlue2", RGB_(0xbc, 0xd2, 0xee) },
- { "LightSteelBlue3", RGB_(0xa2, 0xb5, 0xcd) },
- { "LightSteelBlue4", RGB_(0x6e, 0x7b, 0x8b) },
- { "LightYellow", RGB_(0xff, 0xff, 0xe0) },
- { "LightYellow1", RGB_(0xff, 0xff, 0xe0) },
- { "LightYellow2", RGB_(0xee, 0xee, 0xd1) },
- { "LightYellow3", RGB_(0xcd, 0xcd, 0xb4) },
- { "LightYellow4", RGB_(0x8b, 0x8b, 0x7a) },
- { "Lime", RGB_(0x00, 0xff, 0x00) },
- { "LimeGreen", RGB_(0x32, 0xcd, 0x32) },
- { "Linen", RGB_(0xfa, 0xf0, 0xe6) },
- { "Magenta", RGB_(0xff, 0x00, 0xff) },
- { "Magenta1", RGB_(0xff, 0x0, 0xff) },
- { "Magenta2", RGB_(0xee, 0x0, 0xee) },
- { "Magenta3", RGB_(0xcd, 0x0, 0xcd) },
- { "Magenta4", RGB_(0x8b, 0x0, 0x8b) },
- { "Maroon", RGB_(0x80, 0x00, 0x00) },
- { "Maroon1", RGB_(0xff, 0x34, 0xb3) },
- { "Maroon2", RGB_(0xee, 0x30, 0xa7) },
- { "Maroon3", RGB_(0xcd, 0x29, 0x90) },
- { "Maroon4", RGB_(0x8b, 0x1c, 0x62) },
- { "MediumAquamarine", RGB_(0x66, 0xcd, 0xaa) },
- { "MediumBlue", RGB_(0x00, 0x00, 0xcd) },
- { "MediumOrchid", RGB_(0xba, 0x55, 0xd3) },
- { "MediumOrchid1", RGB_(0xe0, 0x66, 0xff) },
- { "MediumOrchid2", RGB_(0xd1, 0x5f, 0xee) },
- { "MediumOrchid3", RGB_(0xb4, 0x52, 0xcd) },
- { "MediumOrchid4", RGB_(0x7a, 0x37, 0x8b) },
- { "MediumPurple", RGB_(0x93, 0x70, 0xdb) },
- { "MediumPurple1", RGB_(0xab, 0x82, 0xff) },
- { "MediumPurple2", RGB_(0x9f, 0x79, 0xee) },
- { "MediumPurple3", RGB_(0x89, 0x68, 0xcd) },
- { "MediumPurple4", RGB_(0x5d, 0x47, 0x8b) },
- { "MediumSeaGreen", RGB_(0x3c, 0xb3, 0x71) },
- { "MediumSlateBlue", RGB_(0x7b, 0x68, 0xee) },
- { "MediumSpringGreen", RGB_(0x00, 0xfa, 0x9a) },
- { "MediumTurquoise", RGB_(0x48, 0xd1, 0xcc) },
- { "MediumVioletRed", RGB_(0xc7, 0x15, 0x85) },
- { "MidnightBlue", RGB_(0x19, 0x19, 0x70) },
- { "MintCream", RGB_(0xf5, 0xff, 0xfa) },
- { "MistyRose", RGB_(0xff, 0xe4, 0xe1) },
- { "MistyRose1", RGB_(0xff, 0xe4, 0xe1) },
- { "MistyRose2", RGB_(0xee, 0xd5, 0xd2) },
- { "MistyRose3", RGB_(0xcd, 0xb7, 0xb5) },
- { "MistyRose4", RGB_(0x8b, 0x7d, 0x7b) },
- { "Moccasin", RGB_(0xff, 0xe4, 0xb5) },
- { "NavajoWhite", RGB_(0xff, 0xde, 0xad) },
- { "NavajoWhite1", RGB_(0xff, 0xde, 0xad) },
- { "NavajoWhite2", RGB_(0xee, 0xcf, 0xa1) },
- { "NavajoWhite3", RGB_(0xcd, 0xb3, 0x8b) },
- { "NavajoWhite4", RGB_(0x8b, 0x79, 0x5e) },
- { "Navy", RGB_(0x00, 0x00, 0x80) },
- { "NavyBlue", RGB_(0x0, 0x0, 0x80) },
- { "OldLace", RGB_(0xfd, 0xf5, 0xe6) },
- { "Olive", RGB_(0x80, 0x80, 0x00) },
- { "OliveDrab", RGB_(0x6b, 0x8e, 0x23) },
- { "OliveDrab1", RGB_(0xc0, 0xff, 0x3e) },
- { "OliveDrab2", RGB_(0xb3, 0xee, 0x3a) },
- { "OliveDrab3", RGB_(0x9a, 0xcd, 0x32) },
- { "OliveDrab4", RGB_(0x69, 0x8b, 0x22) },
- { "Orange", RGB_(0xff, 0xa5, 0x00) },
- { "Orange1", RGB_(0xff, 0xa5, 0x0) },
- { "Orange2", RGB_(0xee, 0x9a, 0x0) },
- { "Orange3", RGB_(0xcd, 0x85, 0x0) },
- { "Orange4", RGB_(0x8b, 0x5a, 0x0) },
- { "OrangeRed", RGB_(0xff, 0x45, 0x00) },
- { "OrangeRed1", RGB_(0xff, 0x45, 0x0) },
- { "OrangeRed2", RGB_(0xee, 0x40, 0x0) },
- { "OrangeRed3", RGB_(0xcd, 0x37, 0x0) },
- { "OrangeRed4", RGB_(0x8b, 0x25, 0x0) },
- { "Orchid", RGB_(0xda, 0x70, 0xd6) },
- { "Orchid1", RGB_(0xff, 0x83, 0xfa) },
- { "Orchid2", RGB_(0xee, 0x7a, 0xe9) },
- { "Orchid3", RGB_(0xcd, 0x69, 0xc9) },
- { "Orchid4", RGB_(0x8b, 0x47, 0x89) },
- { "PaleGoldenRod", RGB_(0xee, 0xe8, 0xaa) },
- { "PaleGreen", RGB_(0x98, 0xfb, 0x98) },
- { "PaleGreen1", RGB_(0x9a, 0xff, 0x9a) },
- { "PaleGreen2", RGB_(0x90, 0xee, 0x90) },
- { "PaleGreen3", RGB_(0x7c, 0xcd, 0x7c) },
- { "PaleGreen4", RGB_(0x54, 0x8b, 0x54) },
- { "PaleTurquoise", RGB_(0xaf, 0xee, 0xee) },
- { "PaleTurquoise1", RGB_(0xbb, 0xff, 0xff) },
- { "PaleTurquoise2", RGB_(0xae, 0xee, 0xee) },
- { "PaleTurquoise3", RGB_(0x96, 0xcd, 0xcd) },
- { "PaleTurquoise4", RGB_(0x66, 0x8b, 0x8b) },
- { "PaleVioletRed", RGB_(0xdb, 0x70, 0x93) },
- { "PaleVioletRed1", RGB_(0xff, 0x82, 0xab) },
- { "PaleVioletRed2", RGB_(0xee, 0x79, 0x9f) },
- { "PaleVioletRed3", RGB_(0xcd, 0x68, 0x89) },
- { "PaleVioletRed4", RGB_(0x8b, 0x47, 0x5d) },
- { "PapayaWhip", RGB_(0xff, 0xef, 0xd5) },
- { "PeachPuff", RGB_(0xff, 0xda, 0xb9) },
- { "PeachPuff1", RGB_(0xff, 0xda, 0xb9) },
- { "PeachPuff2", RGB_(0xee, 0xcb, 0xad) },
- { "PeachPuff3", RGB_(0xcd, 0xaf, 0x95) },
- { "PeachPuff4", RGB_(0x8b, 0x77, 0x65) },
- { "Peru", RGB_(0xcd, 0x85, 0x3f) },
- { "Pink", RGB_(0xff, 0xc0, 0xcb) },
- { "Pink1", RGB_(0xff, 0xb5, 0xc5) },
- { "Pink2", RGB_(0xee, 0xa9, 0xb8) },
- { "Pink3", RGB_(0xcd, 0x91, 0x9e) },
- { "Pink4", RGB_(0x8b, 0x63, 0x6c) },
- { "Plum", RGB_(0xdd, 0xa0, 0xdd) },
- { "Plum1", RGB_(0xff, 0xbb, 0xff) },
- { "Plum2", RGB_(0xee, 0xae, 0xee) },
- { "Plum3", RGB_(0xcd, 0x96, 0xcd) },
- { "Plum4", RGB_(0x8b, 0x66, 0x8b) },
- { "PowderBlue", RGB_(0xb0, 0xe0, 0xe6) },
- { "Purple", RGB_(0x80, 0x00, 0x80) },
- { "Purple1", RGB_(0x9b, 0x30, 0xff) },
- { "Purple2", RGB_(0x91, 0x2c, 0xee) },
- { "Purple3", RGB_(0x7d, 0x26, 0xcd) },
- { "Purple4", RGB_(0x55, 0x1a, 0x8b) },
- { "RebeccaPurple", RGB_(0x66, 0x33, 0x99) },
- { "Red", RGB_(0xff, 0x00, 0x00) },
- { "Red1", RGB_(0xff, 0x0, 0x0) },
- { "Red2", RGB_(0xee, 0x0, 0x0) },
- { "Red3", RGB_(0xcd, 0x0, 0x0) },
- { "Red4", RGB_(0x8b, 0x0, 0x0) },
- { "RosyBrown", RGB_(0xbc, 0x8f, 0x8f) },
- { "RosyBrown1", RGB_(0xff, 0xc1, 0xc1) },
- { "RosyBrown2", RGB_(0xee, 0xb4, 0xb4) },
- { "RosyBrown3", RGB_(0xcd, 0x9b, 0x9b) },
- { "RosyBrown4", RGB_(0x8b, 0x69, 0x69) },
- { "RoyalBlue", RGB_(0x41, 0x69, 0xe1) },
- { "RoyalBlue1", RGB_(0x48, 0x76, 0xff) },
- { "RoyalBlue2", RGB_(0x43, 0x6e, 0xee) },
- { "RoyalBlue3", RGB_(0x3a, 0x5f, 0xcd) },
- { "RoyalBlue4", RGB_(0x27, 0x40, 0x8b) },
- { "SaddleBrown", RGB_(0x8b, 0x45, 0x13) },
- { "Salmon", RGB_(0xfa, 0x80, 0x72) },
- { "Salmon1", RGB_(0xff, 0x8c, 0x69) },
- { "Salmon2", RGB_(0xee, 0x82, 0x62) },
- { "Salmon3", RGB_(0xcd, 0x70, 0x54) },
- { "Salmon4", RGB_(0x8b, 0x4c, 0x39) },
- { "SandyBrown", RGB_(0xf4, 0xa4, 0x60) },
- { "SeaGreen", RGB_(0x2e, 0x8b, 0x57) },
- { "SeaGreen1", RGB_(0x54, 0xff, 0x9f) },
- { "SeaGreen2", RGB_(0x4e, 0xee, 0x94) },
- { "SeaGreen3", RGB_(0x43, 0xcd, 0x80) },
- { "SeaGreen4", RGB_(0x2e, 0x8b, 0x57) },
- { "SeaShell", RGB_(0xff, 0xf5, 0xee) },
- { "Seashell1", RGB_(0xff, 0xf5, 0xee) },
- { "Seashell2", RGB_(0xee, 0xe5, 0xde) },
- { "Seashell3", RGB_(0xcd, 0xc5, 0xbf) },
- { "Seashell4", RGB_(0x8b, 0x86, 0x82) },
- { "Sienna", RGB_(0xa0, 0x52, 0x2d) },
- { "Sienna1", RGB_(0xff, 0x82, 0x47) },
- { "Sienna2", RGB_(0xee, 0x79, 0x42) },
- { "Sienna3", RGB_(0xcd, 0x68, 0x39) },
- { "Sienna4", RGB_(0x8b, 0x47, 0x26) },
- { "Silver", RGB_(0xc0, 0xc0, 0xc0) },
- { "SkyBlue", RGB_(0x87, 0xce, 0xeb) },
- { "SkyBlue1", RGB_(0x87, 0xce, 0xff) },
- { "SkyBlue2", RGB_(0x7e, 0xc0, 0xee) },
- { "SkyBlue3", RGB_(0x6c, 0xa6, 0xcd) },
- { "SkyBlue4", RGB_(0x4a, 0x70, 0x8b) },
- { "SlateBlue", RGB_(0x6a, 0x5a, 0xcd) },
- { "SlateBlue1", RGB_(0x83, 0x6f, 0xff) },
- { "SlateBlue2", RGB_(0x7a, 0x67, 0xee) },
- { "SlateBlue3", RGB_(0x69, 0x59, 0xcd) },
- { "SlateBlue4", RGB_(0x47, 0x3c, 0x8b) },
- { "SlateGray", RGB_(0x70, 0x80, 0x90) },
- { "SlateGray1", RGB_(0xc6, 0xe2, 0xff) },
- { "SlateGray2", RGB_(0xb9, 0xd3, 0xee) },
- { "SlateGray3", RGB_(0x9f, 0xb6, 0xcd) },
- { "SlateGray4", RGB_(0x6c, 0x7b, 0x8b) },
- { "SlateGrey", RGB_(0x70, 0x80, 0x90) },
- { "Snow", RGB_(0xff, 0xfa, 0xfa) },
- { "Snow1", RGB_(0xff, 0xfa, 0xfa) },
- { "Snow2", RGB_(0xee, 0xe9, 0xe9) },
- { "Snow3", RGB_(0xcd, 0xc9, 0xc9) },
- { "Snow4", RGB_(0x8b, 0x89, 0x89) },
- { "SpringGreen", RGB_(0x00, 0xff, 0x7f) },
- { "SpringGreen1", RGB_(0x0, 0xff, 0x7f) },
- { "SpringGreen2", RGB_(0x0, 0xee, 0x76) },
- { "SpringGreen3", RGB_(0x0, 0xcd, 0x66) },
- { "SpringGreen4", RGB_(0x0, 0x8b, 0x45) },
- { "SteelBlue", RGB_(0x46, 0x82, 0xb4) },
- { "SteelBlue1", RGB_(0x63, 0xb8, 0xff) },
- { "SteelBlue2", RGB_(0x5c, 0xac, 0xee) },
- { "SteelBlue3", RGB_(0x4f, 0x94, 0xcd) },
- { "SteelBlue4", RGB_(0x36, 0x64, 0x8b) },
- { "Tan", RGB_(0xd2, 0xb4, 0x8c) },
- { "Tan1", RGB_(0xff, 0xa5, 0x4f) },
- { "Tan2", RGB_(0xee, 0x9a, 0x49) },
- { "Tan3", RGB_(0xcd, 0x85, 0x3f) },
- { "Tan4", RGB_(0x8b, 0x5a, 0x2b) },
- { "Teal", RGB_(0x00, 0x80, 0x80) },
- { "Thistle", RGB_(0xd8, 0xbf, 0xd8) },
- { "Thistle1", RGB_(0xff, 0xe1, 0xff) },
- { "Thistle2", RGB_(0xee, 0xd2, 0xee) },
- { "Thistle3", RGB_(0xcd, 0xb5, 0xcd) },
- { "Thistle4", RGB_(0x8b, 0x7b, 0x8b) },
- { "Tomato", RGB_(0xff, 0x63, 0x47) },
- { "Tomato1", RGB_(0xff, 0x63, 0x47) },
- { "Tomato2", RGB_(0xee, 0x5c, 0x42) },
- { "Tomato3", RGB_(0xcd, 0x4f, 0x39) },
- { "Tomato4", RGB_(0x8b, 0x36, 0x26) },
- { "Turquoise", RGB_(0x40, 0xe0, 0xd0) },
- { "Turquoise1", RGB_(0x0, 0xf5, 0xff) },
- { "Turquoise2", RGB_(0x0, 0xe5, 0xee) },
- { "Turquoise3", RGB_(0x0, 0xc5, 0xcd) },
- { "Turquoise4", RGB_(0x0, 0x86, 0x8b) },
- { "Violet", RGB_(0xee, 0x82, 0xee) },
- { "VioletRed", RGB_(0xd0, 0x20, 0x90) },
- { "VioletRed1", RGB_(0xff, 0x3e, 0x96) },
- { "VioletRed2", RGB_(0xee, 0x3a, 0x8c) },
- { "VioletRed3", RGB_(0xcd, 0x32, 0x78) },
- { "VioletRed4", RGB_(0x8b, 0x22, 0x52) },
- { "WebGray", RGB_(0x80, 0x80, 0x80) },
- { "WebGreen", RGB_(0x0, 0x80, 0x0) },
- { "WebGrey", RGB_(0x80, 0x80, 0x80) },
- { "WebMaroon", RGB_(0x80, 0x0, 0x0) },
- { "WebPurple", RGB_(0x80, 0x0, 0x80) },
- { "Wheat", RGB_(0xf5, 0xde, 0xb3) },
- { "Wheat1", RGB_(0xff, 0xe7, 0xba) },
- { "Wheat2", RGB_(0xee, 0xd8, 0xae) },
- { "Wheat3", RGB_(0xcd, 0xba, 0x96) },
- { "Wheat4", RGB_(0x8b, 0x7e, 0x66) },
- { "White", RGB_(0xff, 0xff, 0xff) },
- { "WhiteSmoke", RGB_(0xf5, 0xf5, 0xf5) },
- { "X11Gray", RGB_(0xbe, 0xbe, 0xbe) },
- { "X11Green", RGB_(0x0, 0xff, 0x0) },
- { "X11Grey", RGB_(0xbe, 0xbe, 0xbe) },
- { "X11Maroon", RGB_(0xb0, 0x30, 0x60) },
- { "X11Purple", RGB_(0xa0, 0x20, 0xf0) },
- { "Yellow", RGB_(0xff, 0xff, 0x00) },
- { "Yellow1", RGB_(0xff, 0xff, 0x0) },
- { "Yellow2", RGB_(0xee, 0xee, 0x0) },
- { "Yellow3", RGB_(0xcd, 0xcd, 0x0) },
- { "Yellow4", RGB_(0x8b, 0x8b, 0x0) },
- { "YellowGreen", RGB_(0x9a, 0xcd, 0x32) },
- { NULL, 0 },
-};
-
-
-/// Translate to RgbValue if \p name is an hex value (e.g. #XXXXXX),
-/// else look into color_name_table to translate a color name to its
-/// hex value
-///
-/// @param[in] name string value to convert to RGB
-/// return the hex value or -1 if could not find a correct value
-RgbValue name_to_color(const char *name)
-{
- if (name[0] == '#' && isxdigit(name[1]) && isxdigit(name[2])
- && isxdigit(name[3]) && isxdigit(name[4]) && isxdigit(name[5])
- && isxdigit(name[6]) && name[7] == NUL) {
- // rgb hex string
- return strtol((char *)(name + 1), NULL, 16);
- } else if (!STRICMP(name, "bg") || !STRICMP(name, "background")) {
- return normal_bg;
- } else if (!STRICMP(name, "fg") || !STRICMP(name, "foreground")) {
- return normal_fg;
- }
-
- for (int i = 0; color_name_table[i].name != NULL; i++) {
- if (!STRICMP(name, color_name_table[i].name)) {
- return color_name_table[i].color;
- }
- }
-
- return -1;
-}
-
-int name_to_ctermcolor(const char *name)
-{
- int i;
- int off = TOUPPER_ASC(*name);
- for (i = ARRAY_SIZE(color_names); --i >= 0;) {
- if (off == color_names[i][0]
- && STRICMP(name+1, color_names[i]+1) == 0) {
- break;
- }
- }
- if (i < 0) {
- return -1;
- }
- TriState bold = kNone;
- return lookup_color(i, false, &bold);
-}
-
-/**************************************
-* End of Highlighting stuff *
-**************************************/
diff --git a/src/nvim/syntax.h b/src/nvim/syntax.h
index 15fc084a0a..0d890314c5 100644
--- a/src/nvim/syntax.h
+++ b/src/nvim/syntax.h
@@ -29,12 +29,6 @@
#define SYN_GROUP_STATIC(s) syn_check_group(S_LEN(s))
-typedef struct {
- char *name;
- RgbValue color;
-} color_name_table_T;
-extern color_name_table_T color_name_table[];
-
/// Array of highlight definitions, used for unit testing
extern const char *const highlight_init_cmdline[];
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index a76a806b80..5c8789ec37 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -55,6 +55,7 @@
#include "nvim/fileio.h"
#include "nvim/getchar.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/keymap.h"
#include "nvim/log.h"
#include "nvim/macros.h"
@@ -70,7 +71,6 @@
#include "nvim/os/input.h"
#include "nvim/screen.h"
#include "nvim/state.h"
-#include "nvim/syntax.h"
#include "nvim/terminal.h"
#include "nvim/ui.h"
#include "nvim/vim.h"
@@ -1288,7 +1288,7 @@ static bool send_mouse_event(Terminal *term, int c)
return mouse_win == curwin;
}
- // ignore left release action if it was not proccessed above
+ // ignore left release action if it was not processed above
// to prevent leaving Terminal mode after entering to it using a mouse
if (c == K_LEFTRELEASE && mouse_win->w_buffer->terminal == term) {
return false;
diff --git a/src/nvim/testdir/test_highlight.vim b/src/nvim/testdir/test_highlight.vim
index 6971ecd357..aa7b3a225b 100644
--- a/src/nvim/testdir/test_highlight.vim
+++ b/src/nvim/testdir/test_highlight.vim
@@ -146,7 +146,7 @@ func Test_highlight_eol_with_cursorline_vertsplit()
" 'abcd |abcd '
" ^^^^ ^^^^^^^^^ no highlight
" ^ 'Search' highlight
- " ^ 'VertSplit' highlight
+ " ^ 'WinSeparator' highlight
let attrs0 = ScreenAttrs(1, 15)[0]
call assert_equal(repeat([attrs0[0]], 4), attrs0[0:3])
call assert_equal(repeat([attrs0[0]], 9), attrs0[6:14])
@@ -160,7 +160,7 @@ func Test_highlight_eol_with_cursorline_vertsplit()
" 'abcd |abcd '
" ^^^^ underline
" ^ 'Search' highlight with underline
- " ^ 'VertSplit' highlight
+ " ^ 'WinSeparator' highlight
" ^^^^^^^^^ no highlight
" underline
diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c
index b262fc6c54..917847608a 100644
--- a/src/nvim/tui/input.c
+++ b/src/nvim/tui/input.c
@@ -19,6 +19,7 @@
# include "nvim/os/os_win_console.h"
#endif
#include "nvim/event/rstream.h"
+#include "nvim/msgpack_rpc/channel.h"
#define KEY_BUFFER_SIZE 0xfff
@@ -115,6 +116,7 @@ static void tinput_wait_enqueue(void **argv)
{
TermInput *input = argv[0];
if (rbuffer_size(input->key_buffer) == 0 && input->paste == 3) {
+ // End streamed paste with an empty string.
const String keys = { .data = "", .size = 0 };
String copy = copy_string(keys);
multiqueue_put(main_loop.events, tinput_paste_event, 3,
@@ -124,8 +126,16 @@ static void tinput_wait_enqueue(void **argv)
const String keys = { .data = buf, .size = len };
if (input->paste) {
String copy = copy_string(keys);
- multiqueue_put(main_loop.events, tinput_paste_event, 3,
- copy.data, copy.size, (intptr_t)input->paste);
+ if (ui_client_channel_id) {
+ Array args = ARRAY_DICT_INIT;
+ ADD(args, STRING_OBJ(copy_string(keys))); // 'data'
+ ADD(args, BOOLEAN_OBJ(true)); // 'crlf'
+ ADD(args, INTEGER_OBJ(input->paste)); // 'phase'
+ rpc_send_event(ui_client_channel_id, "nvim_paste", args);
+ } else {
+ multiqueue_put(main_loop.events, tinput_paste_event, 3,
+ copy.data, copy.size, (intptr_t)input->paste);
+ }
if (input->paste == 1) {
// Paste phase: "continue"
input->paste = 2;
@@ -133,7 +143,17 @@ static void tinput_wait_enqueue(void **argv)
rbuffer_consumed(input->key_buffer, len);
rbuffer_reset(input->key_buffer);
} else {
- const size_t consumed = input_enqueue(keys);
+ size_t consumed;
+ if (ui_client_channel_id) {
+ Array args = ARRAY_DICT_INIT;
+ Error err = ERROR_INIT;
+ ADD(args, STRING_OBJ(copy_string(keys)));
+ // TODO(bfredl): could be non-blocking now with paste?
+ Object result = rpc_send_call(ui_client_channel_id, "nvim_input", args, &err);
+ consumed = result.type == kObjectTypeInteger ? (size_t)result.data.integer : 0;
+ } else {
+ consumed = input_enqueue(keys);
+ }
if (consumed) {
rbuffer_consumed(input->key_buffer, consumed);
}
diff --git a/src/nvim/ui.c b/src/nvim/ui.c
index 7c67c058b0..da50f068b7 100644
--- a/src/nvim/ui.c
+++ b/src/nvim/ui.c
@@ -12,6 +12,7 @@
#include "nvim/charset.h"
#include "nvim/cursor.h"
#include "nvim/cursor_shape.h"
+#include "nvim/msgpack_rpc/channel.h"
#include "nvim/diff.h"
#include "nvim/event/loop.h"
#include "nvim/ex_cmds2.h"
@@ -224,7 +225,21 @@ void ui_refresh(void)
int save_p_lz = p_lz;
p_lz = false; // convince redrawing() to return true ...
- screen_resize(width, height);
+ if (!ui_client_channel_id) {
+ screen_resize(width, height);
+ } else {
+ Array args = ARRAY_DICT_INIT;
+ Error err = ERROR_INIT;
+ ADD(args, INTEGER_OBJ((int)width));
+ ADD(args, INTEGER_OBJ((int)height));
+ rpc_send_call(ui_client_channel_id, "nvim_ui_try_resize", args, &err);
+
+ if (ERROR_SET(&err)) {
+ ELOG("ui_client resize: %s", err.msg);
+ }
+ api_clear_error(&err);
+ }
+
p_lz = save_p_lz;
if (ext_widgets[kUIMessages]) {
diff --git a/src/nvim/ui_client.c b/src/nvim/ui_client.c
index 4a435aac4d..6e45a28e89 100644
--- a/src/nvim/ui_client.c
+++ b/src/nvim/ui_client.c
@@ -6,40 +6,55 @@
#include <assert.h>
#include "nvim/vim.h"
+#include "nvim/log.h"
+#include "nvim/map.h"
#include "nvim/ui_client.h"
#include "nvim/api/private/helpers.h"
#include "nvim/msgpack_rpc/channel.h"
#include "nvim/api/private/dispatch.h"
#include "nvim/ui.h"
+#include "nvim/highlight.h"
+#include "nvim/screen.h"
+
+static Map(String, UIClientHandler) ui_client_handlers = MAP_INIT;
+
+// Temporary buffer for converting a single grid_line event
+static size_t buf_size = 0;
+static schar_T *buf_char = NULL;
+static sattr_T *buf_attr = NULL;
+
+static void add_ui_client_event_handler(String method, UIClientHandler handler)
+{
+ map_put(String, UIClientHandler)(&ui_client_handlers, method, handler);
+}
void ui_client_init(uint64_t chan)
{
Array args = ARRAY_DICT_INIT;
- int width = 80;
- int height = 25;
+ int width = Columns;
+ int height = Rows;
Dictionary opts = ARRAY_DICT_INIT;
PUT(opts, "rgb", BOOLEAN_OBJ(true));
PUT(opts, "ext_linegrid", BOOLEAN_OBJ(true));
PUT(opts, "ext_termcolors", BOOLEAN_OBJ(true));
- // TODO(bfredl): use the size of the client UI
ADD(args, INTEGER_OBJ((int)width));
ADD(args, INTEGER_OBJ((int)height));
ADD(args, DICTIONARY_OBJ(opts));
rpc_send_event(chan, "nvim_ui_attach", args);
msgpack_rpc_add_redraw(); // GAME!
+ // TODO(bfredl): use a keyset instead
+ ui_client_methods_table_init();
ui_client_channel_id = chan;
}
/// Handler for "redraw" events sent by the NVIM server
///
-/// This is just a stub. The mentioned functionality will be implemented.
-///
-/// This function will be called by handle_request (in msgpack_rpc/channle.c)
+/// This function will be called by handle_request (in msgpack_rpc/channel.c)
/// The individual ui_events sent by the server are individually handled
-/// by their respective handlers defined in ui_events_redraw.generated.h
+/// by their respective handlers defined in ui_events_client.generated.h
///
/// @note The "flush" event is called only once and only after handling all
/// the other events
@@ -50,10 +65,21 @@ Object ui_client_handle_redraw(uint64_t channel_id, Array args, Error *error)
{
for (size_t i = 0; i < args.size; i++) {
Array call = args.items[i].data.array;
- char *method_name = call.items[0].data.string.data;
+ String name = call.items[0].data.string;
+
+ UIClientHandler handler = map_get(String, UIClientHandler)(&ui_client_handlers, name);
+ if (!handler) {
+ ELOG("No ui client handler for %s", name.size ? name.data : "<empty>");
+ continue;
+ }
- fprintf(stderr, "%s: %zu\n", method_name, call.size-1);
+ // fprintf(stderr, "%s: %zu\n", name.data, call.size-1);
+ DLOG("Invoke ui client handler for %s", name.data);
+ for (size_t j = 1; j < call.size; j++) {
+ handler(call.items[j].data.array);
+ }
}
+
return NIL;
}
@@ -64,7 +90,126 @@ void ui_client_execute(uint64_t chan)
{
while (true) {
loop_poll_events(&main_loop, -1);
+ multiqueue_process_events(resize_events);
}
getout(0);
}
+
+static HlAttrs ui_client_dict2hlattrs(Dictionary d, bool rgb)
+{
+ Error err = ERROR_INIT;
+ Dict(highlight) dict = { 0 };
+ if (!api_dict_to_keydict(&dict, KeyDict_highlight_get_field, d, &err)) {
+ // TODO(bfredl): log "err"
+ return HLATTRS_INIT;
+ }
+ return dict2hlattrs(&dict, true, NULL, &err);
+}
+
+#ifdef INCLUDE_GENERATED_DECLARATIONS
+#include "ui_events_client.generated.h"
+#endif
+
+void ui_client_event_grid_resize(Array args)
+{
+ if (args.size < 3
+ || args.items[0].type != kObjectTypeInteger
+ || args.items[1].type != kObjectTypeInteger
+ || args.items[2].type != kObjectTypeInteger) {
+ ELOG("Error handling ui event 'grid_resize'");
+ return;
+ }
+
+ Integer grid = args.items[0].data.integer;
+ Integer width = args.items[1].data.integer;
+ Integer height = args.items[2].data.integer;
+ ui_call_grid_resize(grid, width, height);
+
+ if (buf_size < (size_t)width) {
+ xfree(buf_char);
+ xfree(buf_attr);
+ buf_size = (size_t)width;
+ buf_char = xmalloc(buf_size * sizeof(schar_T));
+ buf_attr = xmalloc(buf_size * sizeof(sattr_T));
+ }
+}
+
+void ui_client_event_grid_line(Array args)
+{
+ if (args.size < 4
+ || args.items[0].type != kObjectTypeInteger
+ || args.items[1].type != kObjectTypeInteger
+ || args.items[2].type != kObjectTypeInteger
+ || args.items[3].type != kObjectTypeArray) {
+ goto error;
+ }
+
+ Integer grid = args.items[0].data.integer;
+ Integer row = args.items[1].data.integer;
+ Integer startcol = args.items[2].data.integer;
+ Array cells = args.items[3].data.array;
+
+ Integer endcol, clearcol;
+ // TODO(hlpr98): Accomodate other LineFlags when included in grid_line
+ LineFlags lineflags = 0;
+ endcol = startcol;
+
+ size_t j = 0;
+ int cur_attr = 0;
+ int clear_attr = 0;
+ int clear_width = 0;
+ for (size_t i = 0; i < cells.size; i++) {
+ if (cells.items[i].type != kObjectTypeArray) {
+ goto error;
+ }
+ Array cell = cells.items[i].data.array;
+
+ if (cell.size < 1 || cell.items[0].type != kObjectTypeString) {
+ goto error;
+ }
+ String sstring = cell.items[0].data.string;
+
+ char *schar = sstring.data;
+ int repeat = 1;
+ if (cell.size >= 2) {
+ if (cell.items[1].type != kObjectTypeInteger
+ || cell.items[1].data.integer < 0) {
+ goto error;
+ }
+ cur_attr = (int)cell.items[1].data.integer;
+ }
+
+ if (cell.size >= 3) {
+ if (cell.items[2].type != kObjectTypeInteger
+ || cell.items[2].data.integer < 0) {
+ goto error;
+ }
+ repeat = (int)cell.items[2].data.integer;
+ }
+
+ if (i == cells.size - 1 && sstring.size == 1 && sstring.data[0] == ' ' && repeat > 1) {
+ clear_width = repeat;
+ break;
+ }
+
+ for (int r = 0; r < repeat; r++) {
+ if (j >= buf_size) {
+ goto error; // _YIKES_
+ }
+ STRLCPY(buf_char[j], schar, sizeof(schar_T));
+ buf_attr[j++] = cur_attr;
+ }
+ }
+
+ endcol = startcol + (int)j;
+ clearcol = endcol + clear_width;
+ clear_attr = cur_attr;
+
+ ui_call_raw_line(grid, row, startcol, endcol, clearcol, clear_attr, lineflags,
+ (const schar_T *)buf_char, (const sattr_T *)buf_attr);
+ return;
+
+error:
+ ELOG("Error handling ui event 'grid_line'");
+}
diff --git a/src/nvim/ui_client.h b/src/nvim/ui_client.h
index 067f78d5c5..253deecc52 100644
--- a/src/nvim/ui_client.h
+++ b/src/nvim/ui_client.h
@@ -3,7 +3,11 @@
#include "nvim/api/private/defs.h"
+typedef void (*UIClientHandler)(Array args);
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
#include "ui_client.h.generated.h"
+#include "ui_events_client.h.generated.h"
#endif
+
#endif // NVIM_UI_CLIENT_H
diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c
index d7becb4fd4..e356960cc8 100644
--- a/src/nvim/ui_compositor.c
+++ b/src/nvim/ui_compositor.c
@@ -14,6 +14,7 @@
#include "nvim/api/private/helpers.h"
#include "nvim/ascii.h"
#include "nvim/highlight.h"
+#include "nvim/highlight_group.h"
#include "nvim/lib/kvec.h"
#include "nvim/log.h"
#include "nvim/lua/executor.h"
@@ -23,7 +24,6 @@
#include "nvim/os/os.h"
#include "nvim/popupmnu.h"
#include "nvim/screen.h"
-#include "nvim/syntax.h"
#include "nvim/ugrid.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
diff --git a/src/nvim/window.c b/src/nvim/window.c
index a235b07b47..8b9f1e024d 100644
--- a/src/nvim/window.c
+++ b/src/nvim/window.c
@@ -25,6 +25,7 @@
#include "nvim/getchar.h"
#include "nvim/globals.h"
#include "nvim/hashtab.h"
+#include "nvim/highlight_group.h"
#include "nvim/main.h"
#include "nvim/mark.h"
#include "nvim/memline.h"
@@ -60,7 +61,7 @@
#define NOWIN (win_T *)-1 // non-existing window
-#define ROWS_AVAIL (Rows - p_ch - tabline_height())
+#define ROWS_AVAIL (Rows - p_ch - tabline_height() - global_stl_height())
/// flags for win_enter_ext()
typedef enum {
@@ -658,6 +659,7 @@ win_T *win_new_float(win_T *wp, FloatConfig fconfig, Error *err)
}
wp->w_floating = 1;
wp->w_status_height = 0;
+ wp->w_hsep_height = 0;
wp->w_vsep_width = 0;
win_config_float(wp, fconfig);
@@ -967,6 +969,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
int before;
int minheight;
int wmh1;
+ int hsep_height;
bool did_set_fraction = false;
// aucmd_win should always remain floating
@@ -1079,6 +1082,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
}
}
} else {
+ hsep_height = global_stl_height() > 0 ? 1 : STATUS_HEIGHT;
layout = FR_COL;
/*
@@ -1087,7 +1091,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
*/
// Current window requires at least 1 space.
wmh1 = p_wmh == 0 ? 1 : p_wmh;
- needed = wmh1 + STATUS_HEIGHT;
+ needed = wmh1 + hsep_height;
if (flags & WSP_ROOM) {
needed += p_wh - wmh1;
}
@@ -1129,15 +1133,15 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
new_size = oldwin_height / 2;
}
- if (new_size > available - minheight - STATUS_HEIGHT) {
- new_size = available - minheight - STATUS_HEIGHT;
+ if (new_size > available - minheight - hsep_height) {
+ new_size = available - minheight - hsep_height;
}
if (new_size < wmh1) {
new_size = wmh1;
}
// if it doesn't fit in the current window, need win_equal()
- if (oldwin_height - new_size - STATUS_HEIGHT < p_wmh) {
+ if (oldwin_height - new_size - hsep_height < p_wmh) {
do_equal = true;
}
@@ -1150,7 +1154,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
set_fraction(oldwin);
did_set_fraction = true;
- win_setheight_win(oldwin->w_height + new_size + STATUS_HEIGHT,
+ win_setheight_win(oldwin->w_height + new_size + hsep_height,
oldwin);
oldwin_height = oldwin->w_height;
if (need_status) {
@@ -1167,8 +1171,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
while (frp != NULL) {
if (frp->fr_win != oldwin && frp->fr_win != NULL
&& (frp->fr_win->w_height > new_size
- || frp->fr_win->w_height > oldwin_height - new_size
- - STATUS_HEIGHT)) {
+ || frp->fr_win->w_height > oldwin_height - new_size - hsep_height)) {
do_equal = true;
break;
}
@@ -1294,13 +1297,15 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
if (flags & (WSP_TOP | WSP_BOT)) {
// set height and row of new window to full height
wp->w_winrow = tabline_height();
- win_new_height(wp, curfrp->fr_height - (p_ls > 0));
- wp->w_status_height = (p_ls > 0);
+ win_new_height(wp, curfrp->fr_height - (p_ls == 1 || p_ls == 2));
+ wp->w_status_height = (p_ls == 1 || p_ls == 2);
+ wp->w_hsep_height = 0;
} else {
// height and row of new window is same as current window
wp->w_winrow = oldwin->w_winrow;
win_new_height(wp, oldwin->w_height);
wp->w_status_height = oldwin->w_status_height;
+ wp->w_hsep_height = oldwin->w_hsep_height;
}
frp->fr_height = curfrp->fr_height;
@@ -1333,6 +1338,7 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
frame_fix_width(oldwin);
frame_fix_width(wp);
} else {
+ bool is_stl_global = global_stl_height() > 0;
// width and column of new window is same as current window
if (flags & (WSP_TOP | WSP_BOT)) {
wp->w_wincol = 0;
@@ -1348,28 +1354,53 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
// "new_size" of the current window goes to the new window, use
// one row for the status line
win_new_height(wp, new_size);
+ if (before) {
+ wp->w_hsep_height = is_stl_global ? 1 : 0;
+ } else {
+ wp->w_hsep_height = oldwin->w_hsep_height;
+ oldwin->w_hsep_height = is_stl_global ? 1 : 0;
+ }
if (flags & (WSP_TOP | WSP_BOT)) {
int new_fr_height = curfrp->fr_height - new_size;
- if (!((flags & WSP_BOT) && p_ls == 0)) {
+ if (!((flags & WSP_BOT) && p_ls == 0) && global_stl_height() == 0) {
new_fr_height -= STATUS_HEIGHT;
+ } else if (global_stl_height() > 0) {
+ if (flags & WSP_BOT) {
+ frame_add_hsep(curfrp);
+ } else {
+ new_fr_height -= 1;
+ }
}
frame_new_height(curfrp, new_fr_height, flags & WSP_TOP, false);
} else {
- win_new_height(oldwin, oldwin_height - (new_size + STATUS_HEIGHT));
+ win_new_height(oldwin, oldwin_height - (new_size
+ + (global_stl_height() > 0 ? 1 : STATUS_HEIGHT)));
}
+
if (before) { // new window above current one
wp->w_winrow = oldwin->w_winrow;
- wp->w_status_height = STATUS_HEIGHT;
- oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
+
+ if (is_stl_global) {
+ wp->w_status_height = 0;
+ oldwin->w_winrow += wp->w_height + 1;
+ } else {
+ wp->w_status_height = STATUS_HEIGHT;
+ oldwin->w_winrow += wp->w_height + STATUS_HEIGHT;
+ }
} else { // new window below current one
- wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
- wp->w_status_height = oldwin->w_status_height;
- if (!(flags & WSP_BOT)) {
- oldwin->w_status_height = STATUS_HEIGHT;
+ if (is_stl_global) {
+ wp->w_winrow = oldwin->w_winrow + oldwin->w_height + 1;
+ wp->w_status_height = 0;
+ } else {
+ wp->w_winrow = oldwin->w_winrow + oldwin->w_height + STATUS_HEIGHT;
+ wp->w_status_height = oldwin->w_status_height;
+ if (!(flags & WSP_BOT)) {
+ oldwin->w_status_height = STATUS_HEIGHT;
+ }
}
}
- if (flags & WSP_BOT) {
+ if ((flags & WSP_BOT) && global_stl_height() == 0) {
frame_add_statusline(curfrp);
}
frame_fix_height(wp);
@@ -1609,10 +1640,10 @@ int make_windows(int count, bool vertical)
maxcount = (curwin->w_width + curwin->w_vsep_width
- (p_wiw - p_wmw)) / (p_wmw + 1);
} else {
- // Each window needs at least 'winminheight' lines and a status line.
- maxcount = (curwin->w_height
- + curwin->w_status_height
- - (p_wh - p_wmh)) / (p_wmh + STATUS_HEIGHT);
+ // Each window needs at least 'winminheight' lines
+ // If statusline isn't global, each window also needs a statusline
+ maxcount = (curwin->w_height + curwin->w_hsep_height + curwin->w_status_height
+ - (p_wh - p_wmh)) / (p_wmh + (global_stl_height() > 0 ? 1 : STATUS_HEIGHT));
}
if (maxcount < 2) {
@@ -1707,7 +1738,7 @@ static void win_exchange(long Prenum)
* if wp != wp2
* 3. remove wp from the list
* 4. insert wp after wp2
- * 5. exchange the status line height and vsep width.
+ * 5. exchange the status line height, hsep height and vsep width.
*/
wp2 = curwin->w_prev;
frp2 = curwin->w_frame->fr_prev;
@@ -1733,6 +1764,9 @@ static void win_exchange(long Prenum)
temp = curwin->w_vsep_width;
curwin->w_vsep_width = wp->w_vsep_width;
wp->w_vsep_width = temp;
+ temp = curwin->w_hsep_height;
+ curwin->w_hsep_height = wp->w_hsep_height;
+ wp->w_hsep_height = temp;
frame_fix_height(curwin);
frame_fix_height(wp);
@@ -1813,10 +1847,13 @@ static void win_rotate(bool upwards, int count)
frame_insert(frp->fr_parent->fr_child, frp);
}
- // exchange status height and vsep width of old and new last window
+ // exchange status height, hsep height and vsep width of old and new last window
n = wp2->w_status_height;
wp2->w_status_height = wp1->w_status_height;
wp1->w_status_height = n;
+ n = wp2->w_hsep_height;
+ wp2->w_hsep_height = wp1->w_hsep_height;
+ wp1->w_hsep_height = n;
frame_fix_height(wp1);
frame_fix_height(wp2);
n = wp2->w_vsep_width;
@@ -1893,11 +1930,16 @@ void win_move_after(win_T *win1, win_T *win2)
// check if there is something to do
if (win2->w_next != win1) {
- // may need move the status line/vertical separator of the last window
+ // may need move the status line, horizontal or vertical separator of the last window
if (win1 == lastwin) {
height = win1->w_prev->w_status_height;
win1->w_prev->w_status_height = win1->w_status_height;
win1->w_status_height = height;
+
+ height = win1->w_prev->w_hsep_height;
+ win1->w_prev->w_hsep_height = win1->w_hsep_height;
+ win1->w_hsep_height = height;
+
if (win1->w_prev->w_vsep_width == 1) {
// Remove the vertical separator from the last-but-one window,
// add it to the last window. Adjust the frame widths.
@@ -1910,6 +1952,11 @@ void win_move_after(win_T *win1, win_T *win2)
height = win1->w_status_height;
win1->w_status_height = win2->w_status_height;
win2->w_status_height = height;
+
+ height = win1->w_hsep_height;
+ win1->w_hsep_height = win2->w_hsep_height;
+ win2->w_hsep_height = height;
+
if (win1->w_vsep_width == 1) {
// Remove the vertical separator from win1, add it to the last
// window, win2. Adjust the frame widths.
@@ -1973,6 +2020,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
int room = 0;
int new_size;
int has_next_curwin = 0;
+ int hsep_height;
bool hnc;
if (topfr->fr_layout == FR_LEAF) {
@@ -2118,19 +2166,22 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
totwincount -= wincount;
}
} else { // topfr->fr_layout == FR_COL
+ hsep_height = global_stl_height() > 0 ? 1 : STATUS_HEIGHT;
topfr->fr_width = width;
topfr->fr_height = height;
if (dir != 'h') { // equalize frame heights
// Compute maximum number of windows vertically in this frame.
n = frame_minheight(topfr, NOWIN);
- // add one for the bottom window if it doesn't have a statusline
+ // add one for the bottom window if it doesn't have a statusline or separator
if (row + height == cmdline_row && p_ls == 0) {
+ extra_sep = STATUS_HEIGHT;
+ } else if (global_stl_height() > 0) {
extra_sep = 1;
} else {
extra_sep = 0;
}
- totwincount = (n + extra_sep) / (p_wmh + 1);
+ totwincount = (n + extra_sep) / (p_wmh + hsep_height);
has_next_curwin = frame_has_win(topfr, next_curwin);
/*
@@ -2165,7 +2216,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
} else {
// These windows don't use up room.
totwincount -= (n + (fr->fr_next == NULL
- ? extra_sep : 0)) / (p_wmh + 1);
+ ? extra_sep : 0)) / (p_wmh + hsep_height);
}
room -= new_size - n;
if (room < 0) {
@@ -2211,7 +2262,7 @@ static void win_equal_rec(win_T *next_curwin, bool current, frame_T *topfr, int
// Compute the maximum number of windows vert. in "fr".
n = frame_minheight(fr, NOWIN);
wincount = (n + (fr->fr_next == NULL ? extra_sep : 0))
- / (p_wmh + 1);
+ / (p_wmh + hsep_height);
m = frame_minheight(fr, next_curwin);
if (has_next_curwin) {
hnc = frame_has_win(fr, next_curwin);
@@ -3167,7 +3218,7 @@ static tabpage_T *alt_tabpage(void)
/*
* Find the left-upper window in frame "frp".
*/
-static win_T *frame2win(frame_T *frp)
+win_T *frame2win(frame_T *frp)
{
while (frp->fr_win == NULL) {
frp = frp->fr_child;
@@ -3194,23 +3245,40 @@ static bool frame_has_win(const frame_T *frp, const win_T *wp)
return false;
}
+/// Check if current window is at the bottom
+/// Returns true if there are no windows below current window
+static bool is_bottom_win(win_T *wp)
+ FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL
+{
+ frame_T *frp;
+ for (frp = wp->w_frame; frp->fr_parent != NULL; frp = frp->fr_parent) {
+ if (frp->fr_parent->fr_layout == FR_COL && frp->fr_next != NULL) {
+ return false;
+ }
+ }
+ return true;
+}
/// Set a new height for a frame. Recursively sets the height for contained
/// frames and windows. Caller must take care of positions.
///
/// @param topfirst resize topmost contained frame first.
/// @param wfh obey 'winfixheight' when there is a choice;
/// may cause the height not to be set.
-static void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wfh)
+void frame_new_height(frame_T *topfrp, int height, bool topfirst, bool wfh)
FUNC_ATTR_NONNULL_ALL
{
frame_T *frp;
int extra_lines;
int h;
+ win_T *wp;
if (topfrp->fr_win != NULL) {
// Simple case: just one window.
- win_new_height(topfrp->fr_win,
- height - topfrp->fr_win->w_status_height);
+ wp = topfrp->fr_win;
+ if (is_bottom_win(wp)) {
+ wp->w_hsep_height = 0;
+ }
+ win_new_height(wp, height - wp->w_hsep_height - wp->w_status_height);
} else if (topfrp->fr_layout == FR_ROW) {
do {
// All frames in this row get the same new height.
@@ -3366,8 +3434,8 @@ static void frame_add_statusline(frame_T *frp)
if (frp->fr_layout == FR_LEAF) {
wp = frp->fr_win;
if (wp->w_status_height == 0) {
- if (wp->w_height > 0) { // don't make it negative
- --wp->w_height;
+ if (wp->w_height - STATUS_HEIGHT >= 0) { // don't make it negative
+ wp->w_height -= STATUS_HEIGHT;
}
wp->w_status_height = STATUS_HEIGHT;
}
@@ -3487,10 +3555,8 @@ static void frame_new_width(frame_T *topfrp, int width, bool leftfirst, bool wfw
topfrp->fr_width = width;
}
-/*
- * Add the vertical separator to windows at the right side of "frp".
- * Note: Does not check if there is room!
- */
+/// Add the vertical separator to windows at the right side of "frp".
+/// Note: Does not check if there is room!
static void frame_add_vsep(const frame_T *frp)
FUNC_ATTR_NONNULL_ARG(1)
{
@@ -3520,6 +3586,37 @@ static void frame_add_vsep(const frame_T *frp)
}
}
+/// Add the horizontal separator to windows at the bottom of "frp".
+/// Note: Does not check if there is room or whether the windows have a statusline!
+static void frame_add_hsep(const frame_T *frp)
+ FUNC_ATTR_NONNULL_ARG(1)
+{
+ win_T *wp;
+
+ if (frp->fr_layout == FR_LEAF) {
+ wp = frp->fr_win;
+ if (wp->w_hsep_height == 0) {
+ if (wp->w_height > 0) { // don't make it negative
+ wp->w_height++;
+ }
+ wp->w_hsep_height = 1;
+ }
+ } else if (frp->fr_layout == FR_ROW) {
+ // Handle all the frames in the row.
+ FOR_ALL_FRAMES(frp, frp->fr_child) {
+ frame_add_hsep(frp);
+ }
+ } else {
+ assert(frp->fr_layout == FR_COL);
+ // Only need to handle the last frame in the column.
+ frp = frp->fr_child;
+ while (frp->fr_next != NULL) {
+ frp = frp->fr_next;
+ }
+ frame_add_hsep(frp);
+ }
+}
+
/*
* Set frame width from the window it contains.
*/
@@ -3534,7 +3631,7 @@ static void frame_fix_width(win_T *wp)
static void frame_fix_height(win_T *wp)
FUNC_ATTR_NONNULL_ALL
{
- wp->w_frame->fr_height = wp->w_height + wp->w_status_height;
+ wp->w_frame->fr_height = wp->w_height + wp->w_hsep_height + wp->w_status_height;
}
/*
@@ -3552,10 +3649,11 @@ static int frame_minheight(frame_T *topfrp, win_T *next_curwin)
if (topfrp->fr_win != NULL) {
if (topfrp->fr_win == next_curwin) {
- m = p_wh + topfrp->fr_win->w_status_height;
+ m = p_wh + topfrp->fr_win->w_hsep_height + topfrp->fr_win->w_status_height;
} else {
- // window: minimal height of the window plus status line
- m = p_wmh + topfrp->fr_win->w_status_height;
+ // window: minimal height of the window plus separator column or status line
+ // depending on whether global statusline is enabled
+ m = p_wmh + topfrp->fr_win->w_hsep_height + topfrp->fr_win->w_status_height;
if (topfrp->fr_win == curwin && next_curwin == NULL) {
// Current window is minimal one line high.
if (p_wmh == 0) {
@@ -3784,7 +3882,7 @@ static int win_alloc_firstwin(win_T *oldwin)
new_frame(curwin);
topframe = curwin->w_frame;
topframe->fr_width = Columns;
- topframe->fr_height = Rows - p_ch;
+ topframe->fr_height = Rows - p_ch - global_stl_height();
return OK;
}
@@ -5200,11 +5298,8 @@ void win_size_restore(garray_T *gap)
}
}
-/*
- * Update the position for all windows, using the width and height of the
- * frames.
- * Returns the row just after the last window.
- */
+// Update the position for all windows, using the width and height of the frames.
+// Returns the row just after the last window and global statusline (if there is one).
int win_comp_pos(void)
{
int row = tabline_height();
@@ -5219,7 +5314,7 @@ int win_comp_pos(void)
}
}
- return row;
+ return row + global_stl_height();
}
void win_reconfig_floats(void)
@@ -5253,7 +5348,7 @@ static void frame_comp_pos(frame_T *topfrp, int *row, int *col)
wp->w_redr_status = true;
wp->w_pos_changed = true;
}
- const int h = wp->w_height + wp->w_status_height;
+ const int h = wp->w_height + wp->w_hsep_height + wp->w_status_height;
*row += h > topfrp->fr_height ? topfrp->fr_height : h;
*col += wp->w_width + wp->w_vsep_width;
} else {
@@ -5302,7 +5397,7 @@ void win_setheight_win(int height, win_T *win)
win_config_float(win, win->w_float_config);
redraw_later(win, NOT_VALID);
} else {
- frame_setheight(win->w_frame, height + win->w_status_height);
+ frame_setheight(win->w_frame, height + win->w_hsep_height + win->w_status_height);
// recompute the window positions
int row = win_comp_pos();
@@ -5393,8 +5488,8 @@ static void frame_setheight(frame_T *curfrp, int height)
room_cmdline = 0;
} else {
win_T *wp = lastwin_nofloating();
- room_cmdline = Rows - p_ch
- - (wp->w_winrow + wp->w_height + wp->w_status_height);
+ room_cmdline = Rows - p_ch - global_stl_height()
+ - (wp->w_winrow + wp->w_height + wp->w_hsep_height + wp->w_status_height);
if (room_cmdline < 0) {
room_cmdline = 0;
}
@@ -5756,7 +5851,7 @@ void win_drag_status_line(win_T *dragwin, int offset)
} else { // drag down
up = false;
// Only dragging the last status line can reduce p_ch.
- room = Rows - cmdline_row;
+ room = Rows - cmdline_row - global_stl_height();
if (curfr->fr_next == NULL) {
room -= 1;
} else {
@@ -6397,72 +6492,104 @@ char_u *file_name_in_line(char_u *line, int col, int options, long count, char_u
return find_file_name_in_path(ptr, len, options, count, rel_fname);
}
-/// Add or remove a status line for the bottom window(s), according to the
+/// Add or remove a status line from window(s), according to the
/// value of 'laststatus'.
///
/// @param morewin pretend there are two or more windows if true.
void last_status(bool morewin)
{
// Don't make a difference between horizontal or vertical split.
- last_status_rec(topframe, (p_ls == 2
- || (p_ls == 1 && (morewin || !one_window()))));
+ last_status_rec(topframe, (p_ls == 2 || (p_ls == 1 && (morewin || !one_window()))),
+ global_stl_height() > 0);
}
-static void last_status_rec(frame_T *fr, bool statusline)
+// Look for resizable frames and take lines from them to make room for the statusline
+static void resize_frame_for_status(frame_T *fr, int resize_amount)
+{
+ // Find a frame to take a line from.
+ frame_T *fp = fr;
+ win_T *wp = fr->fr_win;
+ int n;
+
+ while (resize_amount > 0) {
+ while (fp->fr_height <= frame_minheight(fp, NULL)) {
+ if (fp == topframe) {
+ emsg(_(e_noroom));
+ return;
+ }
+ // In a column of frames: go to frame above. If already at
+ // the top or in a row of frames: go to parent.
+ if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL) {
+ fp = fp->fr_prev;
+ } else {
+ fp = fp->fr_parent;
+ }
+ }
+ n = MIN(fp->fr_height - frame_minheight(fp, NULL), resize_amount);
+ resize_amount -= n;
+
+ if (fp != fr) {
+ frame_new_height(fp, fp->fr_height - n, false, false);
+ frame_fix_height(wp);
+ (void)win_comp_pos();
+ } else {
+ win_new_height(wp, wp->w_height - n);
+ }
+ }
+}
+
+static void last_status_rec(frame_T *fr, bool statusline, bool is_stl_global)
{
frame_T *fp;
win_T *wp;
if (fr->fr_layout == FR_LEAF) {
wp = fr->fr_win;
- if (wp->w_status_height != 0 && !statusline) {
- // remove status line
- win_new_height(wp, wp->w_height + 1);
+ bool is_last = is_bottom_win(wp);
+
+ if (is_last) {
+ if (wp->w_status_height != 0 && (!statusline || is_stl_global)) {
+ // Remove status line
+ wp->w_status_height = 0;
+ win_new_height(wp, wp->w_height + STATUS_HEIGHT);
+ comp_col();
+ } else if (wp->w_status_height == 0 && !is_stl_global && statusline) {
+ // Add statusline to window if needed
+ wp->w_status_height = STATUS_HEIGHT;
+ resize_frame_for_status(fr, STATUS_HEIGHT);
+ comp_col();
+ }
+ } else if (wp->w_status_height != 0 && is_stl_global) {
+ // If statusline is global and the window has a statusline, replace it with a horizontal
+ // separator
+ if (STATUS_HEIGHT - 1 != 0) {
+ win_new_height(wp, wp->w_height + STATUS_HEIGHT - 1);
+ }
wp->w_status_height = 0;
+ wp->w_hsep_height = 1;
comp_col();
- } else if (wp->w_status_height == 0 && statusline) {
- // Find a frame to take a line from.
- fp = fr;
- while (fp->fr_height <= frame_minheight(fp, NULL)) {
- if (fp == topframe) {
- emsg(_(e_noroom));
- return;
- }
- // In a column of frames: go to frame above. If already at
- // the top or in a row of frames: go to parent.
- if (fp->fr_parent->fr_layout == FR_COL && fp->fr_prev != NULL) {
- fp = fp->fr_prev;
- } else {
- fp = fp->fr_parent;
- }
- }
- wp->w_status_height = 1;
- if (fp != fr) {
- frame_new_height(fp, fp->fr_height - 1, false, false);
- frame_fix_height(wp);
- (void)win_comp_pos();
- } else {
- win_new_height(wp, wp->w_height - 1);
- }
+ } else if (wp->w_status_height == 0 && !is_stl_global) {
+ // If statusline isn't global and the window doesn't have a statusline, re-add it
+ wp->w_status_height = STATUS_HEIGHT;
+ wp->w_hsep_height = 0;
+ resize_frame_for_status(fr, STATUS_HEIGHT - 1);
comp_col();
- redraw_all_later(SOME_VALID);
}
- } else if (fr->fr_layout == FR_ROW) {
- // vertically split windows, set status line for each one
+ redraw_all_later(SOME_VALID);
+ } else if (fr->fr_layout == FR_COL) {
+ // For a column frame, recursively call this function for all child frames
FOR_ALL_FRAMES(fp, fr->fr_child) {
- last_status_rec(fp, statusline);
+ last_status_rec(fp, statusline, is_stl_global);
}
} else {
- // horizontally split window, set status line for last one
- for (fp = fr->fr_child; fp->fr_next != NULL; fp = fp->fr_next) {
+ // For a row frame, recursively call this function for all child frames
+ FOR_ALL_FRAMES(fp, fr->fr_child) {
+ last_status_rec(fp, statusline, is_stl_global);
}
- last_status_rec(fp, statusline);
}
}
-/*
- * Return the number of lines used by the tab page line.
- */
+/// Return the number of lines used by the tab page line.
int tabline_height(void)
{
if (ui_has(kUITabline)) {
@@ -6478,10 +6605,14 @@ int tabline_height(void)
return 1;
}
-/*
- * Return the minimal number of rows that is needed on the screen to display
- * the current number of windows.
- */
+/// Return the number of lines used by the global statusline
+int global_stl_height(void)
+{
+ return (p_ls == 3) ? STATUS_HEIGHT : 0;
+}
+
+/// Return the minimal number of rows that is needed on the screen to display
+/// the current number of windows.
int min_rows(void)
{
if (firstwin == NULL) { // not initialized yet
@@ -6495,7 +6626,7 @@ int min_rows(void)
total = n;
}
}
- total += tabline_height();
+ total += tabline_height() + global_stl_height();
total += 1; // count the room for the command line
return total;
}
diff --git a/test/functional/lua/overrides_spec.lua b/test/functional/lua/overrides_spec.lua
index b0712ff366..9b51af1eec 100644
--- a/test/functional/lua/overrides_spec.lua
+++ b/test/functional/lua/overrides_spec.lua
@@ -61,6 +61,44 @@ describe('print', function()
eq('Vim(lua):E5108: Error executing lua E5114: Error while converting print argument #2: <Unknown error: lua_tolstring returned NULL for tostring result>',
pcall_err(command, 'lua print("foo", v_tblout, "bar")'))
end)
+ it('coerces error values into strings', function()
+ write_file(fname, [[
+ function string_error() error("my mistake") end
+ function number_error() error(1234) end
+ function nil_error() error(nil) end
+ function table_error() error({message = "my mistake"}) end
+ function custom_error()
+ local err = {message = "my mistake", code = 11234}
+ setmetatable(err, {
+ __tostring = function(t)
+ return "Internal Error [" .. t.code .. "] " .. t.message
+ end
+ })
+ error(err)
+ end
+ function bad_custom_error()
+ local err = {message = "my mistake", code = 11234}
+ setmetatable(err, {
+ -- intentionally not a function, downstream programmer has made an mistake
+ __tostring = "Internal Error [" .. err.code .. "] " .. err.message
+ })
+ error(err)
+ end
+ ]])
+ eq('', exec_capture('luafile ' .. fname))
+ eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:0: my mistake',
+ pcall_err(command, 'lua string_error()'))
+ eq('Vim(lua):E5108: Error executing lua Xtest-functional-lua-overrides-luafile:0: 1234',
+ pcall_err(command, 'lua number_error()'))
+ eq('Vim(lua):E5108: Error executing lua [NULL]',
+ pcall_err(command, 'lua nil_error()'))
+ eq('Vim(lua):E5108: Error executing lua [NULL]',
+ pcall_err(command, 'lua table_error()'))
+ eq('Vim(lua):E5108: Error executing lua Internal Error [11234] my mistake',
+ pcall_err(command, 'lua custom_error()'))
+ eq('Vim(lua):E5108: Error executing lua [NULL]',
+ pcall_err(command, 'lua bad_custom_error()'))
+ end)
it('prints strings with NULs and NLs correctly', function()
meths.set_option('more', true)
eq('abc ^@ def\nghi^@^@^@jkl\nTEST\n\n\nT\n',
diff --git a/test/functional/lua/vim_spec.lua b/test/functional/lua/vim_spec.lua
index e66e08d9d0..5b4daf02ea 100644
--- a/test/functional/lua/vim_spec.lua
+++ b/test/functional/lua/vim_spec.lua
@@ -14,7 +14,7 @@ local feed = helpers.feed
local pcall_err = helpers.pcall_err
local exec_lua = helpers.exec_lua
local matches = helpers.matches
-local source = helpers.source
+local exec = helpers.exec
local NIL = helpers.NIL
local retry = helpers.retry
local next_msg = helpers.next_msg
@@ -743,7 +743,7 @@ describe('lua stdlib', function()
-- compat: nvim_call_function uses "special" value for vimL float
eq(false, exec_lua([[return vim.api.nvim_call_function('sin', {0.0}) == 0.0 ]]))
- source([[
+ exec([[
func! FooFunc(test)
let g:test = a:test
return {}
@@ -771,6 +771,12 @@ describe('lua stdlib', function()
-- error handling
eq({false, 'Vim:E897: List or Blob required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]]))
+
+ -- conversion between LuaRef and Vim Funcref
+ eq(true, exec_lua([[
+ local x = vim.fn.VarArg(function() return 'foo' end, function() return 'bar' end)
+ return #x == 2 and x[1]() == 'foo' and x[2]() == 'bar'
+ ]]))
end)
it('vim.fn should error when calling API function', function()
@@ -993,8 +999,11 @@ describe('lua stdlib', function()
exec_lua [[
local counter = 0
- vim.g.AddCounter = function() counter = counter + 1 end
- vim.g.GetCounter = function() return counter end
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.g.AddCounter = add_counter
+ vim.g.GetCounter = get_counter
+ vim.g.funcs = {add = add_counter, get = get_counter}
]]
eq(0, eval('g:GetCounter()'))
@@ -1006,11 +1015,18 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.g.GetCounter()]]))
exec_lua([[vim.api.nvim_get_var('AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]]))
+ exec_lua([[vim.g.funcs.add()]])
+ eq(5, exec_lua([[return vim.g.funcs.get()]]))
+ exec_lua([[vim.api.nvim_get_var('funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]]))
exec_lua [[
local counter = 0
- vim.api.nvim_set_var('AddCounter', function() counter = counter + 1 end)
- vim.api.nvim_set_var('GetCounter', function() return counter end)
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_set_var('AddCounter', add_counter)
+ vim.api.nvim_set_var('GetCounter', get_counter)
+ vim.api.nvim_set_var('funcs', {add = add_counter, get = get_counter})
]]
eq(0, eval('g:GetCounter()'))
@@ -1022,6 +1038,10 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.g.GetCounter()]]))
exec_lua([[vim.api.nvim_get_var('AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_get_var('GetCounter')()]]))
+ exec_lua([[vim.g.funcs.add()]])
+ eq(5, exec_lua([[return vim.g.funcs.get()]]))
+ exec_lua([[vim.api.nvim_get_var('funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_get_var('funcs').get()]]))
-- Check if autoload works properly
local pathsep = helpers.get_pathsep()
@@ -1072,8 +1092,11 @@ describe('lua stdlib', function()
exec_lua [[
local counter = 0
- vim.b.AddCounter = function() counter = counter + 1 end
- vim.b.GetCounter = function() return counter end
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.b.AddCounter = add_counter
+ vim.b.GetCounter = get_counter
+ vim.b.funcs = {add = add_counter, get = get_counter}
]]
eq(0, eval('b:GetCounter()'))
@@ -1085,11 +1108,18 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.b.GetCounter()]]))
exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.b.funcs.add()]])
+ eq(5, exec_lua([[return vim.b.funcs.get()]]))
+ exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]]))
exec_lua [[
local counter = 0
- vim.api.nvim_buf_set_var(0, 'AddCounter', function() counter = counter + 1 end)
- vim.api.nvim_buf_set_var(0, 'GetCounter', function() return counter end)
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_buf_set_var(0, 'AddCounter', add_counter)
+ vim.api.nvim_buf_set_var(0, 'GetCounter', get_counter)
+ vim.api.nvim_buf_set_var(0, 'funcs', {add = add_counter, get = get_counter})
]]
eq(0, eval('b:GetCounter()'))
@@ -1101,6 +1131,10 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.b.GetCounter()]]))
exec_lua([[vim.api.nvim_buf_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_buf_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.b.funcs.add()]])
+ eq(5, exec_lua([[return vim.b.funcs.get()]]))
+ exec_lua([[vim.api.nvim_buf_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_buf_get_var(0, 'funcs').get()]]))
exec_lua [[
vim.cmd "vnew"
@@ -1141,8 +1175,11 @@ describe('lua stdlib', function()
exec_lua [[
local counter = 0
- vim.w.AddCounter = function() counter = counter + 1 end
- vim.w.GetCounter = function() return counter end
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.w.AddCounter = add_counter
+ vim.w.GetCounter = get_counter
+ vim.w.funcs = {add = add_counter, get = get_counter}
]]
eq(0, eval('w:GetCounter()'))
@@ -1154,11 +1191,18 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.w.GetCounter()]]))
exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.w.funcs.add()]])
+ eq(5, exec_lua([[return vim.w.funcs.get()]]))
+ exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]]))
exec_lua [[
local counter = 0
- vim.api.nvim_win_set_var(0, 'AddCounter', function() counter = counter + 1 end)
- vim.api.nvim_win_set_var(0, 'GetCounter', function() return counter end)
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_win_set_var(0, 'AddCounter', add_counter)
+ vim.api.nvim_win_set_var(0, 'GetCounter', get_counter)
+ vim.api.nvim_win_set_var(0, 'funcs', {add = add_counter, get = get_counter})
]]
eq(0, eval('w:GetCounter()'))
@@ -1170,6 +1214,10 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.w.GetCounter()]]))
exec_lua([[vim.api.nvim_win_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_win_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.w.funcs.add()]])
+ eq(5, exec_lua([[return vim.w.funcs.get()]]))
+ exec_lua([[vim.api.nvim_win_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_win_get_var(0, 'funcs').get()]]))
exec_lua [[
vim.cmd "vnew"
@@ -1205,8 +1253,11 @@ describe('lua stdlib', function()
exec_lua [[
local counter = 0
- vim.t.AddCounter = function() counter = counter + 1 end
- vim.t.GetCounter = function() return counter end
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.t.AddCounter = add_counter
+ vim.t.GetCounter = get_counter
+ vim.t.funcs = {add = add_counter, get = get_counter}
]]
eq(0, eval('t:GetCounter()'))
@@ -1218,11 +1269,18 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.t.GetCounter()]]))
exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.t.funcs.add()]])
+ eq(5, exec_lua([[return vim.t.funcs.get()]]))
+ exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]]))
exec_lua [[
local counter = 0
- vim.api.nvim_tabpage_set_var(0, 'AddCounter', function() counter = counter + 1 end)
- vim.api.nvim_tabpage_set_var(0, 'GetCounter', function() return counter end)
+ local function add_counter() counter = counter + 1 end
+ local function get_counter() return counter end
+ vim.api.nvim_tabpage_set_var(0, 'AddCounter', add_counter)
+ vim.api.nvim_tabpage_set_var(0, 'GetCounter', get_counter)
+ vim.api.nvim_tabpage_set_var(0, 'funcs', {add = add_counter, get = get_counter})
]]
eq(0, eval('t:GetCounter()'))
@@ -1234,6 +1292,10 @@ describe('lua stdlib', function()
eq(3, exec_lua([[return vim.t.GetCounter()]]))
exec_lua([[vim.api.nvim_tabpage_get_var(0, 'AddCounter')()]])
eq(4, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'GetCounter')()]]))
+ exec_lua([[vim.t.funcs.add()]])
+ eq(5, exec_lua([[return vim.t.funcs.get()]]))
+ exec_lua([[vim.api.nvim_tabpage_get_var(0, 'funcs').add()]])
+ eq(6, exec_lua([[return vim.api.nvim_tabpage_get_var(0, 'funcs').get()]]))
exec_lua [[
vim.cmd "tabnew"
diff --git a/test/functional/terminal/channel_spec.lua b/test/functional/terminal/channel_spec.lua
index 9059441fd9..b5f3c2bd31 100644
--- a/test/functional/terminal/channel_spec.lua
+++ b/test/functional/terminal/channel_spec.lua
@@ -33,7 +33,7 @@ describe('terminal channel is closed and later released if', function()
-- channel has been closed but not released
eq("Vim(call):Can't send data to closed stream",
pcall_err(command, [[call chanclose(id) | call chansend(id, 'test')]]))
- screen:expect({any='%[Terminal closed]'})
+ screen:expect({any='%[Terminal closed%]'})
eq(chans, eval('len(nvim_list_chans())'))
-- delete terminal
feed('i<CR>')
@@ -49,7 +49,7 @@ describe('terminal channel is closed and later released if', function()
-- channel has been closed but not released
eq("Vim(call):Can't send data to closed stream",
pcall_err(command, [[call chanclose(id) | call chansend(id, 'test')]]))
- screen:expect({any='%[Terminal closed]'})
+ screen:expect({any='%[Terminal closed%]'})
eq(chans, eval('len(nvim_list_chans())'))
-- channel still hasn't been released yet
eq("Vim(call):Can't send data to closed stream",
diff --git a/test/functional/ui/cursor_spec.lua b/test/functional/ui/cursor_spec.lua
index 03cd4bfd06..4c51547e2c 100644
--- a/test/functional/ui/cursor_spec.lua
+++ b/test/functional/ui/cursor_spec.lua
@@ -212,10 +212,10 @@ describe('ui/cursor', function()
if m.blinkwait then m.blinkwait = 700 end
end
if m.hl_id then
- m.hl_id = 60
+ m.hl_id = 61
m.attr = {background = Screen.colors.DarkGray}
end
- if m.id_lm then m.id_lm = 61 end
+ if m.id_lm then m.id_lm = 62 end
end
-- Assert the new expectation.
diff --git a/test/functional/ui/global_statusline_spec.lua b/test/functional/ui/global_statusline_spec.lua
new file mode 100644
index 0000000000..6b37e5e2f1
--- /dev/null
+++ b/test/functional/ui/global_statusline_spec.lua
@@ -0,0 +1,233 @@
+local helpers = require('test.functional.helpers')(after_each)
+local Screen = require('test.functional.ui.screen')
+local clear, command, feed = helpers.clear, helpers.command, helpers.feed
+
+describe('global statusline', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(60, 16)
+ screen:attach()
+ command('set laststatus=3')
+ command('set ruler')
+ end)
+
+ it('works', function()
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {bold = true, foreground = Screen.colors.Blue1};
+ [2] = {bold = true, reverse = true};
+ }}
+
+ feed('i<CR><CR>')
+ screen:expect{grid=[[
+ |
+ |
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] [+] 3,1 All}|
+ {3:-- INSERT --} |
+ ]], attr_ids={
+ [1] = {bold = true, foreground = Screen.colors.Blue};
+ [2] = {bold = true, reverse = true};
+ [3] = {bold = true};
+ }}
+ end)
+
+ it('works with splits', function()
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:├────────────────┤}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:├────────────────────}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:────────────────────┴────────────────┴─┤}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {3:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {bold = true, foreground = Screen.colors.Blue1};
+ [3] = {bold = true, reverse = true};
+ }}
+ end)
+
+ it('works when switching between values of laststatus', function()
+ command('set laststatus=1')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ 0,0-1 All |
+ ]], attr_ids={
+ [1] = {foreground = Screen.colors.Blue, bold = true};
+ }}
+
+ command('set laststatus=3')
+ screen:expect{grid=[[
+ ^ |
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {1:~ }|
+ {2:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {foreground = Screen.colors.Blue, bold = true};
+ [2] = {reverse = true, bold = true};
+ }}
+
+ command('vsplit | split | vsplit | vsplit | wincmd l | split | 2wincmd l | split')
+ command('set laststatus=2')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│< Name] 0,0-1 │}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{3:<No Name] 0,0-1 All}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:<No Name] 0,0-1 All < Name] 0,0-1 <│}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {1:[No Name] 0,0-1 All <No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {foreground = Screen.colors.Blue, bold = true};
+ [3] = {reverse = true, bold = true};
+ }}
+
+ command('set laststatus=3')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:├────────────────┤}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:├────────────────────}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:────────────────────┴────────────────┴─┤}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {3:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {foreground = Screen.colors.Blue, bold = true};
+ [3] = {reverse = true, bold = true};
+ }}
+
+ command('set laststatus=0')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│< Name] 0,0-1 │}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{3:<No Name] 0,0-1 All}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:<No Name] 0,0-1 All < Name] 0,0-1 <│}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ 0,0-1 All |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {foreground = Screen.colors.Blue, bold = true};
+ [3] = {reverse = true, bold = true};
+ }}
+
+ command('set laststatus=3')
+ screen:expect{grid=[[
+ {1:│} {1:│} {1:│}^ |
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:├────────────────┤}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│} {1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:├────────────────────}|
+ {2:~ }{1:│}{2:~ }{1:│}{2:~}{1:│} |
+ {1:────────────────────┴────────────────┴─┤}{2:~ }|
+ {1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {2:~ }{1:│}{2:~ }|
+ {3:[No Name] 0,0-1 All}|
+ |
+ ]], attr_ids={
+ [1] = {reverse = true};
+ [2] = {foreground = Screen.colors.Blue, bold = true};
+ [3] = {reverse = true, bold = true};
+ }}
+ end)
+end)
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
index 295b70f265..dcea2c76dd 100644
--- a/test/functional/ui/hlstate_spec.lua
+++ b/test/functional/ui/hlstate_spec.lua
@@ -59,7 +59,7 @@ describe('ext_hlstate detailed highlights', function()
it('work with cleared UI highlights', function()
screen:set_default_attr_ids({
- [1] = {{}, {{hi_name = "VertSplit", ui_name = "VertSplit", kind = "ui"}}},
+ [1] = {{}, {{hi_name = "VertSplit", ui_name = "WinSeparator", kind = "ui"}}},
[2] = {{bold = true, foreground = Screen.colors.Blue1},
{{hi_name = "NonText", ui_name = "EndOfBuffer", kind = "ui"}}},
[3] = {{bold = true, reverse = true},
diff --git a/test/unit/viml/expressions/parser_spec.lua b/test/unit/viml/expressions/parser_spec.lua
index 8342044b5e..51a703b593 100644
--- a/test/unit/viml/expressions/parser_spec.lua
+++ b/test/unit/viml/expressions/parser_spec.lua
@@ -48,6 +48,7 @@ local predefined_hl_defs = {
TermCursor=true,
VertSplit=true,
WildMenu=true,
+ WinSeparator=true,
EndOfBuffer=true,
QuickFixLine=true,
Substitute=true,