From c9662de55d78baa82dfcac1afab170a0d8e4f163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Sat, 30 Jan 2016 20:15:30 +0100 Subject: Implement system clipboard registers "* and "+ Both registers are currently treated identically. The actual system integration is performed by two shell scripts vis-copy and vis-paste. --- Makefile | 6 ++++++ buffer.c | 4 ++++ buffer.h | 2 ++ main.c | 2 ++ register.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- register.h | 9 +++++++-- ui.h | 2 +- vis-copy | 10 ++++++++++ vis-operators.c | 6 +++--- vis-paste | 10 ++++++++++ vis.c | 3 ++- vis.h | 1 + 12 files changed, 104 insertions(+), 11 deletions(-) create mode 100755 vis-copy create mode 100755 vis-paste diff --git a/Makefile b/Makefile index 486aa3b..b04d860 100644 --- a/Makefile +++ b/Makefile @@ -80,6 +80,10 @@ install: vis @chmod 755 ${DESTDIR}${PREFIX}/bin/vis @cp -f vis-open ${DESTDIR}${PREFIX}/bin @chmod 755 ${DESTDIR}${PREFIX}/bin/vis-open + @cp -f vis-copy ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/vis-copy + @cp -f vis-paste ${DESTDIR}${PREFIX}/bin + @chmod 755 ${DESTDIR}${PREFIX}/bin/vis-paste @echo installing support files to ${DESTDIR}${SHAREPREFIX} @mkdir -p ${DESTDIR}${SHAREPREFIX} @cp -r visrc.lua lexers ${DESTDIR}${SHAREPREFIX} @@ -92,6 +96,8 @@ uninstall: @echo removing executable file from ${DESTDIR}${PREFIX}/bin @rm -f ${DESTDIR}${PREFIX}/bin/vis @rm -f ${DESTDIR}${PREFIX}/bin/vis-open + @rm -f ${DESTDIR}${PREFIX}/bin/vis-copy + @rm -f ${DESTDIR}${PREFIX}/bin/vis-paste @echo removing manual page from ${DESTDIR}${MANPREFIX}/man1 @rm -f ${DESTDIR}${MANPREFIX}/man1/vis.1 @echo removing support files from ${DESTDIR}${SHAREPREFIX} diff --git a/buffer.c b/buffer.c index a0b60e2..b9bc28c 100644 --- a/buffer.c +++ b/buffer.c @@ -36,6 +36,10 @@ void buffer_release(Buffer *buf) { buffer_init(buf); } +void buffer_clear(Buffer *buf) { + buf->len = 0; +} + bool buffer_put(Buffer *buf, const void *data, size_t len) { if (!buffer_grow(buf, len)) return false; diff --git a/buffer.h b/buffer.h index 0dc2dc6..037055b 100644 --- a/buffer.h +++ b/buffer.h @@ -16,6 +16,8 @@ typedef struct { void buffer_init(Buffer*); /* release/free all data stored in this buffer, reset size to zero */ void buffer_release(Buffer*); +/* set buffer size to zero, keep allocated memory */ +void buffer_clear(Buffer*); /* reserve space to store at least size bytes in this buffer.*/ bool buffer_grow(Buffer*, size_t size); /* truncate buffer, but keep associated memory region for further data */ diff --git a/main.c b/main.c index 487ce3c..077ed77 100644 --- a/main.c +++ b/main.c @@ -1306,6 +1306,8 @@ static const char *key2register(Vis *vis, const char *keys, enum VisRegister *re return NULL; if (keys[0] >= 'a' && keys[0] <= 'z') *reg = keys[0] - 'a'; + else if (keys[0] == '*' || keys[0] == '+') + *reg = VIS_REG_CLIPBOARD; else if (keys[0] == '_') *reg = VIS_REG_BLACKHOLE; return keys+1; diff --git a/register.c b/register.c index 30e4c58..a15e8b3 100644 --- a/register.c +++ b/register.c @@ -1,20 +1,56 @@ #include #include -#include "register.h" -#include "buffer.h" +#include "vis.h" #include "text.h" #include "util.h" +#include "register.h" + +typedef struct { + Buffer *stdout; + Buffer *stderr; +} Clipboard; + +static ssize_t read_stdout(void *context, char *data, size_t len) { + Buffer *buf = ((Clipboard*)context)->stdout; + buffer_append(buf, data, len); + return len; +} + +static ssize_t read_stderr(void *context, char *data, size_t len) { + Buffer *buf = ((Clipboard*)context)->stderr; + buffer_append(buf, data, len); + return len; +} void register_release(Register *reg) { buffer_release(®->buf); } -const char *register_get(Register *reg, size_t *len) { +const char *register_get(Vis *vis, Register *reg, size_t *len) { switch (reg->type) { case REGISTER_NORMAL: *len = reg->buf.len; return reg->buf.data; + case REGISTER_CLIPBOARD: + { + Buffer stderr; + buffer_init(&stderr); + buffer_clear(®->buf); + Clipboard clipboard = { + .stdout = ®->buf, + .stderr = &stderr, + }; + + int status = vis_pipe(vis, &clipboard, + &(Filerange){ .start = 0, .end = 0 }, + (const char*[]){ "vis-paste", "vis-paste", NULL }, + read_stdout, read_stderr); + if (status != 0) + vis_info_show(vis, "Command failed %s", stderr.len > 0 ? stderr.data : ""); + *len = reg->buf.len; + return reg->buf.data; + } case REGISTER_BLACKHOLE: default: *len = 0; @@ -22,7 +58,7 @@ const char *register_get(Register *reg, size_t *len) { } } -bool register_put(Register *reg, Text *txt, Filerange *range) { +bool register_put(Vis *vis, Register *reg, Text *txt, Filerange *range) { switch (reg->type) { case REGISTER_NORMAL: { @@ -32,6 +68,22 @@ bool register_put(Register *reg, Text *txt, Filerange *range) { reg->buf.len = text_bytes_get(txt, range->start, len, reg->buf.data); return true; } + case REGISTER_CLIPBOARD: + { + Buffer stderr; + buffer_init(&stderr); + Clipboard clipboard = { + .stderr = &stderr, + }; + + int status = vis_pipe(vis, &clipboard, range, + (const char*[]){ "vis-copy", "vis-copy", NULL }, + NULL, read_stderr); + + if (status != 0) + vis_info_show(vis, "Command failed %s", stderr.len > 0 ? stderr.data : ""); + return status == 0; + } case REGISTER_BLACKHOLE: return true; default: diff --git a/register.h b/register.h index 1b14688..d3f7b7f 100644 --- a/register.h +++ b/register.h @@ -6,18 +6,23 @@ #include "buffer.h" #include "text-util.h" +#ifndef VIS_H +typedef struct Vis Vis; +#endif + typedef struct { Buffer buf; bool linewise; /* place register content on a new line when inserting? */ enum { REGISTER_NORMAL, REGISTER_BLACKHOLE, + REGISTER_CLIPBOARD, } type; } Register; void register_release(Register *reg); -const char *register_get(Register *reg, size_t *len); -bool register_put(Register *reg, Text *txt, Filerange *range); +const char *register_get(Vis*, Register*reg, size_t *len); +bool register_put(Vis*, Register *reg, Text *txt, Filerange *range); bool register_append(Register *reg, Text *txt, Filerange *range); #endif diff --git a/ui.h b/ui.h index 61fa4df..314bc9d 100644 --- a/ui.h +++ b/ui.h @@ -38,9 +38,9 @@ enum UiStyles { UI_STYLE_MAX, }; +#include "vis.h" #include "text.h" #include "view.h" -#include "vis.h" struct Ui { bool (*init)(Ui*, Vis*); diff --git a/vis-copy b/vis-copy new file mode 100755 index 0000000..80d1a07 --- /dev/null +++ b/vis-copy @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ ! -z "$DISPLAY" ]; then + exec xsel -i +elif type pbcopy >/dev/null 2>&1; then + exec pbcopy +else + echo "System clipboard not supported" 1>&2 + exit 1 +fi diff --git a/vis-operators.c b/vis-operators.c index fe410dc..7901851 100644 --- a/vis-operators.c +++ b/vis-operators.c @@ -8,7 +8,7 @@ static size_t op_delete(Vis *vis, Text *txt, OperatorContext *c) { c->reg->linewise = c->linewise; - register_put(c->reg, txt, &c->range); + register_put(vis, c->reg, txt, &c->range); text_delete_range(txt, &c->range); size_t pos = c->range.start; if (c->linewise && pos == text_size(txt)) @@ -24,7 +24,7 @@ static size_t op_change(Vis *vis, Text *txt, OperatorContext *c) { static size_t op_yank(Vis *vis, Text *txt, OperatorContext *c) { c->reg->linewise = c->linewise; - register_put(c->reg, txt, &c->range); + register_put(vis, c->reg, txt, &c->range); return c->pos; } @@ -52,7 +52,7 @@ static size_t op_put(Vis *vis, Text *txt, OperatorContext *c) { } size_t len; - const char *data = register_get(c->reg, &len); + const char *data = register_get(vis, c->reg, &len); for (int i = 0; i < c->count; i++) { text_insert(txt, pos, data, len); diff --git a/vis-paste b/vis-paste new file mode 100755 index 0000000..232da2e --- /dev/null +++ b/vis-paste @@ -0,0 +1,10 @@ +#!/bin/sh + +if [ ! -z "$DISPLAY" ]; then + exec xsel -o +elif type pbpaste >/dev/null 2>&1; then + exec pbpaste +else + echo "System clipboard not supported" 1>&2 + exit 1 +fi diff --git a/vis.c b/vis.c index 3edc766..b6d6b49 100644 --- a/vis.c +++ b/vis.c @@ -316,6 +316,7 @@ Vis *vis_new(Ui *ui, VisEvent *event) { vis->tabwidth = 8; vis->expandtab = false; vis->registers[VIS_REG_BLACKHOLE].type = REGISTER_BLACKHOLE; + vis->registers[VIS_REG_CLIPBOARD].type = REGISTER_CLIPBOARD; action_reset(&vis->action); if (!(vis->search_pattern = text_regex_new())) goto err; @@ -1005,7 +1006,7 @@ void vis_register_set(Vis *vis, enum VisRegister reg) { const char *vis_register_get(Vis *vis, enum VisRegister reg, size_t *len) { if (reg < LENGTH(vis->registers)) - return register_get(&vis->registers[reg], len); + return register_get(vis, &vis->registers[reg], len); *len = 0; return NULL; } diff --git a/vis.h b/vis.h index 8de1f51..00d95a6 100644 --- a/vis.h +++ b/vis.h @@ -349,6 +349,7 @@ enum VisRegister { VIS_REG_z, VIS_REG_DEFAULT, /* used when no other register is specified */ VIS_REG_BLACKHOLE, /* /dev/null register */ + VIS_REG_CLIPBOARD, /* system clipboard register */ VIS_REG_PROMPT, /* internal register which shadows DEFAULT in PROMPT mode */ VIS_REG_INVALID, /* has to be the last enum member */ }; -- cgit v1.2.3