You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4286 lines
112 KiB
4286 lines
112 KiB
Index: README_vimshell.txt |
|
--- README_vimshell.txt.orig 2011-02-12 14:22:29.000000000 +0100 |
|
+++ README_vimshell.txt 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -0,0 +1,12 @@ |
|
+TESTING |
|
+======= |
|
+ |
|
+shell-read with poll(2) |
|
+shell-read with select(2) - works |
|
+compiling VIM without builtin terminals - only termcap or terminfo - works |
|
+GUI-VIM ohne builtin_terms ? |
|
+ |
|
+DOCUMENTATION |
|
+============= |
|
+ |
|
+See :help vimshell for documentation. |
|
Index: runtime/doc/vimshell.txt |
|
--- runtime/doc/vimshell.txt.orig 2011-02-12 14:22:29.000000000 +0100 |
|
+++ runtime/doc/vimshell.txt 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -0,0 +1,93 @@ |
|
+*vimshell.txt* For Vim version 7.0. Last change: 2006 Sep 2 |
|
+ |
|
+ |
|
+ VIM REFERENCE MANUAL by Bram Moolenaar |
|
+ |
|
+ |
|
+The VIM-Shell *vimshell* |
|
+ |
|
+1. What is VIM-Shell? |
|
+ |
|
+The VIM-shell is a extension for VIM, a very popular programmer's editor for |
|
+many platforms, written by Bram Moolenaar et al. VIM features split windows, |
|
+and this patch makes it possible to start shells in those windows. It is only |
|
+available for POSIX systems like Linux, FreeBSD, OpenBSD, NetBSD and MacOS X. |
|
+I don't think the Windows-VIM needs such a patch, because I think the command |
|
+line there isn't really popular. |
|
+ |
|
+============================================================================== |
|
+2. How to use the VIM-Shell |
|
+ |
|
+2.1 General concept: ":vimshell" |
|
+ |
|
+The whole VIM-Shell functionality is hidden behind one single command: |
|
+:vimshell. |
|
+ |
|
+:vimshell[!] [params] tries to close your active buffer and creates a new one. |
|
+This behaves exactly the same as the :enew command (see :help enew im VIM for |
|
+details). If you have local modifications to your buffer, the command will be |
|
+aborted (but you can override this by adding a ! at the end, in this case the |
|
+active buffer will be dismissed in any case). The window containing this empty |
|
+buffer is then converted to a VIM-Shell. |
|
+ |
|
+:vimshell |
|
+ |
|
+starts a VIM-Shell in your current window. I strongly suggest you open a new |
|
+window before doing that. By default, without any parameters, /bin/sh will be |
|
+spawned. |
|
+ |
|
+:vimshell bash |
|
+ |
|
+When called with parameters, VIM-Shell passes these parameters verbatim to |
|
+execvp when starting a shell. Your current $PATH will be searched for the |
|
+command. |
|
+ |
|
+:vimshell irssi -n anonymous -c vienna.irc.at |
|
+ |
|
+starts the textmode IRC client "irssi" with the abovementioned parameters. |
|
+ |
|
+:vimshell mutt |
|
+ |
|
+Never lose track of your e-mails while working in VIM! |
|
+ |
|
+When you exit such a shell, or the program running in it terminates, the |
|
+buffer will be converted back to a normal, empty VIM-buffer. The window will |
|
+not be closed. |
|
+ |
|
+2.2 Navigation |
|
+ |
|
+When the currently active window is a VIM-Shell, every character entered gets |
|
+routed to the shell, and no mapping expansion takes place. VIM doesn't get any |
|
+notice of the characters that you type in a VIM-Shell. |
|
+ |
|
+The big exception is Ctrl_W, which is passed through to VIM, so you can close |
|
+the VIM-shell (Ctrl_W + c), change to another window, resize the window, etc. |
|
+Key mappings |
|
+ |
|
+Because I feel that opening up a window and then typing :vimshell is a bit |
|
+cumbersome, I suggest you use the following key mappings in your .vimrc: |
|
+ |
|
+ " VIM-Shell |
|
+ " Ctrl_W e opens up a vimshell in a horizontally split window |
|
+ " Ctrl_W E opens up a vimshell in a vertically split window |
|
+ " The shell window will be auto closed after termination |
|
+ nmap <C-W>e :new \| vimshell bash<CR> |
|
+ nmap <C-W>E :vnew \| vimshell bash<CR> |
|
+ |
|
+Just hitting Ctrl_W and e to drop a shell window in your VIM session is |
|
+really, really comfortable :-) |
|
+ |
|
+This is a small introduction on how to use the new features in your |
|
+VIM-Shell-enabled VIM. |
|
+ |
|
+============================================================================== |
|
+3. Authorship |
|
+ |
|
+The VIM-Shell was written in 2004, 2005, 2006 by Thomas Wana <thomas@wana.at>. |
|
+Homepage: http://www.wana.at/vimshell/ |
|
+ |
|
+The VIM-Shell is published under the GNU GPL license (which is compatible with |
|
+the VIM license). The copyright remains by the author. |
|
+ |
|
+============================================================================== |
|
+ vim:tw=78:ts=8:ft=help:norl: |
|
Index: src/Makefile |
|
--- src/Makefile.orig 2010-08-15 14:56:15.000000000 +0200 |
|
+++ src/Makefile 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -1441,6 +1441,8 @@ |
|
auto/pathdef.c \ |
|
popupmnu.c \ |
|
quickfix.c \ |
|
+ vim_shell.c \ |
|
+ terminal.c \ |
|
regexp.c \ |
|
screen.c \ |
|
search.c \ |
|
@@ -1524,6 +1526,8 @@ |
|
objects/pathdef.o \ |
|
objects/popupmnu.o \ |
|
objects/quickfix.o \ |
|
+ objects/vim_shell.o \ |
|
+ objects/terminal.o \ |
|
objects/regexp.o \ |
|
objects/screen.o \ |
|
objects/search.o \ |
|
@@ -2609,6 +2613,12 @@ |
|
objects/quickfix.o: quickfix.c |
|
$(CCC) -o $@ quickfix.c |
|
|
|
+objects/vim_shell.o: vim_shell.c |
|
+ $(CCC) -o $@ vim_shell.c |
|
+ |
|
+objects/terminal.o: terminal.c |
|
+ $(CCC) -o $@ terminal.c |
|
+ |
|
objects/regexp.o: regexp.c |
|
$(CCC) -o $@ regexp.c |
|
|
|
@@ -2883,6 +2893,8 @@ |
|
auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \ |
|
regexp.h gui.h gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h \ |
|
globals.h farsi.h arabic.h |
|
+objects/terminal.o: terminal.c vim_shell.h auto/osdef.h |
|
+objects/vim_shell.o: vim_shell.c vim_shell.h auto/osdef.h |
|
objects/regexp.o: regexp.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \ |
|
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \ |
|
gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \ |
|
Index: src/buffer.c |
|
--- src/buffer.c.orig 2010-08-13 11:14:35.000000000 +0200 |
|
+++ src/buffer.c 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -581,6 +581,17 @@ |
|
#ifdef FEAT_TCL |
|
tcl_buffer_free(buf); |
|
#endif |
|
+#ifdef FEAT_VIMSHELL |
|
+ if(buf->is_shell!=0) |
|
+ { |
|
+ /* |
|
+ * It is guaranteed that this buffer isn't connected to a |
|
+ * window anymore, or else we'd not come up here. So we can |
|
+ * savely scrap the shell here. |
|
+ */ |
|
+ vim_shell_delete(buf); |
|
+ } |
|
+#endif |
|
ml_close(buf, TRUE); /* close and delete the memline/memfile */ |
|
buf->b_ml.ml_line_count = 0; /* no lines in buffer */ |
|
if ((flags & BFA_KEEP_UNDO) == 0) |
|
Index: src/colines.c |
|
--- src/colines.c.orig 2011-02-12 14:22:29.000000000 +0100 |
|
+++ src/colines.c 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -0,0 +1,39 @@ |
|
+#include <stdio.h> |
|
+#include <unistd.h> |
|
+#include <stdlib.h> |
|
+#include <signal.h> |
|
+#include <termios.h> |
|
+#include <sys/types.h> |
|
+#include <pty.h> |
|
+ |
|
+void sigwinch(int arg) |
|
+{ |
|
+ struct winsize ws; |
|
+ printf("window size is now: "); |
|
+ |
|
+ if(ioctl(0, TIOCGWINSZ, &ws)<0) |
|
+ { |
|
+ perror("ioctl"); |
|
+ return; |
|
+ } |
|
+ printf("rows = %d, cols = %d\n", ws.ws_row, ws.ws_col); |
|
+} |
|
+ |
|
+int main() |
|
+{ |
|
+ struct sigaction sa; |
|
+ sa.sa_handler=sigwinch; |
|
+ sigemptyset(&sa.sa_mask); |
|
+ sa.sa_flags=0; |
|
+ if(sigaction(SIGWINCH, &sa, NULL)<0) |
|
+ { |
|
+ perror("sigaction"); |
|
+ return -1; |
|
+ } |
|
+ sigwinch(0); |
|
+ while(1) |
|
+ { |
|
+ sleep(10); |
|
+ } |
|
+ return 0; |
|
+} |
|
Index: src/config.h.in |
|
--- src/config.h.in.orig 2010-08-13 15:45:27.000000000 +0200 |
|
+++ src/config.h.in 2011-02-12 14:27:47.000000000 +0100 |
|
@@ -429,5 +429,9 @@ |
|
/* Define if you want XSMP interaction as well as vanilla swapfile safety */ |
|
#undef USE_XSMP_INTERACT |
|
|
|
+/* VIMSHELL stuff */ |
|
+#undef HAVE_PTY_H |
|
+#undef HAVE_LIBUTIL_H |
|
+ |
|
/* Define if fcntl()'s F_SETFD command knows about FD_CLOEXEC */ |
|
#undef HAVE_FD_CLOEXEC |
|
Index: src/configure.in |
|
--- src/configure.in.orig 2010-08-13 16:15:17.000000000 +0200 |
|
+++ src/configure.in 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -3487,6 +3487,24 @@ |
|
fi |
|
AC_SUBST(DEPEND_CFLAGS_FILTER) |
|
|
|
+dnl ------------------------------------------------------------------ |
|
+dnl VIMSHELL configure thingies |
|
+dnl needs -lutil, but not on MacOS X |
|
+dnl The $MACOSX variable isn't set on the Mac I can use for testing, so we |
|
+dnl have to use other means to find out if this is a Mac. uname for example. |
|
+if test "$(uname)" = "Darwin"; then |
|
+ LIBS="$LIBS" |
|
+else |
|
+ LIBS="$LIBS -lutil" |
|
+fi |
|
+AC_CHECK_HEADERS(pty.h libutil.h stdint.h) |
|
+AC_CHECK_FUNCS(forkpty) |
|
+if test $ac_cv_func_forkpty = no; then |
|
+ AC_MSG_ERROR(vimshell needs forkpty - sorry.) |
|
+fi |
|
+dnl ------------------------------------------------------------------ |
|
+ |
|
+ |
|
dnl write output files |
|
AC_OUTPUT(auto/config.mk:config.mk.in) |
|
|
|
Index: src/eval.c |
|
--- src/eval.c.orig 2010-08-09 22:12:14.000000000 +0200 |
|
+++ src/eval.c 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -12174,6 +12174,9 @@ |
|
#if defined(UNIX) && defined(FEAT_X11) |
|
"X11", |
|
#endif |
|
+#ifdef FEAT_VIMSHELL |
|
+ "vimshell", |
|
+#endif |
|
NULL |
|
}; |
|
|
|
Index: src/ex_cmds.h |
|
--- src/ex_cmds.h.orig 2010-07-21 15:48:02.000000000 +0200 |
|
+++ src/ex_cmds.h 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -1027,6 +1027,10 @@ |
|
BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), |
|
EX(CMD_view, "view", ex_edit, |
|
BANG|FILE1|EDITCMD|ARGOPT|TRLBAR), |
|
+#ifdef FEAT_VIMSHELL |
|
+EX(CMD_vimshell, "vimshell", ex_vimshell, |
|
+ EXTRA|BANG|TRLBAR|CMDWIN), |
|
+#endif |
|
EX(CMD_vimgrep, "vimgrep", ex_vimgrep, |
|
RANGE|NOTADR|BANG|NEEDARG|EXTRA|NOTRLCOM|TRLBAR|XFILE), |
|
EX(CMD_vimgrepadd, "vimgrepadd", ex_vimgrep, |
|
Index: src/ex_docmd.c |
|
--- src/ex_docmd.c.orig 2010-08-07 16:59:47.000000000 +0200 |
|
+++ src/ex_docmd.c 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -149,6 +149,7 @@ |
|
static void ex_quit __ARGS((exarg_T *eap)); |
|
static void ex_cquit __ARGS((exarg_T *eap)); |
|
static void ex_quit_all __ARGS((exarg_T *eap)); |
|
+static void ex_vimshell __ARGS((exarg_T *eap)); |
|
#ifdef FEAT_WINDOWS |
|
static void ex_close __ARGS((exarg_T *eap)); |
|
static void ex_win_close __ARGS((int forceit, win_T *win, tabpage_T *tp)); |
|
@@ -11237,3 +11238,115 @@ |
|
ml_clearmarked(); /* clear rest of the marks */ |
|
} |
|
#endif |
|
+ |
|
+#ifdef FEAT_VIMSHELL |
|
+/* |
|
+ * ":vimshell": creates an empty buffer in the current window and starts a |
|
+ * VIM-Shell inside. |
|
+ * ":vimshellac": same as "vimshell" but closes the window after the shell |
|
+ * terminated (ac = "auto-close"). This is useful for redefinitions of 'Man' |
|
+ * etc. |
|
+ */ |
|
+ static void |
|
+ex_vimshell(eap) |
|
+ exarg_T *eap; |
|
+{ |
|
+ unsigned char *argv[50], argidx, *p; |
|
+ unsigned char cmdline[500]; |
|
+ char cmdbuf[50]; |
|
+ |
|
+ if(curbuf->is_shell!=0) |
|
+ { |
|
+ emsg("VIMSHELL: current buffer is already a shell!"); |
|
+ return; |
|
+ } |
|
+ |
|
+ snprintf(cmdbuf, sizeof(cmdbuf), ":enew%s", eap->forceit==TRUE ? "!" : ""); |
|
+ |
|
+ /* |
|
+ * Do a ":enew" command to get a new buffer in the current window. |
|
+ * Also assures that we don't throw away any unsaved changes the user |
|
+ * made to the previous buffer. |
|
+ */ |
|
+ did_emsg=FALSE; |
|
+ if(do_cmdline_cmd(cmdbuf)==FAIL || did_emsg==TRUE) |
|
+ { |
|
+ return; |
|
+ } |
|
+ |
|
+ /* |
|
+ * Set buffer read only (the user can't write into it anyway, but just |
|
+ * to make sure. We want to be able to close the buffer without any |
|
+ * problems any time). |
|
+ */ |
|
+ curbuf->b_p_ro=TRUE; |
|
+ |
|
+ /* |
|
+ * Parse command line arguments. If none given, default to '/bin/sh' |
|
+ */ |
|
+ snprintf(cmdline, sizeof(cmdline), "%s", eap->arg); |
|
+ p=cmdline; |
|
+ argidx=0; |
|
+ if(!strcmp(p, "")) |
|
+ { |
|
+ argv[0]="/bin/sh"; |
|
+ } |
|
+ else |
|
+ { |
|
+ argv[argidx]=p; |
|
+ do |
|
+ { |
|
+ if(*p==' ') |
|
+ { |
|
+ argidx++; |
|
+ if(argidx+1 >= sizeof(argv)/sizeof(argv[0])) |
|
+ { |
|
+ /* |
|
+ * Too many command line arguments, drop out |
|
+ */ |
|
+ emsg("VIMSHELL: too many command line arguments"); |
|
+ return; |
|
+ } |
|
+ |
|
+ /* |
|
+ * Convert all ' ' to \0 |
|
+ */ |
|
+ for(;*p==' ';p++) |
|
+ *p=0; |
|
+ if(*p!=0) |
|
+ { |
|
+ argv[argidx]=p; |
|
+ } |
|
+ } |
|
+ } while(*p++); |
|
+ } |
|
+ argv[++argidx]=NULL; |
|
+ |
|
+ /* |
|
+ * Convert the current buffer into a shell window. |
|
+ */ |
|
+ curbuf->shell=(struct vim_shell_window *)vim_shell_new(W_WIDTH(curwin), curwin->w_height); |
|
+ if(curbuf->shell==NULL) |
|
+ { |
|
+ EMSG2("VIMSHELL: error creating a new shell: %s", vim_shell_strerror()); |
|
+ return; |
|
+ } |
|
+ curbuf->is_shell=1; |
|
+ curbuf->gtk_input_id=0; |
|
+ |
|
+ /* |
|
+ * start the shell |
|
+ */ |
|
+ if(vim_shell_start(curbuf->shell, (char **)argv)<0) |
|
+ { |
|
+ EMSG2("VIMSHELL: error starting the shell: %s", vim_shell_strerror()); |
|
+ |
|
+ vim_shell_delete(curbuf); |
|
+ return; |
|
+ } |
|
+ |
|
+ /* |
|
+ * we're up and running. |
|
+ */ |
|
+} |
|
+#endif |
|
Index: src/feature.h |
|
--- src/feature.h.orig 2010-07-27 21:45:42.000000000 +0200 |
|
+++ src/feature.h 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -1297,6 +1297,15 @@ |
|
|
|
#endif |
|
|
|
+ /* |
|
+ * The VIM-Shell. Only works on UNIX for now (more specifically, |
|
+ * only Linux, *BSD and MacOS X, others not tested. Generally, if |
|
+ * a system has a forkpty call, it should be working.) |
|
+ */ |
|
+#if defined(FEAT_NORMAL) && (defined(UNIX) || defined(MACOS_X)) |
|
+#define FEAT_VIMSHELL |
|
+#endif |
|
+ |
|
/* |
|
* +autochdir 'autochdir' option. |
|
*/ |
|
Index: src/gui_gtk_x11.c |
|
--- src/gui_gtk_x11.c.orig 2010-08-15 13:52:15.000000000 +0200 |
|
+++ src/gui_gtk_x11.c 2011-02-12 14:22:29.000000000 +0100 |
|
@@ -5358,6 +5358,66 @@ |
|
} |
|
#endif |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+/* |
|
+ * VIM-Shell callback, called when a shell file descriptor has data |
|
+ * available. |
|
+ */ |
|
+ static void |
|
+vimshell_request_cb( |
|
+ gpointer data, |
|
+ gint source_fd, |
|
+ GdkInputCondition condition) |
|
+{ |
|
+ buf_T *buf; |
|
+ int did_redraw=0; |
|
+ |
|
+ /* |
|
+ * Search the right buffer. |
|
+ */ |
|
+ for(buf=firstbuf;buf!=NULL;buf=buf->b_next) |
|
+ { |
|
+ if(buf->is_shell!=0 && buf->shell && buf->shell->fd_master==source_fd) |
|
+ { |
|
+ int r; |
|
+ |
|
+ r=vim_shell_do_read_lowlevel(buf); |
|
+ if(r>did_redraw) |
|
+ did_redraw=r; |
|
+ |
|
+ if(r==1 && updating_screen==FALSE) |
|
+ redraw_buf_later(buf, VALID); |
|
+ else if(r==2) |
|
+ { |
|
+ /* |
|
+ * Shell died, so remove the GTK-input |
|
+ * VIMSHELL TODO: this should really be happening inside vim_shell_delete |
|
+ */ |
|
+ gdk_input_remove(buf->gtk_input_id); |
|
+ buf->gtk_input_id=0; |
|
+ if(updating_screen==FALSE) |
|
+ redraw_buf_later(buf, CLEAR); |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ if(updating_screen==FALSE) |
|
+ { |
|
+ if(did_redraw==1) |
|
+ update_screen(VALID); |
|
+ else if(did_redraw==2) |
|
+ { |
|
+ update_screen(CLEAR); |
|
+ out_flush(); |
|
+ } |
|
+ } |
|
+ |
|
+ if (gtk_main_level() > 0) |
|
+ gtk_main_quit(); |
|
+} |
|
+#endif |
|
+ |
|
+ |
|
/* |
|
* GUI input routine called by gui_wait_for_chars(). Waits for a character |
|
* from the keyboard. |
|
@@ -5394,6 +5454,24 @@ |
|
} |
|
#endif |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+ /* |
|
+ * Go through all buffers, see if we have to add not yet added inputs |
|
+ */ |
|
+ { |
|
+ buf_T *buf; |
|
+ for(buf=firstbuf;buf!=NULL;buf=buf->b_next) |
|
+ { |
|
+ if(buf->is_shell!=0 && buf->shell && buf->gtk_input_id==0) |
|
+ { |
|
+ buf->gtk_input_id=gdk_input_add(buf->shell->fd_master, |
|
+ GDK_INPUT_READ, vimshell_request_cb, NULL); |
|
+ } |
|
+ } |
|
+ } |
|
+#endif |
|
+ |
|
+ |
|
timed_out = FALSE; |
|
|
|
/* this timeout makes sure that we will return if no characters arrived in |
|
Index: src/main.c |
|
--- src/main.c.orig 2010-08-08 15:09:55.000000000 +0200 |
|
+++ src/main.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -179,6 +179,11 @@ |
|
*/ |
|
mch_early_init(); |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+ vim_shell_init(); |
|
+#endif |
|
+ |
|
+ |
|
/* Many variables are in "params" so that we can pass them to invoked |
|
* functions without a lot of arguments. "argc" and "argv" are also |
|
* copied, so that they can be changed. */ |
|
Index: src/move.c |
|
--- src/move.c.orig 2010-08-08 15:12:31.000000000 +0200 |
|
+++ src/move.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -625,6 +625,14 @@ |
|
void |
|
validate_cursor() |
|
{ |
|
+#ifdef FEAT_VIMSHELL |
|
+ /* |
|
+ * The vimshell repositions its artificial cursor in vim_shell_redraw. Don't do the |
|
+ * checks below. |
|
+ */ |
|
+ if(curwin->w_buffer && curwin->w_buffer->is_shell!=0) |
|
+ return; |
|
+#endif |
|
check_cursor_moved(curwin); |
|
if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) |
|
curs_columns(TRUE); |
|
Index: src/normal.c |
|
--- src/normal.c.orig 2010-07-31 15:25:19.000000000 +0200 |
|
+++ src/normal.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -648,10 +648,50 @@ |
|
dont_scroll = FALSE; /* allow scrolling here */ |
|
#endif |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+ /* |
|
+ * We reroute ALL characters to the shell, EXCEPT Ctrl_W, so all |
|
+ * Window-Commands should still be working (not unimportant, think of |
|
+ * leaving the window ...) |
|
+ * VIMSHELL TODO: what about mouse commands, GUI commands, etc |
|
+ */ |
|
+ if(curbuf->is_shell) |
|
+ { |
|
+ no_mapping++; |
|
+ allow_keys++; |
|
+ c = safe_vgetc(); |
|
+ no_mapping--; |
|
+ allow_keys--; |
|
+ |
|
+ if(curbuf->is_shell && c!=Ctrl_W) |
|
+ { |
|
+ if(vim_shell_write(curbuf->shell, c)<0) |
|
+ { |
|
+ /* |
|
+ * The shell died, clean up |
|
+ */ |
|
+ vim_shell_delete(curbuf); |
|
+ curbuf->is_shell=0; |
|
+ curbuf->b_p_ro=FALSE; |
|
+ |
|
+ redraw_later(CLEAR); |
|
+ update_screen(CLEAR); |
|
+ } |
|
+ return; |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ c = safe_vgetc(); |
|
+ } |
|
+#else |
|
+ |
|
/* |
|
* Get the command character from the user. |
|
*/ |
|
c = safe_vgetc(); |
|
+#endif |
|
+ |
|
LANGMAP_ADJUST(c, TRUE); |
|
|
|
#ifdef FEAT_VISUAL |
|
Index: src/os_unix.c |
|
--- src/os_unix.c.orig 2010-08-08 15:14:04.000000000 +0200 |
|
+++ src/os_unix.c 2011-02-12 14:27:20.000000000 +0100 |
|
@@ -4834,7 +4834,11 @@ |
|
# endif |
|
#endif |
|
#ifndef HAVE_SELECT |
|
+# ifdef FEAT_VIMSHELL |
|
+ struct pollfd fds[51]; |
|
+# else |
|
struct pollfd fds[6]; |
|
+#endif |
|
int nfd; |
|
# ifdef FEAT_XCLIPBOARD |
|
int xterm_idx = -1; |
|
@@ -4845,6 +4849,15 @@ |
|
# ifdef USE_XSMP |
|
int xsmp_idx = -1; |
|
# endif |
|
+# ifdef FEAT_VIMSHELL |
|
+ struct |
|
+ { |
|
+ int idx; |
|
+ struct vim_shell_window *shell; |
|
+ buf_T *buffer; |
|
+ } vimshell_idxs[50]; |
|
+ int vimshell_idx_cnt; |
|
+# endif |
|
# ifdef FEAT_NETBEANS_INTG |
|
int nb_idx = -1; |
|
# endif |
|
@@ -4908,6 +4921,50 @@ |
|
} |
|
#endif |
|
|
|
+# ifdef FEAT_VIMSHELL |
|
+ { |
|
+ /* |
|
+ * Loop through all windows and see if they contain vimshells. |
|
+ * If yes, add the master-fd to the list of polled fds. |
|
+ */ |
|
+ memset(vimshell_idxs, 0, sizeof(vimshell_idxs)); |
|
+ vimshell_idx_cnt=0; |
|
+ for(buf=firstbuf; buf!=NULL; buf=buf->b_next) |
|
+ { |
|
+ buf_T *buf; |
|
+ if(buf->is_shell!=0) |
|
+ { |
|
+ vimshell_idxs[vimshell_idx_count].idx=nfd; |
|
+ vimshell_idxs[vimshell_idx_count].buffer=buf; |
|
+ vimshell_idxs[vimshell_idx_count].shell=buf->shell; |
|
+ |
|
+ /* |
|
+ * We will first run out of fds before we run out of |
|
+ * vimshell_idxs-slots, so no check here. |
|
+ */ |
|
+ vimshell_idx_count++; |
|
+ |
|
+ if(buf->shell==NULL) |
|
+ { |
|
+ // VIMSHELL TODO: error message here |
|
+ continue; |
|
+ } |
|
+ fds[nfd].fd = buf->shell->fd_master; |
|
+ fds[nfd].events = POLLIN; |
|
+ nfd++; |
|
+ if(nfd>=sizeof(fds)/sizeof(fds[0])) |
|
+ { |
|
+ /* |
|
+ * no more fds-slots left! aieeee |
|
+ */ |
|
+ // VIMSHELL TODO: issue a warning here or something |
|
+ break; |
|
+ } |
|
+ } |
|
+ } |
|
+ } |
|
+# endif |
|
+ |
|
ret = poll(fds, nfd, towait); |
|
# ifdef FEAT_MZSCHEME |
|
if (ret == 0 && mzquantum_used) |
|
@@ -4968,6 +5025,38 @@ |
|
} |
|
#endif |
|
|
|
+# ifdef FEAT_VIMSHELL |
|
+#error "VIMSHELL: probably doesn't work with poll(), never tested, sorry (use select)" |
|
+ { |
|
+ /* |
|
+ * See if any of the shell's fds have a read request ready |
|
+ * If yes, call the shell's read handler. |
|
+ */ |
|
+ int i; |
|
+ int did_redraw=0; |
|
+ for(i=0;i<vimshell_idx_cnt;i++) |
|
+ { |
|
+ if(fds[vimshell_idxs[i].idx].revents & POLLIN) |
|
+ { |
|
+ if(vim_shell_read(vimshell_idxs[i].shell)<0) |
|
+ { |
|
+ // VIMSHELL TODO: handle error here |
|
+ continue; |
|
+ } |
|
+ |
|
+ redraw_buf_later(vimshell_idxs[i].buffer, NOT_VALID); |
|
+ |
|
+ did_redraw=1; |
|
+ } |
|
+ // VIMSHELL TODO: handle POLLHUP here too (shell terminated) |
|
+ } |
|
+ if(did_redraw==1) |
|
+ { |
|
+ update_screen(NOT_VALID); |
|
+ out_flush(); |
|
+ } |
|
+ } |
|
+# endif |
|
|
|
#else /* HAVE_SELECT */ |
|
|
|
@@ -5048,6 +5137,25 @@ |
|
maxfd = xsmp_icefd; |
|
} |
|
# endif |
|
+# ifdef FEAT_VIMSHELL |
|
+ { |
|
+ /* |
|
+ * Loop through all windows and see if they contain vimshells. |
|
+ * If yes, add the master-fd to the list of fds |
|
+ */ |
|
+ win_T *win; |
|
+ FOR_ALL_WINDOWS(win) |
|
+ { |
|
+ buf_T *buf=win->w_buffer; |
|
+ if(buf->is_shell!=0) |
|
+ { |
|
+ FD_SET(buf->shell->fd_master, &rfds); |
|
+ if (maxfd < buf->shell->fd_master) |
|
+ maxfd = buf->shell->fd_master; |
|
+ } |
|
+ } |
|
+ } |
|
+# endif |
|
#ifdef FEAT_NETBEANS_INTG |
|
if (nb_fd != -1) |
|
{ |
|
@@ -5141,6 +5249,17 @@ |
|
} |
|
#endif |
|
|
|
+# ifdef FEAT_VIMSHELL |
|
+ if((maxfd=vim_shell_do_read_select(rfds))!=0) |
|
+ { |
|
+ ret-=maxfd; |
|
+# ifdef MAY_LOOP |
|
+ if (ret == 0) |
|
+ finished = FALSE; /* keep going if event was only one */ |
|
+# endif |
|
+ } |
|
+# endif |
|
+ |
|
#endif /* HAVE_SELECT */ |
|
|
|
#ifdef MAY_LOOP |
|
Index: src/screen.c |
|
--- src/screen.c.orig 2010-08-13 15:21:27.000000000 +0200 |
|
+++ src/screen.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -92,13 +92,21 @@ |
|
/* |
|
* The attributes that are actually active for writing to the screen. |
|
*/ |
|
+#ifdef FEAT_VIMSHELL |
|
+int screen_attr = 0; |
|
+#else |
|
static int screen_attr = 0; |
|
+#endif |
|
|
|
/* |
|
* Positioning the cursor is reduced by remembering the last position. |
|
* Mostly used by windgoto() and screen_char(). |
|
*/ |
|
+#ifdef FEAT_VIMSHELL |
|
+int screen_cur_row, screen_cur_col; /* last known cursor position */ |
|
+#else |
|
static int screen_cur_row, screen_cur_col; /* last known cursor position */ |
|
+#endif |
|
|
|
#ifdef FEAT_SEARCH_EXTRA |
|
static match_T search_hl; /* used for 'hlsearch' highlight matching */ |
|
@@ -143,7 +151,11 @@ |
|
static void prepare_search_hl __ARGS((win_T *wp, linenr_T lnum)); |
|
static void next_search_hl __ARGS((win_T *win, match_T *shl, linenr_T lnum, colnr_T mincol)); |
|
#endif |
|
+#ifdef FEAT_VIMSHELL |
|
+void screen_start_highlight __ARGS((int attr)); |
|
+#else |
|
static void screen_start_highlight __ARGS((int attr)); |
|
+#endif |
|
static void screen_char __ARGS((unsigned off, int row, int col)); |
|
#ifdef FEAT_MBYTE |
|
static void screen_char_2 __ARGS((unsigned off, int row, int col)); |
|
@@ -1989,9 +2001,19 @@ |
|
else if (dollar_vcol == 0) |
|
wp->w_botline = lnum; |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+ /* |
|
+ * We don't want '~' to appear right in the middle of our shells ... |
|
+ */ |
|
+ if(wp->w_buffer->is_shell==0) |
|
+ { |
|
+#endif |
|
/* make sure the rest of the screen is blank */ |
|
/* put '~'s on rows that aren't part of the file. */ |
|
win_draw_end(wp, '~', ' ', row, wp->w_height, HLF_AT); |
|
+#ifdef FEAT_VIMSHELL |
|
+ } |
|
+#endif |
|
} |
|
|
|
/* Reset the type of redrawing required, the window has been updated. */ |
|
@@ -2039,6 +2061,18 @@ |
|
if (!got_int) |
|
got_int = save_got_int; |
|
#endif |
|
+ |
|
+#ifdef FEAT_VIMSHELL |
|
+ /* |
|
+ * If this window contains a shell, redraw the shell. |
|
+ */ |
|
+ if(wp->w_buffer->is_shell != 0) |
|
+ { |
|
+ wp->w_buffer->shell->force_redraw=(type>=NOT_VALID ? 1 : 0); |
|
+ vim_shell_redraw(wp->w_buffer->shell, wp); |
|
+ return; |
|
+ } |
|
+#endif |
|
} |
|
|
|
#ifdef FEAT_SIGNS |
|
@@ -7221,7 +7255,11 @@ |
|
} |
|
#endif |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+ void |
|
+#else |
|
static void |
|
+#endif |
|
screen_start_highlight(attr) |
|
int attr; |
|
{ |
|
@@ -7421,7 +7459,11 @@ |
|
* Put character ScreenLines["off"] on the screen at position "row" and "col", |
|
* using the attributes from ScreenAttrs["off"]. |
|
*/ |
|
+#ifdef FEAT_VIMSHELL |
|
+ void |
|
+#else |
|
static void |
|
+#endif |
|
screen_char(off, row, col) |
|
unsigned off; |
|
int row; |
|
Index: src/structs.h |
|
--- src/structs.h.orig 2010-08-07 16:59:27.000000000 +0200 |
|
+++ src/structs.h 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -499,6 +499,11 @@ |
|
|
|
typedef struct file_buffer buf_T; /* forward declaration */ |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+struct vim_shell_window; |
|
+#endif |
|
+ |
|
+ |
|
/* |
|
* Simplistic hashing scheme to quickly locate the blocks in the used list. |
|
* 64 blocks are found directly (64 * 4K = 256K, most files are smaller). |
|
@@ -1648,6 +1653,12 @@ |
|
int b_was_netbeans_file;/* TRUE if b_netbeans_file was once set */ |
|
#endif |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+ char is_shell; /* (flag) Is this buffer a shell? (0 = false) */ |
|
+ struct vim_shell_window *shell; /* Pointer to the shell struct, or NULL */ |
|
+ int gtk_input_id; /* GTK-input id returned by gdk_input_add, only for GUI */ |
|
+#endif |
|
+ |
|
}; |
|
|
|
|
|
@@ -2130,6 +2141,12 @@ |
|
#ifdef FEAT_RUBY |
|
void *w_ruby_ref; |
|
#endif |
|
+ |
|
+#ifdef FEAT_VIMSHELL |
|
+ char is_shell; /* (flag) Is this buffer a shell? (0 = false) */ |
|
+ struct vim_shell_window *shell; /* Pointer to the shell struct, or NULL */ |
|
+ int gtk_input_id; /* GTK-input id returned by gdk_input_add, only for GUI */ |
|
+#endif |
|
}; |
|
|
|
/* |
|
Index: src/syntax.c |
|
--- src/syntax.c.orig 2010-08-08 15:17:03.000000000 +0200 |
|
+++ src/syntax.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -6232,6 +6232,10 @@ |
|
syntax_present(win) |
|
win_T *win; |
|
{ |
|
+#ifdef FEAT_VIMSHELL |
|
+ if(win->is_shell!=0) |
|
+ return 0; |
|
+#endif |
|
return (win->w_s->b_syn_patterns.ga_len != 0 |
|
|| win->w_s->b_syn_clusters.ga_len != 0 |
|
|| win->w_s->b_keywtab.ht_used > 0 |
|
Index: src/terminal.c |
|
--- src/terminal.c.orig 2011-02-12 14:22:30.000000000 +0100 |
|
+++ src/terminal.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -0,0 +1,1933 @@ |
|
+/* |
|
+ * terminal.c |
|
+ * |
|
+ * This is the screen-like terminal emulator; it is a better vt100 and supports the |
|
+ * same commands that screen does (including color etc). |
|
+ * |
|
+ * The interface is vim_shell_terminal_input and vim_shell_terminal_output. These |
|
+ * functions get characters from the shell (or from the user) and process them |
|
+ * accordingly to the terminal rules (ESC sequences etc). They then work directly |
|
+ * on the vim_shell-window-buffer, updating its contents. |
|
+ * |
|
+ * VIMSHELL TODO: *) don't scroll scroll region if cursor is outside |
|
+ * *) change the buffer name according to the window title |
|
+ * *) CSI (0x9B) |
|
+ * *) Get the ESC codes for switching charsets from terminfo/termcap |
|
+ * *) Origin mode |
|
+ * *) "erase with background color" |
|
+ * |
|
+ * This file is part of the VIM-Shell project. http://vimshell.wana.at |
|
+ * |
|
+ * Author: Thomas Wana <thomas@wana.at> |
|
+ * |
|
+ */ |
|
+ |
|
+static char *RCSID="$Id$"; |
|
+ |
|
+#include <string.h> |
|
+#include <stdlib.h> |
|
+#include <unistd.h> |
|
+#include <ctype.h> |
|
+#include <errno.h> |
|
+ |
|
+#include "vim.h" |
|
+ |
|
+#ifdef FEAT_VIMSHELL |
|
+#ifdef VIMSHELL_DEBUG |
|
+# define ESCDEBUG |
|
+/* |
|
+ * Really extreme logging |
|
+ * Log *every* character we write to the shell |
|
+ */ |
|
+//# define VERBOSE |
|
+#endif |
|
+ |
|
+#ifdef ESCDEBUG |
|
+# define ESCDEBUGPRINTF(a...) if(vimshell_debug_fp) { fprintf(vimshell_debug_fp, a); fflush(vimshell_debug_fp); } |
|
+#else |
|
+# define ESCDEBUGPRINTF(a...) |
|
+#endif |
|
+ |
|
+#ifdef VERBOSE |
|
+# define VERBOSEPRINTF(a...) if(vimshell_debug_fp) { fprintf(vimshell_debug_fp, a); fflush(vimshell_debug_fp); } |
|
+#else |
|
+# define VERBOSEPRINTF(a...) |
|
+#endif |
|
+ |
|
+/* |
|
+ * These are the VIM keynames. |
|
+ */ |
|
+#define VIMSHELL_KEY_DOWN K_DOWN |
|
+#define VIMSHELL_KEY_UP K_UP |
|
+#define VIMSHELL_KEY_LEFT K_LEFT |
|
+#define VIMSHELL_KEY_RIGHT K_RIGHT |
|
+#define VIMSHELL_KEY_HOME K_HOME |
|
+#define VIMSHELL_KEY_BACKSPACE K_BS |
|
+#define VIMSHELL_KEY_F1 K_F1 |
|
+#define VIMSHELL_KEY_F2 K_F2 |
|
+#define VIMSHELL_KEY_F3 K_F3 |
|
+#define VIMSHELL_KEY_F4 K_F4 |
|
+#define VIMSHELL_KEY_F5 K_F5 |
|
+#define VIMSHELL_KEY_F6 K_F6 |
|
+#define VIMSHELL_KEY_F7 K_F7 |
|
+#define VIMSHELL_KEY_F8 K_F8 |
|
+#define VIMSHELL_KEY_F9 K_F9 |
|
+#define VIMSHELL_KEY_F10 K_F10 |
|
+#define VIMSHELL_KEY_F11 K_F11 |
|
+#define VIMSHELL_KEY_F12 K_F12 |
|
+#define VIMSHELL_KEY_DC K_DEL |
|
+#define VIMSHELL_KEY_END K_END |
|
+#define VIMSHELL_KEY_IC K_INS |
|
+#define VIMSHELL_KEY_NPAGE K_PAGEDOWN |
|
+#define VIMSHELL_KEY_PPAGE K_PAGEUP |
|
+#define VIMSHELL_KEY_K0 K_K0 |
|
+#define VIMSHELL_KEY_K1 K_K1 |
|
+#define VIMSHELL_KEY_K2 K_K2 |
|
+#define VIMSHELL_KEY_K3 K_K3 |
|
+#define VIMSHELL_KEY_K4 K_K4 |
|
+#define VIMSHELL_KEY_K5 K_K5 |
|
+#define VIMSHELL_KEY_K6 K_K6 |
|
+#define VIMSHELL_KEY_K7 K_K7 |
|
+#define VIMSHELL_KEY_K8 K_K8 |
|
+#define VIMSHELL_KEY_K9 K_K9 |
|
+#define VIMSHELL_KEY_KPLUS K_KPLUS |
|
+#define VIMSHELL_KEY_KMINUS K_KMINUS |
|
+#define VIMSHELL_KEY_KDIVIDE K_KDIVIDE |
|
+#define VIMSHELL_KEY_KMULTIPLY K_KMULTIPLY |
|
+#define VIMSHELL_KEY_KENTER K_KENTER |
|
+#define VIMSHELL_KEY_KPOINT K_KPOINT |
|
+ |
|
+static void terminal_ED(struct vim_shell_window *shell, int argc, char argv[20][20]); |
|
+static void terminal_CUP(struct vim_shell_window *shell, int argc, char argv[20][20]); |
|
+static int terminal_flush_output(struct vim_shell_window *shell); |
|
+ |
|
+/* |
|
+ * A routine that prints a buffer in 'hexdump -C'-style via printf |
|
+ */ |
|
+static void vimshell_hexdump(FILE *fp, unsigned char *buffer, long len) |
|
+{ |
|
+ unsigned long pos=0; |
|
+ |
|
+ while(len>0) |
|
+ { |
|
+ int i; |
|
+ fprintf(fp,"%08x ",(unsigned int)pos); |
|
+ for(i=0;i<16 && i<len;i++) |
|
+ { |
|
+ fprintf(fp,"%02x ",buffer[pos+i]); |
|
+ if(i==7 || i==15) |
|
+ fprintf(fp," "); |
|
+ } |
|
+ fprintf(fp,"|"); |
|
+ for(i=0;i<16 && i<len;i++) |
|
+ { |
|
+ unsigned char c=buffer[pos+i]; |
|
+ if(isprint(c)) |
|
+ { |
|
+ fprintf(fp,"%c",c); |
|
+ } |
|
+ else |
|
+ { |
|
+ fprintf(fp,"."); |
|
+ } |
|
+ } |
|
+ fprintf(fp,"|\n"); |
|
+ len-=16; |
|
+ pos+=16; |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * Tabulation Clear (TBC) |
|
+ * |
|
+ * 9/11 6/7 |
|
+ * CSI g |
|
+ * |
|
+ * Clears a horizontal tab stop at cursor position. |
|
+ * |
|
+ * 9/11 3/0 6/7 |
|
+ * CSI 0 g |
|
+ * |
|
+ * Clears a horizontal tab stop at cursor position. |
|
+ * |
|
+ * 9/11 3/3 6/7 |
|
+ * CSI 3 g |
|
+ * |
|
+ * Clears all horizontal tab stops. |
|
+ */ |
|
+static void terminal_TBC(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int param; |
|
+ |
|
+ if(argc==0) |
|
+ { |
|
+ param=0; |
|
+ } |
|
+ else if(argc>1) |
|
+ { |
|
+ ESCDEBUGPRINTF("%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ // VIMSHELL TODO: DRINGEND! wenn argc==0 dann ist argv[0] NULL und wir crashen |
|
+ // hier ... passiert in einigen Funktionen, dank copy+paste! Super gmocht Tom! |
|
+ param=strtol(argv[0], NULL, 10); |
|
+ switch(param) |
|
+ { |
|
+ case 0: |
|
+ shell->tabline[shell->cursor_x]=0; |
|
+ break; |
|
+ case 3: |
|
+ memset(shell->tabline, 0, shell->size_x); |
|
+ break; |
|
+ default: |
|
+ ESCDEBUGPRINTF( "%s: sequence error (2)\n", __FUNCTION__); |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * CUB . Cursor Backward . Host to VT100 and VT100 to Host |
|
+ * ESC [ Pn D default value: 1 |
|
+ * |
|
+ * The CUB sequence moves the active position to the left. The distance moved is |
|
+ * determined by the parameter. If the parameter value is zero or one, the active |
|
+ * position is moved one position to the left. If the parameter value is n, the active |
|
+ * position is moved n positions to the left. If an attempt is made to move the cursor |
|
+ * to the left of the left margin, the cursor stops at the left margin. Editor Function |
|
+ */ |
|
+static void terminal_CUB(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int distance; |
|
+ |
|
+ if(argc==0) |
|
+ { |
|
+ distance=1; |
|
+ } |
|
+ else if(argc>1) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ distance=strtol(argv[0], NULL, 10); |
|
+ if(distance==0) |
|
+ distance=1; |
|
+ |
|
+ if(shell->cursor_x<distance) |
|
+ shell->cursor_x=0; |
|
+ else |
|
+ shell->cursor_x-=distance; |
|
+} |
|
+ |
|
+/* |
|
+ * CUU . Cursor Up . Host to VT100 and VT100 to Host |
|
+ * ESC [ Pn A default value: 1 |
|
+ * |
|
+ * Moves the active position upward without altering the column position. The |
|
+ * number of lines moved is determined by the parameter. A parameter value of zero |
|
+ * or one moves the active position one line upward. A parameter value of n moves the |
|
+ * active position n lines upward. If an attempt is made to move the cursor above the |
|
+ * top margin, the cursor stops at the top margin. Editor Function |
|
+ */ |
|
+static void terminal_CUU(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int distance; |
|
+ |
|
+ if(argc==0) |
|
+ { |
|
+ distance=1; |
|
+ } |
|
+ else if(argc>1) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ distance=strtol(argv[0], NULL, 10); |
|
+ if(distance==0) |
|
+ distance=1; |
|
+ |
|
+ if((int)shell->cursor_y-distance<shell->scroll_top_margin) |
|
+ shell->cursor_y=shell->scroll_top_margin; |
|
+ else |
|
+ shell->cursor_y-=distance; |
|
+} |
|
+ |
|
+ |
|
+/* |
|
+ * CUD . Cursor Down . Host to VT100 and VT100 to Host |
|
+ * ESC [ Pn B default value: 1 |
|
+ * |
|
+ * The CUD sequence moves the active position downward without altering the column |
|
+ * position. The number of lines moved is determined by the parameter. If the parameter |
|
+ * value is zero or one, the active position is moved one line downward. If the parameter |
|
+ * value is n, the active position is moved n lines downward. In an attempt is made to |
|
+ * move the cursor below the bottom margin, the cursor stops at the bottom margin. Editor Function |
|
+ */ |
|
+static void terminal_CUD(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int distance; |
|
+ |
|
+ if(argc==0) |
|
+ { |
|
+ distance=1; |
|
+ } |
|
+ else if(argc>1) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ distance=strtol(argv[0], NULL, 10); |
|
+ if(distance==0) |
|
+ distance=1; |
|
+ |
|
+ shell->cursor_y+=distance; |
|
+ if(shell->cursor_y+1>=shell->scroll_bottom_margin) |
|
+ shell->cursor_y=shell->scroll_bottom_margin; |
|
+} |
|
+ |
|
+/* |
|
+ * CUF . Cursor Forward . Host to VT100 and VT100 to Host |
|
+ * ESC [ Pn C default value: 1 |
|
+ * |
|
+ * The CUF sequence moves the active position to the right. The distance moved is |
|
+ * determined by the parameter. A parameter value of zero or one moves the active |
|
+ * position one position to the right. A parameter value of n moves the active position n |
|
+ * positions to the right. If an attempt is made to move the cursor to the right |
|
+ * of the right margin, the cursor stops at the right margin. Editor Function |
|
+ */ |
|
+static void terminal_CUF(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int distance; |
|
+ |
|
+ if(argc==0) |
|
+ { |
|
+ distance=1; |
|
+ } |
|
+ else if(argc>1) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ distance=strtol(argv[0], NULL, 10); |
|
+ if(distance==0) |
|
+ distance=1; |
|
+ |
|
+ shell->cursor_x+=distance; |
|
+ if(shell->cursor_x+1>=shell->size_x) |
|
+ shell->cursor_x=shell->size_x+1; |
|
+} |
|
+ |
|
+/* |
|
+ * SGR . Select Graphic Rendition |
|
+ * ESC [ Ps ; . . . ; Ps m default value: 0 |
|
+ * |
|
+ * Invoke the graphic rendition specified by the parameter(s). All following characters |
|
+ * transmitted to the VT100 are rendered according to the parameter(s) until the next |
|
+ * occurrence of SGR. Format Effector |
|
+ * |
|
+ * Parameter Parameter Meaning |
|
+ * 0 Attributes off |
|
+ * 1 Bold or increased intensity |
|
+ * 4 Underscore |
|
+ * 5 Blink |
|
+ * 7 Negative (reverse) image |
|
+ * |
|
+ * All other parameter values are ignored. |
|
+ * |
|
+ * With the Advanced Video Option, only one type of character attribute is possible as |
|
+ * determined by the cursor selection; in that case specifying either the underscore or |
|
+ * the reverse attribute will activate the currently selected attribute. (See cursor |
|
+ * selection in Chapter 1). |
|
+ */ |
|
+static void terminal_SGR(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ if(argc==0) |
|
+ { |
|
+ shell->rendition=0; |
|
+ shell->fgcolor=VIMSHELL_COLOR_DEFAULT; // default fgcolor |
|
+ shell->bgcolor=VIMSHELL_COLOR_DEFAULT; // default bgcolor |
|
+ } |
|
+ else |
|
+ { |
|
+ int i; |
|
+ for(i=0;i<argc;i++) |
|
+ { |
|
+ int val; |
|
+ switch((val=strtol(argv[i], NULL, 10))) |
|
+ { |
|
+ case 0: |
|
+ shell->rendition=0; |
|
+ shell->fgcolor=VIMSHELL_COLOR_DEFAULT; |
|
+ shell->bgcolor=VIMSHELL_COLOR_DEFAULT; |
|
+ break; |
|
+ case 1: |
|
+ shell->rendition|=RENDITION_BOLD; |
|
+ break; |
|
+ case 2: |
|
+ shell->rendition|=RENDITION_DIM; |
|
+ break; |
|
+ case 4: |
|
+ shell->rendition|=RENDITION_UNDERSCORE; |
|
+ break; |
|
+ case 5: |
|
+ shell->rendition|=RENDITION_BLINK; |
|
+ break; |
|
+ case 7: |
|
+ shell->rendition|=RENDITION_NEGATIVE; |
|
+ break; |
|
+ case 8: |
|
+ shell->rendition|=RENDITION_HIDDEN; |
|
+ break; |
|
+ case 22: |
|
+ shell->rendition&=~RENDITION_BOLD; |
|
+ break; |
|
+ case 24: |
|
+ shell->rendition&=~RENDITION_UNDERSCORE; |
|
+ break; |
|
+ case 25: |
|
+ shell->rendition&=~RENDITION_BLINK; |
|
+ break; |
|
+ case 27: |
|
+ shell->rendition&=~RENDITION_NEGATIVE; |
|
+ break; |
|
+ default: |
|
+ if(val>=30 && val<=37) |
|
+ shell->fgcolor=val-30; |
|
+ else if(val>=40 && val<=47) |
|
+ shell->bgcolor=val-40; |
|
+ else if(val==39) |
|
+ shell->fgcolor=VIMSHELL_COLOR_DEFAULT; // default fgcolor |
|
+ else if(val==49) |
|
+ shell->bgcolor=VIMSHELL_COLOR_DEFAULT; // default bgcolor |
|
+ else |
|
+ ESCDEBUGPRINTF( "%s: unknown rendition %s\n", |
|
+ __FUNCTION__, argv[i]); |
|
+ } |
|
+ } |
|
+ } |
|
+ ESCDEBUGPRINTF("%s: rendition is now: %04x\n", __FUNCTION__, shell->rendition); |
|
+ ESCDEBUGPRINTF("%s: foreground color: %d, background color: %d\n", __FUNCTION__, |
|
+ shell->fgcolor, shell->bgcolor); |
|
+} |
|
+ |
|
+/* |
|
+ * Copy the screen contents to the alternate screen. |
|
+ */ |
|
+static void terminal_backup_screen(struct vim_shell_window *shell) |
|
+{ |
|
+ size_t len; |
|
+ if(shell->alt!=NULL) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: WARNING: alternate screen taken\n", __FUNCTION__); |
|
+ vim_shell_free(shell->alt->winbuf); |
|
+ vim_shell_free(shell->alt->bgbuf); |
|
+ vim_shell_free(shell->alt->fgbuf); |
|
+ vim_shell_free(shell->alt->rendbuf); |
|
+ vim_shell_free(shell->alt->tabline); |
|
+ vim_shell_free(shell->alt->charset); |
|
+ vim_shell_free(shell->alt); |
|
+ shell->alt=NULL; |
|
+ } |
|
+ |
|
+ shell->alt=(struct vim_shell_window *)vim_shell_malloc(sizeof(struct vim_shell_window)); |
|
+ if(shell->alt==NULL) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: ERROR: unable to allocate a new screen\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ *(shell->alt)=*shell; |
|
+ |
|
+ len=shell->size_x*shell->size_y; |
|
+ shell->alt->winbuf=(uint8_t *)vim_shell_malloc(len); |
|
+ shell->alt->fgbuf=(uint8_t *)vim_shell_malloc(len); |
|
+ shell->alt->bgbuf=(uint8_t *)vim_shell_malloc(len); |
|
+ shell->alt->rendbuf=(uint8_t *)vim_shell_malloc(len); |
|
+ shell->alt->tabline=(uint8_t *)vim_shell_malloc(shell->size_x); |
|
+ shell->alt->charset=(uint8_t *)vim_shell_malloc(len); |
|
+ if(shell->alt->winbuf==NULL || shell->alt->winbuf==NULL || shell->alt->winbuf==NULL || shell->alt->winbuf==NULL || |
|
+ shell->alt->charset==NULL || shell->alt->tabline==NULL) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: ERROR: unable to allocate buffers\n", __FUNCTION__); |
|
+ if(shell->alt->winbuf) vim_shell_free(shell->alt->winbuf); |
|
+ if(shell->alt->fgbuf) vim_shell_free(shell->alt->fgbuf); |
|
+ if(shell->alt->bgbuf) vim_shell_free(shell->alt->bgbuf); |
|
+ if(shell->alt->rendbuf) vim_shell_free(shell->alt->rendbuf); |
|
+ if(shell->alt->tabline) vim_shell_free(shell->alt->tabline); |
|
+ if(shell->alt->charset) vim_shell_free(shell->alt->charset); |
|
+ vim_shell_free(shell->alt); |
|
+ shell->alt=NULL; |
|
+ return; |
|
+ } |
|
+ |
|
+ memcpy(shell->alt->winbuf, shell->winbuf, len); |
|
+ memcpy(shell->alt->fgbuf, shell->fgbuf, len); |
|
+ memcpy(shell->alt->bgbuf, shell->bgbuf, len); |
|
+ memcpy(shell->alt->rendbuf, shell->rendbuf, len); |
|
+ memcpy(shell->alt->charset, shell->charset, len); |
|
+ memcpy(shell->alt->tabline, shell->tabline, shell->size_x); |
|
+} |
|
+ |
|
+/* |
|
+ * Restore the alternate screen |
|
+ */ |
|
+static void terminal_restore_screen(struct vim_shell_window *shell) |
|
+{ |
|
+ struct vim_shell_window *alt; |
|
+ if(shell->alt==NULL) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: WARNING: nothing to restore\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ vim_shell_free(shell->winbuf); |
|
+ vim_shell_free(shell->rendbuf); |
|
+ vim_shell_free(shell->tabline); |
|
+ vim_shell_free(shell->fgbuf); |
|
+ vim_shell_free(shell->bgbuf); |
|
+ vim_shell_free(shell->charset); |
|
+ |
|
+ alt=shell->alt; |
|
+ *shell=*(shell->alt); |
|
+ shell->alt=NULL; |
|
+ |
|
+ vim_shell_free(alt); |
|
+ |
|
+ /* |
|
+ * Invalidate the shell so it will be fully redrawn |
|
+ */ |
|
+ shell->force_redraw=1; |
|
+} |
|
+ |
|
+/* |
|
+ * Erases the whole screen and homes the cursor. |
|
+ */ |
|
+static void terminal_init_screen(struct vim_shell_window *shell) |
|
+{ |
|
+ char ed_argv[20][20]; |
|
+ |
|
+ strcpy(ed_argv[0], "2"); |
|
+ |
|
+ /* |
|
+ * Erase all of the display. |
|
+ */ |
|
+ terminal_ED(shell, 1, ed_argv); |
|
+ |
|
+ /* |
|
+ * Cursor to HOME position. |
|
+ */ |
|
+ terminal_CUP(shell, 0, NULL); |
|
+} |
|
+ |
|
+static void terminal_mode(struct vim_shell_window *shell, int set, int argc, char argv[20][20]) |
|
+{ |
|
+ int i; |
|
+ |
|
+ for(i=0;i<argc;i++) |
|
+ { |
|
+ if(!strcmp(argv[i], "4")) |
|
+ { |
|
+ shell->insert_mode=set; |
|
+ ESCDEBUGPRINTF( "%s: insert mode: %d\n", __FUNCTION__, set); |
|
+ } |
|
+ else if(!strcmp(argv[i], "?1")) |
|
+ { |
|
+ shell->application_cursor_mode=set; |
|
+ ESCDEBUGPRINTF( "%s: application cursor mode: %d\n", __FUNCTION__, set); |
|
+ } |
|
+ else if(!strcmp(argv[i], "?5")) |
|
+ { |
|
+ ESCDEBUGPRINTF("%s: background dark/light mode ignored\n", __FUNCTION__); |
|
+ } |
|
+ else if(!strcmp(argv[i], "?6")) |
|
+ { |
|
+ ESCDEBUGPRINTF("%s: set terminal width ignored\n", __FUNCTION__); |
|
+ } |
|
+ else if(!strcmp(argv[i], "?7")) |
|
+ { |
|
+ shell->wraparound=set; |
|
+ ESCDEBUGPRINTF( "%s: wraparound: %d\n", __FUNCTION__, set); |
|
+ } |
|
+ else if(!strcmp(argv[i], "34") || !strcmp(argv[i], "?25")) |
|
+ { |
|
+ shell->cursor_visible=set; |
|
+ ESCDEBUGPRINTF( "%s: cursor visible: %d\n", __FUNCTION__, set); |
|
+ } |
|
+ else if(!strcmp(argv[i], "?4")) |
|
+ { |
|
+ ESCDEBUGPRINTF("%s: selection between smooth and jump scrolling ignored\n",__FUNCTION__); |
|
+ } |
|
+ else if(!strcmp(argv[i], "?1049") || !strcmp(argv[i], "?1047")) |
|
+ { |
|
+ if(set==1) |
|
+ { |
|
+ terminal_backup_screen(shell); |
|
+ terminal_init_screen(shell); |
|
+ ESCDEBUGPRINTF( "%s: terminal screen backed up.\n", __FUNCTION__); |
|
+ } |
|
+ else |
|
+ { |
|
+ terminal_restore_screen(shell); |
|
+ ESCDEBUGPRINTF( "%s: terminal screen restored from backup.\n", __FUNCTION__); |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: unimplemented terminal mode: %s\n", __FUNCTION__, argv[i]); |
|
+ } |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * EL . Erase In Line |
|
+ * ESC [ Ps K default value: 0 |
|
+ * |
|
+ * Erases some or all characters in the active line according to the parameter. Editor Function |
|
+ * |
|
+ * Parameter Parameter Meaning |
|
+ * 0 Erase from the active position to the end of the line, inclusive (default) |
|
+ * 1 Erase from the start of the line to the active position, inclusive |
|
+ * 2 Erase all of the line, inclusive |
|
+ */ |
|
+static void terminal_EL(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int i, size, pos; |
|
+ |
|
+ if(argc==0) |
|
+ i=0; |
|
+ else if(argc==1) |
|
+ i=strtol(argv[0], NULL, 10); |
|
+ else |
|
+ { |
|
+ /* |
|
+ * Error in sequence |
|
+ */ |
|
+ ESCDEBUGPRINTF( "%s: error in sequence\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ size=shell->size_x*shell->size_y; |
|
+ pos=shell->cursor_y*shell->size_x+shell->cursor_x; |
|
+ if(i==0) |
|
+ { |
|
+ /* |
|
+ * erase from the active position to the end of line |
|
+ */ |
|
+ |
|
+ memset(shell->winbuf+pos, ' ', shell->size_x-shell->cursor_x); |
|
+ memset(shell->fgbuf+pos, VIMSHELL_COLOR_DEFAULT, shell->size_x-shell->cursor_x); |
|
+ memset(shell->bgbuf+pos, VIMSHELL_COLOR_DEFAULT, shell->size_x-shell->cursor_x); |
|
+ memset(shell->rendbuf+pos, 0, shell->size_x-shell->cursor_x); |
|
+ memset(shell->charset+pos, 0, shell->size_x-shell->cursor_x); |
|
+ ESCDEBUGPRINTF( "%s: erase from active position to end of line\n", __FUNCTION__); |
|
+ |
|
+ } |
|
+ else if(i==1) |
|
+ { |
|
+ /* |
|
+ * erase from start of the line to the active position, inclusive |
|
+ */ |
|
+ |
|
+ memset(shell->winbuf+shell->cursor_y*shell->size_x, ' ', shell->cursor_x); |
|
+ memset(shell->fgbuf+ shell->cursor_y*shell->size_x, VIMSHELL_COLOR_DEFAULT, shell->cursor_x); |
|
+ memset(shell->bgbuf+ shell->cursor_y*shell->size_x, VIMSHELL_COLOR_DEFAULT, shell->cursor_x); |
|
+ memset(shell->rendbuf+shell->cursor_y*shell->size_x, 0, shell->cursor_x); |
|
+ memset(shell->charset+shell->cursor_y*shell->size_x, 0, shell->cursor_x); |
|
+ ESCDEBUGPRINTF( "%s: erase from start of line to active position\n", __FUNCTION__); |
|
+ } |
|
+ else if(i==2) |
|
+ { |
|
+ /* |
|
+ * Erase all of the line |
|
+ */ |
|
+ |
|
+ memset(shell->winbuf +shell->cursor_y*shell->size_x, ' ', shell->size_x); |
|
+ memset(shell->fgbuf +shell->cursor_y*shell->size_x, VIMSHELL_COLOR_DEFAULT, shell->size_x); |
|
+ memset(shell->bgbuf +shell->cursor_y*shell->size_x, VIMSHELL_COLOR_DEFAULT, shell->size_x); |
|
+ memset(shell->rendbuf+shell->cursor_y*shell->size_x, 0, shell->size_x); |
|
+ memset(shell->charset+shell->cursor_y*shell->size_x, 0, shell->size_x); |
|
+ ESCDEBUGPRINTF( "%s: erase all of the line\n", __FUNCTION__); |
|
+ } |
|
+ else |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: error in sequence (2)\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * ED . Erase In Display |
|
+ * ESC [ Ps J default value: 0 |
|
+ * |
|
+ * This sequence erases some or all of the characters in the display according |
|
+ * to the parameter. Any complete line erased by this sequence will return that |
|
+ * line to single width mode. Editor Function |
|
+ * |
|
+ * Parameter Parameter Meaning |
|
+ * 0 Erase from the active position to the end of the screen, inclusive (default) |
|
+ * 1 Erase from start of the screen to the active position, inclusive |
|
+ * 2 Erase all of the display . all lines are erased, changed to single-width, and the cursor does not move. |
|
+ */ |
|
+static void terminal_ED(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int i, size, pos; |
|
+ |
|
+ if(argc==0) |
|
+ i=0; |
|
+ else if(argc==1) |
|
+ i=strtol(argv[0], NULL, 10); |
|
+ else |
|
+ { |
|
+ /* |
|
+ * Error in sequence |
|
+ */ |
|
+ ESCDEBUGPRINTF( "%s: error in sequence\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ size=shell->size_x*shell->size_y; |
|
+ pos=shell->cursor_y*shell->size_x+shell->cursor_x; |
|
+ if(i==0) |
|
+ { |
|
+ /* |
|
+ * erase from the active position to the end of screen |
|
+ */ |
|
+ |
|
+ memset(shell->winbuf+pos, ' ', size-pos); |
|
+ memset(shell->fgbuf+pos, VIMSHELL_COLOR_DEFAULT, size-pos); |
|
+ memset(shell->bgbuf+pos, VIMSHELL_COLOR_DEFAULT, size-pos); |
|
+ memset(shell->rendbuf+pos, 0, size-pos); |
|
+ memset(shell->charset+pos, 0, size-pos); |
|
+ ESCDEBUGPRINTF( "%s: erase from active position to end of screen\n", __FUNCTION__); |
|
+ |
|
+ } |
|
+ else if(i==1) |
|
+ { |
|
+ /* |
|
+ * erase from start of the screen to the active position, inclusive |
|
+ */ |
|
+ |
|
+ memset(shell->winbuf, ' ', pos); |
|
+ memset(shell->fgbuf, VIMSHELL_COLOR_DEFAULT, pos); |
|
+ memset(shell->bgbuf, VIMSHELL_COLOR_DEFAULT, pos); |
|
+ memset(shell->rendbuf, 0, pos); |
|
+ memset(shell->charset, 0, pos); |
|
+ ESCDEBUGPRINTF( "%s: erase from start of screen to active position\n", __FUNCTION__); |
|
+ } |
|
+ else if(i==2) |
|
+ { |
|
+ /* |
|
+ * Erase all of the display |
|
+ */ |
|
+ |
|
+ memset(shell->winbuf, ' ', size); |
|
+ memset(shell->fgbuf, VIMSHELL_COLOR_DEFAULT, size); |
|
+ memset(shell->bgbuf, VIMSHELL_COLOR_DEFAULT, size); |
|
+ memset(shell->rendbuf, 0, size); |
|
+ memset(shell->charset, 0, size); |
|
+ ESCDEBUGPRINTF( "%s: erase all of the display\n", __FUNCTION__); |
|
+ } |
|
+ else |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: error in sequence (2)\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * CUP . Cursor Position |
|
+ * ESC [ Pn ; Pn H default value: 1 |
|
+ * |
|
+ * The CUP sequence moves the active position to the position specified by |
|
+ * the parameters. This sequence has two parameter values, the first specifying |
|
+ * the line position and the second specifying the column position. A parameter |
|
+ * value of zero or one for the first or second parameter moves the active |
|
+ * position to the first line or column in the display, respectively. The default |
|
+ * condition with no parameters present is equivalent to a cursor to home action. |
|
+ * In the VT100, this control behaves identically with its format effector |
|
+ * counterpart, HVP. Editor Function |
|
+ * |
|
+ * The numbering of lines depends on the state of the Origin Mode (DECOM). |
|
+ */ |
|
+static void terminal_CUP(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ if(argc==0) |
|
+ { |
|
+ /* |
|
+ * goto home position |
|
+ */ |
|
+ shell->cursor_x=0; |
|
+ shell->cursor_y=0; |
|
+ } |
|
+ else if(argc==2) |
|
+ { |
|
+ int x, y; |
|
+ |
|
+ y=strtol(argv[0], NULL, 10); |
|
+ x=strtol(argv[1], NULL, 10); |
|
+ if(x==0) |
|
+ x++; |
|
+ if(y==0) |
|
+ y++; |
|
+ |
|
+ shell->cursor_y=y-1; |
|
+ shell->cursor_x=x-1; |
|
+ |
|
+ // VIMSHELL TODO: if origin mode enabled, position at the |
|
+ // top margin or so :) |
|
+ |
|
+ if(shell->cursor_x>=shell->size_x) |
|
+ shell->cursor_x=shell->size_x-1; |
|
+ if(shell->cursor_y>=shell->size_y) |
|
+ shell->cursor_y=shell->size_y-1; |
|
+ } |
|
+ else |
|
+ { |
|
+ /* |
|
+ * Error in sequence |
|
+ */ |
|
+ ESCDEBUGPRINTF( "%s: error in sequence\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ ESCDEBUGPRINTF( "%s: moved to X = %d, Y = %d\n", __FUNCTION__, shell->cursor_x, shell->cursor_y); |
|
+} |
|
+ |
|
+/* |
|
+ * DECSTBM . Set Top and Bottom Margins (DEC Private) |
|
+ * ESC [ Pn; Pn r default values: see below |
|
+ * |
|
+ * This sequence sets the top and bottom margins to define the scrolling region. |
|
+ * The first parameter is the line number of the first line in the scrolling region; the |
|
+ * second parameter is the line number of the bottom line in the scrolling region. Default |
|
+ * is the entire screen (no margins). The minimum size of the scrolling region allowed is |
|
+ * two lines, i.e., the top margin must be less than the bottom margin. The cursor is placed |
|
+ * in the home position (see Origin Mode DECOM). |
|
+ */ |
|
+static void terminal_DECSTBM(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ if(argc!=2) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ shell->scroll_top_margin=strtol(argv[0], NULL, 10)-1; |
|
+ shell->scroll_bottom_margin=strtol(argv[1], NULL, 10)-1; |
|
+ |
|
+ ESCDEBUGPRINTF( "%s: top margin = %d, bottom margin = %d\n", __FUNCTION__, |
|
+ shell->scroll_top_margin, shell->scroll_bottom_margin); |
|
+ |
|
+ if(shell->scroll_top_margin>=shell->scroll_bottom_margin) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: scroll margin error %d >= %d\n", __FUNCTION__, |
|
+ shell->scroll_top_margin, shell->scroll_bottom_margin); |
|
+ |
|
+ shell->scroll_top_margin=0; |
|
+ shell->scroll_bottom_margin=shell->size_y-1; |
|
+ |
|
+ return; |
|
+ } |
|
+ |
|
+ // Move cursor into home position |
|
+ terminal_CUP(shell, 0, NULL); |
|
+} |
|
+ |
|
+ |
|
+// Status: 100% |
|
+static void terminal_scroll_up(struct vim_shell_window *shell) |
|
+{ |
|
+ // VIMSHELL TODO: maintain a scrollback buffer? copy the first line into |
|
+ // a scrollback buffer. |
|
+ |
|
+ /* |
|
+ * scroll up by moving up the screen buffer a whole line. blank out |
|
+ * the last line. |
|
+ */ |
|
+ int len, from, to; |
|
+ |
|
+ ESCDEBUGPRINTF( "%s: done\n", __FUNCTION__); |
|
+ |
|
+ len=shell->scroll_bottom_margin-shell->scroll_top_margin; |
|
+ len*=shell->size_x; |
|
+ |
|
+ to=shell->scroll_top_margin*shell->size_x; |
|
+ from=shell->size_x+shell->scroll_top_margin*shell->size_x; |
|
+ |
|
+ memmove(shell->winbuf+to, shell->winbuf+from, len); |
|
+ memmove(shell->fgbuf+to, shell->fgbuf+from, len); |
|
+ memmove(shell->bgbuf+to, shell->bgbuf+from, len); |
|
+ memmove(shell->rendbuf+to, shell->rendbuf+from, len); |
|
+ memmove(shell->charset+to, shell->charset+from, len); |
|
+ |
|
+ memset(shell->winbuf+shell->scroll_bottom_margin*shell->size_x, ' ', shell->size_x); |
|
+ memset(shell->fgbuf+shell->scroll_bottom_margin*shell->size_x, VIMSHELL_COLOR_DEFAULT, shell->size_x); |
|
+ memset(shell->bgbuf+shell->scroll_bottom_margin*shell->size_x, VIMSHELL_COLOR_DEFAULT, shell->size_x); |
|
+ memset(shell->rendbuf+shell->scroll_bottom_margin*shell->size_x, 0, shell->size_x); |
|
+ memset(shell->charset+shell->scroll_bottom_margin*shell->size_x, 0, shell->size_x); |
|
+} |
|
+ |
|
+// Status: unknown |
|
+static void terminal_scroll_down(struct vim_shell_window *shell) |
|
+{ |
|
+ /* |
|
+ * scroll down by moving the screen buffer down a whole line, overwriting |
|
+ * the last line. Then, blank out the first line. |
|
+ */ |
|
+ size_t len; |
|
+ int from, to; |
|
+ |
|
+ ESCDEBUGPRINTF( "%s: done\n", __FUNCTION__); |
|
+ |
|
+ len=shell->scroll_bottom_margin-shell->scroll_top_margin; |
|
+ len*=shell->size_x; |
|
+ |
|
+ to=shell->scroll_top_margin*shell->size_x+shell->size_x; |
|
+ from=shell->scroll_top_margin*shell->size_x; |
|
+ |
|
+ memmove(shell->winbuf+to, shell->winbuf+from, len); |
|
+ memmove(shell->fgbuf+to, shell->fgbuf+from, len); |
|
+ memmove(shell->bgbuf+to, shell->bgbuf+from, len); |
|
+ memmove(shell->rendbuf+to, shell->rendbuf+from, len); |
|
+ memmove(shell->charset+to, shell->charset+from, len); |
|
+ |
|
+ memset(shell->winbuf+from, ' ', shell->size_x); |
|
+ memset(shell->fgbuf+from, VIMSHELL_COLOR_DEFAULT, shell->size_x); |
|
+ memset(shell->bgbuf+from, VIMSHELL_COLOR_DEFAULT, shell->size_x); |
|
+ memset(shell->rendbuf+from, 0, shell->size_x); |
|
+ memset(shell->charset+from, 0, shell->size_x); |
|
+} |
|
+ |
|
+/* |
|
+ * Insert Line(s) (ANSI). |
|
+ * ESC [ Pn L |
|
+ * Inserts Pn lines at the cursor. If fewer than Pn lines remain from the current line to the |
|
+ * end of the scrolling region, the number of lines inserted is the lesser number. Lines within |
|
+ * the scrolling region at and below the cursor move down. Lines moved past the bottom margin |
|
+ * are lost. The cursor is reset to the first column. This sequence is ignored when the |
|
+ * cursor is outside the scrolling region. |
|
+ */ |
|
+// Status: unknown |
|
+static void terminal_IL(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int lines, bak_top; |
|
+ if(argc>1) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ if(argc==0) |
|
+ lines=1; |
|
+ else |
|
+ { |
|
+ lines=strtol(argv[0], NULL, 10); |
|
+ if(lines==0) |
|
+ lines=1; |
|
+ } |
|
+ |
|
+ if(shell->scroll_bottom_margin-shell->cursor_y < lines) |
|
+ lines=shell->scroll_bottom_margin-shell->cursor_y; |
|
+ |
|
+ bak_top=shell->scroll_top_margin; |
|
+ |
|
+ ESCDEBUGPRINTF( "%s: inserted %d lines\n", __FUNCTION__, lines); |
|
+ |
|
+ /* |
|
+ * Set a scrolling region around the part we want to move and scroll down 'lines' times. |
|
+ */ |
|
+ shell->scroll_top_margin=shell->cursor_y; |
|
+ while(lines--) |
|
+ terminal_scroll_down(shell); |
|
+ |
|
+ shell->scroll_top_margin=bak_top; |
|
+ |
|
+ shell->cursor_x=0; |
|
+} |
|
+ |
|
+/* |
|
+ * Delete Line(s) (ANSI). |
|
+ * ESC [ Pn M |
|
+ * Deletes Pn lines starting at the line with the cursor. If fewer than Pn lines remain from |
|
+ * the current line to the end of the scrolling region, the number of lines deleted is the |
|
+ * lesser number. As lines are deleted, lines within the scrolling region and below the cursor move |
|
+ * up, and blank lines are added at the bottom of the scrolling region. The cursor is reset to the |
|
+ * first column. This sequence is ignored when the cursor is outside the scrolling region. |
|
+ * VIMSHELL TODO last sentence |
|
+ */ |
|
+// Status: unknown |
|
+static void terminal_DL(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int lines, bak_top; |
|
+ if(argc>1) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ if(argc==0) |
|
+ lines=1; |
|
+ else |
|
+ { |
|
+ lines=strtol(argv[0], NULL, 10); |
|
+ if(lines==0) |
|
+ lines=1; |
|
+ } |
|
+ |
|
+ if(shell->scroll_bottom_margin-shell->cursor_y < lines) |
|
+ lines=shell->scroll_bottom_margin-shell->cursor_y; |
|
+ |
|
+ bak_top=shell->scroll_top_margin; |
|
+ |
|
+ ESCDEBUGPRINTF( "%s: deleted %d lines\n", __FUNCTION__, lines); |
|
+ |
|
+ /* |
|
+ * Set a scrolling region around the part we want to move and scroll up 'lines' times. |
|
+ */ |
|
+ shell->scroll_top_margin=shell->cursor_y; |
|
+ while(lines--) |
|
+ terminal_scroll_up(shell); |
|
+ |
|
+ shell->scroll_top_margin=bak_top; |
|
+ |
|
+ shell->cursor_x=0; |
|
+} |
|
+ |
|
+/* |
|
+ * Insert Characters (ANSI) |
|
+ * ESC [ Pn @ |
|
+ * Insert Pn blank characters at the cursor position, with the character attributes set to |
|
+ * normal. The cursor does not move and remains at the beginning of the inserted blank characters. |
|
+ * A parameter of 0 or 1 inserts one blank character. Data on the line is shifted forward as |
|
+ * in character insertion. |
|
+ */ |
|
+static void terminal_ICH(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int chars; |
|
+ int curpos; |
|
+ size_t len; |
|
+ if(argc>1) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ if(argc==0) |
|
+ chars=1; |
|
+ else |
|
+ { |
|
+ chars=strtol(argv[0], NULL, 10); |
|
+ if(chars==0) |
|
+ chars=1; |
|
+ } |
|
+ |
|
+ curpos=shell->cursor_y*shell->size_x+shell->cursor_x; |
|
+ len=shell->size_x-shell->cursor_x-1; |
|
+ |
|
+ ESCDEBUGPRINTF( "%s: inserted %d characters\n", __FUNCTION__, chars); |
|
+ |
|
+ while(chars--) |
|
+ { |
|
+ memmove(shell->winbuf+curpos+1, shell->winbuf+curpos, len); |
|
+ memmove(shell->fgbuf+curpos+1, shell->fgbuf+curpos, len); |
|
+ memmove(shell->bgbuf+curpos+1, shell->bgbuf+curpos, len); |
|
+ memmove(shell->rendbuf+curpos+1, shell->rendbuf+curpos, len); |
|
+ memmove(shell->charset+curpos+1, shell->charset+curpos, len); |
|
+ |
|
+ memset(shell->winbuf+curpos, ' ', 1); |
|
+ memset(shell->fgbuf+curpos, VIMSHELL_COLOR_DEFAULT, 1); |
|
+ memset(shell->bgbuf+curpos, VIMSHELL_COLOR_DEFAULT, 1); |
|
+ memset(shell->rendbuf+curpos, 0, 1); |
|
+ memset(shell->charset+curpos, 0, 1); |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * Delete Characters (ANSI) |
|
+ * ESC [ Pn P |
|
+ * Deletes Pn characters starting with the character at the cursor position. When a character |
|
+ * is deleted, all characters to the right of the cursor move to the left. This creates a space |
|
+ * character at the right margin for each character deleted. Character attributes move with the |
|
+ * characters. The spaces created at the end of the line have all their character attributes off. |
|
+ */ |
|
+static void terminal_DCH(struct vim_shell_window *shell, int argc, char argv[20][20]) |
|
+{ |
|
+ int chars; |
|
+ int curpos; |
|
+ size_t len; |
|
+ if(argc>1) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence error\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ if(argc==0) |
|
+ chars=1; |
|
+ else |
|
+ { |
|
+ chars=strtol(argv[0], NULL, 10); |
|
+ if(chars==0) |
|
+ chars=1; |
|
+ } |
|
+ |
|
+ curpos=shell->cursor_y*shell->size_x+shell->cursor_x; |
|
+ len=shell->size_x-shell->cursor_x-1; |
|
+ |
|
+ ESCDEBUGPRINTF( "%s: deleted %d characters\n", __FUNCTION__, chars); |
|
+ |
|
+ while(chars--) |
|
+ { |
|
+ memmove(shell->winbuf+curpos, shell->winbuf+curpos+1, len); |
|
+ memmove(shell->fgbuf+curpos, shell->fgbuf+curpos+1, len); |
|
+ memmove(shell->bgbuf+curpos, shell->bgbuf+curpos+1, len); |
|
+ memmove(shell->rendbuf+curpos, shell->rendbuf+curpos+1, len); |
|
+ memmove(shell->charset+curpos, shell->charset+curpos+1, len); |
|
+ |
|
+ memset(shell->winbuf+curpos+len, ' ', 1); |
|
+ memset(shell->fgbuf+curpos+len, VIMSHELL_COLOR_DEFAULT, 1); |
|
+ memset(shell->bgbuf+curpos+len, VIMSHELL_COLOR_DEFAULT, 1); |
|
+ memset(shell->rendbuf+curpos+len, 0, 1); |
|
+ memset(shell->charset+curpos+len, 0, 1); |
|
+ } |
|
+} |
|
+ |
|
+static void terminal_BEL(struct vim_shell_window *shell) |
|
+{ |
|
+ /* |
|
+ * "Sound bell tone from keyboard." |
|
+ * Sure. |
|
+ */ |
|
+} |
|
+ |
|
+static void terminal_BS(struct vim_shell_window *shell) |
|
+{ |
|
+ /* |
|
+ * "Move the cursor to the left one character position, |
|
+ * unless it is at the left margin, in which case no action occurs." |
|
+ */ |
|
+ if(shell->cursor_x>0) |
|
+ shell->cursor_x--; |
|
+} |
|
+ |
|
+static void terminal_LF(struct vim_shell_window *shell) |
|
+{ |
|
+ /* |
|
+ * "This code causes a line feed or a new line operation." |
|
+ */ |
|
+ |
|
+ if(shell->just_wrapped_around==1) |
|
+ { |
|
+ /* |
|
+ * Terminals which have the xenl capability ignore a linefeed after |
|
+ * an auto margin wrap. |
|
+ */ |
|
+ VERBOSEPRINTF( "%s: ignored LF because of earlier wrap around\n", |
|
+ __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ shell->cursor_y++; |
|
+ if(shell->cursor_y-1==shell->scroll_bottom_margin) |
|
+ { |
|
+ shell->cursor_y--; |
|
+ terminal_scroll_up(shell); |
|
+ } |
|
+ |
|
+ VERBOSEPRINTF( "%s: did LF, cursor is now at X = %u, Y = %u\n", __FUNCTION__, |
|
+ shell->cursor_x, shell->cursor_y); |
|
+} |
|
+ |
|
+static void terminal_CR(struct vim_shell_window *shell) |
|
+{ |
|
+ /* |
|
+ * "Move cursor to the left margin on the current line." |
|
+ */ |
|
+ if(shell->just_wrapped_around==1) |
|
+ { |
|
+ /* |
|
+ * Terminals which have the xenl capability ignore a linefeed after |
|
+ * an auto margin wrap. |
|
+ */ |
|
+ VERBOSEPRINTF( "%s: ignored CR because of earlier wrap around\n", |
|
+ __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ shell->cursor_x=0; |
|
+ VERBOSEPRINTF( "%s: did CR, cursor is now at X = %u, Y = %u\n", __FUNCTION__, |
|
+ shell->cursor_x, shell->cursor_y); |
|
+} |
|
+ |
|
+/* |
|
+ * RI . Reverse Index |
|
+ * ESC M |
|
+ * |
|
+ * Move the active position to the same horizontal position on the preceding line. If the |
|
+ * active position is at the top margin, a scroll down is performed. Format Effector |
|
+ */ |
|
+static void terminal_RI(struct vim_shell_window *shell) |
|
+{ |
|
+ ESCDEBUGPRINTF( "%s: done\n", __FUNCTION__); |
|
+ if(shell->cursor_y==shell->scroll_top_margin) |
|
+ terminal_scroll_down(shell); |
|
+ else |
|
+ shell->cursor_y--; |
|
+} |
|
+ |
|
+/* |
|
+ * IND . Index |
|
+ * ESC D |
|
+ * |
|
+ * This sequence causes the active position to move downward one line without changing the |
|
+ * column position. If the active position is at the bottom margin, a scroll up is performed. |
|
+ * Format Effector |
|
+ */ |
|
+static void terminal_IND(struct vim_shell_window *shell) |
|
+{ |
|
+ ESCDEBUGPRINTF( "%s: done\n", __FUNCTION__); |
|
+ if(shell->cursor_y==shell->scroll_bottom_margin) |
|
+ terminal_scroll_up(shell); |
|
+ else |
|
+ shell->cursor_y++; |
|
+} |
|
+ |
|
+/* |
|
+ * ESC 7 |
|
+ * ESC [s (ANSI) |
|
+ * Saves the current terminal rendering settings |
|
+ */ |
|
+static void terminal_save_attributes(struct vim_shell_window *shell) |
|
+{ |
|
+ shell->saved_cursor_x=shell->cursor_x; |
|
+ shell->saved_cursor_y=shell->cursor_y; |
|
+ shell->saved_rendition=shell->rendition; |
|
+ shell->saved_fgcolor=shell->fgcolor; |
|
+ shell->saved_bgcolor=shell->bgcolor; |
|
+ shell->saved_G0_charset=shell->G0_charset; |
|
+ shell->saved_G1_charset=shell->G1_charset; |
|
+ shell->saved_application_keypad_mode=shell->application_keypad_mode; |
|
+ shell->saved_application_cursor_mode=shell->application_cursor_mode; |
|
+ shell->saved_insert_mode=shell->insert_mode; |
|
+} |
|
+ |
|
+/* |
|
+ * ESC 8 |
|
+ * ESC [u (ANSI) |
|
+ * Restores the current terminal rendering settings |
|
+ */ |
|
+static void terminal_restore_attributes(struct vim_shell_window *shell) |
|
+{ |
|
+ shell->cursor_x=shell->saved_cursor_x; |
|
+ shell->cursor_y=shell->saved_cursor_y; |
|
+ shell->rendition=shell->saved_rendition; |
|
+ shell->fgcolor=shell->saved_fgcolor; |
|
+ shell->bgcolor=shell->saved_bgcolor; |
|
+ shell->G0_charset=shell->saved_G0_charset; |
|
+ shell->G1_charset=shell->saved_G1_charset; |
|
+ shell->application_keypad_mode=shell->saved_application_keypad_mode; |
|
+ shell->application_cursor_mode=shell->saved_application_cursor_mode; |
|
+ shell->insert_mode=shell->saved_insert_mode; |
|
+} |
|
+ |
|
+#define ADVANCE_PSEQ { pseq++; if(*pseq==0) return; } |
|
+ |
|
+/* |
|
+ * Attempts to parse the escape sequence stored in shell->esc_sequence. |
|
+ * When it succeeds, it removes that escape sequence from the buffer and |
|
+ * possibly clears shell->in_esc_sequence when there are no characters left, |
|
+ * leaving ESC mode. |
|
+ */ |
|
+static void terminal_parse_esc_sequence(struct vim_shell_window *shell) |
|
+{ |
|
+ char *pseq; |
|
+ |
|
+ if(shell->in_esc_sequence==0 || shell->esc_sequence[0]!=033) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: invalid esc sequence in esc buffer\n", |
|
+ __FUNCTION__); |
|
+ /* |
|
+ * We would stick here forever, so flush the buffer |
|
+ */ |
|
+ shell->in_esc_sequence=0; |
|
+ terminal_flush_output(shell); |
|
+ |
|
+ return; |
|
+ } |
|
+ |
|
+ if(shell->in_esc_sequence==1) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: not much in the buffer ...\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ |
|
+ shell->esc_sequence[shell->in_esc_sequence]=0; |
|
+ pseq=shell->esc_sequence+1; |
|
+ |
|
+ if(*pseq=='[') |
|
+ { |
|
+ /* |
|
+ * Got a Control Sequence Introducer (CSI) = ESC [ |
|
+ * Parse Parameters. |
|
+ */ |
|
+ |
|
+ int argc=0; |
|
+ char argv[20][20]; |
|
+ |
|
+ ADVANCE_PSEQ; |
|
+ |
|
+ memset(argv, 0, sizeof(argv)); |
|
+ |
|
+ if((*pseq>='0' && *pseq<='9') || *pseq=='?' || *pseq==';') |
|
+ { |
|
+ int cont; |
|
+ do |
|
+ { |
|
+ cont=0; |
|
+ while((*pseq>='0' && *pseq<='9') || *pseq=='?') |
|
+ { |
|
+ char dummy[2]; |
|
+ dummy[0]=*pseq; |
|
+ dummy[1]=0; |
|
+ strcat(argv[argc], dummy); |
|
+ ADVANCE_PSEQ; |
|
+ } |
|
+ if(argv[argc][0]==0) |
|
+ { |
|
+ strcpy(argv[argc], "0"); |
|
+ } |
|
+ |
|
+ argc++; |
|
+ if(*pseq==';') |
|
+ { |
|
+ cont=1; |
|
+ ADVANCE_PSEQ; |
|
+ } |
|
+ } while(cont==1); |
|
+ } |
|
+ |
|
+#ifdef ESCDEBUG |
|
+ ESCDEBUGPRINTF("%s: sequence = '%s', argc = %d, ", __FUNCTION__, shell->esc_sequence, argc); |
|
+ { |
|
+ int i; |
|
+ for(i=0;i<argc;i++) |
|
+ { |
|
+ ESCDEBUGPRINTF("argv[%d] = '%s', ",i, argv[i]); |
|
+ } |
|
+ } |
|
+ ESCDEBUGPRINTF("\n"); |
|
+#endif |
|
+ |
|
+ switch(*pseq) |
|
+ { |
|
+ case 'f': |
|
+ case 'H': |
|
+ terminal_CUP(shell, argc, argv); |
|
+ break; |
|
+ case 'J': |
|
+ terminal_ED(shell, argc, argv); |
|
+ break; |
|
+ case 'K': |
|
+ terminal_EL(shell, argc, argv); |
|
+ break; |
|
+ case 'C': |
|
+ terminal_CUF(shell, argc, argv); |
|
+ break; |
|
+ case 'l': |
|
+ terminal_mode(shell, 0, argc, argv); |
|
+ break; |
|
+ case 'h': |
|
+ terminal_mode(shell, 1, argc, argv); |
|
+ break; |
|
+ case 'm': |
|
+ terminal_SGR(shell, argc, argv); |
|
+ break; |
|
+ case 'r': // set scroll margins |
|
+ terminal_DECSTBM(shell, argc, argv); |
|
+ break; |
|
+ case 'B': // cursor down |
|
+ terminal_CUD(shell, argc, argv); |
|
+ break; |
|
+ case 'D': // cursor backward |
|
+ terminal_CUB(shell, argc, argv); |
|
+ break; |
|
+ case 'A': // cursor up |
|
+ terminal_CUU(shell, argc, argv); |
|
+ break; |
|
+ case 'M': // delete line |
|
+ terminal_DL(shell, argc, argv); |
|
+ break; |
|
+ case 'L': // insert line |
|
+ terminal_IL(shell, argc, argv); |
|
+ break; |
|
+ case '@': // insert characters |
|
+ terminal_ICH(shell, argc, argv); |
|
+ break; |
|
+ case 'P': // delete characters |
|
+ terminal_DCH(shell, argc, argv); |
|
+ break; |
|
+ case 'E': // new line |
|
+ terminal_CR(shell); |
|
+ terminal_LF(shell); |
|
+ break; |
|
+ case 's': // Save Cursor and attributes |
|
+ terminal_save_attributes(shell); |
|
+ break; |
|
+ case 'u': // Restore Cursor and attributes |
|
+ terminal_restore_attributes(shell); |
|
+ break; |
|
+ case 'g': // Tabulator clear |
|
+ terminal_TBC(shell, argc, argv); |
|
+ break; |
|
+ default: |
|
+ ESCDEBUGPRINTF( "%s: unimplemented CSI code: %c\n", |
|
+ __FUNCTION__, *pseq); |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: sequence is (probably not yet complete) '%s'\n", |
|
+ __FUNCTION__, shell->esc_sequence); |
|
+ switch(*pseq) |
|
+ { |
|
+ case '#': |
|
+ ADVANCE_PSEQ; |
|
+ if(*pseq=='8') // fill screen with E's |
|
+ { |
|
+ memset(shell->winbuf, 'E', shell->size_x*shell->size_y); |
|
+ } |
|
+ break; |
|
+ case '(': // switch G0 charset |
|
+ ADVANCE_PSEQ; |
|
+ shell->G0_charset=*pseq; |
|
+ ESCDEBUGPRINTF( "%s: G0 character set is now: %c\n", __FUNCTION__, *pseq); |
|
+ break; |
|
+ case ')': // switch G1 charset |
|
+ ADVANCE_PSEQ; |
|
+ shell->G1_charset=*pseq; |
|
+ ESCDEBUGPRINTF( "%s: G1 character set is now: %c\n", __FUNCTION__, *pseq); |
|
+ break; |
|
+ case 'D': // index |
|
+ terminal_IND(shell); |
|
+ break; |
|
+ case 'M': // reverse index |
|
+ terminal_RI(shell); |
|
+ break; |
|
+ case '7': // Save Cursor |
|
+ terminal_save_attributes(shell); |
|
+ break; |
|
+ case '8': // Restore Cursor |
|
+ terminal_restore_attributes(shell); |
|
+ break; |
|
+ case '=': // Application Keypad Mode |
|
+ shell->application_keypad_mode=1; |
|
+ ESCDEBUGPRINTF( "%s: keypad switched to application mode\n", __FUNCTION__); |
|
+ break; |
|
+ case '>': // Numeric Keypad Mode |
|
+ shell->application_keypad_mode=0; |
|
+ ESCDEBUGPRINTF( "%s: keypad switched to numeric mode\n", __FUNCTION__); |
|
+ break; |
|
+ case 'H': // Set Horizontal Tab |
|
+ shell->tabline[shell->cursor_x]=1; |
|
+ break; |
|
+ case 'E': // NEL - Moves cursor to first position on next line. If cursor is |
|
+ // at bottom margin, screen performs a scroll-up. |
|
+ terminal_IND(shell); |
|
+ shell->cursor_x=0; |
|
+ break; |
|
+ case ']': // This could be the beginning of the xterm title hack |
|
+ ADVANCE_PSEQ; |
|
+ if(*pseq=='1' || *pseq=='2' || *pseq=='0') |
|
+ { |
|
+ char title[50]; |
|
+ ADVANCE_PSEQ; |
|
+ if(*pseq==';') |
|
+ { |
|
+ int end; |
|
+ title[0]=0; |
|
+ /* |
|
+ * I know this loop is ugly but ADVANCE_PSEQ |
|
+ * is a macro, sorry |
|
+ */ |
|
+ for(end=0;!end;) |
|
+ { |
|
+ ADVANCE_PSEQ; |
|
+ if(strlen(title)>sizeof(title)-2) |
|
+ end=1; |
|
+ if(*pseq==7) |
|
+ end=1; |
|
+ else |
|
+ { |
|
+ char dummy[2]; |
|
+ dummy[0]=*pseq; |
|
+ dummy[1]=0; |
|
+ strcat(title, dummy); |
|
+ } |
|
+ } |
|
+ |
|
+ snprintf(shell->windowtitle, sizeof(shell->windowtitle), |
|
+ "%s", title); |
|
+ |
|
+ ESCDEBUGPRINTF( "%s: changing title to '%s'\n", |
|
+ __FUNCTION__, shell->windowtitle); |
|
+ } |
|
+ else |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: error in xterm title hack " |
|
+ "sequence: %c\n", __FUNCTION__, *pseq); |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: unimplemented xterm title hack " |
|
+ "code: %d\n", __FUNCTION__, *pseq); |
|
+ } |
|
+ break; |
|
+ default: |
|
+ ESCDEBUGPRINTF( "%s: unimplemented esc code: %c\n", |
|
+ __FUNCTION__, *pseq); |
|
+ } |
|
+ } |
|
+ |
|
+ /* |
|
+ * when we end up here, we successfully completed the sequence. |
|
+ */ |
|
+ shell->in_esc_sequence=0; |
|
+ terminal_flush_output(shell); |
|
+ |
|
+#ifdef ESCDEBUG |
|
+ pseq++; |
|
+ if(*pseq!=0) |
|
+ { |
|
+ ESCDEBUGPRINTF( "WARNING: %s: sequence is not over! left in buffer: '%s'\n", |
|
+ __FUNCTION__, pseq); |
|
+ } |
|
+#endif |
|
+} |
|
+ |
|
+ |
|
+/* |
|
+ * Main character write part. |
|
+ * This here runs most of the time, just writing the character to the |
|
+ * right cursor position. |
|
+ */ |
|
+static void terminal_normal_char(struct vim_shell_window *shell, char input) |
|
+{ |
|
+ int pos; |
|
+ uint8_t charset; |
|
+ |
|
+ shell->just_wrapped_around=0; |
|
+ /* |
|
+ * If the cursor is currently in the 'virtual' column (that is the column |
|
+ * after the physical line end), we wrap around now. |
|
+ */ |
|
+ if(shell->cursor_x==shell->size_x) |
|
+ { |
|
+ if(shell->wraparound==1) |
|
+ { |
|
+ terminal_CR(shell); |
|
+ terminal_LF(shell); |
|
+ shell->just_wrapped_around=1; |
|
+ VERBOSEPRINTF( "%s: auto margin - wrapped around!\n",__FUNCTION__); |
|
+ } |
|
+ else |
|
+ { |
|
+ shell->cursor_x--; |
|
+ } |
|
+ } |
|
+ |
|
+ /* |
|
+ * write the character at its right position. |
|
+ */ |
|
+ if(shell->insert_mode!=0) |
|
+ { |
|
+ /* |
|
+ * If insert mode is on, move all characters from the current position+1 to |
|
+ * the end of the row. The last character on the row falls out. |
|
+ * Fortunately, we already implemented this kind of operation :) |
|
+ */ |
|
+ terminal_ICH(shell, 0, NULL); |
|
+ } |
|
+ pos=shell->cursor_y*shell->size_x+shell->cursor_x; |
|
+ |
|
+ /* |
|
+ * Select which character to display. |
|
+ */ |
|
+ if(shell->active_charset==1) |
|
+ charset=shell->G1_charset=='0' ? VIMSHELL_CHARSET_DRAWING : VIMSHELL_CHARSET_USASCII; |
|
+ else |
|
+ charset=shell->G0_charset=='0' ? VIMSHELL_CHARSET_DRAWING : VIMSHELL_CHARSET_USASCII; |
|
+ |
|
+ shell->winbuf[pos]=input; |
|
+ shell->fgbuf[pos]=shell->fgcolor; |
|
+ shell->bgbuf[pos]=shell->bgcolor; |
|
+ shell->rendbuf[pos]=shell->rendition; |
|
+ shell->charset[pos]=charset; |
|
+ VERBOSEPRINTF( "%s: writing char '%c' to position X = %u, Y = %u (col: 0x%02x,0x%02x)\n", __FUNCTION__, |
|
+ input, shell->cursor_x, shell->cursor_y, current_fg, current_bg); |
|
+ shell->cursor_x++; |
|
+} |
|
+ |
|
+/* |
|
+ * Here, all characters between 000 and 037 are processed. This is in a |
|
+ * separate function because control characters can be in the normal |
|
+ * flow of characters or in the middle of escape sequences. |
|
+ */ |
|
+static void terminal_process_control_char(struct vim_shell_window *shell, char input) |
|
+{ |
|
+ switch(input) |
|
+ { |
|
+ case 007: // BEL, Bell, 0x07 |
|
+ terminal_BEL(shell); |
|
+ break; |
|
+ case 010: // BS, Backspace, 0x08 |
|
+ terminal_BS(shell); |
|
+ break; |
|
+ case 011: // TAB |
|
+ { |
|
+ /* |
|
+ * Move to the next tabstop or stop at the right margin if no |
|
+ * tabstop found. |
|
+ */ |
|
+ int i, found; |
|
+ for(found=0, i=shell->cursor_x+1;i<shell->size_x && !found;i++) |
|
+ { |
|
+ if(shell->tabline[i]==1) |
|
+ { |
|
+ shell->cursor_x=i; |
|
+ found=1; |
|
+ } |
|
+ } |
|
+ if(found==0) |
|
+ { |
|
+ shell->cursor_x=shell->size_x-1; |
|
+ } |
|
+ } |
|
+ break; |
|
+ case 013: |
|
+ case 014: |
|
+ case 012: // LF, Line Feed, 0x0a, \n |
|
+ terminal_LF(shell); |
|
+ break; |
|
+ case 015: // CR, Carriage Return, 0x0d, \r |
|
+ terminal_CR(shell); |
|
+ break; |
|
+ case 016: // SO, Invoke G1 character set, as designated by SCS control sequence. |
|
+ shell->active_charset=1; |
|
+ break; |
|
+ case 017: // SI, Select G0 character set, as selected by ESC ( sequence. |
|
+ shell->active_charset=0; |
|
+ break; |
|
+ case 030: |
|
+ case 032: // CAN or SUB - cancel escape sequence |
|
+ shell->in_esc_sequence=0; |
|
+ // VIMSHELL TODO: display substitution character? |
|
+ ESCDEBUGPRINTF("%s: WARNING: possible source of rendering faults: " |
|
+ "substitution characters after CAN or SUB?\n", __FUNCTION__); |
|
+ break; |
|
+ case 033: // ESC, Escape |
|
+ /* |
|
+ * Note: This also fulfills the requirement that a ESC occuring while processing |
|
+ * an escape sequence should restart the sequence. |
|
+ */ |
|
+ shell->in_esc_sequence=1; |
|
+ shell->esc_sequence[0]=033; |
|
+ break; |
|
+ default: |
|
+ ESCDEBUGPRINTF("%s: unimplemented control character: %u\n", __FUNCTION__, input); |
|
+ break; |
|
+ } |
|
+} |
|
+ |
|
+static void terminal_input_char(struct vim_shell_window *shell, char input) |
|
+{ |
|
+ if(shell->in_esc_sequence==0) |
|
+ { |
|
+ if(input>=0 && input<=037) |
|
+ { |
|
+ /* |
|
+ * A control character, process it |
|
+ */ |
|
+ terminal_process_control_char(shell, input); |
|
+ } |
|
+ else |
|
+ { |
|
+ // all normal characters are processed here |
|
+ terminal_normal_char(shell, input); |
|
+ } |
|
+ } |
|
+ else |
|
+ { |
|
+ if(input>=0 && input<=037) |
|
+ { |
|
+ /* |
|
+ * That's right, control characters can appear even in |
|
+ * the middle of escape sequences. |
|
+ */ |
|
+ terminal_process_control_char(shell, input); |
|
+ return; |
|
+ } |
|
+ |
|
+ /* |
|
+ * Aha, we are right in the middle of an escape sequence. |
|
+ * Add this character and attempt to parse the sequence. |
|
+ */ |
|
+ shell->esc_sequence[shell->in_esc_sequence]=input; |
|
+ shell->in_esc_sequence++; |
|
+ |
|
+ if(shell->in_esc_sequence>=sizeof(shell->esc_sequence)) |
|
+ { |
|
+ /* |
|
+ * about to overrun esc sequence buffer ... |
|
+ * Should never happen, but still: kill the sequence, or we'd loop |
|
+ * forever. |
|
+ */ |
|
+ |
|
+ shell->in_esc_sequence=0; |
|
+ terminal_flush_output(shell); |
|
+ return; |
|
+ } |
|
+ |
|
+ terminal_parse_esc_sequence(shell); |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * If we are ready, flush the outbuf into the shell. |
|
+ * CHECK: should always be called when shell->in_esc_sequence goes back to zero, |
|
+ * so characters that are waiting for a sequence to become complete can be |
|
+ * flushed out. |
|
+ */ |
|
+static int terminal_flush_output(struct vim_shell_window *shell) |
|
+{ |
|
+ if(/*shell->in_esc_sequence==0 && */ shell->outbuf_pos>0) |
|
+ { |
|
+ int len; |
|
+#ifdef ESCDEBUG |
|
+ ESCDEBUGPRINTF( "%s: sending:\n",__FUNCTION__); |
|
+ vimshell_hexdump(vimshell_debug_fp, shell->outbuf, shell->outbuf_pos); |
|
+#endif |
|
+ len=write(shell->fd_master, shell->outbuf, shell->outbuf_pos); |
|
+ if(len<0) |
|
+ { |
|
+ ESCDEBUGPRINTF( "%s: ERROR: write failed: %s\n", |
|
+ __FUNCTION__,strerror(errno)); |
|
+ shell->outbuf_pos=0; |
|
+ return -1; |
|
+ } |
|
+ |
|
+ if(shell->outbuf_pos!=len) |
|
+ memmove(shell->outbuf, shell->outbuf+len, len); |
|
+ shell->outbuf_pos-=len; |
|
+ |
|
+ return len; |
|
+ } |
|
+ return 0; |
|
+} |
|
+ |
|
+/* |
|
+ * Main Terminal processing method (VIM <- Shell). |
|
+ * Gets a buffer with input data from the shell, interprets it and updates |
|
+ * the shell window's windowbuffer accordingly. |
|
+ */ |
|
+void vim_shell_terminal_input(struct vim_shell_window *shell, char *input, int len) |
|
+{ |
|
+ int i; |
|
+ for(i=0;i<len;i++) |
|
+ { |
|
+ terminal_input_char(shell, input[i]); |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * Main Terminal output method (VIM -> Shell). |
|
+ * Translates the character 'c' into an appropriate escape sequence (if necessary) |
|
+ * and puts it into the out buffer. |
|
+ */ |
|
+int vim_shell_terminal_output(struct vim_shell_window *shell, int c) |
|
+{ |
|
+ char outbuf[50]; |
|
+ size_t written; |
|
+ |
|
+ outbuf[1]=0; |
|
+ |
|
+ switch(c) |
|
+ { |
|
+ case VIMSHELL_KEY_BACKSPACE: |
|
+ sprintf(outbuf, "\177"); |
|
+ ESCDEBUGPRINTF( "%s: key is backspace\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_UP: |
|
+ sprintf(outbuf, "\033%cA", shell->application_cursor_mode ? 'O' : '['); |
|
+ ESCDEBUGPRINTF( "%s: key is cursor up\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_DOWN: |
|
+ sprintf(outbuf, "\033%cB", shell->application_cursor_mode ? 'O' : '['); |
|
+ ESCDEBUGPRINTF( "%s: key is cursor down\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_LEFT: |
|
+ sprintf(outbuf, "\033%cD", shell->application_cursor_mode ? 'O' : '['); |
|
+ ESCDEBUGPRINTF( "%s: key is cursor left\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_RIGHT: |
|
+ sprintf(outbuf, "\033%cC", shell->application_cursor_mode ? 'O' : '['); |
|
+ ESCDEBUGPRINTF( "%s: key is cursor right\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_HOME: |
|
+ sprintf(outbuf, "\033[1~"); |
|
+ ESCDEBUGPRINTF( "%s: key is home\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F1: |
|
+ sprintf(outbuf, "\033OP"); |
|
+ ESCDEBUGPRINTF( "%s: key is F1\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F2: |
|
+ sprintf(outbuf, "\033OQ"); |
|
+ ESCDEBUGPRINTF( "%s: key is F2\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F3: |
|
+ sprintf(outbuf, "\033OR"); |
|
+ ESCDEBUGPRINTF( "%s: key is F3\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F4: |
|
+ sprintf(outbuf, "\033OS"); |
|
+ ESCDEBUGPRINTF( "%s: key is F4\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F5: |
|
+ sprintf(outbuf, "\033[15~"); |
|
+ ESCDEBUGPRINTF( "%s: key is F5\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F6: |
|
+ sprintf(outbuf, "\033[17~"); |
|
+ ESCDEBUGPRINTF( "%s: key is F6\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F7: |
|
+ sprintf(outbuf, "\033[18~"); |
|
+ ESCDEBUGPRINTF( "%s: key is F7\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F8: |
|
+ sprintf(outbuf, "\033[19~"); |
|
+ ESCDEBUGPRINTF( "%s: key is F8\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F9: |
|
+ sprintf(outbuf, "\033[20~"); |
|
+ ESCDEBUGPRINTF( "%s: key is F9\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F10: |
|
+ sprintf(outbuf, "\033[21~"); |
|
+ ESCDEBUGPRINTF( "%s: key is F10\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F11: |
|
+ sprintf(outbuf, "\033[23~"); |
|
+ ESCDEBUGPRINTF( "%s: key is F11\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_F12: |
|
+ sprintf(outbuf, "\033[24~"); |
|
+ ESCDEBUGPRINTF( "%s: key is F12\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_DC: |
|
+ sprintf(outbuf, "\033[3~"); |
|
+ ESCDEBUGPRINTF( "%s: key is delete character\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_END: |
|
+ sprintf(outbuf, "\033[4~"); |
|
+ ESCDEBUGPRINTF( "%s: key is end\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_IC: |
|
+ sprintf(outbuf, "\033[2~"); |
|
+ ESCDEBUGPRINTF( "%s: key is insert character\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_NPAGE: |
|
+ sprintf(outbuf, "\033[6~"); |
|
+ ESCDEBUGPRINTF( "%s: key is page down\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_PPAGE: |
|
+ sprintf(outbuf, "\033[5~"); |
|
+ ESCDEBUGPRINTF( "%s: key is page up\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K0: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Op" : "0"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 0\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K1: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Oq" : "1"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 1\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K2: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Or" : "2"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 2\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K3: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Os" : "3"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 3\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K4: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Ot" : "4"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 4\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K5: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Ou" : "5"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 5\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K6: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Ov" : "6"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 6\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K7: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Ow" : "7"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 7\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K8: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Ox" : "8"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 8\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_K9: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Oy" : "9"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad 9\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_KPLUS: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Ok" : "+"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad plus\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_KMINUS: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Om" : "-"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad minus\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_KDIVIDE: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Oo" : "/"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad divide\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_KMULTIPLY: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033Oj" : "*"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad multiply\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_KENTER: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033OM" : "\015"); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad enter\n", __FUNCTION__); |
|
+ break; |
|
+ case VIMSHELL_KEY_KPOINT: |
|
+ sprintf(outbuf, "%s", shell->application_keypad_mode ? "\033On" : "."); |
|
+ ESCDEBUGPRINTF( "%s: key is keypad point\n", __FUNCTION__); |
|
+ break; |
|
+ default: |
|
+ outbuf[0]=(char)c; |
|
+ } |
|
+ |
|
+ if(shell->outbuf_pos+strlen(outbuf)>=sizeof(shell->outbuf)) |
|
+ { |
|
+ written=sizeof(shell->outbuf)-shell->outbuf_pos; |
|
+ ESCDEBUGPRINTF( "%s: WARNING: prevented from overflowing the outbuf, help!\n", |
|
+ __FUNCTION__); |
|
+ } |
|
+ else |
|
+ written=strlen(outbuf); |
|
+ |
|
+ memcpy(shell->outbuf+shell->outbuf_pos, outbuf, written); |
|
+ shell->outbuf_pos+=written; |
|
+ |
|
+ if(terminal_flush_output(shell)<0) |
|
+ return -1; |
|
+ |
|
+ return written; |
|
+} |
|
+#endif |
|
Index: src/ui.c |
|
--- src/ui.c.orig 2010-08-08 15:17:30.000000000 +0200 |
|
+++ src/ui.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -1736,6 +1736,64 @@ |
|
len = 0; /* to avoid gcc warning */ |
|
for (try = 0; try < 100; ++try) |
|
{ |
|
+# ifdef FEAT_VIMSHELL |
|
+ { |
|
+ /* |
|
+ * When we use the VIM shell, we use select to look if there was |
|
+ * some activity on the shells. This is because the read below after |
|
+ * this block blocks, and this sucks. |
|
+ * |
|
+ * This loop is basically here so the shells can send updates while |
|
+ * we are waiting for the read(2) on the read_cmd_fd to become available. |
|
+ */ |
|
+# ifndef HAVE_SELECT |
|
+#error sorry - vimshell needs select. programmer is too lazy to write this with poll (at this time) |
|
+# endif |
|
+ fd_set rdfd; |
|
+ buf_T *buf; |
|
+ int maxfd, ret, done; |
|
+ |
|
+ done=0; |
|
+ while(!done) |
|
+ { |
|
+ FD_ZERO(&rdfd); |
|
+ FD_SET(read_cmd_fd, &rdfd); |
|
+ maxfd=read_cmd_fd; |
|
+ |
|
+ for(buf=firstbuf; buf!=NULL; buf=buf->b_next) |
|
+ { |
|
+ if(buf->is_shell!=0) |
|
+ { |
|
+ FD_SET(buf->shell->fd_master, &rdfd); |
|
+ if( maxfd < buf->shell->fd_master) |
|
+ maxfd = buf->shell->fd_master; |
|
+ } |
|
+ } |
|
+ |
|
+ ret=select(maxfd+1, &rdfd, NULL, NULL, NULL); |
|
+ if(ret<0) |
|
+ { |
|
+ /* |
|
+ * we fsck'd something up ... let's just get out of here |
|
+ */ |
|
+ done=1; |
|
+ } |
|
+ else if(ret>0) |
|
+ { |
|
+ if(FD_ISSET(read_cmd_fd, &rdfd)) |
|
+ { |
|
+ /* |
|
+ * we have what we came here for. exit this loop |
|
+ * (but only after processing available shell reads) |
|
+ */ |
|
+ done=1; |
|
+ } |
|
+ |
|
+ vim_shell_do_read_select(rdfd); |
|
+ } |
|
+ } // while(!done) |
|
+ } |
|
+# endif |
|
# ifdef VMS |
|
len = vms_read( |
|
# else |
|
Index: src/version.c |
|
--- src/version.c.orig 2010-08-01 15:45:48.000000000 +0200 |
|
+++ src/version.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -619,6 +619,11 @@ |
|
#else |
|
"-vertsplit", |
|
#endif |
|
+#ifdef FEAT_VIMSHELL |
|
+ "+vimshell", |
|
+#else |
|
+ "-vimshell", |
|
+#endif |
|
#ifdef FEAT_VIRTUALEDIT |
|
"+virtualedit", |
|
#else |
|
Index: src/vim.h |
|
--- src/vim.h.orig 2010-07-29 20:46:39.000000000 +0200 |
|
+++ src/vim.h 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -426,6 +426,14 @@ |
|
|
|
/* |
|
* The characters and attributes cached for the screen. |
|
+ * VIM-Shell: the VIM-shell really needs more than one byte for the attributes. |
|
+ * Despite of a single warning during compilation, it seems to work |
|
+ * fine to simply change the type here. |
|
+ * We use the sattr_T as follows: |
|
+ * The lowest byte is handled the same as before, for rendering attributes. |
|
+ * The remaining byte is split, the uppermost 4 bits for the active foreground |
|
+ * color, and the lowermost 4 bits for the active background color (at this |
|
+ * screen position). |
|
*/ |
|
typedef char_u schar_T; |
|
#ifdef FEAT_SYN_HL |
|
@@ -2155,6 +2163,10 @@ |
|
# include <XSUB.h> |
|
#endif |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+#include "vim_shell.h" |
|
+#endif |
|
+ |
|
/* values for vim_handle_signal() that are not a signal */ |
|
#define SIGNAL_BLOCK -1 |
|
#define SIGNAL_UNBLOCK -2 |
|
Index: src/vim_shell.c |
|
--- src/vim_shell.c.orig 2011-02-12 14:22:30.000000000 +0100 |
|
+++ src/vim_shell.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -0,0 +1,932 @@ |
|
+/* |
|
+ * vim_shell.c |
|
+ * |
|
+ * This is the interface layer of the VIM-Shell. VIM only calls functions from this module, |
|
+ * e.g. create a new VIM-Shell, read characters from the shell or write characters to the |
|
+ * shell. The respective functions pass these things down to the terminal layer, implemented |
|
+ * in terminal.c. |
|
+ * |
|
+ * This file is part of the VIM-Shell project. http://vimshell.wana.at |
|
+ * |
|
+ * Author: Thomas Wana <thomas@wana.at> |
|
+ * |
|
+ */ |
|
+ |
|
+ |
|
+static char *RCSID="$Id$"; |
|
+ |
|
+#include "vim.h" |
|
+ |
|
+#ifdef FEAT_VIMSHELL |
|
+#include <errno.h> |
|
+#include <stdlib.h> |
|
+#include <string.h> |
|
+#include <unistd.h> |
|
+#include <ctype.h> |
|
+#include <sys/types.h> |
|
+#include <sys/wait.h> |
|
+#include <signal.h> |
|
+#ifdef HAVE_PTY_H |
|
+#include <pty.h> |
|
+#endif |
|
+#ifdef HAVE_TERMIOS_H |
|
+#include <termios.h> |
|
+#endif |
|
+#ifdef HAVE_LIBUTIL_H |
|
+#include <libutil.h> |
|
+#endif |
|
+#include <fcntl.h> |
|
+ |
|
+/* #include <pty.h> */ |
|
+/* |
|
+#include <asm-generic/ioctls.h> |
|
+#include <asm-generic/termios.h> |
|
+*/ |
|
+ |
|
+#if !defined(TIOCSWINSZ) |
|
+# error "VIMSHELL: needs TIOCSWINSZ at the moment, not available on your system, sorry." |
|
+#endif |
|
+ |
|
+#ifdef VIMSHELL_DEBUG |
|
+# define CHILDDEBUG |
|
+# define SIGDEBUG |
|
+#endif |
|
+ |
|
+#ifdef CHILDDEBUG |
|
+# define CHILDDEBUGPRINTF(a...) if(vimshell_debug_fp) fprintf(vimshell_debug_fp, a) |
|
+#else |
|
+# define CHILDDEBUGPRINTF(a...) |
|
+#endif |
|
+ |
|
+#ifdef SIGDEBUG |
|
+# define SIGDEBUGPRINTF(a...) if(vimshell_debug_fp) fprintf(vimshell_debug_fp, a) |
|
+#else |
|
+# define SIGDEBUGPRINTF(a...) |
|
+#endif |
|
+ |
|
+ |
|
+int vimshell_errno; |
|
+ |
|
+FILE *vimshell_debug_fp=NULL; |
|
+ |
|
+/* |
|
+ * Main initialization function. Sets up global things always needed for the VIM shell. |
|
+ */ |
|
+int vim_shell_init() |
|
+{ |
|
+#ifdef VIMSHELL_DEBUG |
|
+ vimshell_debug_fp=fopen("vimshell.debug", "w"); |
|
+#endif |
|
+ |
|
+ /* |
|
+ * Everything went OK |
|
+ */ |
|
+ return 0; |
|
+} |
|
+ |
|
+/* |
|
+ * A routine that prints a buffer in 'hexdump -C'-style via printf |
|
+ */ |
|
+static void vimshell_hexdump(FILE *fp, unsigned char *buffer, long len) |
|
+{ |
|
+ unsigned long pos=0; |
|
+ |
|
+ while(len>0) |
|
+ { |
|
+ int i; |
|
+ fprintf(fp,"%08x ",(unsigned int)pos); |
|
+ for(i=0;i<16 && i<len;i++) |
|
+ { |
|
+ fprintf(fp,"%02x ",buffer[pos+i]); |
|
+ if(i==7 || i==15) |
|
+ fprintf(fp," "); |
|
+ } |
|
+ fprintf(fp,"|"); |
|
+ for(i=0;i<16 && i<len;i++) |
|
+ { |
|
+ unsigned char c=buffer[pos+i]; |
|
+ if(isprint(c)) |
|
+ { |
|
+ fprintf(fp,"%c",c); |
|
+ } |
|
+ else |
|
+ { |
|
+ fprintf(fp,"."); |
|
+ } |
|
+ } |
|
+ fprintf(fp,"|\n"); |
|
+ len-=16; |
|
+ pos+=16; |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * Create a new window. |
|
+ * @return: pointer to a new struct vim_shell_window on success |
|
+ * NULL on failure |
|
+ */ |
|
+struct vim_shell_window *vim_shell_new(uint16_t width, uint16_t height) |
|
+{ |
|
+ struct vim_shell_window *rval; |
|
+ int i; |
|
+ |
|
+ rval=(struct vim_shell_window *)vim_shell_malloc(sizeof(struct vim_shell_window)); |
|
+ if(rval==NULL) |
|
+ { |
|
+ vimshell_errno=VIMSHELL_OUT_OF_MEMORY; |
|
+ return NULL; |
|
+ } |
|
+ |
|
+ memset(rval, 0, sizeof(struct vim_shell_window)); |
|
+ |
|
+ rval->size_x=width; |
|
+ rval->size_y=height; |
|
+ |
|
+ rval->fgcolor=VIMSHELL_COLOR_DEFAULT; |
|
+ rval->bgcolor=VIMSHELL_COLOR_DEFAULT; |
|
+ |
|
+ rval->G0_charset='B'; // United States (USASCII) |
|
+ rval->G1_charset='0'; // Special graphics characters and line drawing set |
|
+ rval->active_charset=0; |
|
+ |
|
+ rval->winbuf=(uint8_t *)vim_shell_malloc(width*height); |
|
+ rval->fgbuf=(uint8_t *)vim_shell_malloc(width*height); |
|
+ rval->bgbuf=(uint8_t *)vim_shell_malloc(width*height); |
|
+ rval->rendbuf=(uint8_t *)vim_shell_malloc(width*height); |
|
+ rval->charset=(uint8_t *)vim_shell_malloc(width*height); |
|
+ rval->tabline=(uint8_t *)vim_shell_malloc(width); |
|
+ //rval->phys_screen=(uint32_t *)vim_shell_malloc(width*height*4); |
|
+ if(rval->winbuf==NULL || rval->fgbuf==NULL || rval->bgbuf==NULL || rval->rendbuf==NULL || rval->charset==NULL || |
|
+ rval->tabline==NULL /* || rval->phys_screen==NULL */) |
|
+ { |
|
+ vimshell_errno=VIMSHELL_OUT_OF_MEMORY; |
|
+ // VIMSHELL TODO: cleanup, free the buffers that were successfully allocated |
|
+ vim_shell_free(rval); |
|
+ return NULL; |
|
+ } |
|
+ memset(rval->winbuf, ' ', width*height); |
|
+ memset(rval->fgbuf, rval->fgcolor, width*height); |
|
+ memset(rval->bgbuf, rval->bgcolor, width*height); |
|
+ memset(rval->rendbuf, 0, width*height); |
|
+ memset(rval->charset, 0, width*height); |
|
+ memset(rval->tabline, 0, width); |
|
+ |
|
+#if 0 |
|
+ for(i=0;i<width*height;i++) |
|
+ { |
|
+ /* |
|
+ * This is: default foreground, default background, no rendering attributes, ' ' as character |
|
+ */ |
|
+ rval->phys_screen[i]=0x09090020; |
|
+ } |
|
+#endif |
|
+ |
|
+ /* |
|
+ * Set a tab every 8 columns (default) |
|
+ */ |
|
+ for(i=1;i<width;i++) |
|
+ { |
|
+ if((i+1)%8==0 && i+1<width) |
|
+ rval->tabline[i]=1; |
|
+ } |
|
+ |
|
+ rval->wraparound=1; |
|
+ |
|
+ rval->cursor_x=0; |
|
+ rval->cursor_y=0; |
|
+ rval->cursor_visible=1; |
|
+ |
|
+ rval->scroll_top_margin=0; |
|
+ rval->scroll_bottom_margin=height-1; |
|
+ |
|
+ CHILDDEBUGPRINTF("%s: vimshell created, width = %d, height = %d\n", |
|
+ __FUNCTION__, width, height); |
|
+ |
|
+ vimshell_errno=VIMSHELL_SUCCESS; |
|
+ return rval; |
|
+} |
|
+ |
|
+/* |
|
+ * start the program in argv in the shell window. |
|
+ */ |
|
+int vim_shell_start(struct vim_shell_window *shell, char *argv[]) |
|
+{ |
|
+ struct winsize winsize; |
|
+ struct termios termios; |
|
+ |
|
+ memset(&termios, 0, sizeof(struct termios)); |
|
+ |
|
+ /* |
|
+ * Set terminal parameters. |
|
+ */ |
|
+ termios.c_iflag=ICRNL; |
|
+ termios.c_oflag=ONLCR | OPOST; |
|
+ termios.c_cflag=CS8 | CREAD | HUPCL; |
|
+ termios.c_lflag=ECHO | ECHOE | ECHOK | ECHOKE | ISIG | ECHOCTL | ICANON; |
|
+ termios.c_cc[VMIN]=1; |
|
+ termios.c_cc[VTIME]=0; |
|
+ termios.c_cc[VINTR]=003; |
|
+ termios.c_cc[VQUIT]=034; |
|
+ termios.c_cc[VERASE]=0177; |
|
+ termios.c_cc[VKILL]=025; |
|
+ termios.c_cc[VEOF]=004; |
|
+ termios.c_cc[VSTART]=021; |
|
+ termios.c_cc[VSTOP]=023; |
|
+ termios.c_cc[VSUSP]=032; |
|
+ |
|
+ winsize.ws_row=shell->size_y; |
|
+ winsize.ws_col=shell->size_x; |
|
+ winsize.ws_xpixel=0; |
|
+ winsize.ws_ypixel=0; |
|
+ |
|
+ /* |
|
+ * allocate a pty, fork and exec the command |
|
+ */ |
|
+ shell->pid=forkpty(&shell->fd_master, NULL, &termios, &winsize); |
|
+ if(shell->pid==0) |
|
+ { |
|
+ /* |
|
+ * child code |
|
+ */ |
|
+ setenv("TERM", "screen", 1); |
|
+ if(execvp(*argv, argv)<0) |
|
+ { |
|
+ vimshell_errno=VIMSHELL_EXECV_ERROR; |
|
+ // VIMSHELL TODO close fds?? |
|
+ return -1; |
|
+ } |
|
+ } |
|
+ else if(shell->pid<0) |
|
+ { |
|
+ vimshell_errno=VIMSHELL_FORKPTY_ERROR; |
|
+ return -1; |
|
+ } |
|
+ |
|
+ /* |
|
+ * Set the file descriptor to non-blocking |
|
+ */ |
|
+ if(fcntl(shell->fd_master, F_SETFL, fcntl(shell->fd_master, F_GETFL) | O_NONBLOCK)<0) |
|
+ { |
|
+ vimshell_errno=VIMSHELL_FCNTL_ERROR; |
|
+ return -1; |
|
+ } |
|
+ |
|
+ /* |
|
+ * parent code |
|
+ */ |
|
+ if(ioctl(shell->fd_master, TIOCSWINSZ, &winsize)<0) |
|
+ { |
|
+ CHILDDEBUGPRINTF( "%s: ERROR: ioctl to change window size: %s\n", |
|
+ __FUNCTION__,strerror(errno)); |
|
+ } |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+/* |
|
+ * this is much like strerror, only with vimshell_errno. Additionally, if errno is not |
|
+ * null, the formatted error message (strerror) will be appended to the output. |
|
+ */ |
|
+char *vim_shell_strerror() |
|
+{ |
|
+ static char errbuf[200]; |
|
+ static char *errmsg[]={"Success", |
|
+ "Out of memory", |
|
+ "forkpty error", |
|
+ "read error", |
|
+ "write error", |
|
+ "execv error", |
|
+ "sigaction error", |
|
+ "read (EOF)", |
|
+ "fcntl error"}; |
|
+ |
|
+ if(errno==0) |
|
+ return errmsg[vimshell_errno]; |
|
+ |
|
+ snprintf(errbuf, sizeof(errbuf), "%s: %s", errmsg[vimshell_errno], strerror(errno)); |
|
+ return errbuf; |
|
+} |
|
+ |
|
+/* |
|
+ * Read what is available from the master pty and tear it through the |
|
+ * terminal emulation. This will fill the window buffer. |
|
+ */ |
|
+int vim_shell_read(struct vim_shell_window *shell) |
|
+{ |
|
+ // for now, copy what we have into the window buffer. |
|
+ char input[2000]; |
|
+ int rval; |
|
+ |
|
+retry: |
|
+ if((rval=read(shell->fd_master, input, sizeof(input)))<0) |
|
+ { |
|
+ if(errno==EINTR) |
|
+ goto retry; |
|
+ if(errno==EAGAIN) |
|
+ { |
|
+ /* |
|
+ * This function should only be called when there really |
|
+ * are bytes available to read from the fd_master. This |
|
+ * is ensured by calling select() before this function. |
|
+ * But it seems that there is a race with a SIGWINSZ right |
|
+ * in the middle of a select() (reporting there are characters |
|
+ * available) and the following read() that will block forever. |
|
+ * It seems that SIGWINSZ flushes the processes input queue, at |
|
+ * least on Linux. |
|
+ * |
|
+ * So if we get here although there is nothing to read, don't |
|
+ * report an error, just return successfully. |
|
+ */ |
|
+ goto success; |
|
+ } |
|
+ |
|
+ vimshell_errno=VIMSHELL_READ_ERROR; |
|
+ return -1; |
|
+ } |
|
+ |
|
+ if(rval==0) |
|
+ { |
|
+ /* |
|
+ * This means end-of-file, the subprocess exited. |
|
+ */ |
|
+ vimshell_errno=VIMSHELL_READ_EOF; |
|
+ return -1; |
|
+ } |
|
+ |
|
+#ifdef RAWDEBUG |
|
+ fprintf(vimshell_debug_fp, "\nincoming bytes:\n"); |
|
+ vimshell_hexdump(vimshell_debug_fp, input, rval); |
|
+#endif |
|
+ |
|
+ /* |
|
+ * Interface to the terminal layer: give the input buffer to the |
|
+ * terminal emulator for processing. |
|
+ */ |
|
+ vim_shell_terminal_input(shell, input, rval); |
|
+ |
|
+success: |
|
+ vimshell_errno=VIMSHELL_SUCCESS; |
|
+ return 0; |
|
+} |
|
+ |
|
+/* |
|
+ * Write a character to the VIM-Shell. |
|
+ * Blow it through terminal_output so it gets translated correctly etc... |
|
+ */ |
|
+int vim_shell_write(struct vim_shell_window *shell, int c) |
|
+{ |
|
+ if(vim_shell_terminal_output(shell, c)<0) |
|
+ { |
|
+ vimshell_errno=VIMSHELL_WRITE_ERROR; |
|
+ return -1; |
|
+ } |
|
+ |
|
+ vimshell_errno=VIMSHELL_SUCCESS; |
|
+ return 0; |
|
+} |
|
+ |
|
+/* |
|
+ * Free everything that is associated with this shell window. |
|
+ * Also terminates the process. The shell pointer will be set to NULL. |
|
+ * The buffer will be restored to a usable, empty buffer. |
|
+ */ |
|
+void vim_shell_delete(buf_T *buf) |
|
+{ |
|
+ struct vim_shell_window *sh=buf->shell; |
|
+ int status; |
|
+ pid_t pid; |
|
+ |
|
+ /* |
|
+ * First, kill the child and wait for it. |
|
+ * VIMSHELL TODO: this can be extended a lot. e.g. using a SIGCHLD handler |
|
+ * or an SIGALRM handler and kill(SIGKILL) the process when the alarm fires |
|
+ * etc. But for now (and most of all cases) this should be OK. |
|
+ */ |
|
+ pid=sh->pid; |
|
+ if(pid>0) |
|
+ { |
|
+ kill(pid, SIGTERM); |
|
+ kill(pid, SIGHUP); |
|
+ while(waitpid(pid, &status, 0)<0 && errno==EINTR); |
|
+ CHILDDEBUGPRINTF( "%s: PID %u terminated, exit status = %d\n", __FUNCTION__, pid, |
|
+ WEXITSTATUS(status)); |
|
+ } |
|
+ |
|
+ /* |
|
+ * The child is dead. Clean up |
|
+ */ |
|
+ close(sh->fd_master); |
|
+ if(sh->alt) |
|
+ { |
|
+ vim_shell_free(sh->alt->winbuf); |
|
+ vim_shell_free(sh->alt->fgbuf); |
|
+ vim_shell_free(sh->alt->bgbuf); |
|
+ vim_shell_free(sh->alt->rendbuf); |
|
+ vim_shell_free(sh->alt->tabline); |
|
+ vim_shell_free(sh->alt->charset); |
|
+ vim_shell_free(sh->alt); |
|
+ sh->alt=NULL; |
|
+ } |
|
+ vim_shell_free(sh->winbuf); |
|
+ vim_shell_free(sh->fgbuf); |
|
+ vim_shell_free(sh->bgbuf); |
|
+ vim_shell_free(sh->rendbuf); |
|
+ vim_shell_free(sh->tabline); |
|
+ vim_shell_free(sh->charset); |
|
+ vim_shell_free(sh); |
|
+ |
|
+ CHILDDEBUGPRINTF( "%s: vimshell %p freed.\n", __FUNCTION__, sh); |
|
+ |
|
+ buf->is_shell=0; |
|
+ buf->shell=NULL; |
|
+ buf->b_p_ro=FALSE; |
|
+} |
|
+ |
|
+/* |
|
+ * Does the work of actually resizing the shell's buffers. Deallocating them, |
|
+ * reallocating them, copying over the old contents to the right places, etc... |
|
+ * rval: 0 = success, <0 = error |
|
+ */ |
|
+static int internal_screenbuf_resize(struct vim_shell_window *shell, int width, int height) |
|
+{ |
|
+ uint8_t *owinbuf, *ofgbuf, *obgbuf, *orendbuf, *otabline, *ocharset; |
|
+ int x, y, len, vlen; |
|
+ uint16_t oldwidth, oldheight; |
|
+ |
|
+ oldwidth=shell->size_x; |
|
+ oldheight=shell->size_y; |
|
+ shell->size_x=(uint16_t)width; |
|
+ shell->size_y=(uint16_t)height; |
|
+ |
|
+ owinbuf=shell->winbuf; |
|
+ ofgbuf=shell->fgbuf; |
|
+ obgbuf=shell->bgbuf; |
|
+ orendbuf=shell->rendbuf; |
|
+ ocharset=shell->charset; |
|
+ otabline=shell->tabline; |
|
+ |
|
+ shell->winbuf=(uint8_t *)vim_shell_malloc(width*height); |
|
+ shell->fgbuf=(uint8_t *)vim_shell_malloc(width*height); |
|
+ shell->bgbuf=(uint8_t *)vim_shell_malloc(width*height); |
|
+ shell->rendbuf=(uint8_t *)vim_shell_malloc(width*height); |
|
+ shell->charset=(uint8_t *)vim_shell_malloc(width*height); |
|
+ shell->tabline=(uint8_t *)vim_shell_malloc(width); |
|
+ if(shell->winbuf==NULL || shell->fgbuf==NULL || shell->bgbuf==NULL || shell->rendbuf==NULL || shell->charset==NULL || |
|
+ shell->tabline==NULL) |
|
+ { |
|
+ vimshell_errno=VIMSHELL_OUT_OF_MEMORY; |
|
+ if(shell->winbuf) vim_shell_free(shell->winbuf); |
|
+ if(shell->fgbuf) vim_shell_free(shell->fgbuf); |
|
+ if(shell->bgbuf) vim_shell_free(shell->bgbuf); |
|
+ if(shell->rendbuf) vim_shell_free(shell->rendbuf); |
|
+ if(shell->charset) vim_shell_free(shell->charset); |
|
+ if(shell->tabline) vim_shell_free(shell->tabline); |
|
+ |
|
+ /* |
|
+ * Reassign the old buffers, they are still valid. And bring the shell |
|
+ * back to a sane state. |
|
+ */ |
|
+ shell->winbuf=owinbuf; |
|
+ shell->fgbuf=ofgbuf; |
|
+ shell->bgbuf=obgbuf; |
|
+ shell->rendbuf=orendbuf; |
|
+ shell->charset=ocharset; |
|
+ shell->tabline=otabline; |
|
+ |
|
+ shell->size_x=oldwidth; |
|
+ shell->size_y=oldheight; |
|
+ |
|
+ return -1; |
|
+ } |
|
+ memset(shell->winbuf, ' ', width*height); |
|
+ memset(shell->fgbuf, shell->fgcolor, width*height); |
|
+ memset(shell->bgbuf, shell->bgcolor, width*height); |
|
+ memset(shell->rendbuf, 0, width*height); |
|
+ memset(shell->charset, 0, width*height); |
|
+ memset(shell->tabline, 0, width); |
|
+ |
|
+ CHILDDEBUGPRINTF( "%s: width = %d, height = %d, oldwidth = %d, oldheight = %d\n",__FUNCTION__,width,height, |
|
+ oldwidth,oldheight); |
|
+ |
|
+ /* |
|
+ * copy over the old contents of the screen, line by line (!) |
|
+ */ |
|
+ len=(oldwidth<width ? oldwidth : width); |
|
+ vlen=(oldheight<height ? oldheight : height); |
|
+ for(y=0;y<vlen;y++) |
|
+ { |
|
+ int y_off; |
|
+ y_off=oldheight-vlen; |
|
+ memcpy(shell->winbuf+y*width, owinbuf+(y+y_off)*oldwidth, len); |
|
+ memcpy(shell->fgbuf+y*width, ofgbuf+(y+y_off)*oldwidth, len); |
|
+ memcpy(shell->bgbuf+y*width, obgbuf+(y+y_off)*oldwidth, len); |
|
+ memcpy(shell->rendbuf+y*width, orendbuf+(y+y_off)*oldwidth, len); |
|
+ memcpy(shell->charset+y*width, ocharset+(y+y_off)*oldwidth, len); |
|
+ } |
|
+ memcpy(shell->tabline, otabline, len); |
|
+ |
|
+ /* |
|
+ * free the old contents |
|
+ */ |
|
+ vim_shell_free(owinbuf); |
|
+ vim_shell_free(ofgbuf); |
|
+ vim_shell_free(obgbuf); |
|
+ vim_shell_free(orendbuf); |
|
+ vim_shell_free(otabline); |
|
+ vim_shell_free(ocharset); |
|
+ |
|
+ /* |
|
+ * Correct tabs |
|
+ */ |
|
+ if(oldwidth<width) |
|
+ { |
|
+ for(x=oldwidth;x<width;x++) |
|
+ { |
|
+ if((x+1)%8==0 && x+1<width) |
|
+ shell->tabline[x]=1; |
|
+ } |
|
+ } |
|
+ |
|
+ /* |
|
+ * Correct cursor |
|
+ */ |
|
+ if(shell->cursor_x>=shell->size_x) |
|
+ shell->cursor_x=shell->size_x-1; |
|
+ if(shell->cursor_y>=shell->size_y) |
|
+ shell->cursor_y=shell->size_y-1; |
|
+ |
|
+ /* |
|
+ * Update scroll region |
|
+ */ |
|
+ shell->scroll_top_margin=0; |
|
+ shell->scroll_bottom_margin=shell->size_y-1; |
|
+ |
|
+ /* |
|
+ * Invalidate the vimshell screen buffer, so vim_shell_redraw redraws the whole |
|
+ * screen. |
|
+ */ |
|
+ shell->force_redraw=1; |
|
+ |
|
+ return 0; |
|
+} |
|
+ |
|
+/* |
|
+ * Resizes the shell. |
|
+ * It reallocates all the size dependant buffers and instructs the shell to change |
|
+ * its size. |
|
+ * The width and height parameters are the *desired* width and height. The actual |
|
+ * width and height is dependant on wether all windows that currently render this shell |
|
+ * are able to display this width and height. |
|
+ */ |
|
+void vim_shell_resize(struct vim_shell_window *shell, int want_width, int want_height) |
|
+{ |
|
+ int width, height; |
|
+ struct winsize ws; |
|
+ win_T *win; |
|
+ |
|
+ width=want_width; |
|
+ height=want_height; |
|
+ FOR_ALL_WINDOWS(win) |
|
+ { |
|
+ if(win->w_buffer && win->w_buffer->is_shell && win->w_buffer->shell==shell) |
|
+ { |
|
+ if(win->w_width<width) |
|
+ width=win->w_width; |
|
+ if(win->w_height<height) |
|
+ height=win->w_height; |
|
+ } |
|
+ } |
|
+ |
|
+ CHILDDEBUGPRINTF( "%s: resizing to %d, %d\n",__FUNCTION__,width,height); |
|
+ |
|
+ if(internal_screenbuf_resize(shell, width, height)<0) |
|
+ { |
|
+ CHILDDEBUGPRINTF("%s: error while resizing.\n", __FUNCTION__); |
|
+ return; |
|
+ } |
|
+ if(shell->alt!=NULL) |
|
+ { |
|
+ if(internal_screenbuf_resize(shell->alt, width, height)<0) |
|
+ { |
|
+ CHILDDEBUGPRINTF("%s: error while resizing the backup screen. Recovering...\n", __FUNCTION__); |
|
+ |
|
+ /* |
|
+ * We now really have a problem. The main shell window is already |
|
+ * resized and this one didn't work. What should we do? Just destroy the screen |
|
+ * backup so it never gets restored. internal_screenbuf_resize already did |
|
+ * the job to of freeing the SINGle buffers, we just have to free the remaining struct. |
|
+ */ |
|
+ vim_shell_free(shell->alt); |
|
+ shell->alt=NULL; |
|
+ } |
|
+ } |
|
+ |
|
+ /* |
|
+ * Tell the shell that the size has changed. |
|
+ */ |
|
+ ws.ws_row=height; |
|
+ ws.ws_col=width; |
|
+ ws.ws_xpixel=0; |
|
+ ws.ws_ypixel=0; |
|
+ if(ioctl(shell->fd_master, TIOCSWINSZ, &ws)<0) |
|
+ { |
|
+ CHILDDEBUGPRINTF( "%s: ERROR: ioctl to change window size: %s\n", |
|
+ __FUNCTION__,strerror(errno)); |
|
+ } |
|
+} |
|
+ |
|
+/* |
|
+ * Draws the Shell-Buffer into the VIM-Window. |
|
+ */ |
|
+void vim_shell_redraw(struct vim_shell_window *shell, win_T *win) |
|
+{ |
|
+ int x, y; |
|
+ int win_row, win_col; |
|
+ int off; |
|
+ int last_set_fg, last_set_bg; |
|
+ int cs_state; |
|
+ int term_is_bold, term_is_underline, term_is_negative; |
|
+ int saved_screen_cur_row, saved_screen_cur_col; |
|
+ int force_redraw; |
|
+ int using_gui=0; |
|
+ int t_colors_original=t_colors; |
|
+ |
|
+ if(t_colors>15) |
|
+ { |
|
+ t_colors = 15; |
|
+ } |
|
+ |
|
+#ifdef FEAT_GUI |
|
+ if(gui.in_use) |
|
+ { |
|
+ using_gui=1; |
|
+ } |
|
+#endif |
|
+ |
|
+ win_row=W_WINROW(win); |
|
+ win_col=W_WINCOL(win); |
|
+ |
|
+ force_redraw=shell->force_redraw; |
|
+ |
|
+ // invalidate the color cache |
|
+ last_set_fg=last_set_bg=-1; |
|
+ cs_state=VIMSHELL_CHARSET_USASCII; |
|
+ |
|
+ saved_screen_cur_row=screen_cur_row; |
|
+ saved_screen_cur_col=screen_cur_col; |
|
+ |
|
+ // go to normal mode |
|
+ term_is_bold=term_is_underline=term_is_negative=0; |
|
+ screen_stop_highlight(); |
|
+ |
|
+ for(y=0;y<shell->size_y;y++) |
|
+ { |
|
+ size_t index=y*shell->size_x; |
|
+ int skipped, y_reposition_necessary; |
|
+ |
|
+ off=LineOffset[win_row+y]+win_col; |
|
+ skipped=0; |
|
+ y_reposition_necessary=1; |
|
+ for(x=0;x<shell->size_x;x++) |
|
+ { |
|
+ uint8_t c=shell->winbuf[index]; |
|
+ sattr_T r=(sattr_T)shell->rendbuf[index]; |
|
+ uint8_t fg=shell->fgbuf[index]; |
|
+ uint8_t bg=shell->bgbuf[index]; |
|
+ uint8_t cs=shell->charset[index]; |
|
+ uint8_t fg_color=fg&0xF; |
|
+ uint8_t bg_color=bg&0xF; |
|
+ if(t_colors > 15) |
|
+ { |
|
+ bg_color=0x00; |
|
+ fg_color=0x03; |
|
+ } |
|
+ |
|
+ /* |
|
+ * Switch terminal charset if necessary |
|
+ */ |
|
+ if(cs_state!=cs) |
|
+ { |
|
+ cs_state=cs; |
|
+ if(cs==VIMSHELL_CHARSET_USASCII) |
|
+ { |
|
+ // VIMSHELL TODO: make a term code out of this hack |
|
+ out_str_nf("\033(B"); |
|
+ CHILDDEBUGPRINTF( "%s: switched terminal to normal charset\n",__FUNCTION__); |
|
+ } |
|
+ else if(cs==VIMSHELL_CHARSET_DRAWING) |
|
+ { |
|
+ // VIMSHELL TODO: make a term code out of this hack |
|
+ out_str_nf("\033(0"); |
|
+ CHILDDEBUGPRINTF( "%s: switched terminal to alternate charset\n",__FUNCTION__); |
|
+ } |
|
+ } |
|
+ |
|
+ /* |
|
+ * Store the foreground and background color along with the rendering attributes. |
|
+ */ |
|
+ r |= (fg&0x0F)<<12 | (bg&0x0F)<<8; |
|
+ |
|
+ /* |
|
+ * Only do an update if render attributes or the character |
|
+ * has changed at this position. |
|
+ */ |
|
+ if(ScreenLines[off]!=c || ScreenAttrs[off]!=r || force_redraw) |
|
+ { |
|
+ // render attributes |
|
+ if( ((r & RENDITION_BOLD)==0) == (term_is_bold==0) && |
|
+ ((r & RENDITION_UNDERSCORE)==0) == (term_is_underline==0) && |
|
+ ((r & RENDITION_NEGATIVE)==0) == (term_is_negative==0)) |
|
+ { |
|
+ /* |
|
+ * already in the right rendition mode ... |
|
+ */ |
|
+ } |
|
+ else if(using_gui==0) |
|
+ { |
|
+ out_str_nf(T_ME); |
|
+ term_is_bold=term_is_underline=term_is_negative=0; |
|
+ last_set_fg=last_set_bg=-1; |
|
+ if ((r & RENDITION_BOLD) && !term_is_bold) |
|
+ { |
|
+ if(T_MD!=NULL) |
|
+ out_str_nf(T_MD); |
|
+ term_is_bold=1; |
|
+ } |
|
+ if ((r & RENDITION_UNDERSCORE) && !term_is_underline) |
|
+ { |
|
+ if(T_US != NULL) |
|
+ out_str_nf(T_US); |
|
+ term_is_underline=1; |
|
+ } |
|
+ if ((r & RENDITION_NEGATIVE) && !term_is_negative) |
|
+ { |
|
+ if(T_MR!=NULL) |
|
+ out_str_nf(T_MR); |
|
+ term_is_negative=1; |
|
+ } |
|
+ } |
|
+ |
|
+ // colors |
|
+ if(t_colors > 1 && using_gui==0) |
|
+ { |
|
+ // VIMSHELL TODO: not every terminal will understand these colors ... |
|
+ // look at tag:cterm_normal_fg_color |
|
+ if(last_set_fg!=fg_color) |
|
+ { |
|
+ term_fg_color(fg_color); |
|
+ last_set_fg=fg_color; |
|
+ } |
|
+ if(last_set_bg!=bg_color) |
|
+ { |
|
+ term_bg_color(bg_color); |
|
+ last_set_bg=bg_color; |
|
+ } |
|
+ } |
|
+ |
|
+ ScreenLines[off]=c; |
|
+ ScreenAttrs[off]=r; |
|
+ |
|
+ if(y_reposition_necessary || skipped>0) |
|
+ { |
|
+ /* |
|
+ * Bring the cursor to where we need it. |
|
+ */ |
|
+ term_windgoto(win_row+y, win_col+x); |
|
+ skipped=0; |
|
+ y_reposition_necessary=0; |
|
+ } |
|
+ |
|
+ // print it |
|
+ out_char(c); |
|
+ } |
|
+ else |
|
+ { |
|
+ skipped++; |
|
+ } |
|
+ |
|
+ off++; |
|
+ index++; |
|
+ } |
|
+ } |
|
+ /* |
|
+ * Always leave this function with the normal ASCII charset enabled and |
|
+ * with sane rendering attributes (normal mode). |
|
+ */ |
|
+ if(cs_state!=VIMSHELL_CHARSET_USASCII) |
|
+ { |
|
+ // VIMSHELL TODO: make a term code out of this hack |
|
+ out_str_nf("\033(B"); |
|
+ CHILDDEBUGPRINTF( "%s: switched terminal to normal charset\n",__FUNCTION__); |
|
+ } |
|
+ |
|
+ /* |
|
+ * Move the cursor to where VIM thinks it is :) |
|
+ */ |
|
+ term_windgoto(saved_screen_cur_row, saved_screen_cur_col); |
|
+ |
|
+ /* |
|
+ * Position the cursor. |
|
+ * VIMSHELL TODO: we could cache that, e.g. when the cursor didn't move don't turn |
|
+ * it on again etc. |
|
+ */ |
|
+ win->w_wrow=shell->cursor_y; |
|
+ win->w_wcol=shell->cursor_x; |
|
+ setcursor(); |
|
+ cursor_on(); |
|
+ |
|
+ /* |
|
+ * Restore the rendering attributes |
|
+ */ |
|
+ out_str_nf(T_ME); |
|
+ screen_start_highlight(screen_attr); |
|
+ out_flush(); |
|
+ |
|
+ if(shell->force_redraw) |
|
+ shell->force_redraw=0; |
|
+ |
|
+ t_colors = t_colors_original; |
|
+} |
|
+ |
|
+/* |
|
+ * Really do the read, finally :) |
|
+ * Returns 1 if the contents of the window are VALID (in VIM speak) |
|
+ * Returns 2 if the contents have to be CLEARed (after the shell has died) |
|
+ */ |
|
+int vim_shell_do_read_lowlevel(buf_T *buf) |
|
+{ |
|
+ int rval=1; |
|
+ if(vim_shell_read(buf->shell)<0) |
|
+ { |
|
+ /* |
|
+ * Shell died? Cleanup. Also remove the RO attribute from the |
|
+ * buffer. |
|
+ */ |
|
+ vim_shell_delete(buf); |
|
+ rval=2; |
|
+ } |
|
+ |
|
+ return rval; |
|
+} |
|
+ |
|
+/* |
|
+ * This function is called from two places: os_unix.c and ui.c, and handles |
|
+ * shell reads that are necessary because a select() became ready. This function |
|
+ * is here to avoid identical code in both places. |
|
+ * It returns the number of shell-reads. |
|
+ * If there was no activity in any of the shells, it returns 0. |
|
+ */ |
|
+int vim_shell_do_read_select(fd_set rfds) |
|
+{ |
|
+ /* |
|
+ * Loop through all buffers and see if they are vimshells. |
|
+ * If yes, check if there are read events ready for the appropriate |
|
+ * fds. If so, call the shell's read handler. |
|
+ */ |
|
+ buf_T *buf; |
|
+ int did_redraw=0; |
|
+ int rval=0; |
|
+ |
|
+ for(buf=firstbuf;buf!=NULL;buf=buf->b_next) |
|
+ { |
|
+ if(buf->is_shell != 0) |
|
+ { |
|
+ if(FD_ISSET(buf->shell->fd_master, &rfds)) |
|
+ { |
|
+ int r; |
|
+ |
|
+ r=vim_shell_do_read_lowlevel(buf); |
|
+ if(r>did_redraw) |
|
+ did_redraw=r; |
|
+ |
|
+ rval++; |
|
+ |
|
+ if(r==1 && updating_screen==FALSE) |
|
+ redraw_buf_later(buf, VALID); |
|
+ else if(r==2 && updating_screen==FALSE) |
|
+ redraw_buf_later(buf, CLEAR); |
|
+ } |
|
+ } |
|
+ } |
|
+ |
|
+ /* |
|
+ * Only redraw if we aren't currently redrawing, to avoid endless recursions. |
|
+ * update_screen calls win_update, which calls win_line, which calls breakcheck, |
|
+ * which again calls RealWaitForChar which calls this function ... |
|
+ */ |
|
+ if(updating_screen==FALSE) |
|
+ { |
|
+ if(did_redraw==1) |
|
+ { |
|
+ update_screen(VALID); |
|
+ } |
|
+ else if(did_redraw==2 || did_redraw==3) |
|
+ { |
|
+ update_screen(CLEAR); |
|
+ out_flush(); |
|
+ } |
|
+ } |
|
+ |
|
+ return rval; |
|
+} |
|
+#endif |
|
Index: src/vim_shell.h |
|
--- src/vim_shell.h.orig 2011-02-12 14:22:30.000000000 +0100 |
|
+++ src/vim_shell.h 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -0,0 +1,273 @@ |
|
+/* |
|
+ * vim_shell.h |
|
+ * |
|
+ * Global include file for VIM-Shell. Defines structures and interfaces. |
|
+ * |
|
+ * This file is part of the VIM-Shell project. http://vimshell.wana.at |
|
+ * |
|
+ * Author: Thomas Wana <thomas@wana.at> |
|
+ * |
|
+ * $Id$ |
|
+ */ |
|
+ |
|
+#ifndef __VIMSHELL_H |
|
+ |
|
+#define __VIMSHELL_H |
|
+ |
|
+#include "vim.h" |
|
+ |
|
+#include <stdio.h> |
|
+#ifdef HAVE_STDINT_H |
|
+#include <stdint.h> |
|
+#endif |
|
+#include <sys/types.h> |
|
+#include <sys/select.h> |
|
+ |
|
+/* |
|
+ * Master debug flag. Disable this and no debug messages at all will |
|
+ * be written anywhere. |
|
+ */ |
|
+//#define VIMSHELL_DEBUG |
|
+ |
|
+/* |
|
+ * Rendition constants |
|
+ */ |
|
+#define RENDITION_BOLD 1 |
|
+#define RENDITION_UNDERSCORE 2 |
|
+#define RENDITION_BLINK 4 |
|
+#define RENDITION_NEGATIVE 8 |
|
+#define RENDITION_DIM 16 |
|
+#define RENDITION_HIDDEN 32 |
|
+ |
|
+/* |
|
+ * charset constants |
|
+ */ |
|
+#define VIMSHELL_CHARSET_USASCII 0 |
|
+#define VIMSHELL_CHARSET_DRAWING 1 |
|
+ |
|
+/* |
|
+ * Color constants |
|
+ */ |
|
+#define VIMSHELL_COLOR_BLACK 0 |
|
+#define VIMSHELL_COLOR_RED 1 |
|
+#define VIMSHELL_COLOR_GREEN 2 |
|
+#define VIMSHELL_COLOR_YELLOW 3 |
|
+#define VIMSHELL_COLOR_BLUE 4 |
|
+#define VIMSHELL_COLOR_MAGENTA 5 |
|
+#define VIMSHELL_COLOR_CYAN 6 |
|
+#define VIMSHELL_COLOR_WHITE 7 |
|
+#define VIMSHELL_COLOR_DEFAULT 9 |
|
+ |
|
+#define vim_shell_malloc alloc |
|
+#define vim_shell_free vim_free |
|
+ |
|
+/* |
|
+ * The main vim_shell_window struct. |
|
+ * Holds everything that is needed to know about a single |
|
+ * vim shell. (like file descriptors, window buffers, window |
|
+ * positions, etc) |
|
+ */ |
|
+struct vim_shell_window |
|
+{ |
|
+ /* |
|
+ * current dimensions of the window |
|
+ */ |
|
+ uint16_t size_x; |
|
+ uint16_t size_y; |
|
+ |
|
+ /* |
|
+ * cursor position and visible flag |
|
+ */ |
|
+ uint16_t cursor_x; |
|
+ uint16_t cursor_y; |
|
+ uint16_t cursor_visible; |
|
+ |
|
+ /* |
|
+ * Saved cursor positions (ESC 7, ESC 8) |
|
+ */ |
|
+ uint16_t saved_cursor_x; |
|
+ uint16_t saved_cursor_y; |
|
+ |
|
+ /* |
|
+ * We support the xterm title hack and store the title in this buffer. |
|
+ */ |
|
+ char windowtitle[50]; |
|
+ |
|
+ /* |
|
+ * The output buffer. This is necessary because writes to the shell can be delayed, |
|
+ * e.g. if we are waiting for an incoming ESC sequence to complete. |
|
+ */ |
|
+ uint8_t outbuf[100]; |
|
+ uint8_t outbuf_pos; |
|
+ |
|
+ /* |
|
+ * Pointer to the window buffer. |
|
+ * The window buffer is the internal representation of the |
|
+ * window's content. The vim shell receives characters from |
|
+ * the terminal, which the terminal emulation translates into |
|
+ * e.g. cursor positions or actual characters. These are placed |
|
+ * here at the right screen position. Its size is size_y*size_x. |
|
+ */ |
|
+ uint8_t *winbuf; |
|
+ uint8_t *fgbuf; |
|
+ uint8_t *bgbuf; |
|
+ uint8_t *rendbuf; |
|
+ uint8_t *charset; |
|
+ |
|
+ /* |
|
+ * The tabulator line. It represents a single row. Zero means no |
|
+ * tab at this position, 1 means there is a tab. |
|
+ */ |
|
+ uint8_t *tabline; |
|
+ |
|
+ /* |
|
+ * These buffers hold what's currently physical on the screen. |
|
+ * Note, not on the "virtual" screen, that is the image of the shell, |
|
+ * but the real screen that is printed out in vim_shell_redraw. |
|
+ * This is mainly to implement caching features... |
|
+ * We hold here: |
|
+ * 1 byte foreground-color |
|
+ * 1 byte background-color |
|
+ * 1 byte rendering attributes |
|
+ * 1 byte the actual character |
|
+ */ |
|
+ uint32_t *phys_screen; |
|
+ |
|
+ /* |
|
+ * Flag that determines if we are right in the middle of an |
|
+ * escape sequence coming in. |
|
+ */ |
|
+ uint8_t in_esc_sequence; |
|
+ |
|
+ /* |
|
+ * Buffer for a escape sequence in progress (see in_esc_sequence). |
|
+ */ |
|
+ uint8_t esc_sequence[50]; |
|
+ |
|
+ /* |
|
+ * Auto-Margin enabled? |
|
+ */ |
|
+ uint8_t wraparound; |
|
+ |
|
+ /* |
|
+ * Caused the last character a warp around? |
|
+ */ |
|
+ uint8_t just_wrapped_around; |
|
+ |
|
+ /* |
|
+ * The currently used rendition of the shell. |
|
+ */ |
|
+ uint8_t rendition; |
|
+ uint8_t saved_rendition; |
|
+ |
|
+ /* |
|
+ * The currently active colors. |
|
+ */ |
|
+ uint8_t fgcolor; |
|
+ uint8_t bgcolor; |
|
+ uint8_t saved_fgcolor; |
|
+ uint8_t saved_bgcolor; |
|
+ |
|
+ /* |
|
+ * Scroll region. |
|
+ */ |
|
+ uint8_t scroll_top_margin; |
|
+ uint8_t scroll_bottom_margin; |
|
+ |
|
+ /* |
|
+ * Charset configuration. |
|
+ */ |
|
+ uint8_t G0_charset; |
|
+ uint8_t G1_charset; |
|
+ uint8_t active_charset; |
|
+ uint8_t saved_G0_charset; |
|
+ uint8_t saved_G1_charset; |
|
+ uint8_t saved_active_charset; |
|
+ |
|
+ /* |
|
+ * Mode switches. |
|
+ */ |
|
+ uint8_t application_keypad_mode; |
|
+ uint8_t application_cursor_mode; |
|
+ uint8_t saved_application_keypad_mode; |
|
+ uint8_t saved_application_cursor_mode; |
|
+ |
|
+ uint8_t insert_mode; |
|
+ uint8_t saved_insert_mode; |
|
+ |
|
+ /* |
|
+ * This flag determines if the shell should be completely redrawn in the next |
|
+ * vim_shell_redraw, regardless of what we think to know about the screen. |
|
+ */ |
|
+ uint8_t force_redraw; |
|
+ |
|
+ /* |
|
+ * Pointer to the alternate screen. If NULL, there is no alternate screen. |
|
+ * If not NULL, this holds a backup of the screen contents and properties |
|
+ * before the screen switch. Switching back means to copy back the contents |
|
+ * of the alternate screen to the main screen and freeing the alternate screen. |
|
+ */ |
|
+ struct vim_shell_window *alt; |
|
+ |
|
+ /* |
|
+ * file descriptor of the master side of the pty |
|
+ */ |
|
+ int fd_master; |
|
+ |
|
+ /* |
|
+ * pid of the subshell |
|
+ */ |
|
+ pid_t pid; |
|
+ |
|
+}; |
|
+ |
|
+/* |
|
+ * This is set when something goes wrong in one of the |
|
+ * vim_shell functions. |
|
+ */ |
|
+extern int vimshell_errno; |
|
+ |
|
+/* |
|
+ * The debug handle where debug-messages will be written |
|
+ */ |
|
+extern FILE *vimshell_debug_fp; |
|
+ |
|
+#define VIMSHELL_SUCCESS 0 |
|
+#define VIMSHELL_OUT_OF_MEMORY 1 |
|
+#define VIMSHELL_FORKPTY_ERROR 2 |
|
+#define VIMSHELL_READ_ERROR 3 |
|
+#define VIMSHELL_WRITE_ERROR 4 |
|
+#define VIMSHELL_EXECV_ERROR 5 |
|
+#define VIMSHELL_SIGACTION_ERROR 6 |
|
+#define VIMSHELL_READ_EOF 7 |
|
+#define VIMSHELL_FCNTL_ERROR 8 |
|
+ |
|
+/* |
|
+ * vim_shell.c |
|
+ */ |
|
+extern int vim_shell_init(); |
|
+extern struct vim_shell_window *vim_shell_new(uint16_t width, uint16_t height); |
|
+extern int vim_shell_start(struct vim_shell_window *shell, char *argv[]); |
|
+extern char *vim_shell_strerror(); |
|
+extern int vim_shell_read(struct vim_shell_window *shell); |
|
+extern int vim_shell_write(struct vim_shell_window *shell, int c); |
|
+extern void vim_shell_redraw(struct vim_shell_window *shell, win_T *win); |
|
+extern int vim_shell_do_read_select(fd_set rfds); |
|
+extern int vim_shell_do_read_lowlevel(buf_T *buf); |
|
+extern void vim_shell_delete(buf_T *buf); |
|
+extern void vim_shell_resize(struct vim_shell_window *shell, int width, int height); |
|
+ |
|
+/* |
|
+ * terminal.c |
|
+ */ |
|
+extern void vim_shell_terminal_input(struct vim_shell_window *shell, char *input, int len); |
|
+extern int vim_shell_terminal_output(struct vim_shell_window *shell, int c); |
|
+ |
|
+/* |
|
+ * screen.c |
|
+ */ |
|
+extern int screen_cur_row, screen_cur_col; /* last known cursor position */ |
|
+extern void screen_start_highlight __ARGS((int attr)); |
|
+extern int screen_attr; |
|
+ |
|
+#endif |
|
Index: src/window.c |
|
--- src/window.c.orig 2010-07-20 22:23:49.000000000 +0200 |
|
+++ src/window.c 2011-02-12 14:22:30.000000000 +0100 |
|
@@ -119,6 +119,13 @@ |
|
# define CHECK_CMDWIN |
|
#endif |
|
|
|
+#ifdef FEAT_VIMSHELL |
|
+# define CHECK_VIMSHELL if (curwin->w_buffer->is_shell != 0) { EMSG("VIMSHELL: command not available for shell windows"); break; } |
|
+#else |
|
+# define CHECK_VIMSHELL |
|
+#endif |
|
+ |
|
+ |
|
switch (nchar) |
|
{ |
|
/* split current window in two parts, horizontally */ |
|
@@ -486,6 +493,7 @@ |
|
#if defined(FEAT_QUICKFIX) |
|
case '}': |
|
CHECK_CMDWIN |
|
+ CHECK_VIMSHELL |
|
if (Prenum) |
|
g_do_tagpreview = Prenum; |
|
else |
|
@@ -495,6 +503,7 @@ |
|
case ']': |
|
case Ctrl_RSB: |
|
CHECK_CMDWIN |
|
+ CHECK_VIMSHELL |
|
#ifdef FEAT_VISUAL |
|
reset_VIsual_and_resel(); /* stop Visual mode */ |
|
#endif |
|
@@ -515,6 +524,7 @@ |
|
case Ctrl_F: |
|
wingotofile: |
|
CHECK_CMDWIN |
|
+ CHECK_VIMSHELL |
|
|
|
ptr = grab_file_name(Prenum1, &lnum); |
|
if (ptr != NULL) |
|
@@ -553,6 +563,7 @@ |
|
case 'd': /* Go to definition, using 'define' */ |
|
case Ctrl_D: |
|
CHECK_CMDWIN |
|
+ CHECK_VIMSHELL |
|
if ((len = find_ident_under_cursor(&ptr, FIND_IDENT)) == 0) |
|
break; |
|
find_pattern_in_path(ptr, 0, len, TRUE, |
|
@@ -584,6 +595,7 @@ |
|
case 'g': |
|
case Ctrl_G: |
|
CHECK_CMDWIN |
|
+ CHECK_VIMSHELL |
|
#ifdef USE_ON_FLY_SCROLL |
|
dont_scroll = TRUE; /* disallow scrolling here */ |
|
#endif |
|
@@ -5600,6 +5612,15 @@ |
|
wp->w_redr_status = TRUE; |
|
#endif |
|
invalidate_botline_win(wp); |
|
+ |
|
+#ifdef FEAT_VIMSHELL |
|
+ if(wp->w_buffer->is_shell!=0) |
|
+ { |
|
+ struct vim_shell_window *shell=wp->w_buffer->shell; |
|
+ vim_shell_resize(shell, shell->size_x, height); |
|
+ redraw_win_later(wp, CLEAR); |
|
+ } |
|
+#endif |
|
} |
|
|
|
#ifdef FEAT_VERTSPLIT |
|
@@ -5622,6 +5643,14 @@ |
|
} |
|
redraw_win_later(wp, NOT_VALID); |
|
wp->w_redr_status = TRUE; |
|
+#ifdef FEAT_VIMSHELL |
|
+ if(wp->w_buffer->is_shell!=0) |
|
+ { |
|
+ struct vim_shell_window *shell=wp->w_buffer->shell; |
|
+ vim_shell_resize(shell, width, shell->size_y); |
|
+ redraw_win_later(wp, CLEAR); |
|
+ } |
|
+#endif |
|
} |
|
#endif |
|
|
|
|