Compare commits

...

23 Commits

Author SHA1 Message Date
Bram Moolenaar
da22b8cc8b patch 8.0.1037: "icase" of 'diffopt' is not used for highlighting
Problem:    "icase" of 'diffopt' is not used for highlighting differences.
Solution:   Also use "icase". (Rick Howe)
2017-09-02 18:01:50 +02:00
Bram Moolenaar
dada6d2a8e patch 8.0.1036: ++eof argument for terminal only available on MS-Windows
Problem:    ++eof argument for terminal only available on MS-Windows.
Solution:   Also support ++eof on Unix.  Add a test.
2017-09-02 17:18:35 +02:00
Bram Moolenaar
ef68e4fa52 patch 8.0.1035: sending buffer lines to terminal doesn't work on MS-Windows
Problem:    Sending buffer lines to terminal doesn't work on MS-Windows.
Solution:   Use CR instead of NL after every line.  Make the EOF text work
            properly.  Add the ++eof argument to :terminal.
2017-09-02 16:28:36 +02:00
Bram Moolenaar
3346cc4ffb patch 8.0.1034: sending buffer lines to terminal doesn't work on MS-Windows
Problem:    Sending buffer lines to terminal doesn't work on MS-Windows.
Solution:   Send CTRL-D to mark the end of the text. (Yasuhiro Matsumoto,
            closes #2043) Add the "eof_chars" option.
2017-09-02 14:54:21 +02:00
Bram Moolenaar
995e4afcfe patch 8.0.1033: detecting background color does not work in screen
Problem:    Detecting background color does not work in screen, even when it
            is working like an xterm.
Solution:   Make "screen.xterm" use termcap entries like an xterm. (Lubomir
            Rintel, closes #2048)  When termresponse version is huge also
            recognize as not being an xterm.
2017-09-01 20:24:03 +02:00
Bram Moolenaar
9ac9dfa9e2 patch 8.0.1032: "make tags" doesn't work well on MS-Windows
Problem:    "make tags" doesn't work well on MS-Windows.
Solution:   Add or fix tags target. (Ken Takata)
2017-09-01 18:41:26 +02:00
Bram Moolenaar
2c809b7c7d patch 8.0.1031: "text" argument for getqflist() is confusing
Problem:    "text" argument for getqflist() is confusing. (Lcd47)
Solution:   Use "lines" instead. (Yegappan Lakshmanan)
2017-09-01 18:34:02 +02:00
Bram Moolenaar
9e8dcf9d6f patch 8.0.1030: MS-Windows: wrong size computation in is_cygpty()
Problem:    MS-Windows: wrong size computation in is_cygpty().
Solution:   Compute the size properly. (Ken Takata)
2017-08-31 21:35:45 +02:00
Bram Moolenaar
da73253a0b patch 8.0.1029: return value of getqflist() is inconsistent
Problem:    Return value of getqflist() is inconsistent.  (Lcd47)
Solution:   Always return an "items" entry.
2017-08-31 20:58:02 +02:00
Bram Moolenaar
3d593c2dc9 patch 8.0.1028: MS-Windows: viminfo uses $VIM/_viminfo if $HOME not set
Problem:    MS-Windows: viminfo uses $VIM/_viminfo if $HOME not set. (Yongwei
            Wu)
Solution:   Use vim_getenv() but check it's returning the default "C:/".
2017-08-31 20:42:18 +02:00
Bram Moolenaar
2db0ec4b2e patch 8.0.1027: more terminals can't handle requesting cursor mode
Problem:    More terminals can't handle requesting cursor mode.
Solution:   Recognize Putty. (Hirohito Higashi)  Also include Xfce in the
            version check. (Dominique Pelle)  Recognize Konsole.
2017-08-31 20:17:59 +02:00
Bram Moolenaar
5c6dbcb03f patch 8.0.1026: GTK on-the-spot input has problems
Problem:    GTK on-the-spot input has problems. (Gerd Wachsmuth)
Solution:   Support over-the-spot. (Yukihiro Nakadaira, Ketn Takata, closes
            #1215)
2017-08-30 22:00:20 +02:00
Bram Moolenaar
4e83961985 patch 8.0.1025: stray copy command in test
Problem:    Stray copy command in test.
Solution:   Remove the copy command.
2017-08-30 21:58:03 +02:00
Bram Moolenaar
4bebc9a056 patch 8.0.1024: folds lost when session file has a buffer in two windows
Problem:    Manual folds are lost when a session file has the same buffer in
            two windows. (Jeansen)
Solution:   Use ":edit" only once. (Christian Brabandt, closes #1958)
2017-08-30 21:07:38 +02:00
Bram Moolenaar
a539f4f1ae patch 8.0.1023: it is not easy to identify a quickfix list
Problem:    It is not easy to identify a quickfix list.
Solution:   Add the "id" field. (Yegappan Lakshmanan)
2017-08-30 20:33:55 +02:00
Bram Moolenaar
1a333bc44a patch 8.0.1022: test 80 is old style
Problem:    Test 80 is old style.
Solution:   Turn it into a new style test. (Yegappan Lakshmanan)
2017-08-30 20:21:58 +02:00
Bram Moolenaar
dc5471d482 patch 8.0.1021: older Gnome terminal still echoes t_RC
Problem:    Older Gnome terminal still echoes t_RC. (Fracois Ingelrest)
Solution:   Check for version > 3000 instead of 4000.
2017-08-30 18:59:03 +02:00
Bram Moolenaar
0f0f230012 patch 8.0.1020: when a timer calls getchar(1) input is overwritten
Problem:    When a timer calls getchar(1) input is overwritten.
Solution:   Increment tb_change_cnt in inchar(). (closes #1940)
2017-08-30 18:52:56 +02:00
Bram Moolenaar
d41babef89 patch 8.0.1019: pasting in virtual edit happens in the wrong place
Problem:    Pasting in virtual edit happens in the wrong place.
Solution:   Do not adjust coladd when after the end of the line (closes #2015)
2017-08-30 17:01:35 +02:00
Bram Moolenaar
4ad3b2b588 patch 8.0.1018: warnings from 64-bit compiler
Problem:    Warnings from 64-bit compiler. (Christian Brabandt)
Solution:   Add type casts.
2017-08-30 15:57:33 +02:00
Bram Moolenaar
dde6034111 patch 8.0.1017: test for MS-Windows $HOME always passes
Problem:    Test for MS-Windows $HOME always passes.
Solution:   Rename the test function.  Make the test pass.
2017-08-30 14:55:42 +02:00
Bram Moolenaar
f3af54eeb1 patch 8.0.1016: gnome terminal echoes t_RC
Problem:    Gnome terminal echoes t_RC.
Solution:   Detect Gnome terminal by the version string.  Add v: variables for
            all the term responses.
2017-08-30 14:53:06 +02:00
Bram Moolenaar
97a80e440a patch 8.0.1015: missing update to terminal test
Problem:    Missing update to terminal test.
Solution:   Add the changes to the test.
2017-08-30 13:31:49 +02:00
44 changed files with 1165 additions and 703 deletions

View File

@@ -1902,6 +1902,26 @@ v:termresponse The escape sequence returned by the terminal for the |t_RV|
always 95 or bigger). Pc is always zero.
{only when compiled with |+termresponse| feature}
*v:termblinkresp*
v:termblinkresp The escape sequence returned by the terminal for the |t_RC|
termcap entry. This is used to find out whether the terminal
cursor is blinking. This is used by |term_getcursor()|.
*v:termstyleresp*
v:termstyleresp The escape sequence returned by the terminal for the |t_RS|
termcap entry. This is used to find out what the shape of the
cursor is. This is used by |term_getcursor()|.
*v:termrgbresp*
v:termrgbresp The escape sequence returned by the terminal for the |t_RB|
termcap entry. This is used to find out what the terminal
background color is, see 'background'.
*v:termu7resp*
v:termu7resp The escape sequence returned by the terminal for the |t_u7|
termcap entry. This is used to find out what the terminal
does with ambiguous width characters, see 'ambiwidth'.
*v:testing* *testing-variable*
v:testing Must be set before using `test_garbagecollect_now()`.
Also, when set certain error messages won't be shown for 2
@@ -4612,20 +4632,24 @@ getqflist([{what}]) *getqflist()*
returns only the items listed in {what} as a dictionary. The
following string items are supported in {what}:
context get the context stored with |setqflist()|
id get information for the quickfix list with
|quickfix-ID|; zero means the id for the
current list or the list specifed by 'nr'
items quickfix list entries
lines use 'errorformat' to extract items from a list
of lines and return the resulting entries.
Only a |List| type is accepted. The current
quickfix list is not modified.
nr get information for this quickfix list; zero
means the current quickfix list and '$' means
the last quickfix list
text use 'errorformat' to extract items from the
text and return the resulting entries. The
value can be a string with one line or a list
with multiple lines. The current quickfix list
is not modified.
title get the list title
winid get the |window-ID| (if opened)
all all of the above quickfix properties
Non-string items in {what} are ignored.
If "nr" is not present then the current quickfix list is used.
If both "nr" and a non-zero "id" are specified, then the list
specified by "id" is used.
To get the number of lists in the quickfix stack, set 'nr' to
'$' in {what}. The 'nr' value in the returned dictionary
contains the quickfix stack size.
@@ -4637,6 +4661,7 @@ getqflist([{what}]) *getqflist()*
The returned dictionary contains the following entries:
context context information stored with |setqflist()|
id quickfix list ID |quickfix-ID|
items quickfix list entries
nr quickfix list number
title quickfix list title text
@@ -4645,6 +4670,7 @@ getqflist([{what}]) *getqflist()*
Examples: >
:echo getqflist({'all': 1})
:echo getqflist({'nr': 2, 'title': 1})
:echo getqflist({'lines' : ["F1:10:L10"]})
<
getreg([{regname} [, 1 [, {list}]]]) *getreg()*
@@ -7045,12 +7071,12 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
argument is ignored. The following items can be specified in
{what}:
context any Vim type can be stored as a context
text use 'errorformat' to extract items from the
text and add the resulting entries to the
quickfix list {nr}. The value can be a string
with one line or a list with multiple lines.
id quickfix list identifier |quickfix-ID|
items list of quickfix entries. Same as the {list}
argument.
lines use 'errorformat' to parse a list of lines and
add the resulting entries to the quickfix list
{nr} or {id}. Only a |List| value is supported.
nr list number in the quickfix stack; zero
means the current quickfix list and '$' means
the last quickfix list
@@ -7059,10 +7085,14 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
If the "nr" item is not present, then the current quickfix list
is modified. When creating a new quickfix list, "nr" can be
set to a value one greater than the quickfix stack size.
When modifying a quickfix list, to guarantee that the correct
list is modified, 'id' should be used instead of 'nr' to
specify the list.
Examples: >
:call setqflist([], 'r', {'title': 'My search'})
:call setqflist([], 'r', {'nr': 2, 'title': 'Errors'})
:call setqflist([], 'r', {'title': 'My search'})
:call setqflist([], 'r', {'nr': 2, 'title': 'Errors'})
:call setqflist([], 'a', {'id':myid, 'lines':["F1:10:L10"]})
<
Returns zero for success, -1 for failure.
@@ -8111,6 +8141,12 @@ term_start({cmd}, {options}) *term_start()*
have "%d" where the buffer number goes,
e.g. "10split|buffer %d"; when not
specified "botright sbuf %d" is used
"eof_chars" Text to send after all buffer lines were
written to the terminal. When not set
CTRL-D is used. For Python use CTRL-Z or
"exit()". For a shell use "exit". A CR
is always added.
{only on MS-Windows}
{only available when compiled with the |+terminal| feature}

View File

@@ -832,6 +832,9 @@ Use the RPM or port for your system.
Currently, GUI Vim supports three styles, |OverTheSpot|, |OffTheSpot| and
|Root|.
When compiled with |+GUI_GTK| feature, GUI Vim supports two styles,
|OnTheSpot| and |OverTheSpot|. You can select the style with the 'imstyle'
option.
*. on-the-spot *OnTheSpot*
Preedit Area and Status Area are performed by the client application in

View File

@@ -4356,6 +4356,23 @@ A jump table for the options with a short description can be found at |Q_op|.
<
NOTE: This function is invoked very often. Keep it fast.
*'imstyle'* *'imst'*
'imstyle' 'imst' number (default 1)
global
{not in Vi}
{only available when compiled with |+xim| and
|+GUI_GTK|}
This option specifies the input style of Input Method.
Set to zero if you want to use on-the-spot style.
Set to one if you want to use over-the-spot style.
See: |xim-input-style|
For a long time on-the-spot sytle had been used in GTK version of vim,
however, it is known that it causes troubles when using mappings,
|single-repeat|, etc. Therefore over-the-spot style becomes the
default now. This should work fine for most people, however if you
have any problem with it, try using on-the-spot style.
*'include'* *'inc'*
'include' 'inc' string (default "^\s*#\s*include")
global or local to buffer |global-local|

View File

@@ -133,6 +133,14 @@ Syntax ~
height.
++cols={width} Use {width} for the terminal window
width.
++eof={text} when using [range], text to send after
the last line was written. The default
is to send CTRL-D. A CR is appended.
E.g. for a shell use "++eof=exit" and
for Python "++eof=exit()". Special
codes can be used like with `:map`,
e.g. "<C-Z>" for CTRL-Z.
{only on MS-Windows}
If you want to use more options use the |term_start()|
function.
@@ -141,11 +149,13 @@ When the buffer associated with the terminal is unloaded or wiped out the job
is killed, similar to calling `job_stop(job, "kill")`
So long as the job is running the window behaves like it contains a modified
buffer. Trying to close the window with `CTRL-W :close` or `CTRL-W :hide`
fails, unless "!" is added, in which case the job is ended. The text in the
window is lost. The buffer still exists, but getting it in a window with
`:buffer` will show an
empty buffer.
buffer. Trying to close the window with `CTRL-W :quit` fails. When using
`CTRL-W :quit!` the job is ended. The text in the window is lost. The buffer
still exists, but getting it in a window with `:buffer` will show an empty
buffer.
Trying to close the window with `CTRL-W :close` also fails. Using
`CTRL-W :close!` will close the window and make the buffer hidden.
You can use `CTRL-W :hide` to close the terminal window and make the buffer
hidden, the job keeps running. The `:buffer` command can be used to turn the

View File

@@ -76,6 +76,10 @@ endif
# Set to yes to enable terminal support.
TERMINAL=no
ifndef CTAGS
# this assumes ctags is Exuberant ctags
CTAGS = ctags -I INIT+ --fields=+S
endif
# Link against the shared version of libstdc++ by default. Set
# STATIC_STDCPLUS to "yes" to link against static version instead.
@@ -885,6 +889,12 @@ xxd/xxd.exe: xxd/xxd.c
GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h
$(MAKE) -C GvimExt -f Make_ming.mak CROSS=$(CROSS) CROSS_COMPILE=$(CROSS_COMPILE) CXX='$(CXX)' STATIC_STDCPLUS=$(STATIC_STDCPLUS)
tags: notags
$(CTAGS) *.c *.cpp *.h if_perl.xs
notags:
-$(DEL) tags
clean:
-$(DEL) $(OUTDIR)$(DIRSLASH)*.o
-$(DEL) $(OUTDIR)$(DIRSLASH)*.res

View File

@@ -344,7 +344,8 @@ FEATURES = HUGE
!endif
!ifndef CTAGS
CTAGS = ctags
# this assumes ctags is Exuberant ctags
CTAGS = ctags -I INIT+ --fields=+S
!endif
!ifndef CSCOPE
@@ -1220,7 +1221,7 @@ GvimExt/gvimext.dll: GvimExt/gvimext.cpp GvimExt/gvimext.rc GvimExt/gvimext.h
tags: notags
$(CTAGS) *.c *.cpp *.h if_perl.xs proto\*.pro
$(CTAGS) *.c *.cpp *.h if_perl.xs
notags:
- if exist tags del tags

View File

@@ -2100,17 +2100,17 @@ test1 \
test_listchars \
test_search_mbyte \
test_wordcount \
test3 test4 test5 test6 test7 test8 test9 \
test11 test12 test14 test15 test17 test18 test19 \
test20 test21 test22 test25 test27 test28 test29 \
test3 test4 test5 test7 test8 \
test11 test12 test14 test15 test17 test19 \
test20 test25 test28 test29 \
test30 test31 test32 test33 test34 test36 test37 test38 test39 \
test40 test41 test42 test43 test44 test45 test48 test49 \
test50 test51 test52 test53 test54 test55 test56 test57 test59 \
test50 test52 test53 test54 test55 test56 test57 test59 \
test60 test64 test66 test68 test69 \
test70 test72 test73 test74 test77 test78 test79 \
test80 test83 test84 test85 test86 test87 test88 \
test91 test94 test95 test98 test99 \
test100 test101 test103 test104 test107 test108:
test70 test72 test73 test77 test78 test79 \
test83 test85 test86 test87 test88 \
test94 test95 test99 \
test108:
cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE)
# Run individual NEW style test, assuming that Vim was already compiled.

View File

@@ -1300,11 +1300,16 @@ write_buf_line(buf_T *buf, linenr_T lnum, channel_T *channel)
return;
memcpy((char *)p, (char *)line, len);
for (i = 0; i < len; ++i)
if (p[i] == NL)
p[i] = NUL;
if (channel->ch_write_text_mode)
p[len] = CAR;
else
{
for (i = 0; i < len; ++i)
if (p[i] == NL)
p[i] = NUL;
p[len] = NL;
p[len] = NL;
}
p[len + 1] = NUL;
channel_send(channel, PART_IN, p, len + 1, "write_buf_line");
vim_free(p);
@@ -1417,6 +1422,12 @@ channel_write_in(channel_T *channel)
in_part->ch_buf_top = lnum;
if (lnum > buf->b_ml.ml_line_count || lnum > in_part->ch_buf_bot)
{
#if defined(FEAT_TERMINAL)
/* Send CTRL-D or "eof_chars" to close stdin on MS-Windows. */
if (channel->ch_job != NULL)
term_send_eof(channel);
#endif
/* Writing is done, no longer need the buffer. */
in_part->ch_bufref.br_buf = NULL;
ch_log(channel, "Finished writing all lines to channel");
@@ -4626,6 +4637,20 @@ get_job_options(typval_T *tv, jobopt_T *opt, int supported, int supported2)
return FAIL;
}
}
else if (STRCMP(hi->hi_key, "eof_chars") == 0)
{
char_u *p;
if (!(supported2 & JO2_EOF_CHARS))
break;
opt->jo_set2 |= JO2_EOF_CHARS;
p = opt->jo_eof_chars = get_tv_string_chk(item);
if (p == NULL)
{
EMSG2(_(e_invarg2), "term_opencmd");
return FAIL;
}
}
else if (STRCMP(hi->hi_key, "term_rows") == 0)
{
if (!(supported2 & JO2_TERM_ROWS))

View File

@@ -1949,6 +1949,40 @@ diffopt_horizontal(void)
return (diff_flags & DIFF_HORIZONTAL) != 0;
}
/*
* Compare the characters at "p1" and "p2". If they are equal (possibly
* ignoring case) return TRUE and set "len" to the number of bytes.
*/
static int
diff_equal_char(char_u *p1, char_u *p2, int *len)
{
#ifdef FEAT_MBYTE
int l = (*mb_ptr2len)(p1);
if (l != (*mb_ptr2len)(p2))
return FALSE;
if (l > 1)
{
if (STRNCMP(p1, p2, l) != 0
&& (!enc_utf8
|| !(diff_flags & DIFF_ICASE)
|| utf_fold(utf_ptr2char(p1))
!= utf_fold(utf_ptr2char(p2))))
return FALSE;
*len = l;
}
else
#endif
{
if ((*p1 != *p2)
&& (!(diff_flags & DIFF_ICASE)
|| TOLOWER_LOC(*p1) != TOLOWER_LOC(*p2)))
return FALSE;
*len = 1;
}
return TRUE;
}
/*
* Find the difference within a changed line.
* Returns TRUE if the line was added, no other buffer has it.
@@ -1969,6 +2003,10 @@ diff_find_change(
int idx;
int off;
int added = TRUE;
#ifdef FEAT_MBYTE
char_u *p1, *p2;
int l;
#endif
/* Make a copy of the line, the next ml_get() will invalidate it. */
line_org = vim_strsave(ml_get_buf(wp->w_buffer, lnum, FALSE));
@@ -2017,10 +2055,11 @@ diff_find_change(
}
else
{
if (line_org[si_org] != line_new[si_new])
if (!diff_equal_char(line_org + si_org, line_new + si_new,
&l))
break;
++si_org;
++si_new;
si_org += l;
si_new += l;
}
}
#ifdef FEAT_MBYTE
@@ -2056,10 +2095,16 @@ diff_find_change(
}
else
{
if (line_org[ei_org] != line_new[ei_new])
p1 = line_org + ei_org;
p2 = line_new + ei_new;
#ifdef FEAT_MBYTE
p1 -= (*mb_head_off)(line_org, p1);
p2 -= (*mb_head_off)(line_new, p2);
#endif
if (!diff_equal_char(p1, p2, &l))
break;
--ei_org;
--ei_new;
ei_org -= l;
ei_new -= l;
}
}
if (*endp < ei_org)

View File

@@ -9683,7 +9683,7 @@ ins_left(
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
/* Only call start_arrow() when not busy with preediting, it will
* break undo. K_LEFT is inserted in im_correct_cursor(). */
if (!im_is_preediting())
if (p_imst == IM_OVER_THE_SPOT || !im_is_preediting())
#endif
{
start_arrow_with_change(&tpos, end_change);

View File

@@ -187,6 +187,10 @@ static struct vimvar
{VV_NAME("t_none", VAR_NUMBER), VV_RO},
{VV_NAME("t_job", VAR_NUMBER), VV_RO},
{VV_NAME("t_channel", VAR_NUMBER), VV_RO},
{VV_NAME("termrgbresp", VAR_STRING), VV_RO},
{VV_NAME("termu7resp", VAR_STRING), VV_RO},
{VV_NAME("termstyleresp", VAR_STRING), VV_RO},
{VV_NAME("termblinkresp", VAR_STRING), VV_RO},
};
/* shorthand */

View File

@@ -2098,11 +2098,16 @@ viminfo_filename(char_u *file)
else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL)
{
#ifdef VIMINFO_FILE2
/* don't use $HOME when not defined (turned into "c:/"!). */
# ifdef VMS
if (mch_getenv((char_u *)"SYS$LOGIN") == NULL)
# else
# ifdef MSWIN
/* Use $VIM only if $HOME is the default "C:/". */
if (STRCMP(vim_getenv((char_u *)"HOME", NULL), "C:/") == 0
&& mch_getenv((char_u *)"HOME") == NULL)
# else
if (mch_getenv((char_u *)"HOME") == NULL)
# endif
# endif
{
/* don't use $VIM when not available. */

View File

@@ -11099,7 +11099,7 @@ static int ses_do_frame(frame_T *fr);
static int ses_do_win(win_T *wp);
static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, unsigned *flagp);
static int ses_put_fname(FILE *fd, char_u *name, unsigned *flagp);
static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp);
static int ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, int add_eol);
/*
* Write openfile commands for the current buffers to an .exrc file.
@@ -11195,7 +11195,7 @@ makeopens(
{
if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L
: buf->b_wininfo->wi_fpos.lnum) < 0
|| ses_fname(fd, buf, &ssop_flags) == FAIL)
|| ses_fname(fd, buf, &ssop_flags, TRUE) == FAIL)
return FAIL;
}
}
@@ -11289,7 +11289,8 @@ makeopens(
)
{
if (fputs(need_tabnew ? "tabedit " : "edit ", fd) < 0
|| ses_fname(fd, wp->w_buffer, &ssop_flags) == FAIL)
|| ses_fname(fd, wp->w_buffer, &ssop_flags, TRUE)
== FAIL)
return FAIL;
need_tabnew = FALSE;
if (!wp->w_arg_idx_invalid)
@@ -11636,9 +11637,20 @@ put_view(
/*
* Editing a file in this buffer: use ":edit file".
* This may have side effects! (e.g., compressed or network file).
*
* Note, if a buffer for that file already exists, use :badd to
* edit that buffer, to not lose folding information (:edit resets
* folds in other buffers)
*/
if (fputs("edit ", fd) < 0
|| ses_fname(fd, wp->w_buffer, flagp) == FAIL)
if (fputs("if bufexists('", fd) < 0
|| ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
|| fputs("') | buffer ", fd) < 0
|| ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
|| fputs(" | else | edit ", fd) < 0
|| ses_fname(fd, wp->w_buffer, flagp, FALSE) == FAIL
|| fputs(" | endif", fd) < 0
||
put_eol(fd) == FAIL)
return FAIL;
}
else
@@ -11651,7 +11663,7 @@ put_view(
{
/* The buffer does have a name, but it's not a file name. */
if (fputs("file ", fd) < 0
|| ses_fname(fd, wp->w_buffer, flagp) == FAIL)
|| ses_fname(fd, wp->w_buffer, flagp, TRUE) == FAIL)
return FAIL;
}
#endif
@@ -11823,11 +11835,11 @@ ses_arglist(
/*
* Write a buffer name to the session file.
* Also ends the line.
* Also ends the line, if "add_eol" is TRUE.
* Returns FAIL if writing fails.
*/
static int
ses_fname(FILE *fd, buf_T *buf, unsigned *flagp)
ses_fname(FILE *fd, buf_T *buf, unsigned *flagp, int add_eol)
{
char_u *name;
@@ -11846,7 +11858,8 @@ ses_fname(FILE *fd, buf_T *buf, unsigned *flagp)
name = buf->b_sfname;
else
name = buf->b_ffname;
if (ses_put_fname(fd, name, flagp) == FAIL || put_eol(fd) == FAIL)
if (ses_put_fname(fd, name, flagp) == FAIL
|| (add_eol && put_eol(fd) == FAIL))
return FAIL;
return OK;
}

View File

@@ -3468,7 +3468,8 @@ cursorcmd(void)
windgoto(msg_row, msg_col);
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
redrawcmd_preedit();
if (p_imst == IM_ON_THE_SPOT)
redrawcmd_preedit();
#endif
#ifdef MCH_CURSOR_SHAPE
mch_update_cursor();

View File

@@ -125,7 +125,7 @@ static int vgetorpeek(int);
static void map_free(mapblock_T **);
static void validate_maphash(void);
static void showmap(mapblock_T *mp, int local);
static int inchar(char_u *buf, int maxlen, long wait_time, int tb_change_cnt);
static int inchar(char_u *buf, int maxlen, long wait_time);
#ifdef FEAT_EVAL
static char_u *eval_map_expr(char_u *str, int c);
#endif
@@ -462,8 +462,7 @@ flush_buffers(int flush_typeahead)
* of an escape sequence.
* In an xterm we get one char at a time and we have to get them all.
*/
while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L,
typebuf.tb_change_cnt) != 0)
while (inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 10L) != 0)
;
typebuf.tb_off = MAXMAPLEN;
typebuf.tb_len = 0;
@@ -2046,8 +2045,7 @@ vgetorpeek(int advance)
if (got_int)
{
/* flush all input */
c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L,
typebuf.tb_change_cnt);
c = inchar(typebuf.tb_buf, typebuf.tb_buflen - 1, 0L);
/*
* If inchar() returns TRUE (script file was active) or we
* are inside a mapping, get out of insert mode.
@@ -2610,8 +2608,7 @@ vgetorpeek(int advance)
&& (p_timeout
|| (keylen == KEYLEN_PART_KEY && p_ttimeout))
&& (c = inchar(typebuf.tb_buf + typebuf.tb_off
+ typebuf.tb_len, 3, 25L,
typebuf.tb_change_cnt)) == 0)
+ typebuf.tb_len, 3, 25L)) == 0)
{
colnr_T col = 0, vcol;
char_u *ptr;
@@ -2848,7 +2845,7 @@ vgetorpeek(int advance)
? -1L
: ((keylen == KEYLEN_PART_KEY && p_ttm >= 0)
? p_ttm
: p_tm)), typebuf.tb_change_cnt);
: p_tm)));
#ifdef FEAT_CMDL_INFO
if (i != 0)
@@ -2954,12 +2951,12 @@ vgetorpeek(int advance)
inchar(
char_u *buf,
int maxlen,
long wait_time, /* milli seconds */
int tb_change_cnt)
long wait_time) /* milli seconds */
{
int len = 0; /* init for GCC */
int retesc = FALSE; /* return ESC with gotint */
int script_char;
int tb_change_cnt = typebuf.tb_change_cnt;
if (wait_time == -1L || wait_time > 100L) /* flush output before waiting */
{
@@ -3065,9 +3062,17 @@ inchar(
len = ui_inchar(buf, maxlen / 3, wait_time, tb_change_cnt);
}
/* If the typebuf was changed further down, it is like nothing was added by
* this call. */
if (typebuf_changed(tb_change_cnt))
return 0;
/* Note the change in the typeahead buffer, this matters for when
* vgetorpeek() is called recursively, e.g. using getchar(1) in a timer
* function. */
if (len > 0 && ++typebuf.tb_change_cnt == 0)
typebuf.tb_change_cnt = 1;
return fix_input_buffer(buf, len);
}

View File

@@ -2,7 +2,7 @@
* iscygpty.c -- part of ptycheck
* https://github.com/k-takata/ptycheck
*
* Copyright (c) 2015-2016 K.Takata
* Copyright (c) 2015-2017 K.Takata
*
* You can redistribute it and/or modify it under the terms of either
* the MIT license (as described below) or the Vim license.
@@ -27,6 +27,8 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifdef _WIN32
#include <ctype.h>
#include <io.h>
#include <wchar.h>
@@ -60,19 +62,19 @@
//#define USE_DYNFILEID
#ifdef USE_DYNFILEID
typedef BOOL (WINAPI *pfnGetFileInformationByHandleEx)(
HANDLE hFile,
HANDLE hFile,
FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
LPVOID lpFileInformation,
DWORD dwBufferSize
LPVOID lpFileInformation,
DWORD dwBufferSize
);
static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL;
# ifndef USE_FILEEXTD
static BOOL WINAPI stub_GetFileInformationByHandleEx(
HANDLE hFile,
HANDLE hFile,
FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
LPVOID lpFileInformation,
DWORD dwBufferSize
LPVOID lpFileInformation,
DWORD dwBufferSize
)
{
return FALSE;
@@ -111,7 +113,7 @@ int is_cygpty(int fd)
return 0;
#else
HANDLE h;
int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * MAX_PATH;
int size = sizeof(FILE_NAME_INFO) + sizeof(WCHAR) * (MAX_PATH - 1);
FILE_NAME_INFO *nameinfo;
WCHAR *p = NULL;
@@ -125,7 +127,7 @@ int is_cygpty(int fd)
if (GetFileType(h) != FILE_TYPE_PIPE) {
return 0;
}
nameinfo = malloc(size);
nameinfo = malloc(size + sizeof(WCHAR));
if (nameinfo == NULL) {
return 0;
}
@@ -178,4 +180,6 @@ int is_cygpty_used(void)
return ret;
}
/* vi:set ts=8 sts=4 sw=4 noet: */
#endif /* _WIN32 */
/* vim: set ts=4 sw=4: */

View File

@@ -2,7 +2,7 @@
* iscygpty.h -- part of ptycheck
* https://github.com/k-takata/ptycheck
*
* Copyright (c) 2015-2016 K.Takata
* Copyright (c) 2015-2017 K.Takata
*
* You can redistribute it and/or modify it under the terms of either
* the MIT license (as described below) or the Vim license.
@@ -30,7 +30,12 @@
#ifndef _ISCYGPTY_H
#define _ISCYGPTY_H
#ifdef _WIN32
int is_cygpty(int fd);
int is_cygpty_used(void);
#else
#define is_cygpty(fd) 0
#define is_cygpty_used() 0
#endif
#endif /* _ISCYGPTY_H */

View File

@@ -4788,6 +4788,11 @@ static unsigned long im_commit_handler_id = 0;
static unsigned int im_activatekey_keyval = GDK_VoidSymbol;
static unsigned int im_activatekey_state = 0;
static GtkWidget *preedit_window = NULL;
static GtkWidget *preedit_label = NULL;
static void im_preedit_window_set_position(void);
void
im_set_active(int active)
{
@@ -4825,6 +4830,9 @@ im_set_position(int row, int col)
area.height = gui.char_height;
gtk_im_context_set_cursor_location(xic, &area);
if (p_imst == IM_OVER_THE_SPOT)
im_preedit_window_set_position();
}
}
@@ -4851,6 +4859,95 @@ im_add_to_input(char_u *str, int len)
if (input_conv.vc_type != CONV_NONE)
vim_free(str);
if (p_mh) /* blank out the pointer if necessary */
gui_mch_mousehide(TRUE);
}
static void
im_preedit_window_set_position(void)
{
int x, y, w, h, sw, sh;
if (preedit_window == NULL)
return;
sw = gdk_screen_get_width(gtk_widget_get_screen(preedit_window));
sh = gdk_screen_get_height(gtk_widget_get_screen(preedit_window));
#if GTK_CHECK_VERSION(3,0,0)
gdk_window_get_origin(gtk_widget_get_window(gui.drawarea), &x, &y);
#else
gdk_window_get_origin(gui.drawarea->window, &x, &y);
#endif
gtk_window_get_size(GTK_WINDOW(preedit_window), &w, &h);
x = x + FILL_X(gui.col);
y = y + FILL_Y(gui.row);
if (x + w > sw)
x = sw - w;
if (y + h > sh)
y = sh - h;
gtk_window_move(GTK_WINDOW(preedit_window), x, y);
}
static void
im_preedit_window_open()
{
char *preedit_string;
char buf[8];
PangoAttrList *attr_list;
PangoLayout *layout;
GdkColor color;
gint w, h;
if (preedit_window == NULL)
{
preedit_window = gtk_window_new(GTK_WINDOW_POPUP);
preedit_label = gtk_label_new("");
gtk_container_add(GTK_CONTAINER(preedit_window), preedit_label);
}
gtk_widget_modify_font(preedit_label, gui.norm_font);
vim_snprintf(buf, sizeof(buf), "#%06X", gui.norm_pixel);
gdk_color_parse(buf, &color);
gtk_widget_modify_fg(preedit_label, GTK_STATE_NORMAL, &color);
vim_snprintf(buf, sizeof(buf), "#%06X", gui.back_pixel);
gdk_color_parse(buf, &color);
gtk_widget_modify_bg(preedit_window, GTK_STATE_NORMAL, &color);
gtk_im_context_get_preedit_string(xic, &preedit_string, &attr_list, NULL);
if (preedit_string[0] != NUL)
{
gtk_label_set_text(GTK_LABEL(preedit_label), preedit_string);
gtk_label_set_attributes(GTK_LABEL(preedit_label), attr_list);
layout = gtk_label_get_layout(GTK_LABEL(preedit_label));
pango_layout_get_pixel_size(layout, &w, &h);
h = MAX(h, gui.char_height);
gtk_window_resize(GTK_WINDOW(preedit_window), w, h);
gtk_widget_show_all(preedit_window);
im_preedit_window_set_position();
}
g_free(preedit_string);
pango_attr_list_unref(attr_list);
}
static void
im_preedit_window_close()
{
if (preedit_window != NULL)
gtk_widget_hide(preedit_window);
}
static void
im_show_preedit()
{
im_preedit_window_open();
if (p_mh) /* blank out the pointer if necessary */
gui_mch_mousehide(TRUE);
}
@@ -4861,6 +4958,12 @@ im_delete_preedit(void)
char_u bskey[] = {CSI, 'k', 'b'};
char_u delkey[] = {CSI, 'k', 'D'};
if (p_imst == IM_OVER_THE_SPOT)
{
im_preedit_window_close();
return;
}
if (State & NORMAL)
{
im_preedit_cursor = 0;
@@ -4933,40 +5036,43 @@ im_commit_cb(GtkIMContext *context UNUSED,
xim_log("im_commit_cb(): %s\n", str);
#endif
/* The imhangul module doesn't reset the preedit string before
* committing. Call im_delete_preedit() to work around that. */
im_delete_preedit();
/* Indicate that preediting has finished. */
if (preedit_start_col == MAXCOL)
if (p_imst == IM_ON_THE_SPOT)
{
init_preedit_start_col();
commit_with_preedit = FALSE;
/* The imhangul module doesn't reset the preedit string before
* committing. Call im_delete_preedit() to work around that. */
im_delete_preedit();
/* Indicate that preediting has finished. */
if (preedit_start_col == MAXCOL)
{
init_preedit_start_col();
commit_with_preedit = FALSE;
}
/* The thing which setting "preedit_start_col" to MAXCOL means that
* "preedit_start_col" will be set forcedly when calling
* preedit_changed_cb() next time.
* "preedit_start_col" should not reset with MAXCOL on this part. Vim
* is simulating the preediting by using add_to_input_str(). when
* preedit begin immediately before committed, the typebuf is not
* flushed to screen, then it can't get correct "preedit_start_col".
* Thus, it should calculate the cells by adding cells of the committed
* string. */
if (input_conv.vc_type != CONV_NONE)
{
im_str = string_convert(&input_conv, (char_u *)str, &len);
g_return_if_fail(im_str != NULL);
}
else
im_str = (char_u *)str;
clen = mb_string2cells(im_str, len);
if (input_conv.vc_type != CONV_NONE)
vim_free(im_str);
preedit_start_col += clen;
}
/* The thing which setting "preedit_start_col" to MAXCOL means that
* "preedit_start_col" will be set forcedly when calling
* preedit_changed_cb() next time.
* "preedit_start_col" should not reset with MAXCOL on this part. Vim
* is simulating the preediting by using add_to_input_str(). when
* preedit begin immediately before committed, the typebuf is not
* flushed to screen, then it can't get correct "preedit_start_col".
* Thus, it should calculate the cells by adding cells of the committed
* string. */
if (input_conv.vc_type != CONV_NONE)
{
im_str = string_convert(&input_conv, (char_u *)str, &len);
g_return_if_fail(im_str != NULL);
}
else
im_str = (char_u *)str;
clen = mb_string2cells(im_str, len);
if (input_conv.vc_type != CONV_NONE)
vim_free(im_str);
preedit_start_col += clen;
/* Is this a single character that matches a keypad key that's just
* been pressed? If so, we don't want it to be entered as such - let
* us carry on processing the raw keycode so that it may be used in
@@ -4990,14 +5096,17 @@ im_commit_cb(GtkIMContext *context UNUSED,
if (add_to_input)
im_add_to_input((char_u *)str, slen);
/* Inserting chars while "im_is_active" is set does not cause a change of
* buffer. When the chars are committed the buffer must be marked as
* changed. */
if (!commit_with_preedit)
preedit_start_col = MAXCOL;
if (p_imst == IM_ON_THE_SPOT)
{
/* Inserting chars while "im_is_active" is set does not cause a
* change of buffer. When the chars are committed the buffer must be
* marked as changed. */
if (!commit_with_preedit)
preedit_start_col = MAXCOL;
/* This flag is used in changed() at next call. */
xim_changed_while_preediting = TRUE;
/* This flag is used in changed() at next call. */
xim_changed_while_preediting = TRUE;
}
if (gtk_main_level() > 0)
gtk_main_quit();
@@ -5031,7 +5140,8 @@ im_preedit_end_cb(GtkIMContext *context UNUSED, gpointer data UNUSED)
im_delete_preedit();
/* Indicate that preediting has finished */
preedit_start_col = MAXCOL;
if (p_imst == IM_ON_THE_SPOT)
preedit_start_col = MAXCOL;
xim_has_preediting = FALSE;
#if 0
@@ -5092,9 +5202,14 @@ im_preedit_changed_cb(GtkIMContext *context, gpointer data UNUSED)
char_u *p;
int i;
gtk_im_context_get_preedit_string(context,
&preedit_string, NULL,
&cursor_index);
if (p_imst == IM_ON_THE_SPOT)
gtk_im_context_get_preedit_string(context,
&preedit_string, NULL,
&cursor_index);
else
gtk_im_context_get_preedit_string(context,
&preedit_string, NULL,
NULL);
#ifdef XIM_DEBUG
xim_log("im_preedit_changed_cb(): %s\n", preedit_string);
@@ -5102,66 +5217,82 @@ im_preedit_changed_cb(GtkIMContext *context, gpointer data UNUSED)
g_return_if_fail(preedit_string != NULL); /* just in case */
/* If preedit_start_col is MAXCOL set it to the current cursor position. */
if (preedit_start_col == MAXCOL && preedit_string[0] != '\0')
if (p_imst == IM_OVER_THE_SPOT)
{
xim_has_preediting = TRUE;
/* Urgh, this breaks if the input buffer isn't empty now */
init_preedit_start_col();
if (preedit_string[0] == NUL)
{
xim_has_preediting = FALSE;
im_delete_preedit();
}
else
{
xim_has_preediting = TRUE;
im_show_preedit();
}
}
else if (cursor_index == 0 && preedit_string[0] == '\0')
else
{
xim_has_preediting = FALSE;
/* If preedit_start_col is MAXCOL set it to the current cursor position. */
if (preedit_start_col == MAXCOL && preedit_string[0] != '\0')
{
xim_has_preediting = TRUE;
/* If at the start position (after typing backspace)
* preedit_start_col must be reset. */
preedit_start_col = MAXCOL;
}
/* Urgh, this breaks if the input buffer isn't empty now */
init_preedit_start_col();
}
else if (cursor_index == 0 && preedit_string[0] == '\0')
{
xim_has_preediting = FALSE;
im_delete_preedit();
/* If at the start position (after typing backspace)
* preedit_start_col must be reset. */
preedit_start_col = MAXCOL;
}
/*
* Compute the end of the preediting area: "preedit_end_col".
* According to the documentation of gtk_im_context_get_preedit_string(),
* the cursor_pos output argument returns the offset in bytes. This is
* unfortunately not true -- real life shows the offset is in characters,
* and the GTK+ source code agrees with me. Will file a bug later.
*/
if (preedit_start_col != MAXCOL)
preedit_end_col = preedit_start_col;
str = (char_u *)preedit_string;
for (p = str, i = 0; *p != NUL; p += utf_byte2len(*p), ++i)
{
int is_composing;
im_delete_preedit();
is_composing = ((*p & 0x80) != 0 && utf_iscomposing(utf_ptr2char(p)));
/*
* These offsets are used as counters when generating <BS> and <Del>
* to delete the preedit string. So don't count composing characters
* unless 'delcombine' is enabled.
* Compute the end of the preediting area: "preedit_end_col".
* According to the documentation of gtk_im_context_get_preedit_string(),
* the cursor_pos output argument returns the offset in bytes. This is
* unfortunately not true -- real life shows the offset is in characters,
* and the GTK+ source code agrees with me. Will file a bug later.
*/
if (!is_composing || p_deco)
{
if (i < cursor_index)
++im_preedit_cursor;
else
++im_preedit_trailing;
}
if (!is_composing && i >= cursor_index)
{
/* This is essentially the same as im_preedit_trailing, except
* composing characters are not counted even if p_deco is set. */
++num_move_back;
}
if (preedit_start_col != MAXCOL)
preedit_end_col += utf_ptr2cells(p);
}
preedit_end_col = preedit_start_col;
str = (char_u *)preedit_string;
for (p = str, i = 0; *p != NUL; p += utf_byte2len(*p), ++i)
{
int is_composing;
if (p > str)
{
im_add_to_input(str, (int)(p - str));
im_correct_cursor(num_move_back);
is_composing = ((*p & 0x80) != 0 && utf_iscomposing(utf_ptr2char(p)));
/*
* These offsets are used as counters when generating <BS> and <Del>
* to delete the preedit string. So don't count composing characters
* unless 'delcombine' is enabled.
*/
if (!is_composing || p_deco)
{
if (i < cursor_index)
++im_preedit_cursor;
else
++im_preedit_trailing;
}
if (!is_composing && i >= cursor_index)
{
/* This is essentially the same as im_preedit_trailing, except
* composing characters are not counted even if p_deco is set. */
++num_move_back;
}
if (preedit_start_col != MAXCOL)
preedit_end_col += utf_ptr2cells(p);
}
if (p > str)
{
im_add_to_input(str, (int)(p - str));
im_correct_cursor(num_move_back);
}
}
g_free(preedit_string);
@@ -5310,7 +5441,8 @@ im_shutdown(void)
}
im_is_active = FALSE;
im_commit_handler_id = 0;
preedit_start_col = MAXCOL;
if (p_imst == IM_ON_THE_SPOT)
preedit_start_col = MAXCOL;
xim_has_preediting = FALSE;
}
@@ -5465,7 +5597,8 @@ xim_reset(void)
}
}
preedit_start_col = MAXCOL;
if (p_imst == IM_ON_THE_SPOT)
preedit_start_col = MAXCOL;
xim_has_preediting = FALSE;
}
@@ -5570,19 +5703,22 @@ xim_queue_key_press_event(GdkEventKey *event, int down)
{
int imresult = gtk_im_context_filter_keypress(xic, event);
/* Some XIM send following sequence:
* 1. preedited string.
* 2. committed string.
* 3. line changed key.
* 4. preedited string.
* 5. remove preedited string.
* if 3, Vim can't move back the above line for 5.
* thus, this part should not parse the key. */
if (!imresult && preedit_start_col != MAXCOL
&& event->keyval == GDK_Return)
if (p_imst == IM_ON_THE_SPOT)
{
im_synthesize_keypress(GDK_Return, 0U);
return FALSE;
/* Some XIM send following sequence:
* 1. preedited string.
* 2. committed string.
* 3. line changed key.
* 4. preedited string.
* 5. remove preedited string.
* if 3, Vim can't move back the above line for 5.
* thus, this part should not parse the key. */
if (!imresult && preedit_start_col != MAXCOL
&& event->keyval == GDK_Return)
{
im_synthesize_keypress(GDK_Return, 0U);
return FALSE;
}
}
/* If XIM tried to commit a keypad key as a single char.,

View File

@@ -2730,12 +2730,15 @@ skip_to_option_part(char_u *p)
changed(void)
{
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
/* The text of the preediting area is inserted, but this doesn't
* mean a change of the buffer yet. That is delayed until the
* text is committed. (this means preedit becomes empty) */
if (im_is_preediting() && !xim_changed_while_preediting)
return;
xim_changed_while_preediting = FALSE;
if (p_imst == IM_ON_THE_SPOT)
{
/* The text of the preediting area is inserted, but this doesn't
* mean a change of the buffer yet. That is delayed until the
* text is committed. (this means preedit becomes empty) */
if (im_is_preediting() && !xim_changed_while_preediting)
return;
xim_changed_while_preediting = FALSE;
}
#endif
if (!curbuf->b_changed)

View File

@@ -607,11 +607,14 @@ check_cursor_col_win(win_T *win)
if (oldcoladd > win->w_cursor.col)
{
win->w_cursor.coladd = oldcoladd - win->w_cursor.col;
if (win->w_cursor.col < len && win->w_cursor.coladd > 0)
/* Make sure that coladd is not more than the char width.
* Not for the last character, coladd is then used when the cursor
* is actually after the last character. */
if (win->w_cursor.col + 1 < len && win->w_cursor.coladd > 0)
{
int cs, ce;
/* check that coladd is not more than the char width */
getvcol(win, &win->w_cursor, &cs, NULL, &ce);
if (win->w_cursor.coladd > ce - cs)
win->w_cursor.coladd = ce - cs;

View File

@@ -1606,13 +1606,22 @@ static struct vimoption options[] =
#endif
SCRIPTID_INIT},
{"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE,
# if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
#if defined(FEAT_EVAL) && defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
(char_u *)&p_imsf, PV_NONE,
{(char_u *)"", (char_u *)NULL}
# else
#else
(char_u *)NULL, PV_NONE,
{(char_u *)NULL, (char_u *)0L}
# endif
#endif
SCRIPTID_INIT},
{"imstyle", "imst", P_NUM|P_VI_DEF|P_SECURE,
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
(char_u *)&p_imst, PV_NONE,
{(char_u *)IM_OVER_THE_SPOT, (char_u *)0L}
#else
(char_u *)NULL, PV_NONE,
{(char_u *)0L, (char_u *)0L}
#endif
SCRIPTID_INIT},
{"include", "inc", P_STRING|P_ALLOCED|P_VI_DEF,
#ifdef FEAT_FIND_ID
@@ -8990,6 +8999,15 @@ set_num_option(
#endif
}
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
/* 'imstyle' */
else if (pp == &p_imst)
{
if (p_imst != IM_ON_THE_SPOT && p_imst != IM_OVER_THE_SPOT)
errmsg = e_invarg;
}
#endif
else if (pp == &p_window)
{
if (p_window < 1)

View File

@@ -581,6 +581,9 @@ EXTERN int p_ic; /* 'ignorecase' */
EXTERN char_u *p_imak; /* 'imactivatekey' */
EXTERN char_u *p_imaf; /* 'imactivatefunc' */
EXTERN char_u *p_imsf; /* 'imstatusfunc' */
EXTERN long p_imst; /* 'imstyle' */
# define IM_ON_THE_SPOT 0L
# define IM_OVER_THE_SPOT 1L
#endif
#ifdef USE_IM_CONTROL
EXTERN int p_imcmdline; /* 'imcmdline' */

View File

@@ -2280,6 +2280,7 @@ vim_is_xterm(char_u *name)
|| STRNICMP(name, "kterm", 5) == 0
|| STRNICMP(name, "mlterm", 6) == 0
|| STRNICMP(name, "rxvt", 4) == 0
|| STRNICMP(name, "screen.xterm", 12) == 0
|| STRCMP(name, "builtin_xterm") == 0);
}

View File

@@ -16,6 +16,7 @@ int term_update_window(win_T *wp);
int term_is_finished(buf_T *buf);
int term_show_buffer(buf_T *buf);
void term_change_in_curbuf(void);
void term_send_eof(channel_T *ch);
int term_get_attr(buf_T *buf, linenr_T lnum, int col);
char_u *term_get_status_text(term_T *term);
int set_ref_in_term(int copyID);

View File

@@ -58,6 +58,7 @@ struct qfline_S
*/
typedef struct qf_list_S
{
int_u qf_id; /* Unique identifier for this list */
qfline_T *qf_start; /* pointer to the first error */
qfline_T *qf_last; /* pointer to the last error */
qfline_T *qf_ptr; /* pointer to the current error */
@@ -96,6 +97,7 @@ struct qf_info_S
};
static qf_info_T ql_info; /* global quickfix list */
static int_u last_qf_id = 0; /* Last used quickfix list id */
#define FMT_PATTERNS 10 /* maximum number of % recognized */
@@ -1399,6 +1401,7 @@ qf_new_list(qf_info_T *qi, char_u *qf_title)
qi->qf_curlist = qi->qf_listcount++;
vim_memset(&qi->qf_lists[qi->qf_curlist], 0, (size_t)(sizeof(qf_list_T)));
qf_store_title(qi, qi->qf_curlist, qf_title);
qi->qf_lists[qi->qf_curlist].qf_id = ++last_qf_id;
}
/*
@@ -1672,6 +1675,9 @@ copy_loclist(win_T *from, win_T *to)
to_qfl->qf_index = from_qfl->qf_index; /* current index in the list */
/* Assign a new ID for the location list */
to_qfl->qf_id = ++last_qf_id;
/* When no valid entries are present in the list, qf_ptr points to
* the first item in the list */
if (to_qfl->qf_nonevalid)
@@ -2808,6 +2814,7 @@ qf_free(qf_info_T *qi, int idx)
qfl->qf_title = NULL;
free_tv(qfl->qf_ctx);
qfl->qf_ctx = NULL;
qfl->qf_id = 0;
}
/*
@@ -4628,6 +4635,7 @@ enum {
QF_GETLIST_NR = 0x4,
QF_GETLIST_WINID = 0x8,
QF_GETLIST_CONTEXT = 0x10,
QF_GETLIST_ID = 0x20,
QF_GETLIST_ALL = 0xFF
};
@@ -4635,16 +4643,19 @@ enum {
* Parse text from 'di' and return the quickfix list items
*/
static int
qf_get_list_from_text(dictitem_T *di, dict_T *retdict)
qf_get_list_from_lines(dictitem_T *di, dict_T *retdict)
{
int status = FAIL;
qf_info_T *qi;
/* Only string and list values are supported */
if ((di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL)
|| (di->di_tv.v_type == VAR_LIST
&& di->di_tv.vval.v_list != NULL))
/* Only a List value is supported */
if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL)
{
list_T *l = list_alloc();
if (l == NULL)
return FAIL;
qi = (qf_info_T *)alloc((unsigned)sizeof(qf_info_T));
if (qi != NULL)
{
@@ -4654,17 +4665,13 @@ qf_get_list_from_text(dictitem_T *di, dict_T *retdict)
if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, p_efm,
TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0)
{
list_T *l = list_alloc();
if (l != NULL)
{
(void)get_errorlist(qi, NULL, 0, l);
dict_add_list(retdict, "items", l);
status = OK;
}
(void)get_errorlist(qi, NULL, 0, l);
qf_free(qi, 0);
}
free(qi);
}
dict_add_list(retdict, "items", l);
status = OK;
}
return status;
@@ -4684,21 +4691,21 @@ get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
dictitem_T *di;
int flags = QF_GETLIST_NONE;
if ((di = dict_find(what, (char_u *)"text", -1)) != NULL)
return qf_get_list_from_text(di, retdict);
if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL)
return qf_get_list_from_lines(di, retdict);
if (wp != NULL)
{
qi = GET_LOC_LIST(wp);
if (qi == NULL)
{
/* If querying for the size of the location list, return 0 */
if (((di = dict_find(what, (char_u *)"nr", -1)) != NULL)
&& (di->di_tv.v_type == VAR_STRING)
&& (STRCMP(di->di_tv.vval.v_string, "$") == 0))
return dict_add_nr_str(retdict, "nr", 0, NULL);
return FAIL;
}
/* List is not present or is empty */
if (qi == NULL || qi->qf_listcount == 0)
{
/* If querying for the size of the list, return 0 */
if (((di = dict_find(what, (char_u *)"nr", -1)) != NULL)
&& (di->di_tv.v_type == VAR_STRING)
&& (STRCMP(di->di_tv.vval.v_string, "$") == 0))
return dict_add_nr_str(retdict, "nr", 0, NULL);
return FAIL;
}
qf_idx = qi->qf_curlist; /* default is the current list */
@@ -4714,41 +4721,52 @@ get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
if (qf_idx < 0 || qf_idx >= qi->qf_listcount)
return FAIL;
}
else if (qi->qf_listcount == 0) /* stack is empty */
return FAIL;
flags |= QF_GETLIST_NR;
}
else if ((di->di_tv.v_type == VAR_STRING)
&& (STRCMP(di->di_tv.vval.v_string, "$") == 0))
{
/* Get the last quickfix list number */
if (qi->qf_listcount > 0)
qf_idx = qi->qf_listcount - 1;
else
qf_idx = -1; /* Quickfix stack is empty */
flags |= QF_GETLIST_NR;
qf_idx = qi->qf_listcount - 1;
else
return FAIL;
flags |= QF_GETLIST_NR;
}
if ((di = dict_find(what, (char_u *)"id", -1)) != NULL)
{
/* Look for a list with the specified id */
if (di->di_tv.v_type == VAR_NUMBER)
{
/* For zero, use the current list or the list specifed by 'nr' */
if (di->di_tv.vval.v_number != 0)
{
for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++)
{
if (qi->qf_lists[qf_idx].qf_id == di->di_tv.vval.v_number)
break;
}
if (qf_idx == qi->qf_listcount)
return FAIL; /* List not found */
}
flags |= QF_GETLIST_ID;
}
else
return FAIL;
}
if (qf_idx != -1)
{
if (dict_find(what, (char_u *)"all", -1) != NULL)
flags |= QF_GETLIST_ALL;
if (dict_find(what, (char_u *)"all", -1) != NULL)
flags |= QF_GETLIST_ALL;
if (dict_find(what, (char_u *)"title", -1) != NULL)
flags |= QF_GETLIST_TITLE;
if (dict_find(what, (char_u *)"title", -1) != NULL)
flags |= QF_GETLIST_TITLE;
if (dict_find(what, (char_u *)"winid", -1) != NULL)
flags |= QF_GETLIST_WINID;
if (dict_find(what, (char_u *)"winid", -1) != NULL)
flags |= QF_GETLIST_WINID;
if (dict_find(what, (char_u *)"context", -1) != NULL)
flags |= QF_GETLIST_CONTEXT;
if (dict_find(what, (char_u *)"context", -1) != NULL)
flags |= QF_GETLIST_CONTEXT;
if (dict_find(what, (char_u *)"items", -1) != NULL)
flags |= QF_GETLIST_ITEMS;
}
if (dict_find(what, (char_u *)"items", -1) != NULL)
flags |= QF_GETLIST_ITEMS;
if (flags & QF_GETLIST_TITLE)
{
@@ -4798,6 +4816,10 @@ get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
status = dict_add_nr_str(retdict, "context", 0L, (char_u *)"");
}
if ((status == OK) && (flags & QF_GETLIST_ID))
status = dict_add_nr_str(retdict, "id", qi->qf_lists[qf_idx].qf_id,
NULL);
return status;
}
@@ -4983,6 +5005,21 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title)
return FAIL;
}
if (!newlist && (di = dict_find(what, (char_u *)"id", -1)) != NULL)
{
/* Use the quickfix/location list with the specified id */
if (di->di_tv.v_type == VAR_NUMBER)
{
for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++)
if (qi->qf_lists[qf_idx].qf_id == di->di_tv.vval.v_number)
break;
if (qf_idx == qi->qf_listcount)
return FAIL; /* List not found */
}
else
return FAIL;
}
if (newlist)
{
qi->qf_curlist = qf_idx;
@@ -5014,12 +5051,10 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title)
}
}
if ((di = dict_find(what, (char_u *)"text", -1)) != NULL)
if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL)
{
/* Only string and list values are supported */
if ((di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL)
|| (di->di_tv.v_type == VAR_LIST
&& di->di_tv.vval.v_list != NULL))
/* Only a List value is supported */
if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL)
{
if (action == 'r')
qf_free_items(qi, qf_idx);

View File

@@ -5197,7 +5197,8 @@ win_line(
/* XIM don't send preedit_start and preedit_end, but they send
* preedit_changed and commit. Thus Vim can't set "im_is_active", use
* im_is_preediting() here. */
if (xic != NULL
if (p_imst == IM_ON_THE_SPOT
&& xic != NULL
&& lnum == wp->w_cursor.lnum
&& (State & INSERT)
&& !p_imdisable

View File

@@ -1632,6 +1632,7 @@ struct channel_S {
int ch_last_msg_id; /* ID of the last message */
chanpart_T ch_part[PART_COUNT]; /* info for socket, out, err and in */
int ch_write_text_mode; /* write buffer lines with CR, not NL */
char *ch_hostname; /* only for socket, allocated */
int ch_port; /* only for socket */
@@ -1713,7 +1714,8 @@ struct channel_S {
#define JO2_CURWIN 0x0200 /* "curwin" */
#define JO2_HIDDEN 0x0400 /* "hidden" */
#define JO2_TERM_OPENCMD 0x0800 /* "term_opencmd" */
#define JO2_ALL 0x0FFF
#define JO2_EOF_CHARS 0x1000 /* "eof_chars" */
#define JO2_ALL 0x1FFF
#define JO_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
#define JO_CB_ALL \
@@ -1779,6 +1781,7 @@ typedef struct
char_u *jo_term_name;
char_u *jo_term_opencmd;
int jo_term_finish;
char_u *jo_eof_chars;
#endif
} jobopt_T;

View File

@@ -1369,9 +1369,7 @@ static int need_gather = FALSE; /* need to fill termleader[] */
static char_u termleader[256 + 1]; /* for check_termcode() */
#ifdef FEAT_TERMRESPONSE
static int check_for_codes = FALSE; /* check for key code response */
# ifdef MACOS
static int is_terminal_app = FALSE; /* recognized Terminal.app */
# endif
static int is_not_xterm = FALSE; /* recognized not-really-xterm */
#endif
static struct builtin_term *
@@ -3506,13 +3504,10 @@ may_req_ambiguous_char_width(void)
/*
* Similar to requesting the version string: Request the terminal background
* color when it is the right moment.
* Also request the cursor shape, if possible.
*/
void
may_req_bg_color(void)
{
int did_one = FALSE;
if (can_get_termresponse() && starting == 0)
{
/* Only request background if t_RB is set and 'background' wasn't
@@ -3524,20 +3519,7 @@ may_req_bg_color(void)
LOG_TR("Sending BG request");
out_str(T_RBG);
rbg_status = STATUS_SENT;
did_one = TRUE;
}
/* Only request cursor blinking mode if t_RC is set. */
if (rbm_status == STATUS_GET && *T_CRC != NUL)
{
LOG_TR("Sending BC request");
out_str(T_CRC);
rbm_status = STATUS_SENT;
did_one = TRUE;
}
if (did_one)
{
/* check for the characters now, otherwise they might be eaten by
* get_keystroke() */
out_flush();
@@ -4505,12 +4487,17 @@ check_termcode(
key_name[0] = (int)KS_EXTRA;
key_name[1] = (int)KE_IGNORE;
slen = i + 1;
# ifdef FEAT_EVAL
set_vim_var_string(VV_TERMU7RESP, tp, slen);
# endif
}
else
#endif
/* eat it when at least one digit and ending in 'c' */
if (*T_CRV != NUL && i > 2 + (tp[0] != CSI) && tp[i] == 'c')
{
int version = col;
LOG_TR("Received CRV response");
crv_status = STATUS_GOT;
# ifdef FEAT_AUTOCMD
@@ -4523,31 +4510,34 @@ check_termcode(
switch_to_8bit();
/* rxvt sends its version number: "20703" is 2.7.3.
* Screen sends 40500.
* Ignore it for when the user has set 'term' to xterm,
* even though it's an rxvt. */
if (col > 20000)
col = 0;
if (version > 20000)
version = 0;
if (tp[1 + (tp[0] != CSI)] == '>' && semicols == 2)
{
int need_flush = FALSE;
/* Only set 'ttymouse' automatically if it was not set
* by the user already. */
if (!option_was_set((char_u *)"ttym"))
{
# ifdef TTYM_SGR
if (col >= 277)
if (version >= 277)
set_option_value((char_u *)"ttym", 0L,
(char_u *)"sgr", 0);
else
# endif
/* if xterm version >= 95 use mouse dragging */
if (col >= 95)
if (version >= 95)
set_option_value((char_u *)"ttym", 0L,
(char_u *)"xterm2", 0);
}
/* if xterm version >= 141 try to get termcap codes */
if (col >= 141)
if (version >= 141)
{
LOG_TR("Enable checking for XT codes");
check_for_codes = TRUE;
@@ -4556,7 +4546,7 @@ check_termcode(
}
/* libvterm sends 0;100;0 */
if (col == 100
if (version == 100
&& STRNCMP(tp + extra - 2, "0;100;0c", 8) == 0)
{
/* If run from Vim $COLORS is set to the number of
@@ -4566,35 +4556,66 @@ check_termcode(
may_adjust_color_count(256);
}
/* Detect terminals that set $TERM to something like
* "xterm-256colors" but are not fully xterm
* compatible. */
# ifdef MACOS
/* Mac Terminal.app sends 1;95;0 */
if (col == 95
if (version == 95
&& STRNCMP(tp + extra - 2, "1;95;0c", 7) == 0)
{
/* Terminal.app sets $TERM to "xterm-256colors",
* but it's not fully xterm compatible. */
is_terminal_app = TRUE;
}
is_not_xterm = TRUE;
# endif
/* Gnome terminal sends 1;3801;0 or 1;4402;0.
* xfce4-terminal sends 1;2802;0.
* screen sends 83;40500;0
* Assuming any version number over 2800 is not an
* xterm (without the limit for rxvt and screen). */
if (col >= 2800)
is_not_xterm = TRUE;
/* PuTTY sends 0;136;0 */
if (version == 136
&& STRNCMP(tp + extra - 2, "0;136;0c", 8) == 0)
is_not_xterm = TRUE;
/* Konsole sends 0;115;0 */
if (version == 115
&& STRNCMP(tp + extra - 2, "0;115;0c", 8) == 0)
is_not_xterm = TRUE;
/* Only request the cursor style if t_SH and t_RS are
* set. Not for Terminal.app, it can't handle t_RS, it
* echoes the characters to the screen. */
if (rcs_status == STATUS_GET
# ifdef MACOS
&& !is_terminal_app
# endif
&& !is_not_xterm
&& *T_CSH != NUL
&& *T_CRS != NUL)
{
LOG_TR("Sending cursor style request");
out_str(T_CRS);
rcs_status = STATUS_SENT;
out_flush();
need_flush = TRUE;
}
/* Only request the cursor blink mode if t_RC set. Not
* for Gnome terminal, it can't handle t_RC, it
* echoes the characters to the screen. */
if (rbm_status == STATUS_GET
&& !is_not_xterm
&& *T_CRC != NUL)
{
LOG_TR("Sending cursor blink mode request");
out_str(T_CRC);
rbm_status = STATUS_SENT;
need_flush = TRUE;
}
if (need_flush)
out_flush();
}
slen = i + 1;
# ifdef FEAT_EVAL
set_vim_var_string(VV_TERMRESPONSE, tp, i + 1);
set_vim_var_string(VV_TERMRESPONSE, tp, slen);
# endif
# ifdef FEAT_AUTOCMD
apply_autocmds(EVENT_TERMRESPONSE,
@@ -4602,7 +4623,6 @@ check_termcode(
# endif
key_name[0] = (int)KS_EXTRA;
key_name[1] = (int)KE_IGNORE;
slen = i + 1;
}
/* Check blinking cursor from xterm:
@@ -4626,6 +4646,9 @@ check_termcode(
key_name[0] = (int)KS_EXTRA;
key_name[1] = (int)KE_IGNORE;
slen = i + 1;
# ifdef FEAT_EVAL
set_vim_var_string(VV_TERMBLINKRESP, tp, slen);
# endif
}
/*
@@ -4714,6 +4737,9 @@ check_termcode(
/* Sometimes the 0x07 is followed by 0x18, unclear
* when this happens. */
++slen;
# ifdef FEAT_EVAL
set_vim_var_string(VV_TERMRGBRESP, tp, slen);
# endif
break;
}
if (i == len)
@@ -4788,6 +4814,9 @@ check_termcode(
key_name[0] = (int)KS_EXTRA;
key_name[1] = (int)KE_IGNORE;
slen = i + 1 + (tp[i] == ESC);
# ifdef FEAT_EVAL
set_vim_var_string(VV_TERMSTYLERESP, tp, slen);
# endif
}
}

View File

@@ -110,6 +110,7 @@ struct terminal_S {
int tl_channel_closed;
int tl_finish; /* 'c' for ++close, 'o' for ++open */
char_u *tl_opencmd;
char_u *tl_eof_chars;
#ifdef WIN3264
void *tl_winpty_config;
@@ -389,6 +390,9 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
if (opt->jo_term_opencmd != NULL)
term->tl_opencmd = vim_strsave(opt->jo_term_opencmd);
if (opt->jo_eof_chars != NULL)
term->tl_eof_chars = vim_strsave(opt->jo_eof_chars);
set_string_option_direct((char_u *)"buftype", -1,
(char_u *)"terminal", OPT_FREE|OPT_LOCAL, 0);
@@ -490,6 +494,20 @@ ex_terminal(exarg_T *eap)
opt.jo_term_cols = atoi((char *)ep + 1);
p = skiptowhite(cmd);
}
else if ((int)(p - cmd) == 3 && STRNICMP(cmd, "eof", 3) == 0
&& ep != NULL)
{
char_u *buf = NULL;
char_u *keys;
p = skiptowhite(cmd);
*p = NUL;
keys = replace_termcodes(ep + 1, &buf, TRUE, TRUE, TRUE);
opt.jo_set2 |= JO2_EOF_CHARS;
opt.jo_eof_chars = vim_strsave(keys);
vim_free(buf);
*p = ' ';
}
else
{
if (*p)
@@ -570,6 +588,7 @@ free_terminal(buf_T *buf)
vim_free(term->tl_title);
vim_free(term->tl_status_text);
vim_free(term->tl_opencmd);
vim_free(term->tl_eof_chars);
vim_free(term->tl_cursor_color);
vim_free(term);
buf->b_term = NULL;
@@ -1281,8 +1300,8 @@ term_paste_register(int prev_c UNUSED)
WCHAR *ret = NULL;
int length = 0;
MultiByteToWideChar_alloc(enc_codepage, 0, (char*)s, STRLEN(s),
&ret, &length);
MultiByteToWideChar_alloc(enc_codepage, 0, (char *)s,
(int)STRLEN(s), &ret, &length);
if (ret != NULL)
{
WideCharToMultiByte_alloc(CP_UTF8, 0,
@@ -1292,7 +1311,7 @@ term_paste_register(int prev_c UNUSED)
}
#endif
channel_send(curbuf->b_term->tl_job->jv_channel, PART_IN,
s, STRLEN(s), NULL);
s, (int)STRLEN(s), NULL);
#ifdef WIN3264
if (tmp != s)
vim_free(s);
@@ -1851,7 +1870,7 @@ handle_settermprop(
int length = 0;
MultiByteToWideChar_alloc(CP_UTF8, 0,
(char*)value->string, STRLEN(value->string),
(char*)value->string, (int)STRLEN(value->string),
&ret, &length);
if (ret != NULL)
{
@@ -2821,7 +2840,7 @@ f_term_start(typval_T *argvars, typval_T *rettv)
+ JO_EXIT_CB + JO_CLOSE_CALLBACK,
JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
+ JO2_CWD + JO2_ENV) == FAIL)
+ JO2_CWD + JO2_ENV + JO2_EOF_CHARS) == FAIL)
return;
if (opt.jo_vertical)
@@ -2890,6 +2909,32 @@ f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
}
}
/*
* Called when a channel has sent all the lines to a terminal.
* Send a CTRL-D to mark the end of the text.
*/
void
term_send_eof(channel_T *ch)
{
term_T *term;
for (term = first_term; term != NULL; term = term->tl_next)
if (term->tl_job == ch->ch_job)
{
if (term->tl_eof_chars != NULL)
{
channel_send(ch, PART_IN, term->tl_eof_chars,
(int)STRLEN(term->tl_eof_chars), NULL);
channel_send(ch, PART_IN, (char_u *)"\r", 1, NULL);
}
# ifdef WIN3264
else
/* Default: CTRL-D */
channel_send(ch, PART_IN, (char_u *)"\004\r", 2, NULL);
# endif
}
}
# if defined(WIN3264) || defined(PROTO)
/**************************************
@@ -3060,8 +3105,6 @@ term_and_job_init(
if (job == NULL)
goto failed;
/* TODO: when all lines are written and the fd is closed, the command
* doesn't get EOF and hangs. */
if (opt->jo_set & JO_IN_BUF)
job->jv_in_buf = buflist_findnr(opt->jo_io_buf[PART_IN]);
@@ -3083,6 +3126,9 @@ term_and_job_init(
GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL));
/* Write lines with CR instead of NL. */
channel->ch_write_text_mode = TRUE;
jo = CreateJobObject(NULL, NULL);
if (jo == NULL)
goto failed;
@@ -3188,7 +3234,6 @@ terminal_enabled(void)
return dyn_winpty_init(FALSE) == OK;
}
# else
/**************************************

View File

@@ -50,7 +50,6 @@ SCRIPTS_ALL = \
test70.out \
test73.out \
test79.out \
test80.out \
test88.out \
test94.out \
test95.out \

View File

@@ -86,7 +86,7 @@ SCRIPT = test1.out test3.out test4.out test5.out \
test64.out \
test66.out test68.out test69.out \
test72.out \
test77a.out test78.out test79.out test80.out \
test77a.out test78.out test79.out \
test88.out \
test94.out \
test95.out test99.out \

View File

@@ -31,6 +31,7 @@ let test_values = {
\ 'history': [[0, 1, 100], [-1, 10001]],
\ 'iminsert': [[0, 1], [-1, 3, 999]],
\ 'imsearch': [[-1, 0, 1], [-2, 3, 999]],
\ 'imstyle': [[0, 1], [-1, 2, 999]],
\ 'lines': [[2, 24], [-1, 0, 1]],
\ 'linespace': [[0, 2, 4], ['']],
\ 'numberwidth': [[1, 4, 8, 10], [-1, 0, 11]],

View File

@@ -1,201 +0,0 @@
Test for *sub-replace-special* and *sub-replace-expression* on substitute().
Test for submatch() on substitute().
Test for *:s%* on :substitute.
STARTTEST
:so small.vim
ENDTEST
TEST_1:
STARTTEST
:set magic
:set cpo&
:$put =\"\n\nTEST_1:\"
:$put =substitute('A', 'A', '&&', '')
:$put =substitute('B', 'B', '\&', '')
:$put =substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', '')
:$put =substitute('D', 'D', 'd', '')
:$put =substitute('E', 'E', '~', '')
:$put =substitute('F', 'F', '\~', '')
:$put =substitute('G', 'G', '\ugg', '')
:$put =substitute('H', 'H', '\Uh\Eh', '')
:$put =substitute('I', 'I', '\lII', '')
:$put =substitute('J', 'J', '\LJ\EJ', '')
:$put =substitute('K', 'K', '\Uk\ek', '')
:$put =substitute('lLl', 'L', '
', '')
:$put =substitute('mMm', 'M', '\r', '')
:$put =substitute('nNn', 'N', '\
', '')
:$put =substitute('oOo', 'O', '\n', '')
:$put =substitute('pPp', 'P', '\b', '')
:$put =substitute('qQq', 'Q', '\t', '')
:$put =substitute('rRr', 'R', '\\', '')
:$put =substitute('sSs', 'S', '\c', '')
:$put =substitute('uUu', 'U', \"\n\", '')
:$put =substitute('vVv', 'V', \"\b\", '')
:$put =substitute('wWw', 'W', \"\\\", '')
:$put =substitute('xXx', 'X', \"\r\", '')
:$put =substitute('Y', 'Y', '\L\uyYy\l\EY', '')
:$put =substitute('Z', 'Z', '\U\lZzZ\u\Ez', '')
/^TEST_2
ENDTEST
TEST_2:
STARTTEST
:set nomagic
:set cpo&
:$put =\"\n\nTEST_2:\"
:$put =substitute('A', 'A', '&&', '')
:$put =substitute('B', 'B', '\&', '')
:$put =substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', '')
:$put =substitute('D', 'D', 'd', '')
:$put =substitute('E', 'E', '~', '')
:$put =substitute('F', 'F', '\~', '')
:$put =substitute('G', 'G', '\ugg', '')
:$put =substitute('H', 'H', '\Uh\Eh', '')
:$put =substitute('I', 'I', '\lII', '')
:$put =substitute('J', 'J', '\LJ\EJ', '')
:$put =substitute('K', 'K', '\Uk\ek', '')
:$put =substitute('lLl', 'L', '
', '')
:$put =substitute('mMm', 'M', '\r', '')
:$put =substitute('nNn', 'N', '\
', '')
:$put =substitute('oOo', 'O', '\n', '')
:$put =substitute('pPp', 'P', '\b', '')
:$put =substitute('qQq', 'Q', '\t', '')
:$put =substitute('rRr', 'R', '\\', '')
:$put =substitute('sSs', 'S', '\c', '')
:$put =substitute('tTt', 'T', \"\r\", '')
:$put =substitute('uUu', 'U', \"\n\", '')
:$put =substitute('vVv', 'V', \"\b\", '')
:$put =substitute('wWw', 'W', \"\\\", '')
:$put =substitute('X', 'X', '\L\uxXx\l\EX', '')
:$put =substitute('Y', 'Y', '\U\lYyY\u\Ey', '')
/^TEST_3
ENDTEST
TEST_3:
STARTTEST
:set magic&
:set cpo&
:$put =\"\n\nTEST_3:\"
:let y = substitute('aAa', 'A', '\="\\"', '') | $put =y
:let y = substitute('bBb', 'B', '\="\\\\"', '') | $put =y
:let y = substitute('cCc', 'C', '\="
"', '') | $put =y
:let y = substitute('dDd', 'D', '\="\\
"', '') | $put =y
:let y = substitute('eEe', 'E', '\="\\\\
"', '') | $put =y
:let y = substitute('fFf', 'F', '\="\\r"', '') | $put =y
:let y = substitute('jJj', 'J', '\="\\n"', '') | $put =y
:let y = substitute('kKk', 'K', '\="\r"', '') | $put =y
:let y = substitute('lLl', 'L', '\="\n"', '') | $put =y
/^TEST_4
ENDTEST
TEST_4:
STARTTEST
:set magic&
:set cpo&
:$put =\"\n\nTEST_4:\"
:let y = substitute('aAa', 'A', '\=substitute(submatch(0), ".", "\\", "")', '') | $put =y
:let y = substitute('bBb', 'B', '\=substitute(submatch(0), ".", "\\\\", "")', '') | $put =y
:let y = substitute('cCc', 'C', '\=substitute(submatch(0), ".", "
", "")', '') | $put =y
:let y = substitute('dDd', 'D', '\=substitute(submatch(0), ".", "\\
", "")', '') | $put =y
:let y = substitute('eEe', 'E', '\=substitute(submatch(0), ".", "\\\\
", "")', '') | $put =y
:let y = substitute('fFf', 'F', '\=substitute(submatch(0), ".", "\\r", "")', '') | $put =y
:let y = substitute('jJj', 'J', '\=substitute(submatch(0), ".", "\\n", "")', '') | $put =y
:let y = substitute('kKk', 'K', '\=substitute(submatch(0), ".", "\r", "")', '') | $put =y
:let y = substitute('lLl', 'L', '\=substitute(submatch(0), ".", "\n", "")', '') | $put =y
/^TEST_5
ENDTEST
TEST_5:
STARTTEST
:set magic&
:set cpo&
:$put =\"\n\nTEST_5:\"
:$put =substitute('A123456789', 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\=submatch(0) . submatch(9) . submatch(8) . submatch(7) . submatch(6) . submatch(5) . submatch(4) . submatch(3) . submatch(2) . submatch(1)', '')
:$put =substitute('A123456789', 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\=string([submatch(0, 1), submatch(9, 1), submatch(8, 1), submatch(7, 1), submatch(6, 1), submatch(5, 1), submatch(4, 1), submatch(3, 1), submatch(2, 1), submatch(1, 1)])', '')
/^TEST_6
ENDTEST
TEST_6:
STARTTEST
:set magic&
:$put =\"\n\nTEST_6:\"
:set cpo+=/
:$put =substitute('A', 'A', 'a', '')
:$put =substitute('B', 'B', '%', '')
:set cpo-=/
:$put =substitute('C', 'C', 'c', '')
:$put =substitute('D', 'D', '%', '')
/^TEST_7
ENDTEST
TEST_7:
STARTTEST
:set magic&
:set cpo&
:$put =\"\n\nTEST_7:\"
:$put =substitute('A
A', 'A.', '\=submatch(0)', '')
:$put =substitute(\"B\nB\", 'B.', '\=submatch(0)', '')
:$put =substitute(\"B\nB\", 'B.', '\=string(submatch(0, 1))', '')
:$put =substitute('-bb', '\zeb', 'a', 'g')
:$put =substitute('-bb', '\ze', 'c', 'g')
/^TEST_8
ENDTEST
TEST_8:
STARTTEST
:set magic&
:set cpo&
:$put =\"\n\nTEST_8:\"
:$put =',,X'
:s/\(^\|,\)\ze\(,\|X\)/\1N/g
:$put =',,Y'
:s/\(^\|,\)\ze\(,\|Y\)/\1N/gc
a:$put =',,Z'
:s/\(^\|,\)\ze\(,\|Z\)/\1N/gc
yy/^TEST_9:
ENDTEST
TEST_9:
STARTTEST
:set magic&
:set cpo&
:$put =\"\n\nTEST_9:\"
:$put ='xxx'
:s/x/X/gc
yyq/^TEST_10:
ENDTEST
TEST_10:
STARTTEST
:set magic&
:set cpo&
:$put =\"\n\nTEST_10:\"
:let y = substitute('123', '\zs', 'a', 'g') | $put =y
:let y = substitute('123', '\zs.', 'a', 'g') | $put =y
:let y = substitute('123', '.\zs', 'a', 'g') | $put =y
:let y = substitute('123', '\ze', 'a', 'g') | $put =y
:let y = substitute('123', '\ze.', 'a', 'g') | $put =y
:let y = substitute('123', '.\ze', 'a', 'g') | $put =y
:let y = substitute('123', '1\|\ze', 'a', 'g') | $put =y

View File

@@ -1,131 +0,0 @@
Results of test72:
TEST_1:
AA
&
C123456789987654321
d
~
~
Gg
Hh
iI
jJ
Kk
l
l
m
m
n
n
o
o
pp
q q
r\r
scs
u
u
vv
w\w
x
x
YyyY
zZZz
TEST_2:
AA
&
C123456789987654321
d
~
~
Gg
Hh
iI
jJ
Kk
l
l
m
m
n
n
o
o
pp
q q
r\r
scs
t
t
u
u
vv
w\w
XxxX
yYYy
TEST_3:
a\a
b\\b
c
c
d\
d
e\\
e
f\rf
j\nj
k
k
l
l
TEST_4:
a\a
b\b
c
c
d
d
e\
e
f
f
j
j
k
k
l
l
TEST_5:
A123456789987654321
[['A123456789'], ['9'], ['8'], ['7'], ['6'], ['5'], ['4'], ['3'], ['2'], ['1']]
TEST_6:
a
%
c
%
TEST_7:
A
A
B
B
['B
']B
-abab
c-cbcbc
TEST_8:

View File

@@ -280,13 +280,13 @@ func Test_diffopt_icase()
set diffopt=icase,foldcolumn:0
e one
call setline(1, ['One', 'Two', 'Three', 'Four'])
call setline(1, ['One', 'Two', 'Three', 'Four', 'Fi#ve'])
redraw
let normattr = screenattr(1, 1)
diffthis
botright vert new two
call setline(1, ['one', 'TWO', 'Three ', 'Four'])
call setline(1, ['one', 'TWO', 'Three ', 'Four', 'fI=VE'])
diffthis
redraw
@@ -295,6 +295,10 @@ func Test_diffopt_icase()
call assert_notequal(normattr, screenattr(3, 1))
call assert_equal(normattr, screenattr(4, 1))
let dtextattr = screenattr(5, 3)
call assert_notequal(dtextattr, screenattr(5, 1))
call assert_notequal(dtextattr, screenattr(5, 5))
diffoff!
%bwipe!
set diffopt&

View File

@@ -121,5 +121,35 @@ func Test_mksession_arglist()
argdel *
endfunc
func Test_mksession_one_buffer_two_windows()
edit Xtest1
new Xtest2
split
mksession! Xtest_mks.out
let lines = readfile('Xtest_mks.out')
let count1 = 0
let count2 = 0
let count2buf = 0
for line in lines
if line =~ 'edit \f*Xtest1$'
let count1 += 1
endif
if line =~ 'edit \f\{-}Xtest2'
let count2 += 1
endif
if line =~ 'buffer \f\{-}Xtest2'
let count2buf += 1
endif
endfor
call assert_equal(1, count1, 'Xtest1 count')
call assert_equal(2, count2, 'Xtest2 count')
call assert_equal(2, count2buf, 'Xtest2 buffer count')
close
bwipe!
call delete('Xtest_mks.out')
endfunc
" vim: shiftwidth=2 sts=2 expandtab

View File

@@ -1897,8 +1897,9 @@ func Xproperty_tests(cchar)
call g:Xsetlist([], 'r', {'nr':2,'title':'Fruits','context':['Fruits']})
let l1=g:Xgetlist({'nr':1,'all':1})
let l2=g:Xgetlist({'nr':2,'all':1})
let l1.nr=2
let l2.nr=1
let save_id = l1.id
let l1.id=l2.id
let l2.id=save_id
call g:Xsetlist([], 'r', l1)
call g:Xsetlist([], 'r', l2)
let newl1=g:Xgetlist({'nr':1,'all':1})
@@ -2298,25 +2299,26 @@ func Xsetexpr_tests(cchar)
call s:setup_commands(a:cchar)
let t = ["File1:10:Line10", "File1:20:Line20"]
call g:Xsetlist([], ' ', {'text' : t})
call g:Xsetlist([], 'a', {'text' : "File1:30:Line30"})
call g:Xsetlist([], ' ', {'lines' : t})
call g:Xsetlist([], 'a', {'lines' : ["File1:30:Line30"]})
let l = g:Xgetlist()
call assert_equal(3, len(l))
call assert_equal(20, l[1].lnum)
call assert_equal('Line30', l[2].text)
call g:Xsetlist([], 'r', {'text' : "File2:5:Line5"})
call g:Xsetlist([], 'r', {'lines' : ["File2:5:Line5"]})
let l = g:Xgetlist()
call assert_equal(1, len(l))
call assert_equal('Line5', l[0].text)
call assert_equal(-1, g:Xsetlist([], 'a', {'text' : 10}))
call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : 10}))
call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : "F1:10:L10"}))
call g:Xsetlist([], 'f')
" Add entries to multiple lists
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:10:Line10"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:20:Line20"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:15:Line15"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:25:Line25"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:10:Line10"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:20:Line20"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:15:Line15"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:25:Line25"]})
call assert_equal('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text)
call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text)
endfunc
@@ -2333,10 +2335,10 @@ func Xmultidirstack_tests(cchar)
call g:Xsetlist([], 'f')
Xexpr "" | Xexpr ""
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "Entering dir 'Xone/a'"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "Entering dir 'Xtwo/a'"})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "one.txt:3:one one one"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "two.txt:5:two two two"})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["Entering dir 'Xone/a'"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["Entering dir 'Xtwo/a'"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["one.txt:3:one one one"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["two.txt:5:two two two"]})
let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1})
@@ -2370,10 +2372,10 @@ func Xmultifilestack_tests(cchar)
call g:Xsetlist([], 'f')
Xexpr "" | Xexpr ""
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "[one.txt]"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "[two.txt]"})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "(3,5) one one one"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "(5,9) two two two"})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["[one.txt]"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["[two.txt]"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["(3,5) one one one"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["(5,9) two two two"]})
let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1})
@@ -2522,26 +2524,59 @@ endfunc
" Test for getting the quickfix list items from some text without modifying
" the quickfix stack
func XgetListFromText(cchar)
func XgetListFromLines(cchar)
call s:setup_commands(a:cchar)
call g:Xsetlist([], 'f')
let l = g:Xgetlist({'text' : "File1:10:Line10"}).items
call assert_equal(1, len(l))
call assert_equal('Line10', l[0].text)
let l = g:Xgetlist({'text' : ["File2:20:Line20", "File2:30:Line30"]}).items
let l = g:Xgetlist({'lines' : ["File2:20:Line20", "File2:30:Line30"]}).items
call assert_equal(2, len(l))
call assert_equal(30, l[1].lnum)
call assert_equal({}, g:Xgetlist({'text' : 10}))
call assert_equal({}, g:Xgetlist({'text' : []}))
call assert_equal({}, g:Xgetlist({'lines' : 10}))
call assert_equal({}, g:Xgetlist({'lines' : 'File1:10:Line10'}))
call assert_equal([], g:Xgetlist({'lines' : []}).items)
call assert_equal([], g:Xgetlist({'lines' : [10, 20]}).items)
" Make sure that the quickfix stack is not modified
call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
endfunc
func Test_get_list_from_text()
call XgetListFromText('c')
call XgetListFromText('l')
func Test_get_list_from_lines()
call XgetListFromLines('c')
call XgetListFromLines('l')
endfunc
" Tests for the quickfix list id
func Xqfid_tests(cchar)
call s:setup_commands(a:cchar)
call g:Xsetlist([], 'f')
call assert_equal({}, g:Xgetlist({'id':0}))
Xexpr ''
let start_id = g:Xgetlist({'id' : 0}).id
Xexpr '' | Xexpr ''
Xolder
call assert_equal(start_id, g:Xgetlist({'id':0, 'nr':1}).id)
call assert_equal(start_id + 1, g:Xgetlist({'id':0, 'nr':0}).id)
call assert_equal(start_id + 2, g:Xgetlist({'id':0, 'nr':'$'}).id)
call assert_equal({}, g:Xgetlist({'id':0, 'nr':99}))
call assert_equal(2, g:Xgetlist({'id':start_id + 1, 'nr':0}).nr)
call assert_equal({}, g:Xgetlist({'id':99, 'nr':0}))
call assert_equal({}, g:Xgetlist({'id':"abc", 'nr':0}))
call g:Xsetlist([], 'a', {'id':start_id, 'context':[1,2]})
call assert_equal([1,2], g:Xgetlist({'nr':1, 'context':1}).context)
call g:Xsetlist([], 'a', {'id':start_id+1, 'lines':['F1:10:L10']})
call assert_equal('L10', g:Xgetlist({'nr':2, 'items':1}).items[0].text)
call assert_equal(-1, g:Xsetlist([], 'a', {'id':999, 'title':'Vim'}))
call assert_equal(-1, g:Xsetlist([], 'a', {'id':'abc', 'title':'Vim'}))
let qfid = g:Xgetlist({'id':0, 'nr':0})
call g:Xsetlist([], 'f')
call assert_equal({}, g:Xgetlist({'id':qfid, 'nr':0}))
endfunc
func Test_qf_id()
call Xqfid_tests('c')
call Xqfid_tests('l')
endfunc

View File

@@ -114,3 +114,183 @@ func Test_substitute_repeat()
call feedkeys("Qsc\<CR>y", 'tx')
bwipe!
endfunc
" Test for *sub-replace-special* and *sub-replace-expression* on substitute().
func Test_sub_replace_1()
" Run the tests with 'magic' on
set magic
set cpo&
call assert_equal('AA', substitute('A', 'A', '&&', ''))
call assert_equal('&', substitute('B', 'B', '\&', ''))
call assert_equal('C123456789987654321', substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', ''))
call assert_equal('d', substitute('D', 'D', 'd', ''))
call assert_equal('~', substitute('E', 'E', '~', ''))
call assert_equal('~', substitute('F', 'F', '\~', ''))
call assert_equal('Gg', substitute('G', 'G', '\ugg', ''))
call assert_equal('Hh', substitute('H', 'H', '\Uh\Eh', ''))
call assert_equal('iI', substitute('I', 'I', '\lII', ''))
call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', ''))
call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', ''))
call assert_equal("l\<C-V>\<C-M>l",
\ substitute('lLl', 'L', "\<C-V>\<C-M>", ''))
call assert_equal("m\<C-M>m", substitute('mMm', 'M', '\r', ''))
call assert_equal("n\<C-V>\<C-M>n",
\ substitute('nNn', 'N', "\\\<C-V>\<C-M>", ''))
call assert_equal("o\no", substitute('oOo', 'O', '\n', ''))
call assert_equal("p\<C-H>p", substitute('pPp', 'P', '\b', ''))
call assert_equal("q\tq", substitute('qQq', 'Q', '\t', ''))
call assert_equal('r\r', substitute('rRr', 'R', '\\', ''))
call assert_equal('scs', substitute('sSs', 'S', '\c', ''))
call assert_equal("u\nu", substitute('uUu', 'U', "\n", ''))
call assert_equal("v\<C-H>v", substitute('vVv', 'V', "\b", ''))
call assert_equal("w\\w", substitute('wWw', 'W', "\\", ''))
call assert_equal("x\<C-M>x", substitute('xXx', 'X', "\r", ''))
call assert_equal("YyyY", substitute('Y', 'Y', '\L\uyYy\l\EY', ''))
call assert_equal("zZZz", substitute('Z', 'Z', '\U\lZzZ\u\Ez', ''))
endfunc
func Test_sub_replace_2()
" Run the tests with 'magic' off
set nomagic
set cpo&
call assert_equal('AA', substitute('A', 'A', '&&', ''))
call assert_equal('&', substitute('B', 'B', '\&', ''))
call assert_equal('C123456789987654321', substitute('C123456789', 'C\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)', '\0\9\8\7\6\5\4\3\2\1', ''))
call assert_equal('d', substitute('D', 'D', 'd', ''))
call assert_equal('~', substitute('E', 'E', '~', ''))
call assert_equal('~', substitute('F', 'F', '\~', ''))
call assert_equal('Gg', substitute('G', 'G', '\ugg', ''))
call assert_equal('Hh', substitute('H', 'H', '\Uh\Eh', ''))
call assert_equal('iI', substitute('I', 'I', '\lII', ''))
call assert_equal('jJ', substitute('J', 'J', '\LJ\EJ', ''))
call assert_equal('Kk', substitute('K', 'K', '\Uk\ek', ''))
call assert_equal("l\<C-V>\<C-M>l",
\ substitute('lLl', 'L', "\<C-V>\<C-M>", ''))
call assert_equal("m\<C-M>m", substitute('mMm', 'M', '\r', ''))
call assert_equal("n\<C-V>\<C-M>n",
\ substitute('nNn', 'N', "\\\<C-V>\<C-M>", ''))
call assert_equal("o\no", substitute('oOo', 'O', '\n', ''))
call assert_equal("p\<C-H>p", substitute('pPp', 'P', '\b', ''))
call assert_equal("q\tq", substitute('qQq', 'Q', '\t', ''))
call assert_equal('r\r', substitute('rRr', 'R', '\\', ''))
call assert_equal('scs', substitute('sSs', 'S', '\c', ''))
call assert_equal("t\<C-M>t", substitute('tTt', 'T', "\r", ''))
call assert_equal("u\nu", substitute('uUu', 'U', "\n", ''))
call assert_equal("v\<C-H>v", substitute('vVv', 'V', "\b", ''))
call assert_equal('w\w', substitute('wWw', 'W', "\\", ''))
call assert_equal('XxxX', substitute('X', 'X', '\L\uxXx\l\EX', ''))
call assert_equal('yYYy', substitute('Y', 'Y', '\U\lYyY\u\Ey', ''))
endfunc
func Test_sub_replace_3()
set magic&
set cpo&
call assert_equal('a\a', substitute('aAa', 'A', '\="\\"', ''))
call assert_equal('b\\b', substitute('bBb', 'B', '\="\\\\"', ''))
call assert_equal("c\rc", substitute('cCc', 'C', "\\=\"\r\"", ''))
call assert_equal("d\\\rd", substitute('dDd', 'D', "\\=\"\\\\\r\"", ''))
call assert_equal("e\\\\\re", substitute('eEe', 'E', "\\=\"\\\\\\\\\r\"", ''))
call assert_equal('f\rf', substitute('fFf', 'F', '\="\\r"', ''))
call assert_equal('j\nj', substitute('jJj', 'J', '\="\\n"', ''))
call assert_equal("k\<C-M>k", substitute('kKk', 'K', '\="\r"', ''))
call assert_equal("l\nl", substitute('lLl', 'L', '\="\n"', ''))
endfunc
" Test for submatch() on substitute().
func Test_sub_replace_4()
set magic&
set cpo&
call assert_equal('a\a', substitute('aAa', 'A',
\ '\=substitute(submatch(0), ".", "\\", "")', ''))
call assert_equal('b\b', substitute('bBb', 'B',
\ '\=substitute(submatch(0), ".", "\\\\", "")', ''))
call assert_equal("c\<C-V>\<C-M>c", substitute('cCc', 'C', '\=substitute(submatch(0), ".", "\<C-V>\<C-M>", "")', ''))
call assert_equal("d\<C-V>\<C-M>d", substitute('dDd', 'D', '\=substitute(submatch(0), ".", "\\\<C-V>\<C-M>", "")', ''))
call assert_equal("e\\\<C-V>\<C-M>e", substitute('eEe', 'E', '\=substitute(submatch(0), ".", "\\\\\<C-V>\<C-M>", "")', ''))
call assert_equal("f\<C-M>f", substitute('fFf', 'F', '\=substitute(submatch(0), ".", "\\r", "")', ''))
call assert_equal("j\nj", substitute('jJj', 'J', '\=substitute(submatch(0), ".", "\\n", "")', ''))
call assert_equal("k\rk", substitute('kKk', 'K', '\=substitute(submatch(0), ".", "\r", "")', ''))
call assert_equal("l\nl", substitute('lLl', 'L', '\=substitute(submatch(0), ".", "\n", "")', ''))
endfunc
func Test_sub_replace_5()
set magic&
set cpo&
call assert_equal('A123456789987654321', substitute('A123456789',
\ 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
\ '\=submatch(0) . submatch(9) . submatch(8) . ' .
\ 'submatch(7) . submatch(6) . submatch(5) . ' .
\ 'submatch(4) . submatch(3) . submatch(2) . submatch(1)',
\ ''))
call assert_equal("[['A123456789'], ['9'], ['8'], ['7'], ['6'], " .
\ "['5'], ['4'], ['3'], ['2'], ['1']]",
\ substitute('A123456789',
\ 'A\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)\(.\)',
\ '\=string([submatch(0, 1), submatch(9, 1), ' .
\ 'submatch(8, 1), submatch(7, 1), submatch(6, 1), ' .
\ 'submatch(5, 1), submatch(4, 1), submatch(3, 1), ' .
\ 'submatch(2, 1), submatch(1, 1)])',
\ ''))
endfunc
func Test_sub_replace_6()
set magic&
set cpo+=/
call assert_equal('a', substitute('A', 'A', 'a', ''))
call assert_equal('%', substitute('B', 'B', '%', ''))
set cpo-=/
call assert_equal('c', substitute('C', 'C', 'c', ''))
call assert_equal('%', substitute('D', 'D', '%', ''))
endfunc
func Test_sub_replace_7()
set magic&
set cpo&
call assert_equal('AA', substitute('AA', 'A.', '\=submatch(0)', ''))
call assert_equal("B\nB", substitute("B\nB", 'B.', '\=submatch(0)', ''))
call assert_equal("['B\n']B", substitute("B\nB", 'B.', '\=string(submatch(0, 1))', ''))
call assert_equal('-abab', substitute('-bb', '\zeb', 'a', 'g'))
call assert_equal('c-cbcbc', substitute('-bb', '\ze', 'c', 'g'))
endfunc
" Test for *:s%* on :substitute.
func Test_sub_replace_8()
new
set magic&
set cpo&
$put =',,X'
s/\(^\|,\)\ze\(,\|X\)/\1N/g
call assert_equal('N,,NX', getline("$"))
$put =',,Y'
let cmd = ':s/\(^\|,\)\ze\(,\|Y\)/\1N/gc'
call feedkeys(cmd . "\<CR>a", "xt")
call assert_equal('N,,NY', getline("$"))
:$put =',,Z'
let cmd = ':s/\(^\|,\)\ze\(,\|Z\)/\1N/gc'
call feedkeys(cmd . "\<CR>yy", "xt")
call assert_equal('N,,NZ', getline("$"))
enew! | close
endfunc
func Test_sub_replace_9()
new
set magic&
set cpo&
$put ='xxx'
call feedkeys(":s/x/X/gc\<CR>yyq", "xt")
call assert_equal('XXx', getline("$"))
enew! | close
endfunc
func Test_sub_replace_10()
set magic&
set cpo&
call assert_equal('a1a2a3a', substitute('123', '\zs', 'a', 'g'))
call assert_equal('aaa', substitute('123', '\zs.', 'a', 'g'))
call assert_equal('1a2a3a', substitute('123', '.\zs', 'a', 'g'))
call assert_equal('a1a2a3a', substitute('123', '\ze', 'a', 'g'))
call assert_equal('a1a2a3', substitute('123', '\ze.', 'a', 'g'))
call assert_equal('aaa', substitute('123', '.\ze', 'a', 'g'))
call assert_equal('aa2a3a', substitute('123', '1\|\ze', 'a', 'g'))
call assert_equal('1aaa', substitute('123', '1\zs\|[23]', 'a', 'g'))
endfunc

View File

@@ -84,6 +84,7 @@ endfunc
func Test_terminal_hide_buffer()
let buf = Run_shell_in_terminal({})
setlocal bufhidden=hide
quit
for nr in range(1, winnr('$'))
call assert_notequal(winbufnr(nr), buf)
@@ -356,13 +357,13 @@ func Test_finish_open_close()
call assert_equal(1, winnr('$'))
exe 'terminal ++open ' . cmd
close
close!
call WaitFor("winnr('$') == 2", waittime)
call assert_equal(2, winnr('$'))
bwipe
call term_start(cmd, {'term_finish': 'open'})
close
close!
call WaitFor("winnr('$') == 2", waittime)
call assert_equal(2, winnr('$'))
bwipe
@@ -385,7 +386,7 @@ func Test_finish_open_close()
call assert_fails("call term_start(cmd, {'term_opencmd': 'split % and %d'})", 'E475:')
call term_start(cmd, {'term_finish': 'open', 'term_opencmd': '4split | buffer %d'})
close
close!
call WaitFor("winnr('$') == 2", waittime)
call assert_equal(2, winnr('$'))
call assert_equal(4, winheight(0))
@@ -488,25 +489,48 @@ func Test_terminal_noblock()
endfunc
func Test_terminal_write_stdin()
" Todo: make this work on all systems.
if !has('unix')
return
if !executable('wc')
throw 'skipped: wc command not available'
endif
new
call setline(1, ['one', 'two', 'three'])
%term wc
call WaitFor('getline(1) != ""')
let nrs = split(getline(1))
call WaitFor('getline("$") =~ "3"')
let nrs = split(getline('$'))
call assert_equal(['3', '3', '14'], nrs)
bwipe
new
call setline(1, ['one', 'two', 'three', 'four'])
2,3term wc
call WaitFor('getline(1) != ""')
let nrs = split(getline(1))
call WaitFor('getline("$") =~ "2"')
let nrs = split(getline('$'))
call assert_equal(['2', '2', '10'], nrs)
bwipe
if executable('python')
new
call setline(1, ['print("hello")'])
1term ++eof=exit() python
" MS-Windows echoes the input, Unix doesn't.
call WaitFor('getline("$") =~ "exit" || getline(1) =~ "hello"')
if getline(1) =~ 'hello'
call assert_equal('hello', getline(1))
else
call assert_equal('hello', getline(line('$') - 1))
endif
bwipe
if has('win32')
new
call setline(1, ['print("hello")'])
1term ++eof=<C-Z> python
call WaitFor('getline("$") =~ "Z"')
call assert_equal('hello', getline(line('$') - 1))
bwipe
endif
endif
bwipe!
endfunc

View File

@@ -1,7 +1,7 @@
" Tests for 'virtualedit'.
func Test_yank_move_change()
split
new
call setline(1, [
\ "func foo() error {",
\ "\tif n, err := bar();",
@@ -29,3 +29,15 @@ func Test_yank_move_change()
set virtualedit=
set ts=8
endfunc
func Test_paste_end_of_line()
new
set virtualedit=all
call setline(1, ['456', '123'])
normal! gg0"ay$
exe "normal! 2G$lllA\<C-O>:normal! \"agP\r"
call assert_equal('123456', getline(2))
bwipe!
set virtualedit=
endfunc

View File

@@ -38,76 +38,73 @@ func CheckHomeIsInSubprocessEnvironment(exp)
endfunc
func CheckHome(exp, ...)
"call assert_equal(a:exp, $HOME)
"call assert_equal(a:exp, expand('~', ':p'))
call assert_equal(a:exp, $HOME)
call assert_equal(a:exp, expand('~', ':p'))
if !a:0
call CheckHomeIsMissingFromSubprocessEnvironment()
else
call CheckHomeIsInSubprocessEnvironment(a:exp)
call CheckHomeIsInSubprocessEnvironment(a:1)
endif
endfunc
func TestWindowsHome()
func Test_WindowsHome()
command! -nargs=* SaveEnv call <SID>save_env(<f-args>)
command! -nargs=* RestoreEnv call <SID>restore_env()
command! -nargs=* UnletEnv call <SID>unlet_env(<f-args>)
set noshellslash
SaveEnv $HOME $USERPROFILE $HOMEDRIVE $HOMEPATH
let save_home = $HOME
SaveEnv $USERPROFILE $HOMEDRIVE $HOMEPATH
try
RestoreEnv
UnletEnv $HOME $USERPROFILE $HOMEPATH
let $HOMEDRIVE = 'C:'
call CheckHome('C:\')
RestoreEnv
UnletEnv $HOME $USERPROFILE
" Normal behavior: use $HOMEDRIVE and $HOMEPATH, ignore $USERPROFILE
let $USERPROFILE = 'unused'
let $HOMEDRIVE = 'C:'
let $HOMEPATH = '\foobar'
let $HOME = '' " Force recomputing "homedir"
call CheckHome('C:\foobar')
RestoreEnv
UnletEnv $HOME $HOMEDRIVE $HOMEPATH
" Same, but with $HOMEPATH not set
UnletEnv $HOMEPATH
let $HOME = '' " Force recomputing "homedir"
call CheckHome('C:\')
" Use $USERPROFILE if $HOMEPATH and $HOMEDRIVE are empty
UnletEnv $HOMEDRIVE $HOMEPATH
let $USERPROFILE = 'C:\foo'
let $HOME = '' " Force recomputing "homedir"
call CheckHome('C:\foo')
RestoreEnv
UnletEnv $HOME
let $USERPROFILE = 'C:\foo'
let $HOMEDRIVE = 'C:'
let $HOMEPATH = '\baz'
call CheckHome('C:\foo')
RestoreEnv
" If $HOME is set the others don't matter
let $HOME = 'C:\bar'
let $USERPROFILE = 'C:\foo'
let $HOMEDRIVE = 'C:'
let $HOMEPATH = '\baz'
call CheckHome('C:\bar', 1)
let $USERPROFILE = 'unused'
let $HOMEDRIVE = 'unused'
let $HOMEPATH = 'unused'
call CheckHome('C:\bar', 'C:\bar')
RestoreEnv
" If $HOME contains %USERPROFILE% it is expanded
let $USERPROFILE = 'C:\foo'
let $HOME = '%USERPROFILE%\bar'
let $USERPROFILE = 'C:\foo'
let $HOMEDRIVE = 'C:'
let $HOMEPATH = '\baz'
call CheckHome('%USERPROFILE%\bar', 1)
let $HOMEDRIVE = 'unused'
let $HOMEPATH = 'unused'
call CheckHome('C:\foo\bar', '%USERPROFILE%\bar')
RestoreEnv
" Invalid $HOME is kept
let $USERPROFILE = 'C:\foo'
let $HOME = '%USERPROFILE'
let $USERPROFILE = 'C:\foo'
let $HOMEDRIVE = 'C:'
let $HOMEPATH = '\baz'
call CheckHome('%USERPROFILE', 1)
let $HOMEDRIVE = 'unused'
let $HOMEPATH = 'unused'
call CheckHome('%USERPROFILE', '%USERPROFILE')
RestoreEnv
" %USERPROFILE% not at start of $HOME is not expanded
let $USERPROFILE = 'unused'
let $HOME = 'C:\%USERPROFILE%'
let $USERPROFILE = 'C:\foo'
let $HOMEDRIVE = 'C:'
let $HOMEPATH = '\baz'
call CheckHome('C:\%USERPROFILE%', 1)
let $HOMEDRIVE = 'unused'
let $HOMEPATH = 'unused'
call CheckHome('C:\%USERPROFILE%', 'C:\%USERPROFILE%')
if has('channel')
RestoreEnv
UnletEnv $HOME
let $HOME = save_home
let env = ''
let job = job_start('cmd /c set', {'out_cb': {ch,x->[env,execute('let env=x')]}})
sleep 1

View File

@@ -2984,7 +2984,7 @@ u_sync(
if (curbuf->b_u_synced || (!force && no_u_sync > 0))
return;
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
if (im_is_preediting())
if (p_imst == IM_ON_THE_SPOT && im_is_preediting())
return; /* XIM is busy, don't break an undo sequence */
#endif
if (get_undolevel() < 0)

View File

@@ -769,6 +769,52 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1037,
/**/
1036,
/**/
1035,
/**/
1034,
/**/
1033,
/**/
1032,
/**/
1031,
/**/
1030,
/**/
1029,
/**/
1028,
/**/
1027,
/**/
1026,
/**/
1025,
/**/
1024,
/**/
1023,
/**/
1022,
/**/
1021,
/**/
1020,
/**/
1019,
/**/
1018,
/**/
1017,
/**/
1016,
/**/
1015,
/**/
1014,
/**/

View File

@@ -2012,7 +2012,11 @@ typedef int sock_T;
#define VV_TYPE_NONE 78
#define VV_TYPE_JOB 79
#define VV_TYPE_CHANNEL 80
#define VV_LEN 81 /* number of v: vars */
#define VV_TERMRGBRESP 81
#define VV_TERMU7RESP 82
#define VV_TERMSTYLERESP 83
#define VV_TERMBLINKRESP 84
#define VV_LEN 85 /* number of v: vars */
/* used for v_number in VAR_SPECIAL */
#define VVAL_FALSE 0L