Merge remote-tracking branch 'vim/master'

This commit is contained in:
Kazuki Sakamoto
2017-09-08 18:18:07 -07:00
13 changed files with 460 additions and 162 deletions
+1
View File
@@ -638,6 +638,7 @@ RT_ALL = \
runtime/pack/dist/opt/matchit/doc/tags \
runtime/pack/dist/opt/shellmenu/plugin/shellmenu.vim \
runtime/pack/dist/opt/swapmouse/plugin/swapmouse.vim \
runtime/pack/dist/opt/termdebug/plugin/termdebug.vim \
# runtime files for all distributions without CR-NL translation
RT_ALL_BIN = \
+12 -9
View File
@@ -2401,7 +2401,7 @@ term_getscrolled({buf}) Number get the scroll count of a terminal
term_getsize({buf}) List get the size of a terminal
term_getstatus({buf}) String get the status of a terminal
term_gettitle({buf}) String get the title of a terminal
term_gettty({buf}) String get the tty name of a terminal
term_getttty({buf}, [{input}]) String get the tty name of a terminal
term_list() List get the list of terminal buffers
term_scrape({buf}, {row}) List get row of a terminal screen
term_sendkeys({buf}, {keys}) none send keystrokes to a terminal
@@ -5245,7 +5245,8 @@ job_info({job}) *job_info()*
"status" what |job_status()| returns
"channel" what |job_getchannel()| returns
"process" process ID
"tty" controlling terminal name, empty when none
"tty_in" terminal input name, empty when none
"tty_out" terminal output name, empty when none
"exitval" only valid when "status" is "dead"
"exit_cb" function to be called on exit
"stoponexit" |job-stoponexit|
@@ -8092,10 +8093,13 @@ term_gettitle({buf}) *term_gettitle()*
string is returned.
{only available when compiled with the |+terminal| feature}
term_gettty({buf}) *term_gettty()*
term_gettty({buf} [, {input}]) *term_gettty()*
Get the name of the controlling terminal associated with
terminal window {buf}.
{buf} is used as with |term_getsize()|.
terminal window {buf}. {buf} is used as with |term_getsize()|.
When {input} is omitted or 0, return the name for writing
(stdout). When {input} is 1 return the name for reading
(stdin). On UNIX, both return same name.
{only available when compiled with the |+terminal| feature}
term_list() *term_list()*
@@ -8173,10 +8177,9 @@ term_start({cmd}, {options}) *term_start()*
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}
CTRL-D is used on MS-Windows. For Python
use CTRL-Z or "exit()". For a shell use
"exit". A CR is always added.
{only available when compiled with the |+terminal| feature}
+101 -8
View File
@@ -1,35 +1,128 @@
" Debugger commands.
" Debugger plugin using gdb.
"
" WORK IN PROGRESS - much doesn't work yet
"
" Open two terminal windows:
" Open two visible terminal windows:
" 1. run a pty, as with ":term NONE"
" 2. run gdb, passing the pty
" The current window is used to edit source code and follows gdb.
" The current window is used to view source code and follows gdb.
"
" A third terminal window is hidden, it is used for communication with gdb.
"
" The communication with gdb uses GDB/MI. See:
" https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html
"
" Author: Bram Moolenaar
" Copyright: Vim license applies
" Copyright: Vim license applies, see ":help license"
" The command that starts debugging, e.g. ":Termdebug vim".
" To end type "quit" in the gdb window.
command -nargs=* -complete=file Termdebug call s:StartDebug(<q-args>)
" Name of the gdb command, defaults to "gdb".
if !exists('debugger')
let debugger = 'gdb'
endif
" Sign used to highlight the line where the program has stopped.
sign define debugPC linehl=debugPC
if &background == 'light'
hi debugPC term=reverse ctermbg=lightblue guibg=lightblue
else
hi debugPC term=reverse ctermbg=darkblue guibg=darkblue
endif
let s:pc_id = 12
func s:StartDebug(cmd)
let s:startwin = win_getid(winnr())
let s:startsigncolumn = &signcolumn
" Open a terminal window without a job, to run the debugged program
let s:ptybuf = term_start('NONE', {})
let pty = job_info(term_getjob(s:ptybuf))['tty']
let s:ptybuf = term_start('NONE', {
\ 'term_name': 'gdb program',
\ })
if s:ptybuf == 0
echoerr 'Failed to open the program terminal window'
return
endif
let pty = job_info(term_getjob(s:ptybuf))['tty_out']
" Create a hidden terminal window to communicate with gdb
let s:commbuf = term_start('NONE', {
\ 'term_name': 'gdb communication',
\ 'out_cb': function('s:CommOutput'),
\ 'hidden': 1,
\ })
if s:commbuf == 0
echoerr 'Failed to open the communication terminal window'
exe 'bwipe! ' . s:ptybuf
return
endif
let commpty = job_info(term_getjob(s:commbuf))['tty_out']
" Open a terminal window to run the debugger.
let cmd = [g:debugger, '-tty', pty, a:cmd]
echomsg 'executing "' . join(cmd) . '"'
let gdbbuf = term_start(cmd, {
\ 'exit_cb': function('s:EndDebug'),
\ 'term_finish': 'close'
\ 'term_finish': 'close',
\ })
if gdbbuf == 0
echoerr 'Failed to open the gdb terminal window'
exe 'bwipe! ' . s:ptybuf
exe 'bwipe! ' . s:commbuf
return
endif
" Connect gdb to the communication pty, using the GDB/MI interface
call term_sendkeys(gdbbuf, 'new-ui mi ' . commpty . "\r")
endfunc
func s:EndDebug(job, status)
exe 'bwipe! ' . s:ptybuf
exe 'bwipe! ' . s:ptybuf
exe 'bwipe! ' . s:commbuf
call setwinvar(s:startwin, '&signcolumn', s:startsigncolumn)
endfunc
" Handle a message received from gdb on the GDB/MI interface.
func s:CommOutput(chan, msg)
let msgs = split(a:msg, "\r")
for msg in msgs
" remove prefixed NL
if msg[0] == "\n"
let msg = msg[1:]
endif
if msg != ''
if msg =~ '^\*\(stopped\|running\)'
let wid = win_getid(winnr())
if win_gotoid(s:startwin)
if msg =~ '^\*stopped'
" TODO: proper parsing
let fname = substitute(msg, '.*fullname="\([^"]*\)".*', '\1', '')
let lnum = substitute(msg, '.*line="\([^"]*\)".*', '\1', '')
if lnum =~ '^[0-9]*$'
if expand('%:h') != fname
if &modified
" TODO: find existing window
exe 'split ' . fnameescape(fname)
let s:startwin = win_getid(winnr())
else
exe 'edit ' . fnameescape(fname)
endif
endif
exe lnum
exe 'sign place ' . s:pc_id . ' line=' . lnum . ' name=debugPC file=' . fnameescape(fname)
setlocal signcolumn=yes
endif
else
exe 'sign unplace ' . s:pc_id
endif
call win_gotoid(wid)
endif
endif
endif
endfor
endfunc
+16 -6
View File
@@ -3925,8 +3925,8 @@ build_stl_str_hl(
char_u *t;
int byteval;
#ifdef FEAT_EVAL
win_T *o_curwin;
buf_T *o_curbuf;
win_T *save_curwin;
buf_T *save_curbuf;
#endif
int empty_line;
colnr_T virtcol;
@@ -3968,6 +3968,9 @@ build_stl_str_hl(
char_u tmp[TMPLEN];
char_u *usefmt = fmt;
struct stl_hlrec *sp;
int save_must_redraw = must_redraw;
int save_redr_type = curwin->w_redr_type;
int save_highlight_shcnaged = need_highlight_changed;
#ifdef FEAT_EVAL
/*
@@ -4277,15 +4280,15 @@ build_stl_str_hl(
vim_snprintf((char *)tmp, sizeof(tmp), "%d", curbuf->b_fnum);
set_internal_string_var((char_u *)"actual_curbuf", tmp);
o_curbuf = curbuf;
o_curwin = curwin;
save_curbuf = curbuf;
save_curwin = curwin;
curwin = wp;
curbuf = wp->w_buffer;
str = eval_to_string_safe(p, &t, use_sandbox);
curwin = o_curwin;
curbuf = o_curbuf;
curwin = save_curwin;
curbuf = save_curbuf;
do_unlet((char_u *)"g:actual_curbuf", TRUE);
if (str != NULL && *str != 0)
@@ -4740,6 +4743,13 @@ build_stl_str_hl(
sp->userhl = 0;
}
/* We do not want redrawing a stausline, ruler, title, etc. to trigger
* another redraw, it may cause an endless loop. This happens when a
* statusline changes a highlight group. */
must_redraw = save_must_redraw;
curwin->w_redr_type = save_redr_type;
need_highlight_changed = save_highlight_shcnaged;
return width;
}
#endif /* FEAT_STL_OPT */
+38 -4
View File
@@ -990,7 +990,13 @@ ch_close_part(channel_T *channel, ch_part_T part)
if ((part == PART_IN || channel->CH_IN_FD != *fd)
&& (part == PART_OUT || channel->CH_OUT_FD != *fd)
&& (part == PART_ERR || channel->CH_ERR_FD != *fd))
{
#ifdef WIN32
if (channel->ch_named_pipe)
DisconnectNamedPipe((HANDLE)fd);
#endif
fd_close(*fd);
}
}
*fd = INVALID_FD;
@@ -3107,7 +3113,20 @@ channel_wait(channel_T *channel, sock_T fd, int timeout)
if (r && nread > 0)
return CW_READY;
if (r == 0)
return CW_ERROR;
{
DWORD err = GetLastError();
if (err != ERROR_BAD_PIPE && err != ERROR_BROKEN_PIPE)
return CW_ERROR;
if (channel->ch_named_pipe)
{
DisconnectNamedPipe((HANDLE)fd);
ConnectNamedPipe((HANDLE)fd, NULL);
}
else
return CW_ERROR;
}
/* perhaps write some buffer lines */
channel_write_any_lines();
@@ -3695,7 +3714,17 @@ channel_send(
if (part == PART_SOCK)
res = sock_write(fd, (char *)buf, len);
else
{
res = fd_write(fd, (char *)buf, len);
#ifdef WIN32
if (channel->ch_named_pipe && res < 0)
{
DisconnectNamedPipe((HANDLE)fd);
ConnectNamedPipe((HANDLE)fd, NULL);
}
#endif
}
if (res < 0 && (errno == EWOULDBLOCK
#ifdef EAGAIN
|| errno == EAGAIN
@@ -4077,6 +4106,7 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
if (ret > 0 && fd != INVALID_FD && FD_ISSET(fd, rfds))
{
channel_read(channel, part, "channel_select_check");
FD_CLR(fd, rfds);
--ret;
}
}
@@ -4086,6 +4116,7 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
&& FD_ISSET(in_part->ch_fd, wfds))
{
channel_write_input(channel);
FD_CLR(in_part->ch_fd, wfds);
--ret;
}
}
@@ -4874,7 +4905,8 @@ job_free_contents(job_T *job)
}
mch_clear_job(job);
vim_free(job->jv_tty_name);
vim_free(job->jv_tty_in);
vim_free(job->jv_tty_out);
vim_free(job->jv_stoponexit);
free_callback(job->jv_exit_cb, job->jv_exit_partial);
}
@@ -5528,8 +5560,10 @@ job_info(job_T *job, dict_T *dict)
nr = job->jv_proc_info.dwProcessId;
#endif
dict_add_nr_str(dict, "process", nr, NULL);
dict_add_nr_str(dict, "tty", 0L,
job->jv_tty_name != NULL ? job->jv_tty_name : (char_u *)"");
dict_add_nr_str(dict, "tty_in", 0L,
job->jv_tty_in != NULL ? job->jv_tty_in : (char_u *)"");
dict_add_nr_str(dict, "tty_out", 0L,
job->jv_tty_out != NULL ? job->jv_tty_out : (char_u *)"");
dict_add_nr_str(dict, "exitval", job->jv_exitval, NULL);
dict_add_nr_str(dict, "exit_cb", 0L, job->jv_exit_cb);
+1 -1
View File
@@ -843,7 +843,7 @@ static struct fst
{"term_getsize", 1, 1, f_term_getsize},
{"term_getstatus", 1, 1, f_term_getstatus},
{"term_gettitle", 1, 1, f_term_gettitle},
{"term_gettty", 1, 1, f_term_gettty},
{"term_gettty", 1, 2, f_term_gettty},
{"term_list", 0, 0, f_term_list},
{"term_scrape", 2, 2, f_term_scrape},
{"term_sendkeys", 2, 2, f_term_sendkeys},
+8 -2
View File
@@ -5285,7 +5285,11 @@ mch_job_start(char **argv, job_T *job, jobopt_T *options)
&& (!(use_file_for_in || use_null_for_in)
|| !(use_file_for_in || use_null_for_out)
|| !(use_out_for_err || use_file_for_err || use_null_for_err)))
open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name);
{
open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
if (job->jv_tty_out != NULL)
job->jv_tty_in = vim_strsave(job->jv_tty_out);
}
/* TODO: without the channel feature connect the child to /dev/null? */
/* Open pipes for stdin, stdout, stderr. */
@@ -5709,7 +5713,9 @@ mch_create_pty_channel(job_T *job, jobopt_T *options)
int pty_slave_fd = -1;
channel_T *channel;
open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_name);
open_pty(&pty_master_fd, &pty_slave_fd, &job->jv_tty_out);
if (job->jv_tty_out != NULL)
job->jv_tty_in = vim_strsave(job->jv_tty_out);
close(pty_slave_fd);
channel = add_channel();
+2 -1
View File
@@ -3,6 +3,7 @@ void ex_terminal(exarg_T *eap);
void free_terminal(buf_T *buf);
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
int term_job_running(term_T *term);
int term_none_open(term_T *term);
int term_in_normal_mode(void);
void term_enter_job_mode(void);
int send_keys_to_term(term_T *term, int c, int typed);
@@ -16,7 +17,6 @@ int term_update_window(win_T *wp);
int term_is_finished(buf_T *buf);
int term_show_buffer(buf_T *buf);
void term_change_in_curbuf(void);
void term_send_eof(channel_T *ch);
int term_get_attr(buf_T *buf, linenr_T lnum, int col);
char_u *term_get_status_text(term_T *term);
int set_ref_in_term(int copyID);
@@ -35,5 +35,6 @@ void f_term_scrape(typval_T *argvars, typval_T *rettv);
void f_term_sendkeys(typval_T *argvars, typval_T *rettv);
void f_term_start(typval_T *argvars, typval_T *rettv);
void f_term_wait(typval_T *argvars, typval_T *rettv);
void term_send_eof(channel_T *ch);
int terminal_enabled(void);
/* vim: set ft=c : */
+5 -1
View File
@@ -1487,7 +1487,8 @@ struct jobvar_S
PROCESS_INFORMATION jv_proc_info;
HANDLE jv_job_object;
#endif
char_u *jv_tty_name; /* controlling tty, allocated */
char_u *jv_tty_in; /* controlling tty input, allocated */
char_u *jv_tty_out; /* controlling tty output, allocated */
jobstatus_T jv_status;
char_u *jv_stoponexit; /* allocated */
int jv_exitval;
@@ -1655,6 +1656,9 @@ struct channel_S {
/* callback for Netbeans when channel is
* closed */
#ifdef WIN32
int ch_named_pipe; /* using named pipe instead of pty */
#endif
char_u *ch_callback; /* call when any msg is not handled */
partial_T *ch_partial;
char_u *ch_close_cb; /* call when channel is closed */
+107 -86
View File
@@ -7364,6 +7364,8 @@ do_highlight(
int attr;
int id;
int idx;
struct hl_group *item;
struct hl_group item_before;
int dodefault = FALSE;
int doclear = FALSE;
int dolink = FALSE;
@@ -7459,12 +7461,13 @@ do_highlight(
}
from_id = syn_check_group(from_start, (int)(from_end - from_start));
item = &HL_TABLE()[from_id - 1];
if (STRNCMP(to_start, "NONE", 4) == 0)
to_id = 0;
else
to_id = syn_check_group(to_start, (int)(to_end - to_start));
if (from_id > 0 && (!init || HL_TABLE()[from_id - 1].sg_set == 0))
if (from_id > 0 && (!init || item->sg_set == 0))
{
/*
* Don't allow a link when there already is some highlighting
@@ -7476,22 +7479,26 @@ do_highlight(
if (sourcing_name == NULL && !dodefault)
EMSG(_("E414: group has settings, highlight link ignored"));
}
else
else if (item->sg_link != to_id
#ifdef FEAT_EVAL
|| item->sg_scriptID != current_SID
#endif
|| item->sg_cleared)
{
if (!init)
HL_TABLE()[from_id - 1].sg_set |= SG_LINK;
HL_TABLE()[from_id - 1].sg_link = to_id;
item->sg_set |= SG_LINK;
item->sg_link = to_id;
#ifdef FEAT_EVAL
HL_TABLE()[from_id - 1].sg_scriptID = current_SID;
item->sg_scriptID = current_SID;
#endif
HL_TABLE()[from_id - 1].sg_cleared = FALSE;
item->sg_cleared = FALSE;
redraw_all_later(SOME_VALID);
/* Only call highlight_changed() once after multiple changes. */
need_highlight_changed = TRUE;
}
}
/* Only call highlight_changed() once, after sourcing a syntax file */
need_highlight_changed = TRUE;
return;
}
@@ -7578,19 +7585,23 @@ do_highlight(
if (id == 0) /* failed (out of memory) */
return;
idx = id - 1; /* index is ID minus one */
item = &HL_TABLE()[idx];
/* Return if "default" was used and the group already has settings. */
if (dodefault && hl_has_settings(idx, TRUE))
return;
if (STRCMP(HL_TABLE()[idx].sg_name_u, "NORMAL") == 0)
/* Make a copy so we can check if any attribute actually changed. */
item_before = *item;
if (STRCMP(item->sg_name_u, "NORMAL") == 0)
is_normal_group = TRUE;
#ifdef FEAT_GUI_X11
else if (STRCMP(HL_TABLE()[idx].sg_name_u, "MENU") == 0)
else if (STRCMP(item->sg_name_u, "MENU") == 0)
is_menu_group = TRUE;
else if (STRCMP(HL_TABLE()[idx].sg_name_u, "SCROLLBAR") == 0)
else if (STRCMP(item->sg_name_u, "SCROLLBAR") == 0)
is_scrollbar_group = TRUE;
else if (STRCMP(HL_TABLE()[idx].sg_name_u, "TOOLTIP") == 0)
else if (STRCMP(item->sg_name_u, "TOOLTIP") == 0)
is_tooltip_group = TRUE;
#endif
@@ -7599,7 +7610,7 @@ do_highlight(
{
highlight_clear(idx);
if (!doclear)
HL_TABLE()[idx].sg_set = 0;
item->sg_set = 0;
}
if (!doclear)
@@ -7630,10 +7641,10 @@ do_highlight(
if (STRCMP(key, "NONE") == 0)
{
if (!init || HL_TABLE()[idx].sg_set == 0)
if (!init || item->sg_set == 0)
{
if (!init)
HL_TABLE()[idx].sg_set |= SG_TERM+SG_CTERM+SG_GUI;
item->sg_set |= SG_TERM+SG_CTERM+SG_GUI;
highlight_clear(idx);
}
continue;
@@ -7720,31 +7731,31 @@ do_highlight(
break;
if (*key == 'T')
{
if (!init || !(HL_TABLE()[idx].sg_set & SG_TERM))
if (!init || !(item->sg_set & SG_TERM))
{
if (!init)
HL_TABLE()[idx].sg_set |= SG_TERM;
HL_TABLE()[idx].sg_term = attr;
item->sg_set |= SG_TERM;
item->sg_term = attr;
}
}
else if (*key == 'C')
{
if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
if (!init || !(item->sg_set & SG_CTERM))
{
if (!init)
HL_TABLE()[idx].sg_set |= SG_CTERM;
HL_TABLE()[idx].sg_cterm = attr;
HL_TABLE()[idx].sg_cterm_bold = FALSE;
item->sg_set |= SG_CTERM;
item->sg_cterm = attr;
item->sg_cterm_bold = FALSE;
}
}
#if defined(FEAT_GUI) || defined(FEAT_EVAL)
else
{
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
if (!init || !(item->sg_set & SG_GUI))
{
if (!init)
HL_TABLE()[idx].sg_set |= SG_GUI;
HL_TABLE()[idx].sg_gui = attr;
item->sg_set |= SG_GUI;
item->sg_gui = attr;
}
}
#endif
@@ -7753,69 +7764,74 @@ do_highlight(
{
/* in non-GUI fonts are simply ignored */
#ifdef FEAT_GUI
if (!gui.shell_created)
if (item->sg_font_name != NULL
&& STRCMP(item->sg_font_name, arg) == 0)
{
/* Font name didn't change, ignore. */
}
else if (!gui.shell_created)
{
/* GUI not started yet, always accept the name. */
vim_free(HL_TABLE()[idx].sg_font_name);
HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
vim_free(item->sg_font_name);
item->sg_font_name = vim_strsave(arg);
}
else
{
GuiFont temp_sg_font = HL_TABLE()[idx].sg_font;
GuiFont temp_sg_font = item->sg_font;
# ifdef FEAT_XFONTSET
GuiFontset temp_sg_fontset = HL_TABLE()[idx].sg_fontset;
GuiFontset temp_sg_fontset = item->sg_fontset;
# endif
/* First, save the current font/fontset.
* Then try to allocate the font/fontset.
* If the allocation fails, HL_TABLE()[idx].sg_font OR
* If the allocation fails, item->sg_font OR
* sg_fontset will be set to NOFONT or NOFONTSET respectively.
*/
HL_TABLE()[idx].sg_font = NOFONT;
item->sg_font = NOFONT;
# ifdef FEAT_XFONTSET
HL_TABLE()[idx].sg_fontset = NOFONTSET;
item->sg_fontset = NOFONTSET;
# endif
hl_do_font(idx, arg, is_normal_group, is_menu_group,
is_tooltip_group, FALSE);
# ifdef FEAT_XFONTSET
if (HL_TABLE()[idx].sg_fontset != NOFONTSET)
if (item->sg_fontset != NOFONTSET)
{
/* New fontset was accepted. Free the old one, if there
* was one. */
gui_mch_free_fontset(temp_sg_fontset);
vim_free(HL_TABLE()[idx].sg_font_name);
HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
vim_free(item->sg_font_name);
item->sg_font_name = vim_strsave(arg);
}
else
HL_TABLE()[idx].sg_fontset = temp_sg_fontset;
item->sg_fontset = temp_sg_fontset;
# endif
if (HL_TABLE()[idx].sg_font != NOFONT)
if (item->sg_font != NOFONT)
{
/* New font was accepted. Free the old one, if there was
* one. */
gui_mch_free_font(temp_sg_font);
vim_free(HL_TABLE()[idx].sg_font_name);
HL_TABLE()[idx].sg_font_name = vim_strsave(arg);
vim_free(item->sg_font_name);
item->sg_font_name = vim_strsave(arg);
}
else
HL_TABLE()[idx].sg_font = temp_sg_font;
item->sg_font = temp_sg_font;
}
#endif
}
else if (STRCMP(key, "CTERMFG") == 0 || STRCMP(key, "CTERMBG") == 0)
{
if (!init || !(HL_TABLE()[idx].sg_set & SG_CTERM))
if (!init || !(item->sg_set & SG_CTERM))
{
if (!init)
HL_TABLE()[idx].sg_set |= SG_CTERM;
item->sg_set |= SG_CTERM;
/* When setting the foreground color, and previously the "bold"
* flag was set for a light color, reset it now */
if (key[5] == 'F' && HL_TABLE()[idx].sg_cterm_bold)
if (key[5] == 'F' && item->sg_cterm_bold)
{
HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
HL_TABLE()[idx].sg_cterm_bold = FALSE;
item->sg_cterm &= ~HL_BOLD;
item->sg_cterm_bold = FALSE;
}
if (VIM_ISDIGIT(*arg))
@@ -7872,22 +7888,22 @@ do_highlight(
* colors (on some terminals, e.g. "linux") */
if (bold == TRUE)
{
HL_TABLE()[idx].sg_cterm |= HL_BOLD;
HL_TABLE()[idx].sg_cterm_bold = TRUE;
item->sg_cterm |= HL_BOLD;
item->sg_cterm_bold = TRUE;
}
else if (bold == FALSE)
HL_TABLE()[idx].sg_cterm &= ~HL_BOLD;
item->sg_cterm &= ~HL_BOLD;
}
/* Add one to the argument, to avoid zero. Zero is used for
* "NONE", then "color" is -1. */
if (key[5] == 'F')
{
HL_TABLE()[idx].sg_cterm_fg = color + 1;
item->sg_cterm_fg = color + 1;
if (is_normal_group)
{
cterm_normal_fg_color = color + 1;
cterm_normal_fg_bold = (HL_TABLE()[idx].sg_cterm & HL_BOLD);
cterm_normal_fg_bold = (item->sg_cterm & HL_BOLD);
#ifdef FEAT_GUI
/* Don't do this if the GUI is used. */
if (!gui.in_use && !gui.starting)
@@ -7901,7 +7917,7 @@ do_highlight(
}
else
{
HL_TABLE()[idx].sg_cterm_bg = color + 1;
item->sg_cterm_bg = color + 1;
if (is_normal_group)
{
cterm_normal_bg_color = color + 1;
@@ -7941,23 +7957,23 @@ do_highlight(
else if (STRCMP(key, "GUIFG") == 0)
{
#if defined(FEAT_GUI) || defined(FEAT_EVAL)
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
if (!init || !(item->sg_set & SG_GUI))
{
if (!init)
HL_TABLE()[idx].sg_set |= SG_GUI;
item->sg_set |= SG_GUI;
# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
/* In GUI guifg colors are only used when recognized */
i = color_name2handle(arg);
if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT)
{
HL_TABLE()[idx].sg_gui_fg = i;
item->sg_gui_fg = i;
# endif
vim_free(HL_TABLE()[idx].sg_gui_fg_name);
vim_free(item->sg_gui_fg_name);
if (STRCMP(arg, "NONE") != 0)
HL_TABLE()[idx].sg_gui_fg_name = vim_strsave(arg);
item->sg_gui_fg_name = vim_strsave(arg);
else
HL_TABLE()[idx].sg_gui_fg_name = NULL;
item->sg_gui_fg_name = NULL;
# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
# ifdef FEAT_GUI_X11
if (is_menu_group)
@@ -7978,23 +7994,23 @@ do_highlight(
else if (STRCMP(key, "GUIBG") == 0)
{
#if defined(FEAT_GUI) || defined(FEAT_EVAL)
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
if (!init || !(item->sg_set & SG_GUI))
{
if (!init)
HL_TABLE()[idx].sg_set |= SG_GUI;
item->sg_set |= SG_GUI;
# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
/* In GUI guifg colors are only used when recognized */
i = color_name2handle(arg);
if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !USE_24BIT)
{
HL_TABLE()[idx].sg_gui_bg = i;
item->sg_gui_bg = i;
# endif
vim_free(HL_TABLE()[idx].sg_gui_bg_name);
vim_free(item->sg_gui_bg_name);
if (STRCMP(arg, "NONE") != 0)
HL_TABLE()[idx].sg_gui_bg_name = vim_strsave(arg);
item->sg_gui_bg_name = vim_strsave(arg);
else
HL_TABLE()[idx].sg_gui_bg_name = NULL;
item->sg_gui_bg_name = NULL;
# if defined(FEAT_GUI) || defined(FEAT_TERMGUICOLORS)
# ifdef FEAT_GUI_X11
if (is_menu_group)
@@ -8015,22 +8031,22 @@ do_highlight(
else if (STRCMP(key, "GUISP") == 0)
{
#if defined(FEAT_GUI) || defined(FEAT_EVAL)
if (!init || !(HL_TABLE()[idx].sg_set & SG_GUI))
if (!init || !(item->sg_set & SG_GUI))
{
if (!init)
HL_TABLE()[idx].sg_set |= SG_GUI;
item->sg_set |= SG_GUI;
# ifdef FEAT_GUI
i = color_name2handle(arg);
if (i != INVALCOLOR || STRCMP(arg, "NONE") == 0 || !gui.in_use)
{
HL_TABLE()[idx].sg_gui_sp = i;
item->sg_gui_sp = i;
# endif
vim_free(HL_TABLE()[idx].sg_gui_sp_name);
vim_free(item->sg_gui_sp_name);
if (STRCMP(arg, "NONE") != 0)
HL_TABLE()[idx].sg_gui_sp_name = vim_strsave(arg);
item->sg_gui_sp_name = vim_strsave(arg);
else
HL_TABLE()[idx].sg_gui_sp_name = NULL;
item->sg_gui_sp_name = NULL;
# ifdef FEAT_GUI
}
# endif
@@ -8043,7 +8059,7 @@ do_highlight(
char_u *tname;
if (!init)
HL_TABLE()[idx].sg_set |= SG_TERM;
item->sg_set |= SG_TERM;
/*
* The "start" and "stop" arguments can be a literal escape
@@ -8110,13 +8126,13 @@ do_highlight(
p = vim_strsave(buf);
if (key[2] == 'A')
{
vim_free(HL_TABLE()[idx].sg_start);
HL_TABLE()[idx].sg_start = p;
vim_free(item->sg_start);
item->sg_start = p;
}
else
{
vim_free(HL_TABLE()[idx].sg_stop);
HL_TABLE()[idx].sg_stop = p;
vim_free(item->sg_stop);
item->sg_stop = p;
}
}
else
@@ -8125,13 +8141,13 @@ do_highlight(
error = TRUE;
break;
}
HL_TABLE()[idx].sg_cleared = FALSE;
item->sg_cleared = FALSE;
/*
* When highlighting has been given for a group, don't link it.
*/
if (!init || !(HL_TABLE()[idx].sg_set & SG_LINK))
HL_TABLE()[idx].sg_link = 0;
if (!init || !(item->sg_set & SG_LINK))
item->sg_link = 0;
/*
* Continue with next argument.
@@ -8148,10 +8164,10 @@ do_highlight(
{
if (is_normal_group)
{
HL_TABLE()[idx].sg_term_attr = 0;
HL_TABLE()[idx].sg_cterm_attr = 0;
item->sg_term_attr = 0;
item->sg_cterm_attr = 0;
#ifdef FEAT_GUI
HL_TABLE()[idx].sg_gui_attr = 0;
item->sg_gui_attr = 0;
/*
* Need to update all groups, because they might be using "bg"
* and/or "fg", which have been changed now.
@@ -8186,15 +8202,20 @@ do_highlight(
else
set_hl_attr(idx);
#ifdef FEAT_EVAL
HL_TABLE()[idx].sg_scriptID = current_SID;
item->sg_scriptID = current_SID;
#endif
redraw_all_later(NOT_VALID);
}
vim_free(key);
vim_free(arg);
/* Only call highlight_changed() once, after sourcing a syntax file */
need_highlight_changed = TRUE;
/* Only call highlight_changed() once, after a sequence of highlight
* commands, and only if an attribute actually changed. */
if (memcmp(item, &item_before, sizeof(item_before)) != 0)
{
redraw_all_later(NOT_VALID);
need_highlight_changed = TRUE;
}
}
#if defined(EXITFREE) || defined(PROTO)
+139 -33
View File
@@ -38,8 +38,7 @@
* in tl_scrollback are no longer used.
*
* TODO:
* - ":term NONE" does not work on MS-Windows.
* https://github.com/vim/vim/pull/2056
* - patch to use GUI or cterm colors for vterm. Yasuhiro, #2067
* - Redirecting output does not work on MS-Windows.
* - implement term_setsize()
* - add test for giving error for invalid 'termsize' value.
@@ -97,7 +96,8 @@ struct terminal_S {
/* used when tl_job is NULL and only a pty was created */
int tl_tty_fd;
char_u *tl_tty_name;
char_u *tl_tty_in;
char_u *tl_tty_out;
int tl_normal_mode; /* TRUE: Terminal-Normal mode */
int tl_channel_closed;
@@ -245,7 +245,11 @@ setup_job_options(jobopt_T *opt, int rows, int cols)
opt->jo_term_cols = cols;
}
static void
/*
* Start a terminal window and return its buffer.
* Returns NULL when failed.
*/
static buf_T *
term_start(typval_T *argvar, jobopt_T *opt, int forceit)
{
exarg_T split_ea;
@@ -253,9 +257,10 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
term_T *term;
buf_T *old_curbuf = NULL;
int res;
buf_T *newbuf;
if (check_restricted() || check_secure())
return;
return NULL;
if ((opt->jo_set & (JO_IN_IO + JO_OUT_IO + JO_ERR_IO))
== (JO_IN_IO + JO_OUT_IO + JO_ERR_IO)
@@ -263,12 +268,12 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
|| (!(opt->jo_set & JO_ERR_IO) && (opt->jo_set & JO_ERR_BUF)))
{
EMSG(_(e_invarg));
return;
return NULL;
}
term = (term_T *)alloc_clear(sizeof(term_T));
if (term == NULL)
return;
return NULL;
term->tl_dirty_row_end = MAX_ROW;
term->tl_cursor_visible = TRUE;
term->tl_cursor_shape = VTERM_PROP_CURSORSHAPE_BLOCK;
@@ -283,13 +288,13 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
{
no_write_message();
vim_free(term);
return;
return NULL;
}
if (do_ecmd(0, NULL, NULL, &split_ea, ECMD_ONE,
ECMD_HIDE + (forceit ? ECMD_FORCEIT : 0), curwin) == FAIL)
{
vim_free(term);
return;
return NULL;
}
}
else if (opt->jo_hidden)
@@ -303,7 +308,7 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
if (buf == NULL || ml_open(buf) == FAIL)
{
vim_free(term);
return;
return NULL;
}
old_curbuf = curbuf;
--curbuf->b_nwindows;
@@ -333,7 +338,7 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
{
/* split failed */
vim_free(term);
return;
return NULL;
}
}
term->tl_buffer = curbuf;
@@ -419,6 +424,7 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
else
res = term_and_job_init(term, argvar, opt);
newbuf = curbuf;
if (res == OK)
{
/* Get and remember the size we ended up with. Update the pty. */
@@ -453,7 +459,9 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
/* Wiping out the buffer will also close the window and call
* free_terminal(). */
do_buffer(DOBUF_WIPE, DOBUF_FIRST, FORWARD, buf->b_fnum, TRUE);
return NULL;
}
return newbuf;
}
/*
@@ -693,7 +701,7 @@ write_to_term(buf_T *buffer, char_u *msg, channel_T *channel)
gui_macvim_force_flush();
#endif
}
else
else if (buffer->b_nwindows > 0)
redraw_after_callback(TRUE);
}
}
@@ -883,6 +891,20 @@ term_job_running(term_T *term)
|| term->tl_job->jv_channel->ch_keep_open);
}
/*
* Return TRUE if "term" has an active channel and used ":term NONE".
*/
int
term_none_open(term_T *term)
{
/* Also consider the job finished when the channel is closed, to avoid a
* race condition when updating the title. */
return term != NULL
&& term->tl_job != NULL
&& channel_is_open(term->tl_job->jv_channel)
&& term->tl_job->jv_channel->ch_keep_open;
}
/*
* Add the last line of the scrollback buffer to the buffer in the window.
*/
@@ -2384,6 +2406,8 @@ term_get_status_text(term_T *term)
}
else if (term->tl_title != NULL)
txt = term->tl_title;
else if (term_none_open(term))
txt = (char_u *)_("active");
else if (term_job_running(term))
txt = (char_u *)_("running");
else
@@ -2671,14 +2695,32 @@ f_term_gettty(typval_T *argvars, typval_T *rettv)
{
buf_T *buf = term_get_buf(argvars);
char_u *p;
int num = 0;
rettv->v_type = VAR_STRING;
if (buf == NULL)
return;
if (buf->b_term->tl_job != NULL)
p = buf->b_term->tl_job->jv_tty_name;
else
p = buf->b_term->tl_tty_name;
if (argvars[1].v_type != VAR_UNKNOWN)
num = get_tv_number(&argvars[1]);
switch (num)
{
case 0:
if (buf->b_term->tl_job != NULL)
p = buf->b_term->tl_job->jv_tty_out;
else
p = buf->b_term->tl_tty_out;
break;
case 1:
if (buf->b_term->tl_job != NULL)
p = buf->b_term->tl_job->jv_tty_in;
else
p = buf->b_term->tl_tty_in;
break;
default:
EMSG2(_(e_invarg2), get_tv_string(&argvars[1]));
return;
}
if (p != NULL)
rettv->vval.v_string = vim_strsave(p);
}
@@ -2845,11 +2887,13 @@ f_term_sendkeys(typval_T *argvars, typval_T *rettv)
f_term_start(typval_T *argvars, typval_T *rettv)
{
jobopt_T opt;
buf_T *buf;
init_job_options(&opt);
if (argvars[1].v_type != VAR_UNKNOWN
&& get_job_options(&argvars[1], &opt,
JO_TIMEOUT_ALL + JO_STOPONEXIT
+ JO_CALLBACK + JO_OUT_CALLBACK + JO_ERR_CALLBACK
+ JO_EXIT_CB + JO_CLOSE_CALLBACK + JO_OUT_IO,
JO2_TERM_NAME + JO2_TERM_FINISH + JO2_HIDDEN + JO2_TERM_OPENCMD
+ JO2_TERM_COLS + JO2_TERM_ROWS + JO2_VERTICAL + JO2_CURWIN
@@ -2858,10 +2902,10 @@ f_term_start(typval_T *argvars, typval_T *rettv)
if (opt.jo_vertical)
cmdmod.split = WSP_VERT;
term_start(&argvars[0], &opt, FALSE);
buf = term_start(&argvars[0], &opt, FALSE);
if (curbuf->b_term != NULL)
rettv->vval.v_number = curbuf->b_fnum;
if (buf != NULL && buf->b_term != NULL)
rettv->vval.v_number = buf->b_fnum;
}
/*
@@ -2959,11 +3003,13 @@ term_send_eof(channel_T *ch)
#define WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN 1ul
#define WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN 2ull
#define WINPTY_MOUSE_MODE_FORCE 2
void* (*winpty_config_new)(UINT64, void*);
void* (*winpty_open)(void*, void*);
void* (*winpty_spawn_config_new)(UINT64, void*, LPCWSTR, void*, void*, void*);
BOOL (*winpty_spawn)(void*, void*, HANDLE*, HANDLE*, DWORD*, void*);
void (*winpty_config_set_mouse_mode)(void*, int);
void (*winpty_config_set_initial_size)(void*, int, int);
LPCWSTR (*winpty_conin_name)(void*);
LPCWSTR (*winpty_conout_name)(void*);
@@ -2994,7 +3040,10 @@ dyn_winpty_init(int verbose)
{"winpty_conerr_name", (FARPROC*)&winpty_conerr_name},
{"winpty_config_free", (FARPROC*)&winpty_config_free},
{"winpty_config_new", (FARPROC*)&winpty_config_new},
{"winpty_config_set_initial_size", (FARPROC*)&winpty_config_set_initial_size},
{"winpty_config_set_mouse_mode",
(FARPROC*)&winpty_config_set_mouse_mode},
{"winpty_config_set_initial_size",
(FARPROC*)&winpty_config_set_initial_size},
{"winpty_conin_name", (FARPROC*)&winpty_conin_name},
{"winpty_conout_name", (FARPROC*)&winpty_conout_name},
{"winpty_error_free", (FARPROC*)&winpty_error_free},
@@ -3060,7 +3109,6 @@ term_and_job_init(
HANDLE child_thread_handle;
void *winpty_err;
void *spawn_config = NULL;
char buf[MAX_PATH];
garray_T ga;
char_u *cmd;
@@ -3093,13 +3141,14 @@ term_and_job_init(
if (term->tl_winpty_config == NULL)
goto failed;
winpty_config_set_mouse_mode(term->tl_winpty_config,
WINPTY_MOUSE_MODE_FORCE);
winpty_config_set_initial_size(term->tl_winpty_config,
term->tl_cols, term->tl_rows);
term->tl_winpty = winpty_open(term->tl_winpty_config, &winpty_err);
if (term->tl_winpty == NULL)
goto failed;
/* TODO: if the command is "NONE" only create a pty. */
spawn_config = winpty_spawn_config_new(
WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN |
WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN,
@@ -3167,9 +3216,10 @@ term_and_job_init(
job->jv_proc_info.dwProcessId = GetProcessId(child_process_handle);
job->jv_job_object = jo;
job->jv_status = JOB_STARTED;
sprintf(buf, "winpty://%lu",
GetProcessId(winpty_agent_process(term->tl_winpty)));
job->jv_tty_name = vim_strsave((char_u*)buf);
job->jv_tty_in = utf16_to_enc(
(short_u*)winpty_conin_name(term->tl_winpty), NULL);
job->jv_tty_out = utf16_to_enc(
(short_u*)winpty_conout_name(term->tl_winpty), NULL);
++job->jv_refcount;
term->tl_job = job;
@@ -3210,9 +3260,68 @@ failed:
}
static int
create_pty_only(term_T *term, jobopt_T *opt)
create_pty_only(term_T *term, jobopt_T *options)
{
/* TODO: implement this */
HANDLE hPipeIn = INVALID_HANDLE_VALUE;
HANDLE hPipeOut = INVALID_HANDLE_VALUE;
char in_name[80], out_name[80];
channel_T *channel = NULL;
create_vterm(term, term->tl_rows, term->tl_cols);
vim_snprintf(in_name, sizeof(in_name), "\\\\.\\pipe\\vim-%d-in-%d",
GetCurrentProcessId(),
curbuf->b_fnum);
hPipeIn = CreateNamedPipe(in_name, PIPE_ACCESS_OUTBOUND,
PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
PIPE_UNLIMITED_INSTANCES,
0, 0, NMPWAIT_NOWAIT, NULL);
if (hPipeIn == INVALID_HANDLE_VALUE)
goto failed;
vim_snprintf(out_name, sizeof(out_name), "\\\\.\\pipe\\vim-%d-out-%d",
GetCurrentProcessId(),
curbuf->b_fnum);
hPipeOut = CreateNamedPipe(out_name, PIPE_ACCESS_INBOUND,
PIPE_TYPE_MESSAGE | PIPE_NOWAIT,
PIPE_UNLIMITED_INSTANCES,
0, 0, 0, NULL);
if (hPipeOut == INVALID_HANDLE_VALUE)
goto failed;
ConnectNamedPipe(hPipeIn, NULL);
ConnectNamedPipe(hPipeOut, NULL);
term->tl_job = job_alloc();
if (term->tl_job == NULL)
goto failed;
++term->tl_job->jv_refcount;
/* behave like the job is already finished */
term->tl_job->jv_status = JOB_FINISHED;
channel = add_channel();
if (channel == NULL)
goto failed;
term->tl_job->jv_channel = channel;
channel->ch_keep_open = TRUE;
channel->ch_named_pipe = TRUE;
channel_set_pipes(channel,
(sock_T)hPipeIn,
(sock_T)hPipeOut,
(sock_T)hPipeOut);
channel_set_job(channel, term->tl_job, options);
term->tl_job->jv_tty_in = vim_strsave((char_u*)in_name);
term->tl_job->jv_tty_out = vim_strsave((char_u*)out_name);
return OK;
failed:
if (hPipeIn != NULL)
CloseHandle(hPipeIn);
if (hPipeOut != NULL)
CloseHandle(hPipeOut);
return FAIL;
}
@@ -3239,7 +3348,8 @@ term_free_vterm(term_T *term)
static void
term_report_winsize(term_T *term, int rows, int cols)
{
winpty_set_size(term->tl_winpty, cols, rows, NULL);
if (term->tl_winpty)
winpty_set_size(term->tl_winpty, cols, rows, NULL);
}
int
@@ -3280,8 +3390,6 @@ term_and_job_init(
static int
create_pty_only(term_T *term, jobopt_T *opt)
{
int ret;
create_vterm(term, term->tl_rows, term->tl_cols);
term->tl_job = job_alloc();
@@ -3292,9 +3400,7 @@ create_pty_only(term_T *term, jobopt_T *opt)
/* behave like the job is already finished */
term->tl_job->jv_status = JOB_FINISHED;
ret = mch_create_pty_channel(term->tl_job, opt);
return ret;
return mch_create_pty_channel(term->tl_job, opt);
}
/*
+18 -11
View File
@@ -36,11 +36,11 @@ endfunc
func Test_terminal_basic()
let buf = Run_shell_in_terminal({})
if has("unix")
call assert_match("^/dev/", job_info(g:job).tty)
call assert_match("^/dev/", term_gettty(''))
call assert_match('^/dev/', job_info(g:job).tty_out)
call assert_match('^/dev/', term_gettty(''))
else
call assert_match("^winpty://", job_info(g:job).tty)
call assert_match("^winpty://", term_gettty(''))
call assert_match('^\\\\.\\pipe\\', job_info(g:job).tty_out)
call assert_match('^\\\\.\\pipe\\', term_gettty(''))
endif
call assert_equal('t', mode())
call assert_match('%aR[^\n]*running]', execute('ls'))
@@ -544,10 +544,6 @@ func Test_terminal_write_stdin()
endfunc
func Test_terminal_no_cmd()
" Todo: make this work on all systems.
if !has('unix')
return
endif
" Todo: make this work in the GUI
if !has('gui_running')
return
@@ -555,11 +551,20 @@ func Test_terminal_no_cmd()
let buf = term_start('NONE', {})
call assert_notequal(0, buf)
let pty = job_info(term_getjob(buf))['tty']
let pty = job_info(term_getjob(buf))['tty_out']
call assert_notequal('', pty)
call system('echo "look here" > ' . pty)
if has('win32')
silent exe '!cmd /c "echo look here > ' . pty . '"'
else
call system('echo "look here" > ' . pty)
endif
call term_wait(buf)
call assert_equal('look here', term_getline(buf, 1))
let result = term_getline(buf, 1)
if has('win32')
let result = substitute(result, '\s\+$', '', '')
endif
call assert_equal('look here', result)
bwipe!
endfunc
@@ -605,6 +610,7 @@ func Test_terminal_redir_file()
call WaitFor('len(readfile("Xfile")) > 0')
call assert_match('123', readfile('Xfile')[0])
call delete('Xfile')
bwipe
endif
if has('unix')
@@ -613,6 +619,7 @@ func Test_terminal_redir_file()
call WaitFor('len(readfile("Xfile")) > 0')
call assert_match('executing job failed', readfile('Xfile')[0])
call delete('Xfile')
bwipe
call writefile(['one line'], 'Xfile')
let buf = term_start('cat', {'in_io': 'file', 'in_name': 'Xfile'})
+12
View File
@@ -784,6 +784,18 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1077,
/**/
1076,
/**/
1075,
/**/
1074,
/**/
1073,
/**/
1072,
/**/
1071,
/**/