Merge remote-tracking branch 'upstream/master'

This commit is contained in:
ckelsel 2017-07-30 09:10:22 +08:00
commit 7c7039767a
13 changed files with 843 additions and 590 deletions

View File

@ -27,6 +27,7 @@ Reporting problems
- When reporting a crash, include a stacktrace.
- [Bisect][git-bisect] to the cause of a regression, if you are able. This is _extremely_ helpful.
- Check `$NVIM_LOG_FILE`, if it exists.
- Include `cmake --system-information` for **build** issues.
Pull requests ("PRs")
---------------------
@ -94,8 +95,9 @@ and [AppVeyor].
See [Building Neovim#running-tests][wiki-run-tests] to run tests locally.
Passing locally doesn't guarantee passing the CI build, because of the
different compilers and platforms tested against.
- CI runs [ASan] and other analyzers. To run valgrind locally:
`VALGRIND=1 make test`
- CI runs [ASan] and other analyzers.
- To run valgrind locally: `VALGRIND=1 make test`
- To run Clang ASan/UBSan locally: `CC=clang make CMAKE_FLAGS="-DCLANG_ASAN_UBSAN=ON"`
- The `lint` build ([#3174][3174]) checks modified lines _and their immediate
neighbors_. This is to encourage incrementally updating the legacy style to
meet our style guidelines.

View File

@ -0,0 +1,92 @@
-- TODO(jkeyes): remove this and use the upstream version as soon as it is
-- available in a release of busted.
local pretty = require 'pl.pretty'
return function(options)
local busted = require 'busted'
local handler = require 'busted.outputHandlers.base'()
local success = 'ok %u - %s'
local failure = 'not ' .. success
local skip = 'ok %u - # SKIP %s'
local counter = 0
handler.suiteReset = function()
counter = 0
return nil, true
end
handler.suiteEnd = function()
print('1..' .. counter)
io.flush()
return nil, true
end
local function showFailure(t)
local message = t.message
local trace = t.trace or {}
if message == nil then
message = 'Nil error'
elseif type(message) ~= 'string' then
message = pretty.write(message)
end
print(failure:format(counter, t.name))
print('# ' .. t.element.trace.short_src .. ' @ ' .. t.element.trace.currentline)
if t.randomseed then print('# Random seed: ' .. t.randomseed) end
print('# Failure message: ' .. message:gsub('\n', '\n# '))
if options.verbose and trace.traceback then
print('# ' .. trace.traceback:gsub('^\n', '', 1):gsub('\n', '\n# '))
end
end
handler.testStart = function(element, parent)
local trace = element.trace
if options.verbose and trace and trace.short_src then
local fileline = trace.short_src .. ' @ ' .. trace.currentline .. ': '
local testName = fileline .. handler.getFullName(element)
print('# ' .. testName)
end
io.flush()
return nil, true
end
handler.testEnd = function(element, parent, status, trace)
counter = counter + 1
if status == 'success' then
local t = handler.successes[#handler.successes]
print(success:format(counter, t.name))
elseif status == 'pending' then
local t = handler.pendings[#handler.pendings]
print(skip:format(counter, (t.message or t.name)))
elseif status == 'failure' then
showFailure(handler.failures[#handler.failures])
elseif status == 'error' then
showFailure(handler.errors[#handler.errors])
end
io.flush()
return nil, true
end
handler.error = function(element, parent, message, debug)
if element.descriptor ~= 'it' then
counter = counter + 1
showFailure(handler.errors[#handler.errors])
end
io.flush()
return nil, true
end
busted.subscribe({ 'suite', 'reset' }, handler.suiteReset)
busted.subscribe({ 'suite', 'end' }, handler.suiteEnd)
busted.subscribe({ 'test', 'start' }, handler.testStart, { predicate = handler.cancelOnPending })
busted.subscribe({ 'test', 'end' }, handler.testEnd, { predicate = handler.cancelOnPending })
busted.subscribe({ 'error' }, handler.error)
return handler
end

View File

@ -1,3 +1,6 @@
# Set LC_ALL to meet expectations of some locale-sensitive tests.
set(ENV{LC_ALL} "en_US.UTF-8")
set(ENV{VIMRUNTIME} ${WORKING_DIR}/runtime)
set(ENV{NVIM_RPLUGIN_MANIFEST} ${WORKING_DIR}/Xtest_rplugin_manifest)
set(ENV{XDG_CONFIG_HOME} ${WORKING_DIR}/Xtest_xdg/config)

View File

@ -861,8 +861,7 @@ Exceptions:
Substitute with an expression *sub-replace-expression*
*sub-replace-\=* *s/\=*
When the substitute string starts with "\=" the remainder is interpreted as an
expression. This does not work recursively: a |substitute()| function inside
the expression cannot use "\=" for the substitute string.
expression.
The special meaning for characters as mentioned at |sub-replace-special| does
not apply except for "<CR>". A <NL> character is used as a line break, you

View File

@ -6011,9 +6011,9 @@ range({expr} [, {max} [, {stride}]]) *range()*
*readfile()*
readfile({fname} [, {binary} [, {max}]])
Read file {fname} and return a |List|, each line of the file
as an item. Lines broken at NL characters. Macintosh files
separated with CR will result in a single long line (unless a
NL appears somewhere).
as an item. Lines are broken at NL characters. Macintosh
files separated with CR will result in a single long line
(unless a NL appears somewhere).
All NUL characters are replaced with a NL character.
When {binary} contains "b" binary mode is used:
- When the last line ends in a NL an extra empty list item is
@ -6531,15 +6531,27 @@ serverlist() *serverlist()*
nvim --cmd "echo serverlist()" --cmd "q"
<
serverstart([{address}]) *serverstart()*
Opens a TCP socket (IPv4/IPv6), Unix domain socket (Unix),
or named pipe (Windows) at {address} for clients to connect
to and returns {address}.
Opens a socket or named pipe at {address} and listens for
|RPC| messages. Clients can send |API| commands to the address
to control Nvim. Returns the address string.
If {address} contains `:`, a TCP socket is used. Everything in
front of the last occurrence of `:` is the IP or hostname,
everything after it the port. If the port is empty or `0`,
a random port will be assigned.
If {address} does not contain a colon ":" it is interpreted as
a named pipe or Unix domain socket path.
Example: >
if has('win32')
call serverstart('\\.\pipe\nvim-pipe-1234')
else
call serverstart('nvim.sock')
endif
<
If {address} contains a colon ":" it is interpreted as a TCP
address where the last ":" separates the host and port.
Assigns a random port if it is empty or 0. Supports IPv4/IPv6.
Example: >
:call serverstart('::1:12345')
<
If no address is given, it is equivalent to: >
:call serverstart(tempname())
@ -7318,6 +7330,9 @@ submatch({nr}[, {list}]) *submatch()* *E935*
|substitute()| this list will always contain one or zero
items, since there are no real line breaks.
When substitute() is used recursively only the submatches in
the current (deepest) call can be obtained.
Example: >
:s/\d\+/\=submatch(0) + 1/
< This finds the first number in the line and adds one to it.

View File

@ -79,8 +79,8 @@ Working intuitively and consistently is a major goal of Nvim. Examples:
avoids features that cannot be provided on all platforms--instead that is
delegated to external plugins/extensions.
- Test-only globals and functions such as test_autochdir(), test_settime(),
etc., are not exposed (because they don't exist).
- Vim's internal test functions (test_autochdir(), test_settime(), etc.) are
not exposed (nor implemented); instead Nvim has a robust API.
ARCHITECTURE ~
@ -89,6 +89,9 @@ stability and allows those plugins to work without blocking the editor. Even
"legacy" Python and Ruby plugins which use the old Vim interfaces (|if_py| and
|if_ruby|) run out-of-process.
Platform and I/O facilities are built upon libuv. Nvim benefits from libuv
features and bug fixes, and other projects benefit from improvements to libuv
by Nvim developers.
FEATURES ~

View File

@ -447,7 +447,7 @@ static void out_data_append_to_screen(char *output, size_t remaining,
size_t off = 0;
int last_row = (int)Rows - 1;
while (off < remaining) {
while (output != NULL && off < remaining) {
// Found end of line?
if (output[off] == NL) {
// Can we start a new line or do we need to continue the last one?
@ -473,7 +473,7 @@ static void out_data_append_to_screen(char *output, size_t remaining,
off++;
}
if (remaining) {
if (output != NULL && remaining) {
if (last_col == 0) {
screen_del_lines(0, 0, 1, (int)Rows, NULL);
}
@ -496,12 +496,8 @@ static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data,
size_t cnt;
char *ptr = rbuffer_read_ptr(buf, &cnt);
if (ptr == NULL || cnt == 0) {
// Nothing to read;
return;
}
if (out_data_decide_throttle(cnt)) { // Skip output above a threshold.
if (ptr != NULL && cnt > 0
&& out_data_decide_throttle(cnt)) { // Skip output above a threshold.
// Save the skipped output. If it is the final chunk, we display it later.
out_data_ring(ptr, cnt);
} else {

File diff suppressed because it is too large Load Diff

View File

@ -4882,7 +4882,7 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
int c2_len = PTR2LEN(s2);
int c2 = PTR2CHAR(s2);
if ((c1 != c2 && (!ireg_ic || mb_tolower(c1) != mb_tolower(c2)))
if ((c1 != c2 && (!rex.reg_ic || mb_tolower(c1) != mb_tolower(c2)))
|| c1_len != c2_len) {
match = false;
break;
@ -4895,13 +4895,13 @@ static long find_match_text(colnr_T startcol, int regstart, char_u *match_text)
&& !(enc_utf8 && utf_iscomposing(PTR2CHAR(s2)))) {
cleanup_subexpr();
if (REG_MULTI) {
reg_startpos[0].lnum = reglnum;
reg_startpos[0].col = col;
reg_endpos[0].lnum = reglnum;
reg_endpos[0].col = s2 - regline;
rex.reg_startpos[0].lnum = reglnum;
rex.reg_startpos[0].col = col;
rex.reg_endpos[0].lnum = reglnum;
rex.reg_endpos[0].col = s2 - regline;
} else {
reg_startp[0] = regline + col;
reg_endp[0] = s2;
rex.reg_startp[0] = regline + col;
rex.reg_endp[0] = s2;
}
return 1L;
}
@ -5116,8 +5116,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
case NFA_MATCH:
{
// If the match ends before a composing characters and
// ireg_icombine is not set, that is not really a match.
if (enc_utf8 && !ireg_icombine && utf_iscomposing(curc)) {
// rex.reg_icombine is not set, that is not really a match.
if (enc_utf8 && !rex.reg_icombine && utf_iscomposing(curc)) {
break;
}
nfa_match = true;
@ -5400,15 +5400,15 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
int this_class;
// Get class of current and previous char (if it exists).
this_class = mb_get_class_tab(reginput, reg_buf->b_chartab);
this_class = mb_get_class_tab(reginput, rex.reg_buf->b_chartab);
if (this_class <= 1) {
result = false;
} else if (reg_prev_class() == this_class) {
result = false;
}
} else if (!vim_iswordc_buf(curc, reg_buf)
} else if (!vim_iswordc_buf(curc, rex.reg_buf)
|| (reginput > regline
&& vim_iswordc_buf(reginput[-1], reg_buf))) {
&& vim_iswordc_buf(reginput[-1], rex.reg_buf))) {
result = false;
}
if (result) {
@ -5425,15 +5425,15 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
int this_class, prev_class;
// Get class of current and previous char (if it exists).
this_class = mb_get_class_tab(reginput, reg_buf->b_chartab);
this_class = mb_get_class_tab(reginput, rex.reg_buf->b_chartab);
prev_class = reg_prev_class();
if (this_class == prev_class
|| prev_class == 0 || prev_class == 1) {
result = false;
}
} else if (!vim_iswordc_buf(reginput[-1], reg_buf)
} else if (!vim_iswordc_buf(reginput[-1], rex.reg_buf)
|| (reginput[0] != NUL
&& vim_iswordc_buf(curc, reg_buf))) {
&& vim_iswordc_buf(curc, rex.reg_buf))) {
result = false;
}
if (result) {
@ -5444,14 +5444,14 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
case NFA_BOF:
if (reglnum == 0 && reginput == regline
&& (!REG_MULTI || reg_firstlnum == 1)) {
&& (!REG_MULTI || rex.reg_firstlnum == 1)) {
add_here = true;
add_state = t->state->out;
}
break;
case NFA_EOF:
if (reglnum == reg_maxline && curc == NUL) {
if (reglnum == rex.reg_maxline && curc == NUL) {
add_here = true;
add_state = t->state->out;
}
@ -5475,7 +5475,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
// (no preceding character).
len += mb_char2len(mc);
}
if (ireg_icombine && len == 0) {
if (rex.reg_icombine && len == 0) {
// If \Z was present, then ignore composing characters.
// When ignoring the base character this always matches.
if (sta->c != curc) {
@ -5526,14 +5526,14 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
}
case NFA_NEWL:
if (curc == NUL && !reg_line_lbr && REG_MULTI
&& reglnum <= reg_maxline) {
if (curc == NUL && !rex.reg_line_lbr && REG_MULTI
&& reglnum <= rex.reg_maxline) {
go_to_nextline = true;
// Pass -1 for the offset, which means taking the position
// at the start of the next line.
add_state = t->state->out;
add_off = -1;
} else if (curc == '\n' && reg_line_lbr) {
} else if (curc == '\n' && rex.reg_line_lbr) {
// match \n as if it is an ordinary character
add_state = t->state->out;
add_off = 1;
@ -5574,7 +5574,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
result = result_if_matched;
break;
}
if (ireg_ic) {
if (rex.reg_ic) {
int curc_low = mb_tolower(curc);
int done = false;
@ -5591,7 +5591,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
}
} else if (state->c < 0 ? check_char_class(state->c, curc)
: (curc == state->c
|| (ireg_ic && mb_tolower(curc)
|| (rex.reg_ic && mb_tolower(curc)
== mb_tolower(state->c)))) {
result = result_if_matched;
break;
@ -5639,13 +5639,13 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
break;
case NFA_KWORD: // \k
result = vim_iswordp_buf(reginput, reg_buf);
result = vim_iswordp_buf(reginput, rex.reg_buf);
ADD_STATE_IF_MATCH(t->state);
break;
case NFA_SKWORD: // \K
result = !ascii_isdigit(curc)
&& vim_iswordp_buf(reginput, reg_buf);
&& vim_iswordp_buf(reginput, rex.reg_buf);
ADD_STATE_IF_MATCH(t->state);
break;
@ -5760,24 +5760,24 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
break;
case NFA_LOWER_IC: // [a-z]
result = ri_lower(curc) || (ireg_ic && ri_upper(curc));
result = ri_lower(curc) || (rex.reg_ic && ri_upper(curc));
ADD_STATE_IF_MATCH(t->state);
break;
case NFA_NLOWER_IC: // [^a-z]
result = curc != NUL
&& !(ri_lower(curc) || (ireg_ic && ri_upper(curc)));
&& !(ri_lower(curc) || (rex.reg_ic && ri_upper(curc)));
ADD_STATE_IF_MATCH(t->state);
break;
case NFA_UPPER_IC: // [A-Z]
result = ri_upper(curc) || (ireg_ic && ri_lower(curc));
result = ri_upper(curc) || (rex.reg_ic && ri_lower(curc));
ADD_STATE_IF_MATCH(t->state);
break;
case NFA_NUPPER_IC: // [^A-Z]
result = curc != NUL
&& !(ri_upper(curc) || (ireg_ic && ri_lower(curc)));
&& !(ri_upper(curc) || (rex.reg_ic && ri_lower(curc)));
ADD_STATE_IF_MATCH(t->state);
break;
@ -5851,13 +5851,15 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
case NFA_LNUM_GT:
case NFA_LNUM_LT:
assert(t->state->val >= 0
&& !((reg_firstlnum > 0 && reglnum > LONG_MAX - reg_firstlnum)
|| (reg_firstlnum <0 && reglnum < LONG_MIN + reg_firstlnum))
&& reglnum + reg_firstlnum >= 0);
&& !((rex.reg_firstlnum > 0
&& reglnum > LONG_MAX - rex.reg_firstlnum)
|| (rex.reg_firstlnum < 0
&& reglnum < LONG_MIN + rex.reg_firstlnum))
&& reglnum + rex.reg_firstlnum >= 0);
result = (REG_MULTI
&& nfa_re_num_cmp((uintmax_t)t->state->val,
t->state->c - NFA_LNUM,
(uintmax_t)(reglnum + reg_firstlnum)));
(uintmax_t)(reglnum + rex.reg_firstlnum)));
if (result) {
add_here = true;
add_state = t->state->out;
@ -5893,7 +5895,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
}
result = false;
win_T *wp = reg_win == NULL ? curwin : reg_win;
win_T *wp = rex.reg_win == NULL ? curwin : rex.reg_win;
if (op == 1 && col - 1 > t->state->val && col > 100) {
long ts = wp->w_buffer->b_p_ts;
@ -5920,18 +5922,18 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
case NFA_MARK_GT:
case NFA_MARK_LT:
{
pos_T *pos = getmark_buf(reg_buf, t->state->val, FALSE);
pos_T *pos = getmark_buf(rex.reg_buf, t->state->val, false);
// Compare the mark position to the match position.
result = (pos != NULL // mark doesn't exist
&& pos->lnum > 0 // mark isn't set in reg_buf
&& (pos->lnum == reglnum + reg_firstlnum
&& (pos->lnum == reglnum + rex.reg_firstlnum
? (pos->col == (colnr_T)(reginput - regline)
? t->state->c == NFA_MARK
: (pos->col < (colnr_T)(reginput - regline)
? t->state->c == NFA_MARK_GT
: t->state->c == NFA_MARK_LT))
: (pos->lnum < reglnum + reg_firstlnum
: (pos->lnum < reglnum + rex.reg_firstlnum
? t->state->c == NFA_MARK_GT
: t->state->c == NFA_MARK_LT)));
if (result) {
@ -5942,10 +5944,10 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
}
case NFA_CURSOR:
result = (reg_win != NULL
&& (reglnum + reg_firstlnum == reg_win->w_cursor.lnum)
result = (rex.reg_win != NULL
&& (reglnum + rex.reg_firstlnum == rex.reg_win->w_cursor.lnum)
&& ((colnr_T)(reginput - regline)
== reg_win->w_cursor.col));
== rex.reg_win->w_cursor.col));
if (result) {
add_here = true;
add_state = t->state->out;
@ -5995,13 +5997,13 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
#endif
result = (c == curc);
if (!result && ireg_ic) {
if (!result && rex.reg_ic) {
result = mb_tolower(c) == mb_tolower(curc);
}
// If ireg_icombine is not set only skip over the character
// If rex.reg_icombine is not set only skip over the character
// itself. When it is set skip over composing characters.
if (result && enc_utf8 && !ireg_icombine) {
if (result && enc_utf8 && !rex.reg_icombine) {
clen = utf_ptr2len(reginput);
}
@ -6109,8 +6111,8 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
&& ((toplevel
&& reglnum == 0
&& clen != 0
&& (ireg_maxcol == 0
|| (colnr_T)(reginput - regline) < ireg_maxcol))
&& (rex.reg_maxcol == 0
|| (colnr_T)(reginput - regline) < rex.reg_maxcol))
|| (nfa_endp != NULL
&& (REG_MULTI
? (reglnum < nfa_endp->se_u.pos.lnum
@ -6145,7 +6147,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start,
// Checking if the required start character matches is
// cheaper than adding a state that won't match.
c = PTR2CHAR(reginput + clen);
if (c != prog->regstart && (!ireg_ic || mb_tolower(c)
if (c != prog->regstart && (!rex.reg_ic || mb_tolower(c)
!= mb_tolower(prog->regstart))) {
#ifdef REGEXP_DEBUG
fprintf(log_fd,
@ -6271,34 +6273,37 @@ static long nfa_regtry(nfa_regprog_T *prog, colnr_T col, proftime_T *tm)
cleanup_subexpr();
if (REG_MULTI) {
for (i = 0; i < subs.norm.in_use; i++) {
reg_startpos[i].lnum = subs.norm.list.multi[i].start_lnum;
reg_startpos[i].col = subs.norm.list.multi[i].start_col;
rex.reg_startpos[i].lnum = subs.norm.list.multi[i].start_lnum;
rex.reg_startpos[i].col = subs.norm.list.multi[i].start_col;
reg_endpos[i].lnum = subs.norm.list.multi[i].end_lnum;
reg_endpos[i].col = subs.norm.list.multi[i].end_col;
rex.reg_endpos[i].lnum = subs.norm.list.multi[i].end_lnum;
rex.reg_endpos[i].col = subs.norm.list.multi[i].end_col;
}
if (reg_startpos[0].lnum < 0) {
reg_startpos[0].lnum = 0;
reg_startpos[0].col = col;
if (rex.reg_startpos[0].lnum < 0) {
rex.reg_startpos[0].lnum = 0;
rex.reg_startpos[0].col = col;
}
if (rex.reg_endpos[0].lnum < 0) {
// pattern has a \ze but it didn't match, use current end
rex.reg_endpos[0].lnum = reglnum;
rex.reg_endpos[0].col = (int)(reginput - regline);
} else {
// Use line number of "\ze".
reglnum = rex.reg_endpos[0].lnum;
}
if (reg_endpos[0].lnum < 0) {
/* pattern has a \ze but it didn't match, use current end */
reg_endpos[0].lnum = reglnum;
reg_endpos[0].col = (int)(reginput - regline);
} else
/* Use line number of "\ze". */
reglnum = reg_endpos[0].lnum;
} else {
for (i = 0; i < subs.norm.in_use; i++) {
reg_startp[i] = subs.norm.list.line[i].start;
reg_endp[i] = subs.norm.list.line[i].end;
rex.reg_startp[i] = subs.norm.list.line[i].start;
rex.reg_endp[i] = subs.norm.list.line[i].end;
}
if (reg_startp[0] == NULL)
reg_startp[0] = regline + col;
if (reg_endp[0] == NULL)
reg_endp[0] = reginput;
if (rex.reg_startp[0] == NULL) {
rex.reg_startp[0] = regline + col;
}
if (rex.reg_endp[0] == NULL) {
rex.reg_endp[0] = reginput;
}
}
/* Package any found \z(...\) matches for export. Default is none. */
@ -6352,14 +6357,14 @@ static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm)
colnr_T col = startcol;
if (REG_MULTI) {
prog = (nfa_regprog_T *)reg_mmatch->regprog;
line = reg_getline((linenr_T)0); /* relative to the cursor */
reg_startpos = reg_mmatch->startpos;
reg_endpos = reg_mmatch->endpos;
prog = (nfa_regprog_T *)rex.reg_mmatch->regprog;
line = reg_getline((linenr_T)0); // relative to the cursor
rex.reg_startpos = rex.reg_mmatch->startpos;
rex.reg_endpos = rex.reg_mmatch->endpos;
} else {
prog = (nfa_regprog_T *)reg_match->regprog;
reg_startp = reg_match->startp;
reg_endp = reg_match->endp;
prog = (nfa_regprog_T *)rex.reg_match->regprog;
rex.reg_startp = rex.reg_match->startp;
rex.reg_endp = rex.reg_match->endp;
}
/* Be paranoid... */
@ -6368,15 +6373,17 @@ static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm)
goto theend;
}
/* If pattern contains "\c" or "\C": overrule value of ireg_ic */
if (prog->regflags & RF_ICASE)
ireg_ic = TRUE;
else if (prog->regflags & RF_NOICASE)
ireg_ic = FALSE;
// If pattern contains "\c" or "\C": overrule value of rex.reg_ic
if (prog->regflags & RF_ICASE) {
rex.reg_ic = true;
} else if (prog->regflags & RF_NOICASE) {
rex.reg_ic = false;
}
/* If pattern contains "\Z" overrule value of ireg_icombine */
if (prog->regflags & RF_ICOMBINE)
ireg_icombine = TRUE;
// If pattern contains "\Z" overrule value of rex.reg_icombine
if (prog->regflags & RF_ICOMBINE) {
rex.reg_icombine = true;
}
regline = line;
reglnum = 0; /* relative to line */
@ -6405,17 +6412,17 @@ static long nfa_regexec_both(char_u *line, colnr_T startcol, proftime_T *tm)
if (skip_to_start(prog->regstart, &col) == FAIL)
return 0L;
/* If match_text is set it contains the full text that must match.
* Nothing else to try. Doesn't handle combining chars well. */
if (prog->match_text != NULL
&& !ireg_icombine
)
// If match_text is set it contains the full text that must match.
// Nothing else to try. Doesn't handle combining chars well.
if (prog->match_text != NULL && !rex.reg_icombine) {
return find_match_text(col, prog->regstart, prog->match_text);
}
}
/* If the start column is past the maximum column: no need to try. */
if (ireg_maxcol > 0 && col >= ireg_maxcol)
// If the start column is past the maximum column: no need to try.
if (rex.reg_maxcol > 0 && col >= rex.reg_maxcol) {
goto theend;
}
nstate = prog->nstate;
for (i = 0; i < nstate; ++i) {
@ -6567,15 +6574,15 @@ nfa_regexec_nl (
bool line_lbr
)
{
reg_match = rmp;
reg_mmatch = NULL;
reg_maxline = 0;
reg_line_lbr = line_lbr;
reg_buf = curbuf;
reg_win = NULL;
ireg_ic = rmp->rm_ic;
ireg_icombine = FALSE;
ireg_maxcol = 0;
rex.reg_match = rmp;
rex.reg_mmatch = NULL;
rex.reg_maxline = 0;
rex.reg_line_lbr = line_lbr;
rex.reg_buf = curbuf;
rex.reg_win = NULL;
rex.reg_ic = rmp->rm_ic;
rex.reg_icombine = false;
rex.reg_maxcol = 0;
return nfa_regexec_both(line, col, NULL);
}
@ -6616,16 +6623,16 @@ nfa_regexec_nl (
static long nfa_regexec_multi(regmmatch_T *rmp, win_T *win, buf_T *buf,
linenr_T lnum, colnr_T col, proftime_T *tm)
{
reg_match = NULL;
reg_mmatch = rmp;
reg_buf = buf;
reg_win = win;
reg_firstlnum = lnum;
reg_maxline = reg_buf->b_ml.ml_line_count - lnum;
reg_line_lbr = FALSE;
ireg_ic = rmp->rmm_ic;
ireg_icombine = FALSE;
ireg_maxcol = rmp->rmm_maxcol;
rex.reg_match = NULL;
rex.reg_mmatch = rmp;
rex.reg_buf = buf;
rex.reg_win = win;
rex.reg_firstlnum = lnum;
rex.reg_maxline = rex.reg_buf->b_ml.ml_line_count - lnum;
rex.reg_line_lbr = false;
rex.reg_ic = rmp->rmm_ic;
rex.reg_icombine = false;
rex.reg_maxcol = rmp->rmm_maxcol;
return nfa_regexec_both(NULL, col, tm);
}

View File

@ -209,3 +209,26 @@ func Test_expand_star_star()
bwipe!
call delete('a', 'rf')
endfunc
func Test_paste_in_cmdline()
let @a = "def"
call feedkeys(":abc \<C-R>a ghi\<C-B>\"\<CR>", 'tx')
call assert_equal('"abc def ghi', @:)
new
call setline(1, 'asdf.x /tmp/some verylongword a;b-c*d ')
call feedkeys(":aaa \<C-R>\<C-W> bbb\<C-B>\"\<CR>", 'tx')
call assert_equal('"aaa asdf bbb', @:)
call feedkeys("ft:aaa \<C-R>\<C-F> bbb\<C-B>\"\<CR>", 'tx')
call assert_equal('"aaa /tmp/some bbb', @:)
set incsearch
call feedkeys("fy:aaa veryl\<C-R>\<C-W> bbb\<C-B>\"\<CR>", 'tx')
call assert_equal('"aaa verylongword bbb', @:)
call feedkeys("f;:aaa \<C-R>\<C-A> bbb\<C-B>\"\<CR>", 'tx')
call assert_equal('"aaa a;b-c*d bbb', @:)
bwipe!
endfunc

View File

@ -384,9 +384,10 @@ func Test_substitute_expr()
\ {-> submatch(2) . submatch(3) . submatch(1)}, ''))
func Recurse()
return substitute('yyy', 'y*', {-> g:val}, '')
return substitute('yyy', 'y\(.\)y', {-> submatch(1)}, '')
endfunc
call assert_equal('--', substitute('xxx', 'x*', {-> '-' . Recurse() . '-'}, ''))
" recursive call works
call assert_equal('-y-x-', substitute('xxx', 'x\(.\)x', {-> '-' . Recurse() . '-' . submatch(1) . '-'}, ''))
endfunc
func Test_invalid_submatch()

View File

@ -1255,21 +1255,27 @@ func! Test_normal22_zet()
" Test for ZZ
" let shell = &shell
" let &shell = 'sh'
call writefile(['1', '2'], 'Xfile')
let args = ' --headless -u NONE -N -U NONE -i NONE --noplugins'
call system(v:progpath . args . ' -c "%d" -c ":norm! ZZ" Xfile')
let a = readfile('Xfile')
call assert_equal([], a)
" Test for ZQ
call writefile(['1', '2'], 'Xfile')
call system(v:progpath . args . ' -c "%d" -c ":norm! ZQ" Xfile')
let a = readfile('Xfile')
call assert_equal(['1', '2'], a)
" clean up
for file in ['Xfile']
" Remove any stale test files from previous run.
for file in ['Xfile_Test_normal22_zet']
call delete(file)
endfor
call writefile(['1', '2'], 'Xfile_Test_normal22_zet')
let args = ' --headless -u NONE -N -U NONE -i NONE --noplugins'
call system(v:progpath . args . ' -c "%d" -c ":norm! ZZ" Xfile_Test_normal22_zet')
let a = readfile('Xfile_Test_normal22_zet')
call assert_equal([], a)
" Test for ZQ
call writefile(['1', '2'], 'Xfile_Test_normal22_zet')
call system(v:progpath . args . ' -c "%d" -c ":norm! ZQ" Xfile_Test_normal22_zet')
let a = readfile('Xfile_Test_normal22_zet')
call assert_equal(['1', '2'], a)
" Nvim: This sometimes hangs the TSAN build.
" for file in ['Xfile_Test_normal22_zet']
" call delete(file)
" endfor
" let &shell = shell
endfunc

View File

@ -610,7 +610,7 @@ static const int included_patches[] = {
// 122 NA
121,
// 120 NA
// 119,
119,
// 118,
// 117 NA
116,
@ -709,7 +709,7 @@ static const int included_patches[] = {
23,
// 22 NA
// 21,
// 20,
20,
19,
// 18,
17,