aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/autoload/health/provider.vim3
-rw-r--r--runtime/autoload/provider/pythonx.vim5
-rw-r--r--runtime/doc/if_lua.txt16
-rw-r--r--runtime/doc/index.txt1
-rw-r--r--runtime/doc/motion.txt6
-rw-r--r--runtime/doc/quickref.txt1
-rw-r--r--runtime/doc/usr_25.txt9
-rw-r--r--runtime/lua/vim/shared.lua75
-rw-r--r--runtime/pack/dist/opt/termdebug/plugin/termdebug.vim1
-rw-r--r--scripts/lua2dox.lua34
-rwxr-xr-xscripts/update_version_stamp.lua7
-rw-r--r--src/nvim/api/private/helpers.h14
-rw-r--r--src/nvim/api/vim.c14
-rw-r--r--src/nvim/auevents.lua6
-rw-r--r--src/nvim/ex_cmds.c5
-rw-r--r--src/nvim/highlight.c19
-rw-r--r--src/nvim/highlight_defs.h2
-rw-r--r--src/nvim/lua/converter.c14
-rw-r--r--src/nvim/lua/executor.c59
-rw-r--r--src/nvim/lua/vim.lua12
-rw-r--r--src/nvim/normal.c16
-rw-r--r--src/nvim/ops.c1
-rw-r--r--src/nvim/quickfix.c8
-rw-r--r--src/nvim/syntax.c12
-rw-r--r--src/nvim/terminal.c19
-rw-r--r--src/nvim/testdir/test_normal.vim24
-rw-r--r--src/nvim/testdir/test_quickfix.vim21
-rw-r--r--src/nvim/testdir/test_substitute.vim10
-rw-r--r--src/nvim/testdir/test_virtualedit.vim9
-rw-r--r--src/nvim/tui/tui.c39
-rw-r--r--test/functional/core/main_spec.lua2
-rw-r--r--test/functional/lua/utility_functions_spec.lua28
-rw-r--r--test/functional/terminal/highlight_spec.lua57
-rw-r--r--test/functional/terminal/tui_spec.lua54
-rw-r--r--test/functional/ui/hlstate_spec.lua10
-rw-r--r--test/functional/ui/screen.lua13
36 files changed, 472 insertions, 154 deletions
diff --git a/runtime/autoload/health/provider.vim b/runtime/autoload/health/provider.vim
index c750a954fa..ad7a614ff5 100644
--- a/runtime/autoload/health/provider.vim
+++ b/runtime/autoload/health/provider.vim
@@ -202,7 +202,8 @@ function! s:version_info(python) abort
let nvim_path = s:trim(s:system([
\ a:python, '-c',
- \ 'import sys; sys.path.remove(""); ' .
+ \ 'import sys; ' .
+ \ 'sys.path = list(filter(lambda x: x != "", sys.path)); ' .
\ 'import neovim; print(neovim.__file__)']))
if s:shell_error || empty(nvim_path)
return [python_version, 'unable to load neovim Python module', pypi_version,
diff --git a/runtime/autoload/provider/pythonx.vim b/runtime/autoload/provider/pythonx.vim
index 6ce7165467..aec18c0508 100644
--- a/runtime/autoload/provider/pythonx.vim
+++ b/runtime/autoload/provider/pythonx.vim
@@ -10,7 +10,8 @@ function! provider#pythonx#Require(host) abort
" Python host arguments
let prog = (ver == '2' ? provider#python#Prog() : provider#python3#Prog())
- let args = [prog, '-c', 'import sys; sys.path.remove(""); import neovim; neovim.start_host()']
+ let args = [prog, '-c', 'import sys; sys.path = list(filter(lambda x: x != "", sys.path)); import neovim; neovim.start_host()']
+
" Collect registered Python plugins into args
let python_plugins = remote#host#PluginsForHost(a:host.name)
@@ -66,7 +67,7 @@ endfunction
function! s:import_module(prog, module) abort
let prog_version = system([a:prog, '-c' , printf(
\ 'import sys; ' .
- \ 'sys.path.remove(""); ' .
+ \ 'sys.path = list(filter(lambda x: x != "", sys.path)); ' .
\ 'sys.stdout.write(str(sys.version_info[0]) + "." + str(sys.version_info[1])); ' .
\ 'import pkgutil; ' .
\ 'exit(2*int(pkgutil.get_loader("%s") is None))',
diff --git a/runtime/doc/if_lua.txt b/runtime/doc/if_lua.txt
index 8528085f47..d527a91a93 100644
--- a/runtime/doc/if_lua.txt
+++ b/runtime/doc/if_lua.txt
@@ -588,6 +588,22 @@ vim.schedule({callback}) *vim.schedule()*
Schedules {callback} to be invoked soon by the main event-loop. Useful
to avoid |textlock| or other temporary restrictions.
+vim.fn.{func}({...})
+ Call vimL function {func} with arguments. {func} can be both builtin
+ functions and user functions. To call autoload functions, use the
+ syntax `vim.fn['some#function']({...})`
+
+ Note: unlike vim.api.|nvim_call_function| this converts values directly
+ between vimL values and lua values. If the vimL function returns a
+ float, it will be representeted directly as a lua number. Both empty
+ lists and dictonaries will be represented by an empty table.
+
+ Note: vim.fn keys are generated on demand. So `pairs(vim.fn)`
+ does NOT work to enumerate all functions.
+
+vim.call({func}, {...})
+ Call vim script function {func}. Equivalent to `vim.fn[func]({...})`
+
vim.type_idx *vim.type_idx*
Type index for use in |lua-special-tbl|. Specifying one of the
values from |vim.types| allows typing the empty table (it is
diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt
index 9e7051b437..7221888074 100644
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -767,6 +767,7 @@ tag char note action in Normal mode ~
|gn| gn 1,2 find the next match with the last used
search pattern and Visually select it
|gm| gm 1 go to character at middle of the screenline
+|gM| gM 1 go to character at middle of the text line
|go| go 1 cursor to byte N in the buffer
|gp| ["x]gp 2 put the text [from register x] after the
cursor N times, leave the cursor after it
diff --git a/runtime/doc/motion.txt b/runtime/doc/motion.txt
index 97c7d1cc43..9e24ee0320 100644
--- a/runtime/doc/motion.txt
+++ b/runtime/doc/motion.txt
@@ -219,6 +219,12 @@ g^ When lines wrap ('wrap' on): To the first non-blank
gm Like "g0", but half a screenwidth to the right (or as
much as possible).
+ *gM*
+gM Like "g0", but to halfway the text of the line.
+ With a count: to this percentage of text in the line.
+ Thus "10gM" is near the start of the text and "90gM"
+ is near the end of the text.
+
*g$* *g<End>*
g$ or g<End> When lines wrap ('wrap' on): To the last character of
the screen line and [count - 1] screen lines downward
diff --git a/runtime/doc/quickref.txt b/runtime/doc/quickref.txt
index 87cb9b54f5..dfa7218bdf 100644
--- a/runtime/doc/quickref.txt
+++ b/runtime/doc/quickref.txt
@@ -47,6 +47,7 @@ N is used to indicate an optional count that can be given before the command.
|g$| N g$ to last character in screen line (differs from "$"
when lines wrap)
|gm| gm to middle of the screen line
+|gM| gM to middle of the line
|bar| N | to column N (default: 1)
|f| N f{char} to the Nth occurrence of {char} to the right
|F| N F{char} to the Nth occurrence of {char} to the left
diff --git a/runtime/doc/usr_25.txt b/runtime/doc/usr_25.txt
index 3a58af6412..2efb67e55f 100644
--- a/runtime/doc/usr_25.txt
+++ b/runtime/doc/usr_25.txt
@@ -346,12 +346,13 @@ scroll:
g0 to first visible character in this line
g^ to first non-blank visible character in this line
- gm to middle of this line
+ gm to middle of screen line
+ gM to middle of the text in this line
g$ to last visible character in this line
- |<-- window -->|
- some long text, part of which is visible ~
- g0 g^ gm g$
+ |<-- window -->|
+ some long text, part of which is visible in one line ~
+ g0 g^ gm gM g$
BREAKING AT WORDS *edit-no-break*
diff --git a/runtime/lua/vim/shared.lua b/runtime/lua/vim/shared.lua
index 220b6c6c7c..7727fdbab0 100644
--- a/runtime/lua/vim/shared.lua
+++ b/runtime/lua/vim/shared.lua
@@ -4,34 +4,37 @@
-- test-suite. If, in the future, Nvim itself is used to run the test-suite
-- instead of "vanilla Lua", these functions could move to src/nvim/lua/vim.lua
+local vim = {}
--- Returns a deep copy of the given object. Non-table objects are copied as
--- in a typical Lua assignment, whereas table objects are copied recursively.
---
--@param orig Table to copy
--@returns New table of copied keys and (nested) values.
-local function deepcopy(orig)
- error(orig)
-end
-local function _id(v)
- return v
-end
-local deepcopy_funcs = {
- table = function(orig)
- local copy = {}
- for k, v in pairs(orig) do
- copy[deepcopy(k)] = deepcopy(v)
- end
- return copy
- end,
- number = _id,
- string = _id,
- ['nil'] = _id,
- boolean = _id,
-}
-deepcopy = function(orig)
- return deepcopy_funcs[type(orig)](orig)
-end
+function vim.deepcopy(orig) end -- luacheck: no unused
+vim.deepcopy = (function()
+ local function _id(v)
+ return v
+ end
+
+ local deepcopy_funcs = {
+ table = function(orig)
+ local copy = {}
+ for k, v in pairs(orig) do
+ copy[vim.deepcopy(k)] = vim.deepcopy(v)
+ end
+ return copy
+ end,
+ number = _id,
+ string = _id,
+ ['nil'] = _id,
+ boolean = _id,
+ }
+
+ return function(orig)
+ return deepcopy_funcs[type(orig)](orig)
+ end
+end)()
--- Splits a string at each instance of a separator.
---
@@ -43,7 +46,7 @@ end
--@param sep Separator string or pattern
--@param plain If `true` use `sep` literally (passed to String.find)
--@returns Iterator over the split components
-local function gsplit(s, sep, plain)
+function vim.gsplit(s, sep, plain)
assert(type(s) == "string", string.format("Expected string, got %s", type(s)))
assert(type(sep) == "string", string.format("Expected string, got %s", type(sep)))
assert(type(plain) == "boolean" or type(plain) == "nil", string.format("Expected boolean or nil, got %s", type(plain)))
@@ -92,8 +95,8 @@ end
--@param sep Separator string or pattern
--@param plain If `true` use `sep` literally (passed to String.find)
--@returns List-like table of the split components.
-local function split(s,sep,plain)
- local t={} for c in gsplit(s, sep, plain) do table.insert(t,c) end
+function vim.split(s,sep,plain)
+ local t={} for c in vim.gsplit(s, sep, plain) do table.insert(t,c) end
return t
end
@@ -102,7 +105,7 @@ end
--@param t Table to check
--@param value Value to compare
--@returns true if `t` contains `value`
-local function tbl_contains(t, value)
+function vim.tbl_contains(t, value)
assert(type(t) == 'table', string.format("Expected table, got %s", type(t)))
for _,v in ipairs(t) do
@@ -122,7 +125,7 @@ end
--- - "keep": use value from the leftmost map
--- - "force": use value from the rightmost map
--@param ... Two or more map-like tables.
-local function tbl_extend(behavior, ...)
+function vim.tbl_extend(behavior, ...)
if (behavior ~= 'error' and behavior ~= 'keep' and behavior ~= 'force') then
error('invalid "behavior": '..tostring(behavior))
end
@@ -149,7 +152,7 @@ end
---
--@param t List-like table
--@returns Flattened copy of the given list-like table.
-local function tbl_flatten(t)
+function vim.tbl_flatten(t)
-- From https://github.com/premake/premake-core/blob/master/src/base/table.lua
local result = {}
local function _tbl_flatten(_t)
@@ -172,7 +175,7 @@ end
--@see https://www.lua.org/pil/20.2.html
--@param s String to trim
--@returns String with whitespace removed from its beginning and end
-local function trim(s)
+function vim.trim(s)
assert(type(s) == 'string', string.format("Expected string, got %s", type(s)))
return s:match('^%s*(.*%S)') or ''
end
@@ -182,19 +185,9 @@ end
--@see https://github.com/rxi/lume
--@param s String to escape
--@returns %-escaped pattern string
-local function pesc(s)
+function vim.pesc(s)
assert(type(s) == 'string', string.format("Expected string, got %s", type(s)))
return s:gsub('[%(%)%.%%%+%-%*%?%[%]%^%$]', '%%%1')
end
-local module = {
- deepcopy = deepcopy,
- gsplit = gsplit,
- pesc = pesc,
- split = split,
- tbl_contains = tbl_contains,
- tbl_extend = tbl_extend,
- tbl_flatten = tbl_flatten,
- trim = trim,
-}
-return module
+return vim
diff --git a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
index 52b4829f5f..b9fc77dc37 100644
--- a/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
+++ b/runtime/pack/dist/opt/termdebug/plugin/termdebug.vim
@@ -583,6 +583,7 @@ func s:HandleEvaluate(msg)
endif
let s:evalFromBalloonExprResult = split(s:evalFromBalloonExprResult, '\\n')
call s:OpenHoverPreview(s:evalFromBalloonExprResult, v:null)
+ let s:evalFromBalloonExprResult = ''
else
echomsg '"' . s:evalexpr . '": ' . value
endif
diff --git a/scripts/lua2dox.lua b/scripts/lua2dox.lua
index 77cdabcc4b..438f734917 100644
--- a/scripts/lua2dox.lua
+++ b/scripts/lua2dox.lua
@@ -543,7 +543,6 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
local fn = TString_removeCommentFromLine(string_trim(string.sub(line,pos_fn+8)))
if fn_magic then
fn = fn_magic
- fn_magic = nil
end
if string.sub(fn,1,1)=='(' then
@@ -554,49 +553,20 @@ function TLua2DoX_filter.readfile(this,AppStamp,Filename)
-- want to fix for iffy declarations
local open_paren = string.find(fn,'[%({]')
- local fn0 = fn
if open_paren then
- fn0 = string.sub(fn,1,open_paren-1)
-- we might have a missing close paren
if not string.find(fn,'%)') then
fn = fn .. ' ___MissingCloseParenHere___)'
end
end
- local dot = string.find(fn0,'[%.:]')
- if dot then -- it's a method
- local klass = string.sub(fn,1,dot-1)
- local method = string.sub(fn,dot+1)
- --TCore_IO_writeln('function ' .. klass .. '::' .. method .. ftail .. '{}')
- --TCore_IO_writeln(klass .. '::' .. method .. ftail .. '{}')
- outStream:writeln(
- '/*! \\memberof ' .. klass .. ' */ '
- .. method .. '{}'
- )
- else
- -- add vanilla function
-
- outStream:writeln(fn_type .. 'function ' .. fn .. '{}')
- end
+ -- add vanilla function
+ outStream:writeln(fn_type .. 'function ' .. fn .. '{}')
end
else
this:warning(inStream:getLineNo(),'something weird here')
end
fn_magic = nil -- mustn't indavertently use it again
- elseif string.find(line,'=%s*class%(') then
- state = 'in_class' -- it's a class declaration
- local tailComment
- line,tailComment = TString_removeCommentFromLine(line)
- local equals = string.find(line,'=')
- local klass = string_trim(string.sub(line,1,equals-1))
- local tail = string_trim(string.sub(line,equals+1))
- -- class(wibble wibble)
- -- ....v.
- local parent = string.sub(tail,7,-2)
- if #parent>0 then
- parent = ' :public ' .. parent
- end
- outStream:writeln('class ' .. klass .. parent .. '{};')
else
state = '' -- unknown
if #line>0 then -- we don't know what this line means, so just comment it out
diff --git a/scripts/update_version_stamp.lua b/scripts/update_version_stamp.lua
index 394c4f7694..11b521fab6 100755
--- a/scripts/update_version_stamp.lua
+++ b/scripts/update_version_stamp.lua
@@ -13,6 +13,10 @@ local function die(msg)
os.exit(0)
end
+local function iswin()
+ return package.config:sub(1,1) == '\\'
+end
+
if #arg ~= 2 then
die(string.format("Expected two args, got %d", #arg))
end
@@ -20,7 +24,8 @@ end
local versiondeffile = arg[1]
local prefix = arg[2]
-local described = io.popen('git describe --first-parent --dirty 2>/dev/null'):read('*l')
+local dev_null = iswin() and 'NUL' or '/dev/null'
+local described = io.popen('git describe --first-parent --dirty 2>'..dev_null):read('*l')
if not described then
described = io.popen('git describe --first-parent --tags --always --dirty'):read('*l')
end
diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h
index 0ea7667428..8930f252f6 100644
--- a/src/nvim/api/private/helpers.h
+++ b/src/nvim/api/private/helpers.h
@@ -102,6 +102,20 @@ typedef struct {
int did_emsg;
} TryState;
+// `msg_list` controls the collection of abort-causing non-exception errors,
+// which would otherwise be ignored. This pattern is from do_cmdline().
+//
+// TODO(bfredl): prepare error-handling at "top level" (nv_event).
+#define TRY_WRAP(code) \
+ do { \
+ struct msglist **saved_msg_list = msg_list; \
+ struct msglist *private_msg_list; \
+ msg_list = &private_msg_list; \
+ private_msg_list = NULL; \
+ code \
+ msg_list = saved_msg_list; /* Restore the exception context. */ \
+ } while (0)
+
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "api/private/helpers.h.generated.h"
#endif
diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c
index 602733fd31..59761c13e7 100644
--- a/src/nvim/api/vim.c
+++ b/src/nvim/api/vim.c
@@ -53,20 +53,6 @@
# include "api/vim.c.generated.h"
#endif
-// `msg_list` controls the collection of abort-causing non-exception errors,
-// which would otherwise be ignored. This pattern is from do_cmdline().
-//
-// TODO(bfredl): prepare error-handling at "top level" (nv_event).
-#define TRY_WRAP(code) \
- do { \
- struct msglist **saved_msg_list = msg_list; \
- struct msglist *private_msg_list; \
- msg_list = &private_msg_list; \
- private_msg_list = NULL; \
- code \
- msg_list = saved_msg_list; /* Restore the exception context. */ \
- } while (0)
-
void api_vim_init(void)
FUNC_API_NOEXPORT
{
diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua
index c223679596..a52789c795 100644
--- a/src/nvim/auevents.lua
+++ b/src/nvim/auevents.lua
@@ -21,9 +21,9 @@ return {
'BufWritePre', -- before writing a buffer
'ChanInfo', -- info was received about channel
'ChanOpen', -- channel was opened
- 'CmdLineChanged', -- command line was modified
- 'CmdLineEnter', -- after entering cmdline mode
- 'CmdLineLeave', -- before leaving cmdline mode
+ 'CmdlineChanged', -- command line was modified
+ 'CmdlineEnter', -- after entering cmdline mode
+ 'CmdlineLeave', -- before leaving cmdline mode
'CmdUndefined', -- command undefined
'CmdWinEnter', -- after entering the cmdline window
'CmdWinLeave', -- before leaving the cmdline window
diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c
index 2e8bd79c81..04aa8f7ef6 100644
--- a/src/nvim/ex_cmds.c
+++ b/src/nvim/ex_cmds.c
@@ -3524,6 +3524,11 @@ static buf_T *do_sub(exarg_T *eap, proftime_T timeout,
// Note: If not first match on a line, column can't be known here
current_match.start.lnum = sub_firstlnum;
+ // Match might be after the last line for "\n\zs" matching at
+ // the end of the last line.
+ if (lnum > curbuf->b_ml.ml_line_count) {
+ break;
+ }
if (sub_firstline == NULL) {
sub_firstline = vim_strsave(ml_get(sub_firstlnum));
}
diff --git a/src/nvim/highlight.c b/src/nvim/highlight.c
index 83ee89b2a1..c96f07ed89 100644
--- a/src/nvim/highlight.c
+++ b/src/nvim/highlight.c
@@ -321,18 +321,26 @@ int hl_combine_attr(int char_attr, int prim_attr)
if (spell_aep.cterm_fg_color > 0) {
new_en.cterm_fg_color = spell_aep.cterm_fg_color;
+ new_en.rgb_ae_attr &= ((~HL_FG_INDEXED)
+ | (spell_aep.rgb_ae_attr & HL_FG_INDEXED));
}
if (spell_aep.cterm_bg_color > 0) {
new_en.cterm_bg_color = spell_aep.cterm_bg_color;
+ new_en.rgb_ae_attr &= ((~HL_BG_INDEXED)
+ | (spell_aep.rgb_ae_attr & HL_BG_INDEXED));
}
if (spell_aep.rgb_fg_color >= 0) {
new_en.rgb_fg_color = spell_aep.rgb_fg_color;
+ new_en.rgb_ae_attr &= ((~HL_FG_INDEXED)
+ | (spell_aep.rgb_ae_attr & HL_FG_INDEXED));
}
if (spell_aep.rgb_bg_color >= 0) {
new_en.rgb_bg_color = spell_aep.rgb_bg_color;
+ new_en.rgb_ae_attr &= ((~HL_BG_INDEXED)
+ | (spell_aep.rgb_ae_attr & HL_BG_INDEXED));
}
if (spell_aep.rgb_sp_color >= 0) {
@@ -422,6 +430,7 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through)
cattrs.cterm_bg_color = fattrs.cterm_bg_color;
cattrs.cterm_fg_color = cterm_blend(ratio, battrs.cterm_fg_color,
fattrs.cterm_bg_color);
+ cattrs.rgb_ae_attr &= ~(HL_FG_INDEXED | HL_BG_INDEXED);
} else {
cattrs = fattrs;
if (ratio >= 50) {
@@ -435,6 +444,8 @@ int hl_blend_attrs(int back_attr, int front_attr, bool *through)
} else {
cattrs.rgb_sp_color = -1;
}
+
+ cattrs.rgb_ae_attr &= ~HL_BG_INDEXED;
}
cattrs.rgb_bg_color = rgb_blend(ratio, battrs.rgb_bg_color,
fattrs.rgb_bg_color);
@@ -611,6 +622,14 @@ Dictionary hlattrs2dict(HlAttrs ae, bool use_rgb)
}
if (use_rgb) {
+ if (mask & HL_FG_INDEXED) {
+ PUT(hl, "fg_indexed", BOOLEAN_OBJ(true));
+ }
+
+ if (mask & HL_BG_INDEXED) {
+ PUT(hl, "bg_indexed", BOOLEAN_OBJ(true));
+ }
+
if (ae.rgb_fg_color != -1) {
PUT(hl, "foreground", INTEGER_OBJ(ae.rgb_fg_color));
}
diff --git a/src/nvim/highlight_defs.h b/src/nvim/highlight_defs.h
index 255699c8e0..36f3181674 100644
--- a/src/nvim/highlight_defs.h
+++ b/src/nvim/highlight_defs.h
@@ -19,6 +19,8 @@ typedef enum {
HL_STANDOUT = 0x20,
HL_STRIKETHROUGH = 0x40,
HL_NOCOMBINE = 0x80,
+ HL_BG_INDEXED = 0x0100,
+ HL_FG_INDEXED = 0x0200,
} HlAttrFlags;
/// Stores a complete highlighting entry, including colors and attributes
diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c
index 9665655e74..844232c64a 100644
--- a/src/nvim/lua/converter.c
+++ b/src/nvim/lua/converter.c
@@ -401,6 +401,8 @@ nlua_pop_typval_table_processing_end:
return ret;
}
+static bool typval_conv_special = false;
+
#define TYPVAL_ENCODE_ALLOW_SPECIALS true
#define TYPVAL_ENCODE_CONV_NIL(tv) \
@@ -439,7 +441,13 @@ nlua_pop_typval_table_processing_end:
lua_createtable(lstate, 0, 0)
#define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \
- nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary)
+ do { \
+ if (typval_conv_special) { \
+ nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); \
+ } else { \
+ lua_createtable(lstate, 0, 0); \
+ } \
+ } while (0)
#define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \
do { \
@@ -548,9 +556,11 @@ nlua_pop_typval_table_processing_end:
/// @param[in] tv typval_T to convert.
///
/// @return true in case of success, false otherwise.
-bool nlua_push_typval(lua_State *lstate, typval_T *const tv)
+bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special)
{
+ typval_conv_special = special;
const int initial_size = lua_gettop(lstate);
+
if (!lua_checkstack(lstate, initial_size + 2)) {
emsgf(_("E1502: Lua failed to grow stack to %i"), initial_size + 4);
return false;
diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c
index 127458fe39..c7ff163f83 100644
--- a/src/nvim/lua/executor.c
+++ b/src/nvim/lua/executor.c
@@ -295,6 +295,9 @@ static int nlua_state_init(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL
// in_fast_event
lua_pushcfunction(lstate, &nlua_in_fast_event);
lua_setfield(lstate, -2, "in_fast_event");
+ // call
+ lua_pushcfunction(lstate, &nlua_call);
+ lua_setfield(lstate, -2, "call");
// vim.loop
luv_set_loop(lstate, &main_loop.uv);
@@ -539,6 +542,60 @@ int nlua_in_fast_event(lua_State *lstate)
return 1;
}
+int nlua_call(lua_State *lstate)
+{
+ Error err = ERROR_INIT;
+ size_t name_len;
+ const char_u *name = (const char_u *)luaL_checklstring(lstate, 1, &name_len);
+ int nargs = lua_gettop(lstate)-1;
+ if (nargs > MAX_FUNC_ARGS) {
+ return luaL_error(lstate, "Function called with too many arguments");
+ }
+
+ typval_T vim_args[MAX_FUNC_ARGS + 1];
+ int i = 0; // also used for freeing the variables
+ for (; i < nargs; i++) {
+ lua_pushvalue(lstate, (int)i+2);
+ if (!nlua_pop_typval(lstate, &vim_args[i])) {
+ api_set_error(&err, kErrorTypeException,
+ "error converting argument %d", i+1);
+ goto free_vim_args;
+ }
+ }
+
+ TRY_WRAP({
+ // TODO(bfredl): this should be simplified in error handling refactor
+ force_abort = false;
+ suppress_errthrow = false;
+ current_exception = NULL;
+ did_emsg = false;
+
+ try_start();
+ typval_T rettv;
+ int dummy;
+ // call_func() retval is deceptive, ignore it. Instead we set `msg_list`
+ // (TRY_WRAP) to capture abort-causing non-exception errors.
+ (void)call_func(name, (int)name_len, &rettv, nargs,
+ vim_args, NULL, curwin->w_cursor.lnum, curwin->w_cursor.lnum,
+ &dummy, true, NULL, NULL);
+ if (!try_end(&err)) {
+ nlua_push_typval(lstate, &rettv, false);
+ }
+ tv_clear(&rettv);
+ });
+
+free_vim_args:
+ while (i > 0) {
+ tv_clear(&vim_args[--i]);
+ }
+ if (ERROR_SET(&err)) {
+ lua_pushstring(lstate, err.msg);
+ api_clear_error(&err);
+ return lua_error(lstate);
+ }
+ return 1;
+}
+
#ifdef WIN32
/// os.getenv: override os.getenv to maintain coherency. #9681
///
@@ -623,7 +680,7 @@ void executor_eval_lua(const String str, typval_T *const arg,
if (arg->v_type == VAR_UNKNOWN) {
lua_pushnil(lstate);
} else {
- nlua_push_typval(lstate, arg);
+ nlua_push_typval(lstate, arg, true);
}
if (lua_pcall(lstate, 1, 1, 0)) {
nlua_error(lstate,
diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua
index b67762e48e..5514819a02 100644
--- a/src/nvim/lua/vim.lua
+++ b/src/nvim/lua/vim.lua
@@ -242,6 +242,17 @@ local function __index(t, key)
end
end
+
+-- vim.fn.{func}(...)
+local function fn_index(t, key)
+ local function func(...)
+ return vim.call(key, ...)
+ end
+ t[key] = func
+ return func
+end
+local fn = setmetatable({}, {__index=fn_index})
+
local module = {
_update_package_paths = _update_package_paths,
_os_proc_children = _os_proc_children,
@@ -249,6 +260,7 @@ local module = {
_system = _system,
paste = paste,
schedule_wrap = schedule_wrap,
+ fn=fn,
}
setmetatable(module, {
diff --git a/src/nvim/normal.c b/src/nvim/normal.c
index d1c6362931..2ef2c3101f 100644
--- a/src/nvim/normal.c
+++ b/src/nvim/normal.c
@@ -6749,6 +6749,22 @@ static void nv_g_cmd(cmdarg_T *cap)
curwin->w_set_curswant = true;
break;
+ case 'M':
+ {
+ const char_u *const ptr = get_cursor_line_ptr();
+
+ oap->motion_type = kMTCharWise;
+ oap->inclusive = false;
+ i = (int)mb_string2cells_len(ptr, STRLEN(ptr));
+ if (cap->count0 > 0 && cap->count0 <= 100) {
+ coladvance((colnr_T)(i * cap->count0 / 100));
+ } else {
+ coladvance((colnr_T)(i / 2));
+ }
+ curwin->w_set_curswant = true;
+ }
+ break;
+
case '_':
/* "g_": to the last non-blank character in the line or <count> lines
* downward. */
diff --git a/src/nvim/ops.c b/src/nvim/ops.c
index 030782cbcc..fbbdfdcd82 100644
--- a/src/nvim/ops.c
+++ b/src/nvim/ops.c
@@ -1562,6 +1562,7 @@ int op_delete(oparg_T *oap)
oap->end = curwin->w_cursor;
curwin->w_cursor = oap->start;
}
+ mb_adjust_opend(oap);
}
if (oap->line_count == 1) { /* delete characters within one line */
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index aa934bab43..cf5194d16f 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -2006,9 +2006,7 @@ static int copy_loclist(const qf_list_T *from_qfl, qf_list_T *to_qfl)
}
if (from_qfl->qf_ctx != NULL) {
to_qfl->qf_ctx = xcalloc(1, sizeof(*to_qfl->qf_ctx));
- if (to_qfl->qf_ctx != NULL) {
- tv_copy(from_qfl->qf_ctx, to_qfl->qf_ctx);
- }
+ tv_copy(from_qfl->qf_ctx, to_qfl->qf_ctx);
} else {
to_qfl->qf_ctx = NULL;
}
@@ -3473,7 +3471,9 @@ static int qf_goto_cwindow(const qf_info_T *qi, bool resize, int sz,
if (sz != win->w_width) {
win_setwidth(sz);
}
- } else if (sz != win->w_height) {
+ } else if (sz != win->w_height
+ && (win->w_height + win->w_status_height + tabline_height()
+ < cmdline_row)) {
win_setheight(sz);
}
}
diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c
index ac8ace9fff..bdbc09a87a 100644
--- a/src/nvim/syntax.c
+++ b/src/nvim/syntax.c
@@ -2460,11 +2460,8 @@ update_si_end(
int force /* when TRUE overrule a previous end */
)
{
- lpos_T startpos;
- lpos_T endpos;
lpos_T hl_endpos;
lpos_T end_endpos;
- int end_idx;
/* return quickly for a keyword */
if (sip->si_idx < 0)
@@ -2480,9 +2477,12 @@ update_si_end(
* We need to find the end of the region. It may continue in the next
* line.
*/
- end_idx = 0;
- startpos.lnum = current_lnum;
- startpos.col = startcol;
+ int end_idx = 0;
+ lpos_T startpos = {
+ .lnum = current_lnum,
+ .col = startcol,
+ };
+ lpos_T endpos = { 0 };
find_endpos(sip->si_idx, &startpos, &endpos, &hl_endpos,
&(sip->si_flags), &end_endpos, &end_idx, sip->si_extmatch);
diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c
index 7609006906..c5e756905a 100644
--- a/src/nvim/terminal.c
+++ b/src/nvim/terminal.c
@@ -138,6 +138,8 @@ struct terminal {
int pressed_button; // which mouse button is pressed
bool pending_resize; // pending width/height
+ bool color_set[16];
+
size_t refcount; // reference count
};
@@ -241,6 +243,7 @@ Terminal *terminal_open(TerminalOptions opts)
(uint8_t)((color_val >> 8) & 0xFF),
(uint8_t)((color_val >> 0) & 0xFF));
vterm_state_set_palette_color(state, i, &color);
+ rv->color_set[i] = true;
}
}
}
@@ -598,16 +601,22 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr,
int vt_fg = fg_default ? -1 : get_rgb(state, cell.fg);
int vt_bg = bg_default ? -1 : get_rgb(state, cell.bg);
- int vt_fg_idx = ((!fg_default && VTERM_COLOR_IS_INDEXED(&cell.fg))
- ? cell.fg.indexed.idx + 1 : 0);
- int vt_bg_idx = ((!bg_default && VTERM_COLOR_IS_INDEXED(&cell.bg))
- ? cell.bg.indexed.idx + 1 : 0);
+ bool fg_indexed = VTERM_COLOR_IS_INDEXED(&cell.fg);
+ bool bg_indexed = VTERM_COLOR_IS_INDEXED(&cell.bg);
+
+ int vt_fg_idx = ((!fg_default && fg_indexed) ? cell.fg.indexed.idx + 1 : 0);
+ int vt_bg_idx = ((!bg_default && bg_indexed) ? cell.bg.indexed.idx + 1 : 0);
+
+ bool fg_set = vt_fg_idx && vt_fg_idx <= 16 && term->color_set[vt_fg_idx-1];
+ bool bg_set = vt_bg_idx && vt_bg_idx <= 16 && term->color_set[vt_bg_idx-1];
int hl_attrs = (cell.attrs.bold ? HL_BOLD : 0)
| (cell.attrs.italic ? HL_ITALIC : 0)
| (cell.attrs.reverse ? HL_INVERSE : 0)
| (cell.attrs.underline ? HL_UNDERLINE : 0)
- | (cell.attrs.strike ? HL_STRIKETHROUGH: 0);
+ | (cell.attrs.strike ? HL_STRIKETHROUGH: 0)
+ | ((fg_indexed && !fg_set) ? HL_FG_INDEXED : 0)
+ | ((bg_indexed && !bg_set) ? HL_BG_INDEXED : 0);
int attr_id = 0;
diff --git a/src/nvim/testdir/test_normal.vim b/src/nvim/testdir/test_normal.vim
index 07d250cace..eab638d19a 100644
--- a/src/nvim/testdir/test_normal.vim
+++ b/src/nvim/testdir/test_normal.vim
@@ -1895,6 +1895,7 @@ fun! Test_normal33_g_cmd2()
set wrap listchars= sbr=
let lineA='abcdefghijklmnopqrstuvwxyz'
let lineB='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+ let lineC='0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
$put =lineA
$put =lineB
@@ -1928,9 +1929,30 @@ fun! Test_normal33_g_cmd2()
call assert_equal(15, col('.'))
call assert_equal('l', getreg(0))
+ norm! 2ggdd
+ $put =lineC
+
+ " Test for gM
+ norm! gMyl
+ call assert_equal(73, col('.'))
+ call assert_equal('0', getreg(0))
+ " Test for 20gM
+ norm! 20gMyl
+ call assert_equal(29, col('.'))
+ call assert_equal('S', getreg(0))
+ " Test for 60gM
+ norm! 60gMyl
+ call assert_equal(87, col('.'))
+ call assert_equal('E', getreg(0))
+
+ " Test for g Ctrl-G
+ set ff=unix
+ let a=execute(":norm! g\<c-g>")
+ call assert_match('Col 87 of 144; Line 2 of 2; Word 1 of 1; Byte 88 of 146', a)
+
" Test for gI
norm! gIfoo
- call assert_equal(['', 'fooabcdefghijk lmno0123456789AMNOPQRSTUVWXYZ'], getline(1,'$'))
+ call assert_equal(['', 'foo0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'], getline(1,'$'))
" Test for gi
wincmd c
diff --git a/src/nvim/testdir/test_quickfix.vim b/src/nvim/testdir/test_quickfix.vim
index 77fba0b9af..8949b3d968 100644
--- a/src/nvim/testdir/test_quickfix.vim
+++ b/src/nvim/testdir/test_quickfix.vim
@@ -283,6 +283,27 @@ func Test_cwindow()
call XwindowTests('l')
endfunc
+func Test_copenHeight()
+ copen
+ wincmd H
+ let height = winheight(0)
+ copen 10
+ call assert_equal(height, winheight(0))
+ quit
+endfunc
+
+func Test_copenHeight_tabline()
+ set tabline=foo showtabline=2
+ copen
+ wincmd H
+ let height = winheight(0)
+ copen 10
+ call assert_equal(height, winheight(0))
+ quit
+ set tabline& showtabline&
+endfunc
+
+
" Tests for the :cfile, :lfile, :caddfile, :laddfile, :cgetfile and :lgetfile
" commands.
func XfileTests(cchar)
diff --git a/src/nvim/testdir/test_substitute.vim b/src/nvim/testdir/test_substitute.vim
index b29b678129..e209310a05 100644
--- a/src/nvim/testdir/test_substitute.vim
+++ b/src/nvim/testdir/test_substitute.vim
@@ -149,6 +149,7 @@ func Run_SubCmd_Tests(tests)
for t in a:tests
let start = line('.') + 1
let end = start + len(t[2]) - 1
+ " TODO: why is there a one second delay the first time we get here?
exe "normal o" . t[0]
call cursor(start, 1)
exe t[1]
@@ -717,3 +718,12 @@ one two
close!
endfunc
+
+func Test_sub_beyond_end()
+ new
+ call setline(1, '#')
+ let @/ = '^#\n\zs'
+ s///e
+ call assert_equal('#', getline(1))
+ bwipe!
+endfunc
diff --git a/src/nvim/testdir/test_virtualedit.vim b/src/nvim/testdir/test_virtualedit.vim
index 67adede8d7..1e6b26a057 100644
--- a/src/nvim/testdir/test_virtualedit.vim
+++ b/src/nvim/testdir/test_virtualedit.vim
@@ -73,3 +73,12 @@ func Test_edit_CTRL_G()
bwipe!
set virtualedit=
endfunc
+
+func Test_edit_change()
+ new
+ set virtualedit=all
+ call setline(1, "\t⒌")
+ normal Cx
+ call assert_equal('x', getline(1))
+ bwipe!
+endfunc
diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c
index 945b093f32..11746441aa 100644
--- a/src/nvim/tui/tui.c
+++ b/src/nvim/tui/tui.c
@@ -515,20 +515,8 @@ static void update_attrs(UI *ui, int attr_id)
}
data->print_attr_id = attr_id;
HlAttrs attrs = kv_A(data->attrs, (size_t)attr_id);
-
- int fg = ui->rgb ? attrs.rgb_fg_color : (attrs.cterm_fg_color - 1);
- if (fg == -1) {
- fg = ui->rgb ? data->clear_attrs.rgb_fg_color
- : (data->clear_attrs.cterm_fg_color - 1);
- }
-
- int bg = ui->rgb ? attrs.rgb_bg_color : (attrs.cterm_bg_color - 1);
- if (bg == -1) {
- bg = ui->rgb ? data->clear_attrs.rgb_bg_color
- : (data->clear_attrs.cterm_bg_color - 1);
- }
-
int attr = ui->rgb ? attrs.rgb_ae_attr : attrs.cterm_ae_attr;
+
bool bold = attr & HL_BOLD;
bool italic = attr & HL_ITALIC;
bool reverse = attr & HL_INVERSE;
@@ -596,14 +584,29 @@ static void update_attrs(UI *ui, int attr_id)
unibi_out_ext(ui, data->unibi_ext.set_underline_color);
}
}
- if (ui->rgb) {
+
+ int fg, bg;
+ if (ui->rgb && !(attr & HL_FG_INDEXED)) {
+ fg = ((attrs.rgb_fg_color != -1)
+ ? attrs.rgb_fg_color : data->clear_attrs.rgb_fg_color);
if (fg != -1) {
UNIBI_SET_NUM_VAR(data->params[0], (fg >> 16) & 0xff); // red
UNIBI_SET_NUM_VAR(data->params[1], (fg >> 8) & 0xff); // green
UNIBI_SET_NUM_VAR(data->params[2], fg & 0xff); // blue
unibi_out_ext(ui, data->unibi_ext.set_rgb_foreground);
}
+ } else {
+ fg = (attrs.cterm_fg_color
+ ? attrs.cterm_fg_color - 1 : (data->clear_attrs.cterm_fg_color - 1));
+ if (fg != -1) {
+ UNIBI_SET_NUM_VAR(data->params[0], fg);
+ unibi_out(ui, unibi_set_a_foreground);
+ }
+ }
+ if (ui->rgb && !(attr & HL_BG_INDEXED)) {
+ bg = ((attrs.rgb_bg_color != -1)
+ ? attrs.rgb_bg_color : data->clear_attrs.rgb_bg_color);
if (bg != -1) {
UNIBI_SET_NUM_VAR(data->params[0], (bg >> 16) & 0xff); // red
UNIBI_SET_NUM_VAR(data->params[1], (bg >> 8) & 0xff); // green
@@ -611,17 +614,15 @@ static void update_attrs(UI *ui, int attr_id)
unibi_out_ext(ui, data->unibi_ext.set_rgb_background);
}
} else {
- if (fg != -1) {
- UNIBI_SET_NUM_VAR(data->params[0], fg);
- unibi_out(ui, unibi_set_a_foreground);
- }
-
+ bg = (attrs.cterm_bg_color
+ ? attrs.cterm_bg_color - 1 : (data->clear_attrs.cterm_bg_color - 1));
if (bg != -1) {
UNIBI_SET_NUM_VAR(data->params[0], bg);
unibi_out(ui, unibi_set_a_background);
}
}
+
data->default_attr = fg == -1 && bg == -1
&& !bold && !italic && !underline && !undercurl && !reverse && !standout
&& !strikethrough;
diff --git a/test/functional/core/main_spec.lua b/test/functional/core/main_spec.lua
index b793e531c9..37a9f0b836 100644
--- a/test/functional/core/main_spec.lua
+++ b/test/functional/core/main_spec.lua
@@ -67,7 +67,7 @@ describe('Command-line option', function()
|
|
]], {
- [1] = {foreground = 4210943},
+ [1] = {foreground = tonumber('0x4040ff'), fg_indexed=true},
[2] = {bold = true, reverse = true}
})
feed('i:cq<CR>')
diff --git a/test/functional/lua/utility_functions_spec.lua b/test/functional/lua/utility_functions_spec.lua
index a51334398c..0b789e84b0 100644
--- a/test/functional/lua/utility_functions_spec.lua
+++ b/test/functional/lua/utility_functions_spec.lua
@@ -10,6 +10,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
before_each(clear)
@@ -299,4 +300,31 @@ describe('lua stdlib', function()
eq("Error executing lua: .../shared.lua: Expected string, got number",
pcall_err(exec_lua, [[return vim.pesc(2)]]))
end)
+
+ it('vim.call and vim.fn', function()
+ eq(true, exec_lua([[return vim.call('sin', 0.0) == 0.0 ]]))
+ eq(true, exec_lua([[return vim.fn.sin(0.0) == 0.0 ]]))
+ -- 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([[
+ func! FooFunc(test)
+ let g:test = a:test
+ return {}
+ endfunc
+ func! VarArg(...)
+ return a:000
+ endfunc
+ ]])
+ eq(true, exec_lua([[return next(vim.fn.FooFunc(3)) == nil ]]))
+ eq(3, eval("g:test"))
+ -- compat: nvim_call_function uses "special" value for empty dict
+ eq(true, exec_lua([[return next(vim.api.nvim_call_function("FooFunc", {5})) == true ]]))
+ eq(5, eval("g:test"))
+
+ eq({2, "foo", true}, exec_lua([[return vim.fn.VarArg(2, "foo", true)]]))
+
+ -- error handling
+ eq({false, 'Vim:E714: List required'}, exec_lua([[return {pcall(vim.fn.add, "aa", "bb")}]]))
+ end)
end)
diff --git a/test/functional/terminal/highlight_spec.lua b/test/functional/terminal/highlight_spec.lua
index 06a6fd6f2b..8d3f0218af 100644
--- a/test/functional/terminal/highlight_spec.lua
+++ b/test/functional/terminal/highlight_spec.lua
@@ -121,13 +121,12 @@ it(':terminal highlight has lower precedence than editor #9964', function()
local screen = Screen.new(30, 4)
screen:set_default_attr_ids({
-- "Normal" highlight emitted by the child nvim process.
- N_child = {foreground = tonumber('0x4040ff'), background = tonumber('0xffff40')},
- -- "Search" highlight emitted by the child nvim process.
- S_child = {background = tonumber('0xffff40'), italic = true, foreground = tonumber('0x4040ff')},
+ N_child = {foreground = tonumber('0x4040ff'), background = tonumber('0xffff40'), fg_indexed=true, bg_indexed=true},
-- "Search" highlight in the parent nvim process.
S = {background = Screen.colors.Green, italic = true, foreground = Screen.colors.Red},
-- "Question" highlight in the parent nvim process.
- Q = {background = tonumber('0xffff40'), bold = true, foreground = Screen.colors.SeaGreen4},
+ -- note: bg is indexed as it comes from the (cterm) child, while fg isn't as it comes from (rgb) parent
+ Q = {background = tonumber('0xffff40'), bold = true, foreground = Screen.colors.SeaGreen4, bg_indexed=true},
})
screen:attach({rgb=true})
-- Child nvim process in :terminal (with cterm colors).
@@ -160,6 +159,54 @@ it(':terminal highlight has lower precedence than editor #9964', function()
]])
end)
+describe(':terminal highlight forwarding', function()
+ local screen
+
+ before_each(function()
+ clear()
+ screen = Screen.new(50, 7)
+ screen:set_rgb_cterm(true)
+ screen:set_default_attr_ids({
+ [1] = {{reverse = true}, {reverse = true}},
+ [2] = {{bold = true}, {bold = true}},
+ [3] = {{fg_indexed = true, foreground = tonumber('0xe0e000')}, {foreground = 3}},
+ [4] = {{foreground = tonumber('0xff8000')}, {}},
+ })
+ screen:attach()
+ command('enew | call termopen(["'..nvim_dir..'/tty-test"])')
+ feed('i')
+ screen:expect([[
+ tty ready |
+ {1: } |
+ |
+ |
+ |
+ |
+ {2:-- TERMINAL --} |
+ ]])
+ end)
+
+ it('will handle cterm and rgb attributes', function()
+ if helpers.pending_win32(pending) then return end
+ thelpers.set_fg(3)
+ thelpers.feed_data('text')
+ thelpers.feed_termcode('[38:2:255:128:0m')
+ thelpers.feed_data('color')
+ thelpers.clear_attrs()
+ thelpers.feed_data('text')
+ screen:expect{grid=[[
+ tty ready |
+ {3:text}{4:color}text{1: } |
+ |
+ |
+ |
+ |
+ {2:-- TERMINAL --} |
+ ]]}
+ end)
+end)
+
+
describe(':terminal highlight with custom palette', function()
local screen
@@ -167,7 +214,7 @@ describe(':terminal highlight with custom palette', function()
clear()
screen = Screen.new(50, 7)
screen:set_default_attr_ids({
- [1] = {foreground = tonumber('0x123456')},
+ [1] = {foreground = tonumber('0x123456')}, -- no fg_indexed when overriden
[2] = {foreground = 12},
[3] = {bold = true, reverse = true},
[5] = {background = 11},
diff --git a/test/functional/terminal/tui_spec.lua b/test/functional/terminal/tui_spec.lua
index bc83660c19..5ac2ffb611 100644
--- a/test/functional/terminal/tui_spec.lua
+++ b/test/functional/terminal/tui_spec.lua
@@ -680,11 +680,11 @@ describe('TUI', function()
screen:set_option('rgb', true)
screen:set_default_attr_ids({
[1] = {reverse = true},
- [2] = {foreground = tonumber('0x4040ff')},
+ [2] = {foreground = tonumber('0x4040ff'), fg_indexed=true},
[3] = {bold = true, reverse = true},
[4] = {bold = true},
- [5] = {reverse = true, foreground = tonumber('0xe0e000')},
- [6] = {foreground = tonumber('0xe0e000')},
+ [5] = {reverse = true, foreground = tonumber('0xe0e000'), fg_indexed=true},
+ [6] = {foreground = tonumber('0xe0e000'), fg_indexed=true},
[7] = {reverse = true, foreground = Screen.colors.SeaGreen4},
[8] = {foreground = Screen.colors.SeaGreen4},
[9] = {bold = true, foreground = Screen.colors.Blue1},
@@ -728,6 +728,54 @@ describe('TUI', function()
]])
end)
+ it('forwards :term palette colors with termguicolors', function()
+ screen:set_rgb_cterm(true)
+ screen:set_default_attr_ids({
+ [1] = {{reverse = true}, {reverse = true}},
+ [2] = {{bold = true, reverse = true}, {bold = true, reverse = true}},
+ [3] = {{bold = true}, {bold = true}},
+ [4] = {{fg_indexed = true, foreground = tonumber('0xe0e000')}, {foreground = 3}},
+ [5] = {{foreground = tonumber('0xff8000')}, {}},
+ })
+
+ feed_data(':set statusline=^^^^^^^\n')
+ feed_data(':set termguicolors\n')
+ feed_data(':terminal '..nvim_dir..'/tty-test\n')
+ -- Depending on platform the above might or might not fit in the cmdline
+ -- so clear it for consistent behavior.
+ feed_data(':\027')
+ screen:expect{grid=[[
+ {1:t}ty ready |
+ |
+ |
+ |
+ {2:^^^^^^^ }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+ feed_data(':call chansend(&channel, "\\033[38;5;3mtext\\033[38:2:255:128:0mcolor\\033[0;10mtext")\n')
+ screen:expect{grid=[[
+ {1:t}ty ready |
+ {4:text}{5:color}text |
+ |
+ |
+ {2:^^^^^^^ }|
+ |
+ {3:-- TERMINAL --} |
+ ]]}
+
+ feed_data(':set notermguicolors\n')
+ screen:expect{grid=[[
+ {1:t}ty ready |
+ {4:text}colortext |
+ |
+ |
+ {2:^^^^^^^ }|
+ :set notermguicolors |
+ {3:-- TERMINAL --} |
+ ]]}
+ end)
+
it('is included in nvim_list_uis()', function()
feed_data(':echo map(nvim_list_uis(), {k,v -> sort(items(filter(v, {k,v -> k[:3] !=# "ext_" })))})\r')
screen:expect([=[
diff --git a/test/functional/ui/hlstate_spec.lua b/test/functional/ui/hlstate_spec.lua
index 1e18df835a..2a567b28ee 100644
--- a/test/functional/ui/hlstate_spec.lua
+++ b/test/functional/ui/hlstate_spec.lua
@@ -181,11 +181,11 @@ describe('ext_hlstate detailed highlights', function()
it("work with :terminal", function()
screen:set_default_attr_ids({
[1] = {{}, {{hi_name = "TermCursorNC", ui_name = "TermCursorNC", kind = "ui"}}},
- [2] = {{foreground = 52479}, {{kind = "term"}}},
- [3] = {{bold = true, foreground = 52479}, {{kind = "term"}}},
- [4] = {{foreground = 52479}, {2, 1}},
- [5] = {{foreground = 4259839}, {{kind = "term"}}},
- [6] = {{foreground = 4259839}, {5, 1}},
+ [2] = {{foreground = tonumber('0x00ccff'), fg_indexed=true}, {{kind = "term"}}},
+ [3] = {{bold = true, foreground = tonumber('0x00ccff'), fg_indexed=true}, {{kind = "term"}}},
+ [4] = {{foreground = tonumber('0x00ccff'), fg_indexed=true}, {2, 1}},
+ [5] = {{foreground = tonumber('0x40ffff'), fg_indexed=true}, {{kind = "term"}}},
+ [6] = {{foreground = tonumber('0x40ffff'), fg_indexed=true}, {5, 1}},
[7] = {{}, {{hi_name = "MsgArea", ui_name = "MsgArea", kind = "ui"}}},
})
command('enew | call termopen(["'..nvim_dir..'/tty-test"])')
diff --git a/test/functional/ui/screen.lua b/test/functional/ui/screen.lua
index b57e13fea1..41e022791e 100644
--- a/test/functional/ui/screen.lua
+++ b/test/functional/ui/screen.lua
@@ -1362,6 +1362,7 @@ function Screen:linegrid_check_attrs(attrs)
if self._rgb_cterm then
attr_rgb, attr_cterm, info = unpack(v)
attr = {attr_rgb, attr_cterm}
+ info = info or {}
elseif self._options.ext_hlstate then
attr, info = unpack(v)
else
@@ -1400,11 +1401,12 @@ end
function Screen:_pprint_hlitem(item)
-- print(inspect(item))
local multi = self._rgb_cterm or self._options.ext_hlstate
- local attrdict = "{"..self:_pprint_attrs(multi and item[1] or item).."}"
+ local cterm = (not self._rgb_cterm and not self._options.rgb)
+ local attrdict = "{"..self:_pprint_attrs(multi and item[1] or item, cterm).."}"
local attrdict2, hlinfo
local descdict = ""
if self._rgb_cterm then
- attrdict2 = ", {"..self:_pprint_attrs(item[2]).."}"
+ attrdict2 = ", {"..self:_pprint_attrs(item[2], true).."}"
hlinfo = item[3]
else
attrdict2 = ""
@@ -1433,13 +1435,15 @@ function Screen:_pprint_hlinfo(states)
end
-function Screen:_pprint_attrs(attrs)
+function Screen:_pprint_attrs(attrs, cterm)
local items = {}
for f, v in pairs(attrs) do
local desc = tostring(v)
if f == "foreground" or f == "background" or f == "special" then
if Screen.colornames[v] ~= nil then
desc = "Screen.colors."..Screen.colornames[v]
+ elseif cterm then
+ desc = tostring(v)
else
desc = string.format("tonumber('0x%06x')",v)
end
@@ -1511,7 +1515,8 @@ function Screen:_equal_attrs(a, b)
a.italic == b.italic and a.reverse == b.reverse and
a.foreground == b.foreground and a.background == b.background and
a.special == b.special and a.blend == b.blend and
- a.strikethrough == b.strikethrough
+ a.strikethrough == b.strikethrough and
+ a.fg_indexed == b.fg_indexed and a.bg_indexed == b.bg_indexed
end
function Screen:_equal_info(a, b)