diff options
-rw-r--r-- | runtime/doc/deprecated.txt | 1 | ||||
-rw-r--r-- | runtime/doc/options.txt | 8 | ||||
-rw-r--r-- | runtime/doc/vim_diff.txt | 3 | ||||
-rw-r--r-- | src/nvim/getchar.c | 2 | ||||
-rw-r--r-- | src/nvim/macros.h | 2 | ||||
-rw-r--r-- | src/nvim/option.c | 6 | ||||
-rw-r--r-- | src/nvim/option_defs.h | 5 | ||||
-rw-r--r-- | src/nvim/options.lua | 6 | ||||
-rw-r--r-- | src/nvim/testdir/test_mapping.vim | 82 | ||||
-rw-r--r-- | src/nvim/version.c | 4 | ||||
-rw-r--r-- | test/README.md | 13 | ||||
-rw-r--r-- | test/functional/helpers.lua | 23 | ||||
-rw-r--r-- | test/functional/options/pastetoggle_spec.lua | 37 | ||||
-rw-r--r-- | test/helpers.lua | 23 | ||||
-rw-r--r-- | test/unit/helpers.lua | 236 | ||||
-rw-r--r-- | test/unit/testtest_spec.lua | 19 |
16 files changed, 372 insertions, 98 deletions
diff --git a/runtime/doc/deprecated.txt b/runtime/doc/deprecated.txt index 822019340a..e77d20172e 100644 --- a/runtime/doc/deprecated.txt +++ b/runtime/doc/deprecated.txt @@ -44,6 +44,7 @@ Functions ~ Options ~ *'fe'* 'fenc'+'enc' before Vim 6.0; no longer used. +*'langnoremap'* Deprecated alias to 'nolangremap'. *'vi'* *'viminfo'* Deprecated alias to 'shada' option. diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index c31ebf4ebc..7d41162cfc 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -3762,12 +3762,12 @@ A jump table for the options with a short description can be found at |Q_op|. :source $VIMRUNTIME/menu.vim < Warning: This deletes all menus that you defined yourself! - *'langnoremap'* *'lnr'* -'langnoremap' 'lnr' boolean (default on) + *'langremap'* *'lrm'* *'nolangremap'* *'nolrm'* +'langremap' 'lrm' boolean (default off) global - When on, setting 'langmap' does not apply to characters resulting from + When off, setting 'langmap' does not apply to characters resulting from a mapping. If setting 'langmap' disables some of your mappings, make - sure this option is set. + sure this option is off. *'laststatus'* *'ls'* 'laststatus' 'ls' number (default 2) diff --git a/runtime/doc/vim_diff.txt b/runtime/doc/vim_diff.txt index 11dde27868..41c0c41c80 100644 --- a/runtime/doc/vim_diff.txt +++ b/runtime/doc/vim_diff.txt @@ -45,7 +45,8 @@ these differences. - 'history' defaults to 10000 (the maximum) - 'hlsearch' is set by default - 'incsearch' is set by default -- 'langnoremap' is set by default +- 'langnoremap' is enabled by default +- 'langremap' is disabled by default - 'laststatus' defaults to 2 (statusline is always shown) - 'listchars' defaults to "tab:> ,trail:-,nbsp:+" - 'nocompatible' is always set diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 7143819e21..b83681ad01 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -1903,7 +1903,7 @@ static int vgetorpeek(int advance) } if ((mp == NULL || max_mlen >= mp_match_len) - && keylen != KEYLEN_PART_MAP) { + && keylen != KEYLEN_PART_MAP && keylen != KEYLEN_PART_KEY) { // No matching mapping found or found a non-matching mapping that // matches at least what the matching mapping matched keylen = 0; diff --git a/src/nvim/macros.h b/src/nvim/macros.h index 5042663041..a8df6322cf 100644 --- a/src/nvim/macros.h +++ b/src/nvim/macros.h @@ -94,7 +94,7 @@ do { \ if (*p_langmap \ && (condition) \ - && (!p_lnr || (p_lnr && typebuf_maplen() == 0)) \ + && (p_lrm || (!p_lrm && KeyTyped)) \ && !KeyStuffed \ && (c) >= 0) \ { \ diff --git a/src/nvim/option.c b/src/nvim/option.c index 0b4d9aae5d..b3b4dc1e0a 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -3630,6 +3630,12 @@ static char *set_bool_option(const int opt_idx, char_u *const varp, } else if ((int *)varp == &p_force_off && p_force_off == true) { p_force_off = false; return (char *)e_unsupportedoption; + } else if ((int *)varp == &p_lrm) { + // 'langremap' -> !'langnoremap' + p_lnr = !p_lrm; + } else if ((int *)varp == &p_lnr) { + // 'langnoremap' -> !'langremap' + p_lrm = !p_lnr; // 'undofile' } else if ((int *)varp == &curbuf->b_p_udf || (int *)varp == &p_udf) { // Only take action when the option was set. When reset we do not diff --git a/src/nvim/option_defs.h b/src/nvim/option_defs.h index 2475a0b6a1..4ee0f4f225 100644 --- a/src/nvim/option_defs.h +++ b/src/nvim/option_defs.h @@ -476,8 +476,9 @@ EXTERN char_u *p_isp; // 'isprint' EXTERN int p_js; // 'joinspaces' EXTERN char_u *p_kp; // 'keywordprg' EXTERN char_u *p_km; // 'keymodel' -EXTERN char_u *p_langmap; // 'langmap'*/ -EXTERN int p_lnr; // 'langnoremap'*/ +EXTERN char_u *p_langmap; // 'langmap' +EXTERN int p_lnr; // 'langnoremap' +EXTERN int p_lrm; // 'langremap' EXTERN char_u *p_lm; // 'langmenu' EXTERN char_u *p_lispwords; // 'lispwords' EXTERN long p_ls; // 'laststatus' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index ee2b8a563d..9dff3410d6 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -1347,6 +1347,12 @@ return { defaults={if_true={vi=false, vim=true}} }, { + full_name='langremap', abbreviation='lrm', + type='bool', scope={'global'}, + varname='p_lrm', + defaults={if_true={vi=true, vim=false}} + }, + { full_name='laststatus', abbreviation='ls', type='number', scope={'global'}, vim=true, diff --git a/src/nvim/testdir/test_mapping.vim b/src/nvim/testdir/test_mapping.vim index d937565ce5..6b313ff54f 100644 --- a/src/nvim/testdir/test_mapping.vim +++ b/src/nvim/testdir/test_mapping.vim @@ -35,29 +35,81 @@ func Test_map_ctrl_c_visual() endfunc func Test_map_langmap() - " langmap should not get remapped in insert mode - inoremap { FAIL_ilangmap - set langmap=+{ langnoremap + if !has('langmap') + return + endif + + " check langmap applies in normal mode + set langmap=+- nolangremap + new + call setline(1, ['a', 'b', 'c']) + 2 + call assert_equal('b', getline('.')) + call feedkeys("+", "xt") + call assert_equal('a', getline('.')) + + " check no remapping + map x + + 2 + call feedkeys("x", "xt") + call assert_equal('c', getline('.')) + + " check with remapping + set langremap + 2 + call feedkeys("x", "xt") + call assert_equal('a', getline('.')) + + unmap x + bwipe! + + " 'langnoremap' follows 'langremap' and vise versa + set langremap + set langnoremap + call assert_equal(0, &langremap) + set langremap + call assert_equal(0, &langnoremap) + set nolangremap + call assert_equal(1, &langnoremap) + + " check default values + set langnoremap& + call assert_equal(1, &langnoremap) + call assert_equal(0, &langremap) + set langremap& + call assert_equal(1, &langnoremap) + call assert_equal(0, &langremap) + + " langmap should not apply in insert mode, 'langremap' doesn't matter + set langmap=+{ nolangremap call feedkeys("Go+\<Esc>", "xt") call assert_equal('+', getline('$')) - - " Insert-mode expr mapping with langmap - inoremap <expr> { "FAIL_iexplangmap" + set langmap=+{ langremap call feedkeys("Go+\<Esc>", "xt") call assert_equal('+', getline('$')) - iunmap <expr> { - " langmap should not get remapped in Command-line mode - cnoremap { FAIL_clangmap + " langmap used for register name in insert mode. + call setreg('a', 'aaaa') + call setreg('b', 'bbbb') + call setreg('c', 'cccc') + set langmap=ab langremap + call feedkeys("Go\<C-R>a\<Esc>", "xt") + call assert_equal('bbbb', getline('$')) + call feedkeys("Go\<C-R>\<C-R>a\<Esc>", "xt") + call assert_equal('bbbb', getline('$')) + " mapping does not apply + imap c a + call feedkeys("Go\<C-R>c\<Esc>", "xt") + call assert_equal('cccc', getline('$')) + imap a c + call feedkeys("Go\<C-R>a\<Esc>", "xt") + call assert_equal('bbbb', getline('$')) + + " langmap should not apply in Command-line mode + set langmap=+{ nolangremap call feedkeys(":call append(line('$'), '+')\<CR>", "xt") call assert_equal('+', getline('$')) - cunmap { - " Command-line mode expr mapping with langmap - cnoremap <expr> { "FAIL_cexplangmap" - call feedkeys(":call append(line('$'), '+')\<CR>", "xt") - call assert_equal('+', getline('$')) - cunmap { set nomodified endfunc diff --git a/src/nvim/version.c b/src/nvim/version.c index fdf5436a98..0ee0419849 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -135,7 +135,7 @@ static const int included_patches[] = { 2309, // 2308 NA 2307, - // 2306, + 2306, 2305, // 2304 NA 2303, @@ -205,7 +205,7 @@ static const int included_patches[] = { // 2239, // 2238 NA 2237, - // 2236, + 2236, 2235, // 2234 NA 2233, diff --git a/test/README.md b/test/README.md index df66f24626..2857cc0ecf 100644 --- a/test/README.md +++ b/test/README.md @@ -27,8 +27,8 @@ groups by the semantic component they are testing. Test behaviour is affected by environment variables. Currently supported (Functional, Unit, Benchmarks) (when Defined; when set to _1_; when defined, -treated as Integer; when defined, treated as String; !must be defined to -function properly): +treated as Integer; when defined, treated as String; when defined, treated as +Number; !must be defined to function properly): `GDB` (F) (D): makes nvim instances to be run under `gdbserver`. It will be accessible on `localhost:7777`: use `gdb build/bin/nvim`, type `target remote @@ -99,3 +99,12 @@ get backtrace from). approximately 90% of the tests. Should be used when finding cores is too hard for some reason. Normally (on OS X or when `NVIM_TEST_CORE_GLOB_DIRECTORY` is defined and this variable is not) cores are checked for after each test. + +`NVIM_TEST_RUN_TESTTEST` (U) (1): allows running `test/unit/testtest_spec.lua` +used to check how testing infrastructure works. + +`NVIM_TEST_TRACE_LEVEL` (U) (N): specifies unit tests tracing level: `0` +disables tracing (the fastest, but you get no data if tests crash and there was +no core dump generated), `1` or empty/undefined leaves only C function cals and +returns in the trace (faster then recording everything), `2` records all +function calls, returns and lua source lines exuecuted. diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua index ab36508262..335cf3c3ff 100644 --- a/test/functional/helpers.lua +++ b/test/functional/helpers.lua @@ -16,6 +16,7 @@ local eq = global_helpers.eq local ok = global_helpers.ok local map = global_helpers.map local filter = global_helpers.filter +local dedent = global_helpers.dedent local start_dir = lfs.currentdir() -- XXX: NVIM_PROG takes precedence, QuickBuild sets it. @@ -191,28 +192,6 @@ local function nvim_feed(input) end end -local function dedent(str) - -- find minimum common indent across lines - local indent = nil - for line in str:gmatch('[^\n]+') do - local line_indent = line:match('^%s+') or '' - if indent == nil or #line_indent < #indent then - indent = line_indent - end - end - if indent == nil or #indent == 0 then - -- no minimum common indent - return str - end - -- create a pattern for the indent - indent = indent:gsub('%s', '[ \t]') - -- strip it from the first line - str = str:gsub('^'..indent, '') - -- strip it from the remaining lines - str = str:gsub('[\n]'..indent, '\n') - return str -end - local function feed(...) for _, v in ipairs({...}) do nvim_feed(dedent(v)) diff --git a/test/functional/options/pastetoggle_spec.lua b/test/functional/options/pastetoggle_spec.lua new file mode 100644 index 0000000000..e449df31f5 --- /dev/null +++ b/test/functional/options/pastetoggle_spec.lua @@ -0,0 +1,37 @@ +local helpers = require('test.functional.helpers')(after_each) + +local clear = helpers.clear +local feed = helpers.feed +local execute = helpers.execute +local eq = helpers.eq +local eval = helpers.eval +local sleep = helpers.sleep + +describe("'pastetoggle' option", function() + before_each(function() + clear() + execute('set nopaste') + execute('set pastetoggle=a') + end) + it("toggles 'paste'", function() + eq(eval('&paste'), 0) + feed('a') + -- Need another key so that the vgetorpeek() function returns. + feed('j') + eq(eval('&paste'), 1) + end) + it("multiple key 'pastetoggle' is waited for", function() + eq(eval('&paste'), 0) + local pastetoggle = 'lllll' + execute('set pastetoggle=' .. pastetoggle) + execute('set timeoutlen=1', 'set ttimoutlen=10000') + feed(pastetoggle:sub(0, 2)) + -- sleep() for long enough that vgetorpeek() is gotten into, but short + -- enough that ttimeoutlen is not reached. + sleep(200) + feed(pastetoggle:sub(3, -1)) + -- Need another key so that the vgetorpeek() function returns. + feed('j') + eq(eval('&paste'), 1) + end) +end) diff --git a/test/helpers.lua b/test/helpers.lua index 82451bc61d..3fc10e9e30 100644 --- a/test/helpers.lua +++ b/test/helpers.lua @@ -251,6 +251,28 @@ local function concat_tables(...) return ret end +local function dedent(str) + -- find minimum common indent across lines + local indent = nil + for line in str:gmatch('[^\n]+') do + local line_indent = line:match('^%s+') or '' + if indent == nil or #line_indent < #indent then + indent = line_indent + end + end + if indent == nil or #indent == 0 then + -- no minimum common indent + return str + end + -- create a pattern for the indent + indent = indent:gsub('%s', '[ \t]') + -- strip it from the first line + str = str:gsub('^'..indent, '') + -- strip it from the remaining lines + str = str:gsub('[\n]'..indent, '\n') + return str +end + return { eq = eq, neq = neq, @@ -265,4 +287,5 @@ return { hasenv = hasenv, which = which, concat_tables = concat_tables, + dedent = dedent, } diff --git a/test/unit/helpers.lua b/test/unit/helpers.lua index f4e6194fc7..93e1e91173 100644 --- a/test/unit/helpers.lua +++ b/test/unit/helpers.lua @@ -11,6 +11,7 @@ local posix = nil local syscall = nil local check_cores = global_helpers.check_cores +local dedent = global_helpers.dedent local neq = global_helpers.neq local map = global_helpers.map local eq = global_helpers.eq @@ -511,6 +512,189 @@ if os.getenv('NVIM_TEST_PRINT_SYSCALLS') == '1' then end end +local function just_fail(_) + return false +end +say:set('assertion.just_fail.positive', '%s') +say:set('assertion.just_fail.negative', '%s') +assert:register('assertion', 'just_fail', just_fail, + 'assertion.just_fail.positive', + 'assertion.just_fail.negative') + +local hook_fnamelen = 30 +local hook_sfnamelen = 30 +local hook_numlen = 5 +local hook_msglen = 1 + 1 + 1 + (1 + hook_fnamelen) + (1 + hook_sfnamelen) + (1 + hook_numlen) + 1 + +local tracehelp = dedent([[ + ┌ Trace type: _r_eturn from function , function _c_all, _l_ine executed, + │ _t_ail return, _C_ount (should not actually appear). + │┏ Function type: _L_ua function, _C_ function, _m_ain part of chunk, + │┃ function that did _t_ail call. + │┃┌ Function name type: _g_lobal, _l_ocal, _m_ethod, _f_ield, _u_pvalue, + │┃│ space for unknown. + │┃│ ┏ Source file name ┌ Function name ┏ Line + │┃│ ┃ (trunc to 30 bytes, no .lua) │ (truncated to last 30 bytes) ┃ number + CWN SSSSSSSSSSSSSSSSSSSSSSSSSSSSSS:FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF:LLLLL\n +]]) + +local function child_sethook(wr) + local trace_level = os.getenv('NVIM_TEST_TRACE_LEVEL') + if not trace_level or trace_level == '' then + trace_level = 1 + else + trace_level = tonumber(trace_level) + end + if trace_level <= 0 then + return + end + local trace_only_c = trace_level <= 1 + local function hook(reason, lnum) + local info = nil + if reason ~= 'tail return' then -- tail return + info = debug.getinfo(2, 'nSl') + end + + if trace_only_c and (not info or info.what ~= 'C') then + return + end + + local whatchar = ' ' + local namewhatchar = ' ' + local funcname = '' + local source = '' + local msgchar = reason:sub(1, 1) + + if reason == 'count' then + msgchar = 'C' + end + + if info then + funcname = (info.name or ''):sub(1, hook_fnamelen) + whatchar = info.what:sub(1, 1) + namewhatchar = info.namewhat:sub(1, 1) + if namewhatchar == '' then + namewhatchar = ' ' + end + source = info.source + if source:sub(1, 1) == '@' then + if source:sub(-4, -1) == '.lua' then + source = source:sub(1, -5) + end + source = source:sub(-hook_sfnamelen, -1) + end + lnum = lnum or info.currentline + end + + -- assert(-1 <= lnum and lnum <= 99999) + local lnum_s + if lnum == -1 then + lnum_s = 'nknwn' + else + lnum_s = ('%u'):format(lnum) + end + local msg = ( -- lua does not support %* + '' + .. msgchar + .. whatchar + .. namewhatchar + .. ' ' + .. source .. (' '):rep(hook_sfnamelen - #source) + .. ':' + .. funcname .. (' '):rep(hook_fnamelen - #funcname) + .. ':' + .. ('0'):rep(hook_numlen - #lnum_s) .. lnum_s + .. '\n' + ) + -- eq(hook_msglen, #msg) + sc.write(wr, msg) + end + debug.sethook(hook, trace_only_c and 'cr' or 'crl') +end + +local trace_end_msg = ('E%s\n'):format((' '):rep(hook_msglen - 2)) + +local function itp_child(wr, func) + init() + collectgarbage('stop') + child_sethook(wr) + local err, emsg = pcall(func) + debug.sethook() + collectgarbage('restart') + emsg = tostring(emsg) + sc.write(wr, trace_end_msg) + if not err then + if #emsg > 99999 then + emsg = emsg:sub(1, 99999) + end + sc.write(wr, ('-\n%05u\n%s'):format(#emsg, emsg)) + deinit() + sc.close(wr) + sc.exit(1) + else + sc.write(wr, '+\n') + deinit() + sc.close(wr) + sc.exit(0) + end +end + +local function check_child_err(rd) + local trace = {} + while true do + local traceline = sc.read(rd, hook_msglen) + if #traceline ~= hook_msglen then + if #traceline == 0 then + break + else + trace[#trace + 1] = 'Partial read: <' .. trace .. '>\n' + end + end + if traceline == trace_end_msg then + break + end + trace[#trace + 1] = traceline + end + local res = sc.read(rd, 2) + if #res ~= 2 then + local error + if #trace == 0 then + error = '\nTest crashed, no trace available\n' + else + error = '\nTest crashed, trace:\n' .. tracehelp + for i = 1, #trace do + error = error .. trace[i] + end + end + assert.just_fail(error) + end + if res == '+\n' then + return + end + eq('-\n', res) + local len_s = sc.read(rd, 5) + local len = tonumber(len_s) + neq(0, len) + local err = sc.read(rd, len + 1) + assert.just_fail(err) +end + +local function itp_parent(rd, pid, allow_failure) + local err, emsg = pcall(check_child_err, rd) + sc.wait(pid) + sc.close(rd) + if not err then + if allow_failure then + io.stderr:write('Errorred out:\n' .. tostring(emsg) .. '\n') + os.execute([[ + sh -c "source ci/common/test.sh + check_core_dumps --delete \"]] .. Paths.test_luajit_prg .. [[\""]]) + else + error(emsg) + end + end +end + local function gen_itp(it) child_calls_mod = {} child_calls_mod_once = {} @@ -518,14 +702,6 @@ local function gen_itp(it) preprocess_cache_mod = map(function(v) return v end, preprocess_cache_init) previous_defines_mod = previous_defines_init cdefs_mod = cdefs_init:copy() - local function just_fail(_) - return false - end - say:set('assertion.just_fail.positive', '%s') - say:set('assertion.just_fail.negative', '%s') - assert:register('assertion', 'just_fail', just_fail, - 'assertion.just_fail.positive', - 'assertion.just_fail.negative') local function itp(name, func, allow_failure) if allow_failure and os.getenv('NVIM_TEST_RUN_FAILING_TESTS') ~= '1' then -- FIXME Fix tests with this true @@ -535,50 +711,13 @@ local function gen_itp(it) local rd, wr = sc.pipe() child_pid = sc.fork() if child_pid == 0 then - init() sc.close(rd) - collectgarbage('stop') - local err, emsg = pcall(func) - collectgarbage('restart') - emsg = tostring(emsg) - if not err then - sc.write(wr, ('-\n%05u\n%s'):format(#emsg, emsg)) - deinit() - sc.close(wr) - sc.exit(1) - else - sc.write(wr, '+\n') - deinit() - sc.close(wr) - sc.exit(0) - end + itp_child(wr, func) else sc.close(wr) - sc.wait(child_pid) + local saved_child_pid = child_pid child_pid = nil - local function check() - local res = sc.read(rd, 2) - eq(2, #res) - if res == '+\n' then - return - end - eq('-\n', res) - local len_s = sc.read(rd, 5) - local len = tonumber(len_s) - neq(0, len) - local err = sc.read(rd, len + 1) - assert.just_fail(err) - end - local err, emsg = pcall(check) - sc.close(rd) - if not err then - if allow_failure then - io.stderr:write('Errorred out:\n' .. tostring(emsg) .. '\n') - os.execute([[sh -c "source ci/common/test.sh ; check_core_dumps --delete \"]] .. Paths.test_luajit_prg .. [[\""]]) - else - error(emsg) - end - end + itp_parent(rd, saved_child_pid, allow_failure) end end) end @@ -610,6 +749,7 @@ local module = { only_separate = only_separate, child_call_once = child_call_once, child_cleanup_once = child_cleanup_once, + sc = sc, } return function(after_each) if after_each then diff --git a/test/unit/testtest_spec.lua b/test/unit/testtest_spec.lua new file mode 100644 index 0000000000..d2f3632b6f --- /dev/null +++ b/test/unit/testtest_spec.lua @@ -0,0 +1,19 @@ +local helpers = require('test.unit.helpers')(after_each) +local assert = require('luassert') + +local itp = helpers.gen_itp(it) + +local sc = helpers.sc + +-- All of the below tests must fail. Check how exactly they fail. +if os.getenv('NVIM_TEST_RUN_TESTTEST') ~= '1' then + return +end +describe('test code', function() + itp('does not hang when working with lengthy errors', function() + assert.just_fail(('x'):rep(65536)) + end) + itp('shows trace after exiting abnormally', function() + sc.exit(0) + end) +end) |