diff options
| author | jixiuf <jixiuf@qq.com> | 2022-08-27 21:56:02 +0800 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-08-27 21:56:02 +0800 |
| commit | 30dda383f802f5c5a7363adcf31beb002b4e07b5 (patch) | |
| tree | b2278032f43855c85f29090c484987159fcc777f | |
| parent | 0091bb026637cd6fa6035052d7449df204e53044 (diff) | |
| parent | 7feb9c3351436fe3c64d59c4b730780c9cca02d5 (diff) | |
Merge pull request #624 from jixiuf/osc52
reimplement OSC 52 with VTermSelectionCallbacks from libvterm v0.2
| -rw-r--r-- | CMakeLists.txt | 4 | ||||
| -rw-r--r-- | elisp.c | 8 | ||||
| -rw-r--r-- | elisp.h | 6 | ||||
| -rw-r--r-- | vterm-module.c | 91 | ||||
| -rw-r--r-- | vterm-module.h | 25 | ||||
| -rw-r--r-- | vterm.el | 36 |
6 files changed, 79 insertions, 91 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index e766884..e0c0851 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,8 +63,8 @@ else() endif() ExternalProject_add(libvterm - GIT_REPOSITORY https://github.com/neovim/libvterm.git - GIT_TAG 54c03b21f763fa775a4c0643a9d8326342873179 + GIT_REPOSITORY https://github.com/Sbozzolo/libvterm-mirror.git + GIT_TAG 15133bba2c0bce32baabbf91610a2450495fea02 CONFIGURE_COMMAND "" BUILD_COMMAND ${LIBVTERM_BUILD_COMMAND} "CFLAGS='-fPIC'" BUILD_IN_SOURCE ON @@ -55,7 +55,7 @@ emacs_value Fvterm_invalidate; emacs_value Feq; emacs_value Fvterm_get_color; emacs_value Fvterm_eval; -emacs_value Fvterm_selection; +emacs_value Fvterm_set_selection; /* Set the function cell of the symbol named NAME to SFUN using the 'fset' function. */ @@ -202,8 +202,8 @@ emacs_value vterm_eval(emacs_env *env, emacs_value string) { return env->funcall(env, Fvterm_eval, 1, (emacs_value[]){string}); } -emacs_value vterm_selection(emacs_env *env, emacs_value selection_target, - emacs_value selection_data) { - return env->funcall(env, Fvterm_selection, 2, +emacs_value vterm_set_selection(emacs_env *env, emacs_value selection_target, + emacs_value selection_data) { + return env->funcall(env, Fvterm_set_selection, 2, (emacs_value[]){selection_target, selection_data}); } @@ -58,7 +58,7 @@ extern emacs_value Fvterm_invalidate; extern emacs_value Feq; extern emacs_value Fvterm_get_color; extern emacs_value Fvterm_eval; -extern emacs_value Fvterm_selection; +extern emacs_value Fvterm_set_selection; // Utils void bind_function(emacs_env *env, const char *name, emacs_value Sfun); @@ -93,7 +93,7 @@ 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); emacs_value vterm_eval(emacs_env *env, emacs_value string); -emacs_value vterm_selection(emacs_env *env, emacs_value selection_target, - emacs_value selection_data); +emacs_value vterm_set_selection(emacs_env *env, emacs_value selection_target, + emacs_value selection_data); #endif /* ELISP_H */ diff --git a/vterm-module.c b/vterm-module.c index 72a1e21..8fcf8ed 100644 --- a/vterm-module.c +++ b/vterm-module.c @@ -608,13 +608,13 @@ static void term_redraw(Term *term, emacs_env *env) { term->elisp_code_p_insert = &term->elisp_code_first; if (term->selection_data) { - emacs_value selection_target = env->make_string( - env, &term->selection_target[0], strlen(&term->selection_target[0])); + emacs_value selection_mask = env->make_integer(env, term->selection_mask); emacs_value selection_data = env->make_string(env, term->selection_data, strlen(term->selection_data)); - vterm_selection(env, selection_target, selection_data); + vterm_set_selection(env, selection_mask, selection_data); free(term->selection_data); term->selection_data = NULL; + term->selection_mask = 0; } term->is_invalidated = false; @@ -1076,37 +1076,7 @@ static int handle_osc_cmd_51(Term *term, char subCmd, char *buffer) { } return 0; } -static int handle_osc_cmd_52(Term *term, char *buffer) { - /* OSC 52 ; Pc ; Pd BEL */ - /* Manipulate Selection Data */ - /* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html */ - /* test by printf "\033]52;c;$(printf "%s" "blabla" | base64)\a" */ - - for (int i = 0; i < SELECTION_TARGET_MAX; i++) { /* reset Pc */ - term->selection_target[i] = 0; - } - int selection_target_idx = 0; - size_t cmdlen = strlen(buffer); - - for (int i = 0; i < cmdlen; i++) { - /* OSC 52 ; Pc ; Pd BEL */ - if (buffer[i] == ';') { /* find the second ";" */ - term->selection_data = malloc(cmdlen - i); - strcpy(term->selection_data, &buffer[i + 1]); - break; - } - if (selection_target_idx < SELECTION_TARGET_MAX) { - /* c , p , q , s , 0 , 1 , 2 , 3 , 4 , 5 , 6 , and 7 */ - /* for clipboard, primary, secondary, select, or cut buffers 0 through 7 - * respectively */ - term->selection_target[selection_target_idx] = buffer[i]; - selection_target_idx++; - } else { /* len of Pc should not >12 just ignore this cmd,am I wrong? */ - return 0; - } - } - return 1; -} + static int handle_osc_cmd(Term *term, int cmd, char *buffer) { if (cmd == 51) { char subCmd = '0'; @@ -1116,11 +1086,11 @@ static int handle_osc_cmd(Term *term, int cmd, char *buffer) { subCmd = buffer[0]; /* ++ skip the subcmd char */ return handle_osc_cmd_51(term, subCmd, ++buffer); - } else if (cmd == 52) { - return handle_osc_cmd_52(term, buffer); } return 0; } +/* maybe we should drop support of libvterm < v0.2 */ +/* VTermStringFragmentNotExists was introduced when libvterm is not released */ #ifdef VTermStringFragmentNotExists static int osc_callback(const char *command, size_t cmdlen, void *user) { Term *term = (Term *)user; @@ -1134,10 +1104,6 @@ static int osc_callback(const char *command, size_t cmdlen, void *user) { } else if (cmdlen > 4 && buffer[0] == '5' && buffer[1] == '1' && buffer[2] == ';' && buffer[3] == 'E') { return handle_osc_cmd_51(term, 'E', &buffer[4]); - } else if (cmdlen > 4 && buffer[0] == '5' && buffer[1] == '2' && - buffer[2] == ';') { - /* OSC 52 ; Pc ; Pd BEL */ - return handle_osc_cmd_52(term, &buffer[3]); } return 0; } @@ -1159,13 +1125,6 @@ static int osc_callback(int cmd, VTermStringFragment frag, void *user) { /* "51;A" has also the role of identifying the end of the prompt */ /* "51;E" executes elisp code */ /* The elisp code is executed in term_redraw */ - - /* "52;[cpqs01234567];data" Manipulate Selection Data */ - /* I think libvterm has bug ,sometimes when the data is long enough ,the final - * fragment is missed */ - /* printf "\033]52;c;$(printf "%s" $(ruby -e 'print "x"*999999')|base64)\a" - */ - Term *term = (Term *)user; if (frag.initial) { @@ -1195,6 +1154,36 @@ static VTermStateFallbacks parser_callbacks = { .dcs = NULL, }; +static int set_selection(VTermSelectionMask mask, VTermStringFragment frag, + void *user) { + Term *term = (Term *)user; + + if (frag.initial) { + term->selection_mask = mask; + if (term->selection_data) { + free(term->selection_data); + } + term->selection_data = NULL; + } + + if (frag.len) { + term->selection_data = + concat(term->selection_data, frag.str, frag.len, true); + } + return 1; +} +/* OSC 52 ; Pc ; Pd BEL */ +/* Manipulate Selection Data */ +/* https://invisible-island.net/xterm/ctlseqs/ctlseqs.html */ +/* test by printf "\033]52;c;$(printf "%s" "blabla" | base64)\a" */ +/* c , p , q , s , 0 , 1 , 2 , 3 , 4 , 5 , 6 , and 7 */ +/* for clipboard, primary, secondary, select, or cut buffers 0 through 7 */ +/* respectively */ +static VTermSelectionCallbacks selection_callbacks = { + .set = &set_selection, + .query = NULL, +}; + #endif emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs, emacs_value args[], @@ -1217,6 +1206,9 @@ emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs, emacs_value args[], VTermState *state = vterm_obtain_state(term->vt); vterm_state_set_unrecognised_fallbacks(state, &parser_callbacks, term); + vterm_state_set_selection_callbacks(state, &selection_callbacks, term, + term->selection_buf, SELECTION_BUF_LEN); + vterm_state_set_bold_highbright(state, set_bold_hightbright); vterm_screen_reset(term->vts, 1); @@ -1262,6 +1254,7 @@ emacs_value Fvterm_new(emacs_env *env, ptrdiff_t nargs, emacs_value args[], term->elisp_code_first = NULL; term->elisp_code_p_insert = &term->elisp_code_first; term->selection_data = NULL; + term->selection_mask = 0; term->cmd_buffer = NULL; @@ -1472,8 +1465,8 @@ int emacs_module_init(struct emacs_runtime *ert) { Fvterm_get_color = env->make_global_ref(env, env->intern(env, "vterm--get-color")); Fvterm_eval = env->make_global_ref(env, env->intern(env, "vterm--eval")); - Fvterm_selection = - env->make_global_ref(env, env->intern(env, "vterm--selection")); + Fvterm_set_selection = + env->make_global_ref(env, env->intern(env, "vterm--set-selection")); // Exported functions emacs_value fun; diff --git a/vterm-module.h b/vterm-module.h index 96f538f..dca092b 100644 --- a/vterm-module.h +++ b/vterm-module.h @@ -8,17 +8,17 @@ // https://gcc.gnu.org/wiki/Visibility #if defined _WIN32 || defined __CYGWIN__ - #ifdef __GNUC__ - #define VTERM_EXPORT __attribute__ ((dllexport)) - #else - #define VTERM_EXPORT __declspec(dllexport) - #endif +#ifdef __GNUC__ +#define VTERM_EXPORT __attribute__((dllexport)) #else - #if __GNUC__ >= 4 - #define VTERM_EXPORT __attribute__ ((visibility ("default"))) - #else - #define VTERM_EXPORT - #endif +#define VTERM_EXPORT __declspec(dllexport) +#endif +#else +#if __GNUC__ >= 4 +#define VTERM_EXPORT __attribute__((visibility("default"))) +#else +#define VTERM_EXPORT +#endif #endif VTERM_EXPORT int plugin_is_GPL_compatible; @@ -53,7 +53,7 @@ typedef struct ElispCodeListNode { /* c , p , q , s , 0 , 1 , 2 , 3 , 4 , 5 , 6 , and 7 */ /* clipboard, primary, secondary, select, or cut buffers 0 through 7 */ -#define SELECTION_TARGET_MAX 12 +#define SELECTION_BUF_LEN 4096 typedef struct Cursor { int row, col; @@ -100,8 +100,9 @@ typedef struct Term { /* c , p , q , s , 0 , 1 , 2 , 3 , 4 , 5 , 6 , and 7 */ /* clipboard, primary, secondary, select, or cut buffers 0 through 7 */ - char selection_target[SELECTION_TARGET_MAX]; + VTermSelectionMask selection_mask; char *selection_data; + char selection_buf[SELECTION_BUF_LEN]; /* buf for */ /* the size of dirs almost = window height, value = directory of that line */ LineInfo **lines; @@ -1245,31 +1245,25 @@ Argument BUFFER the terminal buffer." (when (cl-member (selected-window) windows :test #'eq) (set-window-hscroll (selected-window) 0)))))))) -(defun vterm--selection (targets data) +;; see VTermSelectionMask in vterm.el +;; VTERM_SELECTION_CLIPBOARD = (1<<0), +;; VTERM_SELECTION_PRIMARY = (1<<1), +(defconst vterm--selection-clipboard 1) ;(1<<0) +(defconst vterm--selection-primary 2) ;(1<<1) +(defun vterm--set-selection (mask data) "OSC 52 Manipulate Selection Data. Search Manipulate Selection Data in https://invisible-island.net/xterm/ctlseqs/ctlseqs.html ." (when vterm-enable-manipulate-selection-data-by-osc52 - (unless (or (string-equal data "?") - (string-empty-p data)) - (let* ((inhibit-eol-conversion t) - (decoded-data (decode-coding-string - (base64-decode-string data) locale-coding-system)) - (select-enable-clipboard select-enable-clipboard) - (select-enable-primary select-enable-primary)) - ;; https://invisible-island.net/xterm/ctlseqs/ctlseqs.html - ;; c , p , q , s , 0 , 1 , 2 , 3 , 4 , 5 , 6 , and 7 - ;; clipboard, primary, secondary, select, or cut buffers 0 through 7 - (unless (string-empty-p targets) - (setq select-enable-clipboard nil) - (setq select-enable-primary nil)) - (when (cl-find ?c targets) - (setq select-enable-clipboard t)) - (when (cl-find ?p targets) - (setq select-enable-primary t)) - - (kill-new decoded-data) - (message "kill-ring is updated by vterm OSC 52(Manipulate Selection Data)"))))) + (let ((select-enable-clipboard select-enable-clipboard) + (select-enable-primary select-enable-primary)) + (setq select-enable-clipboard + (logand mask vterm--selection-clipboard)) + (setq select-enable-primary + (logand mask vterm--selection-primary)) + (kill-new data) + (message "kill-ring is updated by vterm OSC 52(Manipulate Selection Data)")) + )) ;;; Entry Points |
