From f09547567544d0ac8a618af8d5a17a10a31a6475 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20F=C3=BCrmetz?= Date: Sat, 3 Aug 2019 13:32:46 +0200 Subject: Add directory tracking via OSC callback Solves #55 --- README.md | 19 ++++++++++++++++++ elisp.c | 5 +++++ elisp.h | 2 ++ vterm-module.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- vterm-module.h | 5 ++++- vterm.el | 13 +++++++++---- 6 files changed, 96 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2746558..8753cac 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,25 @@ color you like: - vterm-color-cyan - vterm-color-white +## Directory tracking + +For `zsh` put this in your `.zshrc`: + +```zsh +function chpwd() { + echo -e "\e]51;$(pwd)\e\\" +} +``` + +For bash there's no real change directory hook, so you have to rewrite the cd +command (please als have a look the answers [here](https://unix.stackexchange.com/q/170279)): + +```bash +cd() { + builtin cd "$@" || return + [ "$OLDPWD" = "$PWD" ] || echo -e "\e]51;$(pwd)\e\\" +} +``` ## Related packages diff --git a/elisp.c b/elisp.c index beaf5d6..4f2f106 100644 --- a/elisp.c +++ b/elisp.c @@ -112,10 +112,15 @@ emacs_value vterm_get_color(emacs_env *env, int index) { emacs_value idx = env->make_integer(env, index); return env->funcall(env, Fvterm_get_color, 1, (emacs_value[]){idx}); } + void set_title(emacs_env *env, emacs_value string) { env->funcall(env, Fvterm_set_title, 1, (emacs_value[]){string}); } +void set_directory(emacs_env *env, emacs_value string) { + env->funcall(env, Fvterm_set_directory, 1, (emacs_value[]){string}); +} + void vterm_invalidate(emacs_env *env) { env->funcall(env, Fvterm_invalidate, 0, NULL); } diff --git a/elisp.h b/elisp.h index 6bb149c..5420728 100644 --- a/elisp.h +++ b/elisp.h @@ -45,6 +45,7 @@ emacs_value Fvterm_flush_output; emacs_value Fget_buffer_window; emacs_value Fselected_window; emacs_value Fvterm_set_title; +emacs_value Fvterm_set_directory; emacs_value Fvterm_invalidate; emacs_value Feq; emacs_value Fvterm_get_color; @@ -74,6 +75,7 @@ void forward_char(emacs_env *env, emacs_value n); emacs_value get_buffer_window(emacs_env *env); emacs_value selected_window(emacs_env *env); void set_title(emacs_env *env, emacs_value string); +void set_directory(emacs_env *env, emacs_value string); void vterm_invalidate(emacs_env *env); emacs_value vterm_get_color(emacs_env *env, int index); diff --git a/vterm-module.c b/vterm-module.c index 4ec78dc..f3c6131 100644 --- a/vterm-module.c +++ b/vterm-module.c @@ -376,6 +376,7 @@ static void term_redraw_cursor(Term *term, emacs_env *env) { static void term_redraw(Term *term, emacs_env *env) { term_redraw_cursor(term, env); + if (term->is_invalidated) { long bufline_before = env->extract_integer(env, buffer_line_number(env)); refresh_scrollback(term, env); @@ -384,10 +385,17 @@ static void term_redraw(Term *term, emacs_env *env) { env->extract_integer(env, buffer_line_number(env)) - bufline_before; adjust_topline(term, env, line_added); } - if (term->is_title_changed) { + + if (term->title_changed) { set_title(env, env->make_string(env, term->title, strlen(term->title))); - term->is_title_changed = false; + term->title_changed = false; + } + + if (term->directory_changed) { + set_directory(env, env->make_string(env, term->directory, strlen(term->directory))); + term->directory_changed = false; } + term->is_invalidated = false; } @@ -417,6 +425,7 @@ static bool is_key(unsigned char *key, size_t len, char *key_description) { return (len == strlen(key_description) && memcmp(key, key_description, len) == 0); } + static void term_set_title(Term *term, char *title) { size_t len = strlen(title); if (term->title) { @@ -425,7 +434,7 @@ static void term_set_title(Term *term, char *title) { term->title = malloc(sizeof(char) * (len + 1)); strncpy(term->title, title, len); term->title[len] = 0; - term->is_title_changed = true; + term->title_changed = true; return; } @@ -621,6 +630,11 @@ void term_finalize(void *object) { term->title = NULL; } + if (term->directory) { + free(term->directory); + term->directory = NULL; + } + if (term->pty_fd > 0) { close(term->pty_fd); } @@ -630,6 +644,36 @@ void term_finalize(void *object) { free(term); } +static int osc_callback(const char *command, size_t cmdlen, void *user) +{ + Term *term = (Term *) user; + char buffer[cmdlen + 1]; + + buffer[cmdlen] = '\0'; + memcpy(buffer, command, cmdlen); + + if (term->directory != NULL) { + free(term->directory); + } + + if (cmdlen > 3 && buffer[0] == '5' && buffer[1] == '1' && buffer[2] == ';') { + term->directory = malloc(cmdlen - 3 + 1); + strcpy(term->directory, &buffer[3]); + term->directory_changed = true; + return 1; + } + return 0; +} + +static VTermParserCallbacks parser_callbacks = { + .text = NULL, + .control = NULL, + .escape = NULL, + .csi = NULL, + .osc = &osc_callback, + .dcs = NULL, +}; + emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs, emacs_value args[], void *data) { Term *term = malloc(sizeof(Term)); @@ -642,6 +686,10 @@ emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs, emacs_value args[], vterm_set_utf8(term->vt, 1); term->vts = vterm_obtain_screen(term->vt); + + VTermState *state = vterm_obtain_state(term->vt); + vterm_state_set_unrecognised_fallbacks(state, &parser_callbacks, term); + 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); @@ -657,7 +705,10 @@ emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs, emacs_value args[], term->pty_fd = -1; term->title = NULL; - term->is_title_changed = false; + term->title_changed = false; + + term->directory = NULL; + term->directory_changed = false; return env->make_user_ptr(env, term_finalize, term); } @@ -796,6 +847,8 @@ int emacs_module_init(struct emacs_runtime *ert) { Fvterm_set_title = env->make_global_ref(env, env->intern(env, "vterm--set-title")); + Fvterm_set_directory = + env->make_global_ref(env, env->intern(env, "vterm--set-directory")); Fvterm_invalidate = env->make_global_ref(env, env->intern(env, "vterm--invalidate")); Feq = env->make_global_ref(env, env->intern(env, "eq")); diff --git a/vterm-module.h b/vterm-module.h index ca0bcb5..6a6e792 100644 --- a/vterm-module.h +++ b/vterm-module.h @@ -56,7 +56,10 @@ typedef struct Term { Cursor cursor; char *title; - bool is_title_changed; + bool title_changed; + + char *directory; + bool directory_changed; int width, height; diff --git a/vterm.el b/vterm.el index 6160a88..b09abcc 100644 --- a/vterm.el +++ b/vterm.el @@ -529,20 +529,25 @@ Feeds the size change to the virtual terminal." "Run the `vterm--set-title-hook' with TITLE as argument." (run-hook-with-args 'vterm-set-title-functions title)) +(defun vterm--set-directory (path) + "Set `default-directory' to PATH." + (when (file-directory-p path) + (setq default-directory path))) + (defun vterm--get-color(index) "Get color by index from `vterm-color-palette'. Argument INDEX index of color." (cond - ((and (>= index 0)(< index 8 )) + ((and (>= index 0)(< index 8)) (face-foreground (elt vterm-color-palette index) nil 'default)) - ((and (>= index 8 )(< index 16 )) + ((and (>= index 8 )(< index 16)) (face-background (elt vterm-color-palette (% index 8)) nil 'default)) - ( (= index -1) ;-1 foreground - (face-foreground 'vterm-color-default nil 'default)) + ((= index -1) ;-1 foreground + (face-foreground 'vterm-color-default nil 'default)) (t ;-2 background (face-background 'vterm-color-default nil 'default)))) -- cgit v1.0 From dd012fa9986171221c0bce9d9fdb64332e1044a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20F=C3=BCrmetz?= Date: Sat, 3 Aug 2019 13:59:01 +0200 Subject: Avoid freeing an unallocated buffer --- vterm-module.c | 1 + 1 file changed, 1 insertion(+) diff --git a/vterm-module.c b/vterm-module.c index f3c6131..21ace5f 100644 --- a/vterm-module.c +++ b/vterm-module.c @@ -654,6 +654,7 @@ static int osc_callback(const char *command, size_t cmdlen, void *user) if (term->directory != NULL) { free(term->directory); + term->directory = NULL; } if (cmdlen > 3 && buffer[0] == '5' && buffer[1] == '1' && buffer[2] == ';') { -- cgit v1.0