Compare commits

...

9 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
17 changed files with 260 additions and 103 deletions

View File

@ -4636,14 +4636,13 @@ getqflist([{what}]) *getqflist()*
|quickfix-ID|; zero means the id for the |quickfix-ID|; zero means the id for the
current list or the list specifed by 'nr' 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
@ -4671,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()*
@ -7071,13 +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
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| id quickfix list identifier |quickfix-ID|
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
@ -7093,6 +7092,7 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
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.
@ -8141,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

@ -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

@ -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);
if (channel->ch_write_text_mode)
p[len] = CAR;
else
{
for (i = 0; i < len; ++i) for (i = 0; i < len; ++i)
if (p[i] == NL) if (p[i] == NL)
p[i] = NUL; 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

@ -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
# 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 # 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

@ -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>
@ -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

@ -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

@ -4643,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)
{ {
@ -4661,18 +4664,14 @@ 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();
if (l != NULL)
{ {
(void)get_errorlist(qi, NULL, 0, l); (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;
@ -4692,8 +4691,8 @@ 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);
@ -5052,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

@ -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,24 +4561,25 @@ 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 sends 1;3801;0 or 1;4402;0. /* Gnome terminal sends 1;3801;0 or 1;4402;0.
* xfce4-terminal sends 1;2802;0. * xfce4-terminal sends 1;2802;0.
* screen sends 83;40500;0
* Assuming any version number over 2800 is not an * Assuming any version number over 2800 is not an
* xterm. */ * xterm (without the limit for rxvt and screen). */
if (col >= 2800) if (col >= 2800)
is_not_xterm = TRUE; is_not_xterm = TRUE;
/* PuTTY sends 0;136;0 */ /* PuTTY sends 0;136;0 */
if (col == 136 if (version == 136
&& STRNCMP(tp + extra - 2, "0;136;0c", 8) == 0) && STRNCMP(tp + extra - 2, "0;136;0c", 8) == 0)
is_not_xterm = TRUE; is_not_xterm = TRUE;
/* Konsole sends 0;115;0 */ /* Konsole sends 0;115;0 */
if (col == 115 if (version == 115
&& STRNCMP(tp + extra - 2, "0;115;0c", 8) == 0) && STRNCMP(tp + extra - 2, "0;115;0c", 8) == 0)
is_not_xterm = TRUE; is_not_xterm = TRUE;

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

@ -2299,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
@ -2334,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})
@ -2371,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})
@ -2523,28 +2524,26 @@ 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 endfunc
" Tests for the quickfix list id " Tests for the quickfix list id
@ -2567,7 +2566,7 @@ func Xqfid_tests(cchar)
call g:Xsetlist([], 'a', {'id':start_id, 'context':[1,2]}) call g:Xsetlist([], 'a', {'id':start_id, 'context':[1,2]})
call assert_equal([1,2], g:Xgetlist({'nr':1, 'context':1}).context) call assert_equal([1,2], g:Xgetlist({'nr':1, 'context':1}).context)
call g:Xsetlist([], 'a', {'id':start_id+1, 'text':'F1:10:L10'}) 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('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':999, 'title':'Vim'}))
call assert_equal(-1, g:Xsetlist([], 'a', {'id':'abc', 'title':'Vim'})) call assert_equal(-1, g:Xsetlist([], 'a', {'id':'abc', 'title':'Vim'}))

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

@ -769,6 +769,24 @@ 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, 1027,
/**/ /**/