Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/libedit/emacs.c
39475 views
1
/* $NetBSD: emacs.c,v 1.38 2024/06/29 17:28:07 christos Exp $ */
2
3
/*-
4
* Copyright (c) 1992, 1993
5
* The Regents of the University of California. All rights reserved.
6
*
7
* This code is derived from software contributed to Berkeley by
8
* Christos Zoulas of Cornell University.
9
*
10
* Redistribution and use in source and binary forms, with or without
11
* modification, are permitted provided that the following conditions
12
* are met:
13
* 1. Redistributions of source code must retain the above copyright
14
* notice, this list of conditions and the following disclaimer.
15
* 2. Redistributions in binary form must reproduce the above copyright
16
* notice, this list of conditions and the following disclaimer in the
17
* documentation and/or other materials provided with the distribution.
18
* 3. Neither the name of the University nor the names of its contributors
19
* may be used to endorse or promote products derived from this software
20
* without specific prior written permission.
21
*
22
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
* SUCH DAMAGE.
33
*/
34
35
#include "config.h"
36
#if !defined(lint) && !defined(SCCSID)
37
#if 0
38
static char sccsid[] = "@(#)emacs.c 8.1 (Berkeley) 6/4/93";
39
#else
40
__RCSID("$NetBSD: emacs.c,v 1.38 2024/06/29 17:28:07 christos Exp $");
41
#endif
42
#endif /* not lint && not SCCSID */
43
44
/*
45
* emacs.c: Emacs functions
46
*/
47
#include <ctype.h>
48
49
#include "el.h"
50
#include "emacs.h"
51
#include "fcns.h"
52
53
/* em_delete_or_list():
54
* Delete character under cursor or list completions if at end of line
55
* [^D]
56
*/
57
libedit_private el_action_t
58
/*ARGSUSED*/
59
em_delete_or_list(EditLine *el, wint_t c)
60
{
61
62
if (el->el_line.cursor == el->el_line.lastchar) {
63
/* if I'm at the end */
64
if (el->el_line.cursor == el->el_line.buffer) {
65
/* and the beginning */
66
terminal_writec(el, c); /* then do an EOF */
67
return CC_EOF;
68
} else {
69
/*
70
* Here we could list completions, but it is an
71
* error right now
72
*/
73
terminal_beep(el);
74
return CC_ERROR;
75
}
76
} else {
77
if (el->el_state.doingarg)
78
c_delafter(el, el->el_state.argument);
79
else
80
c_delafter1(el);
81
if (el->el_line.cursor > el->el_line.lastchar)
82
el->el_line.cursor = el->el_line.lastchar;
83
/* bounds check */
84
return CC_REFRESH;
85
}
86
}
87
88
89
/* em_delete_next_word():
90
* Cut from cursor to end of current word
91
* [M-d]
92
*/
93
libedit_private el_action_t
94
/*ARGSUSED*/
95
em_delete_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
96
{
97
wchar_t *cp, *p, *kp;
98
99
if (el->el_line.cursor == el->el_line.lastchar)
100
return CC_ERROR;
101
102
cp = c__next_word(el->el_line.cursor, el->el_line.lastchar,
103
el->el_state.argument, ce__isword);
104
105
for (p = el->el_line.cursor, kp = el->el_chared.c_kill.buf; p < cp; p++)
106
/* save the text */
107
*kp++ = *p;
108
el->el_chared.c_kill.last = kp;
109
110
c_delafter(el, (int)(cp - el->el_line.cursor)); /* delete after dot */
111
if (el->el_line.cursor > el->el_line.lastchar)
112
el->el_line.cursor = el->el_line.lastchar;
113
/* bounds check */
114
return CC_REFRESH;
115
}
116
117
118
/* em_yank():
119
* Paste cut buffer at cursor position
120
* [^Y]
121
*/
122
libedit_private el_action_t
123
/*ARGSUSED*/
124
em_yank(EditLine *el, wint_t c __attribute__((__unused__)))
125
{
126
wchar_t *kp, *cp;
127
128
if (el->el_chared.c_kill.last == el->el_chared.c_kill.buf)
129
return CC_NORM;
130
131
if (el->el_line.lastchar +
132
(el->el_chared.c_kill.last - el->el_chared.c_kill.buf) >=
133
el->el_line.limit)
134
return CC_ERROR;
135
136
el->el_chared.c_kill.mark = el->el_line.cursor;
137
138
/* open the space, */
139
c_insert(el,
140
(int)(el->el_chared.c_kill.last - el->el_chared.c_kill.buf));
141
cp = el->el_line.cursor;
142
/* copy the chars */
143
for (kp = el->el_chared.c_kill.buf; kp < el->el_chared.c_kill.last; kp++)
144
*cp++ = *kp;
145
146
/* if an arg, cursor at beginning else cursor at end */
147
if (el->el_state.argument == 1)
148
el->el_line.cursor = cp;
149
150
return CC_REFRESH;
151
}
152
153
154
/* em_kill_line():
155
* Cut the entire line and save in cut buffer
156
* [^U]
157
*/
158
libedit_private el_action_t
159
/*ARGSUSED*/
160
em_kill_line(EditLine *el, wint_t c __attribute__((__unused__)))
161
{
162
wchar_t *kp, *cp;
163
164
cp = el->el_line.buffer;
165
kp = el->el_chared.c_kill.buf;
166
while (cp < el->el_line.lastchar)
167
*kp++ = *cp++; /* copy it */
168
el->el_chared.c_kill.last = kp;
169
/* zap! -- delete all of it */
170
el->el_line.lastchar = el->el_line.buffer;
171
el->el_line.cursor = el->el_line.buffer;
172
return CC_REFRESH;
173
}
174
175
176
/* em_kill_region():
177
* Cut area between mark and cursor and save in cut buffer
178
* [^W]
179
*/
180
libedit_private el_action_t
181
/*ARGSUSED*/
182
em_kill_region(EditLine *el, wint_t c __attribute__((__unused__)))
183
{
184
wchar_t *kp, *cp;
185
186
if (!el->el_chared.c_kill.mark)
187
return CC_ERROR;
188
189
if (el->el_chared.c_kill.mark > el->el_line.cursor) {
190
cp = el->el_line.cursor;
191
kp = el->el_chared.c_kill.buf;
192
while (cp < el->el_chared.c_kill.mark)
193
*kp++ = *cp++; /* copy it */
194
el->el_chared.c_kill.last = kp;
195
c_delafter(el, (int)(cp - el->el_line.cursor));
196
} else { /* mark is before cursor */
197
cp = el->el_chared.c_kill.mark;
198
kp = el->el_chared.c_kill.buf;
199
while (cp < el->el_line.cursor)
200
*kp++ = *cp++; /* copy it */
201
el->el_chared.c_kill.last = kp;
202
c_delbefore(el, (int)(cp - el->el_chared.c_kill.mark));
203
el->el_line.cursor = el->el_chared.c_kill.mark;
204
}
205
return CC_REFRESH;
206
}
207
208
209
/* em_copy_region():
210
* Copy area between mark and cursor to cut buffer
211
* [M-W]
212
*/
213
libedit_private el_action_t
214
/*ARGSUSED*/
215
em_copy_region(EditLine *el, wint_t c __attribute__((__unused__)))
216
{
217
wchar_t *kp, *cp;
218
219
if (!el->el_chared.c_kill.mark)
220
return CC_ERROR;
221
222
if (el->el_chared.c_kill.mark > el->el_line.cursor) {
223
cp = el->el_line.cursor;
224
kp = el->el_chared.c_kill.buf;
225
while (cp < el->el_chared.c_kill.mark)
226
*kp++ = *cp++; /* copy it */
227
el->el_chared.c_kill.last = kp;
228
} else {
229
cp = el->el_chared.c_kill.mark;
230
kp = el->el_chared.c_kill.buf;
231
while (cp < el->el_line.cursor)
232
*kp++ = *cp++; /* copy it */
233
el->el_chared.c_kill.last = kp;
234
}
235
return CC_NORM;
236
}
237
238
239
/* em_gosmacs_transpose():
240
* Exchange the two characters before the cursor
241
* Gosling emacs transpose chars [^T]
242
*/
243
libedit_private el_action_t
244
em_gosmacs_transpose(EditLine *el, wint_t c)
245
{
246
247
if (el->el_line.cursor > &el->el_line.buffer[1]) {
248
/* must have at least two chars entered */
249
c = el->el_line.cursor[-2];
250
el->el_line.cursor[-2] = el->el_line.cursor[-1];
251
el->el_line.cursor[-1] = c;
252
return CC_REFRESH;
253
} else
254
return CC_ERROR;
255
}
256
257
258
/* em_next_word():
259
* Move next to end of current word
260
* [M-f]
261
*/
262
libedit_private el_action_t
263
/*ARGSUSED*/
264
em_next_word(EditLine *el, wint_t c __attribute__((__unused__)))
265
{
266
if (el->el_line.cursor == el->el_line.lastchar)
267
return CC_ERROR;
268
269
el->el_line.cursor = c__next_word(el->el_line.cursor,
270
el->el_line.lastchar,
271
el->el_state.argument,
272
ce__isword);
273
274
if (el->el_map.type == MAP_VI)
275
if (el->el_chared.c_vcmd.action != NOP) {
276
cv_delfini(el);
277
return CC_REFRESH;
278
}
279
return CC_CURSOR;
280
}
281
282
283
/* em_upper_case():
284
* Uppercase the characters from cursor to end of current word
285
* [M-u]
286
*/
287
libedit_private el_action_t
288
/*ARGSUSED*/
289
em_upper_case(EditLine *el, wint_t c __attribute__((__unused__)))
290
{
291
wchar_t *cp, *ep;
292
293
ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
294
el->el_state.argument, ce__isword);
295
296
for (cp = el->el_line.cursor; cp < ep; cp++)
297
if (iswlower(*cp))
298
*cp = towupper(*cp);
299
300
el->el_line.cursor = ep;
301
if (el->el_line.cursor > el->el_line.lastchar)
302
el->el_line.cursor = el->el_line.lastchar;
303
return CC_REFRESH;
304
}
305
306
307
/* em_capitol_case():
308
* Capitalize the characters from cursor to end of current word
309
* [M-c]
310
*/
311
libedit_private el_action_t
312
/*ARGSUSED*/
313
em_capitol_case(EditLine *el, wint_t c __attribute__((__unused__)))
314
{
315
wchar_t *cp, *ep;
316
317
ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
318
el->el_state.argument, ce__isword);
319
320
for (cp = el->el_line.cursor; cp < ep; cp++) {
321
if (iswalpha(*cp)) {
322
if (iswlower(*cp))
323
*cp = towupper(*cp);
324
cp++;
325
break;
326
}
327
}
328
for (; cp < ep; cp++)
329
if (iswupper(*cp))
330
*cp = towlower(*cp);
331
332
el->el_line.cursor = ep;
333
if (el->el_line.cursor > el->el_line.lastchar)
334
el->el_line.cursor = el->el_line.lastchar;
335
return CC_REFRESH;
336
}
337
338
339
/* em_lower_case():
340
* Lowercase the characters from cursor to end of current word
341
* [M-l]
342
*/
343
libedit_private el_action_t
344
/*ARGSUSED*/
345
em_lower_case(EditLine *el, wint_t c __attribute__((__unused__)))
346
{
347
wchar_t *cp, *ep;
348
349
ep = c__next_word(el->el_line.cursor, el->el_line.lastchar,
350
el->el_state.argument, ce__isword);
351
352
for (cp = el->el_line.cursor; cp < ep; cp++)
353
if (iswupper(*cp))
354
*cp = towlower(*cp);
355
356
el->el_line.cursor = ep;
357
if (el->el_line.cursor > el->el_line.lastchar)
358
el->el_line.cursor = el->el_line.lastchar;
359
return CC_REFRESH;
360
}
361
362
363
/* em_set_mark():
364
* Set the mark at cursor
365
* [^@]
366
*/
367
libedit_private el_action_t
368
/*ARGSUSED*/
369
em_set_mark(EditLine *el, wint_t c __attribute__((__unused__)))
370
{
371
372
el->el_chared.c_kill.mark = el->el_line.cursor;
373
return CC_NORM;
374
}
375
376
377
/* em_exchange_mark():
378
* Exchange the cursor and mark
379
* [^X^X]
380
*/
381
libedit_private el_action_t
382
/*ARGSUSED*/
383
em_exchange_mark(EditLine *el, wint_t c __attribute__((__unused__)))
384
{
385
wchar_t *cp;
386
387
cp = el->el_line.cursor;
388
el->el_line.cursor = el->el_chared.c_kill.mark;
389
el->el_chared.c_kill.mark = cp;
390
return CC_CURSOR;
391
}
392
393
394
/* em_universal_argument():
395
* Universal argument (argument times 4)
396
* [^U]
397
*/
398
libedit_private el_action_t
399
/*ARGSUSED*/
400
em_universal_argument(EditLine *el, wint_t c __attribute__((__unused__)))
401
{ /* multiply current argument by 4 */
402
403
if (el->el_state.argument > 1000000)
404
return CC_ERROR;
405
el->el_state.doingarg = 1;
406
el->el_state.argument *= 4;
407
return CC_ARGHACK;
408
}
409
410
411
/* em_meta_next():
412
* Add 8th bit to next character typed
413
* [<ESC>]
414
*/
415
libedit_private el_action_t
416
/*ARGSUSED*/
417
em_meta_next(EditLine *el, wint_t c __attribute__((__unused__)))
418
{
419
420
el->el_state.metanext = 1;
421
return CC_ARGHACK;
422
}
423
424
425
/* em_toggle_overwrite():
426
* Switch from insert to overwrite mode or vice versa
427
*/
428
libedit_private el_action_t
429
/*ARGSUSED*/
430
em_toggle_overwrite(EditLine *el, wint_t c __attribute__((__unused__)))
431
{
432
433
el->el_state.inputmode = (el->el_state.inputmode == MODE_INSERT) ?
434
MODE_REPLACE : MODE_INSERT;
435
return CC_NORM;
436
}
437
438
439
/* em_copy_prev_word():
440
* Copy current word to cursor
441
*/
442
libedit_private el_action_t
443
/*ARGSUSED*/
444
em_copy_prev_word(EditLine *el, wint_t c __attribute__((__unused__)))
445
{
446
wchar_t *cp, *oldc, *dp;
447
448
if (el->el_line.cursor == el->el_line.buffer)
449
return CC_ERROR;
450
451
/* does a bounds check */
452
cp = c__prev_word(el->el_line.cursor, el->el_line.buffer,
453
el->el_state.argument, ce__isword);
454
455
c_insert(el, (int)(el->el_line.cursor - cp));
456
oldc = el->el_line.cursor;
457
for (dp = oldc; cp < oldc && dp < el->el_line.lastchar; cp++)
458
*dp++ = *cp;
459
460
el->el_line.cursor = dp;/* put cursor at end */
461
462
return CC_REFRESH;
463
}
464
465
466
/* em_inc_search_next():
467
* Emacs incremental next search
468
*/
469
libedit_private el_action_t
470
/*ARGSUSED*/
471
em_inc_search_next(EditLine *el, wint_t c __attribute__((__unused__)))
472
{
473
474
el->el_search.patlen = 0;
475
return ce_inc_search(el, ED_SEARCH_NEXT_HISTORY);
476
}
477
478
479
/* em_inc_search_prev():
480
* Emacs incremental reverse search
481
*/
482
libedit_private el_action_t
483
/*ARGSUSED*/
484
em_inc_search_prev(EditLine *el, wint_t c __attribute__((__unused__)))
485
{
486
487
el->el_search.patlen = 0;
488
return ce_inc_search(el, ED_SEARCH_PREV_HISTORY);
489
}
490
491
492
/* em_delete_prev_char():
493
* Delete the character to the left of the cursor
494
* [^?]
495
*/
496
libedit_private el_action_t
497
/*ARGSUSED*/
498
em_delete_prev_char(EditLine *el, wint_t c __attribute__((__unused__)))
499
{
500
501
if (el->el_line.cursor <= el->el_line.buffer)
502
return CC_ERROR;
503
504
if (el->el_state.doingarg)
505
c_delbefore(el, el->el_state.argument);
506
else
507
c_delbefore1(el);
508
el->el_line.cursor -= el->el_state.argument;
509
if (el->el_line.cursor < el->el_line.buffer)
510
el->el_line.cursor = el->el_line.buffer;
511
return CC_REFRESH;
512
}
513
514