From 2c8fcaa8fbb17b99aa5b0f8bfbbe0451dfa509f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc=20Andr=C3=A9=20Tanner?= Date: Wed, 19 Apr 2017 13:11:52 +0200 Subject: vis: restructure register handling Decouple register content from cursors. Previously each cursor had exactly one corresponding register. Now each register can save a list of values whose lifetime is not tied to the cursor. If multiple cursors exist and a put with a register holding only a single value is performed, then this value is inserted at every cursor location. If there are fewer values available than cursors, then only the matching ones will be used. If a register holding multiple values is inserted in a single cursor context, only the first value will be used. Another option would be to join all existing values. The details of this behavior might be changed in the future. in insert mode has not yet been adapted and register handling in general needs to be cleaned up further. Fix #527 --- register.c | 138 +++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 106 insertions(+), 32 deletions(-) (limited to 'register.c') diff --git a/register.c b/register.c index 69409c1..b55a059 100644 --- a/register.c +++ b/register.c @@ -5,66 +5,143 @@ #include "text.h" #include "util.h" #include "register.h" +#include "buffer.h" + +static Buffer *register_buffer(Register *reg, size_t slot) { + Buffer *buf = array_get(®->values, slot); + if (buf) + return buf; + if (array_resize(®->values, slot) && (buf = array_get(®->values, slot))) + return buf; + Buffer new; + buffer_init(&new); + if (!array_add(®->values, &new)) + return NULL; + size_t capacity = array_capacity(®->values); + for (size_t i = array_length(®->values); i < capacity; i++) { + if (!array_add(®->values, &new)) + return NULL; + } + return array_get(®->values, slot); +} static ssize_t read_buffer(void *context, char *data, size_t len) { buffer_append(context, data, len); return len; } +bool register_init(Register *reg) { + Buffer buf; + buffer_init(&buf); + array_init_sized(®->values, sizeof(Buffer)); + return array_add(®->values, &buf); +} + void register_release(Register *reg) { - buffer_release(®->buf); + if (!reg) + return; + size_t n = array_capacity(®->values); + for (size_t i = 0; i < n; i++) + buffer_release(array_get(®->values, i)); + array_release(®->values); } -const char *register_get(Vis *vis, Register *reg, size_t *len) { +const char *register_slot_get(Vis *vis, Register *reg, size_t slot, size_t *len) { + if (len) + *len = 0; switch (reg->type) { case REGISTER_NORMAL: - if (reg->buf.len > 0 && reg->buf.data[reg->buf.len-1] != '\0') - buffer_append(®->buf, "\0", 1); + { + Buffer *buf = array_get(®->values, slot); + if (!buf) + return NULL; + buffer_terminate(buf); if (len) - *len = reg->buf.len > 0 ? reg->buf.len - 1 : 0; - return reg->buf.data; + *len = buffer_length0(buf); + return buffer_content0(buf); + } case REGISTER_CLIPBOARD: { Buffer buferr; buffer_init(&buferr); - buffer_clear(®->buf); + Buffer *buf = array_get(®->values, slot); + if (!buf) + return NULL; + buffer_clear(buf); int status = vis_pipe(vis, vis->win->file, &(Filerange){ .start = 0, .end = 0 }, (const char*[]){ VIS_CLIPBOARD, "--paste", NULL }, - ®->buf, read_buffer, &buferr, read_buffer); + buf, read_buffer, &buferr, read_buffer); if (status != 0) vis_info_show(vis, "Command failed %s", buffer_content0(&buferr)); - *len = reg->buf.len; - return reg->buf.data; + buffer_release(&buferr); + if (len) + *len = buffer_length0(buf); + return buffer_content0(buf); } case REGISTER_BLACKHOLE: default: - *len = 0; return NULL; } } +const char *register_get(Vis *vis, Register *reg, size_t *len) { + return register_slot_get(vis, reg, 0, len); +} + +bool register_slot_put(Vis *vis, Register *reg, size_t slot, const char *data, size_t len) { + if (reg->type != REGISTER_NORMAL) + return false; + Buffer *buf = register_buffer(reg, slot); + return buf && buffer_put(buf, data, len); +} + bool register_put(Vis *vis, Register *reg, const char *data, size_t len) { - return reg->type == REGISTER_NORMAL && buffer_put(®->buf, data, len); + return register_slot_put(vis, reg, 0, data, len) && + register_resize(reg, 1); } bool register_put0(Vis *vis, Register *reg, const char *data) { return register_put(vis, reg, data, strlen(data)+1); } -bool register_put_range(Vis *vis, Register *reg, Text *txt, Filerange *range) { +static bool register_slot_append_range(Register *reg, size_t slot, Text *txt, Filerange *range) { + switch (reg->type) { + case REGISTER_NORMAL: + { + Buffer *buf = register_buffer(reg, slot); + if (!buf) + return false; + size_t len = text_range_size(range); + if (len == SIZE_MAX || !buffer_grow(buf, len+1)) + return false; + if (buf->len > 0 && buf->data[buf->len-1] == '\0') + buf->len--; + buf->len += text_bytes_get(txt, range->start, len, buf->data + buf->len); + return buffer_append(buf, "\0", 1); + } + default: + return false; + } +} + +bool register_slot_put_range(Vis *vis, Register *reg, size_t slot, Text *txt, Filerange *range) { if (reg->append) - return register_append_range(reg, txt, range); + return register_slot_append_range(reg, slot, txt, range); + switch (reg->type) { case REGISTER_NORMAL: { + Buffer *buf = register_buffer(reg, slot); + if (!buf) + return false; size_t len = text_range_size(range); - if (len == SIZE_MAX || !buffer_reserve(®->buf, len+1)) + if (len == SIZE_MAX || !buffer_reserve(buf, len+1)) return false; - reg->buf.len = text_bytes_get(txt, range->start, len, reg->buf.data); - return buffer_append(®->buf, "\0", 1); + buf->len = text_bytes_get(txt, range->start, len, buf->data); + return buffer_append(buf, "\0", 1); } case REGISTER_CLIPBOARD: { @@ -77,6 +154,7 @@ bool register_put_range(Vis *vis, Register *reg, Text *txt, Filerange *range) { if (status != 0) vis_info_show(vis, "Command failed %s", buffer_content0(&buferr)); + buffer_release(&buferr); return status == 0; } case REGISTER_BLACKHOLE: @@ -86,19 +164,15 @@ bool register_put_range(Vis *vis, Register *reg, Text *txt, Filerange *range) { } } -bool register_append_range(Register *reg, Text *txt, Filerange *range) { - switch (reg->type) { - case REGISTER_NORMAL: - { - size_t len = text_range_size(range); - if (!buffer_grow(®->buf, len+1)) - return false; - if (reg->buf.len > 0 && reg->buf.data[reg->buf.len-1] == '\0') - reg->buf.len--; - reg->buf.len += text_bytes_get(txt, range->start, len, reg->buf.data + reg->buf.len); - return buffer_append(®->buf, "\0", 1); - } - default: - return false; - } +bool register_put_range(Vis *vis, Register *reg, Text *txt, Filerange *range) { + return register_slot_put_range(vis, reg, 0, txt, range) && + register_resize(reg, 1); +} + +size_t register_count(Register *reg) { + return array_length(®->values); +} + +bool register_resize(Register *reg, size_t count) { + return array_truncate(®->values, count); } -- cgit v1.2.3