Merge remote-tracking branch 'vim/master'

This commit is contained in:
Kazuki Sakamoto
2017-07-24 13:56:24 -07:00
12 changed files with 208 additions and 95 deletions
+19 -7
View File
@@ -1,4 +1,4 @@
*terminal.txt* For Vim version 8.0. Last change: 2017 Jul 19
*terminal.txt* For Vim version 8.0. Last change: 2017 Jul 24
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -47,8 +47,9 @@ See option 'termsize' for controlling the size of the terminal window.
(TODO: scrolling when the terminal is larger than the window)
Syntax ~
*:ter* *:terminal*
:terminal[!] [command] Open a new terminal window.
:ter[minal][!] [command] *:ter* *:terminal*
Open a new terminal window.
If [command] is provided run it as a job and connect
the input and output to the terminal.
@@ -79,7 +80,7 @@ The size of the terminal can be in one of three modes:
The minimal size is 2 screen lines with 10 cells.
2. The 'termsize' option is "rows*cols", where "rows" is the minimal number of
screen rows and "cols" is the minial number of cells.
screen rows and "cols" is the minimal number of cells.
3. The 'termsize' option is "rowsXcols" (where the x is upper or lower case).
The terminal size is fixed to the specified number of screen lines and
@@ -101,9 +102,20 @@ can even run Vim in the terminal! That's used for debugging, see below.
MS-Windows ~
On MS-Windows a hidden console is used to run the command in. This should
work well for all kind of commands. Obviously, they must be commands that run
in a terminal, not open their own window.
On MS-Windows winpty is used to make it possible to run all kind of commands.
Obviously, they must be commands that run in a terminal, not open their own
window.
You need the following two files from winpty:
winpty.dll
winpty-agent.exe
You can download them from the following page:
https://github.com/rprichard/winpty
Just put the files somewhere in your PATH.
==============================================================================
2. Remote testing *terminal-testing*
+6 -9
View File
@@ -706,20 +706,17 @@ Or when using MinGW (as one line):
13. Building with Terminal support
==================================
Vim with Terminal support can be built with either MSVC, or MinGW or Cygwin.
Vim with Terminal support can be built with either MSVC, MinGW or Cygwin.
This uses the included libvterm and winpty. No extra header files or
libraries are needed for building.
libraries are needed for building. Just set TERMINAL to yes.
Running Vim with terminal support requires the following two winpty files:
E.g. When using MSVC:
winpty.dll
winpty-agent.dll
nmake -f Make_mvc.mak TERMINAL=yes
You can download them from the following page:
Or when using MinGW (as one line):
https://github.com/rprichard/winpty
Just put the DLL files somewhere in your PATH.
mingw32-make -f Make_mingw.mak TERMINAL=yes
14. Windows 3.1x
+1
View File
@@ -73,6 +73,7 @@ CHANNEL=yes
else
CHANNEL=$(GUI)
endif
# Set to yes to enable terminal support.
TERMINAL=no
+5 -2
View File
@@ -356,6 +356,9 @@ CSCOPE_DEFS = -DFEAT_CSCOPE
!if "$(TERMINAL)" == "yes"
TERMINAL_OBJ = $(OBJDIR)/terminal.obj
TERMINAL_DEFS = -DFEAT_TERMINAL
!if $(MSVC_MAJOR) <= 11
TERMINAL_DEFS = $(TERMINAL_DEFS) /I if_perl_msvc
!endif
TERMINAL_SRC = terminal.c
VTERM_LIB = libvterm/vterm.lib
!endif
@@ -1154,7 +1157,7 @@ all: $(VIM).exe \
$(VIM).exe: $(OUTDIR) $(OBJ) $(GUI_OBJ) $(CUI_OBJ) $(OLE_OBJ) $(OLE_IDL) $(MZSCHEME_OBJ) \
$(LUA_OBJ) $(PERL_OBJ) $(PYTHON_OBJ) $(PYTHON3_OBJ) $(RUBY_OBJ) $(TCL_OBJ) \
$(CSCOPE_OBJ) $(TERMINAL_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) $(XPM_OBJ) \
$(CSCOPE_OBJ) $(TERMINAL_OBJ) $(NETBEANS_OBJ) $(CHANNEL_OBJ) $(XPM_OBJ) $(VTERM_LIB) \
version.c version.h
$(CC) $(CFLAGS) version.c
$(link) $(LINKARGS1) -out:$(VIM).exe $(OBJ) $(GUI_OBJ) $(CUI_OBJ) $(OLE_OBJ) \
@@ -1549,7 +1552,7 @@ proto.h: \
libvterm/vterm.lib :
cd libvterm
$(MAKE) /NOLOGO -f Makefile.msc
$(MAKE) /NOLOGO -f Makefile.msc "MSVC_MAJOR=$(MSVC_MAJOR)"
cd ..
# vim: set noet sw=8 ts=8 sts=0 wm=0 tw=0:
+36 -28
View File
@@ -3634,6 +3634,13 @@ maketitle(void)
#define SPACE_FOR_ARGNR (IOSIZE - 10) /* at least room for " - VIM" */
if (curbuf->b_fname == NULL)
vim_strncpy(buf, (char_u *)_("[No Name]"), SPACE_FOR_FNAME);
#ifdef FEAT_TERMINAL
else if (curbuf->b_term != NULL)
{
vim_strncpy(buf, term_get_status_text(curbuf->b_term),
SPACE_FOR_FNAME);
}
#endif
else
{
p = transstr(gettail(curbuf->b_fname));
@@ -3641,20 +3648,27 @@ maketitle(void)
vim_free(p);
}
switch (bufIsChanged(curbuf)
+ (curbuf->b_p_ro * 2)
+ (!curbuf->b_p_ma * 4))
{
case 1: STRCAT(buf, " +"); break;
case 2: STRCAT(buf, " ="); break;
case 3: STRCAT(buf, " =+"); break;
case 4:
case 6: STRCAT(buf, " -"); break;
case 5:
case 7: STRCAT(buf, " -+"); break;
}
#ifdef FEAT_TERMINAL
if (curbuf->b_term == NULL)
#endif
switch (bufIsChanged(curbuf)
+ (curbuf->b_p_ro * 2)
+ (!curbuf->b_p_ma * 4))
{
case 1: STRCAT(buf, " +"); break;
case 2: STRCAT(buf, " ="); break;
case 3: STRCAT(buf, " =+"); break;
case 4:
case 6: STRCAT(buf, " -"); break;
case 5:
case 7: STRCAT(buf, " -+"); break;
}
if (curbuf->b_fname != NULL)
if (curbuf->b_fname != NULL
#ifdef FEAT_TERMINAL
&& curbuf->b_term == NULL
#endif
)
{
/* Get path of file, replace home dir with ~ */
off = (int)STRLEN(buf);
@@ -3671,18 +3685,8 @@ maketitle(void)
p = gettail_sep(buf + off);
if (p == buf + off)
{
char *txt;
#ifdef FEAT_TERMINAL
if (curbuf->b_term != NULL)
txt = term_job_running(curbuf)
? _("running") : _("finished");
else
#endif
txt = _("help");
/* must be a help or terminal buffer */
vim_strncpy(buf + off, (char_u *)txt,
/* must be a help buffer */
vim_strncpy(buf + off, (char_u *)_("help"),
(size_t)(SPACE_FOR_DIR - off - 1));
}
else
@@ -5680,16 +5684,20 @@ buf_spname(buf_T *buf)
return (char_u *)_(msg_qflist);
}
#endif
#ifdef FEAT_QUICKFIX
/* There is no _file_ when 'buftype' is "nofile", b_sfname
* contains the name as specified by the user */
* contains the name as specified by the user. */
if (bt_nofile(buf))
{
#ifdef FEAT_TERMINAL
if (buf->b_term != NULL)
return term_get_status_text(buf->b_term);
#endif
if (buf->b_sfname != NULL)
return buf->b_sfname;
return (char_u *)_("[Scratch]");
}
#endif
if (buf->b_fname == NULL)
return (char_u *)_("[No Name]");
return NULL;
+2 -2
View File
@@ -2270,8 +2270,6 @@ fontset_ascent(XFontSet fs)
gui_mch_get_color(char_u *name)
{
guicolor_T requested;
XColor available;
Colormap colormap;
/* can't do this when GUI not running */
if (!gui.in_use || name == NULL || *name == NUL)
@@ -2295,6 +2293,8 @@ gui_mch_get_color(char_u *name)
gui_mch_get_rgb_color(int r, int g, int b)
{
char spec[8]; /* space enough to hold "#RRGGBB" */
XColor available;
Colormap colormap;
vim_snprintf(spec, sizeof(spec), "#%.2x%.2x%.2x", r, g, b);
colormap = DefaultColormap(gui.dpy, DefaultScreen(gui.dpy));
+6 -1
View File
@@ -1,3 +1,5 @@
CFLAGS = /DINLINE= /Iinclude
OBJS = \
src\encoding.c \
src\keyboard.c \
@@ -24,7 +26,10 @@ all : vterm.lib
.c.obj :
cl /DINLINE= /Iinclude /Fo$@ /c $<
cl $(CFLAGS) /Fo$@ /c $<
vterm.lib : $(OBJS)
lib /OUT:$@ $(OBJS)
clean:
del $(OBJS) vterm.lib
+18 -16
View File
@@ -1,10 +1,11 @@
#define _XOPEN_SOURCE 500 /* strdup */
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define streq(a,b) (strcmp(a,b)==0)
#define TRUE 1
#define FALSE 0
#include <termios.h>
@@ -60,13 +61,14 @@ static char *helptext[] = {
NULL
};
static bool seticanon(bool icanon, bool echo)
static int seticanon(int icanon, int echo)
{
struct termios termios;
int ret;
tcgetattr(0, &termios);
bool ret = (termios.c_lflag & ICANON);
ret = (termios.c_lflag & ICANON);
if(icanon) termios.c_lflag |= ICANON;
else termios.c_lflag &= ~ICANON;
@@ -84,16 +86,16 @@ static void await_c1(int c1)
int c;
/* await CSI - 8bit or 2byte 7bit form */
bool in_esc = false;
int in_esc = FALSE;
while((c = getchar())) {
if(c == c1)
break;
if(in_esc && c == (char)(c1 - 0x40))
break;
if(!in_esc && c == 0x1b)
in_esc = true;
in_esc = TRUE;
else
in_esc = false;
in_esc = FALSE;
}
}
@@ -121,7 +123,7 @@ static char *read_csi()
static char *read_dcs()
{
unsigned char dcs[32];
bool in_esc = false;
int in_esc = FALSE;
int i;
await_c1(0x90);
@@ -133,10 +135,10 @@ static char *read_dcs()
if(in_esc && c == 0x5c)
break;
if(!in_esc && c == 0x1b)
in_esc = true;
in_esc = TRUE;
else {
dcs[i++] = c;
in_esc = false;
in_esc = FALSE;
}
}
dcs[++i] = 0;
@@ -158,7 +160,7 @@ static void usage(int exitcode)
exit(exitcode);
}
static bool query_dec_mode(int mode)
static int query_dec_mode(int mode)
{
char *s = NULL;
@@ -189,12 +191,12 @@ static bool query_dec_mode(int mode)
free(s);
if(reply_value == 1 || reply_value == 3)
return true;
return TRUE;
if(reply_value == 2 || reply_value == 4)
return false;
return FALSE;
printf("Unrecognised reply to DECRQM: %d\n", reply_value);
return false;
return FALSE;
} while(1);
}
@@ -247,11 +249,11 @@ static int query_rqss_numeric(char *cmd)
} while(1);
}
bool wasicanon;
int wasicanon;
void restoreicanon(void)
{
seticanon(wasicanon, true);
seticanon(wasicanon, TRUE);
}
int main(int argc, char *argv[])
@@ -261,7 +263,7 @@ int main(int argc, char *argv[])
if(argc == 1)
usage(0);
wasicanon = seticanon(false, false);
wasicanon = seticanon(FALSE, FALSE);
atexit(restoreicanon);
while(argi < argc) {
+1 -1
View File
@@ -7602,7 +7602,7 @@ did_set_string_option(
#ifdef FEAT_TERMINAL
/* 'termkey' */
else if (varp == &curwin->w_p_tms)
else if (varp == &curwin->w_p_tk)
{
if (*curwin->w_p_tk != NUL && string_to_key(curwin->w_p_tk, TRUE) == 0)
errmsg = e_invarg;
+1 -1
View File
@@ -4,6 +4,6 @@ void free_terminal(term_T *term);
void write_to_term(buf_T *buffer, char_u *msg, channel_T *channel);
void terminal_loop(void);
void term_job_ended(job_T *job);
int term_job_running(buf_T *buf);
void term_update_window(win_T *wp);
char_u *term_get_status_text(term_T *term);
/* vim: set ft=c : */
+105 -28
View File
@@ -25,7 +25,7 @@
* the terminal emulator.
*
* If the terminal window has keyboard focus, typed keys are converted to the
* terminal encoding and writting to the job over a channel.
* terminal encoding and writing to the job over a channel.
*
* If the job produces output, it is written to the terminal emulator. The
* terminal emulator invokes callbacks when its screen content changes. The
@@ -34,7 +34,6 @@
*
* TODO:
* - do not store terminal buffer in viminfo
* - put terminal title in the statusline
* - Add a scrollback buffer (contains lines to scroll off the top).
* Can use the buf_T lines, store attributes somewhere else?
* - When the job ends:
@@ -43,6 +42,9 @@
* - Free the terminal emulator.
* - Display the scrollback buffer (but with attributes).
* Make the buffer not modifiable, drop attributes when making changes.
* - Need an option or argument to drop the window+buffer right away, to be
* used for a shell or Vim.
* - add a character in :ls output
* - when closing window and job has not ended, make terminal hidden?
* - don't allow exiting Vim when a terminal is still running a job
* - use win_del_lines() to make scroll-up efficient.
@@ -95,6 +97,9 @@ struct terminal_S {
int tl_rows_fixed;
int tl_cols_fixed;
char_u *tl_title; /* NULL or allocated */
char_u *tl_status_text; /* NULL or allocated */
/* Range of screen rows to update. Zero based. */
int tl_dirty_row_start; /* -1 if nothing dirty */
int tl_dirty_row_end; /* row below last one to update */
@@ -271,6 +276,8 @@ free_terminal(term_T *term)
}
term_free(term);
vim_free(term->tl_title);
vim_free(term->tl_status_text);
vim_free(term);
}
@@ -527,6 +534,25 @@ terminal_loop(void)
void
term_job_ended(job_T *job)
{
term_T *term;
int did_one = FALSE;
for (term = first_term; term != NULL; term = term->tl_next)
if (term->tl_job == job)
{
vim_free(term->tl_title);
term->tl_title = NULL;
vim_free(term->tl_status_text);
term->tl_status_text = NULL;
redraw_buf_and_status_later(term->tl_buffer, VALID);
did_one = TRUE;
}
if (did_one)
{
redraw_statuslines();
setcursor();
out_flush();
}
if (curbuf->b_term != NULL && curbuf->b_term->tl_job == job)
maketitle();
}
@@ -534,11 +560,10 @@ term_job_ended(job_T *job)
/*
* Return TRUE if the job for "buf" is still running.
*/
int
term_job_running(buf_T *buf)
static int
term_job_running(term_T *term)
{
return buf->b_term != NULL && buf->b_term->tl_job != NULL
&& buf->b_term->tl_job->jv_status == JOB_STARTED;
return term->tl_job != NULL && term->tl_job->jv_status == JOB_STARTED;
}
static void
@@ -548,22 +573,6 @@ position_cursor(win_T *wp, VTermPos *pos)
wp->w_wcol = MIN(pos->col, MAX(0, wp->w_width - 1));
}
static int handle_damage(VTermRect rect, void *user);
static int handle_moverect(VTermRect dest, VTermRect src, void *user);
static int handle_movecursor(VTermPos pos, VTermPos oldpos, int visible, void *user);
static int handle_resize(int rows, int cols, void *user);
static VTermScreenCallbacks screen_callbacks = {
handle_damage, /* damage */
handle_moverect, /* moverect */
handle_movecursor, /* movecursor */
NULL, /* settermprop */
NULL, /* bell */
handle_resize, /* resize */
NULL, /* sb_pushline */
NULL /* sb_popline */
};
static int
handle_damage(VTermRect rect, void *user)
{
@@ -615,6 +624,30 @@ handle_movecursor(
return 1;
}
static int
handle_settermprop(
VTermProp prop,
VTermValue *value,
void *user)
{
term_T *term = (term_T *)user;
switch (prop)
{
case VTERM_PROP_TITLE:
vim_free(term->tl_title);
term->tl_title = vim_strsave((char_u *)value->string);
vim_free(term->tl_status_text);
term->tl_status_text = NULL;
if (term == curbuf->b_term)
maketitle();
return 1;
default:
break;
}
return 0;
}
/*
* The job running in the terminal resized the terminal.
*/
@@ -639,6 +672,17 @@ handle_resize(int rows, int cols, void *user)
return 1;
}
static VTermScreenCallbacks screen_callbacks = {
handle_damage, /* damage */
handle_moverect, /* moverect */
handle_movecursor, /* movecursor */
handle_settermprop, /* settermprop */
NULL, /* bell */
handle_resize, /* resize */
NULL, /* sb_pushline */
NULL /* sb_popline */
};
/*
* Reverse engineer the RGB value into a cterm color index.
* First color is 1. Return 0 if no match found.
@@ -687,7 +731,7 @@ color2index(VTermColor *color)
else if (red == 128)
{
if (green == 128 && blue == 128)
return 9; /* high intensity bladk */
return 9; /* high intensity black */
}
else if (red == 255)
{
@@ -850,7 +894,10 @@ term_update_window(win_T *wp)
if (c == NUL)
{
ScreenLines[off] = ' ';
ScreenLinesUC[off] = NUL;
#if defined(FEAT_MBYTE)
if (enc_utf8)
ScreenLinesUC[off] = NUL;
#endif
}
else
{
@@ -863,7 +910,8 @@ term_update_window(win_T *wp)
else
{
ScreenLines[off] = c;
ScreenLinesUC[off] = NUL;
if (enc_utf8)
ScreenLinesUC[off] = NUL;
}
#else
ScreenLines[off] = c;
@@ -876,7 +924,10 @@ term_update_window(win_T *wp)
if (cell.width == 2)
{
ScreenLines[off] = NUL;
ScreenLinesUC[off] = NUL;
#if defined(FEAT_MBYTE)
if (enc_utf8)
ScreenLinesUC[off] = NUL;
#endif
++pos.col;
++off;
}
@@ -950,14 +1001,40 @@ create_vterm(term_T *term, int rows, int cols)
vterm_screen_reset(screen, 1 /* hard */);
}
/*
* Return the text to show for the buffer name and status.
*/
char_u *
term_get_status_text(term_T *term)
{
if (term->tl_status_text == NULL)
{
char_u *txt;
size_t len;
if (term->tl_title != NULL)
txt = term->tl_title;
else if (term_job_running(term))
txt = (char_u *)_("running");
else
txt = (char_u *)_("finished");
len = 9 + STRLEN(term->tl_buffer->b_fname) + STRLEN(txt);
term->tl_status_text = alloc(len);
if (term->tl_status_text != NULL)
vim_snprintf((char *)term->tl_status_text, len, "%s [%s]",
term->tl_buffer->b_fname, txt);
}
return term->tl_status_text;
}
# ifdef WIN3264
#define WINPTY_SPAWN_FLAG_AUTO_SHUTDOWN 1ul
#define WINPTY_SPAWN_FLAG_EXIT_AFTER_SHUTDOWN 2ull
void* (*winpty_config_new)(int, void*);
void* (*winpty_config_new)(UINT64, void*);
void* (*winpty_open)(void*, void*);
void* (*winpty_spawn_config_new)(int, void*, LPCWSTR, void*, 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_initial_size)(void*, int, int);
LPCWSTR (*winpty_conin_name)(void*);
+8
View File
@@ -784,6 +784,14 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
769,
/**/
768,
/**/
767,
/**/
766,
/**/
765,
/**/