1 /*
2 * input.c: does the actual input line stuff... keeps the appropriate stuff
3 * on the input line, handles insert/delete of characters/words... the whole
4 * ball o wax.
5 *
6 * Copyright (c) 1990 Michael Sandroff.
7 * Copyright (c) 1991, 1992 Troy Rollo.
8 * Copyright (c) 1992-1996 Matthew Green.
9 * Copyright 1999, 2015 EPIC Software Labs.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notices, the above paragraph (the one permitting redistribution),
19 * this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. The names of the author(s) may not be used to endorse or promote
22 * products derived from this software without specific prior written
23 * permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
26 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 */
37 /*
38 * This file has been mostly rewritten and reorganized by now. One of the
39 * things we can do now is have completely independant input lines on each
40 * screen, and there are really no global variables any more. A lot of the
41 * original code still lies about, as its still useful, but the macros have
42 * made the original code hard to distinguish.
43 */
44
45 #define __need_term_flush__
46 #include "irc.h"
47 #include "alias.h"
48 #include "clock.h"
49 #include "commands.h"
50 #include "exec.h"
51 #include "functions.h"
52 #include "hook.h"
53 #include "input.h"
54 #include "ircaux.h"
55 #include "keys.h"
56 #include "screen.h"
57 #include "server.h"
58 #include "status.h"
59 #include "termx.h"
60 #include "vars.h"
61 #include "window.h"
62 #include "output.h"
63 #include <sys/ioctl.h> /* XXX ugh */
64
65 /* used with input_move_cursor */
66 #define RIGHT 1
67 #define LEFT 0
68
69 static int input_move_cursor (int dir, int refresh);
70
71 /*
72 * This is how close you have to be to the edge of the screen before the
73 * input line scrolls to the adjacent zone. A detailed discussion of zones
74 * can be found below.
75 */
76 const int WIDTH = 10;
77
78 /*
79 * input_prompt: This is the global default for the raw, unexpanded
80 * input prompt for all input lines, as determined by /set input_prompt.
81 */
82 static char * input_prompt;
83
84 /*
85 * These are sanity macros. The file was completely unreadable before
86 * I put these in here. I make no apologies for them.
87 *
88 * current_screen The screen we are working on
89 * INPUT_BUFFER The input buffer for the screen we are working on.
90 * LOGICAL_CHARS
91 * LOGICAL_COLUMN
92 * START
93 * LOGICAL_CURSOR
94 * LOGICAL_LOCATION
95 * NEXT_LOGICAL_LOCATION
96 * PREV_LOGICAL_LOCATION
97 * CURSOR_SPOT
98 * NEXT_SPOT
99 * PREV_SPOT
100 * PHYSICAL_CURSOR The column the physical cursor is in
101 * THIS_CHAR
102 * PREV_CHAR
103 * NEXT_CHAR
104 * ADD_TO_INPUT
105 * CURSOR_RIGHT
106 * CURSOR_LEFT
107 * INPUT_PROMPT The normalized expanded value of 'input_prompt'.
108 * INPUT_PROMPT_LEN How many columns INPUT_PROMPT takes.
109 * IND_LEFT
110 * IND_LEFT_LEN
111 * IND_RIGHT
112 * IND_RIGHT_LEN
113 * INPUT_LINE The line on the terminal where the input line is.
114 * CUT_BUFFER The saved cut buffer (for deletes)
115 */
116
117 #define current_screen last_input_screen
118
119 /*
120 * This is a UTF8 C string containing the input line.
121 * Although ultimately this is the master reference copy of the input line,
122 * any time you change stuff in it, you need to call retokenize_input_line()
123 * to refresh the metadata and update_input() to refresh the screen.
124 */
125 #define INPUT_BUFFER current_screen->il->input_buffer
126
127 /*
128 * A "LOGICAL CHARACTER" is one or more unicode code points that represent
129 * a single glyph to the user. A glyph might take up 1 or 2 columns.
130 * A glyph might require multiple code points if the system uses continuation
131 * characters (Mac OS X) instead of composed characters (everybody else)
132 *
133 * When the user hits <backspace> they expect the previous glyph to be deleted,
134 * which might be a surprisingly complicated thing to determine.
135 *
136 * Therefore, each glyph is associated with metadata pointing at INPUT_BUFFER
137 *
138 * logical_chars[n] This glyph is stored in UTF8 at
139 * input_buffer + logical_chars[n]
140 * logical_location[n] This glyph starts at column <X>
141 * when you count all logical columns in the
142 * input line starting from 0.
143 * first_display_glyph The first logical character that is currently
144 * visible on the screen.
145 *
146 */
147 #define LOGICAL_CHARS current_screen->il->logical_chars
148 #define LOGICAL_COLUMN current_screen->il->logical_columns
149 #define START current_screen->il->first_display_char
150 #define MAXCOLS current_screen->il->number_of_logical_chars
151
152 /*
153 * The "LOGICAL CURSOR" is wherever the input point is. Most of the
154 * time it is at the end (pointing at the NUL at the end of INPUT_BUFFER)
155 * but it can point at any glyph. We always keep the physical cursor on
156 * top of the logical cursor.
157 */
158 #define LOGICAL_CURSOR current_screen->il->logical_cursor
159
160 /* This is the offset into INPUT_BUFFER where the logical cursor starts */
161 #define LOGICAL_LOCATION LOGICAL_CHARS[LOGICAL_CURSOR]
162
163 /*
164 * This is the offset into INPUT_BUFFER where the character after the
165 * logical cursor starts. Note that continuation characters mean that
166 * this spot may be several code points away! That's why we tokenize
167 * the input and keep these in arrays.
168 */
169 #define NEXT_LOGICAL_LOCATION LOGICAL_CHARS[LOGICAL_CURSOR + 1]
170 #define PREV_LOGICAL_LOCATION LOGICAL_CHARS[LOGICAL_CURSOR - 1]
171
172 /*
173 * These are (char *) pointers to where the input cursor currently lives.
174 * (and the next glyph, and the previous glyph)
175 * IN THEORY you could operate on the input buffer by doing string things
176 * on this pointer. BE VERY CAREFUL YOU DON'T SCREW IT UP!
177 *
178 * IF YOU CHANGE THE INPUT BUFFER YOU _MUST_ CALL retokenize_input()
179 * AND YOU _MUST_ CALL update_input()!
180 */
181 #define CURSOR_SPOT (INPUT_BUFFER + LOGICAL_LOCATION)
182 #define NEXT_SPOT (INPUT_BUFFER + NEXT_LOGICAL_LOCATION)
183 #define PREV_SPOT (INPUT_BUFFER + PREV_LOGICAL_LOCATION)
184
185 /*
186 * The physical cursor is the distance of the logical cursor from whatever
187 * glyph is "first", plus the input prompt plus the left indicator.
188 */
189 #define PHYSICAL_CURSOR LOGICAL_COLUMN[LOGICAL_CURSOR] - LOGICAL_COLUMN[START] + INPUT_PROMPT_LEN + (START != 0 ? IND_LEFT_LEN : 0)
190
191 /*
192 * This returns the FIRST CODE POINT of the character under the cursor.
193 * This is suitable for checking if it's a space or an alphanumeric or
194 * to see how many columns this glyph takes up, that kind of stuff...
195 * But it isn't suitable for actually copying stuff around!
196 * This is an rvalue on purpose to keep you from assigning to it.
197 */
198 #define THIS_CHAR grab_codepoint(CURSOR_SPOT)
199 #define PREV_CHAR grab_codepoint(PREV_SPOT)
200 #define NEXT_CHAR grab_codepoint(NEXT_SPOT)
201
202
203 /*
204 * Add a byte to the end of the input line.
205 * You should have done *CURSOR_SPOT = 0, if you're modifying
206 * the middle of the input buffer.
207 * You should have done something "CURSOR_SPOT" -- ie, move it to the
208 * cut buffer or saved it to a local string, so you can add it back.
209 *
210 * AFTER YOU CALL ADD_TO_INPUT() YOU _MUST_ CALL retokenize_input().
211 * AND YOU _MUST_ CALL update_input()!
212 */
213 #define ADD_TO_INPUT(x) strlcat(INPUT_BUFFER, (x), sizeof INPUT_BUFFER);
214
215 /*
216 * Moving the cursor is as easy as changing the logical cursor.
217 * HOWEVER IF YOU DO THIS YOU _MUST_ CALL update_input()!
218 * Update_input() is what updates the cursor on the user's screen.
219 */
220 #define CURSOR_RIGHT LOGICAL_CURSOR++
221 #define CURSOR_LEFT LOGICAL_CURSOR--
222
223
224 #define INPUT_PROMPT current_screen->il->input_prompt
225 #define INPUT_PROMPT_LEN current_screen->il->input_prompt_len
226
227 #define IND_LEFT current_screen->il->ind_left
228 #define IND_LEFT_LEN current_screen->il->ind_left_len
229
230 #define IND_RIGHT current_screen->il->ind_right
231 #define IND_RIGHT_LEN current_screen->il->ind_right_len
232
233 /*
234 * This is the physical line on the screen where the input line is.
235 * IE, if the terminal is 46 lines tall, then this is 46.
236 */
237 #define INPUT_LINE current_screen->il->input_line
238 #define CUT_BUFFER cut_buffer
239
240
BUILT_IN_KEYBINDING(debug_input_line)241 BUILT_IN_KEYBINDING(debug_input_line)
242 {
243 int i;
244 char *s;
245 int offset, column;
246 int codepoint;
247 char buffer[2048];
248 char byte[8];
249
250 *buffer = 0;
251 for (i = 0; i < INPUT_BUFFER_SIZE; i++)
252 {
253 snprintf(byte, sizeof(byte), "%X", INPUT_BUFFER[i]);
254 strlcat(buffer, " ", sizeof(buffer));
255 strlcat(buffer, byte, sizeof(buffer));
256 if (INPUT_BUFFER[i] == 0)
257 break;
258 }
259
260 yell("INPUT LINE is: %s [%s]", INPUT_BUFFER, buffer);
261
262 for (i = 0; i < INPUT_BUFFER_SIZE; i++)
263 {
264 offset = LOGICAL_CHARS[i];
265 column = LOGICAL_COLUMN[i];
266 codepoint = grab_codepoint(INPUT_BUFFER + offset);
267
268 if (i == START)
269 yell("LC %02d: START OF DISPLAY HERE", i);
270 yell("LC %02d: Offset %d, Columns %d, Codepoint %x",
271 i, offset, column, codepoint);
272 if (i == LOGICAL_CURSOR)
273 yell("LC %02d: CURSOR HERE", i);
274 if (codepoint == 0)
275 {
276 yell("LC %02d: END HERE", i);
277 break;
278 }
279 }
280
281 yell("PHYSICAL CURSOR AT %d %d", PHYSICAL_CURSOR, INPUT_LINE);
282 }
283
cursor_position(void * vp)284 int cursor_position (void *vp)
285 {
286 Screen *s = (Screen *)vp;
287 if (!s)
288 return -1;
289
290 /*
291 * This used to return a byte offset into the input line,
292 * because of $mid() and stuff. But now that those funcs
293 * are all utf8 aware, we want to actually return the logical
294 * character itself.
295 */
296 /*return s->il->logical_chars[s->il->logical_cursor]; */
297 return s->il->logical_cursor;
298 }
299
300 #define LOGICAL_LOCATION LOGICAL_CHARS[LOGICAL_CURSOR]
301
302 /* XXXX Only used here anyhow XXXX */
303 /*
304 * safe_puts -- output only 'numcols' columns of bytes from 'str'.
305 *
306 * Arguments:
307 * str - A string to output
308 * numcols - The maximum number of columns to output
309 */
safe_puts(const unsigned char * str,int numcols)310 static int safe_puts (const unsigned char *str, int numcols)
311 {
312 int i = 0;
313 const unsigned char *s, *x;
314 unsigned char utf8str[8];
315 int code_point;
316 int cols;
317 int allow_c1_chars = -1;
318
319 s = str;
320 while ((code_point = next_code_point(&s, 1)))
321 {
322 /* C1 chars have to be checked */
323 if (code_point >= 0x80 && code_point <= 0x9F)
324 {
325 if (allow_c1_chars == -1)
326 allow_c1_chars = get_int_var(ALLOW_C1_CHARS_VAR);
327
328 /* We don't output C1 chars */
329 if (!allow_c1_chars)
330 continue;
331 }
332
333 if ((cols = codepoint_numcolumns(code_point)) == -1)
334 cols = 1;
335
336 if (i + cols > numcols)
337 break;
338
339 /* Convert code_point from utf8 to users encoding */
340 ucs_to_console(code_point, utf8str, sizeof(utf8str));
341
342 for (x = utf8str; *x; x++)
343 term_inputline_putchar(*x);
344
345 i += cols;
346 }
347
348 return i;
349 }
350
351 /* cursor_to_input: move the cursor to the input line, if not there already */
cursor_to_input(void)352 void cursor_to_input (void)
353 {
354 Screen *oldscreen = last_input_screen;
355 Screen *screen;
356 static int recursive = 0;
357
358 if (recursive)
359 return;
360
361 if (!foreground)
362 return; /* Dont bother */
363
364 recursive = 1;
365 for (screen = screen_list; screen; screen = screen->next)
366 {
367 if (screen->alive)
368 {
369 output_screen = screen;
370 last_input_screen = screen;
371 /*yell("moving cursor to %d %d", PHYSICAL_CURSOR, INPUT_LINE); */
372 term_move_cursor(PHYSICAL_CURSOR, INPUT_LINE);
373 term_flush();
374 }
375 }
376 output_screen = last_input_screen = oldscreen;
377 recursive = 0;
378 }
379
380 /*
381 * This function populates the "logical_chars" and "logical_columns"
382 * arrays starting from the 'start'th logical char. If you want to
383 * redo the whole thing, then start should be 0.
384 *
385 * XXX For now, we ignore 'start' and always redo the whole thing.
386 */
retokenize_input(int start)387 static int retokenize_input (int start)
388 {
389 const unsigned char *s, *old_s;
390 int cols;
391 int codepoint;
392 int current_column;
393
394 start = 0;
395 current_column = 0;
396 old_s = s = INPUT_BUFFER;
397
398 while (s && *s)
399 {
400 codepoint = next_code_point(&s, 1);
401 cols = codepoint_numcolumns(codepoint);
402 /* Invalid chars are probably highlights */
403 if (cols == -1)
404 cols = 1;
405
406 if (cols == 0)
407 /* skip over continuation chars */;
408 else
409 {
410 LOGICAL_CHARS[start] = old_s - INPUT_BUFFER;
411 LOGICAL_COLUMN[start] = current_column;
412
413 current_column += cols;
414 start++;
415 LOGICAL_CHARS[start] = 9999;
416 }
417 old_s = s;
418 }
419
420 /* Set down the null */
421 LOGICAL_CHARS[start] = s - INPUT_BUFFER;
422 LOGICAL_COLUMN[start] = current_column;
423 MAXCOLS = start;
424
425 while (++start < INPUT_BUFFER_SIZE)
426 {
427 LOGICAL_CHARS[start] = 9999;
428 LOGICAL_COLUMN[start] = 0;
429 start++;
430 }
431
432 return 0;
433 }
434
435
436 /*
437 * update_input: Refresh the input line so what is on screen agrees with
438 * what is in memory.
439 *
440 * The input line is operated on 'asynchronously' meaning you can perform
441 * many operations in a batch, and then call update_input() when you're
442 * done and it will sort out what the screen needs to look like.
443 *
444 * There are three broad types of changes you can make:
445 * 1. UPDATE_JUST_CURSOR - I moved the cursor, but didn't change anything
446 * 2. UPDATE_FROM_CURSOR - I changed something at or after the cursor
447 * 3. UPDATE_ALL - I changed something before the cursor, OR
448 * An external event happened that I think affects
449 * the input line (such as joining a channel)
450 *
451 * The results of these three are:
452 * UPDATE_ALL - The input line is re-compiled and unconditionally
453 * redrawn. This causes flicker, so we try to avoid
454 * doing this unnecessarily.
455 * UPDATE_FROM_CURSOR - The input line is re-compiled starting from
456 * the cursor and redrawn fromthe cursor
457 * UPDATE_JUST_CURSOR - The cursor is moved; nothing else is changed.
458 *
459 * In addition to all of the above, we always perform these checks:
460 * 1. Has the prompt changed?
461 * 2. Has the left indicator changed?
462 * 3. Has the right indicator changed?
463 * 4. Has the size of the screen changed?
464 * 5. Is the cursor too close to the left edge?
465 * 6. Is the cursor too close to the right edge?
466 * If any of these apply, a corrective measure is taken, and then the
467 * refresh is upgraded to UPDATE_ALL.
468 *
469 * Clear as mud?
470 */
update_input(void * which_screen,int update)471 void update_input (void *which_screen, int update)
472 {
473 char *ptr, *ptr_free;
474 int max;
475 const char * prompt;
476 int do_echo, old_do_echo;
477 Screen *os, *ns;
478 Window *saved_current_window;
479 int cols_used;
480 int original_update;
481 Screen *oos;
482
483 /*
484 * No input line in dumb or bg mode.
485 */
486 if (dumb_mode || !foreground)
487 return;
488
489 /* Save the state of things */
490 os = last_input_screen;
491 saved_current_window = current_window;
492 original_update = update;
493 oos = output_screen;
494
495 for (ns = screen_list; ns; ns = ns->next)
496 {
497
498 /* <<<< INDENTED BACK ONE TAB FOR MY SANITY <<<<< */
499 /* XXX This is an ugly way to do this. */
500 if (which_screen && (Screen *)which_screen != ns)
501 continue; /* Only update this screen */
502
503 /* Ignore inactive screens. */
504 if (!ns->alive)
505 continue;
506
507 /* XXX The (mis)use of last_input_screen is lamentable */
508 last_input_screen = ns;
509 output_screen = ns;
510 current_window = ns->current_window;
511 update = original_update;
512 do_echo = last_input_screen->il->echo;
513
514 /*
515 * FIRST OFF -- Recalculate the metadata
516 * 1. Has the raw prompt changed?
517 * 2. Has the resulting expanded prompt changed?
518 * 3. Has the resulting expanded left indicator changed?
519 * 4. Has the resulting expanded right indicator changed?
520 * 5. Has the size of the screen changed?
521 *
522 * If any of these four are true, we must regenerate zones
523 * We know which logical cursor the cursor sits on, we just
524 * have to figure out where that lives
525 *
526 *
527 * THE CHEATERS GUIDE TO ZONES
528 * I thought it would be easy to just calculate the 'zone' that
529 * every logical character would be in, but there are three
530 * complications:
531 * 1. Changing between zones doesn't happen very much
532 * 2. The size of zones can change frequently (prompt/indicators)
533 * 3. The condition required to switch zones is easily described
534 *
535 * WHEN TO SWITCH ZONES:
536 * Let X be the first logical character being displayed (saved)
537 * Let Y be the width of the scrollable zone (saved/calculated)
538 * Y = WIDTH OF SCREEN
539 * Y -= WIDTH OF PROMPT
540 * IF X > 0
541 * Y -= WIDTH OF LEFT INDICATOR
542 * END IF
543 * IF character under (X + Y)
544 * Y -= WIDTH OF RIGHT INDICATOR
545 * END IF
546 *
547 * The cursor is allowed to be within (X + 10) and (Y - 10),
548 * with the exception of X = 0, then (X) and (Y - 10).
549 * This means the typable area is either (Y - 10) the first zone
550 * or (Y - 20) other zones).
551 *
552 * Therefore, given a logical cursor position, we can calculate
553 * a new X.
554 *
555 * # CALCULATE NEW X
556 * IF logical_column(CURRENT) < Y - 10
557 * LET new X = 0
558 * ELSE IF X > 0 AND distance(lc(X), lc(CURRENT)) < 10)
559 * # SHIFT LEFT
560 * LET new X = Z : distance(lc(X), lc(Z)) = Y
561 * IF new X < 0
562 * new X = 0
563 * END
564 * ELSE IF distance(CURRENT, Y) < 10
565 * # SHIFT RIGHT
566 * IF X = 0
567 * LET new X = Y - 20
568 * ELSE
569 * LET new X = X + Y
570 * END
571 * END
572 *
573 *
574 * Thus, after moving the cursor, we must recalculate all of the
575 * above things. Moving the cursor could be a cursor press, but
576 * also typing.
577 *
578 * After the new X is calculated, if it is different from the old X,
579 * then the input line must be completely redrawn.
580 *
581 * Redrawing the input line involves
582 * 1. Determining where the first byte lives
583 * 2. Determining which column the first byte lives
584 * 3. Determining how many bytes must be output
585 * 4. Determining which column the cursor goes into
586 */
587
588
589 /*
590 * Now we need to retokenize the input.
591 * UPDATE will tell us where to start from (from the cursor or all)
592 * Walk the input buffer, and make a note of the byte offset where
593 * each column begins
594 */
595
596 /*
597 * The input line is a utf8 C string
598 * Decomposed into a sequence of LOGICAL CHARACTERS
599 * Which are composed of ONE OR MORE UNICODE CODE POINTS
600 * Which take up ZERO OR MORE COLUMNS
601 *
602 * char *input_line[] The UTF8 C string
603 * int logical_chars[] Logical chars -> input_line[x]
604 * int logical_column[] Logical chars -> Logical column
605 * int logical_zone[] Logical chars -> zone
606 *
607 * A "zone" is a segment of the input line that is displayed
608 * at once. When you move the cursor to an adjacent "zone" then
609 * the input line is completely redrawn. Zones are numbered from 0.
610 * Zone 0 contains the start of the input line. the final zone
611 * is whatever zone contains the terminal nul.
612 *
613 * WHAT IS DISPLAYED:
614 * [prompt] [left indicator^] [spill-over from zone N-1]
615 * [zone N]
616 * [spill-over from zone-N] [right indicator^^]
617 * ^ [Left Indicator] is not shown for segment 0, which means
618 * zone 0 is longer than other zones.
619 * ^^ [Right Indicator] is not shown for the final zone.
620 */
621
622 /*
623 * No matter what happens, we check the input prompt, the left
624 * and right indicators. XXX Sigh! This is too expensive!
625 * If anything changes, we upgrade to "UPDATE_ALL".
626 */
627
628 /*
629 * If the current window is query'ing an exec'd process,
630 * then we just get the current prompt for that process.
631 * This hardly ever happens, so we malloc() this to make
632 * the code below much simpler.
633 */
634 if (last_input_screen->il->input_prompt_raw)
635 prompt = last_input_screen->il->input_prompt_raw;
636 else if (is_valid_process(get_target_by_refnum(0)))
637 prompt = get_prompt_by_refnum(0);
638 else
639 prompt = input_prompt;
640
641 ptr_free = expand_alias(prompt, empty_string);
642 ptr = new_normalize_string(ptr_free, 0, display_line_mangler);
643 new_free(&ptr_free);
644
645 /*
646 * If the prompt has changed, update the screen, and count
647 * the number of columns the new prompt takes up. If the
648 * prompt changes, we have to redraw the entire input line
649 * from scratch (since stuff probably has moved)
650 */
651 if (strcmp(ptr, INPUT_PROMPT))
652 {
653 malloc_strcpy((char **)&INPUT_PROMPT, ptr);
654 INPUT_PROMPT_LEN = output_with_count(INPUT_PROMPT, 0, 0);
655 update = UPDATE_ALL;
656 }
657
658 new_free(&ptr);
659
660 ptr_free = expand_alias(get_string_var(INPUT_INDICATOR_LEFT_VAR),
661 empty_string);
662 ptr = new_normalize_string(ptr_free, 0, display_line_mangler);
663 new_free(&ptr_free);
664
665 if (strcmp(ptr, IND_LEFT))
666 {
667 malloc_strcpy((char **)&IND_LEFT, ptr);
668 IND_LEFT_LEN = output_with_count(IND_LEFT, 0, 0);
669 update = UPDATE_ALL;
670 }
671
672 new_free(&ptr);
673
674 ptr_free = expand_alias(get_string_var(INPUT_INDICATOR_RIGHT_VAR),
675 empty_string);
676 ptr = new_normalize_string(ptr_free, 0, display_line_mangler);
677 new_free(&ptr_free);
678
679 if (strcmp(ptr, IND_RIGHT))
680 {
681 malloc_strcpy((char **)&IND_RIGHT, ptr);
682 IND_RIGHT_LEN = output_with_count(IND_RIGHT, 0, 0);
683 update = UPDATE_ALL;
684 }
685
686 new_free(&ptr);
687
688
689 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
690 /*
691 *
692 * HAS THE SCREEN CHANGED SIZE SINCE THE LAST TIME?
693 *
694 */
695
696 /*
697 * If the screen has resized, then we need to re-compute the
698 * side-to-side scrolling effect.
699 */
700 if ((last_input_screen->li != last_input_screen->old_li) ||
701 (last_input_screen->co != last_input_screen->old_co) ||
702 (INPUT_LINE != last_input_screen->li))
703 {
704 /*
705 * The input line is always the bottom line
706 */
707 INPUT_LINE = last_input_screen->li - 1;
708
709 last_input_screen->old_co = last_input_screen->co;
710 last_input_screen->old_li = last_input_screen->li;
711 }
712
713
714 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
715 /*
716 * IS THE CURSOR TOO NEAR THE LEFT OR RIGHT EDGE OF SCREEN?
717 *
718 * XXX This should not be done unconditionally.
719 */
720 if (1)
721 {
722 int targetcol;
723 int x;
724 int totalcols;
725 int zone0_overflow = 0;
726 int OLD_START = START;
727
728 /*
729 * Calculate the "zone" that the cursor is in.
730 *
731 * The challenge here is the physical screen is
732 * divided into three parts
733 *
734 * LEFT PART: Input Prompt
735 * Left Indicator (maybe)
736 * RIGHT PART: Right Indicator (maybe)
737 *
738 * The space for the input line is the width of the screen
739 * minus the size of those two parts. The "maybe" parts
740 * throw a monkey wrench since the space for the input line
741 * very much depends on where we are, and where we decide
742 * to put the START!
743 *
744 * As a nod to history, we try to make the zones symmetrical
745 * (ie, if you cursor right off the end of zone 0, you will
746 * be put in zone 1 in a place where if you do a cursor left
747 * you will go back to the end of zone 0); and that the zone
748 * you're in does not depend on where the cursor is.
749 *
750 * Width Zone 0 is columns - prompt - (right indicator)?
751 * Width Zone 1+ is columns - prompt - left indicator -
752 * (right indicator)?
753 *
754 * So the only question for Zone 0 is, is the width of the
755 * entire input line wider than columns - prompt?
756 *
757 */
758 totalcols = input_column_count(INPUT_BUFFER);
759 if (totalcols > last_input_screen->co - INPUT_PROMPT_LEN)
760 zone0_overflow = 1;
761
762 /*
763 * Is the cursor in zone 0?
764 */
765 if (LOGICAL_COLUMN[LOGICAL_CURSOR] <
766 last_input_screen->co -
767 INPUT_PROMPT_LEN -
768 WIDTH -
769 zone0_overflow * IND_RIGHT_LEN)
770 {
771 targetcol = 0;
772 }
773
774 /*
775 * Is the cursor in zone 1?
776 */
777 else
778 {
779 int zone0_length;
780 int net_columns;
781 int zone_length;
782 int zone;
783
784 /* We know how big zone 0 is */
785 zone0_length = last_input_screen->co -
786 INPUT_PROMPT_LEN -
787 WIDTH -
788 IND_RIGHT_LEN;
789
790 /*
791 * After we subtract zone0 (which is wider
792 * than the other columns, how many cols do
793 * we still have to account for?
794 */
795 net_columns = LOGICAL_COLUMN[LOGICAL_CURSOR] -
796 zone0_length;
797
798 /*
799 * Zones 1-N are the same width. Yes, I know
800 * that adding IND_RIGHT_LEN is cheating, but
801 * that's a very small thing. I think?
802 */
803 zone_length = last_input_screen->co -
804 INPUT_PROMPT_LEN -
805 WIDTH -
806 IND_LEFT_LEN -
807 IND_RIGHT_LEN;
808
809 /*
810 * Our new ZONE is rounded down from however
811 * many columns we have left by how many we can
812 * cram into every zone.
813 */
814 zone = net_columns / zone_length;
815
816 /*
817 * The new START is WIDTH chars before the
818 * start of the ZONE we are in (because you
819 * aren't permitted to cursor left to the
820 * WIDTH chars -- that takes you to the previous
821 * zone, got it?
822 */
823 targetcol = (zone0_length + zone * zone_length) - WIDTH;
824 }
825
826 for (x = 0; x <= LOGICAL_CURSOR; x++)
827 {
828 if (LOGICAL_COLUMN[x] >= targetcol)
829 {
830 START = x;
831 if (START != OLD_START)
832 update = UPDATE_ALL;
833 break;
834 }
835 }
836 }
837
838 /*
839 * OK. Now let's update the screen!
840 */
841 if (update == UPDATE_ALL)
842 {
843 /*
844 * Move the cursor to the start of the input line
845 */
846 term_move_cursor(0, INPUT_LINE);
847
848 /* Forcibly output the prompt */
849 old_do_echo = term_echo(1);
850
851 /*
852 * Figure out how many cols we will give to the
853 * prompt. If the prompt is too long, we will
854 * clobber it below. If the prompt won't fit, then
855 * we will clobber the whole thing.
856 */
857 if (START!=0)
858 cols_used = INPUT_PROMPT_LEN + IND_LEFT_LEN;
859 else
860 cols_used = INPUT_PROMPT_LEN;
861
862 if (cols_used > (last_input_screen->co - WIDTH))
863 {
864 cols_used = last_input_screen->co - WIDTH;
865 if (cols_used < 0)
866 cols_used = 0;
867 }
868
869 /* Only output the prompt if there's room for it. */
870 if (cols_used > 0)
871 output_with_count(INPUT_PROMPT, 0, 1);
872
873 if (START!=0)
874 output_with_count(IND_LEFT, 0, 1);
875
876 term_echo(old_do_echo);
877
878 /*
879 * Turn the echo back to what it was before,
880 * and output the rest of the input buffer.
881 */
882 term_echo(do_echo);
883
884 if (input_column_count(INPUT_BUFFER + LOGICAL_CHARS[START]) >
885 last_input_screen->co - cols_used)
886 {
887 cols_used += IND_RIGHT_LEN;
888 safe_puts(INPUT_BUFFER + LOGICAL_CHARS[START],
889 last_input_screen->co - cols_used);
890 output_with_count(IND_RIGHT, 0, 1);
891 }
892 else
893 safe_puts(INPUT_BUFFER + LOGICAL_CHARS[START],
894 last_input_screen->co - cols_used);
895
896 term_echo(old_do_echo);
897
898 /*
899 * Clear the rest of the input line and reset the cursor
900 * to the current input position.
901 */
902 term_clear_to_eol();
903 term_flush();
904 term_move_cursor(PHYSICAL_CURSOR, INPUT_LINE);
905 term_flush();
906 }
907
908 /*
909 * If we're just supposed to refresh whats to the right of the
910 * current logical position...
911 */
912 if (update == UPDATE_FROM_CURSOR)
913 {
914 /*
915 * Move the cursor to where its supposed to be,
916 * Figure out how much we can output from here,
917 * and then output it.
918 */
919 term_move_cursor(PHYSICAL_CURSOR, INPUT_LINE);
920 term_flush();
921 /* XXX 1 Col per byte assumption */
922
923 /* don't ask me why these needed to be split up */
924 max = last_input_screen->co;
925 max -= PHYSICAL_CURSOR;
926
927 old_do_echo = term_echo(do_echo);
928
929 if (input_column_count(INPUT_BUFFER + LOGICAL_LOCATION) > max)
930 {
931 max -= IND_RIGHT_LEN;
932 safe_puts(CURSOR_SPOT, max);
933 output_with_count(IND_RIGHT, 0, 1);
934 }
935 else
936 {
937 safe_puts(CURSOR_SPOT, max);
938 }
939
940 term_echo(old_do_echo);
941 term_clear_to_eol();
942 term_flush();
943 }
944
945 if (update == UPDATE_JUST_CURSOR)
946 {
947 term_move_cursor(PHYSICAL_CURSOR, INPUT_LINE);
948 term_flush();
949 }
950
951 /*
952 * Turn the terminal echo back on, and flush all of the output
953 * we may have done here.
954 */
955 term_echo(1);
956 term_flush();
957
958 /* <<<<< END INDENT ONE TAB BACK FOR MY SANITY <<<<<< */
959 }
960
961 output_screen = oos;
962 last_input_screen = os;
963 current_window = saved_current_window;
964 }
965
966
967 /*
968 * input_move_cursor -- Move the cursor LEFT or RIGHT.
969 *
970 * Arguments:
971 * dir - Must either be LEFT (-1) or RIGHT (1)
972 * refresh - 0 if you don't want me to call update_input.
973 * This might happen if you intend to call me multiple times.
974 * YOU ARE RESPONSIBLE FOR CALLING UPDATE_INPUT() AFTER YOU
975 * ARE DONE!
976 * 1 if I should call update_input
977 *
978 * Return value:
979 * 1 if I moved the logical cursor
980 * 0 if I didn't move the logical cursor (because i'm at the end already)
981 */
input_move_cursor(int direction,int refresh)982 static int input_move_cursor (int direction, int refresh)
983 {
984 int moved = 1;
985
986 if (direction == RIGHT)
987 {
988 /* Stop if we hit the end of the input line */
989 if (!THIS_CHAR)
990 return 0;
991
992 CURSOR_RIGHT;
993 }
994 else if (direction == LEFT)
995 {
996 /* Stop if we hit the start of the input line */
997 if (LOGICAL_CURSOR == 0)
998 return 0;
999
1000 CURSOR_LEFT;
1001 }
1002 else
1003 panic(1, "update_input_cursor not called with RIGHT or LEFT (%d)", direction);
1004
1005 if (refresh)
1006 update_input(last_input_screen, UPDATE_JUST_CURSOR);
1007 return moved;
1008 }
1009
1010 /*
1011 * set_input: sets the input buffer to the given string, discarding whatever
1012 * was in the input buffer before
1013 */
set_input(const char * str)1014 static void set_input (const char *str)
1015 {
1016 size_t len;
1017
1018 strlcpy(INPUT_BUFFER, str, INPUT_BUFFER_SIZE);
1019 START = 0;
1020 LOGICAL_CURSOR = 0;
1021
1022 retokenize_input(LOGICAL_CURSOR);
1023 while ((input_move_cursor(RIGHT, 0)))
1024 ;
1025 update_input(last_input_screen, UPDATE_ALL);
1026
1027 }
1028
1029 /*
1030 * get_input: returns a pointer to the input buffer. Changing this will
1031 * actually change the input buffer. This is a bad way to change the input
1032 * buffer tho, cause no bounds checking won't be done
1033 */
get_input(void)1034 char * get_input (void)
1035 {
1036 return INPUT_BUFFER;
1037 }
1038
1039 /* init_input: initialized the input buffer by clearing it out */
init_input(void)1040 void init_input (void)
1041 {
1042 *INPUT_BUFFER = 0;
1043 START = 0;
1044 LOGICAL_CURSOR = 0;
1045 memset(INPUT_BUFFER, 0, sizeof(INPUT_BUFFER));
1046 retokenize_input(LOGICAL_CURSOR);
1047 }
1048
1049 /*
1050 * set_input_prompt: sets a prompt that will be displayed in the input
1051 * buffer. This prompt cannot be backspaced over, etc. It's a prompt.
1052 * Setting the prompt to null uses no prompt
1053 */
set_input_prompt(void * stuff)1054 void set_input_prompt (void *stuff)
1055 {
1056 VARIABLE *v;
1057 const char *prompt;
1058
1059 v = (VARIABLE *)stuff;
1060 prompt = v->string;
1061
1062 if (prompt)
1063 malloc_strcpy(&input_prompt, prompt);
1064 else if (input_prompt)
1065 malloc_strcpy(&input_prompt, empty_string);
1066 else
1067 return;
1068
1069 update_input(NULL, UPDATE_ALL);
1070 }
1071
1072
1073 /* Please define 'spaces' as get_string_var(WORD_BREAK_VAR). */
1074 #define WHITESPACE(x) ((x < 127) && strchr(spaces, (x & 0x7F)) != NULL)
1075
1076 /*
1077 * Why did i put these in this file? I dunno. But i do know that the ones
1078 * in edit.c didnt have to be here, and i knew the ones that were here DID
1079 * have to be here, so i just moved them all to here, so that they would all
1080 * be in the same place. Easy enough. (jfn, june 1995)
1081 */
1082
1083 /*
1084 * input_forward_word: move the input cursor forward one word in the input
1085 * line
1086 */
1087
BUILT_IN_KEYBINDING(input_forward_word)1088 BUILT_IN_KEYBINDING(input_forward_word)
1089 {
1090 const char *spaces;
1091
1092 if (!(spaces = get_string_var(WORD_BREAK_VAR)))
1093 spaces = " \t";
1094
1095 cursor_to_input();
1096
1097 /* Move to the end of the current word to the whitespace */
1098 while (THIS_CHAR && !WHITESPACE(THIS_CHAR))
1099 input_move_cursor(RIGHT, 1);
1100
1101 /* Move past the whitespace to the start of the next word */
1102 while (THIS_CHAR && WHITESPACE(THIS_CHAR))
1103 input_move_cursor(RIGHT, 1);
1104 }
1105
1106 /* input_backward_word: move the cursor left on word in the input line */
BUILT_IN_KEYBINDING(input_backward_word)1107 BUILT_IN_KEYBINDING(input_backward_word)
1108 {
1109 const char *spaces;
1110
1111 if (!(spaces = get_string_var(WORD_BREAK_VAR)))
1112 spaces = " \t";
1113
1114 cursor_to_input();
1115
1116 /* If already at the start of a word, move back a position */
1117 if (LOGICAL_CURSOR > 0 && !WHITESPACE(THIS_CHAR) && WHITESPACE(PREV_CHAR))
1118 input_move_cursor(LEFT, 1);
1119
1120 /* Move to the start of the current whitespace */
1121 while (LOGICAL_CURSOR > 0 && WHITESPACE(THIS_CHAR))
1122 input_move_cursor(LEFT, 1);
1123
1124 /* Move to the start of the current word */
1125 while (LOGICAL_CURSOR > 0 && !WHITESPACE(THIS_CHAR))
1126 input_move_cursor(LEFT, 1);
1127
1128 /* If we overshot our goal, then move forward */
1129 /* But NOT if at start of input line! (July 6th, 1999) */
1130 if (LOGICAL_CURSOR > 0 && (THIS_CHAR) && WHITESPACE(THIS_CHAR))
1131 input_move_cursor(RIGHT, 1);
1132 }
1133
1134 /*
1135 * input_delete_character -- Deletes the character currently under the
1136 * input cursor.
1137 */
BUILT_IN_KEYBINDING(input_delete_character)1138 BUILT_IN_KEYBINDING(input_delete_character)
1139 {
1140 /* Delete key does nothing at end of input */
1141 if (!THIS_CHAR)
1142 return;
1143
1144 /* Whack the character under cursor and redraw input line */
1145 ov_strcpy(CURSOR_SPOT, NEXT_SPOT);
1146 retokenize_input(LOGICAL_CURSOR);
1147 update_input(last_input_screen, UPDATE_FROM_CURSOR);
1148 }
1149
1150
1151 /*
1152 * input_backspace -- Basically a combination of backward_character and
1153 * delete_character. No, this is not significantly
1154 * more expensive than the old way.
1155 */
BUILT_IN_KEYBINDING(input_backspace)1156 BUILT_IN_KEYBINDING(input_backspace)
1157 {
1158 /* Backspace key does nothing at start of input */
1159 if (LOGICAL_CURSOR == 0)
1160 return;
1161
1162 /* Do a cursor-left, followed by a delete. */
1163 backward_character(0, NULL);
1164 input_delete_character(0, NULL);
1165 }
1166
1167 /*
1168 * input_beginning_of_line: moves the input cursor to the first character in
1169 * the input buffer
1170 */
BUILT_IN_KEYBINDING(input_beginning_of_line)1171 BUILT_IN_KEYBINDING(input_beginning_of_line)
1172 {
1173 START = 0;
1174 LOGICAL_CURSOR=0;
1175
1176 update_input(last_input_screen, UPDATE_ALL);
1177 }
1178
1179 /*
1180 * input_end_of_line: moves the input cursor to the last character in the
1181 * input buffer
1182 */
BUILT_IN_KEYBINDING(input_end_of_line)1183 BUILT_IN_KEYBINDING(input_end_of_line)
1184 {
1185 while ((input_move_cursor(RIGHT, 0)))
1186 ;
1187
1188 update_input(last_input_screen, UPDATE_ALL);
1189 }
1190
1191 /*
1192 * This removes every code ponit between 'start' and 'end' (inclusive)
1193 * The cursor is moved to 'start' because that is where the cut was
1194 * made as far as the user sees.
1195 */
cut_input(int start,int end)1196 static void cut_input (int start, int end)
1197 {
1198 char * buffer;
1199 size_t size;
1200 int x;
1201 int startpos;
1202 int endpos;
1203
1204 startpos = LOGICAL_CHARS[start];
1205 /* We need to sanity check 'end' here. */
1206 if (end > MAXCOLS)
1207 end = MAXCOLS;
1208 endpos = LOGICAL_CHARS[end + 1];
1209 strext2(&CUT_BUFFER, INPUT_BUFFER, startpos, endpos);
1210
1211 LOGICAL_CURSOR = start;
1212 retokenize_input(start);
1213 update_input(last_input_screen, UPDATE_ALL);
1214 }
1215
1216 /*
1217 * To visualize:
1218 *
1219 * This is the input buffer
1220 * ^ (the input cursor)
1221 * orig_pos points to the 'e'.
1222 * c is an 'e'.
1223 * LOGICAL_CURSOR is moved to the space between the 's' and the 't'.
1224 * The input buffer is changed to:
1225 *
1226 * This is e input buffer
1227 * ^ (the input cursor)
1228 */
BUILT_IN_KEYBINDING(input_delete_to_previous_space)1229 BUILT_IN_KEYBINDING(input_delete_to_previous_space)
1230 {
1231 int anchor;
1232
1233 cursor_to_input();
1234
1235 if (LOGICAL_CURSOR <= 0)
1236 return;
1237
1238 anchor = LOGICAL_CURSOR;
1239 while (LOGICAL_CURSOR > 0 && !isspace(PREV_CHAR))
1240 input_move_cursor(LEFT, 0);
1241 cut_input(LOGICAL_CURSOR, anchor);
1242 }
1243
1244 /*
1245 * input_delete_previous_word: deletes from the cursor backwards to the next
1246 * space character. This is probably going to be the same effect as
1247 * delete_to_previous_space, but hey -- you know.
1248 */
BUILT_IN_KEYBINDING(input_delete_previous_word)1249 BUILT_IN_KEYBINDING(input_delete_previous_word)
1250 {
1251 int anchor;
1252
1253 cursor_to_input();
1254
1255 if (LOGICAL_CURSOR <= 0)
1256 return;
1257
1258 anchor = LOGICAL_CURSOR;
1259 input_backward_word(0, NULL);
1260 cut_input(LOGICAL_CURSOR, anchor);
1261 }
1262
1263 /*
1264 * input_delete_next_word: deletes from the cursor to the end of the next
1265 * word
1266 */
BUILT_IN_KEYBINDING(input_delete_next_word)1267 BUILT_IN_KEYBINDING(input_delete_next_word)
1268 {
1269 int anchor;
1270
1271 cursor_to_input();
1272
1273 if (!THIS_CHAR)
1274 return;
1275
1276 anchor = LOGICAL_CURSOR;
1277 input_forward_word(0, NULL);
1278 cut_input(anchor, LOGICAL_CURSOR - 1);
1279 }
1280
1281 /*
1282 * input_add_character: adds the codepoint to the input buffer, repecting
1283 * the current overwrite/insert mode status, etc
1284 *
1285 * Arguments
1286 * key - A code poing to be added at the cursor point
1287 * string - unused
1288 */
BUILT_IN_KEYBINDING(input_add_character)1289 BUILT_IN_KEYBINDING(input_add_character)
1290 {
1291 int numcols;
1292 int numbytes;
1293 unsigned char utf8str[8];
1294 int utf8strlen;
1295
1296 #if 0
1297 /* This test isn't used, but should it be? */
1298 if ((numcols = codepoint_numcolumns(key)) == -1)
1299 numcols = 1;
1300 #endif
1301
1302 utf8strlen = ucs_to_utf8(key, utf8str, sizeof(utf8str));
1303
1304 /* Don't permit the input buffer to get too big. */
1305 if (strlen(INPUT_BUFFER) + utf8strlen >= INPUT_BUFFER_SIZE)
1306 return;
1307
1308 /*
1309 * If we are NOT at the end of the line, and we're inserting
1310 * then insert the char (expensive!)
1311 */
1312 if (THIS_CHAR && get_int_var(INSERT_MODE_VAR))
1313 {
1314 char *ptr = LOCAL_COPY(CURSOR_SPOT);
1315 *CURSOR_SPOT = 0;
1316 ADD_TO_INPUT(utf8str);
1317 ADD_TO_INPUT(ptr);
1318 }
1319
1320 /*
1321 * Otherwise, we're either at the end of the input buffer,
1322 * or we're in overstrike mode.
1323 */
1324 else if (THIS_CHAR == 0)
1325 {
1326 ADD_TO_INPUT(utf8str);
1327 }
1328 else
1329 {
1330 char *ptr = LOCAL_COPY(NEXT_SPOT);
1331 *CURSOR_SPOT = 0;
1332 ADD_TO_INPUT(utf8str);
1333 ADD_TO_INPUT(ptr);
1334 }
1335
1336 retokenize_input(LOGICAL_CURSOR);
1337 update_input(last_input_screen, UPDATE_FROM_CURSOR);
1338 input_move_cursor(RIGHT, 1);
1339 }
1340
1341 /* input_clear_to_eol: erases from the cursor to the end of the input buffer */
BUILT_IN_KEYBINDING(input_clear_to_eol)1342 BUILT_IN_KEYBINDING(input_clear_to_eol)
1343 {
1344 /* This doesnt really speak to the implementation, but it works. */
1345 /* Definitely not right? */
1346 cut_input(LOGICAL_CURSOR, 9999);
1347 }
1348
1349 /*
1350 * input_clear_to_bol: clears from the cursor to the beginning of the input
1351 * buffer
1352 */
BUILT_IN_KEYBINDING(input_clear_to_bol)1353 BUILT_IN_KEYBINDING(input_clear_to_bol)
1354 {
1355 char c;
1356 char *copy;
1357
1358 /* XXX Definitely not right */
1359 cut_input(0, LOGICAL_CURSOR - 1);
1360
1361 LOGICAL_CURSOR = 0;
1362 update_input(last_input_screen, UPDATE_ALL);
1363 }
1364
1365 /*
1366 * input_clear_line: clears entire input line
1367 */
BUILT_IN_KEYBINDING(input_clear_line)1368 BUILT_IN_KEYBINDING(input_clear_line)
1369 {
1370 /* Only copy if there is input. -wd */
1371 if (*INPUT_BUFFER)
1372 cut_input(0, 999);
1373
1374 memset(INPUT_BUFFER, 0, sizeof(INPUT_BUFFER));
1375 LOGICAL_CURSOR = 0;
1376 update_input(last_input_screen, UPDATE_ALL);
1377 }
1378
1379 /*
1380 * input_reset_line: clears entire input line, suitable for use in tabscripts
1381 * This does not mangle the cutbuffer, so you can use it to replace the input
1382 * line w/o any deleterious effects!
1383 */
BUILT_IN_KEYBINDING(input_reset_line)1384 BUILT_IN_KEYBINDING(input_reset_line)
1385 {
1386 /* XXX This code is used in many places */
1387 *INPUT_BUFFER = 0;
1388 START = 0;
1389 LOGICAL_CURSOR=0;
1390 memset(INPUT_BUFFER, 0, sizeof(INPUT_BUFFER));
1391 update_input(last_input_screen, UPDATE_FROM_CURSOR);
1392
1393 if (!string)
1394 set_input(empty_string);
1395 else
1396 set_input(string); /* This calls update_input() */
1397 }
1398
1399
1400 #if 0
1401 /*
1402 * input_transpose_characters: move the character before the cursor to
1403 * the position after the cursor.
1404 */
1405 BUILT_IN_KEYBINDING(input_transpose_characters)
1406 {
1407 /*
1408 * This is tricky because the cursor never moves and there are three cases:
1409 *
1410 * 1. Cursor is at char 0: swap 0 and 1
1411 * A_ B C -> B_ A C
1412 * 2. Cursor is over a char: swap char under cursor and char before cursor
1413 * A B_ C -> B A_ C
1414 * 3. Cursor is at end (not on char): swap char before cursor and char before that
1415 * A B C _ -> A C B _
1416 */
1417
1418 /* Case 1 -- swap char 0 and 1 */
1419 if (LOGICAL_CURSOR == 0 && THIS_CHAR && NEXT_CHAR)
1420 {
1421 int tc, nc;
1422
1423 tc = THIS_CHAR;
1424 nc = NEXT_CHAR;
1425 *THIS_SPOT = nc;
1426 *NEXT_SPOT = tc;
1427 }
1428
1429 /* Case 2 -- cursor over char, but not the first char */
1430 else if (LOGICAL_CURSOR > 0 && THIS_CHAR && PREV_CHAR)
1431 {
1432 int tc, pc;
1433
1434 tc = THIS_CHAR;
1435 pc = PREV_CHAR;
1436 *THIS_SPOT = pc;
1437 *PREV_SPOT = tc;
1438 }
1439
1440 /* Case 3 -- cursor at end */
1441 else if (LOGICAL_CURSOR > 1 && !THIS_CHAR && PREV_CHAR && PREV_PREV_CHAR)
1442 {
1443 int pc, ppc;
1444
1445 pc = PREV_CHAR;
1446 ppc = PREV_PREV_CHAR;
1447 *THIS_SPOT = ppc;
1448 *PREV_PREV_SPOT = pc;
1449 }
1450
1451 /* In all other cases, this is a no-op. */
1452 update_input(last_input_screen, UPDATE_ALL);
1453 }
1454 #endif
1455
1456
BUILT_IN_KEYBINDING(refresh_inputline)1457 BUILT_IN_KEYBINDING(refresh_inputline)
1458 {
1459 update_input(NULL, UPDATE_ALL);
1460 }
1461
1462 /*
1463 * input_yank_cut_buffer: takes the contents of the cut buffer and inserts it
1464 * into the input line
1465 */
BUILT_IN_KEYBINDING(input_yank_cut_buffer)1466 BUILT_IN_KEYBINDING(input_yank_cut_buffer)
1467 {
1468 char *ptr = NULL;
1469 int x;
1470
1471 if (!CUT_BUFFER)
1472 return;
1473
1474 ptr = LOCAL_COPY(CURSOR_SPOT);
1475 *CURSOR_SPOT = 0;
1476 ADD_TO_INPUT(CUT_BUFFER);
1477 ADD_TO_INPUT(ptr);
1478 retokenize_input(LOGICAL_CURSOR);
1479
1480 /* XXX strlen(cut_buffer) is wrong */
1481 for (x = input_column_count(CUT_BUFFER); x > 0; x--)
1482 input_move_cursor(RIGHT, 0);
1483
1484 update_input(last_input_screen, UPDATE_ALL);
1485 }
1486
1487
1488
1489 /* BIND functions: */
BUILT_IN_KEYBINDING(forward_character)1490 BUILT_IN_KEYBINDING(forward_character)
1491 {
1492 input_move_cursor(RIGHT, 1);
1493 }
1494
BUILT_IN_KEYBINDING(backward_character)1495 BUILT_IN_KEYBINDING(backward_character)
1496 {
1497 input_move_cursor(LEFT, 1);
1498 }
1499
BUILT_IN_KEYBINDING(send_line)1500 BUILT_IN_KEYBINDING(send_line)
1501 {
1502 int server = from_server;
1503 char * line;
1504 int holding_already;
1505 int do_unscroll;
1506
1507 /* XXX No No No No No No XXX */
1508 from_server = get_window_server(0);
1509 line = LOCAL_COPY(INPUT_BUFFER);
1510
1511 /* Clear the input line before dispatching the command */
1512 *INPUT_BUFFER = 0;
1513 START = 0;
1514 LOGICAL_CURSOR = 0;
1515 memset(INPUT_BUFFER, 0, sizeof(INPUT_BUFFER));
1516
1517 update_input(last_input_screen, UPDATE_ALL);
1518
1519 holding_already = window_is_holding(last_input_screen->current_window);
1520 do_unscroll = window_is_scrolled_back(last_input_screen->current_window);
1521
1522 /*
1523 * Hold_mode is weird. Hold_mode gets even weirder when you're in
1524 * scrollback mode. Hold_mode users would expect that if they hit
1525 * <enter> when in scrollback mode, that they would scroll down, but
1526 * they would NOT unhold stuff. But then you get into the problem of
1527 * whether to do the scrolldown before or after you run the command.
1528 */
1529 if (holding_already == 0)
1530 unhold_a_window(last_input_screen->current_window);
1531
1532 /* XXX This should be rolled together with fire_wait_prompt */
1533 if (last_input_screen->promptlist &&
1534 last_input_screen->promptlist->type == WAIT_PROMPT_LINE)
1535 {
1536 fire_normal_prompt(line);
1537 }
1538 else
1539 {
1540 int old = system_exception;
1541
1542 if (do_hook(INPUT_LIST, "%s", line))
1543 parse_statement(line, 1, NULL);
1544
1545 system_exception = old;
1546 }
1547
1548 if (holding_already == 1)
1549 unhold_a_window(last_input_screen->current_window);
1550
1551 if (last_input_screen->current_window->holding_top_of_display &&
1552 do_unscroll == 1)
1553 scrollback_forwards(0, NULL); /* XXX - Keybinding */
1554
1555 from_server = server;
1556 }
1557
1558 /****************************************************************************/
1559 /*
1560 * None of the following keybindings have anything to do with the input line.
1561 * But they live here, because all of the keybindings are in this file.
1562 * Maybe some day I'll farm out the keybindings to the four corners.
1563 * Maybe I'll convince^H^H^H^H^H black into scripting them.
1564 */
1565
1566 /* This keybinding should be scripted. */
BUILT_IN_KEYBINDING(toggle_insert_mode)1567 BUILT_IN_KEYBINDING(toggle_insert_mode)
1568 {
1569 char * toggle;
1570
1571 toggle = alloca(7);
1572 strlcpy(toggle, "TOGGLE", 7);
1573 set_var_value(INSERT_MODE_VAR, toggle, 1);
1574 }
1575
1576 /* This keybinding should be scripted. */
BUILT_IN_KEYBINDING(my_clear_screen)1577 BUILT_IN_KEYBINDING(my_clear_screen)
1578 {
1579 clear_window_by_refnum(0, 1);
1580 }
1581
1582 /* This keybinding should be scripted. */
BUILT_IN_KEYBINDING(input_unclear_screen)1583 BUILT_IN_KEYBINDING(input_unclear_screen)
1584 {
1585 unclear_window_by_refnum(0, 1);
1586 }
1587
1588
1589 /* This keybinding should be in screen.c */
BUILT_IN_KEYBINDING(quote_char)1590 BUILT_IN_KEYBINDING(quote_char)
1591 {
1592 last_input_screen->quote_hit = 1;
1593 }
1594
1595 /*
1596 * These six functions are boomerang functions, which allow the highlight
1597 * characters to be bound by simply having these functions put in the
1598 * appropriate characters when you press any key to which you have bound
1599 * that highlight character. >;-)
1600 */
BUILT_IN_KEYBINDING(insert_bold)1601 BUILT_IN_KEYBINDING(insert_bold)
1602 {
1603 input_add_character(BOLD_TOG, string);
1604 }
1605
BUILT_IN_KEYBINDING(insert_reverse)1606 BUILT_IN_KEYBINDING(insert_reverse)
1607 {
1608 input_add_character(REV_TOG, string);
1609 }
1610
BUILT_IN_KEYBINDING(insert_underline)1611 BUILT_IN_KEYBINDING(insert_underline)
1612 {
1613 input_add_character(UND_TOG, string);
1614 }
1615
BUILT_IN_KEYBINDING(highlight_off)1616 BUILT_IN_KEYBINDING(highlight_off)
1617 {
1618 input_add_character(ALL_OFF, string);
1619 }
1620
BUILT_IN_KEYBINDING(insert_blink)1621 BUILT_IN_KEYBINDING(insert_blink)
1622 {
1623 input_add_character(BLINK_TOG, string);
1624 }
1625
BUILT_IN_KEYBINDING(insert_altcharset)1626 BUILT_IN_KEYBINDING(insert_altcharset)
1627 {
1628 input_add_character(ALT_TOG, string);
1629 }
1630
BUILT_IN_KEYBINDING(insert_italic)1631 BUILT_IN_KEYBINDING(insert_italic)
1632 {
1633 input_add_character(ITALIC_TOG, string);
1634 }
1635
1636 /* type_text: the BIND function TYPE_TEXT */
BUILT_IN_KEYBINDING(type_text)1637 BUILT_IN_KEYBINDING(type_text)
1638 {
1639 char * ptr;
1640 int x, totalcols;
1641
1642 ptr = LOCAL_COPY(CURSOR_SPOT);
1643 *CURSOR_SPOT = 0;
1644 ADD_TO_INPUT(string);
1645 ADD_TO_INPUT(ptr);
1646 retokenize_input(LOGICAL_CURSOR);
1647
1648 /* Now skip over what we just typed. */
1649 totalcols = input_column_count(string);
1650 for (x = totalcols; x > 0; x--)
1651 input_move_cursor(RIGHT, 0);
1652
1653 update_input(last_input_screen, UPDATE_ALL);
1654 }
1655
1656 /* parse_text: the bindable function that executes its string */
BUILT_IN_KEYBINDING(parse_text)1657 BUILT_IN_KEYBINDING(parse_text)
1658 {
1659 int old = system_exception;
1660
1661 if (string)
1662 runcmds(string, empty_string);
1663 system_exception = old;
1664 }
1665
BUILT_IN_FUNCTION(function_inputctl,input)1666 BUILT_IN_FUNCTION(function_inputctl, input)
1667 {
1668 char *verb, *domain;
1669 int verblen, domainlen;
1670 char *ret = NULL;
1671 int old_status_update;
1672
1673 GET_FUNC_ARG(verb, input);
1674 verblen = strlen(verb);
1675 if (!my_strnicmp(verb, "GET", verblen)) {
1676 GET_FUNC_ARG(domain, input)
1677 domainlen = strlen(domain);
1678
1679 if (!my_strnicmp(domain, "CUTBUFFER", domainlen)) {
1680 RETURN_STR((const char *)CUT_BUFFER);
1681 }
1682 }
1683 else if (!my_strnicmp(verb, "SET", verblen)) {
1684 GET_FUNC_ARG(domain, input)
1685 domainlen = strlen(domain);
1686
1687 if (!my_strnicmp(domain, "CUTBUFFER", domainlen)) {
1688 malloc_strcpy((char **)&CUT_BUFFER, input);
1689 RETURN_STR((const char *)CUT_BUFFER);
1690 }
1691 }
1692
1693 RETURN_EMPTY;
1694 }
1695
1696