1 /* $OpenBSD: emacs.c,v 1.85 2018/06/18 17:03:58 millert Exp $ */
4 * Emacs-like command line editing and history
6 * created by Ron Natalie at BRL
7 * modified by Doug Kingston, Doug Gwyn, and Lou Salkind
8 * adapted to PD ksh by Eric Gisin
10 * partial rewrite by Marco Peereboom <marco@openbsd.org>
11 * under the same license
17 #include <sys/queue.h>
33 #define AEDIT &aedit /* area for kill ring and macro defns */
36 #define CTRL(x) ((x) == '?' ? 0x7F : (x) & 0x1F) /* ASCII */
37 #define UNCTRL(x) ((x) == 0x7F ? '?' : (x) | 0x40) /* ASCII */
39 /* values returned by keyboard functions */
41 #define KEOL 1 /* ^M, ^J */
42 #define KINTR 2 /* ^G, ^C */
45 int (*xf_func
)(int c
);
50 #define XF_ARG 1 /* command takes number prefix */
51 #define XF_NOBIND 2 /* not allowed to bind to function */
52 #define XF_PREFIX 4 /* function sets prefix */
54 /* Separator for completion */
55 #define is_cfs(c) (c == ' ' || c == '\t' || c == '"' || c == '\'')
57 /* Separator for motion */
58 #define is_mfs(c) (!(isalnum((unsigned char)c) || \
59 c == '_' || c == '$' || c & 0x80))
61 /* Arguments for do_complete()
62 * 0 = enumerate M-= complete as much as possible and then list
67 CT_LIST
, /* list the possible completions */
68 CT_COMPLETE
, /* complete to longest prefix */
69 CT_COMPLIST
/* complete and then list (if non-exact) */
74 TAILQ_ENTRY(kb_entry
) entry
;
80 TAILQ_HEAD(kb_list
, kb_entry
);
81 struct kb_list kblist
= TAILQ_HEAD_INITIALIZER(kblist
);
83 /* { from 4.9 edit.h */
85 * The following are used for my horizontal scrolling stuff
87 static char *xbuf
; /* beg input buffer */
88 static char *xend
; /* end input buffer */
89 static char *xcp
; /* current position */
90 static char *xep
; /* current end */
91 static char *xbp
; /* start of visible portion of input buffer */
92 static char *xlp
; /* last byte visible on screen */
95 * we use x_adj_done so that functions can tell
96 * whether x_adjust() has been called while they are active.
98 static int x_adj_done
;
102 static int x_displen
;
103 static int x_arg
; /* general purpose arg */
104 static int x_arg_defaulted
;/* x_arg not explicitly set; defaulted to 1 */
106 static int xlp_valid
;
107 /* end from 4.9 edit.h } */
108 static int x_tty
; /* are we on a tty? */
109 static int x_bind_quiet
; /* be quiet when binding keys */
110 static int (*x_last_command
)(int);
112 static char **x_histp
; /* history position */
113 static int x_nextcmd
; /* for newline-and-next */
114 static char *xmp
; /* mark pointer */
116 static char *killstack
[KILLSIZE
];
117 static int killsp
, killtp
;
118 static int x_literal_set
;
119 static int x_arg_set
;
120 static char *macro_args
;
121 static int prompt_skip
;
122 static int prompt_redraw
;
124 static int x_ins(char *);
125 static void x_delete(int, int);
126 static int x_bword(void);
127 static int x_fword(void);
128 static void x_goto(char *);
129 static void x_bs(int);
130 static int x_size_str(char *);
131 static int x_size(int);
132 static void x_zots(char *);
133 static void x_zotc(int);
134 static void x_load_hist(char **);
135 static int x_search(char *, int, int);
136 static int x_match(char *, char *);
137 static void x_redraw(int);
138 static void x_push(int);
139 static void x_adjust(void);
140 static void x_e_ungetc(int);
141 static int x_e_getc(void);
142 static int x_e_getu8(char *, int);
143 static void x_e_putc(int);
144 static void x_e_puts(const char *);
145 static int x_comment(int);
146 static int x_fold_case(int);
147 static char *x_lastcp(void);
148 static void do_complete(int, Comp_type
);
149 static int isu8cont(unsigned char);
151 /* proto's for keybindings */
152 static int x_abort(int);
153 static int x_beg_hist(int);
154 static int x_clear_screen(int);
155 static int x_comp_comm(int);
156 static int x_comp_file(int);
157 static int x_complete(int);
158 static int x_del_back(int);
159 static int x_del_bword(int);
160 static int x_del_char(int);
161 static int x_del_fword(int);
162 static int x_del_line(int);
163 static int x_draw_line(int);
164 static int x_end_hist(int);
165 static int x_end_of_text(int);
166 static int x_enumerate(int);
167 static int x_eot_del(int);
168 static int x_error(int);
169 static int x_goto_hist(int);
170 static int x_ins_string(int);
171 static int x_insert(int);
172 static int x_kill(int);
173 static int x_kill_region(int);
174 static int x_list_comm(int);
175 static int x_list_file(int);
176 static int x_literal(int);
177 static int x_meta_yank(int);
178 static int x_mv_back(int);
179 static int x_mv_begin(int);
180 static int x_mv_bword(int);
181 static int x_mv_end(int);
182 static int x_mv_forw(int);
183 static int x_mv_fword(int);
184 static int x_newline(int);
185 static int x_next_com(int);
186 static int x_nl_next_com(int);
187 static int x_noop(int);
188 static int x_prev_com(int);
189 static int x_prev_histword(int);
190 static int x_search_char_forw(int);
191 static int x_search_char_back(int);
192 static int x_search_hist(int);
193 static int x_set_mark(int);
194 static int x_transpose(int);
195 static int x_xchg_point_mark(int);
196 static int x_yank(int);
197 static int x_comp_list(int);
198 static int x_expand(int);
199 static int x_fold_capitalize(int);
200 static int x_fold_lower(int);
201 static int x_fold_upper(int);
202 static int x_set_arg(int);
203 static int x_comment(int);
205 static int x_debug_info(int);
208 static const struct x_ftab x_ftab
[] = {
209 { x_abort
, "abort", 0 },
210 { x_beg_hist
, "beginning-of-history", 0 },
211 { x_clear_screen
, "clear-screen", 0 },
212 { x_comp_comm
, "complete-command", 0 },
213 { x_comp_file
, "complete-file", 0 },
214 { x_complete
, "complete", 0 },
215 { x_del_back
, "delete-char-backward", XF_ARG
},
216 { x_del_bword
, "delete-word-backward", XF_ARG
},
217 { x_del_char
, "delete-char-forward", XF_ARG
},
218 { x_del_fword
, "delete-word-forward", XF_ARG
},
219 { x_del_line
, "kill-line", 0 },
220 { x_draw_line
, "redraw", 0 },
221 { x_end_hist
, "end-of-history", 0 },
222 { x_end_of_text
, "eot", 0 },
223 { x_enumerate
, "list", 0 },
224 { x_eot_del
, "eot-or-delete", XF_ARG
},
225 { x_error
, "error", 0 },
226 { x_goto_hist
, "goto-history", XF_ARG
},
227 { x_ins_string
, "macro-string", XF_NOBIND
},
228 { x_insert
, "auto-insert", XF_ARG
},
229 { x_kill
, "kill-to-eol", XF_ARG
},
230 { x_kill_region
, "kill-region", 0 },
231 { x_list_comm
, "list-command", 0 },
232 { x_list_file
, "list-file", 0 },
233 { x_literal
, "quote", 0 },
234 { x_meta_yank
, "yank-pop", 0 },
235 { x_mv_back
, "backward-char", XF_ARG
},
236 { x_mv_begin
, "beginning-of-line", 0 },
237 { x_mv_bword
, "backward-word", XF_ARG
},
238 { x_mv_end
, "end-of-line", 0 },
239 { x_mv_forw
, "forward-char", XF_ARG
},
240 { x_mv_fword
, "forward-word", XF_ARG
},
241 { x_newline
, "newline", 0 },
242 { x_next_com
, "down-history", XF_ARG
},
243 { x_nl_next_com
, "newline-and-next", 0 },
244 { x_noop
, "no-op", 0 },
245 { x_prev_com
, "up-history", XF_ARG
},
246 { x_prev_histword
, "prev-hist-word", XF_ARG
},
247 { x_search_char_forw
, "search-character-forward", XF_ARG
},
248 { x_search_char_back
, "search-character-backward", XF_ARG
},
249 { x_search_hist
, "search-history", 0 },
250 { x_set_mark
, "set-mark-command", 0 },
251 { x_transpose
, "transpose-chars", 0 },
252 { x_xchg_point_mark
, "exchange-point-and-mark", 0 },
253 { x_yank
, "yank", 0 },
254 { x_comp_list
, "complete-list", 0 },
255 { x_expand
, "expand-file", 0 },
256 { x_fold_capitalize
, "capitalize-word", XF_ARG
},
257 { x_fold_lower
, "downcase-word", XF_ARG
},
258 { x_fold_upper
, "upcase-word", XF_ARG
},
259 { x_set_arg
, "set-arg", XF_NOBIND
},
260 { x_comment
, "comment", 0 },
263 { x_debug_info
, "debug-info", 0 },
271 isu8cont(unsigned char c
)
273 return (c
& (0x80 | 0x40)) == 0x80;
277 x_emacs(char *buf
, size_t len
)
279 struct kb_entry
*k
, *kmatch
= NULL
;
281 int at
= 0, ntries
= 0, submatch
, ret
;
284 xbp
= xbuf
= buf
; xend
= buf
+ len
;
285 xlp
= xcp
= xep
= buf
;
289 x_histp
= histptr
+ 1;
292 x_col
= promptlen(prompt
, &p
);
293 prompt_skip
= p
- prompt
;
297 x_col
= x_col
- (x_col
/ xx_cols
) * xx_cols
;
298 x_displen
= xx_cols
- 2 - x_col
;
304 x_displen
= xx_cols
- 2;
309 if (x_nextcmd
>= 0) {
310 int off
= source
->line
- x_nextcmd
;
311 if (histptr
- history
>= off
)
312 x_load_hist(histptr
- off
);
318 x_last_command
= NULL
;
321 if ((at
= x_e_getu8(line
, at
)) < 0)
331 /* literal, so insert it */
337 TAILQ_FOREACH(k
, &kblist
, entry
) {
341 if (memcmp(k
->seq
, line
, at
) == 0) {
348 /* see if we can abort search early */
354 if (submatch
== 1 && kmatch
) {
355 if (kmatch
->ftab
->xf_func
== x_ins_string
&&
356 kmatch
->args
&& !macro_args
) {
357 /* treat macro string as input */
358 macro_args
= kmatch
->args
;
361 ret
= kmatch
->ftab
->xf_func(line
[at
- 1]);
366 ret
= x_error(0); /* unmatched meta sequence */
371 ret
= x_insert(line
[0]);
378 x_last_command
= kmatch
->ftab
->xf_func
;
380 x_last_command
= NULL
;
393 bi_errorf("invalid return code"); /* can't happen */
396 /* reset meta sequence */
399 x_arg_set
= 0; /* reset args next time around */
411 * Should allow tab and control chars.
431 x_do_ins(const char *cp
, size_t len
)
433 if (xep
+len
>= xend
) {
438 memmove(xcp
+len
, xcp
, xep
- xcp
+ 1);
439 memmove(xcp
, cp
, len
);
449 int adj
= x_adj_done
;
451 if (x_do_ins(s
, strlen(s
)) < 0)
454 * x_zots() may result in a call to x_adjust()
455 * we want xcp to reflect the new position.
459 x_adj_ok
= (xcp
>= xlp
);
461 if (adj
== x_adj_done
) { /* has x_adjust() been called? */
463 for (cp
= xlp
; cp
> xcp
; )
474 int col
= xcp
- xbuf
;
482 while (x_arg
< col
&& isu8cont(xcp
[-x_arg
]))
485 x_delete(x_arg
, false);
492 int nleft
= xep
- xcp
;
500 while (x_arg
< nleft
&& isu8cont(xcp
[x_arg
]))
502 x_delete(x_arg
, false);
506 /* Delete nc bytes to the right of the cursor (including cursor position) */
508 x_delete(int nc
, int push
)
515 if (xmp
!= NULL
&& xmp
> xcp
) {
523 * This lets us yank a word we have deleted.
533 j
+= x_size((unsigned char)*cp
++);
535 memmove(xcp
, xcp
+nc
, xep
- xcp
+ 1); /* Copies the null */
536 x_adj_ok
= 0; /* don't redraw */
540 * if we are already filling the line,
541 * there is no need to ' ','\b'.
542 * But if we must, make sure we do the minimum.
544 if ((i
= xx_cols
- 2 - x_col
) > 0) {
556 for (cp
= x_lastcp(); cp
> xcp
; )
565 x_delete(x_bword(), true);
579 x_goto(xcp
+ x_fword());
586 x_delete(x_fword(), true);
601 while (cp
!= xbuf
&& is_mfs(cp
[-1])) {
605 while (cp
!= xbuf
&& !is_mfs(cp
[-1])) {
625 while (cp
!= xep
&& is_mfs(*cp
)) {
629 while (cp
!= xep
&& !is_mfs(*cp
)) {
640 if (cp
< xbp
|| cp
>= (xbp
+ x_displen
)) {
641 /* we are heading off screen */
644 } else if (cp
< xcp
) { /* move back */
646 x_bs((unsigned char)*--xcp
);
647 } else if (cp
> xcp
) { /* move forward */
649 x_zotc((unsigned char)*xcp
++);
668 size
+= x_size(*cp
++);
676 return 4; /* Kludge, tabs are always four spaces. */
677 if (iscntrl(c
)) /* control char */
687 int adj
= x_adj_done
;
689 if (str
> xbuf
&& isu8cont(*str
)) {
690 while (str
> xbuf
&& isu8cont(*str
))
695 while (*str
&& str
< xlp
&& adj
== x_adj_done
)
703 /* Kludge, tabs are always four spaces. */
705 } else if (iscntrl(c
)) {
715 int col
= xcp
- xbuf
;
723 while (x_arg
< col
&& isu8cont(xcp
[-x_arg
]))
732 int nleft
= xep
- xcp
;
740 while (x_arg
< nleft
&& isu8cont(xcp
[x_arg
]))
747 x_search_char_forw(int c
)
755 ((cp
= (cp
== xep
) ? NULL
: strchr(cp
+ 1, c
)) == NULL
&&
756 (cp
= strchr(xbuf
, c
)) == NULL
)) {
766 x_search_char_back(int c
)
771 for (; x_arg
--; cp
= p
)
775 if (c
< 0 || p
== cp
) {
806 static int x_beg_hist(int c
) { x_load_hist(history
); return KSTD
;}
808 static int x_end_hist(int c
) { x_load_hist(histptr
); return KSTD
;}
810 static int x_prev_com(int c
) { x_load_hist(x_histp
- x_arg
); return KSTD
;}
812 static int x_next_com(int c
) { x_load_hist(x_histp
+ x_arg
); return KSTD
;}
814 /* Goto a particular history number obtained from argument.
815 * If no argument is given history 1 is probably not what you
816 * want so we'll simply go to the oldest one.
822 x_load_hist(history
);
824 x_load_hist(histptr
+ x_arg
- source
->line
);
829 x_load_hist(char **hp
)
833 if (hp
< history
|| hp
> histptr
) {
838 oldsize
= x_size_str(xbuf
);
839 strlcpy(xbuf
, *hp
, xend
- xbuf
);
841 xep
= xcp
= xbuf
+ strlen(xbuf
);
843 if (xep
<= x_lastcp())
851 x_nextcmd
= source
->line
- (histptr
- x_histp
) + 1;
852 return (x_newline(c
));
858 if (xep
== xbuf
&& x_arg_defaulted
)
859 return (x_end_of_text(c
));
861 return (x_del_char(c
));
865 kb_find_hist_func(char c
)
872 TAILQ_FOREACH(k
, &kblist
, entry
)
873 if (!strcmp(k
->seq
, line
))
874 return (k
->ftab
->xf_func
);
879 /* reverse incremental history search */
883 int offset
= -1; /* offset of match in xbuf, else -1 */
884 char pat
[256+1]; /* pattern buffer */
891 x_e_puts("\nI-search: ");
895 if ((c
= x_e_getc()) < 0)
897 f
= kb_find_hist_func(c
);
898 if (c
== CTRL('[')) {
901 } else if (f
== x_search_hist
)
902 offset
= x_search(pat
, 0, offset
);
903 else if (f
== x_del_back
) {
913 offset
= x_search(pat
, 1, offset
);
915 } else if (f
== x_insert
) {
916 /* add char to pattern */
917 /* overflow check... */
918 if (p
>= &pat
[sizeof(pat
) - 1]) {
924 /* already have partial match */
925 offset
= x_match(xbuf
, pat
);
927 x_goto(xbuf
+ offset
+ (p
- pat
) -
932 offset
= x_search(pat
, 0, offset
);
933 } else { /* other command */
943 /* search backward from current line */
945 x_search(char *pat
, int sameline
, int offset
)
950 for (hp
= x_histp
- (sameline
? 0 : 1) ; hp
>= history
; --hp
) {
951 i
= x_match(*hp
, pat
);
956 x_goto(xbuf
+ i
+ strlen(pat
) - (*pat
== '^'));
965 /* return position of first match of pattern in string, else -1 */
967 x_match(char *str
, char *pat
)
970 return (strncmp(str
, pat
+1, strlen(pat
+1)) == 0) ? 0 : -1;
972 char *q
= strstr(str
, pat
);
973 return (q
== NULL
) ? -1 : q
- str
;
984 j
= x_size_str(xbuf
);
987 xlp
= xbp
= xep
= xbuf
;
1017 x_clear_screen(int c
)
1023 /* Redraw (part of) the line.
1024 * A non-negative limit is the screen column up to which needs
1025 * redrawing. A limit of -1 redraws on a new line, while a limit
1026 * of -2 (attempts to) clear the screen.
1031 int i
, j
, truncate
= 0;
1038 if (cur_term
!= NULL
&& clear_screen
!= NULL
) {
1039 if (tputs(clear_screen
, 1, x_putc
) != ERR
)
1046 else if (limit
== -1)
1048 else if (limit
>= 0)
1052 x_col
= promptlen(prompt
, NULL
);
1053 if (x_col
> xx_cols
)
1054 truncate
= (x_col
/ xx_cols
) * xx_cols
;
1056 pprompt(prompt
+ prompt_skip
, truncate
);
1058 if (x_col
> xx_cols
)
1059 x_col
= x_col
- (x_col
/ xx_cols
) * xx_cols
;
1060 x_displen
= xx_cols
- 2 - x_col
;
1061 if (x_displen
< 1) {
1063 x_displen
= xx_cols
- 2;
1068 if (xbp
!= xbuf
|| xep
> xlp
)
1072 i
= 0; /* we fill the line */
1074 i
= limit
- (xlp
- xbp
);
1076 for (j
= 0; j
< i
&& x_col
< (xx_cols
- 2); j
++)
1079 if (xep
> xlp
) { /* more off screen */
1084 } else if (xbp
> xbuf
)
1091 for (cp
= xlp
; cp
> xcp
; )
1105 /* What transpose is meant to do seems to be up for debate. This
1106 * is a general summary of the options; the text is abcd with the
1107 * upper case character or underscore indicating the cursor position:
1108 * Who Before After Before After
1109 * at&t ksh in emacs mode: abCd abdC abcd_ (bell)
1110 * at&t ksh in gmacs mode: abCd baCd abcd_ abdc_
1111 * gnu emacs: abCd acbD abcd_ abdc_
1112 * Pdksh currently goes with GNU behavior since I believe this is the
1113 * most common version of emacs, unless in gmacs mode, in which case
1114 * it does the at&t ksh gmacs mode.
1115 * This should really be broken up into 3 functions so users can bind
1116 * to the one they want.
1121 } else if (xcp
== xep
|| Flag(FGMACS
)) {
1122 if (xcp
- xbuf
== 1) {
1126 /* Gosling/Unipress emacs style: Swap two characters before the
1127 * cursor, do not change cursor position
1137 /* GNU emacs style: Swap the characters before and under the
1138 * cursor, move cursor position along one.
1162 int col
= xcp
- xbuf
;
1163 int lastcol
= xep
- xbuf
;
1166 if (x_arg_defaulted
)
1168 else if (x_arg
> lastcol
)
1170 while (x_arg
< lastcol
&& isu8cont(xbuf
[x_arg
]))
1174 x_goto(xbuf
+ x_arg
);
1177 x_delete(ndel
, true);
1184 char *cp
= str_nsave(xcp
, nchars
, AEDIT
);
1185 afree(killstack
[killsp
], AEDIT
);
1186 killstack
[killsp
] = cp
;
1187 killsp
= (killsp
+ 1) % KILLSIZE
;
1198 if (killstack
[killtp
] == 0) {
1199 x_e_puts("\nnothing to yank");
1204 x_ins(killstack
[killtp
]);
1212 if ((x_last_command
!= x_yank
&& x_last_command
!= x_meta_yank
) ||
1213 killstack
[killtp
] == 0) {
1215 x_e_puts("\nyank something first");
1219 len
= strlen(killstack
[killtp
]);
1221 x_delete(len
, false);
1224 killtp
= KILLSIZE
- 1;
1227 } while (killstack
[killtp
] == 0);
1228 x_ins(killstack
[killtp
]);
1236 xlp
= xep
= xcp
= xbp
= xbuf
;
1250 kb_encode(const char *s
)
1252 static char l
[LINE
+ 1];
1274 kb_decode(const char *s
)
1276 static char l
[LINE
+ 1];
1277 unsigned int i
, at
= 0;
1280 for (i
= 0; i
< strlen(s
); i
++) {
1281 if (iscntrl((unsigned char)s
[i
])) {
1283 l
[at
++] = UNCTRL(s
[i
]);
1295 int len
= strlen(s
);
1298 TAILQ_FOREACH(k
, &kblist
, entry
) {
1302 if (memcmp(k
->seq
, s
, len
) == 0)
1310 kb_del(struct kb_entry
*k
)
1312 TAILQ_REMOVE(&kblist
, k
, entry
);
1317 static struct kb_entry
*
1318 kb_add_string(void *func
, void *args
, char *str
)
1320 unsigned int ele
, count
;
1322 struct x_ftab
*xf
= NULL
;
1324 for (ele
= 0; ele
< NELEM(x_ftab
); ele
++)
1325 if (x_ftab
[ele
].xf_func
== func
) {
1326 xf
= (struct x_ftab
*)&x_ftab
[ele
];
1332 if (kb_match(str
)) {
1333 if (x_bind_quiet
== 0)
1334 bi_errorf("duplicate binding for %s", kb_decode(str
));
1337 count
= strlen(str
);
1339 k
= alloc(sizeof *k
+ count
+ 1, AEDIT
);
1340 k
->seq
= (unsigned char *)(k
+ 1);
1343 k
->args
= args
? strdup(args
) : NULL
;
1345 strlcpy(k
->seq
, str
, count
+ 1);
1347 TAILQ_INSERT_TAIL(&kblist
, k
, entry
);
1352 static struct kb_entry
*
1353 kb_add(void *func
, ...)
1358 char line
[LINE
+ 1];
1361 for (i
= 0; i
< sizeof(line
) - 1; i
++) {
1362 ch
= va_arg(ap
, unsigned int);
1370 return (kb_add_string(func
, NULL
, line
));
1374 kb_print(struct kb_entry
*k
)
1376 if (!(k
->ftab
->xf_flags
& XF_NOBIND
))
1377 shprintf("%s = %s\n",
1378 kb_decode(k
->seq
), k
->ftab
->xf_name
);
1380 shprintf("%s = ", kb_decode(k
->seq
));
1381 shprintf("'%s'\n", kb_decode(k
->args
));
1386 x_bind(const char *a1
, const char *a2
,
1387 int macro
, /* bind -m */
1388 int list
) /* bind -l */
1391 struct kb_entry
*k
, *kb
;
1395 bi_errorf("cannot bind, not a tty");
1400 /* show all function names */
1401 for (i
= 0; i
< NELEM(x_ftab
); i
++) {
1402 if (x_ftab
[i
].xf_name
== NULL
)
1404 if (x_ftab
[i
].xf_name
&&
1405 !(x_ftab
[i
].xf_flags
& XF_NOBIND
))
1406 shprintf("%s\n", x_ftab
[i
].xf_name
);
1412 /* show all bindings */
1413 TAILQ_FOREACH(k
, &kblist
, entry
)
1418 snprintf(in
, sizeof in
, "%s", kb_encode(a1
));
1421 TAILQ_FOREACH(k
, &kblist
, entry
)
1422 if (!strcmp(k
->seq
, in
)) {
1426 shprintf("%s = %s\n", kb_decode(a1
), "auto-insert");
1430 if (strlen(a2
) == 0) {
1432 TAILQ_FOREACH_SAFE(k
, &kblist
, entry
, kb
)
1433 if (!strcmp(k
->seq
, in
)) {
1442 /* delete old mapping */
1443 TAILQ_FOREACH_SAFE(k
, &kblist
, entry
, kb
)
1444 if (!strcmp(k
->seq
, in
)) {
1448 kb_add_string(x_ins_string
, kb_encode(a2
), in
);
1452 /* set non macro binding */
1453 for (i
= 0; i
< NELEM(x_ftab
); i
++) {
1454 if (x_ftab
[i
].xf_name
== NULL
)
1456 if (!strcmp(x_ftab
[i
].xf_name
, a2
)) {
1457 /* delete old mapping */
1458 TAILQ_FOREACH_SAFE(k
, &kblist
, entry
, kb
)
1459 if (!strcmp(k
->seq
, in
)) {
1463 kb_add_string(x_ftab
[i
].xf_func
, NULL
, in
);
1467 bi_errorf("%s: no such function", a2
);
1478 TAILQ_INIT(&kblist
);
1480 /* man page order */
1481 kb_add(x_abort
, CTRL('G'), 0);
1482 kb_add(x_mv_back
, CTRL('B'), 0);
1483 kb_add(x_mv_back
, CTRL('X'), CTRL('D'), 0);
1484 kb_add(x_mv_bword
, CTRL('['), 'b', 0);
1485 kb_add(x_beg_hist
, CTRL('['), '<', 0);
1486 kb_add(x_mv_begin
, CTRL('A'), 0);
1487 kb_add(x_fold_capitalize
, CTRL('['), 'C', 0);
1488 kb_add(x_fold_capitalize
, CTRL('['), 'c', 0);
1489 kb_add(x_comment
, CTRL('['), '#', 0);
1490 kb_add(x_complete
, CTRL('['), CTRL('['), 0);
1491 kb_add(x_comp_comm
, CTRL('X'), CTRL('['), 0);
1492 kb_add(x_comp_file
, CTRL('['), CTRL('X'), 0);
1493 kb_add(x_comp_list
, CTRL('I'), 0);
1494 kb_add(x_comp_list
, CTRL('['), '=', 0);
1495 kb_add(x_del_back
, CTRL('?'), 0);
1496 kb_add(x_del_back
, CTRL('H'), 0);
1497 kb_add(x_del_char
, CTRL('['), '[', '3', '~', 0); /* delete */
1498 kb_add(x_del_bword
, CTRL('W'), 0);
1499 kb_add(x_del_bword
, CTRL('['), CTRL('?'), 0);
1500 kb_add(x_del_bword
, CTRL('['), CTRL('H'), 0);
1501 kb_add(x_del_bword
, CTRL('['), 'h', 0);
1502 kb_add(x_del_fword
, CTRL('['), 'd', 0);
1503 kb_add(x_next_com
, CTRL('N'), 0);
1504 kb_add(x_next_com
, CTRL('X'), 'B', 0);
1505 kb_add(x_fold_lower
, CTRL('['), 'L', 0);
1506 kb_add(x_fold_lower
, CTRL('['), 'l', 0);
1507 kb_add(x_end_hist
, CTRL('['), '>', 0);
1508 kb_add(x_mv_end
, CTRL('E'), 0);
1509 /* how to handle: eot: ^_, underneath copied from original keybindings */
1510 kb_add(x_end_of_text
, CTRL('_'), 0);
1511 kb_add(x_eot_del
, CTRL('D'), 0);
1513 kb_add(x_xchg_point_mark
, CTRL('X'), CTRL('X'), 0);
1514 kb_add(x_expand
, CTRL('['), '*', 0);
1515 kb_add(x_mv_forw
, CTRL('F'), 0);
1516 kb_add(x_mv_forw
, CTRL('X'), 'C', 0);
1517 kb_add(x_mv_fword
, CTRL('['), 'f', 0);
1518 kb_add(x_goto_hist
, CTRL('['), 'g', 0);
1520 kb_add(x_kill
, CTRL('K'), 0);
1521 kb_add(x_enumerate
, CTRL('['), '?', 0);
1522 kb_add(x_list_comm
, CTRL('X'), '?', 0);
1523 kb_add(x_list_file
, CTRL('X'), CTRL('Y'), 0);
1524 kb_add(x_newline
, CTRL('J'), 0);
1525 kb_add(x_newline
, CTRL('M'), 0);
1526 kb_add(x_nl_next_com
, CTRL('O'), 0);
1528 kb_add(x_prev_histword
, CTRL('['), '.', 0);
1529 kb_add(x_prev_histword
, CTRL('['), '_', 0);
1530 /* how to handle: quote: ^^ */
1531 kb_add(x_literal
, CTRL('^'), 0);
1532 kb_add(x_draw_line
, CTRL('L'), 0);
1533 kb_add(x_search_char_back
, CTRL('['), CTRL(']'), 0);
1534 kb_add(x_search_char_forw
, CTRL(']'), 0);
1535 kb_add(x_search_hist
, CTRL('R'), 0);
1536 kb_add(x_set_mark
, CTRL('['), ' ', 0);
1537 kb_add(x_transpose
, CTRL('T'), 0);
1538 kb_add(x_prev_com
, CTRL('P'), 0);
1539 kb_add(x_prev_com
, CTRL('X'), 'A', 0);
1540 kb_add(x_fold_upper
, CTRL('['), 'U', 0);
1541 kb_add(x_fold_upper
, CTRL('['), 'u', 0);
1542 kb_add(x_literal
, CTRL('V'), 0);
1543 kb_add(x_yank
, CTRL('Y'), 0);
1544 kb_add(x_meta_yank
, CTRL('['), 'y', 0);
1545 /* man page ends here */
1548 kb_add(x_prev_com
, CTRL('['), '[', 'A', 0); /* up */
1549 kb_add(x_next_com
, CTRL('['), '[', 'B', 0); /* down */
1550 kb_add(x_mv_forw
, CTRL('['), '[', 'C', 0); /* right */
1551 kb_add(x_mv_back
, CTRL('['), '[', 'D', 0); /* left */
1552 kb_add(x_prev_com
, CTRL('['), 'O', 'A', 0); /* up */
1553 kb_add(x_next_com
, CTRL('['), 'O', 'B', 0); /* down */
1554 kb_add(x_mv_forw
, CTRL('['), 'O', 'C', 0); /* right */
1555 kb_add(x_mv_back
, CTRL('['), 'O', 'D', 0); /* left */
1557 /* more navigation keys */
1558 kb_add(x_mv_begin
, CTRL('['), '[', 'H', 0); /* home */
1559 kb_add(x_mv_end
, CTRL('['), '[', 'F', 0); /* end */
1560 kb_add(x_mv_begin
, CTRL('['), 'O', 'H', 0); /* home */
1561 kb_add(x_mv_end
, CTRL('['), 'O', 'F', 0); /* end */
1562 kb_add(x_mv_begin
, CTRL('['), '[', '1', '~', 0); /* home */
1563 kb_add(x_mv_end
, CTRL('['), '[', '4', '~', 0); /* end */
1564 kb_add(x_mv_begin
, CTRL('['), '[', '7', '~', 0); /* home */
1565 kb_add(x_mv_end
, CTRL('['), '[', '8', '~', 0); /* end */
1567 /* can't be bound */
1568 kb_add(x_set_arg
, CTRL('['), '0', 0);
1569 kb_add(x_set_arg
, CTRL('['), '1', 0);
1570 kb_add(x_set_arg
, CTRL('['), '2', 0);
1571 kb_add(x_set_arg
, CTRL('['), '3', 0);
1572 kb_add(x_set_arg
, CTRL('['), '4', 0);
1573 kb_add(x_set_arg
, CTRL('['), '5', 0);
1574 kb_add(x_set_arg
, CTRL('['), '6', 0);
1575 kb_add(x_set_arg
, CTRL('['), '7', 0);
1576 kb_add(x_set_arg
, CTRL('['), '8', 0);
1577 kb_add(x_set_arg
, CTRL('['), '9', 0);
1579 /* ctrl arrow keys */
1580 kb_add(x_mv_end
, CTRL('['), '[', '1', ';', '5', 'A', 0); /* ctrl up */
1581 kb_add(x_mv_begin
, CTRL('['), '[', '1', ';', '5', 'B', 0); /* ctrl down */
1582 kb_add(x_mv_fword
, CTRL('['), '[', '1', ';', '5', 'C', 0); /* ctrl right */
1583 kb_add(x_mv_bword
, CTRL('['), '[', '1', ';', '5', 'D', 0); /* ctrl left */
1587 x_emacs_keys(X_chars
*ec
)
1590 if (ec
->erase
>= 0) {
1591 kb_add(x_del_back
, ec
->erase
, 0);
1592 kb_add(x_del_bword
, CTRL('['), ec
->erase
, 0);
1595 kb_add(x_del_line
, ec
->kill
, 0);
1596 if (ec
->werase
>= 0)
1597 kb_add(x_del_bword
, ec
->werase
, 0);
1599 kb_add(x_abort
, ec
->intr
, 0);
1601 kb_add(x_noop
, ec
->quit
, 0);
1613 x_kill_region(int c
)
1630 x_delete(rsize
, true);
1636 x_xchg_point_mark(int c
)
1657 * File/command name completion routines
1663 do_complete(XCF_COMMAND
, CT_COMPLETE
);
1669 do_complete(XCF_COMMAND
, CT_LIST
);
1675 do_complete(XCF_COMMAND_FILE
, CT_COMPLETE
);
1681 do_complete(XCF_COMMAND_FILE
, CT_LIST
);
1687 do_complete(XCF_FILE
, CT_COMPLETE
);
1693 do_complete(XCF_FILE
, CT_LIST
);
1699 do_complete(XCF_COMMAND_FILE
, CT_COMPLIST
);
1711 nwords
= x_cf_glob(XCF_FILE
, xbuf
, xep
- xbuf
, xcp
- xbuf
,
1712 &start
, &end
, &words
, &is_command
);
1719 x_goto(xbuf
+ start
);
1720 x_delete(end
- start
, false);
1721 for (i
= 0; i
< nwords
;) {
1722 if (x_escape(words
[i
], strlen(words
[i
]), x_do_ins
) < 0 ||
1723 (++i
< nwords
&& x_ins(" ") < 0)) {
1733 /* type == 0 for list, 1 for complete and 2 for complete-list */
1735 do_complete(int flags
, /* XCF_{COMMAND,FILE,COMMAND_FILE} */
1740 int start
, end
, nlen
, olen
;
1744 nwords
= x_cf_glob(flags
, xbuf
, xep
- xbuf
, xcp
- xbuf
,
1745 &start
, &end
, &words
, &is_command
);
1752 if (type
== CT_LIST
) {
1753 x_print_expansions(nwords
, words
, is_command
);
1755 x_free_words(nwords
, words
);
1760 nlen
= x_longest_prefix(nwords
, words
);
1762 if (nwords
== 1 || nlen
> olen
) {
1763 x_goto(xbuf
+ start
);
1764 x_delete(olen
, false);
1765 x_escape(words
[0], nlen
, x_do_ins
);
1769 /* add space if single non-dir match */
1770 if (nwords
== 1 && words
[0][nlen
- 1] != '/') {
1775 if (type
== CT_COMPLIST
&& !completed
) {
1776 x_print_expansions(nwords
, words
, is_command
);
1783 x_free_words(nwords
, words
);
1787 * x_adjust - redraw the line adjusting starting point etc.
1790 * This function is called when we have exceeded the bounds
1791 * of the edit window. It increments x_adj_done so that
1792 * functions like x_ins and x_delete know that we have been
1793 * called and can skip the x_bs() stuff which has already
1794 * been done by x_redraw.
1803 x_adj_done
++; /* flag the fact that we were called. */
1805 * we had a problem if the prompt length > xx_cols / 2
1807 if ((xbp
= xcp
- (x_displen
/ 2)) < xbuf
)
1814 static int unget_char
= -1;
1827 if (unget_char
>= 0) {
1830 } else if (macro_args
) {
1843 x_e_getu8(char *buf
, int off
)
1854 else if ((c
& 0xf0) == 0xe0)
1856 else if ((c
& 0xe0) == 0xc0 && c
> 0xc1)
1861 for (; len
> 1; len
--) {
1865 if (isu8cont(cc
) == 0 ||
1866 (c
== 0xe0 && len
== 3 && cc
< 0xa0) ||
1867 (c
== 0xed && len
== 3 && cc
& 0x20) ||
1868 (c
== 0xf4 && len
== 4 && cc
& 0x30)) {
1882 if (c
== '\r' || c
== '\n')
1884 if (x_col
< xx_cols
) {
1901 if (x_adj_ok
&& (x_col
< 0 || x_col
>= (xx_cols
- 2)))
1910 shellf("\nksh debug:\n");
1911 shellf("\tx_col == %d,\t\tx_cols == %d,\tx_displen == %d\n",
1912 x_col
, xx_cols
, x_displen
);
1913 shellf("\txcp == 0x%lx,\txep == 0x%lx\n", (long) xcp
, (long) xep
);
1914 shellf("\txbp == 0x%lx,\txbuf == 0x%lx\n", (long) xbp
, (long) xbuf
);
1915 shellf("\txlp == 0x%lx\n", (long) xlp
);
1916 shellf("\txlp == 0x%lx\n", (long) x_lastcp());
1924 x_e_puts(const char *s
)
1926 int adj
= x_adj_done
;
1928 while (*s
&& adj
== x_adj_done
)
1933 * x_set_arg - set an arg value for next function
1936 * This is a simple implementation of M-[0-9].
1948 for (; c
>= 0 && isdigit(c
); c
= x_e_getc(), first
= 0)
1949 n
= n
* 10 + (c
- '0');
1950 if (c
< 0 || first
) {
1953 x_arg_defaulted
= 1;
1957 x_arg_defaulted
= 0;
1964 /* Comment or uncomment the current line. */
1968 int oldsize
= x_size_str(xbuf
);
1969 int len
= xep
- xbuf
;
1970 int ret
= x_do_comment(xbuf
, xend
- xbuf
, &len
);
1980 return x_newline('\n');
1987 * x_prev_histword - recover word from prev command
1990 * This function recovers the last word from the previous
1991 * command and inserts it into the current edit line. If a
1992 * numeric arg is supplied then the n'th word from the
1993 * start of the previous command is used.
2002 x_prev_histword(int c
)
2010 else if (x_arg_defaulted
) {
2011 rcp
= &cp
[strlen(cp
) - 1];
2013 * ignore white-space after the last word
2015 while (rcp
> cp
&& is_cfs(*rcp
))
2017 while (rcp
> cp
&& !is_cfs(*rcp
))
2025 * ignore white-space at start of line
2027 while (*rcp
&& is_cfs(*rcp
))
2029 while (x_arg
-- > 1) {
2030 while (*rcp
&& !is_cfs(*rcp
))
2032 while (*rcp
&& is_cfs(*rcp
))
2036 while (*rcp
&& !is_cfs(*rcp
))
2046 /* Uppercase N(1) words */
2050 return x_fold_case('U');
2053 /* Lowercase N(1) words */
2057 return x_fold_case('L');
2060 /* Lowercase N(1) words */
2062 x_fold_capitalize(int c
)
2064 return x_fold_case('C');
2068 * x_fold_case - convert word to UPPER/lower/Capital case
2071 * This function is used to implement M-U,M-u,M-L,M-l,M-C and M-c
2072 * to UPPER case, lower case or Capitalize words.
2089 * first skip over any white-space
2091 while (cp
!= xep
&& is_mfs(*cp
))
2094 * do the first char on its own since it may be
2095 * a different action than for the rest.
2098 if (c
== 'L') { /* lowercase */
2099 if (isupper((unsigned char)*cp
))
2100 *cp
= tolower((unsigned char)*cp
);
2101 } else { /* uppercase, capitalize */
2102 if (islower((unsigned char)*cp
))
2103 *cp
= toupper((unsigned char)*cp
);
2108 * now for the rest of the word
2110 while (cp
!= xep
&& !is_mfs(*cp
)) {
2111 if (c
== 'U') { /* uppercase */
2112 if (islower((unsigned char)*cp
))
2113 *cp
= toupper((unsigned char)*cp
);
2114 } else { /* lowercase, capitalize */
2115 if (isupper((unsigned char)*cp
))
2116 *cp
= tolower((unsigned char)*cp
);
2126 * x_lastcp - last visible byte
2132 * This function returns a pointer to that byte in the
2133 * edit buffer that will be the last displayed on the
2134 * screen. The sequence:
2136 * for (cp = x_lastcp(); cp > xcp; cp)
2139 * Will position the cursor correctly on the screen.
2152 for (i
= 0, rcp
= xbp
; rcp
< xep
&& i
< x_displen
; rcp
++)
2153 i
+= x_size((unsigned char)*rcp
);