6 static Buffer
*register_buffer(Register
*reg
, size_t slot
) {
7 Buffer
*buf
= array_get(®
->values
, slot
);
10 if (array_resize(®
->values
, slot
) && (buf
= array_get(®
->values
, slot
)))
14 if (!array_add(®
->values
, &new))
16 size_t capacity
= array_capacity(®
->values
);
17 for (size_t i
= array_length(®
->values
); i
< capacity
; i
++) {
18 if (!array_add(®
->values
, &new))
21 return array_get(®
->values
, slot
);
24 static ssize_t
read_buffer(void *context
, char *data
, size_t len
) {
25 buffer_append(context
, data
, len
);
29 bool register_init(Register
*reg
) {
32 array_init_sized(®
->values
, sizeof(Buffer
));
33 return array_add(®
->values
, &buf
);
36 void register_release(Register
*reg
) {
39 size_t n
= array_capacity(®
->values
);
40 for (size_t i
= 0; i
< n
; i
++)
41 buffer_release(array_get(®
->values
, i
));
42 array_release(®
->values
);
45 const char *register_slot_get(Vis
*vis
, Register
*reg
, size_t slot
, size_t *len
) {
51 Buffer
*buf
= array_get(®
->values
, slot
);
54 buffer_terminate(buf
);
56 *len
= buffer_length0(buf
);
57 return buffer_content0(buf
);
61 Buffer
*buf
= array_get(®
->values
, 0);
64 buffer_printf(buf
, "%zu", slot
+1);
66 *len
= buffer_length0(buf
);
67 return buffer_content0(buf
);
69 case REGISTER_CLIPBOARD
:
73 Buffer
*buf
= array_get(®
->values
, slot
);
78 int status
= vis_pipe(vis
, vis
->win
->file
,
79 &(Filerange
){ .start
= 0, .end
= 0 },
80 (const char*[]){ VIS_CLIPBOARD
, "--paste", NULL
},
81 buf
, read_buffer
, &buferr
, read_buffer
);
84 vis_info_show(vis
, "Command failed %s", buffer_content0(&buferr
));
85 buffer_release(&buferr
);
87 *len
= buffer_length0(buf
);
88 return buffer_content0(buf
);
90 case REGISTER_BLACKHOLE
:
96 const char *register_get(Vis
*vis
, Register
*reg
, size_t *len
) {
97 return register_slot_get(vis
, reg
, 0, len
);
100 bool register_slot_put(Vis
*vis
, Register
*reg
, size_t slot
, const char *data
, size_t len
) {
101 if (reg
->type
!= REGISTER_NORMAL
)
103 Buffer
*buf
= register_buffer(reg
, slot
);
104 return buf
&& buffer_put(buf
, data
, len
);
107 bool register_put(Vis
*vis
, Register
*reg
, const char *data
, size_t len
) {
108 return register_slot_put(vis
, reg
, 0, data
, len
) &&
109 register_resize(reg
, 1);
112 bool register_put0(Vis
*vis
, Register
*reg
, const char *data
) {
113 return register_put(vis
, reg
, data
, strlen(data
)+1);
116 static bool register_slot_append_range(Register
*reg
, size_t slot
, Text
*txt
, Filerange
*range
) {
118 case REGISTER_NORMAL
:
120 Buffer
*buf
= register_buffer(reg
, slot
);
123 size_t len
= text_range_size(range
);
124 if (len
== SIZE_MAX
|| !buffer_grow(buf
, len
+1))
126 if (buf
->len
> 0 && buf
->data
[buf
->len
-1] == '\0')
128 buf
->len
+= text_bytes_get(txt
, range
->start
, len
, buf
->data
+ buf
->len
);
129 return buffer_append(buf
, "\0", 1);
136 bool register_slot_put_range(Vis
*vis
, Register
*reg
, size_t slot
, Text
*txt
, Filerange
*range
) {
138 return register_slot_append_range(reg
, slot
, txt
, range
);
141 case REGISTER_NORMAL
:
143 Buffer
*buf
= register_buffer(reg
, slot
);
146 size_t len
= text_range_size(range
);
147 if (len
== SIZE_MAX
|| !buffer_reserve(buf
, len
+1))
149 buf
->len
= text_bytes_get(txt
, range
->start
, len
, buf
->data
);
150 return buffer_append(buf
, "\0", 1);
152 case REGISTER_CLIPBOARD
:
155 buffer_init(&buferr
);
157 int status
= vis_pipe(vis
, vis
->win
->file
, range
,
158 (const char*[]){ VIS_CLIPBOARD
, "--copy", NULL
},
159 NULL
, NULL
, &buferr
, read_buffer
);
162 vis_info_show(vis
, "Command failed %s", buffer_content0(&buferr
));
163 buffer_release(&buferr
);
166 case REGISTER_BLACKHOLE
:
173 bool register_put_range(Vis
*vis
, Register
*reg
, Text
*txt
, Filerange
*range
) {
174 return register_slot_put_range(vis
, reg
, 0, txt
, range
) &&
175 register_resize(reg
, 1);
178 size_t vis_register_count(Vis
*vis
, Register
*reg
) {
179 if (reg
->type
== REGISTER_NUMBER
)
180 return vis
->win
? view_selections_count(vis
->win
->view
) : 0;
181 return array_length(®
->values
);
184 bool register_resize(Register
*reg
, size_t count
) {
185 return array_truncate(®
->values
, count
);
188 enum VisRegister
vis_register_from(Vis
*vis
, char reg
) {
190 case '+': return VIS_REG_CLIPBOARD
;
191 case '@': return VIS_MACRO_LAST_RECORDED
;
194 if ('a' <= reg
&& reg
<= 'z')
195 return VIS_REG_a
+ reg
- 'a';
196 if ('A' <= reg
&& reg
<= 'Z')
197 return VIS_REG_A
+ reg
- 'A';
198 for (size_t i
= 0; i
< LENGTH(vis_registers
); i
++) {
199 if (vis_registers
[i
].name
== reg
)
202 return VIS_REG_INVALID
;
205 void vis_register(Vis
*vis
, enum VisRegister reg
) {
206 if (VIS_REG_A
<= reg
&& reg
<= VIS_REG_Z
) {
207 vis
->action
.reg
= &vis
->registers
[VIS_REG_a
+ reg
- VIS_REG_A
];
208 vis
->action
.reg
->append
= true;
209 } else if (reg
< LENGTH(vis
->registers
)) {
210 vis
->action
.reg
= &vis
->registers
[reg
];
211 vis
->action
.reg
->append
= false;
215 enum VisRegister
vis_register_used(Vis
*vis
) {
216 if (!vis
->action
.reg
)
217 return VIS_REG_DEFAULT
;
218 return vis
->action
.reg
- vis
->registers
;
221 static Register
*register_from(Vis
*vis
, enum VisRegister id
) {
222 if (VIS_REG_A
<= id
&& id
<= VIS_REG_Z
)
223 id
= VIS_REG_a
+ id
- VIS_REG_A
;
224 if (id
< LENGTH(vis
->registers
))
225 return &vis
->registers
[id
];
229 bool vis_register_set(Vis
*vis
, enum VisRegister id
, Array
*data
) {
230 Register
*reg
= register_from(vis
, id
);
233 size_t len
= array_length(data
);
234 for (size_t i
= 0; i
< len
; i
++) {
235 Buffer
*buf
= register_buffer(reg
, i
);
238 TextString
*string
= array_get(data
, i
);
239 if (!buffer_put(buf
, string
->data
, string
->len
))
242 return register_resize(reg
, len
);
245 Array
vis_register_get(Vis
*vis
, enum VisRegister id
) {
247 array_init_sized(&data
, sizeof(TextString
));
248 Register
*reg
= register_from(vis
, id
);
250 size_t len
= array_length(®
->values
);
251 array_reserve(&data
, len
);
252 for (size_t i
= 0; i
< len
; i
++) {
253 Buffer
*buf
= array_get(®
->values
, i
);
254 TextString string
= {
255 .data
= buffer_content(buf
),
256 .len
= buffer_length(buf
),
258 array_add(&data
, &string
);
264 const RegisterDef vis_registers
[] = {
265 [VIS_REG_DEFAULT
] = { '"', VIS_HELP("Unnamed register") },
266 [VIS_REG_ZERO
] = { '0', VIS_HELP("Yank register") },
267 [VIS_REG_1
] = { '1', VIS_HELP("1st sub-expression match") },
268 [VIS_REG_2
] = { '2', VIS_HELP("2nd sub-expression match") },
269 [VIS_REG_3
] = { '3', VIS_HELP("3rd sub-expression match") },
270 [VIS_REG_4
] = { '4', VIS_HELP("4th sub-expression match") },
271 [VIS_REG_5
] = { '5', VIS_HELP("5th sub-expression match") },
272 [VIS_REG_6
] = { '6', VIS_HELP("6th sub-expression match") },
273 [VIS_REG_7
] = { '7', VIS_HELP("7th sub-expression match") },
274 [VIS_REG_8
] = { '8', VIS_HELP("8th sub-expression match") },
275 [VIS_REG_9
] = { '9', VIS_HELP("9th sub-expression match") },
276 [VIS_REG_AMPERSAND
] = { '&', VIS_HELP("Last regex match") },
277 [VIS_REG_BLACKHOLE
] = { '_', VIS_HELP("/dev/null register") },
278 [VIS_REG_CLIPBOARD
] = { '*', VIS_HELP("System clipboard register, see vis-clipboard(1)") },
279 [VIS_REG_DOT
] = { '.', VIS_HELP("Last inserted text") },
280 [VIS_REG_SEARCH
] = { '/', VIS_HELP("Last search pattern") },
281 [VIS_REG_COMMAND
] = { ':', VIS_HELP("Last :-command") },
282 [VIS_REG_SHELL
] = { '!', VIS_HELP("Last shell command given to either <, >, |, or !") },
283 [VIS_REG_NUMBER
] = { '#', VIS_HELP("Register number") },