mirror of
https://github.com/macvim-dev/macvim.git
synced 2026-06-11 15:37:29 +02:00
Merge remote-tracking branch 'vim/master'
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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'})
|
||||
|
||||
@@ -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,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user