aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjixiufeng <jixiufeng@luojilab.com>2018-10-25 00:08:23 +0800
committerjixiufeng <jixiufeng@luojilab.com>2018-10-25 21:33:44 +0800
commita18e037ee61afa5e91e955e26710d068d3ee1f9c (patch)
tree95697e12bc66066ee2f57775c4639bd60a065f36
parent319f99f6ecc0babba7257cf9fbd156733dd83f62 (diff)
try support scroll
-rw-r--r--elisp.c30
-rw-r--r--elisp.h13
-rw-r--r--vterm-module.c408
-rw-r--r--vterm-module.h33
-rw-r--r--vterm.el80
5 files changed, 490 insertions, 74 deletions
diff --git a/elisp.c b/elisp.c
index df71327..1313f06 100644
--- a/elisp.c
+++ b/elisp.c
@@ -86,6 +86,35 @@ void goto_char(emacs_env *env, int pos) {
env->funcall(env, Fgoto_char, 1, (emacs_value[]){point});
}
+void forward_line(emacs_env *env, int n) {
+ emacs_value nline = env->make_integer(env, n );
+ env->funcall(env, Fforward_line, 1, (emacs_value[]){nline});
+}
+void goto_line(emacs_env *env, int n) {
+ emacs_value nline = env->make_integer(env, n );
+ env->funcall(env, Fgoto_line, 1, (emacs_value[]){nline});
+}
+void delete_lines(emacs_env *env ,int linenum,int count ,bool del_whole_line){
+ emacs_value Qlinenum = env->make_integer(env, linenum);
+ emacs_value Qcount = env->make_integer(env, count);
+ if(del_whole_line){
+ env->funcall(env, Fdelete_lines, 3, (emacs_value[]){Qlinenum,Qcount,Qt});
+ }else{
+ env->funcall(env, Fdelete_lines, 3, (emacs_value[]){Qlinenum,Qcount,Qnil});
+ }
+}
+void recenter(emacs_env *env, emacs_value pos){
+ env->funcall(env, Frecenter, 1,
+ (emacs_value[]){pos});
+}
+void forward_char(emacs_env *env, emacs_value n){
+ env->funcall(env, Fforward_char, 1,
+ (emacs_value[]){n});
+}
+emacs_value buffer_line_number(emacs_env *env){
+ return env->funcall(env, Fbuffer_line_number, 0, (emacs_value[]){});
+}
+
void toggle_cursor(emacs_env *env, bool visible) {
emacs_value Qvisible = visible ? Qt : Qnil;
env->funcall(env, Fset, 2, (emacs_value[]){Qcursor_type, Qvisible});
@@ -100,3 +129,4 @@ emacs_value get_hex_color_bg(emacs_env *env, emacs_value face) {
return env->funcall(env, Fvterm_face_color_hex, 2,
(emacs_value[]){face, Qbackground});
}
+
diff --git a/elisp.h b/elisp.h
index 275581e..befc553 100644
--- a/elisp.h
+++ b/elisp.h
@@ -26,6 +26,12 @@ emacs_value Flist;
emacs_value Ferase_buffer;
emacs_value Finsert;
emacs_value Fgoto_char;
+emacs_value Fforward_char;
+emacs_value Fforward_line;
+emacs_value Fgoto_line;
+emacs_value Fdelete_lines;
+emacs_value Fbuffer_line_number;
+emacs_value Frecenter;
emacs_value Fput_text_property;
emacs_value Fset;
emacs_value Fvterm_face_color_hex;
@@ -46,8 +52,13 @@ VTermColor rgb_string_to_color(emacs_env *env, emacs_value string);
void erase_buffer(emacs_env *env);
void insert(emacs_env *env, emacs_value string);
void goto_char(emacs_env *env, int pos);
+void forward_line(emacs_env *env, int n) ;
+void goto_line(emacs_env *env, int n) ;
void toggle_cursor(emacs_env *env, bool visible);
+void delete_lines(emacs_env *env ,int linenum,int count ,bool del_whole_line);
emacs_value get_hex_color_fg(emacs_env *env, emacs_value face);
emacs_value get_hex_color_bg(emacs_env *env, emacs_value face);
-
+emacs_value buffer_line_number(emacs_env *env);
+void recenter(emacs_env *env, emacs_value pos);
+void forward_char(emacs_env *env, emacs_value n);
#endif /* ELISP_H */
diff --git a/vterm-module.c b/vterm-module.c
index 58e457f..fcd8cb3 100644
--- a/vterm-module.c
+++ b/vterm-module.c
@@ -3,7 +3,316 @@
#include "utf8.h"
#include <string.h>
#include <unistd.h>
+#include <limits.h>
#include <vterm.h>
+#include <assert.h>
+
+static int term_sb_push(int cols, const VTermScreenCell *cells, void *data) {
+ Term *term = (Term *)data;
+
+ if (!term->sb_size) {
+ return 0;
+ }
+
+ // copy vterm cells into sb_buffer
+ size_t c = (size_t)cols;
+ ScrollbackLine *sbrow = NULL;
+ if (term->sb_current == term->sb_size) {
+ if (term->sb_buffer[term->sb_current - 1]->cols == c) {
+ // Recycle old row if it's the right size
+ sbrow = term->sb_buffer[term->sb_current - 1];
+ } else {
+ free(term->sb_buffer[term->sb_current - 1]);
+ }
+
+ // Make room at the start by shifting to the right.
+ memmove(term->sb_buffer + 1, term->sb_buffer,
+ sizeof(term->sb_buffer[0]) * (term->sb_current - 1));
+
+ } else if (term->sb_current > 0) {
+ // Make room at the start by shifting to the right.
+ memmove(term->sb_buffer + 1, term->sb_buffer,
+ sizeof(term->sb_buffer[0]) * term->sb_current);
+ }
+
+ if (!sbrow) {
+ sbrow = malloc(sizeof(ScrollbackLine) + c * sizeof(sbrow->cells[0]));
+ sbrow->cols = c;
+ }
+
+ // New row is added at the start of the storage buffer.
+ term->sb_buffer[0] = sbrow;
+ if (term->sb_current < term->sb_size) {
+ term->sb_current++;
+ }
+
+ if (term->sb_pending < (int)term->sb_size) {
+ term->sb_pending++;
+ }
+
+ memcpy(sbrow->cells, cells, sizeof(cells[0]) * c);
+
+ return 1;
+}
+/// Scrollback pop handler (from pangoterm).
+///
+/// @param cols
+/// @param cells VTerm state to update.
+/// @param data Term
+static int term_sb_pop(int cols, VTermScreenCell *cells, void *data){
+ Term *term = (Term *)data;
+
+ if (!term->sb_current) {
+ return 0;
+ }
+
+ if (term->sb_pending) {
+ term->sb_pending--;
+ }
+
+ ScrollbackLine *sbrow = term->sb_buffer[0];
+ term->sb_current--;
+ // Forget the "popped" row by shifting the rest onto it.
+ memmove(term->sb_buffer, term->sb_buffer + 1,
+ sizeof(term->sb_buffer[0]) * (term->sb_current));
+
+ size_t cols_to_copy = (size_t)cols;
+ if (cols_to_copy > sbrow->cols) {
+ cols_to_copy = sbrow->cols;
+ }
+
+ // copy to vterm state
+ memcpy(cells, sbrow->cells, sizeof(cells[0]) * cols_to_copy);
+ size_t col ;
+ for (col = cols_to_copy; col < (size_t)cols; col++) {
+ cells[col].chars[0] = 0;
+ cells[col].width = 1;
+ }
+
+ free(sbrow);
+
+ return 1;
+}
+
+static int row_to_linenr(Term *term, int row){
+ return row != INT_MAX ? row + (int)term->sb_current + 1 : INT_MAX;
+}
+
+static int linenr_to_row(Term *term, int linenr){
+ return linenr - (int)term->sb_current - 1;
+}
+
+static void fetch_cell(Term *term, int row, int col,
+ VTermScreenCell *cell){
+ if (row < 0) {
+ ScrollbackLine *sbrow = term->sb_buffer[-row - 1];
+ if ((size_t)col < sbrow->cols) {
+ *cell = sbrow->cells[col];
+ } else {
+ // fill the pointer with an empty cell
+ VTermColor fg, bg;
+ VTermState *state = vterm_obtain_state(term->vt);
+ vterm_state_get_default_colors(state, &fg, &bg);
+
+ *cell = (VTermScreenCell) {
+ .chars = { 0 },
+ .width = 1,
+ .bg = bg
+ };
+ }
+ } else {
+ vterm_screen_get_cell(term->vts, (VTermPos){.row = row, .col = col},
+ cell);
+ }
+}
+
+static size_t get_col_offset(Term *term, int row, int end_col){
+ int col = 0;
+ size_t offset = 0;
+ unsigned char buf[4];
+
+ while (col < end_col) {
+ VTermScreenCell cell;
+ fetch_cell(term, row, col, &cell);
+ if (cell.chars[0]) {
+ if(cell.width>1){
+ offset+=cell.width-1;
+ }
+ }
+ col += cell.width;
+
+ }
+ return offset;
+}
+
+static size_t refresh_row(Term *term,emacs_env* env, int row,
+ int end_col,bool append_newline){
+ int j;
+ char *ptr = term->textbuf;
+ int length = 0;
+ VTermScreenCell cell;
+ VTermScreenCell lastCell;
+ fetch_cell(term, row, 0, &lastCell);
+
+ for (j = 0; j < end_col; j++) {
+ VTermPos pos = {.row = row, .col = j};
+ fetch_cell(term, row, j, &cell);
+
+ if (!compare_cells(&cell, &lastCell)) {
+ ptr[length]='\0';
+ emacs_value text = render_text(env, ptr, length, &lastCell);
+ insert(env,text);
+ ptr+=length;
+ length = 0;
+ }
+
+ lastCell = cell;
+ if (cell.chars[0] == 0) {
+ ptr[length] = ' ';
+ length++;
+ } else {
+ unsigned char bytes[4];
+ size_t count = codepoint_to_utf8(cell.chars[0], bytes);
+ int k;
+ for (k = 0; k < count; k++) {
+ ptr[length] = bytes[k];
+ length++;
+ }
+ }
+
+ if (cell.width > 1) {
+ int w = cell.width - 1;
+ j = j + w;
+ }
+
+ }
+ if(length>0){
+ emacs_value text = render_text(env, ptr, length, &lastCell);
+ insert(env,text);
+ ptr+=length;
+ }
+ if(append_newline){
+ *ptr='\n';
+ ptr+=1;
+ insert(env,env->make_string(env, "\n", 1));
+ }
+ *ptr=0;
+ return ptr-term->textbuf;
+}
+
+// Refresh the screen (visible part of the buffer when the terminal is
+// focused) of a invalidated terminal
+static void refresh_screen(Term *term,emacs_env *env){
+ int height;
+ int width;
+ vterm_get_size(term->vt, &height, &width);
+ // Term height may have decreased before `invalid_end` reflects it.
+ /* refresh full screen now */
+ /* TODO: only refresh invalid lines */
+ term->invalid_start = 0;
+ term->invalid_end = height;
+
+ int line_start=row_to_linenr(term, term->invalid_start);
+ goto_line(env,line_start-1);
+ int liner ;
+ int r;
+ for (r = term->invalid_start; r < term->invalid_end; r++) {
+ liner =row_to_linenr(term,r);
+ int buffer_lnum = env->extract_integer(env, buffer_line_number(env));
+ if(liner>buffer_lnum){
+ goto_line(env,buffer_lnum); /* maybe should goto end of buffer */
+ int i;
+ for (i = 0; i < liner-buffer_lnum; i++){
+ insert(env,env->make_string(env,"\n",1));
+ }
+ }
+ delete_lines(env,liner,1,false);
+ goto_line(env,liner);
+ refresh_row(term,env,r,width,false);
+ }
+ term->invalid_start = INT_MAX;
+ term->invalid_end = -1;
+}
+
+
+// Refresh the scrollback of an invalidated terminal.
+static void refresh_scrollback(Term *term,emacs_env *env) {
+ int width, height;
+ int buffer_lnum ;
+ vterm_get_size(term->vt, &height, &width);
+
+ while (term->sb_pending > 0) {
+ // This means that either the window height has decreased or the screen
+ // became full and libvterm had to push all rows up. Convert the first
+ // pending scrollback row into a string and append it just above the visible
+ // section of the buffer
+ buffer_lnum = env->extract_integer(env, buffer_line_number(env));
+
+ if ((buffer_lnum- height) >= (int)term->sb_size) {
+ // scrollback full, delete lines at the top
+ delete_lines(env,1, 1,true);
+ /* insert(env,env->make_string(env, "\n", 1)); */
+ }
+ buffer_lnum = env->extract_integer(env, buffer_line_number(env));
+ int buf_index = buffer_lnum- height+1;
+ goto_line(env,buf_index);
+ size_t length=refresh_row(term,env,-term->sb_pending,width,true);
+ term->sb_pending--;
+ }
+ // Remove extra lines at the bottom
+ int max_line_count = (int)term->sb_current + height;
+ buffer_lnum=env->extract_integer(env, buffer_line_number(env));
+
+ // Remove extra lines at the bottom
+ if (buffer_lnum> max_line_count) {
+ delete_lines(env,max_line_count,buffer_lnum-max_line_count, true);
+ }
+}
+
+static void adjust_topline(Term *term,emacs_env *env, long added){
+ int height, width;
+ vterm_get_size(term->vt, &height, &width);
+ /* FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { */
+ int buffer_lnum = env->extract_integer(env, buffer_line_number(env));
+ VTermState *state = vterm_obtain_state(term->vt);
+ VTermPos pos;
+ vterm_state_get_cursorpos(state, &pos);
+ int cursor_lnum=row_to_linenr(term,pos.row);
+ bool following = buffer_lnum ==cursor_lnum + added; // cursor at end?
+
+
+ if (following ) { /* || (wp == curwin && is_focused(term)) */
+ // "Follow" the terminal output
+ goto_line(env,MIN(cursor_lnum,buffer_lnum));
+ size_t offset=get_col_offset(term,pos.row,pos.col);
+ forward_char(env,env->make_integer(env,pos.col-offset));
+ recenter(env,env->make_integer(env,-1)); /* make current lien at the screen bottom */
+
+ } else {
+ goto_line(env,MIN(cursor_lnum,buffer_lnum));
+ size_t offset=get_col_offset(term,pos.row,pos.col);
+ forward_char(env,env->make_integer(env,pos.col-offset));
+ recenter(env,env->make_integer(env,pos.row));
+ }
+}
+static void term_redraw(Term *term,emacs_env *env) {
+ long ml_before = env->extract_integer(env, buffer_line_number(env));
+ refresh_scrollback(term,env);
+ refresh_screen(term,env);
+ long ml_added = env->extract_integer(env, buffer_line_number(env))- ml_before;
+ adjust_topline(term,env, ml_added);
+}
+
+static VTermScreenCallbacks vterm_screen_callbacks = {
+ /* .damage = term_damage, */
+ /* .moverect = term_moverect, */
+ /* .movecursor = term_movecursor, */
+ /* .settermprop = term_settermprop, */
+ /* .bell = term_bell, */
+ .sb_pushline = term_sb_push,
+ .sb_popline = term_sb_pop,
+};
+
static bool compare_cells(VTermScreenCell *a, VTermScreenCell *b) {
bool equal = true;
@@ -41,7 +350,14 @@ static int set_term_prop_cb(VTermProp prop, VTermValue *val, void *user_data) {
static emacs_value render_text(emacs_env *env, char *buffer, int len,
VTermScreenCell *cell) {
- emacs_value text = env->make_string(env, buffer, len);
+ emacs_value text;
+ if(len==0){
+ text= env->make_string(env, "", 0);
+ return text;
+ /* return NULL; */
+ }else{
+ text= env->make_string(env, buffer, len);
+ }
emacs_value foreground = color_to_rgb_string(env, cell->fg);
emacs_value background = color_to_rgb_string(env, cell->bg);
@@ -64,64 +380,7 @@ static emacs_value render_text(emacs_env *env, char *buffer, int len,
return text;
}
-static void term_redraw(Term *term, emacs_env *env) {
- int i, j;
- int rows, cols;
- VTermScreen *screen = vterm_obtain_screen(term->vt);
- vterm_get_size(term->vt, &rows, &cols);
-
- erase_buffer(env);
-
- char buffer[((rows + 1) * cols) * 4];
- int length = 0;
- VTermScreenCell cell;
- VTermScreenCell lastCell;
- VTermPos first = {.row = 0, .col = 0};
- vterm_screen_get_cell(screen, first, &lastCell);
-
- int offset = 0;
- for (i = 0; i < rows; i++) {
- for (j = 0; j < cols; j++) {
- VTermPos pos = {.row = i, .col = j};
- vterm_screen_get_cell(screen, pos, &cell);
-
- if (!compare_cells(&cell, &lastCell)) {
- emacs_value text = render_text(env, buffer, length, &lastCell);
- insert(env, text);
- length = 0;
- }
-
- lastCell = cell;
- if (cell.chars[0] == 0) {
- buffer[length] = ' ';
- length++;
- } else {
- unsigned char bytes[4];
- size_t count = codepoint_to_utf8(cell.chars[0], bytes);
- for (int k = 0; k < count; k++) {
- buffer[length] = bytes[k];
- length++;
- }
- }
-
- if (cell.width > 1) {
- int w = cell.width - 1;
- offset += w;
- j = j + w;
- }
- }
-
- buffer[length] = '\n';
- length++;
- }
- emacs_value text = render_text(env, buffer, length, &lastCell);
- insert(env, text);
- VTermState *state = vterm_obtain_state(term->vt);
- VTermPos pos;
- vterm_state_get_cursorpos(state, &pos);
- term_put_caret(term, env, pos.row, pos.col, -offset);
-}
static void term_setup_colors(Term *term, emacs_env *env) {
VTermColor fg, bg;
@@ -253,7 +512,7 @@ static void term_put_caret(Term *term, emacs_env *env, int row, int col,
vterm_get_size(term->vt, &rows, &cols);
// row * (cols + 1) because of newline character
// col + 1 because (goto-char 1) sets point to first position
- int point = (row * (cols + 1)) + col + 1 + offset;
+ int point = ((row+term->sb_current) * (cols + 1)) + col + 1 + offset;
goto_char(env, point);
}
@@ -269,14 +528,26 @@ static emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs,
int rows = env->extract_integer(env, args[0]);
int cols = env->extract_integer(env, args[1]);
+ int sb_size = env->extract_integer(env, args[2]);
term->vt = vterm_new(rows, cols);
vterm_set_utf8(term->vt, 1);
term_setup_colors(term, env);
- VTermScreen *screen = vterm_obtain_screen(term->vt);
- vterm_screen_reset(screen, 1);
+
+ term->vts = vterm_obtain_screen(term->vt);
+ vterm_screen_reset(term->vts , 1);
+ vterm_screen_set_callbacks(term->vts , &vterm_screen_callbacks, term);
+ vterm_screen_set_damage_merge(term->vts , VTERM_DAMAGE_SCROLL);
+ term->sb_size = MIN(SB_MAX,sb_size);
+ term->sb_current = 0;
+ term->sb_pending = 0;
+ term->sb_buffer = malloc(sizeof(ScrollbackLine *) * term->sb_size);
+ term->invalid_start=0;
+ term->invalid_end=cols;
+
+
return env->make_user_ptr(env, term_finalize, term);
}
@@ -334,11 +605,11 @@ static emacs_value Fvterm_set_size(emacs_env *env, ptrdiff_t nargs,
if (cols != old_cols || rows != old_rows) {
vterm_set_size(term->vt, rows, cols);
+ term_redraw(term,env);
}
return Qnil;
}
-
int emacs_module_init(struct emacs_runtime *ert) {
emacs_env *env = ert->get_environment(ert);
@@ -368,6 +639,15 @@ int emacs_module_init(struct emacs_runtime *ert) {
Fset = env->make_global_ref(env, env->intern(env, "set"));
Fvterm_face_color_hex = env->make_global_ref(env, env->intern(env, "vterm--face-color-hex"));
Fvterm_flush_output = env->make_global_ref(env, env->intern(env, "vterm--flush-output"));
+ Fforward_line = env->make_global_ref(env, env->intern(env, "forward-line"));
+ Fgoto_line = env->make_global_ref(env, env->intern(env, "vterm--goto-line"));
+ Fbuffer_line_number = env->make_global_ref(env, env->intern(env, "vterm--buffer-line-num"));
+ Fdelete_lines = env->make_global_ref(env, env->intern(env, "vterm--delete-lines"));
+ Frecenter = env->make_global_ref(env,env->intern(env, "vterm--recenter"));
+ Fforward_char = env->make_global_ref(env,env->intern(env, "vterm--forward-char"));
+
+
+
// Faces
Qterm = env->make_global_ref(env, env->intern(env, "vterm"));
@@ -383,7 +663,7 @@ int emacs_module_init(struct emacs_runtime *ert) {
// Exported functions
emacs_value fun;
fun =
- env->make_function(env, 2, 2, Fvterm_new, "Allocates a new vterm.", NULL);
+ env->make_function(env, 3, 3, Fvterm_new, "Allocates a new vterm.", NULL);
bind_function(env, "vterm--new", fun);
fun = env->make_function(env, 1, 5, Fvterm_update,
@@ -399,6 +679,6 @@ int emacs_module_init(struct emacs_runtime *ert) {
bind_function(env, "vterm--set-size", fun);
provide(env, "vterm-module");
-
return 0;
}
+
diff --git a/vterm-module.h b/vterm-module.h
index 808fb02..775b59d 100644
--- a/vterm-module.h
+++ b/vterm-module.h
@@ -7,10 +7,41 @@
#include <vterm.h>
int plugin_is_GPL_compatible;
+typedef struct {
+ size_t cols;
+ VTermScreenCell cells[];
+} ScrollbackLine;
+
+#define SB_MAX 100000 // Maximum 'scrollback' value.
+static bool refresh_pending = false;
+
+#ifndef MIN
+# define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
+#endif
+#ifndef MAX
+# define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
+#endif
+
-struct Term {
struct term {
VTerm *vt;
+ VTermScreen *vts;
+ // buffer used to:
+ // - convert VTermScreen cell arrays into utf8 strings
+ // - receive data from libvterm as a result of key presses.
+ char textbuf[0x1fff];
+ ScrollbackLine **sb_buffer; // Scrollback buffer storage for libvterm
+ size_t sb_current; // number of rows pushed to sb_buffer
+ size_t sb_size; // sb_buffer size
+ // "virtual index" that points to the first sb_buffer row that we need to
+ // push to the terminal buffer when refreshing the scrollback. When negative,
+ // it actually points to entries that are no longer in sb_buffer (because the
+ // window height has increased) and must be deleted from the terminal buffer
+ int sb_pending;
+
+
+ int invalid_start, invalid_end; // invalid rows in libvterm screen
+
};
diff --git a/vterm.el b/vterm.el
index a47439f..53f1863 100644
--- a/vterm.el
+++ b/vterm.el
@@ -37,13 +37,20 @@
(defcustom vterm-shell (getenv "SHELL")
"The shell that gets run in the vterm."
+ :type 'string
:group 'vterm)
-(defcustom vterm-keymap-exceptions '("C-x" "C-u" "C-g" "C-h" "M-x" "M-o")
+(defcustom vterm-max-scrollback 1000
+ "Maximum 'scrollback' value."
+ :type 'number
+ :group 'vterm)
+
+(defcustom vterm-keymap-exceptions '("C-x" "C-u" "C-g" "C-h" "M-x" "M-o" "C-v" "M-v")
"Exceptions for vterm-keymap.
If you use a keybinding with a prefix-key that prefix-key cannot
be send to the terminal."
+ :type '(repeat string)
:group 'vterm)
(defface vterm
@@ -102,15 +109,21 @@ be send to the terminal."
(define-derived-mode vterm-mode fundamental-mode "VTerm"
"Mayor mode for vterm buffer."
(buffer-disable-undo)
- (setq vterm--term (vterm--new (window-body-height) (window-body-width))
- buffer-read-only t)
+ (setq vterm--term (vterm--new (window-body-height)
+ (window-body-width)
+ vterm-max-scrollback))
+ (cl-loop repeat (1- (window-body-height)) do
+ (insert "\n"))
+
+ (setq buffer-read-only t)
(setq-local scroll-conservatively 101)
(setq-local scroll-margin 0)
+
(add-hook 'window-size-change-functions #'vterm--window-size-change t t)
(let ((process-environment (append '("TERM=xterm") process-environment)))
(setq vterm--process (make-process
:name "vterm"
- :buffer buffer
+ :buffer (current-buffer)
:command `("/bin/sh" "-c" ,(format "stty -nl sane iutf8 rows %d columns %d >/dev/null && exec %s" (window-body-height) (window-body-width) vterm-shell))
:coding 'no-conversion
:connection-type 'pty
@@ -152,16 +165,17 @@ be send to the terminal."
"Create a new vterm."
(interactive)
(let ((buffer (generate-new-buffer "vterm")))
- (set-buffer buffer)
- (vterm-mode)
+ (with-current-buffer buffer
+ (vterm-mode))
(switch-to-buffer buffer)))
(defun vterm-other-window ()
"Create a new vterm."
(interactive)
(let ((buffer (generate-new-buffer "vterm")))
- (set-buffer buffer)
- (vterm-mode)
+ (with-current-buffer buffer
+ (vterm-mode))
+
(pop-to-buffer buffer)))
(defun vterm--flush-output (output)
@@ -197,5 +211,55 @@ Feeds the size change to the virtual terminal."
(apply #'color-rgb-to-hex (color-name-to-rgb (face-attribute face attr nil 'default)))
(apply #'color-rgb-to-hex (append (color-name-to-rgb (face-attribute face attr nil 'default)) '(2)))))
+
+(defun vterm--delete-lines (line-num count &optional delete-whole-line)
+ "Delete lines from line-num. If option ‘kill-whole-line’ is non-nil,
+ then this command kills the whole line including its terminating newline"
+ (ignore-errors
+ (save-excursion
+ (when (vterm--goto-line line-num)
+ (delete-region (point) (point-at-eol))
+ (when delete-whole-line
+ (when (looking-at "\n")
+ (delete-char 1))
+ (when (and (eobp) (looking-back "\n"))
+ (delete-char -1))
+
+ )
+ (cl-loop repeat (1- count) do
+ (when (or delete-whole-line (forward-line 1))
+ (delete-region (point) (point-at-eol))
+ (when delete-whole-line
+ (when (looking-at "\n")
+ (delete-char 1))
+ (when (and (eobp) (looking-back "\n"))
+ (delete-char -1)))
+ ))))))
+
+
+
+(defun vterm--recenter(&optional arg)
+ (when (get-buffer-window)
+ (with-current-buffer (window-buffer)
+ (when vterm--term
+ (recenter arg)))))
+
+(defun vterm--goto-line(n)
+ "If move succ return t"
+ (ignore-errors
+ (goto-char (point-min))
+ (let ((succ (eq 0 (forward-line (1- n)))))
+ succ)))
+
+(defun vterm--buffer-line-num()
+ (ignore-errors
+ (save-excursion
+ (goto-char (point-max))
+ (line-number-at-pos))))
+
+(defun vterm--forward-char(n )
+ (ignore-errors
+ (forward-char n)))
+
(provide 'vterm)
;;; vterm.el ends here