aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--main.c1
-rw-r--r--register.c138
-rw-r--r--register.h17
-rw-r--r--view.c6
-rw-r--r--view.h2
-rw-r--r--vis-core.h3
-rw-r--r--vis-operators.c10
-rw-r--r--vis.c31
8 files changed, 152 insertions, 56 deletions
diff --git a/main.c b/main.c
index 9e7e9a3..8091c13 100644
--- a/main.c
+++ b/main.c
@@ -18,6 +18,7 @@
#include "util.h"
#include "libutf.h"
#include "array.h"
+#include "buffer.h"
#define PAGE INT_MAX
#define PAGE_HALF (INT_MAX-1)
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(&reg->values, slot);
+ if (buf)
+ return buf;
+ if (array_resize(&reg->values, slot) && (buf = array_get(&reg->values, slot)))
+ return buf;
+ Buffer new;
+ buffer_init(&new);
+ if (!array_add(&reg->values, &new))
+ return NULL;
+ size_t capacity = array_capacity(&reg->values);
+ for (size_t i = array_length(&reg->values); i < capacity; i++) {
+ if (!array_add(&reg->values, &new))
+ return NULL;
+ }
+ return array_get(&reg->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(&reg->values, sizeof(Buffer));
+ return array_add(&reg->values, &buf);
+}
+
void register_release(Register *reg) {
- buffer_release(&reg->buf);
+ if (!reg)
+ return;
+ size_t n = array_capacity(&reg->values);
+ for (size_t i = 0; i < n; i++)
+ buffer_release(array_get(&reg->values, i));
+ array_release(&reg->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(&reg->buf, "\0", 1);
+ {
+ Buffer *buf = array_get(&reg->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(&reg->buf);
+ Buffer *buf = array_get(&reg->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 },
- &reg->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(&reg->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(&reg->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(&reg->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(&reg->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(&reg->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(&reg->values);
+}
+
+bool register_resize(Register *reg, size_t count) {
+ return array_truncate(&reg->values, count);
}
diff --git a/register.h b/register.h
index a815a90..379da87 100644
--- a/register.h
+++ b/register.h
@@ -4,11 +4,11 @@
#include <stddef.h>
#include <stdbool.h>
#include "vis.h"
-#include "buffer.h"
+#include "array.h"
#include "text-util.h"
typedef struct {
- Buffer buf;
+ Array values;
bool linewise; /* place register content on a new line when inserting? */
bool append;
enum {
@@ -18,11 +18,20 @@ typedef struct {
} type;
} Register;
+bool register_init(Register*);
void register_release(Register*);
+
const char *register_get(Vis*, Register*, size_t *len);
-bool register_put(Vis*, Register*, const char *data, size_t len);
+const char *register_slot_get(Vis*, Register*, size_t slot, size_t *len);
+
bool register_put0(Vis*, Register*, const char *data);
+bool register_put(Vis*, Register*, const char *data, size_t len);
+bool register_slot_put(Vis*, Register*, size_t slot, const char *data, size_t len);
+
bool register_put_range(Vis*, Register*, Text*, Filerange*);
-bool register_append_range(Register*, Text*, Filerange*);
+bool register_slot_put_range(Vis*, Register*, size_t slot, Text*, Filerange*);
+
+size_t register_count(Register*);
+bool register_resize(Register*, size_t count);
#endif
diff --git a/view.c b/view.c
index 7e893ff..76410aa 100644
--- a/view.c
+++ b/view.c
@@ -55,7 +55,6 @@ struct Cursor { /* cursor position */
Selection *sel; /* selection (if any) which folows the cursor upon movement */
Mark lastsel_anchor;/* previously used selection data, */
Mark lastsel_cursor;/* used to restore it */
- Register reg; /* per cursor register to support yank/put operation */
int generation; /* used to filter out newly created cursors during iteration */
int number; /* how many cursors are located before this one */
View *view; /* associated view to which this cursor belongs */
@@ -1005,7 +1004,6 @@ bool view_cursors_multiple(View *view) {
static void view_cursors_free(Cursor *c) {
if (!c)
return;
- register_release(&c->reg);
for (Cursor *after = c->next; after; after = after->next)
after->number--;
if (c->prev)
@@ -1119,10 +1117,6 @@ int view_cursors_cell_set(Cursor *c, int cell) {
return c->col;
}
-Register *view_cursors_register(Cursor *c) {
- return &c->reg;
-}
-
void view_cursors_scroll_to(Cursor *c, size_t pos) {
View *view = c->view;
if (view->cursor == c) {
diff --git a/view.h b/view.h
index c382505..262c581 100644
--- a/view.h
+++ b/view.h
@@ -160,8 +160,6 @@ void view_cursors_to(Cursor*, size_t pos);
void view_cursors_scroll_to(Cursor*, size_t pos);
/* place cursor on given (line, column) pair, both values are 1-based */
void view_cursors_place(Cursor*, size_t line, size_t col);
-/* get register associated with this register */
-Register *view_cursors_register(Cursor*);
/* start selected area at current cursor position. further cursor movements
* will affect the selected region. */
void view_cursors_selection_start(Cursor*);
diff --git a/vis-core.h b/vis-core.h
index 654085d..b0caee1 100644
--- a/vis-core.h
+++ b/vis-core.h
@@ -10,6 +10,7 @@
#include "map.h"
#include "ring-buffer.h"
#include "array.h"
+#include "buffer.h"
/* a mode contains a set of key bindings which are currently valid.
*
@@ -40,6 +41,7 @@ struct Mode {
struct OperatorContext {
int count; /* how many times should the command be executed? */
Register *reg; /* always non-NULL, set to a default register */
+ size_t reg_slot; /* register slot to use */
Filerange range; /* which part of the file should be affected by the operator */
size_t pos; /* at which byte from the start of the file should the operation start? */
size_t newpos; /* new position after motion or EPOS if none given */
@@ -248,6 +250,7 @@ void action_reset(Action*);
size_t vis_text_insert_nl(Vis*, Text*, size_t pos);
void mode_set(Vis *vis, Mode *new_mode);
+Macro *macro_get(Vis *vis, enum VisRegister);
void window_selection_save(Win *win);
Win *window_new_file(Vis*, File*, enum UiOption);
diff --git a/vis-operators.c b/vis-operators.c
index 1ef32c3..38ac7c8 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_range(vis, c->reg, txt, &c->range);
+ register_slot_put_range(vis, c->reg, c->reg_slot, txt, &c->range);
text_delete_range(txt, &c->range);
size_t pos = c->range.start;
if (c->linewise && pos == text_size(txt))
@@ -26,10 +26,10 @@ 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_range(vis, c->reg, txt, &c->range);
+ register_slot_put_range(vis, c->reg, c->reg_slot, txt, &c->range);
if (c->reg == &vis->registers[VIS_REG_DEFAULT]) {
vis->registers[VIS_REG_ZERO].linewise = c->reg->linewise;
- register_put_range(vis, &vis->registers[VIS_REG_ZERO], txt, &c->range);
+ register_slot_put_range(vis, &vis->registers[VIS_REG_ZERO], c->reg_slot, txt, &c->range);
}
return c->linewise ? c->pos : c->range.start;
}
@@ -59,7 +59,7 @@ static size_t op_put(Vis *vis, Text *txt, OperatorContext *c) {
}
size_t len;
- const char *data = register_get(vis, c->reg, &len);
+ const char *data = register_slot_get(vis, c->reg, c->reg_slot, &len);
for (int i = 0; i < c->count; i++) {
char nl;
@@ -298,7 +298,7 @@ bool vis_operator(Vis *vis, enum VisOperator id, ...) {
break;
case VIS_OP_REPLACE:
{
- Macro *macro = &vis->registers[VIS_REG_DOT].buf;
+ Macro *macro = macro_get(vis, VIS_REG_DOT);
macro_reset(macro);
macro_append(macro, va_arg(ap, char*));
vis->action.arg.s = macro->data;
diff --git a/vis.c b/vis.c
index 4cfa3fe..a6a48da 100644
--- a/vis.c
+++ b/vis.c
@@ -54,7 +54,6 @@ const RegisterDef vis_registers[] = {
[VIS_REG_SHELL] = { '!', VIS_HELP("Last shell command given to either <, >, |, or !") },
};
-static Macro *macro_get(Vis *vis, enum VisRegister);
static void macro_replay(Vis *vis, const Macro *macro);
static void macro_replay_internal(Vis *vis, const Macro *macro);
static void vis_keys_push(Vis *vis, const char *input, size_t pos, bool record);
@@ -670,6 +669,8 @@ Vis *vis_new(Ui *ui, VisEvent *event) {
vis->tabwidth = 8;
vis->expandtab = false;
vis->change_colors = true;
+ for (size_t i = 0; i < LENGTH(vis->registers); i++)
+ register_init(&vis->registers[i]);
vis->registers[VIS_REG_BLACKHOLE].type = REGISTER_BLACKHOLE;
vis->registers[VIS_REG_CLIPBOARD].type = REGISTER_CLIPBOARD;
array_init(&vis->operators);
@@ -834,6 +835,15 @@ void vis_do(Vis *vis) {
a->type & LINEWISE || (a->movement && a->movement->type & LINEWISE) ||
vis->mode == &vis_modes[VIS_MODE_VISUAL_LINE]);
+
+ Register *reg = a->reg;
+ size_t reg_slot = multiple_cursors ? EPOS : 0;
+ size_t last_reg_slot = reg_slot;
+ if (!reg)
+ reg = &vis->registers[file->internal ? VIS_REG_PROMPT : VIS_REG_DEFAULT];
+ if (a->op == &vis_operators[VIS_OP_PUT_AFTER] && multiple_cursors && register_count(reg) == 1)
+ reg_slot = 0;
+
for (Cursor *cursor = view_cursors(view), *next; cursor; cursor = next) {
if (vis->interrupted)
break;
@@ -847,21 +857,20 @@ void vis_do(Vis *vis) {
continue;
}
- Register *reg = multiple_cursors ? view_cursors_register(cursor) : a->reg;
- if (!reg)
- reg = &vis->registers[file->internal ? VIS_REG_PROMPT : VIS_REG_DEFAULT];
-
OperatorContext c = {
.count = count,
.pos = pos,
.newpos = EPOS,
.range = text_range_empty(),
.reg = reg,
+ .reg_slot = reg_slot == EPOS ? (size_t)view_cursors_number(cursor) : reg_slot,
.linewise = linewise,
.arg = &a->arg,
.context = a->op ? a->op->context : NULL,
};
+ last_reg_slot = c.reg_slot;
+
bool err = false;
if (a->movement) {
size_t start = pos;
@@ -1000,6 +1009,14 @@ void vis_do(Vis *vis) {
}
if (a->op) {
+
+ if (a->op == &vis_operators[VIS_OP_YANK] ||
+ a->op == &vis_operators[VIS_OP_DELETE] ||
+ a->op == &vis_operators[VIS_OP_CHANGE] ||
+ a->op == &vis_operators[VIS_OP_REPLACE]) {
+ register_resize(reg, last_reg_slot+1);
+ }
+
/* we do not support visual repeat, still do something resonable */
if (vis->mode->visual && !a->movement && !a->textobj)
a->movement = &vis_motions[VIS_MOVE_NOP];
@@ -1389,13 +1406,13 @@ int vis_run(Vis *vis, int argc, char *argv[]) {
return vis->exit_status;
}
-static Macro *macro_get(Vis *vis, enum VisRegister id) {
+Macro *macro_get(Vis *vis, enum VisRegister id) {
if (id == VIS_MACRO_LAST_RECORDED)
return vis->last_recording;
if (VIS_REG_A <= id && id <= VIS_REG_Z)
id -= VIS_REG_A;
if (id < LENGTH(vis->registers))
- return &vis->registers[id].buf;
+ return array_get(&vis->registers[id].values, 0);
return NULL;
}