aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjixiuf <jixiuf@qq.com>2022-08-27 21:56:02 +0800
committerGitHub <noreply@github.com>2022-08-27 21:56:02 +0800
commit30dda383f802f5c5a7363adcf31beb002b4e07b5 (patch)
treeb2278032f43855c85f29090c484987159fcc777f
parent0091bb026637cd6fa6035052d7449df204e53044 (diff)
parent7feb9c3351436fe3c64d59c4b730780c9cca02d5 (diff)
Merge pull request #624 from jixiuf/osc52
reimplement OSC 52 with VTermSelectionCallbacks from libvterm v0.2
-rw-r--r--CMakeLists.txt4
-rw-r--r--elisp.c8
-rw-r--r--elisp.h6
-rw-r--r--vterm-module.c91
-rw-r--r--vterm-module.h25
-rw-r--r--vterm.el36
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
diff --git a/elisp.c b/elisp.c
index 24c7601..12d48d0 100644
--- a/elisp.c
+++ b/elisp.c
@@ -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});
}
diff --git a/elisp.h b/elisp.h
index 39be710..22d7e60 100644
--- a/elisp.h
+++ b/elisp.h
@@ -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;
diff --git a/vterm.el b/vterm.el
index 42d7b9c..c1635b5 100644
--- a/vterm.el
+++ b/vterm.el
@@ -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