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
:
72 enum VisRegister id
= reg
- vis
->registers
;
73 const char *cmd
[] = { VIS_CLIPBOARD
, "--paste", "--selection", NULL
, NULL
};
75 Buffer
*buf
= array_get(®
->values
, slot
);
80 if (id
== VIS_REG_PRIMARY
)
84 int status
= vis_pipe(vis
, vis
->win
->file
,
85 &(Filerange
){ .start
= 0, .end
= 0 },
86 cmd
, buf
, read_buffer
, &buferr
, read_buffer
, false);
89 vis_info_show(vis
, "Command failed %s", buffer_content0(&buferr
));
90 buffer_release(&buferr
);
92 *len
= buffer_length0(buf
);
93 return buffer_content0(buf
);
95 case REGISTER_BLACKHOLE
:
101 const char *register_get(Vis
*vis
, Register
*reg
, size_t *len
) {
102 return register_slot_get(vis
, reg
, 0, len
);
105 bool register_slot_put(Vis
*vis
, Register
*reg
, size_t slot
, const char *data
, size_t len
) {
106 if (reg
->type
!= REGISTER_NORMAL
)
108 Buffer
*buf
= register_buffer(reg
, slot
);
109 return buf
&& buffer_put(buf
, data
, len
);
112 bool register_put(Vis
*vis
, Register
*reg
, const char *data
, size_t len
) {
113 return register_slot_put(vis
, reg
, 0, data
, len
) &&
114 register_resize(reg
, 1);
117 bool register_put0(Vis
*vis
, Register
*reg
, const char *data
) {
118 return register_put(vis
, reg
, data
, strlen(data
)+1);
121 static bool register_slot_append_range(Register
*reg
, size_t slot
, Text
*txt
, Filerange
*range
) {
123 case REGISTER_NORMAL
:
125 Buffer
*buf
= register_buffer(reg
, slot
);
128 size_t len
= text_range_size(range
);
129 if (len
== SIZE_MAX
|| !buffer_grow(buf
, len
+1))
131 if (buf
->len
> 0 && buf
->data
[buf
->len
-1] == '\0')
133 buf
->len
+= text_bytes_get(txt
, range
->start
, len
, buf
->data
+ buf
->len
);
134 return buffer_append(buf
, "\0", 1);
141 bool register_slot_put_range(Vis
*vis
, Register
*reg
, size_t slot
, Text
*txt
, Filerange
*range
) {
143 return register_slot_append_range(reg
, slot
, txt
, range
);
146 case REGISTER_NORMAL
:
148 Buffer
*buf
= register_buffer(reg
, slot
);
151 size_t len
= text_range_size(range
);
152 if (len
== SIZE_MAX
|| !buffer_reserve(buf
, len
+1))
154 buf
->len
= text_bytes_get(txt
, range
->start
, len
, buf
->data
);
155 return buffer_append(buf
, "\0", 1);
157 case REGISTER_CLIPBOARD
:
160 const char *cmd
[] = { VIS_CLIPBOARD
, "--copy", "--selection", NULL
, NULL
};
161 enum VisRegister id
= reg
- vis
->registers
;
162 buffer_init(&buferr
);
164 if (id
== VIS_REG_PRIMARY
)
167 cmd
[3] = "clipboard";
169 int status
= vis_pipe(vis
, vis
->win
->file
, range
,
170 cmd
, NULL
, NULL
, &buferr
, read_buffer
, false);
173 vis_info_show(vis
, "Command failed %s", buffer_content0(&buferr
));
174 buffer_release(&buferr
);
177 case REGISTER_BLACKHOLE
:
184 bool register_put_range(Vis
*vis
, Register
*reg
, Text
*txt
, Filerange
*range
) {
185 return register_slot_put_range(vis
, reg
, 0, txt
, range
) &&
186 register_resize(reg
, 1);
189 size_t vis_register_count(Vis
*vis
, Register
*reg
) {
190 if (reg
->type
== REGISTER_NUMBER
)
191 return vis
->win
? view_selections_count(vis
->win
->view
) : 0;
192 return array_length(®
->values
);
195 bool register_resize(Register
*reg
, size_t count
) {
196 return array_truncate(®
->values
, count
);
199 enum VisRegister
vis_register_from(Vis
*vis
, char reg
) {
202 return VIS_MACRO_LAST_RECORDED
;
204 if ('a' <= reg
&& reg
<= 'z')
205 return VIS_REG_a
+ reg
- 'a';
206 if ('A' <= reg
&& reg
<= 'Z')
207 return VIS_REG_A
+ reg
- 'A';
209 for (size_t i
= 0; i
< LENGTH(vis_registers
); i
++) {
210 if (vis_registers
[i
].name
== reg
)
213 return VIS_REG_INVALID
;
216 char vis_register_to(Vis
*vis
, enum VisRegister reg
) {
218 if (reg
== VIS_MACRO_LAST_RECORDED
)
221 if (VIS_REG_a
<= reg
&& reg
<= VIS_REG_z
)
222 return 'a' + reg
- VIS_REG_a
;
223 if (VIS_REG_A
<= reg
&& reg
<= VIS_REG_Z
)
224 return 'A' + reg
- VIS_REG_A
;
226 if (reg
< LENGTH(vis_registers
))
227 return vis_registers
[reg
].name
;
232 void vis_register(Vis
*vis
, enum VisRegister reg
) {
233 if (VIS_REG_A
<= reg
&& reg
<= VIS_REG_Z
) {
234 vis
->action
.reg
= &vis
->registers
[VIS_REG_a
+ reg
- VIS_REG_A
];
235 vis
->action
.reg
->append
= true;
236 } else if (reg
< LENGTH(vis
->registers
)) {
237 vis
->action
.reg
= &vis
->registers
[reg
];
238 vis
->action
.reg
->append
= false;
242 enum VisRegister
vis_register_used(Vis
*vis
) {
243 if (!vis
->action
.reg
)
244 return VIS_REG_DEFAULT
;
245 return vis
->action
.reg
- vis
->registers
;
248 static Register
*register_from(Vis
*vis
, enum VisRegister id
) {
249 if (VIS_REG_A
<= id
&& id
<= VIS_REG_Z
)
250 id
= VIS_REG_a
+ id
- VIS_REG_A
;
251 if (id
< LENGTH(vis
->registers
))
252 return &vis
->registers
[id
];
256 bool vis_register_set(Vis
*vis
, enum VisRegister id
, Array
*data
) {
257 Register
*reg
= register_from(vis
, id
);
260 size_t len
= array_length(data
);
261 for (size_t i
= 0; i
< len
; i
++) {
262 Buffer
*buf
= register_buffer(reg
, i
);
265 TextString
*string
= array_get(data
, i
);
266 if (!buffer_put(buf
, string
->data
, string
->len
))
269 return register_resize(reg
, len
);
272 Array
vis_register_get(Vis
*vis
, enum VisRegister id
) {
274 array_init_sized(&data
, sizeof(TextString
));
275 Register
*reg
= register_from(vis
, id
);
277 size_t len
= array_length(®
->values
);
278 array_reserve(&data
, len
);
279 for (size_t i
= 0; i
< len
; i
++) {
280 Buffer
*buf
= array_get(®
->values
, i
);
281 TextString string
= {
282 .data
= buffer_content(buf
),
283 .len
= buffer_length(buf
),
285 array_add(&data
, &string
);
291 const RegisterDef vis_registers
[] = {
292 [VIS_REG_DEFAULT
] = { '"', VIS_HELP("Unnamed register") },
293 [VIS_REG_ZERO
] = { '0', VIS_HELP("Yank register") },
294 [VIS_REG_1
] = { '1', VIS_HELP("1st sub-expression match") },
295 [VIS_REG_2
] = { '2', VIS_HELP("2nd sub-expression match") },
296 [VIS_REG_3
] = { '3', VIS_HELP("3rd sub-expression match") },
297 [VIS_REG_4
] = { '4', VIS_HELP("4th sub-expression match") },
298 [VIS_REG_5
] = { '5', VIS_HELP("5th sub-expression match") },
299 [VIS_REG_6
] = { '6', VIS_HELP("6th sub-expression match") },
300 [VIS_REG_7
] = { '7', VIS_HELP("7th sub-expression match") },
301 [VIS_REG_8
] = { '8', VIS_HELP("8th sub-expression match") },
302 [VIS_REG_9
] = { '9', VIS_HELP("9th sub-expression match") },
303 [VIS_REG_AMPERSAND
] = { '&', VIS_HELP("Last regex match") },
304 [VIS_REG_BLACKHOLE
] = { '_', VIS_HELP("/dev/null register") },
305 [VIS_REG_PRIMARY
] = { '*', VIS_HELP("Primary clipboard register, see vis-clipboard(1)") },
306 [VIS_REG_CLIPBOARD
] = { '+', VIS_HELP("System clipboard register, see vis-clipboard(1)") },
307 [VIS_REG_DOT
] = { '.', VIS_HELP("Last inserted text") },
308 [VIS_REG_SEARCH
] = { '/', VIS_HELP("Last search pattern") },
309 [VIS_REG_COMMAND
] = { ':', VIS_HELP("Last :-command") },
310 [VIS_REG_SHELL
] = { '!', VIS_HELP("Last shell command given to either <, >, |, or !") },
311 [VIS_REG_NUMBER
] = { '#', VIS_HELP("Register number") },