mirror of
https://github.com/zoriya/vim.git
synced 2025-12-18 13:15:21 +00:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0aed9a2e2e | ||
|
|
d6a7b3e6bb | ||
|
|
dc926dd0dd | ||
|
|
77ac9b5c62 | ||
|
|
93c92eff26 | ||
|
|
fc8bec0be4 | ||
|
|
3eee06e7d4 | ||
|
|
683b796725 | ||
|
|
d21f8b54b2 | ||
|
|
9aa1569128 | ||
|
|
98ebd2bbec | ||
|
|
8e539c51c3 | ||
|
|
f66a2cda2c | ||
|
|
ea5d6fadbb | ||
|
|
97bd5e6527 | ||
|
|
cfce71710b | ||
|
|
82de3c2c03 | ||
|
|
bc906e445c | ||
|
|
f5be7cd016 | ||
|
|
a83e3962ac |
@@ -191,13 +191,16 @@ Section "Vim executables and runtime files"
|
||||
File ${VIMSRC}\vimrun.exe
|
||||
File /oname=tee.exe ${VIMSRC}\teew32.exe
|
||||
File /oname=xxd.exe ${VIMSRC}\xxdw32.exe
|
||||
File ${VIMTOOLS}\diff.exe
|
||||
File ${VIMRT}\vimtutor.bat
|
||||
File ${VIMRT}\README.txt
|
||||
File ..\uninstal.txt
|
||||
File ${VIMRT}\*.vim
|
||||
File ${VIMRT}\rgb.txt
|
||||
|
||||
File ${VIMTOOLS}\diff.exe
|
||||
File ${VIMTOOLS}\winpty32.dll
|
||||
File ${VIMTOOLS}\winpty-agent.exe
|
||||
|
||||
SetOutPath $0\colors
|
||||
File ${VIMRT}\colors\*.*
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@ Special in the terminal window: *CTRL-W_.* *CTRL-W_N*
|
||||
CTRL-W " {reg} paste register {reg} *CTRL-W_quote*
|
||||
Also works with the = register to insert the result of
|
||||
evaluating an expression.
|
||||
CTRL-W CTRL-C ends the job, see below |t_CTRL-W_CTRL-C|
|
||||
|
||||
See option 'termkey' for specifying another key instead of CTRL-W that
|
||||
will work like CTRL-W. However, typing 'termkey' twice sends 'termkey' to
|
||||
@@ -62,16 +63,29 @@ the job. For example:
|
||||
'termkey' . send a CTRL-W to the job in the terminal
|
||||
'termkey' N go to terminal Normal mode, see below
|
||||
'termkey' CTRL-N same as CTRL-W N
|
||||
'termkey' CTRL-C same as |t_CTRL-W_CTRL-C|
|
||||
*t_CTRL-\_CTRL-N*
|
||||
The special key combination CTRL-\ CTRL-N can be used to switch to Normal
|
||||
mode, just like this works in any other mode.
|
||||
*t_CTRL-W_CTRL-C*
|
||||
CTRL-W CTRL-C can be typed to forcefully end the job. On MS-Windows a
|
||||
CTRL-BREAK will also kill the job.
|
||||
|
||||
If you type CTRL-C the effect depends on what the pty has been configured to
|
||||
do. For simple commands this causes a SIGINT to be sent to the job, which
|
||||
would end it. Other commands may ignore the SIGINT or handle the CTRL-C
|
||||
themselves (like Vim does).
|
||||
|
||||
|
||||
Size ~
|
||||
Size and color ~
|
||||
|
||||
See option 'termsize' for controlling the size of the terminal window.
|
||||
(TODO: scrolling when the terminal is larger than the window)
|
||||
|
||||
The terminal uses the 'background' option to decide whether the terminal
|
||||
window will start with a white or black background. The job running in the
|
||||
terminal can change the colors.
|
||||
|
||||
|
||||
Syntax ~
|
||||
|
||||
@@ -115,8 +129,8 @@ Syntax ~
|
||||
If you want to use more options use the |term_start()|
|
||||
function.
|
||||
|
||||
When the buffer associated with the terminal is wiped out the job is killed,
|
||||
similar to calling `job_stop(job, "kill")`
|
||||
When the buffer associated with the terminal is unloaded or wiped out the job
|
||||
is killed, similar to calling `job_stop(job, "kill")`
|
||||
|
||||
By default the 'bufhidden' option of the buffer will be set to "hide".
|
||||
So long as the job is running: If the window is closed the buffer becomes
|
||||
@@ -130,7 +144,7 @@ done, use options like this: >
|
||||
Note that the window will open at an unexpected moment, this will interrupt
|
||||
what you are doing.
|
||||
|
||||
*E947*
|
||||
*E947* *E948*
|
||||
So long as the job is running, the buffer is considered modified and Vim
|
||||
cannot be quit easily, see |abandon|.
|
||||
|
||||
@@ -187,6 +201,8 @@ In Terminal-Normal mode the statusline and window title show "(Terminal)". If
|
||||
the job ends while in Terminal-Normal mode this changes to
|
||||
"(Terminal-finished)".
|
||||
|
||||
It is not possible to enter Insert mode from Terminal-Job mode.
|
||||
|
||||
|
||||
Unix ~
|
||||
|
||||
@@ -226,7 +242,10 @@ You can download them from the following page:
|
||||
|
||||
https://github.com/rprichard/winpty
|
||||
|
||||
Just put the files somewhere in your PATH.
|
||||
Just put the files somewhere in your PATH. You can set the 'winptydll' option
|
||||
to point to the right file, if needed. If you have both the 32-bit and 64-bit
|
||||
version, rename to winpty32.dll and winpty64.dll to match the way Vim was
|
||||
build.
|
||||
|
||||
==============================================================================
|
||||
2. Remote testing *terminal-testing*
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
" These commands create the option window.
|
||||
"
|
||||
" Maintainer: Bram Moolenaar <Bram@vim.org>
|
||||
" Last Change: 2017 Aug 11
|
||||
" Last Change: 2017 Aug 19
|
||||
|
||||
" If there already is an option window, jump to that one.
|
||||
let buf = bufnr('option-window')
|
||||
@@ -510,6 +510,10 @@ if has("terminal")
|
||||
call append("$", "termkey\tkey that precedes Vim commands in a terminal window")
|
||||
call append("$", "\t(local to window)")
|
||||
call <SID>OptionL("tk")
|
||||
if exists("&winptydll")
|
||||
call append("$", "winptydll\tname of the winpty dynamic library")
|
||||
call <SID>OptionG("winptydll", &winptydll)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
|
||||
@@ -2274,6 +2274,7 @@ test_arglist \
|
||||
test_utf8_comparisons \
|
||||
test_viminfo \
|
||||
test_vimscript \
|
||||
test_virtualedit \
|
||||
test_visual \
|
||||
test_window_cmd \
|
||||
test_window_id \
|
||||
|
||||
28
src/buffer.c
28
src/buffer.c
@@ -473,8 +473,8 @@ close_buffer(
|
||||
{
|
||||
if (term_job_running(buf->b_term))
|
||||
{
|
||||
if (wipe_buf)
|
||||
/* Wiping out a terminal buffer kills the job. */
|
||||
if (wipe_buf || unload_buf)
|
||||
/* Wiping out or unloading a terminal buffer kills the job. */
|
||||
free_terminal(buf);
|
||||
else
|
||||
{
|
||||
@@ -1648,7 +1648,7 @@ do_buffer(
|
||||
if (bufIsChanged(curbuf))
|
||||
#endif
|
||||
{
|
||||
EMSG(_(e_nowrtmsg));
|
||||
no_write_message();
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
@@ -1897,6 +1897,28 @@ do_autochdir(void)
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
no_write_message(void)
|
||||
{
|
||||
#ifdef FEAT_TERMINAL
|
||||
if (term_job_running(curbuf->b_term))
|
||||
EMSG(_("E948: Job still running (add ! to end the job)"));
|
||||
else
|
||||
#endif
|
||||
EMSG(_("E37: No write since last change (add ! to override)"));
|
||||
}
|
||||
|
||||
void
|
||||
no_write_message_nobang(void)
|
||||
{
|
||||
#ifdef FEAT_TERMINAL
|
||||
if (term_job_running(curbuf->b_term))
|
||||
EMSG(_("E948: Job still running"));
|
||||
else
|
||||
#endif
|
||||
EMSG(_("E37: No write since last change"));
|
||||
}
|
||||
|
||||
/*
|
||||
* functions for dealing with the buffer list
|
||||
*/
|
||||
|
||||
235
src/channel.c
235
src/channel.c
@@ -1373,7 +1373,7 @@ can_write_buf_line(channel_T *channel)
|
||||
}
|
||||
|
||||
/*
|
||||
* Write any lines to the input channel.
|
||||
* Write any buffer lines to the input channel.
|
||||
*/
|
||||
static void
|
||||
channel_write_in(channel_T *channel)
|
||||
@@ -1445,6 +1445,25 @@ channel_buffer_free(buf_T *buf)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write any lines waiting to be written to "channel".
|
||||
*/
|
||||
static void
|
||||
channel_write_input(channel_T *channel)
|
||||
{
|
||||
chanpart_T *in_part = &channel->ch_part[PART_IN];
|
||||
|
||||
if (in_part->ch_writeque.wq_next != NULL)
|
||||
channel_send(channel, PART_IN, (char_u *)"", 0, "channel_write_input");
|
||||
else if (in_part->ch_bufref.br_buf != NULL)
|
||||
{
|
||||
if (in_part->ch_buf_append)
|
||||
channel_write_new_lines(in_part->ch_bufref.br_buf);
|
||||
else
|
||||
channel_write_in(channel);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write any lines waiting to be written to a channel.
|
||||
*/
|
||||
@@ -1454,17 +1473,7 @@ channel_write_any_lines(void)
|
||||
channel_T *channel;
|
||||
|
||||
for (channel = first_channel; channel != NULL; channel = channel->ch_next)
|
||||
{
|
||||
chanpart_T *in_part = &channel->ch_part[PART_IN];
|
||||
|
||||
if (in_part->ch_bufref.br_buf != NULL)
|
||||
{
|
||||
if (in_part->ch_buf_append)
|
||||
channel_write_new_lines(in_part->ch_bufref.br_buf);
|
||||
else
|
||||
channel_write_in(channel);
|
||||
}
|
||||
}
|
||||
channel_write_input(channel);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2984,7 +2993,9 @@ channel_fill_wfds(int maxfd_arg, fd_set *wfds)
|
||||
{
|
||||
chanpart_T *in_part = &ch->ch_part[PART_IN];
|
||||
|
||||
if (in_part->ch_fd != INVALID_FD && in_part->ch_bufref.br_buf != NULL)
|
||||
if (in_part->ch_fd != INVALID_FD
|
||||
&& (in_part->ch_bufref.br_buf != NULL
|
||||
|| in_part->ch_writeque.wq_next != NULL))
|
||||
{
|
||||
FD_SET((int)in_part->ch_fd, wfds);
|
||||
if ((int)in_part->ch_fd >= maxfd)
|
||||
@@ -3007,7 +3018,9 @@ channel_fill_poll_write(int nfd_in, struct pollfd *fds)
|
||||
{
|
||||
chanpart_T *in_part = &ch->ch_part[PART_IN];
|
||||
|
||||
if (in_part->ch_fd != INVALID_FD && in_part->ch_bufref.br_buf != NULL)
|
||||
if (in_part->ch_fd != INVALID_FD
|
||||
&& (in_part->ch_bufref.br_buf != NULL
|
||||
|| in_part->ch_writeque.wq_next != NULL))
|
||||
{
|
||||
in_part->ch_poll_idx = nfd;
|
||||
fds[nfd].fd = in_part->ch_fd;
|
||||
@@ -3529,6 +3542,29 @@ channel_handle_events(void)
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* Set "channel"/"part" to non-blocking.
|
||||
* Only works for sockets and pipes.
|
||||
*/
|
||||
void
|
||||
channel_set_nonblock(channel_T *channel, ch_part_T part)
|
||||
{
|
||||
chanpart_T *ch_part = &channel->ch_part[part];
|
||||
int fd = ch_part->ch_fd;
|
||||
|
||||
if (fd != INVALID_FD)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
u_long val = 1;
|
||||
|
||||
ioctlsocket(fd, FIONBIO, &val);
|
||||
#else
|
||||
(void)fcntl(fd, F_SETFL, O_NONBLOCK);
|
||||
#endif
|
||||
ch_part->ch_nonblocking = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Write "buf" (NUL terminated string) to "channel"/"part".
|
||||
* When "fun" is not NULL an error message might be given.
|
||||
@@ -3538,14 +3574,16 @@ channel_handle_events(void)
|
||||
channel_send(
|
||||
channel_T *channel,
|
||||
ch_part_T part,
|
||||
char_u *buf,
|
||||
int len,
|
||||
char_u *buf_arg,
|
||||
int len_arg,
|
||||
char *fun)
|
||||
{
|
||||
int res;
|
||||
sock_T fd;
|
||||
chanpart_T *ch_part = &channel->ch_part[part];
|
||||
int did_use_queue = FALSE;
|
||||
|
||||
fd = channel->ch_part[part].ch_fd;
|
||||
fd = ch_part->ch_fd;
|
||||
if (fd == INVALID_FD)
|
||||
{
|
||||
if (!channel->ch_error && fun != NULL)
|
||||
@@ -3561,29 +3599,144 @@ channel_send(
|
||||
{
|
||||
ch_log_lead("SEND ", channel);
|
||||
fprintf(log_fd, "'");
|
||||
ignored = (int)fwrite(buf, len, 1, log_fd);
|
||||
ignored = (int)fwrite(buf_arg, len_arg, 1, log_fd);
|
||||
fprintf(log_fd, "'\n");
|
||||
fflush(log_fd);
|
||||
did_log_msg = TRUE;
|
||||
}
|
||||
|
||||
if (part == PART_SOCK)
|
||||
res = sock_write(fd, (char *)buf, len);
|
||||
else
|
||||
res = fd_write(fd, (char *)buf, len);
|
||||
if (res != len)
|
||||
for (;;)
|
||||
{
|
||||
if (!channel->ch_error && fun != NULL)
|
||||
{
|
||||
ch_error(channel, "%s(): write failed", fun);
|
||||
EMSG2(_("E631: %s(): write failed"), fun);
|
||||
}
|
||||
channel->ch_error = TRUE;
|
||||
return FAIL;
|
||||
}
|
||||
writeq_T *wq = &ch_part->ch_writeque;
|
||||
char_u *buf;
|
||||
int len;
|
||||
|
||||
channel->ch_error = FALSE;
|
||||
return OK;
|
||||
if (wq->wq_next != NULL)
|
||||
{
|
||||
/* first write what was queued */
|
||||
buf = wq->wq_next->wq_ga.ga_data;
|
||||
len = wq->wq_next->wq_ga.ga_len;
|
||||
did_use_queue = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (len_arg == 0)
|
||||
/* nothing to write, called from channel_select_check() */
|
||||
return OK;
|
||||
buf = buf_arg;
|
||||
len = len_arg;
|
||||
}
|
||||
|
||||
if (part == PART_SOCK)
|
||||
res = sock_write(fd, (char *)buf, len);
|
||||
else
|
||||
res = fd_write(fd, (char *)buf, len);
|
||||
if (res < 0 && (errno == EWOULDBLOCK
|
||||
#ifdef EAGAIN
|
||||
|| errno == EAGAIN
|
||||
#endif
|
||||
))
|
||||
res = 0; /* nothing got written */
|
||||
|
||||
if (res >= 0 && ch_part->ch_nonblocking)
|
||||
{
|
||||
writeq_T *entry = wq->wq_next;
|
||||
|
||||
if (did_use_queue)
|
||||
ch_log(channel, "Sent %d bytes now", res);
|
||||
if (res == len)
|
||||
{
|
||||
/* Wrote all the buf[len] bytes. */
|
||||
if (entry != NULL)
|
||||
{
|
||||
/* Remove the entry from the write queue. */
|
||||
ga_clear(&entry->wq_ga);
|
||||
wq->wq_next = entry->wq_next;
|
||||
if (wq->wq_next == NULL)
|
||||
wq->wq_prev = NULL;
|
||||
else
|
||||
wq->wq_next->wq_prev = NULL;
|
||||
continue;
|
||||
}
|
||||
if (did_use_queue)
|
||||
ch_log(channel, "Write queue empty");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Wrote only buf[res] bytes, can't write more now. */
|
||||
if (entry != NULL)
|
||||
{
|
||||
if (res > 0)
|
||||
{
|
||||
/* Remove the bytes that were written. */
|
||||
mch_memmove(entry->wq_ga.ga_data,
|
||||
(char *)entry->wq_ga.ga_data + res,
|
||||
len - res);
|
||||
entry->wq_ga.ga_len -= res;
|
||||
}
|
||||
buf = buf_arg;
|
||||
len = len_arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf += res;
|
||||
len -= res;
|
||||
}
|
||||
ch_log(channel, "Adding %d bytes to the write queue", len);
|
||||
|
||||
/* Append the not written bytes of the argument to the write
|
||||
* buffer. Limit entries to 4000 bytes. */
|
||||
if (wq->wq_prev != NULL
|
||||
&& wq->wq_prev->wq_ga.ga_len + len < 4000)
|
||||
{
|
||||
writeq_T *last = wq->wq_prev;
|
||||
|
||||
/* append to the last entry */
|
||||
if (ga_grow(&last->wq_ga, len) == OK)
|
||||
{
|
||||
mch_memmove((char *)last->wq_ga.ga_data
|
||||
+ last->wq_ga.ga_len,
|
||||
buf, len);
|
||||
last->wq_ga.ga_len += len;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
writeq_T *last = (writeq_T *)alloc((int)sizeof(writeq_T));
|
||||
|
||||
if (last != NULL)
|
||||
{
|
||||
last->wq_prev = wq->wq_prev;
|
||||
last->wq_next = NULL;
|
||||
if (wq->wq_prev == NULL)
|
||||
wq->wq_next = last;
|
||||
else
|
||||
wq->wq_prev->wq_next = last;
|
||||
wq->wq_prev = last;
|
||||
ga_init2(&last->wq_ga, 1, 1000);
|
||||
if (ga_grow(&last->wq_ga, len) == OK)
|
||||
{
|
||||
mch_memmove(last->wq_ga.ga_data, buf, len);
|
||||
last->wq_ga.ga_len = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (res != len)
|
||||
{
|
||||
if (!channel->ch_error && fun != NULL)
|
||||
{
|
||||
ch_error(channel, "%s(): write failed", fun);
|
||||
EMSG2(_("E631: %s(): write failed"), fun);
|
||||
}
|
||||
channel->ch_error = TRUE;
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
channel->ch_error = FALSE;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3795,13 +3948,7 @@ channel_poll_check(int ret_in, void *fds_in)
|
||||
idx = in_part->ch_poll_idx;
|
||||
if (ret > 0 && idx != -1 && (fds[idx].revents & POLLOUT))
|
||||
{
|
||||
if (in_part->ch_buf_append)
|
||||
{
|
||||
if (in_part->ch_bufref.br_buf != NULL)
|
||||
channel_write_new_lines(in_part->ch_bufref.br_buf);
|
||||
}
|
||||
else
|
||||
channel_write_in(channel);
|
||||
channel_write_input(channel);
|
||||
--ret;
|
||||
}
|
||||
}
|
||||
@@ -3873,13 +4020,7 @@ channel_select_check(int ret_in, void *rfds_in, void *wfds_in)
|
||||
if (ret > 0 && in_part->ch_fd != INVALID_FD
|
||||
&& FD_ISSET(in_part->ch_fd, wfds))
|
||||
{
|
||||
if (in_part->ch_buf_append)
|
||||
{
|
||||
if (in_part->ch_bufref.br_buf != NULL)
|
||||
channel_write_new_lines(in_part->ch_bufref.br_buf);
|
||||
}
|
||||
else
|
||||
channel_write_in(channel);
|
||||
channel_write_input(channel);
|
||||
--ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5926,7 +5926,7 @@ f_has(typval_T *argvars, typval_T *rettv)
|
||||
#ifdef FEAT_TERMGUICOLORS
|
||||
"termguicolors",
|
||||
#endif
|
||||
#ifdef FEAT_TERMINAL
|
||||
#if defined(FEAT_TERMINAL) && !defined(WIN3264)
|
||||
"terminal",
|
||||
#endif
|
||||
#ifdef TERMINFO
|
||||
@@ -6133,6 +6133,10 @@ f_has(typval_T *argvars, typval_T *rettv)
|
||||
#ifdef FEAT_NETBEANS_INTG
|
||||
else if (STRICMP(name, "netbeans_enabled") == 0)
|
||||
n = netbeans_active();
|
||||
#endif
|
||||
#if defined(FEAT_TERMINAL) && defined(WIN3264)
|
||||
else if (STRICMP(name, "terminal") == 0)
|
||||
n = terminal_enabled();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -3572,7 +3572,7 @@ getfile(
|
||||
{
|
||||
if (other)
|
||||
--no_wait_return;
|
||||
EMSG(_(e_nowrtmsg));
|
||||
no_write_message();
|
||||
retval = GETFILE_NOT_WRITTEN; /* file has been changed */
|
||||
goto theend;
|
||||
}
|
||||
|
||||
@@ -1934,9 +1934,9 @@ check_changed(buf_T *buf, int flags)
|
||||
}
|
||||
#endif
|
||||
if (flags & CCGD_EXCMD)
|
||||
EMSG(_(e_nowrtmsg));
|
||||
no_write_message();
|
||||
else
|
||||
EMSG(_(e_nowrtmsg_nobang));
|
||||
no_write_message_nobang();
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
@@ -7468,7 +7468,7 @@ ex_win_close(
|
||||
else
|
||||
# endif
|
||||
{
|
||||
EMSG(_(e_nowrtmsg));
|
||||
no_write_message();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1516,8 +1516,6 @@ EXTERN char_u e_notcreate[] INIT(= N_("E482: Can't create file %s"));
|
||||
EXTERN char_u e_notmp[] INIT(= N_("E483: Can't get temp file name"));
|
||||
EXTERN char_u e_notopen[] INIT(= N_("E484: Can't open file %s"));
|
||||
EXTERN char_u e_notread[] INIT(= N_("E485: Can't read file %s"));
|
||||
EXTERN char_u e_nowrtmsg[] INIT(= N_("E37: No write since last change (add ! to override)"));
|
||||
EXTERN char_u e_nowrtmsg_nobang[] INIT(= N_("E37: No write since last change"));
|
||||
EXTERN char_u e_null[] INIT(= N_("E38: Null argument"));
|
||||
#if defined(FEAT_DIGRAPHS) || defined(FEAT_TIMERS)
|
||||
EXTERN char_u e_number_exp[] INIT(= N_("E39: Number expected"));
|
||||
|
||||
35
src/main.c
35
src/main.c
@@ -3597,36 +3597,35 @@ set_progpath(char_u *argv0)
|
||||
{
|
||||
char_u *val = argv0;
|
||||
|
||||
# ifdef PROC_EXE_LINK
|
||||
char buf[MAXPATHL + 1];
|
||||
ssize_t len;
|
||||
|
||||
len = readlink(PROC_EXE_LINK, buf, MAXPATHL);
|
||||
if (len > 0)
|
||||
{
|
||||
buf[len] = NUL;
|
||||
val = (char_u *)buf;
|
||||
}
|
||||
# else
|
||||
# if defined(WIN32)
|
||||
/* A relative path containing a "/" will become invalid when using ":cd",
|
||||
* turn it into a full path.
|
||||
* On MS-Windows "vim" should be expanded to "vim.exe", thus always do
|
||||
* this. */
|
||||
# ifdef WIN32
|
||||
char_u *path = NULL;
|
||||
|
||||
if (mch_can_exe(argv0, &path, FALSE) && path != NULL)
|
||||
val = path;
|
||||
# else
|
||||
char_u buf[MAXPATHL];
|
||||
# else
|
||||
char_u buf[MAXPATHL + 1];
|
||||
# ifdef PROC_EXE_LINK
|
||||
char linkbuf[MAXPATHL + 1];
|
||||
ssize_t len;
|
||||
|
||||
if (!mch_isFullName(argv0))
|
||||
len = readlink(PROC_EXE_LINK, linkbuf, MAXPATHL);
|
||||
if (len > 0)
|
||||
{
|
||||
if (gettail(argv0) != argv0
|
||||
&& vim_FullName(argv0, buf, MAXPATHL, TRUE) != FAIL)
|
||||
val = buf;
|
||||
linkbuf[len] = NUL;
|
||||
val = (char_u *)linkbuf;
|
||||
}
|
||||
# endif
|
||||
|
||||
if (!mch_isFullName(val))
|
||||
{
|
||||
if (gettail(val) != val
|
||||
&& vim_FullName(val, buf, MAXPATHL, TRUE) != FAIL)
|
||||
val = buf;
|
||||
}
|
||||
# endif
|
||||
|
||||
set_vim_var_string(VV_PROGPATH, val, -1);
|
||||
|
||||
@@ -2313,7 +2313,7 @@ msg_scroll_up(void)
|
||||
gui_undraw_cursor();
|
||||
#endif
|
||||
/* scrolling up always works */
|
||||
screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
|
||||
screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
|
||||
|
||||
if (!can_clear((char_u *)" "))
|
||||
{
|
||||
@@ -2905,7 +2905,7 @@ do_more_prompt(int typed_char)
|
||||
}
|
||||
|
||||
if (toscroll == -1 && screen_ins_lines(0, 0, 1,
|
||||
(int)Rows, NULL) == OK)
|
||||
(int)Rows, 0, NULL) == OK)
|
||||
{
|
||||
/* display line at top */
|
||||
(void)disp_sb_line(0, mp);
|
||||
|
||||
11
src/misc2.c
11
src/misc2.c
@@ -605,7 +605,18 @@ check_cursor_col_win(win_T *win)
|
||||
else if (ve_flags == VE_ALL)
|
||||
{
|
||||
if (oldcoladd > win->w_cursor.col)
|
||||
{
|
||||
win->w_cursor.coladd = oldcoladd - win->w_cursor.col;
|
||||
if (win->w_cursor.col < len && win->w_cursor.coladd > 0)
|
||||
{
|
||||
int cs, ce;
|
||||
|
||||
/* check that coladd is not more than the char width */
|
||||
getvcol(win, &win->w_cursor, &cs, NULL, &ce);
|
||||
if (win->w_cursor.coladd > ce - cs)
|
||||
win->w_cursor.coladd = ce - cs;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* avoid weird number when there is a miscalculation or overflow */
|
||||
win->w_cursor.coladd = 0;
|
||||
|
||||
@@ -1163,7 +1163,7 @@ curs_columns(
|
||||
if (extra > 0)
|
||||
win_ins_lines(curwin, 0, extra, FALSE, FALSE);
|
||||
else if (extra < 0)
|
||||
win_del_lines(curwin, 0, -extra, FALSE, FALSE);
|
||||
win_del_lines(curwin, 0, -extra, FALSE, FALSE, 0);
|
||||
}
|
||||
else
|
||||
curwin->w_skipcol = 0;
|
||||
|
||||
@@ -1571,7 +1571,12 @@ do_pending_operator(cmdarg_T *cap, int old_col, int gui_yank)
|
||||
|
||||
oap->start = VIsual;
|
||||
if (VIsual_mode == 'V')
|
||||
{
|
||||
oap->start.col = 0;
|
||||
# ifdef FEAT_VIRTUALEDIT
|
||||
oap->start.coladd = 0;
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -7580,6 +7585,7 @@ nv_gomark(cmdarg_T *cap)
|
||||
if (!virtual_active())
|
||||
curwin->w_cursor.coladd = 0;
|
||||
#endif
|
||||
check_cursor_col();
|
||||
#ifdef FEAT_FOLDING
|
||||
if (cap->oap->op_type == OP_NOP
|
||||
&& pos != NULL
|
||||
|
||||
@@ -3179,6 +3179,7 @@ static struct vimoption options[] =
|
||||
p_term("t_SC", T_CSC)
|
||||
p_term("t_EC", T_CEC)
|
||||
p_term("t_SH", T_CSH)
|
||||
p_term("t_RS", T_CRS)
|
||||
p_term("t_IS", T_CIS)
|
||||
p_term("t_ke", T_KE)
|
||||
p_term("t_ks", T_KS)
|
||||
|
||||
@@ -13,6 +13,8 @@ int do_buffer(int action, int start, int dir, int count, int forceit);
|
||||
void set_curbuf(buf_T *buf, int action);
|
||||
void enter_buffer(buf_T *buf);
|
||||
void do_autochdir(void);
|
||||
void no_write_message(void);
|
||||
void no_write_message_nobang(void);
|
||||
buf_T *buflist_new(char_u *ffname, char_u *sfname, linenr_T lnum, int flags);
|
||||
void free_buf_options(buf_T *buf, int free_p_ff);
|
||||
int buflist_getfile(int n, linenr_T lnum, int options, int forceit);
|
||||
|
||||
@@ -35,6 +35,7 @@ char_u *channel_read_block(channel_T *channel, ch_part_T part, int timeout);
|
||||
void common_channel_read(typval_T *argvars, typval_T *rettv, int raw);
|
||||
channel_T *channel_fd2channel(sock_T fd, ch_part_T *partp);
|
||||
void channel_handle_events(void);
|
||||
void channel_set_nonblock(channel_T *channel, ch_part_T part);
|
||||
int channel_send(channel_T *channel, ch_part_T part, char_u *buf, int len, char *fun);
|
||||
void ch_expr_common(typval_T *argvars, typval_T *rettv, int eval);
|
||||
void ch_raw_common(typval_T *argvars, typval_T *rettv, int eval);
|
||||
|
||||
@@ -45,9 +45,9 @@ void screen_start(void);
|
||||
void windgoto(int row, int col);
|
||||
void setcursor(void);
|
||||
int win_ins_lines(win_T *wp, int row, int line_count, int invalid, int mayclear);
|
||||
int win_del_lines(win_T *wp, int row, int line_count, int invalid, int mayclear);
|
||||
int screen_ins_lines(int off, int row, int line_count, int end, win_T *wp);
|
||||
int screen_del_lines(int off, int row, int line_count, int end, int force, win_T *wp);
|
||||
int win_del_lines(win_T *wp, int row, int line_count, int invalid, int mayclear, int clear_attr);
|
||||
int screen_ins_lines(int off, int row, int line_count, int end, int clear_attr, win_T *wp);
|
||||
int screen_del_lines(int off, int row, int line_count, int end, int force, int attr, win_T *wp);
|
||||
int showmode(void);
|
||||
void unshowmode(int force);
|
||||
void clearmode(void);
|
||||
|
||||
@@ -34,4 +34,5 @@ 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);
|
||||
int terminal_enabled(void);
|
||||
/* vim: set ft=c : */
|
||||
|
||||
@@ -2327,7 +2327,7 @@ win_found:
|
||||
* set b_p_ro flag). */
|
||||
if (!can_abandon(curbuf, forceit))
|
||||
{
|
||||
EMSG(_(e_nowrtmsg));
|
||||
no_write_message();
|
||||
ok = FALSE;
|
||||
}
|
||||
else
|
||||
|
||||
65
src/screen.c
65
src/screen.c
@@ -151,13 +151,13 @@ static void screen_char(unsigned off, int row, int col);
|
||||
static void screen_char_2(unsigned off, int row, int col);
|
||||
#endif
|
||||
static void screenclear2(void);
|
||||
static void lineclear(unsigned off, int width);
|
||||
static void lineclear(unsigned off, int width, int attr);
|
||||
static void lineinvalid(unsigned off, int width);
|
||||
#ifdef FEAT_WINDOWS
|
||||
static void linecopy(int to, int from, win_T *wp);
|
||||
static void redraw_block(int row, int end, win_T *wp);
|
||||
#endif
|
||||
static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del);
|
||||
static int win_do_lines(win_T *wp, int row, int line_count, int mayclear, int del, int clear_attr);
|
||||
static void win_rest_invalid(win_T *wp);
|
||||
static void msg_pos_mode(void);
|
||||
static void recording_mode(int attr);
|
||||
@@ -609,7 +609,8 @@ update_screen(int type_arg)
|
||||
else if (type != CLEAR)
|
||||
{
|
||||
check_for_delay(FALSE);
|
||||
if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, NULL) == FAIL)
|
||||
if (screen_ins_lines(0, 0, msg_scrolled, (int)Rows, 0, NULL)
|
||||
== FAIL)
|
||||
type = CLEAR;
|
||||
FOR_ALL_WINDOWS(wp)
|
||||
{
|
||||
@@ -1537,7 +1538,8 @@ win_update(win_T *wp)
|
||||
if (row > 0)
|
||||
{
|
||||
check_for_delay(FALSE);
|
||||
if (win_del_lines(wp, 0, row, FALSE, wp == firstwin) == OK)
|
||||
if (win_del_lines(wp, 0, row, FALSE, wp == firstwin, 0)
|
||||
== OK)
|
||||
bot_start = wp->w_height - row;
|
||||
else
|
||||
mid_start = 0; /* redraw all lines */
|
||||
@@ -2003,7 +2005,7 @@ win_update(win_T *wp)
|
||||
{
|
||||
check_for_delay(FALSE);
|
||||
if (win_del_lines(wp, row,
|
||||
-xtra_rows, FALSE, FALSE) == FAIL)
|
||||
-xtra_rows, FALSE, FALSE, 0) == FAIL)
|
||||
mod_bot = MAXLNUM;
|
||||
else
|
||||
bot_start = wp->w_height + xtra_rows;
|
||||
@@ -6773,7 +6775,7 @@ win_redr_status_matches(
|
||||
* no room, scroll the screen one line up. */
|
||||
if (cmdline_row == Rows - 1)
|
||||
{
|
||||
screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
|
||||
screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
|
||||
++msg_scrolled;
|
||||
}
|
||||
else
|
||||
@@ -9074,7 +9076,7 @@ screenclear2(void)
|
||||
/* blank out ScreenLines */
|
||||
for (i = 0; i < Rows; ++i)
|
||||
{
|
||||
lineclear(LineOffset[i], (int)Columns);
|
||||
lineclear(LineOffset[i], (int)Columns, 0);
|
||||
LineWraps[i] = FALSE;
|
||||
}
|
||||
|
||||
@@ -9114,7 +9116,7 @@ screenclear2(void)
|
||||
* Clear one line in ScreenLines.
|
||||
*/
|
||||
static void
|
||||
lineclear(unsigned off, int width)
|
||||
lineclear(unsigned off, int width, int attr)
|
||||
{
|
||||
(void)vim_memset(ScreenLines + off, ' ', (size_t)width * sizeof(schar_T));
|
||||
#ifdef FEAT_MBYTE
|
||||
@@ -9122,7 +9124,7 @@ lineclear(unsigned off, int width)
|
||||
(void)vim_memset(ScreenLinesUC + off, 0,
|
||||
(size_t)width * sizeof(u8char_T));
|
||||
#endif
|
||||
(void)vim_memset(ScreenAttrs + off, 0, (size_t)width * sizeof(sattr_T));
|
||||
(void)vim_memset(ScreenAttrs + off, attr, (size_t)width * sizeof(sattr_T));
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -9508,7 +9510,7 @@ win_ins_lines(
|
||||
if (line_count > wp->w_height - row)
|
||||
line_count = wp->w_height - row;
|
||||
|
||||
retval = win_do_lines(wp, row, line_count, mayclear, FALSE);
|
||||
retval = win_do_lines(wp, row, line_count, mayclear, FALSE, 0);
|
||||
if (retval != MAYBE)
|
||||
return retval;
|
||||
|
||||
@@ -9523,7 +9525,7 @@ win_ins_lines(
|
||||
if (wp->w_next != NULL || wp->w_status_height)
|
||||
{
|
||||
if (screen_del_lines(0, W_WINROW(wp) + wp->w_height - line_count,
|
||||
line_count, (int)Rows, FALSE, NULL) == OK)
|
||||
line_count, (int)Rows, FALSE, 0, NULL) == OK)
|
||||
did_delete = TRUE;
|
||||
else if (wp->w_next)
|
||||
return FAIL;
|
||||
@@ -9547,7 +9549,7 @@ win_ins_lines(
|
||||
' ', ' ', 0);
|
||||
}
|
||||
|
||||
if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, NULL)
|
||||
if (screen_ins_lines(0, W_WINROW(wp) + row, line_count, (int)Rows, 0, NULL)
|
||||
== FAIL)
|
||||
{
|
||||
/* deletion will have messed up other windows */
|
||||
@@ -9577,7 +9579,8 @@ win_del_lines(
|
||||
int row,
|
||||
int line_count,
|
||||
int invalid,
|
||||
int mayclear)
|
||||
int mayclear,
|
||||
int clear_attr) /* for clearing lines */
|
||||
{
|
||||
int retval;
|
||||
|
||||
@@ -9587,12 +9590,12 @@ win_del_lines(
|
||||
if (line_count > wp->w_height - row)
|
||||
line_count = wp->w_height - row;
|
||||
|
||||
retval = win_do_lines(wp, row, line_count, mayclear, TRUE);
|
||||
retval = win_do_lines(wp, row, line_count, mayclear, TRUE, clear_attr);
|
||||
if (retval != MAYBE)
|
||||
return retval;
|
||||
|
||||
if (screen_del_lines(0, W_WINROW(wp) + row, line_count,
|
||||
(int)Rows, FALSE, NULL) == FAIL)
|
||||
(int)Rows, FALSE, clear_attr, NULL) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
#ifdef FEAT_WINDOWS
|
||||
@@ -9603,7 +9606,7 @@ win_del_lines(
|
||||
if (wp->w_next || wp->w_status_height || cmdline_row < Rows - 1)
|
||||
{
|
||||
if (screen_ins_lines(0, W_WINROW(wp) + wp->w_height - line_count,
|
||||
line_count, (int)Rows, NULL) == FAIL)
|
||||
line_count, (int)Rows, clear_attr, NULL) == FAIL)
|
||||
{
|
||||
wp->w_redr_status = TRUE;
|
||||
win_rest_invalid(wp->w_next);
|
||||
@@ -9630,7 +9633,8 @@ win_do_lines(
|
||||
int row,
|
||||
int line_count,
|
||||
int mayclear,
|
||||
int del)
|
||||
int del,
|
||||
int clear_attr)
|
||||
{
|
||||
int retval;
|
||||
|
||||
@@ -9694,10 +9698,10 @@ win_do_lines(
|
||||
scroll_region_set(wp, row);
|
||||
if (del)
|
||||
retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
|
||||
wp->w_height - row, FALSE, wp);
|
||||
wp->w_height - row, FALSE, clear_attr, wp);
|
||||
else
|
||||
retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
|
||||
wp->w_height - row, wp);
|
||||
wp->w_height - row, clear_attr, wp);
|
||||
#ifdef FEAT_WINDOWS
|
||||
if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
|
||||
#endif
|
||||
@@ -9771,6 +9775,7 @@ screen_ins_lines(
|
||||
int row,
|
||||
int line_count,
|
||||
int end,
|
||||
int clear_attr,
|
||||
win_T *wp) /* NULL or window to use width from */
|
||||
{
|
||||
int i;
|
||||
@@ -9851,7 +9856,7 @@ screen_ins_lines(
|
||||
*/
|
||||
if (type == USE_T_CD || type == USE_T_CDL ||
|
||||
type == USE_T_CE || type == USE_T_DL)
|
||||
return screen_del_lines(off, row, line_count, end, FALSE, wp);
|
||||
return screen_del_lines(off, row, line_count, end, FALSE, 0, wp);
|
||||
|
||||
/*
|
||||
* If text is retained below the screen, first clear or delete as many
|
||||
@@ -9859,7 +9864,7 @@ screen_ins_lines(
|
||||
* the deleted lines won't later surface during a screen_del_lines.
|
||||
*/
|
||||
if (*T_DB)
|
||||
screen_del_lines(off, end - line_count, line_count, end, FALSE, wp);
|
||||
screen_del_lines(off, end - line_count, line_count, end, FALSE, 0, wp);
|
||||
|
||||
#ifdef FEAT_CLIPBOARD
|
||||
/* Remove a modeless selection when inserting lines halfway the screen
|
||||
@@ -9902,7 +9907,8 @@ screen_ins_lines(
|
||||
linecopy(j + line_count, j, wp);
|
||||
j += line_count;
|
||||
if (can_clear((char_u *)" "))
|
||||
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
|
||||
clear_attr);
|
||||
else
|
||||
lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
LineWraps[j] = FALSE;
|
||||
@@ -9920,7 +9926,7 @@ screen_ins_lines(
|
||||
LineOffset[j + line_count] = temp;
|
||||
LineWraps[j + line_count] = FALSE;
|
||||
if (can_clear((char_u *)" "))
|
||||
lineclear(temp, (int)Columns);
|
||||
lineclear(temp, (int)Columns, clear_attr);
|
||||
else
|
||||
lineinvalid(temp, (int)Columns);
|
||||
}
|
||||
@@ -9928,6 +9934,8 @@ screen_ins_lines(
|
||||
|
||||
screen_stop_highlight();
|
||||
windgoto(cursor_row, 0);
|
||||
if (clear_attr != 0)
|
||||
screen_start_highlight(clear_attr);
|
||||
|
||||
#ifdef FEAT_WINDOWS
|
||||
/* redraw the characters */
|
||||
@@ -9993,6 +10001,7 @@ screen_del_lines(
|
||||
int line_count,
|
||||
int end,
|
||||
int force, /* even when line_count > p_ttyscroll */
|
||||
int clear_attr, /* used for clearing lines */
|
||||
win_T *wp UNUSED) /* NULL or window to use width from */
|
||||
{
|
||||
int j;
|
||||
@@ -10136,7 +10145,8 @@ screen_del_lines(
|
||||
linecopy(j - line_count, j, wp);
|
||||
j -= line_count;
|
||||
if (can_clear((char_u *)" "))
|
||||
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
|
||||
clear_attr);
|
||||
else
|
||||
lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
|
||||
LineWraps[j] = FALSE;
|
||||
@@ -10155,13 +10165,16 @@ screen_del_lines(
|
||||
LineOffset[j - line_count] = temp;
|
||||
LineWraps[j - line_count] = FALSE;
|
||||
if (can_clear((char_u *)" "))
|
||||
lineclear(temp, (int)Columns);
|
||||
lineclear(temp, (int)Columns, clear_attr);
|
||||
else
|
||||
lineinvalid(temp, (int)Columns);
|
||||
}
|
||||
}
|
||||
|
||||
screen_stop_highlight();
|
||||
if (screen_attr != clear_attr)
|
||||
screen_stop_highlight();
|
||||
if (clear_attr != 0)
|
||||
screen_start_highlight(clear_attr);
|
||||
|
||||
#ifdef FEAT_WINDOWS
|
||||
/* redraw the characters */
|
||||
|
||||
@@ -1196,6 +1196,7 @@ typedef struct partial_S partial_T;
|
||||
|
||||
typedef struct jobvar_S job_T;
|
||||
typedef struct readq_S readq_T;
|
||||
typedef struct writeq_S writeq_T;
|
||||
typedef struct jsonq_S jsonq_T;
|
||||
typedef struct cbq_S cbq_T;
|
||||
typedef struct channel_S channel_T;
|
||||
@@ -1512,6 +1513,13 @@ struct readq_S
|
||||
readq_T *rq_prev;
|
||||
};
|
||||
|
||||
struct writeq_S
|
||||
{
|
||||
garray_T wq_ga;
|
||||
writeq_T *wq_next;
|
||||
writeq_T *wq_prev;
|
||||
};
|
||||
|
||||
struct jsonq_S
|
||||
{
|
||||
typval_T *jq_value;
|
||||
@@ -1601,6 +1609,8 @@ typedef struct {
|
||||
#endif
|
||||
int ch_block_write; /* for testing: 0 when not used, -1 when write
|
||||
* does not block, 1 simulate blocking */
|
||||
int ch_nonblocking; /* write() is non-blocking */
|
||||
writeq_T ch_writeque; /* header for write queue */
|
||||
|
||||
cbq_T ch_cb_head; /* dummy node for per-request callbacks */
|
||||
char_u *ch_callback; /* call when a msg is not handled */
|
||||
|
||||
@@ -9999,7 +9999,7 @@ highlight_changed(void)
|
||||
if (ga_grow(&highlight_ga, 28) == FAIL)
|
||||
return FAIL;
|
||||
hlcnt = highlight_ga.ga_len;
|
||||
if (id_S == 0)
|
||||
if (id_S == -1)
|
||||
{
|
||||
/* Make sure id_S is always valid to simplify code below. Use the last
|
||||
* entry. */
|
||||
|
||||
174
src/term.c
174
src/term.c
@@ -114,21 +114,22 @@ char *tgetstr(char *, char **);
|
||||
# else
|
||||
# define LOG_TR(msg)
|
||||
# endif
|
||||
|
||||
# define STATUS_GET 1 /* send request when switching to RAW mode */
|
||||
# define STATUS_SENT 2 /* did send request, waiting for response */
|
||||
# define STATUS_GOT 3 /* received response */
|
||||
|
||||
/* Request Terminal Version status: */
|
||||
# define CRV_GET 1 /* send T_CRV when switched to RAW mode */
|
||||
# define CRV_SENT 2 /* did send T_CRV, waiting for answer */
|
||||
# define CRV_GOT 3 /* received T_CRV response */
|
||||
static int crv_status = CRV_GET;
|
||||
static int crv_status = STATUS_GET;
|
||||
|
||||
/* Request Cursor position report: */
|
||||
# define U7_GET 1 /* send T_U7 when switched to RAW mode */
|
||||
# define U7_SENT 2 /* did send T_U7, waiting for answer */
|
||||
# define U7_GOT 3 /* received T_U7 response */
|
||||
static int u7_status = U7_GET;
|
||||
static int u7_status = STATUS_GET;
|
||||
|
||||
/* Request background color report: */
|
||||
# define RBG_GET 1 /* send T_RBG when switched to RAW mode */
|
||||
# define RBG_SENT 2 /* did send T_RBG, waiting for answer */
|
||||
# define RBG_GOT 3 /* received T_RBG response */
|
||||
static int rbg_status = RBG_GET;
|
||||
static int rbg_status = STATUS_GET;
|
||||
|
||||
/* Request cursor mode report: */
|
||||
static int rcm_status = STATUS_GET;
|
||||
# endif
|
||||
|
||||
/*
|
||||
@@ -160,6 +161,12 @@ static char_u *vim_tgetstr(char *s, char_u **pp);
|
||||
|
||||
static int detected_8bit = FALSE; /* detected 8-bit terminal */
|
||||
|
||||
/* When the cursor shape was detected these values are used:
|
||||
* 1: block, 2: underline, 3: vertical bar
|
||||
* initial_cursor_blink is only valid when initial_cursor_shape is not zero. */
|
||||
static int initial_cursor_shape = 0;
|
||||
static int initial_cursor_blink = FALSE;
|
||||
|
||||
static struct builtin_term builtin_termcaps[] =
|
||||
{
|
||||
|
||||
@@ -819,12 +826,18 @@ static struct builtin_term builtin_termcaps[] =
|
||||
{(int)KS_LE, "\b"},
|
||||
{(int)KS_VI, IF_EB("\033[?25l", ESC_STR "[?25l")},
|
||||
{(int)KS_VE, IF_EB("\033[?25h", ESC_STR "[?25h")},
|
||||
#if 0
|
||||
/* This is currently disabled, because we cannot reliably restore the
|
||||
* cursor style because of what appears to be an xterm bug. */
|
||||
{(int)KS_VE, IF_EB("\033[?25h\033[?12l", ESC_STR "[?25h" ESC_STR "[?12l")},
|
||||
{(int)KS_VS, IF_EB("\033[?12h", ESC_STR "[?12h")},
|
||||
# ifdef TERMINFO
|
||||
{(int)KS_CSH, IF_EB("\033[%p1%d q", ESC_STR "[%p1%d q")},
|
||||
# else
|
||||
{(int)KS_CSH, IF_EB("\033[%d q", ESC_STR "[%d q")},
|
||||
# endif
|
||||
#endif
|
||||
{(int)KS_CRS, IF_EB("\033P$q q\033\\", ESC_STR "P$q q" ESC_STR "\\")},
|
||||
# ifdef TERMINFO
|
||||
{(int)KS_CM, IF_EB("\033[%i%p1%d;%p2%dH",
|
||||
ESC_STR "[%i%p1%d;%p2%dH")},
|
||||
@@ -1803,9 +1816,9 @@ set_termname(char_u *term)
|
||||
* is being used.
|
||||
* Don't do this when the GUI is active, it uses "t_kb" and "t_kD" directly.
|
||||
*/
|
||||
#ifdef FEAT_GUI
|
||||
# ifdef FEAT_GUI
|
||||
if (!gui.in_use)
|
||||
#endif
|
||||
# endif
|
||||
get_stty();
|
||||
#endif
|
||||
|
||||
@@ -1906,8 +1919,8 @@ set_termname(char_u *term)
|
||||
full_screen = TRUE; /* we can use termcap codes from now on */
|
||||
set_term_defaults(); /* use current values as defaults */
|
||||
#ifdef FEAT_TERMRESPONSE
|
||||
LOG_TR("setting crv_status to CRV_GET");
|
||||
crv_status = CRV_GET; /* Get terminal version later */
|
||||
LOG_TR("setting crv_status to STATUS_GET");
|
||||
crv_status = STATUS_GET; /* Get terminal version later */
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -3298,9 +3311,10 @@ settmode(int tmode)
|
||||
/* May need to check for T_CRV response and termcodes, it
|
||||
* doesn't work in Cooked mode, an external program may get
|
||||
* them. */
|
||||
if (tmode != TMODE_RAW && (crv_status == CRV_SENT
|
||||
|| u7_status == U7_SENT
|
||||
|| rbg_status == RBG_SENT))
|
||||
if (tmode != TMODE_RAW && (crv_status == STATUS_SENT
|
||||
|| u7_status == STATUS_SENT
|
||||
|| rbg_status == STATUS_SENT
|
||||
|| rcm_status == STATUS_SENT))
|
||||
(void)vpeekc_nomap();
|
||||
check_for_codes_from_term();
|
||||
}
|
||||
@@ -3347,7 +3361,7 @@ starttermcap(void)
|
||||
may_req_termresponse();
|
||||
/* Immediately check for a response. If t_Co changes, we don't
|
||||
* want to redraw with wrong colors first. */
|
||||
if (crv_status == CRV_SENT)
|
||||
if (crv_status == STATUS_SENT)
|
||||
check_for_codes_from_term();
|
||||
}
|
||||
#endif
|
||||
@@ -3367,8 +3381,10 @@ stoptermcap(void)
|
||||
# endif
|
||||
{
|
||||
/* May need to discard T_CRV, T_U7 or T_RBG response. */
|
||||
if (crv_status == CRV_SENT || u7_status == U7_SENT
|
||||
|| rbg_status == RBG_SENT)
|
||||
if (crv_status == STATUS_SENT
|
||||
|| u7_status == STATUS_SENT
|
||||
|| rbg_status == STATUS_SENT
|
||||
|| rcm_status == STATUS_SENT)
|
||||
{
|
||||
# ifdef UNIX
|
||||
/* Give the terminal a chance to respond. */
|
||||
@@ -3414,14 +3430,14 @@ stoptermcap(void)
|
||||
void
|
||||
may_req_termresponse(void)
|
||||
{
|
||||
if (crv_status == CRV_GET
|
||||
if (crv_status == STATUS_GET
|
||||
&& can_get_termresponse()
|
||||
&& starting == 0
|
||||
&& *T_CRV != NUL)
|
||||
{
|
||||
LOG_TR("Sending CRV");
|
||||
LOG_TR("Sending CRV request");
|
||||
out_str(T_CRV);
|
||||
crv_status = CRV_SENT;
|
||||
crv_status = STATUS_SENT;
|
||||
/* check for the characters now, otherwise they might be eaten by
|
||||
* get_keystroke() */
|
||||
out_flush();
|
||||
@@ -3442,7 +3458,7 @@ may_req_termresponse(void)
|
||||
void
|
||||
may_req_ambiguous_char_width(void)
|
||||
{
|
||||
if (u7_status == U7_GET
|
||||
if (u7_status == STATUS_GET
|
||||
&& can_get_termresponse()
|
||||
&& starting == 0
|
||||
&& *T_U7 != NUL
|
||||
@@ -3457,7 +3473,7 @@ may_req_ambiguous_char_width(void)
|
||||
buf[mb_char2bytes(0x25bd, buf)] = 0;
|
||||
out_str(buf);
|
||||
out_str(T_U7);
|
||||
u7_status = U7_SENT;
|
||||
u7_status = STATUS_SENT;
|
||||
out_flush();
|
||||
|
||||
/* This overwrites a few characters on the screen, a redraw is needed
|
||||
@@ -3477,19 +3493,40 @@ may_req_ambiguous_char_width(void)
|
||||
/*
|
||||
* Similar to requesting the version string: Request the terminal background
|
||||
* color when it is the right moment.
|
||||
* Also request the cursor shape, if possible.
|
||||
*/
|
||||
void
|
||||
may_req_bg_color(void)
|
||||
{
|
||||
if (rbg_status == RBG_GET
|
||||
&& can_get_termresponse()
|
||||
&& starting == 0
|
||||
&& *T_RBG != NUL
|
||||
&& !option_was_set((char_u *)"bg"))
|
||||
int done = FALSE;
|
||||
|
||||
if (can_get_termresponse() && starting == 0)
|
||||
{
|
||||
/* Only request background if t_RB is set and 'background' wasn't
|
||||
* changed. */
|
||||
if (rbg_status == STATUS_GET
|
||||
&& *T_RBG != NUL
|
||||
&& !option_was_set((char_u *)"bg"))
|
||||
{
|
||||
LOG_TR("Sending BG request");
|
||||
out_str(T_RBG);
|
||||
rbg_status = STATUS_SENT;
|
||||
done = TRUE;
|
||||
}
|
||||
|
||||
/* Only request the cursor shape if t_SH and t_RS are set. */
|
||||
if (rcm_status == STATUS_GET
|
||||
&& *T_CSH != NUL
|
||||
&& *T_CRS != NUL)
|
||||
{
|
||||
LOG_TR("Sending cursor shape request");
|
||||
out_str(T_CRS);
|
||||
rcm_status = STATUS_SENT;
|
||||
done = TRUE;
|
||||
}
|
||||
}
|
||||
if (done)
|
||||
{
|
||||
LOG_TR("Sending BG request");
|
||||
out_str(T_RBG);
|
||||
rbg_status = RBG_SENT;
|
||||
/* check for the characters now, otherwise they might be eaten by
|
||||
* get_keystroke() */
|
||||
out_flush();
|
||||
@@ -3676,7 +3713,12 @@ term_cursor_mode(int forced)
|
||||
/* Only do something when redrawing the screen and we can restore the
|
||||
* mode. */
|
||||
if (!full_screen || *T_CEI == NUL)
|
||||
{
|
||||
if (forced && initial_cursor_shape > 0)
|
||||
/* Restore to initial values. */
|
||||
term_cursor_shape(initial_cursor_shape, initial_cursor_blink);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((State & REPLACE) == REPLACE)
|
||||
{
|
||||
@@ -3730,6 +3772,7 @@ term_cursor_blink(int blink)
|
||||
out_str(T_VE);
|
||||
out_flush();
|
||||
}
|
||||
# endif
|
||||
|
||||
/*
|
||||
* "shape" == 1: block, "shape" == 2: underline, "shape" == 3: vertical bar
|
||||
@@ -3743,7 +3786,6 @@ term_cursor_shape(int shape, int blink)
|
||||
out_flush();
|
||||
}
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
@@ -4290,7 +4332,8 @@ check_termcode(
|
||||
{
|
||||
/* Skip over the digits, the final char must
|
||||
* follow. */
|
||||
for (j = slen - 2; j < len && (isdigit(tp[j]) || tp[j] == ';'); ++j)
|
||||
for (j = slen - 2; j < len && (isdigit(tp[j])
|
||||
|| tp[j] == ';'); ++j)
|
||||
;
|
||||
++j;
|
||||
if (len < j) /* got a partial sequence */
|
||||
@@ -4394,7 +4437,7 @@ check_termcode(
|
||||
char *aw = NULL;
|
||||
|
||||
LOG_TR("Received U7 status");
|
||||
u7_status = U7_GOT;
|
||||
u7_status = STATUS_GOT;
|
||||
# ifdef FEAT_AUTOCMD
|
||||
did_cursorhold = TRUE;
|
||||
# endif
|
||||
@@ -4433,8 +4476,8 @@ check_termcode(
|
||||
/* eat it when at least one digit and ending in 'c' */
|
||||
if (*T_CRV != NUL && i > 2 + (tp[0] != CSI) && tp[i] == 'c')
|
||||
{
|
||||
LOG_TR("Received CRV");
|
||||
crv_status = CRV_GOT;
|
||||
LOG_TR("Received CRV response");
|
||||
crv_status = STATUS_GOT;
|
||||
# ifdef FEAT_AUTOCMD
|
||||
did_cursorhold = TRUE;
|
||||
# endif
|
||||
@@ -4566,8 +4609,8 @@ check_termcode(
|
||||
char *newval = (3 * '6' < tp[j+7] + tp[j+12]
|
||||
+ tp[j+17]) ? "light" : "dark";
|
||||
|
||||
LOG_TR("Received RBG");
|
||||
rbg_status = RBG_GOT;
|
||||
LOG_TR("Received RBG response");
|
||||
rbg_status = STATUS_GOT;
|
||||
if (STRCMP(p_bg, newval) != 0)
|
||||
{
|
||||
/* value differs, apply it */
|
||||
@@ -4592,24 +4635,33 @@ check_termcode(
|
||||
}
|
||||
|
||||
/* Check for key code response from xterm:
|
||||
*
|
||||
* {lead}{flag}+r<hex bytes><{tail}
|
||||
*
|
||||
* {lead} can be <Esc>P or DCS
|
||||
* {flag} can be '0' or '1'
|
||||
* {tail} can be Esc>\ or STERM
|
||||
*
|
||||
* Consume any code that starts with "{lead}.+r".
|
||||
* Check for cursor shape response from xterm:
|
||||
* {lead}1$r<number> q{tail}
|
||||
*
|
||||
* {lead} can be <Esc>P or DCS
|
||||
* {tail} can be Esc>\ or STERM
|
||||
*
|
||||
* Consume any code that starts with "{lead}.+r" or "{lead}.$r".
|
||||
*/
|
||||
else if (check_for_codes
|
||||
else if ((check_for_codes || rcm_status == STATUS_SENT)
|
||||
&& ((tp[0] == ESC && len >= 2 && tp[1] == 'P')
|
||||
|| tp[0] == DCS))
|
||||
{
|
||||
j = 1 + (tp[0] == ESC);
|
||||
if (len >= j + 3 && (argp[1] != '+' || argp[2] != 'r'))
|
||||
if (len < j + 3)
|
||||
i = len; /* need more chars */
|
||||
else if ((argp[1] != '+' && argp[1] != '$') || argp[2] != 'r')
|
||||
i = 0; /* no match */
|
||||
else
|
||||
else if (argp[1] == '+')
|
||||
/* key code response */
|
||||
for (i = j; i < len; ++i)
|
||||
{
|
||||
if ((tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')
|
||||
|| tp[i] == STERM)
|
||||
{
|
||||
@@ -4620,6 +4672,32 @@ check_termcode(
|
||||
slen = i + 1 + (tp[i] == ESC);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ((len >= j + 6 && isdigit(argp[3]))
|
||||
&& argp[4] == ' '
|
||||
&& argp[5] == 'q')
|
||||
{
|
||||
/* cursor shape response */
|
||||
i = j + 6;
|
||||
if ((tp[i] == ESC && i + 1 < len && tp[i + 1] == '\\')
|
||||
|| tp[i] == STERM)
|
||||
{
|
||||
int number = argp[3] - '0';
|
||||
|
||||
/* 0, 1 = block blink, 2 = block
|
||||
* 3 = underline blink, 4 = underline
|
||||
* 5 = vertical bar blink, 6 = vertical bar */
|
||||
number = number == 0 ? 1 : number;
|
||||
initial_cursor_shape = (number + 1) / 2;
|
||||
initial_cursor_blink = (number & 1) ? TRUE : FALSE;
|
||||
rcm_status = STATUS_GOT;
|
||||
LOG_TR("Received cursor shape response");
|
||||
|
||||
key_name[0] = (int)KS_EXTRA;
|
||||
key_name[1] = (int)KE_IGNORE;
|
||||
slen = i + 1 + (tp[i] == ESC);
|
||||
}
|
||||
}
|
||||
|
||||
if (i == len)
|
||||
{
|
||||
@@ -5837,7 +5915,7 @@ gather_termleader(void)
|
||||
termleader[len++] = CSI; /* the GUI codes are not in termcodes[] */
|
||||
#endif
|
||||
#ifdef FEAT_TERMRESPONSE
|
||||
if (check_for_codes)
|
||||
if (check_for_codes || *T_CRS != NUL)
|
||||
termleader[len++] = DCS; /* the termcode response starts with DCS
|
||||
in 8-bit mode */
|
||||
#endif
|
||||
|
||||
@@ -41,6 +41,7 @@ enum SpecialKey
|
||||
KS_VE, /* cursor visible */
|
||||
KS_VS, /* cursor very visible */
|
||||
KS_CSH, /* cursor shape */
|
||||
KS_CRS, /* request cursor shape */
|
||||
KS_ME, /* normal mode */
|
||||
KS_MR, /* reverse mode */
|
||||
KS_MD, /* bold mode */
|
||||
@@ -132,6 +133,7 @@ extern char_u *(term_strings[]); /* current terminal strings */
|
||||
#define T_VE (TERM_STR(KS_VE)) /* cursor visible */
|
||||
#define T_VS (TERM_STR(KS_VS)) /* cursor very visible */
|
||||
#define T_CSH (TERM_STR(KS_CSH)) /* cursor shape */
|
||||
#define T_CRS (TERM_STR(KS_CRS)) /* request cursor shape */
|
||||
#define T_ME (TERM_STR(KS_ME)) /* normal mode */
|
||||
#define T_MR (TERM_STR(KS_MR)) /* reverse mode */
|
||||
#define T_MD (TERM_STR(KS_MD)) /* bold mode */
|
||||
|
||||
402
src/terminal.c
402
src/terminal.c
@@ -38,6 +38,7 @@
|
||||
* in tl_scrollback are no longer used.
|
||||
*
|
||||
* TODO:
|
||||
* - help index for winptydll, optwin entry for winptydll
|
||||
* - make [range]terminal pipe [range] lines to the terminal
|
||||
* - implement term_setsize()
|
||||
* - add test for giving error for invalid 'termsize' value.
|
||||
@@ -267,7 +268,7 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
|
||||
/* Create a new buffer in the current window. */
|
||||
if (!can_abandon(curbuf, forceit))
|
||||
{
|
||||
EMSG(_(e_nowrtmsg));
|
||||
no_write_message();
|
||||
vim_free(term);
|
||||
return;
|
||||
}
|
||||
@@ -400,6 +401,10 @@ term_start(typval_T *argvar, jobopt_T *opt, int forceit)
|
||||
vterm_get_size(term->tl_vterm, &term->tl_rows, &term->tl_cols);
|
||||
term_report_winsize(term, term->tl_rows, term->tl_cols);
|
||||
|
||||
/* Make sure we don't get stuck on sending keys to the job, it leads to
|
||||
* a deadlock if the job is waiting for Vim to read. */
|
||||
channel_set_nonblock(term->tl_job->jv_channel, PART_IN);
|
||||
|
||||
if (old_curbuf != NULL)
|
||||
{
|
||||
--curbuf->b_nwindows;
|
||||
@@ -1032,14 +1037,13 @@ term_enter_job_mode()
|
||||
|
||||
/* Remove the terminal contents from the scrollback and the buffer. */
|
||||
gap = &term->tl_scrollback;
|
||||
while (curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled)
|
||||
while (curbuf->b_ml.ml_line_count > term->tl_scrollback_scrolled
|
||||
&& gap->ga_len > 0)
|
||||
{
|
||||
ml_delete(curbuf->b_ml.ml_line_count, FALSE);
|
||||
line = (sb_line_T *)gap->ga_data + gap->ga_len - 1;
|
||||
vim_free(line->sb_cells);
|
||||
--gap->ga_len;
|
||||
if (gap->ga_len == 0)
|
||||
break;
|
||||
}
|
||||
check_cursor();
|
||||
|
||||
@@ -1283,9 +1287,10 @@ may_restore_cursor_props(void)
|
||||
if (did_change_cursor)
|
||||
{
|
||||
did_change_cursor = FALSE;
|
||||
ui_cursor_shape_forced(TRUE);
|
||||
term_cursor_color((char_u *)"");
|
||||
term_cursor_blink(FALSE);
|
||||
/* this will restore the initial cursor style, if possible */
|
||||
ui_cursor_shape_forced(TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1363,9 +1368,6 @@ terminal_loop(void)
|
||||
if (c == K_IGNORE)
|
||||
continue;
|
||||
|
||||
#ifdef UNIX
|
||||
may_send_sigint(c, curbuf->b_term->tl_job->jv_pid, 0);
|
||||
#endif
|
||||
#ifdef WIN3264
|
||||
/* On Windows winpty handles CTRL-C, don't send a CTRL_C_EVENT.
|
||||
* Use CTRL-BREAK to kill the job. */
|
||||
@@ -1401,6 +1403,11 @@ terminal_loop(void)
|
||||
/* Send both keys to the terminal. */
|
||||
send_keys_to_term(curbuf->b_term, prev_c, TRUE);
|
||||
}
|
||||
else if (c == Ctrl_C)
|
||||
{
|
||||
/* "CTRL-W CTRL-C" or 'termkey' CTRL-C: end the job */
|
||||
mch_signal_job(curbuf->b_term->tl_job, (char_u *)"kill");
|
||||
}
|
||||
else if (termkey == 0 && c == '.')
|
||||
{
|
||||
/* "CTRL-W .": send CTRL-W to the job */
|
||||
@@ -1483,6 +1490,169 @@ may_toggle_cursor(term_T *term)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reverse engineer the RGB value into a cterm color index.
|
||||
* First color is 1. Return 0 if no match found.
|
||||
*/
|
||||
static int
|
||||
color2index(VTermColor *color, int fg, int *boldp)
|
||||
{
|
||||
int red = color->red;
|
||||
int blue = color->blue;
|
||||
int green = color->green;
|
||||
|
||||
/* The argument for lookup_color() is for the color_names[] table. */
|
||||
if (red == 0)
|
||||
{
|
||||
if (green == 0)
|
||||
{
|
||||
if (blue == 0)
|
||||
return lookup_color(0, fg, boldp) + 1; /* black */
|
||||
if (blue == 224)
|
||||
return lookup_color(1, fg, boldp) + 1; /* dark blue */
|
||||
}
|
||||
else if (green == 224)
|
||||
{
|
||||
if (blue == 0)
|
||||
return lookup_color(2, fg, boldp) + 1; /* dark green */
|
||||
if (blue == 224)
|
||||
return lookup_color(3, fg, boldp) + 1; /* dark cyan */
|
||||
}
|
||||
}
|
||||
else if (red == 224)
|
||||
{
|
||||
if (green == 0)
|
||||
{
|
||||
if (blue == 0)
|
||||
return lookup_color(4, fg, boldp) + 1; /* dark red */
|
||||
if (blue == 224)
|
||||
return lookup_color(5, fg, boldp) + 1; /* dark magenta */
|
||||
}
|
||||
else if (green == 224)
|
||||
{
|
||||
if (blue == 0)
|
||||
return lookup_color(6, fg, boldp) + 1; /* dark yellow / brown */
|
||||
if (blue == 224)
|
||||
return lookup_color(8, fg, boldp) + 1; /* white / light grey */
|
||||
}
|
||||
}
|
||||
else if (red == 128)
|
||||
{
|
||||
if (green == 128 && blue == 128)
|
||||
return lookup_color(12, fg, boldp) + 1; /* high intensity black / dark grey */
|
||||
}
|
||||
else if (red == 255)
|
||||
{
|
||||
if (green == 64)
|
||||
{
|
||||
if (blue == 64)
|
||||
return lookup_color(20, fg, boldp) + 1; /* light red */
|
||||
if (blue == 255)
|
||||
return lookup_color(22, fg, boldp) + 1; /* light magenta */
|
||||
}
|
||||
else if (green == 255)
|
||||
{
|
||||
if (blue == 64)
|
||||
return lookup_color(24, fg, boldp) + 1; /* yellow */
|
||||
if (blue == 255)
|
||||
return lookup_color(26, fg, boldp) + 1; /* white */
|
||||
}
|
||||
}
|
||||
else if (red == 64)
|
||||
{
|
||||
if (green == 64)
|
||||
{
|
||||
if (blue == 255)
|
||||
return lookup_color(14, fg, boldp) + 1; /* light blue */
|
||||
}
|
||||
else if (green == 255)
|
||||
{
|
||||
if (blue == 64)
|
||||
return lookup_color(16, fg, boldp) + 1; /* light green */
|
||||
if (blue == 255)
|
||||
return lookup_color(18, fg, boldp) + 1; /* light cyan */
|
||||
}
|
||||
}
|
||||
if (t_colors >= 256)
|
||||
{
|
||||
if (red == blue && red == green)
|
||||
{
|
||||
/* 24-color greyscale */
|
||||
static int cutoff[23] = {
|
||||
0x05, 0x10, 0x1B, 0x26, 0x31, 0x3C, 0x47, 0x52,
|
||||
0x5D, 0x68, 0x73, 0x7F, 0x8A, 0x95, 0xA0, 0xAB,
|
||||
0xB6, 0xC1, 0xCC, 0xD7, 0xE2, 0xED, 0xF9};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 23; ++i)
|
||||
if (red < cutoff[i])
|
||||
return i + 233;
|
||||
return 256;
|
||||
}
|
||||
|
||||
/* 216-color cube */
|
||||
return 17 + ((red + 25) / 0x33) * 36
|
||||
+ ((green + 25) / 0x33) * 6
|
||||
+ (blue + 25) / 0x33;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the attributes of a vterm cell into an attribute index.
|
||||
*/
|
||||
static int
|
||||
cell2attr(VTermScreenCellAttrs cellattrs, VTermColor cellfg, VTermColor cellbg)
|
||||
{
|
||||
int attr = 0;
|
||||
|
||||
if (cellattrs.bold)
|
||||
attr |= HL_BOLD;
|
||||
if (cellattrs.underline)
|
||||
attr |= HL_UNDERLINE;
|
||||
if (cellattrs.italic)
|
||||
attr |= HL_ITALIC;
|
||||
if (cellattrs.strike)
|
||||
attr |= HL_STANDOUT;
|
||||
if (cellattrs.reverse)
|
||||
attr |= HL_INVERSE;
|
||||
|
||||
#ifdef FEAT_GUI
|
||||
if (gui.in_use)
|
||||
{
|
||||
guicolor_T fg, bg;
|
||||
|
||||
fg = gui_mch_get_rgb_color(cellfg.red, cellfg.green, cellfg.blue);
|
||||
bg = gui_mch_get_rgb_color(cellbg.red, cellbg.green, cellbg.blue);
|
||||
return get_gui_attr_idx(attr, fg, bg);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef FEAT_TERMGUICOLORS
|
||||
if (p_tgc)
|
||||
{
|
||||
guicolor_T fg, bg;
|
||||
|
||||
fg = gui_get_rgb_color_cmn(cellfg.red, cellfg.green, cellfg.blue);
|
||||
bg = gui_get_rgb_color_cmn(cellbg.red, cellbg.green, cellbg.blue);
|
||||
|
||||
return get_tgc_attr_idx(attr, fg, bg);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int bold = MAYBE;
|
||||
int fg = color2index(&cellfg, TRUE, &bold);
|
||||
int bg = color2index(&cellbg, FALSE, &bold);
|
||||
|
||||
/* with 8 colors set the bold attribute to get a bright foreground */
|
||||
if (bold == TRUE)
|
||||
attr |= HL_BOLD;
|
||||
return get_cterm_attr_idx(attr, fg, bg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
handle_damage(VTermRect rect, void *user)
|
||||
{
|
||||
@@ -1498,18 +1668,32 @@ handle_damage(VTermRect rect, void *user)
|
||||
handle_moverect(VTermRect dest, VTermRect src, void *user)
|
||||
{
|
||||
term_T *term = (term_T *)user;
|
||||
win_T *wp;
|
||||
|
||||
/* Scrolling up is done much more efficiently by deleting lines instead of
|
||||
* redrawing the text. */
|
||||
if (dest.start_col == src.start_col
|
||||
&& dest.end_col == src.end_col
|
||||
&& dest.start_row < src.start_row)
|
||||
{
|
||||
win_T *wp;
|
||||
VTermColor fg, bg;
|
||||
VTermScreenCellAttrs attr;
|
||||
int clear_attr;
|
||||
|
||||
/* Set the color to clear lines with. */
|
||||
vterm_state_get_default_colors(vterm_obtain_state(term->tl_vterm),
|
||||
&fg, &bg);
|
||||
vim_memset(&attr, 0, sizeof(attr));
|
||||
clear_attr = cell2attr(attr, fg, bg);
|
||||
|
||||
FOR_ALL_WINDOWS(wp)
|
||||
{
|
||||
if (wp->w_buffer == term->tl_buffer)
|
||||
/* scrolling up is much more efficient when deleting lines */
|
||||
win_del_lines(wp, dest.start_row,
|
||||
src.start_row - dest.start_row, FALSE, FALSE);
|
||||
src.start_row - dest.start_row, FALSE, FALSE,
|
||||
clear_attr);
|
||||
}
|
||||
}
|
||||
redraw_buf_later(term->tl_buffer, NOT_VALID);
|
||||
return 1;
|
||||
}
|
||||
@@ -1773,169 +1957,6 @@ term_channel_closed(channel_T *ch)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reverse engineer the RGB value into a cterm color index.
|
||||
* First color is 1. Return 0 if no match found.
|
||||
*/
|
||||
static int
|
||||
color2index(VTermColor *color, int fg, int *boldp)
|
||||
{
|
||||
int red = color->red;
|
||||
int blue = color->blue;
|
||||
int green = color->green;
|
||||
|
||||
/* The argument for lookup_color() is for the color_names[] table. */
|
||||
if (red == 0)
|
||||
{
|
||||
if (green == 0)
|
||||
{
|
||||
if (blue == 0)
|
||||
return lookup_color(0, fg, boldp) + 1; /* black */
|
||||
if (blue == 224)
|
||||
return lookup_color(1, fg, boldp) + 1; /* dark blue */
|
||||
}
|
||||
else if (green == 224)
|
||||
{
|
||||
if (blue == 0)
|
||||
return lookup_color(2, fg, boldp) + 1; /* dark green */
|
||||
if (blue == 224)
|
||||
return lookup_color(3, fg, boldp) + 1; /* dark cyan */
|
||||
}
|
||||
}
|
||||
else if (red == 224)
|
||||
{
|
||||
if (green == 0)
|
||||
{
|
||||
if (blue == 0)
|
||||
return lookup_color(4, fg, boldp) + 1; /* dark red */
|
||||
if (blue == 224)
|
||||
return lookup_color(5, fg, boldp) + 1; /* dark magenta */
|
||||
}
|
||||
else if (green == 224)
|
||||
{
|
||||
if (blue == 0)
|
||||
return lookup_color(6, fg, boldp) + 1; /* dark yellow / brown */
|
||||
if (blue == 224)
|
||||
return lookup_color(8, fg, boldp) + 1; /* white / light grey */
|
||||
}
|
||||
}
|
||||
else if (red == 128)
|
||||
{
|
||||
if (green == 128 && blue == 128)
|
||||
return lookup_color(12, fg, boldp) + 1; /* high intensity black / dark grey */
|
||||
}
|
||||
else if (red == 255)
|
||||
{
|
||||
if (green == 64)
|
||||
{
|
||||
if (blue == 64)
|
||||
return lookup_color(20, fg, boldp) + 1; /* light red */
|
||||
if (blue == 255)
|
||||
return lookup_color(22, fg, boldp) + 1; /* light magenta */
|
||||
}
|
||||
else if (green == 255)
|
||||
{
|
||||
if (blue == 64)
|
||||
return lookup_color(24, fg, boldp) + 1; /* yellow */
|
||||
if (blue == 255)
|
||||
return lookup_color(26, fg, boldp) + 1; /* white */
|
||||
}
|
||||
}
|
||||
else if (red == 64)
|
||||
{
|
||||
if (green == 64)
|
||||
{
|
||||
if (blue == 255)
|
||||
return lookup_color(14, fg, boldp) + 1; /* light blue */
|
||||
}
|
||||
else if (green == 255)
|
||||
{
|
||||
if (blue == 64)
|
||||
return lookup_color(16, fg, boldp) + 1; /* light green */
|
||||
if (blue == 255)
|
||||
return lookup_color(18, fg, boldp) + 1; /* light cyan */
|
||||
}
|
||||
}
|
||||
if (t_colors >= 256)
|
||||
{
|
||||
if (red == blue && red == green)
|
||||
{
|
||||
/* 24-color greyscale */
|
||||
static int cutoff[23] = {
|
||||
0x05, 0x10, 0x1B, 0x26, 0x31, 0x3C, 0x47, 0x52,
|
||||
0x5D, 0x68, 0x73, 0x7F, 0x8A, 0x95, 0xA0, 0xAB,
|
||||
0xB6, 0xC1, 0xCC, 0xD7, 0xE2, 0xED, 0xF9};
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 23; ++i)
|
||||
if (red < cutoff[i])
|
||||
return i + 233;
|
||||
return 256;
|
||||
}
|
||||
|
||||
/* 216-color cube */
|
||||
return 17 + ((red + 25) / 0x33) * 36
|
||||
+ ((green + 25) / 0x33) * 6
|
||||
+ (blue + 25) / 0x33;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert the attributes of a vterm cell into an attribute index.
|
||||
*/
|
||||
static int
|
||||
cell2attr(VTermScreenCellAttrs cellattrs, VTermColor cellfg, VTermColor cellbg)
|
||||
{
|
||||
int attr = 0;
|
||||
|
||||
if (cellattrs.bold)
|
||||
attr |= HL_BOLD;
|
||||
if (cellattrs.underline)
|
||||
attr |= HL_UNDERLINE;
|
||||
if (cellattrs.italic)
|
||||
attr |= HL_ITALIC;
|
||||
if (cellattrs.strike)
|
||||
attr |= HL_STANDOUT;
|
||||
if (cellattrs.reverse)
|
||||
attr |= HL_INVERSE;
|
||||
|
||||
#ifdef FEAT_GUI
|
||||
if (gui.in_use)
|
||||
{
|
||||
guicolor_T fg, bg;
|
||||
|
||||
fg = gui_mch_get_rgb_color(cellfg.red, cellfg.green, cellfg.blue);
|
||||
bg = gui_mch_get_rgb_color(cellbg.red, cellbg.green, cellbg.blue);
|
||||
return get_gui_attr_idx(attr, fg, bg);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
#ifdef FEAT_TERMGUICOLORS
|
||||
if (p_tgc)
|
||||
{
|
||||
guicolor_T fg, bg;
|
||||
|
||||
fg = gui_get_rgb_color_cmn(cellfg.red, cellfg.green, cellfg.blue);
|
||||
bg = gui_get_rgb_color_cmn(cellbg.red, cellbg.green, cellbg.blue);
|
||||
|
||||
return get_tgc_attr_idx(attr, fg, bg);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
int bold = MAYBE;
|
||||
int fg = color2index(&cellfg, TRUE, &bold);
|
||||
int bg = color2index(&cellbg, FALSE, &bold);
|
||||
|
||||
/* with 8 colors set the bold attribute to get a bright foreground */
|
||||
if (bold == TRUE)
|
||||
attr |= HL_BOLD;
|
||||
return get_cterm_attr_idx(attr, fg, bg);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Called to update a window that contains an active terminal.
|
||||
* Returns FAIL when there is no terminal running in this window or in
|
||||
@@ -2709,12 +2730,14 @@ f_term_wait(typval_T *argvars, typval_T *rettv UNUSED)
|
||||
}
|
||||
}
|
||||
|
||||
# ifdef WIN3264
|
||||
# if defined(WIN3264) || defined(PROTO)
|
||||
|
||||
/**************************************
|
||||
* 2. MS-Windows implementation.
|
||||
*/
|
||||
|
||||
# ifndef PROTO
|
||||
|
||||
#define WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN 1ul
|
||||
#define WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN 2ull
|
||||
|
||||
@@ -2737,9 +2760,10 @@ HANDLE (*winpty_agent_process)(void*);
|
||||
#define WINPTY_DLL "winpty.dll"
|
||||
|
||||
static HINSTANCE hWinPtyDLL = NULL;
|
||||
# endif
|
||||
|
||||
int
|
||||
dyn_winpty_init(void)
|
||||
static int
|
||||
dyn_winpty_init(int verbose)
|
||||
{
|
||||
int i;
|
||||
static struct
|
||||
@@ -2768,7 +2792,7 @@ dyn_winpty_init(void)
|
||||
|
||||
/* No need to initialize twice. */
|
||||
if (hWinPtyDLL)
|
||||
return 1;
|
||||
return OK;
|
||||
/* Load winpty.dll, prefer using the 'winptydll' option, fall back to just
|
||||
* winpty.dll. */
|
||||
if (*p_winptydll != NUL)
|
||||
@@ -2777,8 +2801,10 @@ dyn_winpty_init(void)
|
||||
hWinPtyDLL = vimLoadLib(WINPTY_DLL);
|
||||
if (!hWinPtyDLL)
|
||||
{
|
||||
EMSG2(_(e_loadlib), *p_winptydll != NUL ? p_winptydll : WINPTY_DLL);
|
||||
return 0;
|
||||
if (verbose)
|
||||
EMSG2(_(e_loadlib), *p_winptydll != NUL ? p_winptydll
|
||||
: (char_u *)WINPTY_DLL);
|
||||
return FAIL;
|
||||
}
|
||||
for (i = 0; winpty_entry[i].name != NULL
|
||||
&& winpty_entry[i].ptr != NULL; ++i)
|
||||
@@ -2786,12 +2812,13 @@ dyn_winpty_init(void)
|
||||
if ((*winpty_entry[i].ptr = (FARPROC)GetProcAddress(hWinPtyDLL,
|
||||
winpty_entry[i].name)) == NULL)
|
||||
{
|
||||
EMSG2(_(e_loadfunc), winpty_entry[i].name);
|
||||
return 0;
|
||||
if (verbose)
|
||||
EMSG2(_(e_loadfunc), winpty_entry[i].name);
|
||||
return FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2813,7 +2840,7 @@ term_and_job_init(term_T *term, int rows, int cols, typval_T *argvar, jobopt_T *
|
||||
garray_T ga;
|
||||
char_u *cmd;
|
||||
|
||||
if (!dyn_winpty_init())
|
||||
if (dyn_winpty_init(TRUE) == FAIL)
|
||||
return FAIL;
|
||||
|
||||
if (argvar->v_type == VAR_STRING)
|
||||
@@ -2977,6 +3004,13 @@ term_report_winsize(term_T *term, int rows, int cols)
|
||||
winpty_set_size(term->tl_winpty, cols, rows, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
terminal_enabled(void)
|
||||
{
|
||||
return dyn_winpty_init(FALSE) == OK;
|
||||
}
|
||||
|
||||
|
||||
# else
|
||||
|
||||
/**************************************
|
||||
|
||||
@@ -55,4 +55,5 @@ source test_taglist.vim
|
||||
source test_timers.vim
|
||||
source test_true_false.vim
|
||||
source test_unlet.vim
|
||||
source test_virtualedit.vim
|
||||
source test_window_cmd.vim
|
||||
|
||||
@@ -1,20 +1,41 @@
|
||||
" Tests for stat functions and checktime
|
||||
|
||||
func Test_existent_file()
|
||||
func CheckFileTime(doSleep)
|
||||
let fname = 'Xtest.tmp'
|
||||
let result = 0
|
||||
|
||||
let ts = localtime()
|
||||
if a:doSleep
|
||||
sleep 1
|
||||
endif
|
||||
let fl = ['Hello World!']
|
||||
call writefile(fl, fname)
|
||||
let tf = getftime(fname)
|
||||
if a:doSleep
|
||||
sleep 1
|
||||
endif
|
||||
let te = localtime()
|
||||
|
||||
call assert_true(ts <= tf && tf <= te)
|
||||
call assert_equal(strlen(fl[0] . "\n"), getfsize(fname))
|
||||
call assert_equal('file', getftype(fname))
|
||||
call assert_equal('rw-', getfperm(fname)[0:2])
|
||||
let time_correct = (ts <= tf && tf <= te)
|
||||
if a:doSleep || time_correct
|
||||
call assert_true(time_correct)
|
||||
call assert_equal(strlen(fl[0] . "\n"), getfsize(fname))
|
||||
call assert_equal('file', getftype(fname))
|
||||
call assert_equal('rw-', getfperm(fname)[0:2])
|
||||
let result = 1
|
||||
endif
|
||||
|
||||
call delete(fname)
|
||||
return result
|
||||
endfunc
|
||||
|
||||
func Test_existent_file()
|
||||
" On some systems the file timestamp is rounded to a multiple of 2 seconds.
|
||||
" We need to sleep to handle that, but that makes the test slow. First try
|
||||
" without the sleep, and if it fails try again with the sleep.
|
||||
if CheckFileTime(0) == 0
|
||||
call CheckFileTime(1)
|
||||
endif
|
||||
endfunc
|
||||
|
||||
func Test_existent_directory()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
" Tests for the terminal window.
|
||||
|
||||
if !exists('*term_start')
|
||||
if !has('terminal')
|
||||
finish
|
||||
endif
|
||||
|
||||
@@ -450,3 +450,23 @@ func Test_terminal_list_args()
|
||||
exe buf . 'bwipe!'
|
||||
call assert_equal("", bufname(buf))
|
||||
endfunction
|
||||
|
||||
func Test_terminal_noblock()
|
||||
let g:buf = term_start(&shell)
|
||||
|
||||
for c in ['a','b','c','d','e','f','g','h','i','j','k']
|
||||
call term_sendkeys(g:buf, 'echo ' . repeat(c, 5000) . "\<cr>")
|
||||
endfor
|
||||
call term_sendkeys(g:buf, "echo done\<cr>")
|
||||
let g:lnum = term_getsize(g:buf)[0] - 1
|
||||
call WaitFor('term_getline(g:buf, g:lnum) =~ "done"', 3000)
|
||||
call assert_match('done', term_getline(g:buf, g:lnum))
|
||||
|
||||
let g:job = term_getjob(g:buf)
|
||||
call Stop_shell_in_terminal(g:buf)
|
||||
call term_wait(g:buf)
|
||||
unlet g:buf
|
||||
unlet g:job
|
||||
unlet g:lnum
|
||||
bwipe
|
||||
endfunc
|
||||
|
||||
31
src/testdir/test_virtualedit.vim
Normal file
31
src/testdir/test_virtualedit.vim
Normal file
@@ -0,0 +1,31 @@
|
||||
" Tests for 'virtualedit'.
|
||||
|
||||
func Test_yank_move_change()
|
||||
split
|
||||
call setline(1, [
|
||||
\ "func foo() error {",
|
||||
\ "\tif n, err := bar();",
|
||||
\ "\terr != nil {",
|
||||
\ "\t\treturn err",
|
||||
\ "\t}",
|
||||
\ "\tn = n * n",
|
||||
\ ])
|
||||
set virtualedit=all
|
||||
set ts=4
|
||||
function! MoveSelectionDown(count) abort
|
||||
normal! m`
|
||||
silent! exe "'<,'>move'>+".a:count
|
||||
norm! ``
|
||||
endfunction
|
||||
|
||||
xmap ]e :<C-U>call MoveSelectionDown(v:count1)<CR>
|
||||
2
|
||||
normal 2gg
|
||||
normal J
|
||||
normal jVj
|
||||
normal ]e
|
||||
normal ce
|
||||
bwipe!
|
||||
set virtualedit=
|
||||
set ts=8
|
||||
endfunc
|
||||
@@ -769,6 +769,46 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
971,
|
||||
/**/
|
||||
970,
|
||||
/**/
|
||||
969,
|
||||
/**/
|
||||
968,
|
||||
/**/
|
||||
967,
|
||||
/**/
|
||||
966,
|
||||
/**/
|
||||
965,
|
||||
/**/
|
||||
964,
|
||||
/**/
|
||||
963,
|
||||
/**/
|
||||
962,
|
||||
/**/
|
||||
961,
|
||||
/**/
|
||||
960,
|
||||
/**/
|
||||
959,
|
||||
/**/
|
||||
958,
|
||||
/**/
|
||||
957,
|
||||
/**/
|
||||
956,
|
||||
/**/
|
||||
955,
|
||||
/**/
|
||||
954,
|
||||
/**/
|
||||
953,
|
||||
/**/
|
||||
952,
|
||||
/**/
|
||||
951,
|
||||
/**/
|
||||
|
||||
Reference in New Issue
Block a user