Compare commits

...

15 Commits

Author SHA1 Message Date
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
36 changed files with 943 additions and 606 deletions

View File

@ -4632,20 +4632,24 @@ getqflist([{what}]) *getqflist()*
returns only the items listed in {what} as a dictionary. The returns only the items listed in {what} as a dictionary. The
following string items are supported in {what}: following string items are supported in {what}:
context get the context stored with |setqflist()| 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 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 nr get information for this quickfix list; zero
means the current quickfix list and '$' means means the current quickfix list and '$' means
the last quickfix list 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 title get the list title
winid get the |window-ID| (if opened) winid get the |window-ID| (if opened)
all all of the above quickfix properties all all of the above quickfix properties
Non-string items in {what} are ignored. Non-string items in {what} are ignored.
If "nr" is not present then the current quickfix list is used. 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 To get the number of lists in the quickfix stack, set 'nr' to
'$' in {what}. The 'nr' value in the returned dictionary '$' in {what}. The 'nr' value in the returned dictionary
contains the quickfix stack size. contains the quickfix stack size.
@ -4657,6 +4661,7 @@ getqflist([{what}]) *getqflist()*
The returned dictionary contains the following entries: The returned dictionary contains the following entries:
context context information stored with |setqflist()| context context information stored with |setqflist()|
id quickfix list ID |quickfix-ID|
items quickfix list entries items quickfix list entries
nr quickfix list number nr quickfix list number
title quickfix list title text title quickfix list title text
@ -4665,6 +4670,7 @@ getqflist([{what}]) *getqflist()*
Examples: > Examples: >
:echo getqflist({'all': 1}) :echo getqflist({'all': 1})
:echo getqflist({'nr': 2, 'title': 1}) :echo getqflist({'nr': 2, 'title': 1})
:echo getqflist({'lines' : ["F1:10:L10"]})
< <
getreg([{regname} [, 1 [, {list}]]]) *getreg()* getreg([{regname} [, 1 [, {list}]]]) *getreg()*
@ -7065,12 +7071,12 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
argument is ignored. The following items can be specified in argument is ignored. The following items can be specified in
{what}: {what}:
context any Vim type can be stored as a context context any Vim type can be stored as a context
text use 'errorformat' to extract items from the id quickfix list identifier |quickfix-ID|
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.
items list of quickfix entries. Same as the {list} items list of quickfix entries. Same as the {list}
argument. 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 nr list number in the quickfix stack; zero
means the current quickfix list and '$' means means the current quickfix list and '$' means
the last quickfix list the last quickfix list
@ -7079,10 +7085,14 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
If the "nr" item is not present, then the current quickfix list If the "nr" item is not present, then the current quickfix list
is modified. When creating a new quickfix list, "nr" can be is modified. When creating a new quickfix list, "nr" can be
set to a value one greater than the quickfix stack size. 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: > Examples: >
:call setqflist([], 'r', {'title': 'My search'}) :call setqflist([], 'r', {'title': 'My search'})
:call setqflist([], 'r', {'nr': 2, 'title': 'Errors'}) :call setqflist([], 'r', {'nr': 2, 'title': 'Errors'})
:call setqflist([], 'a', {'id':myid, 'lines':["F1:10:L10"]})
< <
Returns zero for success, -1 for failure. Returns zero for success, -1 for failure.
@ -8131,6 +8141,12 @@ term_start({cmd}, {options}) *term_start()*
have "%d" where the buffer number goes, have "%d" where the buffer number goes,
e.g. "10split|buffer %d"; when not e.g. "10split|buffer %d"; when not
specified "botright sbuf %d" is used 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} {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 Currently, GUI Vim supports three styles, |OverTheSpot|, |OffTheSpot| and
|Root|. |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* *. on-the-spot *OnTheSpot*
Preedit Area and Status Area are performed by the client application in 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. 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'*
'include' 'inc' string (default "^\s*#\s*include") 'include' 'inc' string (default "^\s*#\s*include")
global or local to buffer |global-local| global or local to buffer |global-local|

View File

@ -133,6 +133,14 @@ Syntax ~
height. height.
++cols={width} Use {width} for the terminal window ++cols={width} Use {width} for the terminal window
width. 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()| If you want to use more options use the |term_start()|
function. 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")` is killed, similar to calling `job_stop(job, "kill")`
So long as the job is running the window behaves like it contains a modified 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` buffer. Trying to close the window with `CTRL-W :quit` fails. When using
fails, unless "!" is added, in which case the job is ended. The text in the `CTRL-W :quit!` the job is ended. The text in the window is lost. The buffer
window is lost. The buffer still exists, but getting it in a window with still exists, but getting it in a window with `:buffer` will show an empty
`:buffer` will show an buffer.
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 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 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. # Set to yes to enable terminal support.
TERMINAL=no 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 # Link against the shared version of libstdc++ by default. Set
# STATIC_STDCPLUS to "yes" to link against static version instead. # 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 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) $(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: clean:
-$(DEL) $(OUTDIR)$(DIRSLASH)*.o -$(DEL) $(OUTDIR)$(DIRSLASH)*.o
-$(DEL) $(OUTDIR)$(DIRSLASH)*.res -$(DEL) $(OUTDIR)$(DIRSLASH)*.res

View File

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

View File

@ -2100,17 +2100,17 @@ test1 \
test_listchars \ test_listchars \
test_search_mbyte \ test_search_mbyte \
test_wordcount \ test_wordcount \
test3 test4 test5 test6 test7 test8 test9 \ test3 test4 test5 test7 test8 \
test11 test12 test14 test15 test17 test18 test19 \ test11 test12 test14 test15 test17 test19 \
test20 test21 test22 test25 test27 test28 test29 \ test20 test25 test28 test29 \
test30 test31 test32 test33 test34 test36 test37 test38 test39 \ test30 test31 test32 test33 test34 test36 test37 test38 test39 \
test40 test41 test42 test43 test44 test45 test48 test49 \ 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 \ test60 test64 test66 test68 test69 \
test70 test72 test73 test74 test77 test78 test79 \ test70 test72 test73 test77 test78 test79 \
test80 test83 test84 test85 test86 test87 test88 \ test83 test85 test86 test87 test88 \
test91 test94 test95 test98 test99 \ test94 test95 test99 \
test100 test101 test103 test104 test107 test108: test108:
cd testdir; rm -f $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTARGET) $(GUI_TESTARG) SCRIPTSOURCE=../$(SCRIPTSOURCE) 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. # 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; return;
memcpy((char *)p, (char *)line, len); memcpy((char *)p, (char *)line, len);
for (i = 0; i < len; ++i) if (channel->ch_write_text_mode)
if (p[i] == NL) p[len] = CAR;
p[i] = NUL; else
{
for (i = 0; i < len; ++i)
if (p[i] == NL)
p[i] = NUL;
p[len] = NL; p[len] = NL;
}
p[len + 1] = NUL; p[len + 1] = NUL;
channel_send(channel, PART_IN, p, len + 1, "write_buf_line"); channel_send(channel, PART_IN, p, len + 1, "write_buf_line");
vim_free(p); vim_free(p);
@ -1417,6 +1422,12 @@ channel_write_in(channel_T *channel)
in_part->ch_buf_top = lnum; in_part->ch_buf_top = lnum;
if (lnum > buf->b_ml.ml_line_count || lnum > in_part->ch_buf_bot) 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. */ /* Writing is done, no longer need the buffer. */
in_part->ch_bufref.br_buf = NULL; in_part->ch_bufref.br_buf = NULL;
ch_log(channel, "Finished writing all lines to channel"); 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; 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) else if (STRCMP(hi->hi_key, "term_rows") == 0)
{ {
if (!(supported2 & JO2_TERM_ROWS)) if (!(supported2 & JO2_TERM_ROWS))

View File

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

View File

@ -2098,11 +2098,16 @@ viminfo_filename(char_u *file)
else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL) else if ((file = find_viminfo_parameter('n')) == NULL || *file == NUL)
{ {
#ifdef VIMINFO_FILE2 #ifdef VIMINFO_FILE2
/* don't use $HOME when not defined (turned into "c:/"!). */
# ifdef VMS # ifdef VMS
if (mch_getenv((char_u *)"SYS$LOGIN") == NULL) if (mch_getenv((char_u *)"SYS$LOGIN") == NULL)
# else # 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) if (mch_getenv((char_u *)"HOME") == NULL)
# endif
# endif # endif
{ {
/* don't use $VIM when not available. */ /* 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_do_win(win_T *wp);
static int ses_arglist(FILE *fd, char *cmd, garray_T *gap, int fullname, unsigned *flagp); 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_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. * 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 if (fprintf(fd, "badd +%ld ", buf->b_wininfo == NULL ? 1L
: buf->b_wininfo->wi_fpos.lnum) < 0 : buf->b_wininfo->wi_fpos.lnum) < 0
|| ses_fname(fd, buf, &ssop_flags) == FAIL) || ses_fname(fd, buf, &ssop_flags, TRUE) == FAIL)
return FAIL; return FAIL;
} }
} }
@ -11289,7 +11289,8 @@ makeopens(
) )
{ {
if (fputs(need_tabnew ? "tabedit " : "edit ", fd) < 0 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; return FAIL;
need_tabnew = FALSE; need_tabnew = FALSE;
if (!wp->w_arg_idx_invalid) if (!wp->w_arg_idx_invalid)
@ -11636,9 +11637,20 @@ put_view(
/* /*
* Editing a file in this buffer: use ":edit file". * Editing a file in this buffer: use ":edit file".
* This may have side effects! (e.g., compressed or network 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 if (fputs("if bufexists('", fd) < 0
|| ses_fname(fd, wp->w_buffer, flagp) == FAIL) || 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; return FAIL;
} }
else else
@ -11651,7 +11663,7 @@ put_view(
{ {
/* The buffer does have a name, but it's not a file name. */ /* The buffer does have a name, but it's not a file name. */
if (fputs("file ", fd) < 0 if (fputs("file ", fd) < 0
|| ses_fname(fd, wp->w_buffer, flagp) == FAIL) || ses_fname(fd, wp->w_buffer, flagp, TRUE) == FAIL)
return FAIL; return FAIL;
} }
#endif #endif
@ -11823,11 +11835,11 @@ ses_arglist(
/* /*
* Write a buffer name to the session file. * 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. * Returns FAIL if writing fails.
*/ */
static int 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; char_u *name;
@ -11846,7 +11858,8 @@ ses_fname(FILE *fd, buf_T *buf, unsigned *flagp)
name = buf->b_sfname; name = buf->b_sfname;
else else
name = buf->b_ffname; 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 FAIL;
return OK; return OK;
} }

View File

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

View File

@ -2,7 +2,7 @@
* iscygpty.c -- part of ptycheck * iscygpty.c -- part of ptycheck
* https://github.com/k-takata/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 * You can redistribute it and/or modify it under the terms of either
* the MIT license (as described below) or the Vim license. * the MIT license (as described below) or the Vim license.
@ -27,6 +27,8 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/ */
#ifdef _WIN32
#include <ctype.h> #include <ctype.h>
#include <io.h> #include <io.h>
#include <wchar.h> #include <wchar.h>
@ -60,19 +62,19 @@
//#define USE_DYNFILEID //#define USE_DYNFILEID
#ifdef USE_DYNFILEID #ifdef USE_DYNFILEID
typedef BOOL (WINAPI *pfnGetFileInformationByHandleEx)( typedef BOOL (WINAPI *pfnGetFileInformationByHandleEx)(
HANDLE hFile, HANDLE hFile,
FILE_INFO_BY_HANDLE_CLASS FileInformationClass, FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
LPVOID lpFileInformation, LPVOID lpFileInformation,
DWORD dwBufferSize DWORD dwBufferSize
); );
static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL; static pfnGetFileInformationByHandleEx pGetFileInformationByHandleEx = NULL;
# ifndef USE_FILEEXTD # ifndef USE_FILEEXTD
static BOOL WINAPI stub_GetFileInformationByHandleEx( static BOOL WINAPI stub_GetFileInformationByHandleEx(
HANDLE hFile, HANDLE hFile,
FILE_INFO_BY_HANDLE_CLASS FileInformationClass, FILE_INFO_BY_HANDLE_CLASS FileInformationClass,
LPVOID lpFileInformation, LPVOID lpFileInformation,
DWORD dwBufferSize DWORD dwBufferSize
) )
{ {
return FALSE; return FALSE;
@ -111,7 +113,7 @@ int is_cygpty(int fd)
return 0; return 0;
#else #else
HANDLE h; 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; FILE_NAME_INFO *nameinfo;
WCHAR *p = NULL; WCHAR *p = NULL;
@ -125,7 +127,7 @@ int is_cygpty(int fd)
if (GetFileType(h) != FILE_TYPE_PIPE) { if (GetFileType(h) != FILE_TYPE_PIPE) {
return 0; return 0;
} }
nameinfo = malloc(size); nameinfo = malloc(size + sizeof(WCHAR));
if (nameinfo == NULL) { if (nameinfo == NULL) {
return 0; return 0;
} }
@ -178,4 +180,6 @@ int is_cygpty_used(void)
return ret; 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 * iscygpty.h -- part of ptycheck
* https://github.com/k-takata/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 * You can redistribute it and/or modify it under the terms of either
* the MIT license (as described below) or the Vim license. * the MIT license (as described below) or the Vim license.
@ -30,7 +30,12 @@
#ifndef _ISCYGPTY_H #ifndef _ISCYGPTY_H
#define _ISCYGPTY_H #define _ISCYGPTY_H
#ifdef _WIN32
int is_cygpty(int fd); int is_cygpty(int fd);
int is_cygpty_used(void); int is_cygpty_used(void);
#else
#define is_cygpty(fd) 0
#define is_cygpty_used() 0
#endif
#endif /* _ISCYGPTY_H */ #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_keyval = GDK_VoidSymbol;
static unsigned int im_activatekey_state = 0; 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 void
im_set_active(int active) im_set_active(int active)
{ {
@ -4825,6 +4830,9 @@ im_set_position(int row, int col)
area.height = gui.char_height; area.height = gui.char_height;
gtk_im_context_set_cursor_location(xic, &area); 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) if (input_conv.vc_type != CONV_NONE)
vim_free(str); 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 */ if (p_mh) /* blank out the pointer if necessary */
gui_mch_mousehide(TRUE); gui_mch_mousehide(TRUE);
} }
@ -4861,6 +4958,12 @@ im_delete_preedit(void)
char_u bskey[] = {CSI, 'k', 'b'}; char_u bskey[] = {CSI, 'k', 'b'};
char_u delkey[] = {CSI, 'k', 'D'}; char_u delkey[] = {CSI, 'k', 'D'};
if (p_imst == IM_OVER_THE_SPOT)
{
im_preedit_window_close();
return;
}
if (State & NORMAL) if (State & NORMAL)
{ {
im_preedit_cursor = 0; im_preedit_cursor = 0;
@ -4933,40 +5036,43 @@ im_commit_cb(GtkIMContext *context UNUSED,
xim_log("im_commit_cb(): %s\n", str); xim_log("im_commit_cb(): %s\n", str);
#endif #endif
/* The imhangul module doesn't reset the preedit string before if (p_imst == IM_ON_THE_SPOT)
* 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(); /* The imhangul module doesn't reset the preedit string before
commit_with_preedit = FALSE; * 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 /* 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 * 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 * 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) if (add_to_input)
im_add_to_input((char_u *)str, slen); im_add_to_input((char_u *)str, slen);
/* Inserting chars while "im_is_active" is set does not cause a change of if (p_imst == IM_ON_THE_SPOT)
* buffer. When the chars are committed the buffer must be marked as {
* changed. */ /* Inserting chars while "im_is_active" is set does not cause a
if (!commit_with_preedit) * change of buffer. When the chars are committed the buffer must be
preedit_start_col = MAXCOL; * marked as changed. */
if (!commit_with_preedit)
preedit_start_col = MAXCOL;
/* This flag is used in changed() at next call. */ /* This flag is used in changed() at next call. */
xim_changed_while_preediting = TRUE; xim_changed_while_preediting = TRUE;
}
if (gtk_main_level() > 0) if (gtk_main_level() > 0)
gtk_main_quit(); gtk_main_quit();
@ -5031,7 +5140,8 @@ im_preedit_end_cb(GtkIMContext *context UNUSED, gpointer data UNUSED)
im_delete_preedit(); im_delete_preedit();
/* Indicate that preediting has finished */ /* Indicate that preediting has finished */
preedit_start_col = MAXCOL; if (p_imst == IM_ON_THE_SPOT)
preedit_start_col = MAXCOL;
xim_has_preediting = FALSE; xim_has_preediting = FALSE;
#if 0 #if 0
@ -5092,9 +5202,14 @@ im_preedit_changed_cb(GtkIMContext *context, gpointer data UNUSED)
char_u *p; char_u *p;
int i; int i;
gtk_im_context_get_preedit_string(context, if (p_imst == IM_ON_THE_SPOT)
&preedit_string, NULL, gtk_im_context_get_preedit_string(context,
&cursor_index); &preedit_string, NULL,
&cursor_index);
else
gtk_im_context_get_preedit_string(context,
&preedit_string, NULL,
NULL);
#ifdef XIM_DEBUG #ifdef XIM_DEBUG
xim_log("im_preedit_changed_cb(): %s\n", preedit_string); 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 */ g_return_if_fail(preedit_string != NULL); /* just in case */
/* If preedit_start_col is MAXCOL set it to the current cursor position. */ if (p_imst == IM_OVER_THE_SPOT)
if (preedit_start_col == MAXCOL && preedit_string[0] != '\0')
{ {
xim_has_preediting = TRUE; if (preedit_string[0] == NUL)
{
/* Urgh, this breaks if the input buffer isn't empty now */ xim_has_preediting = FALSE;
init_preedit_start_col(); 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) /* Urgh, this breaks if the input buffer isn't empty now */
* preedit_start_col must be reset. */ init_preedit_start_col();
preedit_start_col = MAXCOL; }
} 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;
}
/* im_delete_preedit();
* 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;
is_composing = ((*p & 0x80) != 0 && utf_iscomposing(utf_ptr2char(p)));
/* /*
* These offsets are used as counters when generating <BS> and <Del> * Compute the end of the preediting area: "preedit_end_col".
* to delete the preedit string. So don't count composing characters * According to the documentation of gtk_im_context_get_preedit_string(),
* unless 'delcombine' is enabled. * 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) 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) is_composing = ((*p & 0x80) != 0 && utf_iscomposing(utf_ptr2char(p)));
{ /*
im_add_to_input(str, (int)(p - str)); * These offsets are used as counters when generating <BS> and <Del>
im_correct_cursor(num_move_back); * 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); g_free(preedit_string);
@ -5310,7 +5441,8 @@ im_shutdown(void)
} }
im_is_active = FALSE; im_is_active = FALSE;
im_commit_handler_id = 0; im_commit_handler_id = 0;
preedit_start_col = MAXCOL; if (p_imst == IM_ON_THE_SPOT)
preedit_start_col = MAXCOL;
xim_has_preediting = FALSE; 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; 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); int imresult = gtk_im_context_filter_keypress(xic, event);
/* Some XIM send following sequence: if (p_imst == IM_ON_THE_SPOT)
* 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); /* Some XIM send following sequence:
return FALSE; * 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., /* 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) changed(void)
{ {
#if defined(FEAT_XIM) && defined(FEAT_GUI_GTK) #if defined(FEAT_XIM) && defined(FEAT_GUI_GTK)
/* The text of the preediting area is inserted, but this doesn't if (p_imst == IM_ON_THE_SPOT)
* mean a change of the buffer yet. That is delayed until the {
* text is committed. (this means preedit becomes empty) */ /* The text of the preediting area is inserted, but this doesn't
if (im_is_preediting() && !xim_changed_while_preediting) * mean a change of the buffer yet. That is delayed until the
return; * text is committed. (this means preedit becomes empty) */
xim_changed_while_preediting = FALSE; if (im_is_preediting() && !xim_changed_while_preediting)
return;
xim_changed_while_preediting = FALSE;
}
#endif #endif
if (!curbuf->b_changed) if (!curbuf->b_changed)

View File

@ -1606,13 +1606,22 @@ static struct vimoption options[] =
#endif #endif
SCRIPTID_INIT}, SCRIPTID_INIT},
{"imstatusfunc","imsf",P_STRING|P_VI_DEF|P_SECURE, {"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 *)&p_imsf, PV_NONE,
{(char_u *)"", (char_u *)NULL} {(char_u *)"", (char_u *)NULL}
# else #else
(char_u *)NULL, PV_NONE, (char_u *)NULL, PV_NONE,
{(char_u *)NULL, (char_u *)0L} {(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}, SCRIPTID_INIT},
{"include", "inc", P_STRING|P_ALLOCED|P_VI_DEF, {"include", "inc", P_STRING|P_ALLOCED|P_VI_DEF,
#ifdef FEAT_FIND_ID #ifdef FEAT_FIND_ID
@ -8990,6 +8999,15 @@ set_num_option(
#endif #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) else if (pp == &p_window)
{ {
if (p_window < 1) 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_imak; /* 'imactivatekey' */
EXTERN char_u *p_imaf; /* 'imactivatefunc' */ EXTERN char_u *p_imaf; /* 'imactivatefunc' */
EXTERN char_u *p_imsf; /* 'imstatusfunc' */ EXTERN char_u *p_imsf; /* 'imstatusfunc' */
EXTERN long p_imst; /* 'imstyle' */
# define IM_ON_THE_SPOT 0L
# define IM_OVER_THE_SPOT 1L
#endif #endif
#ifdef USE_IM_CONTROL #ifdef USE_IM_CONTROL
EXTERN int p_imcmdline; /* 'imcmdline' */ EXTERN int p_imcmdline; /* 'imcmdline' */

View File

@ -2280,6 +2280,7 @@ vim_is_xterm(char_u *name)
|| STRNICMP(name, "kterm", 5) == 0 || STRNICMP(name, "kterm", 5) == 0
|| STRNICMP(name, "mlterm", 6) == 0 || STRNICMP(name, "mlterm", 6) == 0
|| STRNICMP(name, "rxvt", 4) == 0 || STRNICMP(name, "rxvt", 4) == 0
|| STRNICMP(name, "screen.xterm", 12) == 0
|| STRCMP(name, "builtin_xterm") == 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_is_finished(buf_T *buf);
int term_show_buffer(buf_T *buf); int term_show_buffer(buf_T *buf);
void term_change_in_curbuf(void); 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); int term_get_attr(buf_T *buf, linenr_T lnum, int col);
char_u *term_get_status_text(term_T *term); char_u *term_get_status_text(term_T *term);
int set_ref_in_term(int copyID); int set_ref_in_term(int copyID);

View File

@ -58,6 +58,7 @@ struct qfline_S
*/ */
typedef struct qf_list_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_start; /* pointer to the first error */
qfline_T *qf_last; /* pointer to the last error */ qfline_T *qf_last; /* pointer to the last error */
qfline_T *qf_ptr; /* pointer to the current 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 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 */ #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++; qi->qf_curlist = qi->qf_listcount++;
vim_memset(&qi->qf_lists[qi->qf_curlist], 0, (size_t)(sizeof(qf_list_T))); vim_memset(&qi->qf_lists[qi->qf_curlist], 0, (size_t)(sizeof(qf_list_T)));
qf_store_title(qi, qi->qf_curlist, qf_title); 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 */ 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 /* When no valid entries are present in the list, qf_ptr points to
* the first item in the list */ * the first item in the list */
if (to_qfl->qf_nonevalid) if (to_qfl->qf_nonevalid)
@ -2808,6 +2814,7 @@ qf_free(qf_info_T *qi, int idx)
qfl->qf_title = NULL; qfl->qf_title = NULL;
free_tv(qfl->qf_ctx); free_tv(qfl->qf_ctx);
qfl->qf_ctx = NULL; qfl->qf_ctx = NULL;
qfl->qf_id = 0;
} }
/* /*
@ -4628,6 +4635,7 @@ enum {
QF_GETLIST_NR = 0x4, QF_GETLIST_NR = 0x4,
QF_GETLIST_WINID = 0x8, QF_GETLIST_WINID = 0x8,
QF_GETLIST_CONTEXT = 0x10, QF_GETLIST_CONTEXT = 0x10,
QF_GETLIST_ID = 0x20,
QF_GETLIST_ALL = 0xFF QF_GETLIST_ALL = 0xFF
}; };
@ -4635,16 +4643,19 @@ enum {
* Parse text from 'di' and return the quickfix list items * Parse text from 'di' and return the quickfix list items
*/ */
static int 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; int status = FAIL;
qf_info_T *qi; qf_info_T *qi;
/* Only string and list values are supported */ /* Only a List value is supported */
if ((di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL) if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL)
|| (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)); qi = (qf_info_T *)alloc((unsigned)sizeof(qf_info_T));
if (qi != NULL) 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, if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, p_efm,
TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0)
{ {
list_T *l = list_alloc(); (void)get_errorlist(qi, NULL, 0, l);
if (l != NULL)
{
(void)get_errorlist(qi, NULL, 0, l);
dict_add_list(retdict, "items", l);
status = OK;
}
qf_free(qi, 0); qf_free(qi, 0);
} }
free(qi); free(qi);
} }
dict_add_list(retdict, "items", l);
status = OK;
} }
return status; return status;
@ -4684,21 +4691,21 @@ get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
dictitem_T *di; dictitem_T *di;
int flags = QF_GETLIST_NONE; int flags = QF_GETLIST_NONE;
if ((di = dict_find(what, (char_u *)"text", -1)) != NULL) if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL)
return qf_get_list_from_text(di, retdict); return qf_get_list_from_lines(di, retdict);
if (wp != NULL) if (wp != NULL)
{
qi = GET_LOC_LIST(wp); qi = GET_LOC_LIST(wp);
if (qi == NULL)
{ /* List is not present or is empty */
/* If querying for the size of the location list, return 0 */ if (qi == NULL || qi->qf_listcount == 0)
if (((di = dict_find(what, (char_u *)"nr", -1)) != NULL) {
&& (di->di_tv.v_type == VAR_STRING) /* If querying for the size of the list, return 0 */
&& (STRCMP(di->di_tv.vval.v_string, "$") == 0)) if (((di = dict_find(what, (char_u *)"nr", -1)) != NULL)
return dict_add_nr_str(retdict, "nr", 0, NULL); && (di->di_tv.v_type == VAR_STRING)
return FAIL; && (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 */ 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) if (qf_idx < 0 || qf_idx >= qi->qf_listcount)
return FAIL; 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) else if ((di->di_tv.v_type == VAR_STRING)
&& (STRCMP(di->di_tv.vval.v_string, "$") == 0)) && (STRCMP(di->di_tv.vval.v_string, "$") == 0))
{
/* Get the last quickfix list number */ /* Get the last quickfix list number */
if (qi->qf_listcount > 0) qf_idx = qi->qf_listcount - 1;
qf_idx = qi->qf_listcount - 1; else
else return FAIL;
qf_idx = -1; /* Quickfix stack is empty */ flags |= QF_GETLIST_NR;
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 else
return FAIL; 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) if (dict_find(what, (char_u *)"title", -1) != NULL)
flags |= QF_GETLIST_TITLE; flags |= QF_GETLIST_TITLE;
if (dict_find(what, (char_u *)"winid", -1) != NULL) if (dict_find(what, (char_u *)"winid", -1) != NULL)
flags |= QF_GETLIST_WINID; flags |= QF_GETLIST_WINID;
if (dict_find(what, (char_u *)"context", -1) != NULL) if (dict_find(what, (char_u *)"context", -1) != NULL)
flags |= QF_GETLIST_CONTEXT; flags |= QF_GETLIST_CONTEXT;
if (dict_find(what, (char_u *)"items", -1) != NULL) if (dict_find(what, (char_u *)"items", -1) != NULL)
flags |= QF_GETLIST_ITEMS; flags |= QF_GETLIST_ITEMS;
}
if (flags & QF_GETLIST_TITLE) 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 *)""); 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; return status;
} }
@ -4983,6 +5005,21 @@ qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title)
return FAIL; 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) if (newlist)
{ {
qi->qf_curlist = qf_idx; 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 */ /* Only a List value is supported */
if ((di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL) if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL)
|| (di->di_tv.v_type == VAR_LIST
&& di->di_tv.vval.v_list != NULL))
{ {
if (action == 'r') if (action == 'r')
qf_free_items(qi, qf_idx); 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 /* 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 * preedit_changed and commit. Thus Vim can't set "im_is_active", use
* im_is_preediting() here. */ * im_is_preediting() here. */
if (xic != NULL if (p_imst == IM_ON_THE_SPOT
&& xic != NULL
&& lnum == wp->w_cursor.lnum && lnum == wp->w_cursor.lnum
&& (State & INSERT) && (State & INSERT)
&& !p_imdisable && !p_imdisable

View File

@ -1632,6 +1632,7 @@ struct channel_S {
int ch_last_msg_id; /* ID of the last message */ int ch_last_msg_id; /* ID of the last message */
chanpart_T ch_part[PART_COUNT]; /* info for socket, out, err and in */ 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 */ char *ch_hostname; /* only for socket, allocated */
int ch_port; /* only for socket */ int ch_port; /* only for socket */
@ -1713,7 +1714,8 @@ struct channel_S {
#define JO2_CURWIN 0x0200 /* "curwin" */ #define JO2_CURWIN 0x0200 /* "curwin" */
#define JO2_HIDDEN 0x0400 /* "hidden" */ #define JO2_HIDDEN 0x0400 /* "hidden" */
#define JO2_TERM_OPENCMD 0x0800 /* "term_opencmd" */ #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_MODE_ALL (JO_MODE + JO_IN_MODE + JO_OUT_MODE + JO_ERR_MODE)
#define JO_CB_ALL \ #define JO_CB_ALL \
@ -1779,6 +1781,7 @@ typedef struct
char_u *jo_term_name; char_u *jo_term_name;
char_u *jo_term_opencmd; char_u *jo_term_opencmd;
int jo_term_finish; int jo_term_finish;
char_u *jo_eof_chars;
#endif #endif
} jobopt_T; } jobopt_T;

View File

@ -4496,6 +4496,8 @@ check_termcode(
/* eat it when at least one digit and ending in 'c' */ /* eat it when at least one digit and ending in 'c' */
if (*T_CRV != NUL && i > 2 + (tp[0] != CSI) && tp[i] == 'c') if (*T_CRV != NUL && i > 2 + (tp[0] != CSI) && tp[i] == 'c')
{ {
int version = col;
LOG_TR("Received CRV response"); LOG_TR("Received CRV response");
crv_status = STATUS_GOT; crv_status = STATUS_GOT;
# ifdef FEAT_AUTOCMD # ifdef FEAT_AUTOCMD
@ -4508,10 +4510,11 @@ check_termcode(
switch_to_8bit(); switch_to_8bit();
/* rxvt sends its version number: "20703" is 2.7.3. /* rxvt sends its version number: "20703" is 2.7.3.
* Screen sends 40500.
* Ignore it for when the user has set 'term' to xterm, * Ignore it for when the user has set 'term' to xterm,
* even though it's an rxvt. */ * even though it's an rxvt. */
if (col > 20000) if (version > 20000)
col = 0; version = 0;
if (tp[1 + (tp[0] != CSI)] == '>' && semicols == 2) if (tp[1 + (tp[0] != CSI)] == '>' && semicols == 2)
{ {
@ -4522,19 +4525,19 @@ check_termcode(
if (!option_was_set((char_u *)"ttym")) if (!option_was_set((char_u *)"ttym"))
{ {
# ifdef TTYM_SGR # ifdef TTYM_SGR
if (col >= 277) if (version >= 277)
set_option_value((char_u *)"ttym", 0L, set_option_value((char_u *)"ttym", 0L,
(char_u *)"sgr", 0); (char_u *)"sgr", 0);
else else
# endif # endif
/* if xterm version >= 95 use mouse dragging */ /* if xterm version >= 95 use mouse dragging */
if (col >= 95) if (version >= 95)
set_option_value((char_u *)"ttym", 0L, set_option_value((char_u *)"ttym", 0L,
(char_u *)"xterm2", 0); (char_u *)"xterm2", 0);
} }
/* if xterm version >= 141 try to get termcap codes */ /* if xterm version >= 141 try to get termcap codes */
if (col >= 141) if (version >= 141)
{ {
LOG_TR("Enable checking for XT codes"); LOG_TR("Enable checking for XT codes");
check_for_codes = TRUE; check_for_codes = TRUE;
@ -4543,7 +4546,7 @@ check_termcode(
} }
/* libvterm sends 0;100;0 */ /* libvterm sends 0;100;0 */
if (col == 100 if (version == 100
&& STRNCMP(tp + extra - 2, "0;100;0c", 8) == 0) && STRNCMP(tp + extra - 2, "0;100;0c", 8) == 0)
{ {
/* If run from Vim $COLORS is set to the number of /* If run from Vim $COLORS is set to the number of
@ -4558,14 +4561,26 @@ check_termcode(
* compatible. */ * compatible. */
# ifdef MACOS # ifdef MACOS
/* Mac Terminal.app sends 1;95;0 */ /* Mac Terminal.app sends 1;95;0 */
if (col == 95 if (version == 95
&& STRNCMP(tp + extra - 2, "1;95;0c", 7) == 0) && STRNCMP(tp + extra - 2, "1;95;0c", 7) == 0)
is_not_xterm = TRUE; is_not_xterm = TRUE;
# endif # endif
/* Gnome Terminal.app sends 1;3801;0 or 1;4402;0, /* Gnome terminal sends 1;3801;0 or 1;4402;0.
* assuming any version number over 3000 is not an * xfce4-terminal sends 1;2802;0.
* xterm. */ * screen sends 83;40500;0
if (col >= 3000) * 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; is_not_xterm = TRUE;
/* Only request the cursor style if t_SH and t_RS are /* Only request the cursor style if t_SH and t_RS are

View File

@ -110,6 +110,7 @@ struct terminal_S {
int tl_channel_closed; int tl_channel_closed;
int tl_finish; /* 'c' for ++close, 'o' for ++open */ int tl_finish; /* 'c' for ++close, 'o' for ++open */
char_u *tl_opencmd; char_u *tl_opencmd;
char_u *tl_eof_chars;
#ifdef WIN3264 #ifdef WIN3264
void *tl_winpty_config; void *tl_winpty_config;
@ -389,6 +390,9 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
if (opt->jo_term_opencmd != NULL) if (opt->jo_term_opencmd != NULL)
term->tl_opencmd = vim_strsave(opt->jo_term_opencmd); 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, set_string_option_direct((char_u *)"buftype", -1,
(char_u *)"terminal", OPT_FREE|OPT_LOCAL, 0); (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); opt.jo_term_cols = atoi((char *)ep + 1);
p = skiptowhite(cmd); 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 else
{ {
if (*p) if (*p)
@ -570,6 +588,7 @@ free_terminal(buf_T *buf)
vim_free(term->tl_title); vim_free(term->tl_title);
vim_free(term->tl_status_text); vim_free(term->tl_status_text);
vim_free(term->tl_opencmd); vim_free(term->tl_opencmd);
vim_free(term->tl_eof_chars);
vim_free(term->tl_cursor_color); vim_free(term->tl_cursor_color);
vim_free(term); vim_free(term);
buf->b_term = NULL; buf->b_term = NULL;
@ -2821,7 +2840,7 @@ f_term_start(typval_T *argvars, typval_T *rettv)
+ JO_EXIT_CB + JO_CLOSE_CALLBACK, + JO_EXIT_CB + JO_CLOSE_CALLBACK,
JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN + JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
+ JO2_CWD + JO2_ENV) == FAIL) + JO2_CWD + JO2_ENV + JO2_EOF_CHARS) == FAIL)
return; return;
if (opt.jo_vertical) 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) # if defined(WIN3264) || defined(PROTO)
/************************************** /**************************************
@ -3060,8 +3105,6 @@ term_and_job_init(
if (job == NULL) if (job == NULL)
goto failed; 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) if (opt->jo_set & JO_IN_BUF)
job->jv_in_buf = buflist_findnr(opt->jo_io_buf[PART_IN]); job->jv_in_buf = buflist_findnr(opt->jo_io_buf[PART_IN]);
@ -3083,6 +3126,9 @@ term_and_job_init(
GENERIC_READ, 0, NULL, GENERIC_READ, 0, NULL,
OPEN_EXISTING, 0, NULL)); OPEN_EXISTING, 0, NULL));
/* Write lines with CR instead of NL. */
channel->ch_write_text_mode = TRUE;
jo = CreateJobObject(NULL, NULL); jo = CreateJobObject(NULL, NULL);
if (jo == NULL) if (jo == NULL)
goto failed; goto failed;
@ -3188,7 +3234,6 @@ terminal_enabled(void)
return dyn_winpty_init(FALSE) == OK; return dyn_winpty_init(FALSE) == OK;
} }
# else # else
/************************************** /**************************************

View File

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

View File

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

View File

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

@ -121,5 +121,35 @@ func Test_mksession_arglist()
argdel * argdel *
endfunc 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 " 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']}) call g:Xsetlist([], 'r', {'nr':2,'title':'Fruits','context':['Fruits']})
let l1=g:Xgetlist({'nr':1,'all':1}) let l1=g:Xgetlist({'nr':1,'all':1})
let l2=g:Xgetlist({'nr':2,'all':1}) let l2=g:Xgetlist({'nr':2,'all':1})
let l1.nr=2 let save_id = l1.id
let l2.nr=1 let l1.id=l2.id
let l2.id=save_id
call g:Xsetlist([], 'r', l1) call g:Xsetlist([], 'r', l1)
call g:Xsetlist([], 'r', l2) call g:Xsetlist([], 'r', l2)
let newl1=g:Xgetlist({'nr':1,'all':1}) let newl1=g:Xgetlist({'nr':1,'all':1})
@ -2298,25 +2299,26 @@ func Xsetexpr_tests(cchar)
call s:setup_commands(a:cchar) call s:setup_commands(a:cchar)
let t = ["File1:10:Line10", "File1:20:Line20"] let t = ["File1:10:Line10", "File1:20:Line20"]
call g:Xsetlist([], ' ', {'text' : t}) call g:Xsetlist([], ' ', {'lines' : t})
call g:Xsetlist([], 'a', {'text' : "File1:30:Line30"}) call g:Xsetlist([], 'a', {'lines' : ["File1:30:Line30"]})
let l = g:Xgetlist() let l = g:Xgetlist()
call assert_equal(3, len(l)) call assert_equal(3, len(l))
call assert_equal(20, l[1].lnum) call assert_equal(20, l[1].lnum)
call assert_equal('Line30', l[2].text) 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() let l = g:Xgetlist()
call assert_equal(1, len(l)) call assert_equal(1, len(l))
call assert_equal('Line5', l[0].text) 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') call g:Xsetlist([], 'f')
" Add entries to multiple lists " Add entries to multiple lists
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:10:Line10"]}) call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:10:Line10"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:20:Line20"]}) call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:20:Line20"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:15:Line15"]}) call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:15:Line15"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:25:Line25"]}) 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('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text)
call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text) call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text)
endfunc endfunc
@ -2333,10 +2335,10 @@ func Xmultidirstack_tests(cchar)
call g:Xsetlist([], 'f') call g:Xsetlist([], 'f')
Xexpr "" | Xexpr "" Xexpr "" | Xexpr ""
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "Entering dir 'Xone/a'"}) call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["Entering dir 'Xone/a'"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "Entering dir 'Xtwo/a'"}) call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["Entering dir 'Xtwo/a'"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "one.txt:3:one one one"}) call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["one.txt:3:one one one"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "two.txt:5:two two two"}) call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["two.txt:5:two two two"]})
let l1 = g:Xgetlist({'nr':1, 'items':1}) let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1}) let l2 = g:Xgetlist({'nr':2, 'items':1})
@ -2370,10 +2372,10 @@ func Xmultifilestack_tests(cchar)
call g:Xsetlist([], 'f') call g:Xsetlist([], 'f')
Xexpr "" | Xexpr "" Xexpr "" | Xexpr ""
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "[one.txt]"}) call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["[one.txt]"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "[two.txt]"}) call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["[two.txt]"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "(3,5) one one one"}) call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["(3,5) one one one"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "(5,9) two two two"}) call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["(5,9) two two two"]})
let l1 = g:Xgetlist({'nr':1, 'items':1}) let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, '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 " Test for getting the quickfix list items from some text without modifying
" the quickfix stack " the quickfix stack
func XgetListFromText(cchar) func XgetListFromLines(cchar)
call s:setup_commands(a:cchar) call s:setup_commands(a:cchar)
call g:Xsetlist([], 'f') call g:Xsetlist([], 'f')
let l = g:Xgetlist({'text' : "File1:10:Line10"}).items let l = g:Xgetlist({'lines' : ["File2:20:Line20", "File2:30:Line30"]}).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
call assert_equal(2, len(l)) call assert_equal(2, len(l))
call assert_equal(30, l[1].lnum) call assert_equal(30, l[1].lnum)
call assert_equal({}, g:Xgetlist({'text' : 10})) call assert_equal({}, g:Xgetlist({'lines' : 10}))
call assert_equal({}, g:Xgetlist({'text' : []})) 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 " Make sure that the quickfix stack is not modified
call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr) call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
endfunc endfunc
func Test_get_list_from_text() func Test_get_list_from_lines()
call XgetListFromText('c') call XgetListFromLines('c')
call XgetListFromText('l') 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 endfunc

View File

@ -114,3 +114,183 @@ func Test_substitute_repeat()
call feedkeys("Qsc\<CR>y", 'tx') call feedkeys("Qsc\<CR>y", 'tx')
bwipe! bwipe!
endfunc 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

@ -489,25 +489,48 @@ func Test_terminal_noblock()
endfunc endfunc
func Test_terminal_write_stdin() func Test_terminal_write_stdin()
" Todo: make this work on all systems. if !executable('wc')
if !has('unix') throw 'skipped: wc command not available'
return
endif endif
new new
call setline(1, ['one', 'two', 'three']) call setline(1, ['one', 'two', 'three'])
%term wc %term wc
call WaitFor('getline(1) != ""') call WaitFor('getline("$") =~ "3"')
let nrs = split(getline(1)) let nrs = split(getline('$'))
call assert_equal(['3', '3', '14'], nrs) call assert_equal(['3', '3', '14'], nrs)
bwipe bwipe
new
call setline(1, ['one', 'two', 'three', 'four']) call setline(1, ['one', 'two', 'three', 'four'])
2,3term wc 2,3term wc
call WaitFor('getline(1) != ""') call WaitFor('getline("$") =~ "2"')
let nrs = split(getline(1)) let nrs = split(getline('$'))
call assert_equal(['2', '2', '10'], nrs) call assert_equal(['2', '2', '10'], nrs)
bwipe 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! bwipe!
endfunc endfunc

View File

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

View File

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