Annotation of src/usr.bin/vim/ops.c, Revision 1.2
1.2 ! downsj 1: /* $OpenBSD: ops.c,v 1.1.1.1 1996/09/07 21:40:25 downsj Exp $ */
1.1 downsj 2: /* vi:set ts=4 sw=4:
3: *
4: * VIM - Vi IMproved by Bram Moolenaar
5: *
6: * Do ":help uganda" in Vim to read copying and usage conditions.
7: * Do ":help credits" in Vim to see a list of people who contributed.
8: */
9:
10: /*
11: * ops.c: implementation of various operators: do_shift, do_delete, do_tilde,
12: * do_change, do_yank, do_put, do_join
13: */
14:
15: #include "vim.h"
16: #include "globals.h"
17: #include "proto.h"
18: #include "option.h"
19: #include "ops.h"
20:
21: /*
22: * Number of registers.
23: * 0 = unnamed register, for normal yanks and puts
24: * 1..9 = number registers, for deletes
25: * 10..35 = named registers
26: * 36 = delete register (-)
27: * 37 = GUI selection register (*). Only if USE_GUI defined
28: */
29: #ifdef USE_GUI
30: # define NUM_REGISTERS 38
31: #else
32: # define NUM_REGISTERS 37
33: #endif
34:
35: /*
36: * Symbolic names for some registers.
37: */
38: #define DELETION_REGISTER 36
39: #ifdef USE_GUI
40: # define GUI_SELECTION_REGISTER 37
41: #endif
42:
43: /*
44: * Each yank buffer is an array of pointers to lines.
45: */
46: static struct yankbuf
47: {
48: char_u **y_array; /* pointer to array of line pointers */
49: linenr_t y_size; /* number of lines in y_array */
50: char_u y_type; /* MLINE, MCHAR or MBLOCK */
51: } y_buf[NUM_REGISTERS];
52:
53: static struct yankbuf *y_current; /* ptr to current yank buffer */
54: static int yankappend; /* TRUE when appending */
55: static struct yankbuf *y_previous = NULL; /* ptr to last written yank buffr */
56:
57: /*
58: * structure used by block_prep, do_delete and do_yank for blockwise operators
59: */
60: struct block_def
61: {
62: int startspaces;
63: int endspaces;
64: int textlen;
65: char_u *textstart;
66: colnr_t textcol;
67: };
68:
69: static void get_yank_buffer __ARGS((int));
70: static int stuff_yank __ARGS((int, char_u *));
71: static void free_yank __ARGS((long));
72: static void free_yank_all __ARGS((void));
73: static void block_prep __ARGS((struct block_def *, linenr_t, int));
74: static int same_leader __ARGS((int, char_u *, int, char_u *));
75: static int fmt_end_block __ARGS((linenr_t, int *, char_u **));
76:
77: /*
78: * do_shift - handle a shift operation
79: */
80: void
81: do_shift(op, curs_top, amount)
82: int op;
83: int curs_top;
84: int amount;
85: {
86: register long i;
87: int first_char;
88:
89: if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
90: (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
91: return;
92: for (i = op_line_count; --i >= 0; )
93: {
94: first_char = *ml_get_curline();
95: if (first_char == NUL) /* empty line */
96: curwin->w_cursor.col = 0;
97: /*
98: * Don't move the line right if it starts with # and p_si is set.
99: */
100: else
101: #if defined(SMARTINDENT) || defined(CINDENT)
102: if (first_char != '#' || (
103: # ifdef SMARTINDENT
104: !curbuf->b_p_si
105: # endif
106: # if defined(SMARTINDENT) && defined(CINDENT)
107: &&
108: # endif
109: # ifdef CINDENT
110: (!curbuf->b_p_cin || !in_cinkeys('#', ' ', TRUE))
111: # endif
112: ))
113: #endif
114: {
115: /* if (op_block_mode)
116: shift the block, not the whole line
117: else */
118: shift_line(op == LSHIFT, p_sr, amount);
119: }
120: ++curwin->w_cursor.lnum;
121: }
122:
123: if (curs_top) /* put cursor on first line, for ">>" */
124: {
125: curwin->w_cursor.lnum -= op_line_count;
126: beginline(MAYBE); /* shift_line() may have changed cursor.col */
127: }
128: else
129: --curwin->w_cursor.lnum; /* put cursor on last line, for ":>" */
130: updateScreen(CURSUPD);
131:
132: if (op_line_count > p_report)
133: smsg((char_u *)"%ld line%s %ced %d time%s", op_line_count,
134: plural(op_line_count), (op == RSHIFT) ? '>' : '<',
135: amount, plural((long)amount));
136: }
137:
138: /*
139: * shift the current line one shiftwidth left (if left != 0) or right
140: * leaves cursor on first blank in the line
141: */
142: void
143: shift_line(left, round, amount)
144: int left;
145: int round;
146: int amount;
147: {
148: register int count;
149: register int i, j;
150: int p_sw = (int)curbuf->b_p_sw;
151:
152: count = get_indent(); /* get current indent */
153:
154: if (round) /* round off indent */
155: {
156: i = count / p_sw; /* number of p_sw rounded down */
157: j = count % p_sw; /* extra spaces */
158: if (j && left) /* first remove extra spaces */
159: --amount;
160: if (left)
161: {
162: i -= amount;
163: if (i < 0)
164: i = 0;
165: }
166: else
167: i += amount;
168: count = i * p_sw;
169: }
170: else /* original vi indent */
171: {
172: if (left)
173: {
174: count -= p_sw * amount;
175: if (count < 0)
176: count = 0;
177: }
178: else
179: count += p_sw * amount;
180: }
181: set_indent(count, TRUE); /* set new indent */
182: }
183:
184: #if defined(LISPINDENT) || defined(CINDENT)
185: /*
186: * do_reindent - handle reindenting a block of lines for C or lisp.
187: *
188: * mechanism copied from do_shift, above
189: */
190: void
191: do_reindent(how)
192: int (*how) __ARGS((void));
193: {
194: register long i;
195: char_u *l;
196: int count;
197:
198: if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
199: (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
200: return;
201:
202: for (i = op_line_count; --i >= 0 && !got_int; )
203: {
204: /* it's a slow thing to do, so give feedback so there's no worry that
205: * the computer's just hung. */
206:
207: if ((i % 50 == 0 || i == op_line_count - 1) && op_line_count > p_report)
208: smsg((char_u *)"%ld line%s to indent... ", i, plural(i));
209:
210: /*
211: * Be vi-compatible: For lisp indenting the first line is not
212: * indented, unless there is only one line.
213: */
214: #ifdef LISPINDENT
215: if (i != op_line_count - 1 || op_line_count == 1 ||
216: how != get_lisp_indent)
217: #endif
218: {
219: l = skipwhite(ml_get_curline());
220: if (*l == NUL) /* empty or blank line */
221: count = 0;
222: else
223: count = how(); /* get the indent for this line */
224:
225: set_indent(count, TRUE);
226: }
227: ++curwin->w_cursor.lnum;
228: }
229:
230: /* put cursor on first non-blank of indented line */
231: curwin->w_cursor.lnum -= op_line_count;
232: beginline(MAYBE);
233:
234: updateScreen(CURSUPD);
235:
236: if (op_line_count > p_report)
237: {
238: i = op_line_count - (i + 1);
239: smsg((char_u *)"%ld line%s indented ", i, plural(i));
240: }
241: }
242: #endif /* defined(LISPINDENT) || defined(CINDENT) */
243:
244: /*
245: * check if character is name of yank buffer
246: * Note: There is no check for 0 (default register), caller should do this
247: */
248: int
249: is_yank_buffer(c, writing)
250: int c;
251: int writing; /* if TRUE check for writable buffers */
252: {
253: if (c > '~')
254: return FALSE;
255: if (isalnum(c) || (!writing && vim_strchr((char_u *)".%:", c) != NULL) ||
256: c == '"' || c == '-'
257: #ifdef USE_GUI
258: || (gui.in_use && c == '*')
259: #endif
260: )
261: return TRUE;
262: return FALSE;
263: }
264:
265: /*
266: * Set y_current and yankappend, according to the value of yankbuffer.
267: *
268: * If yankbuffer is 0 and writing, use buffer 0
269: * If yankbuffer is 0 and reading, use previous buffer
270: */
271: static void
272: get_yank_buffer(writing)
273: int writing;
274: {
275: register int i;
276:
277: yankappend = FALSE;
278: if (((yankbuffer == 0 && !writing) || yankbuffer == '"') &&
279: y_previous != NULL)
280: {
281: y_current = y_previous;
282: return;
283: }
284: i = yankbuffer;
285: if (isdigit(i))
286: i -= '0';
287: else if (islower(i))
288: i -= 'a' - 10;
289: else if (isupper(i))
290: {
291: i -= 'A' - 10;
292: yankappend = TRUE;
293: }
294: else if (yankbuffer == '-')
295: i = DELETION_REGISTER;
296: #ifdef USE_GUI
297: else if (gui.in_use && yankbuffer == '*')
298: i = GUI_SELECTION_REGISTER;
299: #endif
300: else /* not 0-9, a-z, A-Z or '-': use buffer 0 */
301: i = 0;
302: y_current = &(y_buf[i]);
303: if (writing) /* remember the buffer we write into for do_put() */
304: y_previous = y_current;
305: }
306:
307: /*
308: * return TRUE if the current yank buffer has type MLINE
309: */
310: int
311: yank_buffer_mline()
312: {
313: if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, FALSE))
314: return FALSE;
315: get_yank_buffer(FALSE);
316: return (y_current->y_type == MLINE);
317: }
318:
319: /*
320: * start or stop recording into a yank buffer
321: *
322: * return FAIL for failure, OK otherwise
323: */
324: int
325: do_record(c)
326: int c;
327: {
328: char_u *p;
329: static int bufname;
330: int retval;
331:
332: if (Recording == FALSE) /* start recording */
333: {
334: /* registers 0-9, a-z and " are allowed */
335: if (c > '~' || (!isalnum(c) && c != '"'))
336: retval = FAIL;
337: else
338: {
339: Recording = TRUE;
340: showmode();
341: bufname = c;
342: retval = OK;
343: }
344: }
345: else /* stop recording */
346: {
347: Recording = FALSE;
348: MSG("");
349: p = get_recorded();
350: if (p == NULL)
351: retval = FAIL;
352: else
353: retval = (stuff_yank(bufname, p));
354: }
355: return retval;
356: }
357:
358: /*
359: * stuff string 'p' into yank buffer 'bufname' (append if uppercase)
360: * 'p' is assumed to be alloced.
361: *
362: * return FAIL for failure, OK otherwise
363: */
364: static int
365: stuff_yank(bufname, p)
366: int bufname;
367: char_u *p;
368: {
369: char_u *lp;
370: char_u **pp;
371:
372: yankbuffer = bufname;
373: /* check for read-only buffer */
374: if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, TRUE))
375: return FAIL;
376: get_yank_buffer(TRUE);
377: if (yankappend && y_current->y_array != NULL)
378: {
379: pp = &(y_current->y_array[y_current->y_size - 1]);
380: lp = lalloc((long_u)(STRLEN(*pp) + STRLEN(p) + 1), TRUE);
381: if (lp == NULL)
382: {
383: vim_free(p);
384: return FAIL;
385: }
386: STRCPY(lp, *pp);
387: STRCAT(lp, p);
388: vim_free(p);
389: vim_free(*pp);
390: *pp = lp;
391: }
392: else
393: {
394: free_yank_all();
395: if ((y_current->y_array =
396: (char_u **)alloc((unsigned)sizeof(char_u *))) == NULL)
397: {
398: vim_free(p);
399: return FAIL;
400: }
401: y_current->y_array[0] = p;
402: y_current->y_size = 1;
403: y_current->y_type = MCHAR; /* used to be MLINE, why? */
404: }
405: return OK;
406: }
407:
408: /*
409: * execute a yank buffer (register): copy it into the stuff buffer
410: *
411: * return FAIL for failure, OK otherwise
412: */
413: int
414: do_execbuf(c, colon, addcr)
415: int c;
416: int colon; /* insert ':' before each line */
417: int addcr; /* always add '\n' to end of line */
418: {
419: static int lastc = NUL;
420: long i;
421: char_u *p;
422: int truncated;
423: int retval;
424:
425:
426: if (c == '@') /* repeat previous one */
427: c = lastc;
428: if (c == '%' || !is_yank_buffer(c, FALSE)) /* check for valid buffer */
429: return FAIL;
430: lastc = c;
431:
432: if (c == ':') /* use last command line */
433: {
434: if (last_cmdline == NULL)
435: {
436: EMSG(e_nolastcmd);
437: return FAIL;
438: }
439: vim_free(new_last_cmdline); /* don't keep the cmdline containing @: */
440: new_last_cmdline = NULL;
441: if (ins_typebuf((char_u *)"\n", FALSE, 0, TRUE) == FAIL)
442: return FAIL;
443: if (ins_typebuf(last_cmdline, FALSE, 0, TRUE) == FAIL)
444: return FAIL;
445: if (ins_typebuf((char_u *)":", FALSE, 0, TRUE) == FAIL)
446: return FAIL;
447: }
448: else if (c == '.') /* use last inserted text */
449: {
450: p = get_last_insert();
451: if (p == NULL)
452: {
453: EMSG(e_noinstext);
454: return FAIL;
455: }
456: i = STRLEN(p);
457: if (i > 0 && p[i - 1] == ESC) /* remove trailing ESC */
458: {
459: p[i - 1] = NUL;
460: truncated = TRUE;
461: }
462: else
463: truncated = FALSE;
464: retval = ins_typebuf(p, FALSE, 0, TRUE);
465: if (truncated)
466: p[i - 1] = ESC;
467: return retval;
468: }
469: else
470: {
471: yankbuffer = c;
472: get_yank_buffer(FALSE);
473: if (y_current->y_array == NULL)
474: return FAIL;
475:
476: /*
477: * Insert lines into typeahead buffer, from last one to first one.
478: */
479: for (i = y_current->y_size; --i >= 0; )
480: {
481: /* insert newline between lines and after last line if type is MLINE */
482: if (y_current->y_type == MLINE || i < y_current->y_size - 1
483: || addcr)
484: {
485: if (ins_typebuf((char_u *)"\n", FALSE, 0, TRUE) == FAIL)
486: return FAIL;
487: }
488: if (ins_typebuf(y_current->y_array[i], FALSE, 0, TRUE) == FAIL)
489: return FAIL;
490: if (colon && ins_typebuf((char_u *)":", FALSE, 0, TRUE) == FAIL)
491: return FAIL;
492: }
493: Exec_reg = TRUE; /* disable the 'q' command */
494: }
495: return OK;
496: }
497:
498: /*
499: * Insert a yank buffer: copy it into the Read buffer.
500: * Used by CTRL-R command and middle mouse button in insert mode.
501: *
502: * return FAIL for failure, OK otherwise
503: */
504: int
505: insertbuf(c)
506: int c;
507: {
508: long i;
509: int retval = OK;
510:
511: /*
512: * It is possible to get into an endless loop by having CTRL-R a in
513: * register a and then, in insert mode, doing CTRL-R a.
514: * If you hit CTRL-C, the loop will be broken here.
515: */
516: mch_breakcheck();
517: if (got_int)
518: return FAIL;
519:
520: /* check for valid buffer */
521: if (c != NUL && !is_yank_buffer(c, FALSE))
522: return FAIL;
523:
524: #ifdef USE_GUI
525: if (c == '*')
526: gui_get_selection(); /* may fill * register */
527: #endif
528:
529: if (c == '.') /* insert last inserted text */
530: retval = stuff_inserted(NUL, 1L, TRUE);
531: else if (c == '%') /* insert file name */
532: {
533: if (check_fname() == FAIL)
534: return FAIL;
535: stuffReadbuff(curbuf->b_xfilename);
536: }
537: else if (c == ':') /* insert last command line */
538: {
539: if (last_cmdline == NULL)
540: {
541: EMSG(e_nolastcmd);
542: return FAIL;
543: }
544: stuffReadbuff(last_cmdline);
545: }
546: else /* name or number register */
547: {
548: yankbuffer = c;
549: get_yank_buffer(FALSE);
550: if (y_current->y_array == NULL)
551: retval = FAIL;
552: else
553: {
554:
555: for (i = 0; i < y_current->y_size; ++i)
556: {
557: stuffReadbuff(y_current->y_array[i]);
558: /* insert newline between lines and after last line if type is
559: * MLINE */
560: if (y_current->y_type == MLINE || i < y_current->y_size - 1)
561: stuffReadbuff((char_u *)"\n");
562: }
563: }
564: }
565:
566: return retval;
567: }
568:
569: /*
570: * paste a yank buffer into the command line.
571: * used by CTRL-R command in command-line mode
572: * insertbuf() can't be used here, because special characters from the
573: * register contents will be interpreted as commands.
574: *
575: * return FAIL for failure, OK otherwise
576: */
577: int
578: cmdline_paste(c)
579: int c;
580: {
581: long i;
582:
583: if (!is_yank_buffer(c, FALSE)) /* check for valid buffer */
584: return FAIL;
585:
586: #ifdef USE_GUI
587: if (c == '*')
588: gui_get_selection();
589: #endif
590:
591: if (c == '.') /* insert last inserted text */
592: return FAIL; /* Unimplemented */
593:
594: if (c == '%') /* insert file name */
595: {
596: if (check_fname() == FAIL)
597: return FAIL;
598: return put_on_cmdline(curbuf->b_xfilename, -1, TRUE);
599: }
600:
601: if (c == ':') /* insert last command line */
602: {
603: if (last_cmdline == NULL)
604: return FAIL;
605: return put_on_cmdline(last_cmdline, -1, TRUE);
606: }
607:
608: yankbuffer = c;
609: get_yank_buffer(FALSE);
610: if (y_current->y_array == NULL)
611: return FAIL;
612:
613: for (i = 0; i < y_current->y_size; ++i)
614: {
615: put_on_cmdline(y_current->y_array[i], -1, FALSE);
616:
617: /* insert ^M between lines and after last line if type is MLINE */
618: if (y_current->y_type == MLINE || i < y_current->y_size - 1)
619: put_on_cmdline((char_u *)"\r", 1, FALSE);
620: }
621: return OK;
622: }
623:
624: /*
625: * do_delete - handle a delete operation
626: */
627: void
628: do_delete()
629: {
630: register int n;
631: linenr_t lnum;
632: char_u *ptr;
633: char_u *newp, *oldp;
634: linenr_t old_lcount = curbuf->b_ml.ml_line_count;
635: int did_yank = FALSE;
636: struct block_def bd;
637:
638: if (curbuf->b_ml.ml_flags & ML_EMPTY) /* nothing to do */
639: return;
640:
641: /*
642: * Imitate the strange Vi behaviour: If the delete spans more than one line
643: * and op_motion_type == MCHAR and the result is a blank line, make the delete
644: * linewise. Don't do this for the change command.
645: */
646: if (op_motion_type == MCHAR && op_line_count > 1 && op_type == DELETE)
647: {
648: ptr = ml_get(curbuf->b_op_end.lnum) + curbuf->b_op_end.col +
649: op_inclusive;
650: ptr = skipwhite(ptr);
651: if (*ptr == NUL && inindent(0))
652: op_motion_type = MLINE;
653: }
654:
655: /*
656: * Check for trying to delete (e.g. "D") in an empty line.
657: * Note: For change command it is ok.
658: */
659: if (op_motion_type == MCHAR && op_line_count == 1 &&
660: op_type == DELETE && *ml_get(curbuf->b_op_start.lnum) == NUL)
661: {
662: beep_flush();
663: return;
664: }
665:
666: /*
667: * Do a yank of whatever we're about to delete.
668: * If a yank buffer was specified, put the deleted text into that buffer
669: */
670: if (yankbuffer != 0)
671: {
672: /* check for read-only buffer */
673: if (!is_yank_buffer(yankbuffer, TRUE))
674: {
675: beep_flush();
676: return;
677: }
678: get_yank_buffer(TRUE); /* yank into specified buffer */
679: if (do_yank(TRUE, FALSE) == OK) /* yank without message */
680: did_yank = TRUE;
681: }
682:
683: /*
684: * Put deleted text into register 1 and shift number buffers if
685: * the delete contains a line break, or when a yankbuffer has been specified!
686: */
687: if (yankbuffer != 0 || op_motion_type == MLINE || op_line_count > 1)
688: {
689: y_current = &y_buf[9];
690: free_yank_all(); /* free buffer nine */
691: for (n = 9; n > 1; --n)
692: y_buf[n] = y_buf[n - 1];
693: y_previous = y_current = &y_buf[1];
694: y_buf[1].y_array = NULL; /* set buffer one to empty */
695: yankbuffer = 0;
696: }
697: else if (yankbuffer == 0) /* yank into unnamed buffer */
698: {
699: yankbuffer = '-'; /* use special delete buffer */
700: get_yank_buffer(TRUE);
701: yankbuffer = 0;
702: }
703:
704: if (yankbuffer == 0 && do_yank(TRUE, FALSE) == OK)
705: did_yank = TRUE;
706:
707: /*
708: * If there's too much stuff to fit in the yank buffer, then get a
709: * confirmation before doing the delete. This is crude, but simple. And it
710: * avoids doing a delete of something we can't put back if we want.
711: */
712: if (!did_yank)
713: {
714: if (ask_yesno((char_u *)"cannot yank; delete anyway", TRUE) != 'y')
715: {
716: emsg(e_abort);
717: return;
718: }
719: }
720:
721: /*
722: * block mode delete
723: */
724: if (op_block_mode)
725: {
726: if (u_save((linenr_t)(curbuf->b_op_start.lnum - 1),
727: (linenr_t)(curbuf->b_op_end.lnum + 1)) == FAIL)
728: return;
729:
730: for (lnum = curwin->w_cursor.lnum;
731: curwin->w_cursor.lnum <= curbuf->b_op_end.lnum;
732: ++curwin->w_cursor.lnum)
733: {
734: block_prep(&bd, curwin->w_cursor.lnum, TRUE);
735: if (bd.textlen == 0) /* nothing to delete */
736: continue;
737:
738: /*
739: * If we delete a TAB, it may be replaced by several characters.
740: * Thus the number of characters may increase!
741: */
742: n = bd.textlen - bd.startspaces - bd.endspaces; /* number of chars deleted */
743: oldp = ml_get_curline();
744: newp = alloc_check((unsigned)STRLEN(oldp) + 1 - n);
745: if (newp == NULL)
746: continue;
747: /* copy up to deleted part */
748: vim_memmove(newp, oldp, (size_t)bd.textcol);
749: /* insert spaces */
750: copy_spaces(newp + bd.textcol, (size_t)(bd.startspaces + bd.endspaces));
751: /* copy the part after the deleted part */
752: oldp += bd.textcol + bd.textlen;
753: vim_memmove(newp + bd.textcol + bd.startspaces + bd.endspaces,
754: oldp, STRLEN(oldp) + 1);
755: /* replace the line */
756: ml_replace(curwin->w_cursor.lnum, newp, FALSE);
757: }
758: curwin->w_cursor.lnum = lnum;
759: CHANGED;
760: updateScreen(VALID_TO_CURSCHAR);
761: op_line_count = 0; /* no lines deleted */
762: }
763: else if (op_motion_type == MLINE)
764: {
765: if (op_type == CHANGE)
766: {
767: /* Delete the lines except the first one.
768: * Temporarily move the cursor to the next line.
769: * Save the current line number, if the last line is deleted
770: * it may be changed.
771: */
772: if (op_line_count > 1)
773: {
774: lnum = curwin->w_cursor.lnum;
775: ++curwin->w_cursor.lnum;
776: dellines((long)(op_line_count - 1), TRUE, TRUE);
777: curwin->w_cursor.lnum = lnum;
778: }
779: if (u_save_cursor() == FAIL)
780: return;
781: if (curbuf->b_p_ai) /* don't delete indent */
782: {
783: beginline(TRUE); /* put cursor on first non-white */
784: did_ai = TRUE; /* delete the indent when ESC hit */
785: }
786: truncate_line(FALSE);
787: if (curwin->w_cursor.col > 0)
788: --curwin->w_cursor.col; /* put cursor on last char in line */
789: }
790: else
791: {
792: dellines(op_line_count, TRUE, TRUE);
793: }
794: u_clearline(); /* "U" command should not be possible after "dd" */
795: beginline(TRUE);
796: }
797: else if (op_line_count == 1) /* delete characters within one line */
798: {
799: if (u_save_cursor() == FAIL)
800: return;
801: /* if 'cpoptions' contains '$', display '$' at end of change */
802: if (vim_strchr(p_cpo, CPO_DOLLAR) != NULL && op_type == CHANGE &&
803: curbuf->b_op_end.lnum == curwin->w_cursor.lnum && !op_is_VIsual)
804: display_dollar(curbuf->b_op_end.col - !op_inclusive);
805: n = curbuf->b_op_end.col - curbuf->b_op_start.col + 1 - !op_inclusive;
806: while (n-- > 0)
807: if (delchar(TRUE) == FAIL)
808: break;
809: }
810: else /* delete characters between lines */
811: {
812: if (u_save_cursor() == FAIL) /* save first line for undo */
813: return;
814: truncate_line(TRUE); /* delete from cursor to end of line */
815:
816: curbuf->b_op_start = curwin->w_cursor; /* remember curwin->w_cursor */
817: ++curwin->w_cursor.lnum;
818: /* includes save for undo */
819: dellines((long)(op_line_count - 2), TRUE, TRUE);
820:
821: if (u_save_cursor() == FAIL) /* save last line for undo */
822: return;
823: n = curbuf->b_op_end.col - !op_inclusive;
824: curwin->w_cursor.col = 0;
825: while (n-- >= 0) /* delete from start of line until op_end */
826: if (delchar(TRUE) == FAIL)
827: break;
828: curwin->w_cursor = curbuf->b_op_start; /* restore curwin->w_cursor */
829: (void)do_join(FALSE, curs_rows() == OK);
830: }
831:
832: if ((op_motion_type == MCHAR && op_line_count == 1) || op_type == CHANGE)
833: {
834: if (dollar_vcol)
835: must_redraw = 0; /* don't want a redraw now */
836: cursupdate();
837: if (!dollar_vcol)
838: updateline();
839: }
840: else if (!global_busy) /* no need to update screen for :global */
841: updateScreen(CURSUPD);
842:
843: msgmore(curbuf->b_ml.ml_line_count - old_lcount);
844:
845: /* correct op_end for deleted text (for "']" command) */
846: if (op_block_mode)
847: curbuf->b_op_end.col = curbuf->b_op_start.col;
848: else
849: curbuf->b_op_end = curbuf->b_op_start;
850: }
851:
852: /*
853: * do_tilde - handle the (non-standard vi) tilde operator
854: */
855: void
856: do_tilde()
857: {
858: FPOS pos;
859: struct block_def bd;
860:
861: if (u_save((linenr_t)(curbuf->b_op_start.lnum - 1),
862: (linenr_t)(curbuf->b_op_end.lnum + 1)) == FAIL)
863: return;
864:
865: pos = curbuf->b_op_start;
866: if (op_block_mode) /* Visual block mode */
867: {
868: for (; pos.lnum <= curbuf->b_op_end.lnum; ++pos.lnum)
869: {
870: block_prep(&bd, pos.lnum, FALSE);
871: pos.col = bd.textcol;
872: while (--bd.textlen >= 0)
873: {
874: swapchar(&pos);
875: if (inc(&pos) == -1) /* at end of file */
876: break;
877: }
878: }
879: }
880: else /* not block mode */
881: {
882: if (op_motion_type == MLINE)
883: {
884: pos.col = 0;
885: curbuf->b_op_end.col = STRLEN(ml_get(curbuf->b_op_end.lnum));
886: if (curbuf->b_op_end.col)
887: --curbuf->b_op_end.col;
888: }
889: else if (!op_inclusive)
890: dec(&(curbuf->b_op_end));
891:
892: while (ltoreq(pos, curbuf->b_op_end))
893: {
894: swapchar(&pos);
895: if (inc(&pos) == -1) /* at end of file */
896: break;
897: }
898: }
899:
900: if (op_motion_type == MCHAR && op_line_count == 1 && !op_block_mode)
901: {
902: cursupdate();
903: updateline();
904: }
905: else
906: updateScreen(CURSUPD);
907:
908: if (op_line_count > p_report)
909: smsg((char_u *)"%ld line%s ~ed",
910: op_line_count, plural(op_line_count));
911: }
912:
913: /*
914: * If op_type == UPPER: make uppercase,
915: * if op_type == LOWER: make lowercase,
916: * else swap case of character at 'pos'
917: */
918: void
919: swapchar(pos)
920: FPOS *pos;
921: {
922: int c;
923:
924: c = gchar(pos);
925: if (islower(c) && op_type != LOWER)
926: {
927: pchar(*pos, toupper(c));
928: CHANGED;
929: }
930: else if (isupper(c) && op_type != UPPER)
931: {
932: pchar(*pos, tolower(c));
933: CHANGED;
934: }
935: }
936:
937: /*
938: * do_change - handle a change operation
939: *
940: * return TRUE if edit() returns because of a CTRL-O command
941: */
942: int
943: do_change()
944: {
945: register colnr_t l;
946:
947: l = curbuf->b_op_start.col;
948: if (op_motion_type == MLINE)
949: {
950: l = 0;
951: can_si = TRUE; /* It's like opening a new line, do si */
952: }
953:
954: if (!op_empty)
955: do_delete(); /* delete the text and take care of undo */
956:
957: if ((l > curwin->w_cursor.col) && !lineempty(curwin->w_cursor.lnum))
958: inc_cursor();
959:
960: #ifdef LISPINDENT
961: if (op_motion_type == MLINE)
962: {
963: if (curbuf->b_p_lisp && curbuf->b_p_ai)
964: fixthisline(get_lisp_indent);
965: # ifdef CINDENT
966: else if (curbuf->b_p_cin)
967: fixthisline(get_c_indent);
968: # endif
969: }
970: #endif
971:
972: op_type = NOP; /* don't want op_type == CHANGED in Insert mode */
973: return edit(NUL, FALSE, (linenr_t)1);
974: }
975:
976: /*
977: * set all the yank buffers to empty (called from main())
978: */
979: void
980: init_yank()
981: {
982: register int i;
983:
984: for (i = 0; i < NUM_REGISTERS; ++i)
985: y_buf[i].y_array = NULL;
986: }
987:
988: /*
989: * Free "n" lines from the current yank buffer.
990: * Called for normal freeing and in case of error.
991: */
992: static void
993: free_yank(n)
994: long n;
995: {
996: if (y_current->y_array != NULL)
997: {
998: register long i;
999:
1000: for (i = n; --i >= 0; )
1001: {
1002: if ((i & 1023) == 1023) /* this may take a while */
1003: {
1004: /*
1005: * This message should never cause a hit-return message.
1006: * Overwrite this message with any next message.
1007: */
1008: ++no_wait_return;
1009: smsg((char_u *)"freeing %ld lines", i + 1);
1010: --no_wait_return;
1011: msg_didout = FALSE;
1012: msg_col = 0;
1013: }
1014: vim_free(y_current->y_array[i]);
1015: }
1016: vim_free(y_current->y_array);
1017: y_current->y_array = NULL;
1018: if (n >= 1000)
1019: MSG("");
1020: }
1021: }
1022:
1023: static void
1024: free_yank_all()
1025: {
1026: free_yank(y_current->y_size);
1027: }
1028:
1029: /*
1030: * Yank the text between curwin->w_cursor and startpos into a yank buffer.
1031: * If we are to append ("uppercase), we first yank into a new yank buffer and
1032: * then concatenate the old and the new one (so we keep the old one in case
1033: * of out-of-memory).
1034: *
1035: * return FAIL for failure, OK otherwise
1036: */
1037: int
1038: do_yank(deleting, mess)
1039: int deleting;
1040: int mess;
1041: {
1042: long i; /* index in y_array[] */
1043: struct yankbuf *curr; /* copy of y_current */
1044: struct yankbuf newbuf; /* new yank buffer when appending */
1045: char_u **new_ptr;
1046: register linenr_t lnum; /* current line number */
1047: long j;
1048: int yanktype = op_motion_type;
1049: long yanklines = op_line_count;
1050: linenr_t yankendlnum = curbuf->b_op_end.lnum;
1051:
1052: char_u *pnew;
1053: struct block_def bd;
1054:
1055: /* check for read-only buffer */
1056: if (yankbuffer != 0 && !is_yank_buffer(yankbuffer, TRUE))
1057: {
1058: beep_flush();
1059: return FAIL;
1060: }
1061: if (!deleting) /* do_delete() already set y_current */
1062: get_yank_buffer(TRUE);
1063:
1064: curr = y_current;
1065: /* append to existing contents */
1066: if (yankappend && y_current->y_array != NULL)
1067: y_current = &newbuf;
1068: else
1069: free_yank_all(); /* free previously yanked lines */
1070:
1071: /*
1072: * If the cursor was in column 1 before and after the movement, and the
1073: * operator is not inclusive, the yank is always linewise.
1074: */
1075: if (op_motion_type == MCHAR && curbuf->b_op_start.col == 0 &&
1076: !op_inclusive && curbuf->b_op_end.col == 0 && yanklines > 1)
1077: {
1078: yanktype = MLINE;
1079: --yankendlnum;
1080: --yanklines;
1081: }
1082:
1083: y_current->y_size = yanklines;
1084: y_current->y_type = yanktype; /* set the yank buffer type */
1085: y_current->y_array = (char_u **)lalloc((long_u)(sizeof(char_u *) *
1086: yanklines), TRUE);
1087:
1088: if (y_current->y_array == NULL)
1089: {
1090: y_current = curr;
1091: return FAIL;
1092: }
1093:
1094: i = 0;
1095: lnum = curbuf->b_op_start.lnum;
1096:
1097: /*
1098: * Visual block mode
1099: */
1100: if (op_block_mode)
1101: {
1102: y_current->y_type = MBLOCK; /* set the yank buffer type */
1103: for ( ; lnum <= yankendlnum; ++lnum)
1104: {
1105: block_prep(&bd, lnum, FALSE);
1106:
1107: if ((pnew = alloc(bd.startspaces + bd.endspaces +
1108: bd.textlen + 1)) == NULL)
1109: goto fail;
1110: y_current->y_array[i++] = pnew;
1111:
1112: copy_spaces(pnew, (size_t)bd.startspaces);
1113: pnew += bd.startspaces;
1114:
1115: vim_memmove(pnew, bd.textstart, (size_t)bd.textlen);
1116: pnew += bd.textlen;
1117:
1118: copy_spaces(pnew, (size_t)bd.endspaces);
1119: pnew += bd.endspaces;
1120:
1121: *pnew = NUL;
1122: }
1123: }
1124: else
1125: {
1126: /*
1127: * there are three parts for non-block mode:
1128: * 1. if yanktype != MLINE yank last part of the top line
1129: * 2. yank the lines between op_start and op_end, inclusive when
1130: * yanktype == MLINE
1131: * 3. if yanktype != MLINE yank first part of the bot line
1132: */
1133: if (yanktype != MLINE)
1134: {
1135: if (yanklines == 1) /* op_start and op_end on same line */
1136: {
1137: j = curbuf->b_op_end.col - curbuf->b_op_start.col +
1138: 1 - !op_inclusive;
1139: if ((y_current->y_array[0] = strnsave(ml_get(lnum) +
1140: curbuf->b_op_start.col, (int)j)) == NULL)
1141: {
1142: fail:
1143: free_yank(i); /* free the allocated lines */
1144: y_current = curr;
1145: return FAIL;
1146: }
1147: goto success;
1148: }
1149: if ((y_current->y_array[0] = strsave(ml_get(lnum++) +
1150: curbuf->b_op_start.col)) == NULL)
1151: goto fail;
1152: ++i;
1153: }
1154:
1155: while (yanktype == MLINE ? (lnum <= yankendlnum) : (lnum < yankendlnum))
1156: {
1157: if ((y_current->y_array[i] = strsave(ml_get(lnum++))) == NULL)
1158: goto fail;
1159: ++i;
1160: }
1161: if (yanktype != MLINE)
1162: {
1163: if ((y_current->y_array[i] = strnsave(ml_get(yankendlnum),
1164: curbuf->b_op_end.col + 1 - !op_inclusive)) == NULL)
1165: goto fail;
1166: }
1167: }
1168:
1169: success:
1170: if (curr != y_current) /* append the new block to the old block */
1171: {
1172: new_ptr = (char_u **)lalloc((long_u)(sizeof(char_u *) *
1173: (curr->y_size + y_current->y_size)), TRUE);
1174: if (new_ptr == NULL)
1175: goto fail;
1176: for (j = 0; j < curr->y_size; ++j)
1177: new_ptr[j] = curr->y_array[j];
1178: vim_free(curr->y_array);
1179: curr->y_array = new_ptr;
1180:
1181: if (yanktype == MLINE) /* MLINE overrides MCHAR and MBLOCK */
1182: curr->y_type = MLINE;
1183:
1184: /* concatenate the last line of the old block with the first line of
1185: * the new block */
1186: if (curr->y_type == MCHAR)
1187: {
1188: pnew = lalloc((long_u)(STRLEN(curr->y_array[curr->y_size - 1])
1189: + STRLEN(y_current->y_array[0]) + 1), TRUE);
1190: if (pnew == NULL)
1191: {
1192: i = y_current->y_size - 1;
1193: goto fail;
1194: }
1195: STRCPY(pnew, curr->y_array[--j]);
1196: STRCAT(pnew, y_current->y_array[0]);
1197: vim_free(curr->y_array[j]);
1198: vim_free(y_current->y_array[0]);
1199: curr->y_array[j++] = pnew;
1200: i = 1;
1201: }
1202: else
1203: i = 0;
1204: while (i < y_current->y_size)
1205: curr->y_array[j++] = y_current->y_array[i++];
1206: curr->y_size = j;
1207: vim_free(y_current->y_array);
1208: y_current = curr;
1209: }
1210: if (mess) /* Display message about yank? */
1211: {
1212: if (yanktype == MCHAR && !op_block_mode)
1213: --yanklines;
1214: if (yanklines > p_report)
1215: {
1216: cursupdate(); /* redisplay now, so message is not deleted */
1217: smsg((char_u *)"%ld line%s yanked", yanklines, plural(yanklines));
1218: }
1219: }
1220:
1221: return OK;
1222: }
1223:
1224: /*
1225: * put contents of register into the text
1226: * For ":put" command count == -1.
1227: */
1228: void
1229: do_put(dir, count, fix_indent)
1230: int dir; /* BACKWARD for 'P', FORWARD for 'p' */
1231: long count;
1232: int fix_indent; /* make indent look nice */
1233: {
1234: char_u *ptr;
1235: char_u *newp, *oldp;
1236: int yanklen;
1237: int oldlen;
1238: int totlen = 0; /* init for gcc */
1239: linenr_t lnum;
1240: colnr_t col;
1241: long i; /* index in y_array[] */
1242: int y_type;
1243: long y_size;
1244: char_u **y_array;
1245: long nr_lines = 0;
1246: colnr_t vcol;
1247: int delcount;
1248: int incr = 0;
1249: long j;
1250: FPOS new_cursor;
1251: int indent;
1252: int orig_indent = 0; /* init for gcc */
1253: int indent_diff = 0; /* init for gcc */
1254: int first_indent = TRUE;
1255: FPOS old_pos;
1256: struct block_def bd;
1257: char_u *insert_string = NULL;
1258:
1259: #ifdef USE_GUI
1260: if (yankbuffer == '*')
1261: gui_get_selection();
1262: #endif
1263:
1264: if (fix_indent)
1265: orig_indent = get_indent();
1266:
1267: curbuf->b_op_start = curwin->w_cursor; /* default for "'[" command */
1268: if (dir == FORWARD)
1269: curbuf->b_op_start.col++;
1270: curbuf->b_op_end = curwin->w_cursor; /* default for "']" command */
1271:
1272: /*
1273: * Using inserted text works differently, because the buffer includes
1274: * special characters (newlines, etc.).
1275: */
1276: if (yankbuffer == '.')
1277: {
1278: (void)stuff_inserted((dir == FORWARD ? (count == -1 ? 'o' : 'a') :
1279: (count == -1 ? 'O' : 'i')), count, FALSE);
1280: return;
1281: }
1282:
1283: /*
1284: * For '%' (file name) and ':' (last command line) we have to create a
1285: * fake yank buffer.
1286: */
1287: if (yankbuffer == '%') /* use file name */
1288: {
1289: if (check_fname() == FAIL)
1290: return;
1291: insert_string = curbuf->b_xfilename;
1292: }
1293: else if (yankbuffer == ':') /* use last command line */
1294: {
1295: if (last_cmdline == NULL)
1296: {
1297: EMSG(e_nolastcmd);
1298: return;
1299: }
1300: insert_string = last_cmdline;
1301: }
1302:
1303: if (insert_string != NULL)
1304: {
1305: y_type = MCHAR; /* use fake one-line yank buffer */
1306: y_size = 1;
1307: y_array = &insert_string;
1308: }
1309: else
1310: {
1311: get_yank_buffer(FALSE);
1312:
1313: y_type = y_current->y_type;
1314: y_size = y_current->y_size;
1315: y_array = y_current->y_array;
1316: }
1317:
1318: if (count == -1) /* :put command */
1319: {
1320: y_type = MLINE;
1321: count = 1;
1322: }
1323:
1324: if (y_size == 0 || y_array == NULL)
1325: {
1.2 ! downsj 1326: EMSG2("Nothing in register %s",
! 1327: yankbuffer == 0 ? (char_u *)"\"" : transchar(yankbuffer));
1.1 downsj 1328: return;
1329: }
1330:
1331: if (y_type == MBLOCK)
1332: {
1333: lnum = curwin->w_cursor.lnum + y_size + 1;
1334: if (lnum > curbuf->b_ml.ml_line_count)
1335: lnum = curbuf->b_ml.ml_line_count + 1;
1336: if (u_save(curwin->w_cursor.lnum - 1, lnum) == FAIL)
1337: return;
1338: }
1339: else if (u_save_cursor() == FAIL)
1340: return;
1341:
1342: yanklen = STRLEN(y_array[0]);
1343: CHANGED;
1344:
1345: lnum = curwin->w_cursor.lnum;
1346: col = curwin->w_cursor.col;
1347:
1348: /*
1349: * block mode
1350: */
1351: if (y_type == MBLOCK)
1352: {
1353: if (dir == FORWARD && gchar_cursor() != NUL)
1354: {
1355: getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col);
1356: ++col;
1357: ++curwin->w_cursor.col;
1358: }
1359: else
1360: getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL);
1361: for (i = 0; i < y_size; ++i)
1362: {
1363: bd.startspaces = 0;
1364: bd.endspaces = 0;
1365: bd.textcol = 0;
1366: vcol = 0;
1367: delcount = 0;
1368:
1369: /* add a new line */
1370: if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count)
1371: {
1372: ml_append(curbuf->b_ml.ml_line_count, (char_u *)"",
1373: (colnr_t)1, FALSE);
1374: ++nr_lines;
1375: }
1376: oldp = ml_get_curline();
1377: oldlen = STRLEN(oldp);
1378: for (ptr = oldp; vcol < col && *ptr; ++ptr)
1379: {
1380: /* Count a tab for what it's worth (if list mode not on) */
1381: incr = lbr_chartabsize(ptr, (colnr_t)vcol);
1382: vcol += incr;
1383: ++bd.textcol;
1384: }
1385: if (vcol < col) /* line too short, padd with spaces */
1386: {
1387: bd.startspaces = col - vcol;
1388: }
1389: else if (vcol > col)
1390: {
1391: bd.endspaces = vcol - col;
1392: bd.startspaces = incr - bd.endspaces;
1393: --bd.textcol;
1394: delcount = 1;
1395: }
1396: yanklen = STRLEN(y_array[i]);
1397: totlen = count * yanklen + bd.startspaces + bd.endspaces;
1398: newp = alloc_check((unsigned)totlen + oldlen + 1);
1399: if (newp == NULL)
1400: break;
1401: /* copy part up to cursor to new line */
1402: ptr = newp;
1403: vim_memmove(ptr, oldp, (size_t)bd.textcol);
1404: ptr += bd.textcol;
1405: /* may insert some spaces before the new text */
1406: copy_spaces(ptr, (size_t)bd.startspaces);
1407: ptr += bd.startspaces;
1408: /* insert the new text */
1409: for (j = 0; j < count; ++j)
1410: {
1411: vim_memmove(ptr, y_array[i], (size_t)yanklen);
1412: ptr += yanklen;
1413: }
1414: /* may insert some spaces after the new text */
1415: copy_spaces(ptr, (size_t)bd.endspaces);
1416: ptr += bd.endspaces;
1417: /* move the text after the cursor to the end of the line. */
1418: vim_memmove(ptr, oldp + bd.textcol + delcount,
1419: (size_t)(oldlen - bd.textcol - delcount + 1));
1420: ml_replace(curwin->w_cursor.lnum, newp, FALSE);
1421:
1422: ++curwin->w_cursor.lnum;
1423: if (i == 0)
1424: curwin->w_cursor.col += bd.startspaces;
1425: }
1426: /* for "']" command */
1427: curbuf->b_op_end.lnum = curwin->w_cursor.lnum - 1;
1428: curbuf->b_op_end.col = bd.textcol + totlen - 1;
1429: curwin->w_cursor.lnum = lnum;
1430: cursupdate();
1431: updateScreen(VALID_TO_CURSCHAR);
1432: }
1433: else /* not block mode */
1434: {
1435: if (y_type == MCHAR)
1436: {
1437: /* if type is MCHAR, FORWARD is the same as BACKWARD on the next char */
1438: if (dir == FORWARD && gchar_cursor() != NUL)
1439: {
1440: ++col;
1441: if (yanklen)
1442: {
1443: ++curwin->w_cursor.col;
1444: ++curbuf->b_op_end.col;
1445: }
1446: }
1447: new_cursor = curwin->w_cursor;
1448: }
1449: else if (dir == BACKWARD)
1450: /* if type is MLINE, BACKWARD is the same as FORWARD on the previous line */
1451: --lnum;
1452:
1453: /*
1454: * simple case: insert into current line
1455: */
1456: if (y_type == MCHAR && y_size == 1)
1457: {
1458: totlen = count * yanklen;
1459: if (totlen)
1460: {
1461: oldp = ml_get(lnum);
1462: newp = alloc_check((unsigned)(STRLEN(oldp) + totlen + 1));
1463: if (newp == NULL)
1464: return; /* alloc() will give error message */
1465: vim_memmove(newp, oldp, (size_t)col);
1466: ptr = newp + col;
1467: for (i = 0; i < count; ++i)
1468: {
1469: vim_memmove(ptr, y_array[0], (size_t)yanklen);
1470: ptr += yanklen;
1471: }
1472: vim_memmove(ptr, oldp + col, STRLEN(oldp + col) + 1);
1473: ml_replace(lnum, newp, FALSE);
1474: /* put cursor on last putted char */
1475: curwin->w_cursor.col += (colnr_t)(totlen - 1);
1476: }
1477: curbuf->b_op_end = curwin->w_cursor;
1478: updateline();
1479: }
1480: else
1481: {
1482: while (--count >= 0)
1483: {
1484: i = 0;
1485: if (y_type == MCHAR)
1486: {
1487: /*
1488: * Split the current line in two at the insert position.
1489: * First insert y_array[size - 1] in front of second line.
1490: * Then append y_array[0] to first line.
1491: */
1492: ptr = ml_get(lnum) + col;
1493: totlen = STRLEN(y_array[y_size - 1]);
1494: newp = alloc_check((unsigned)(STRLEN(ptr) + totlen + 1));
1495: if (newp == NULL)
1496: goto error;
1497: STRCPY(newp, y_array[y_size - 1]);
1498: STRCAT(newp, ptr);
1499: /* insert second line */
1500: ml_append(lnum, newp, (colnr_t)0, FALSE);
1501: vim_free(newp);
1502:
1503: oldp = ml_get(lnum);
1504: newp = alloc_check((unsigned)(col + yanklen + 1));
1505: if (newp == NULL)
1506: goto error;
1507: /* copy first part of line */
1508: vim_memmove(newp, oldp, (size_t)col);
1509: /* append to first line */
1510: vim_memmove(newp + col, y_array[0], (size_t)(yanklen + 1));
1511: ml_replace(lnum, newp, FALSE);
1512:
1513: curwin->w_cursor.lnum = lnum;
1514: i = 1;
1515: }
1516:
1517: while (i < y_size)
1518: {
1519: if ((y_type != MCHAR || i < y_size - 1) &&
1520: ml_append(lnum, y_array[i], (colnr_t)0, FALSE) == FAIL)
1521: goto error;
1522: lnum++;
1523: i++;
1524: if (fix_indent)
1525: {
1526: old_pos = curwin->w_cursor;
1527: curwin->w_cursor.lnum = lnum;
1528: ptr = ml_get(lnum);
1529: #if defined(SMARTINDENT) || defined(CINDENT)
1530: if (*ptr == '#'
1531: # ifdef SMARTINDENT
1532: && curbuf->b_p_si
1533: # endif
1534: # ifdef CINDENT
1535: && curbuf->b_p_cin && in_cinkeys('#', ' ', TRUE)
1536: # endif
1537: )
1538:
1539: indent = 0; /* Leave # lines at start */
1540: else
1541: #endif
1542: if (*ptr == NUL)
1543: indent = 0; /* Ignore empty lines */
1544: else if (first_indent)
1545: {
1546: indent_diff = orig_indent - get_indent();
1547: indent = orig_indent;
1548: first_indent = FALSE;
1549: }
1550: else if ((indent = get_indent() + indent_diff) < 0)
1551: indent = 0;
1552: set_indent(indent, TRUE);
1553: curwin->w_cursor = old_pos;
1554: }
1555: ++nr_lines;
1556: }
1557: }
1558:
1559: /* put '] at last inserted character */
1560: curbuf->b_op_end.lnum = lnum;
1561: col = STRLEN(y_array[y_size - 1]);
1562: if (col > 1)
1563: curbuf->b_op_end.col = col - 1;
1564: else
1565: curbuf->b_op_end.col = 0;
1566:
1567: if (y_type == MLINE)
1568: {
1569: curwin->w_cursor.col = 0;
1570: if (dir == FORWARD)
1571: {
1572: updateScreen(NOT_VALID); /* recomp. curwin->w_botline */
1573: ++curwin->w_cursor.lnum;
1574: }
1575: /* put cursor on first non-blank in last inserted line */
1576: beginline(TRUE);
1577: }
1578: else /* put cursor on first inserted character */
1579: {
1580: curwin->w_cursor = new_cursor;
1581: }
1582:
1583: error:
1584: if (y_type == MLINE) /* for '[ */
1585: {
1586: curbuf->b_op_start.col = 0;
1587: if (dir == FORWARD)
1588: curbuf->b_op_start.lnum++;
1589: }
1590: mark_adjust(curbuf->b_op_start.lnum + (y_type == MCHAR),
1591: MAXLNUM, nr_lines, 0L);
1592: updateScreen(CURSUPD);
1593: }
1594: }
1595:
1596: msgmore(nr_lines);
1597: curwin->w_set_curswant = TRUE;
1598: }
1599:
1600: /* Return the character name of the register with the given number */
1601: int
1602: get_register_name(num)
1603: int num;
1604: {
1605: if (num == -1)
1606: return '"';
1607: else if (num < 10)
1608: return num + '0';
1609: else if (num == DELETION_REGISTER)
1610: return '-';
1611: #ifdef USE_GUI
1612: else if (num == GUI_SELECTION_REGISTER)
1613: return '*';
1614: #endif
1615: else
1616: return num + 'a' - 10;
1617: }
1618:
1619: /*
1620: * display the contents of the yank buffers
1621: */
1622: void
1623: do_dis(arg)
1624: char_u *arg;
1625: {
1626: register int i, n;
1627: register long j;
1628: register char_u *p;
1629: register struct yankbuf *yb;
1630: char_u name;
1631:
1632: if (arg != NULL && *arg == NUL)
1633: arg = NULL;
1634:
1635: set_highlight('t'); /* Highlight title */
1636: start_highlight();
1637: MSG_OUTSTR("\n--- Registers ---");
1638: stop_highlight();
1639: for (i = -1; i < NUM_REGISTERS; ++i)
1640: {
1641: if (i == -1)
1642: {
1643: if (y_previous != NULL)
1644: yb = y_previous;
1645: else
1646: yb = &(y_buf[0]);
1647: }
1648: else
1649: yb = &(y_buf[i]);
1650: name = get_register_name(i);
1651: if (yb->y_array != NULL && (arg == NULL ||
1652: vim_strchr(arg, name) != NULL))
1653: {
1654: msg_outchar('\n');
1655: msg_outchar('"');
1656: msg_outchar(name);
1657: MSG_OUTSTR(" ");
1658:
1659: n = (int)Columns - 6;
1660: for (j = 0; j < yb->y_size && n > 1; ++j)
1661: {
1662: if (j)
1663: {
1664: MSG_OUTSTR("^J");
1665: n -= 2;
1666: }
1667: for (p = yb->y_array[j]; *p && (n -= charsize(*p)) >= 0; ++p)
1668: msg_outtrans_len(p, 1);
1669: }
1.2 ! downsj 1670: if (n > 1 && yb->y_type == MLINE)
! 1671: MSG_OUTSTR("^J");
1.1 downsj 1672: flushbuf(); /* show one line at a time */
1673: }
1674: }
1675:
1676: /*
1677: * display last inserted text
1678: */
1679: if ((p = get_last_insert()) != NULL &&
1680: (arg == NULL || vim_strchr(arg, '.') != NULL))
1681: {
1682: MSG_OUTSTR("\n\". ");
1683: dis_msg(p, TRUE);
1684: }
1685:
1686: /*
1687: * display last command line
1688: */
1689: if (last_cmdline != NULL && (arg == NULL || vim_strchr(arg, ':') != NULL))
1690: {
1691: MSG_OUTSTR("\n\": ");
1692: dis_msg(last_cmdline, FALSE);
1693: }
1694:
1695: /*
1696: * display current file name
1697: */
1698: if (curbuf->b_xfilename != NULL &&
1699: (arg == NULL || vim_strchr(arg, '%') != NULL))
1700: {
1701: MSG_OUTSTR("\n\"% ");
1702: dis_msg(curbuf->b_xfilename, FALSE);
1703: }
1704: }
1705:
1706: /*
1707: * display a string for do_dis()
1708: * truncate at end of screen line
1709: */
1710: void
1711: dis_msg(p, skip_esc)
1712: char_u *p;
1713: int skip_esc; /* if TRUE, ignore trailing ESC */
1714: {
1715: int n;
1716:
1717: n = (int)Columns - 6;
1718: while (*p && !(*p == ESC && skip_esc && *(p + 1) == NUL) &&
1719: (n -= charsize(*p)) >= 0)
1720: msg_outtrans_len(p++, 1);
1721: }
1722:
1723: /*
1724: * join 'count' lines (minimal 2), including u_save()
1725: */
1726: void
1727: do_do_join(count, insert_space, redraw)
1728: long count;
1729: int insert_space;
1730: int redraw; /* can redraw, curwin->w_col valid */
1731: {
1732: if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
1733: (linenr_t)(curwin->w_cursor.lnum + count)) == FAIL)
1734: return;
1735:
1736: if (count > 10)
1737: redraw = FALSE; /* don't redraw each small change */
1738: while (--count > 0)
1739: {
1740: line_breakcheck();
1741: if (got_int || do_join(insert_space, redraw) == FAIL)
1742: {
1743: beep_flush();
1744: break;
1745: }
1746: }
1747: if (redraw)
1748: redraw_later(VALID_TO_CURSCHAR);
1749: else
1750: redraw_later(NOT_VALID);
1751:
1752: /*
1753: * Need to update the screen if the line where the cursor is became too
1754: * long to fit on the screen.
1755: */
1756: cursupdate();
1757: }
1758:
1759: /*
1760: * Join two lines at the cursor position.
1761: *
1762: * return FAIL for failure, OK ohterwise
1763: */
1764: int
1765: do_join(insert_space, redraw)
1766: int insert_space;
1767: int redraw; /* should only be TRUE when curwin->w_row valid */
1768: {
1769: char_u *curr;
1770: char_u *next;
1771: char_u *newp;
1772: int endcurr1, endcurr2;
1773: int currsize; /* size of the current line */
1774: int nextsize; /* size of the next line */
1775: int spaces; /* number of spaces to insert */
1776: int rows_to_del = 0;/* number of rows on screen to delete */
1777: linenr_t t;
1778:
1779: if (curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)
1780: return FAIL; /* can't join on last line */
1781:
1782: if (redraw)
1783: rows_to_del = plines_m(curwin->w_cursor.lnum,
1784: curwin->w_cursor.lnum + 1);
1785:
1786: curr = ml_get_curline();
1787: currsize = STRLEN(curr);
1788: endcurr1 = endcurr2 = NUL;
1789: if (currsize > 0)
1790: {
1791: endcurr1 = *(curr + currsize - 1);
1792: if (currsize > 1)
1793: endcurr2 = *(curr + currsize - 2);
1794: }
1795:
1796: next = ml_get((linenr_t)(curwin->w_cursor.lnum + 1));
1797: spaces = 0;
1798: if (insert_space)
1799: {
1800: next = skipwhite(next);
1801: spaces = 1;
1802: if (*next == ')' || currsize == 0)
1803: spaces = 0;
1804: else
1805: {
1806: if (endcurr1 == ' ' || endcurr1 == TAB)
1807: {
1808: spaces = 0;
1809: if (currsize > 1)
1810: endcurr1 = endcurr2;
1811: }
1812: if (p_js && vim_strchr((char_u *)".!?", endcurr1) != NULL)
1813: spaces = 2;
1814: }
1815: }
1816: nextsize = STRLEN(next);
1817:
1818: newp = alloc_check((unsigned)(currsize + nextsize + spaces + 1));
1819: if (newp == NULL)
1820: return FAIL;
1821:
1822: /*
1823: * Insert the next line first, because we already have that pointer.
1824: * Curr has to be obtained again, because getting next will have
1825: * invalidated it.
1826: */
1827: vim_memmove(newp + currsize + spaces, next, (size_t)(nextsize + 1));
1828:
1829: curr = ml_get_curline();
1830: vim_memmove(newp, curr, (size_t)currsize);
1831:
1832: copy_spaces(newp + currsize, (size_t)spaces);
1833:
1834: ml_replace(curwin->w_cursor.lnum, newp, FALSE);
1835:
1836: /*
1837: * Delete the following line. To do this we move the cursor there
1838: * briefly, and then move it back. After dellines() the cursor may
1839: * have moved up (last line deleted), so the current lnum is kept in t.
1840: */
1841: t = curwin->w_cursor.lnum;
1842: ++curwin->w_cursor.lnum;
1843: dellines(1L, FALSE, FALSE);
1844: curwin->w_cursor.lnum = t;
1845:
1846: /*
1847: * the number of rows on the screen is reduced by the difference
1848: * in number of rows of the two old lines and the one new line
1849: */
1850: if (redraw)
1851: {
1852: rows_to_del -= plines(curwin->w_cursor.lnum);
1853: if (rows_to_del > 0)
1854: win_del_lines(curwin, curwin->w_cline_row + curwin->w_cline_height,
1855: rows_to_del, TRUE, TRUE);
1856: }
1857:
1858: /*
1859: * go to first character of the joined line
1860: */
1861: if (currsize == 0)
1862: curwin->w_cursor.col = 0;
1863: else
1864: {
1865: curwin->w_cursor.col = currsize - 1;
1866: (void)oneright();
1867: }
1868: CHANGED;
1869:
1870: return OK;
1871: }
1872:
1873: /*
1874: * Return TRUE if the two comment leaders given are the same. The cursor is
1875: * in the first line. White-space is ignored. Note that the whole of
1876: * 'leader1' must match 'leader2_len' characters from 'leader2' -- webb
1877: */
1878: static int
1879: same_leader(leader1_len, leader1_flags, leader2_len, leader2_flags)
1880: int leader1_len;
1881: char_u *leader1_flags;
1882: int leader2_len;
1883: char_u *leader2_flags;
1884: {
1885: int idx1 = 0, idx2 = 0;
1886: char_u *p;
1887: char_u *line1;
1888: char_u *line2;
1889:
1890: if (leader1_len == 0)
1891: return (leader2_len == 0);
1892:
1893: /*
1894: * If first leader has 'f' flag, the lines can be joined only if the
1895: * second line does not have a leader.
1896: * If first leader has 'e' flag, the lines can never be joined.
1897: * If fist leader has 's' flag, the lines can only be joined if there is
1898: * some text after it and the second line has the 'm' flag.
1899: */
1900: if (leader1_flags != NULL)
1901: {
1902: for (p = leader1_flags; *p && *p != ':'; ++p)
1903: {
1904: if (*p == COM_FIRST)
1905: return (leader2_len == 0);
1906: if (*p == COM_END)
1907: return FALSE;
1908: if (*p == COM_START)
1909: {
1910: if (*(ml_get_curline() + leader1_len) == NUL)
1911: return FALSE;
1912: if (leader2_flags == NULL || leader2_len == 0)
1913: return FALSE;
1914: for (p = leader2_flags; *p && *p != ':'; ++p)
1915: if (*p == COM_MIDDLE)
1916: return TRUE;
1917: return FALSE;
1918: }
1919: }
1920: }
1921:
1922: /*
1923: * Get current line and next line, compare the leaders.
1924: * The first line has to be saved, only one line can be locked at a time.
1925: */
1926: line1 = strsave(ml_get_curline());
1927: if (line1 != NULL)
1928: {
1929: for (idx1 = 0; vim_iswhite(line1[idx1]); ++idx1)
1930: ;
1931: line2 = ml_get(curwin->w_cursor.lnum + 1);
1932: for (idx2 = 0; idx2 < leader2_len; ++idx2)
1933: {
1934: if (!vim_iswhite(line2[idx2]))
1935: {
1936: if (line1[idx1++] != line2[idx2])
1937: break;
1938: }
1939: else
1940: while (vim_iswhite(line1[idx1]))
1941: ++idx1;
1942: }
1943: vim_free(line1);
1944: }
1945: return (idx2 == leader2_len && idx1 == leader1_len);
1946: }
1947:
1948: /*
1949: * implementation of the format operator 'Q'
1950: */
1951: void
1952: do_format()
1953: {
1954: long old_line_count = curbuf->b_ml.ml_line_count;
1955: int prev_is_blank = FALSE;
1956: int is_end_block = TRUE;
1957: int next_is_end_block;
1958: int leader_len = 0; /* init for gcc */
1959: int next_leader_len;
1960: char_u *leader_flags = NULL;
1961: char_u *next_leader_flags;
1962: int advance = TRUE;
1963: int second_indent = -1;
1964: int do_second_indent;
1965: int first_par_line = TRUE;
1966:
1967: if (u_save((linenr_t)(curwin->w_cursor.lnum - 1),
1968: (linenr_t)(curwin->w_cursor.lnum + op_line_count)) == FAIL)
1969: return;
1970:
1971: /* check for 'q' and '2' in 'formatoptions' */
1972: fo_do_comments = has_format_option(FO_Q_COMS);
1973: do_second_indent = has_format_option(FO_Q_SECOND);
1974:
1975: /*
1976: * get info about the previous and current line.
1977: */
1978: if (curwin->w_cursor.lnum > 1)
1979: is_end_block = fmt_end_block(curwin->w_cursor.lnum - 1,
1980: &next_leader_len, &next_leader_flags);
1981: next_is_end_block = fmt_end_block(curwin->w_cursor.lnum,
1982: &next_leader_len, &next_leader_flags);
1983:
1984: curwin->w_cursor.lnum--;
1985: while (--op_line_count >= 0)
1986: {
1987: /*
1988: * Advance to next block.
1989: */
1990: if (advance)
1991: {
1992: curwin->w_cursor.lnum++;
1993: prev_is_blank = is_end_block;
1994: is_end_block = next_is_end_block;
1995: leader_len = next_leader_len;
1996: leader_flags = next_leader_flags;
1997: }
1998:
1999: /*
2000: * The last line to be formatted.
2001: */
2002: if (op_line_count == 0)
2003: {
2004: next_is_end_block = TRUE;
2005: next_leader_len = 0;
2006: next_leader_flags = NULL;
2007: }
2008: else
2009: next_is_end_block = fmt_end_block(curwin->w_cursor.lnum + 1,
2010: &next_leader_len, &next_leader_flags);
2011: advance = TRUE;
2012:
2013: /*
2014: * For the first line of a paragraph, check indent of second line.
2015: * Don't do this for comments and empty lines.
2016: */
2017: if (first_par_line && do_second_indent &&
2018: prev_is_blank && !is_end_block &&
2019: curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count &&
2020: leader_len == 0 && next_leader_len == 0 &&
2021: !lineempty(curwin->w_cursor.lnum + 1))
2022: second_indent = get_indent_lnum(curwin->w_cursor.lnum + 1);
2023:
2024: /*
2025: * Skip end-of-block (blank) lines
2026: */
2027: if (is_end_block)
2028: {
2029: }
2030: /*
2031: * If we have got to the end of a paragraph, format it.
2032: */
2033: else if (next_is_end_block || !same_leader(leader_len, leader_flags,
2034: next_leader_len, next_leader_flags))
2035: {
2036: /* replace indent in first line with minimal number of tabs and
2037: * spaces, according to current options */
2038: set_indent(get_indent(), TRUE);
2039:
2040: /* put cursor on last non-space */
2041: coladvance(MAXCOL);
2042: while (curwin->w_cursor.col && vim_isspace(gchar_cursor()))
2043: dec_cursor();
2044: curs_columns(FALSE); /* update curwin->w_virtcol */
2045:
2046: /* do the formatting */
2047: State = INSERT; /* for Opencmd() */
2048: insertchar(NUL, TRUE, second_indent);
2049: State = NORMAL;
2050: first_par_line = TRUE;
2051: second_indent = -1;
2052: }
2053: else
2054: {
2055: /*
2056: * Still in same paragraph, so join the lines together.
2057: * But first delete the comment leader from the second line.
2058: */
2059: advance = FALSE;
2060: curwin->w_cursor.lnum++;
2061: curwin->w_cursor.col = 0;
2062: while (next_leader_len--)
2063: delchar(FALSE);
2064: curwin->w_cursor.lnum--;
2065: if (do_join(TRUE, FALSE) == FAIL)
2066: {
2067: beep_flush();
2068: break;
2069: }
2070: first_par_line = FALSE;
2071: }
2072: }
2073: fo_do_comments = FALSE;
2074: /*
2075: * Leave the cursor at the first non-blank of the last formatted line.
2076: * If the cursor was move one line back (e.g. with "Q}") go to the next
2077: * line, so "." will do the next lines.
2078: */
2079: if (op_end_adjusted && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count)
2080: ++curwin->w_cursor.lnum;
2081: beginline(TRUE);
2082: updateScreen(NOT_VALID);
2083: msgmore(curbuf->b_ml.ml_line_count - old_line_count);
2084: }
2085:
2086: /*
2087: * Blank lines, and lines containing only the comment leader, are left
2088: * untouched by the formatting. The function returns TRUE in this
2089: * case. It also returns TRUE when a line starts with the end of a comment
2090: * ('e' in comment flags), so that this line is skipped, and not joined to the
2091: * previous line. A new paragraph starts after a blank line, or when the
2092: * comment leader changes -- webb.
2093: */
2094: static int
2095: fmt_end_block(lnum, leader_len, leader_flags)
2096: linenr_t lnum;
2097: int *leader_len;
2098: char_u **leader_flags;
2099: {
2100: char_u *flags = NULL; /* init for GCC */
2101: char_u *ptr;
2102:
2103: ptr = ml_get(lnum);
2104: *leader_len = get_leader_len(ptr, leader_flags);
2105:
2106: if (*leader_len > 0)
2107: {
2108: /*
2109: * Search for 'e' flag in comment leader flags.
2110: */
2111: flags = *leader_flags;
2112: while (*flags && *flags != ':' && *flags != COM_END)
2113: ++flags;
2114: }
2115:
2116: return (ptr[*leader_len] == NUL ||
2117: (*leader_len > 0 && *flags == COM_END) ||
2118: startPS(lnum, NUL, FALSE));
2119: }
2120:
2121: /*
2122: * prepare a few things for block mode yank/delete/tilde
2123: *
2124: * for delete:
2125: * - textlen includes the first/last char to be (partly) deleted
2126: * - start/endspaces is the number of columns that are taken by the
2127: * first/last deleted char minus the number of columns that have to be deleted.
2128: * for yank and tilde:
2129: * - textlen includes the first/last char to be wholly yanked
2130: * - start/endspaces is the number of columns of the first/last yanked char
2131: * that are to be yanked.
2132: */
2133: static void
2134: block_prep(bd, lnum, is_del)
2135: struct block_def *bd;
2136: linenr_t lnum;
2137: int is_del;
2138: {
2139: colnr_t vcol;
2140: int incr = 0;
2141: char_u *pend;
2142: char_u *pstart;
2143:
2144: bd->startspaces = 0;
2145: bd->endspaces = 0;
2146: bd->textlen = 0;
2147: bd->textcol = 0;
2148: vcol = 0;
2149: pstart = ml_get(lnum);
2150: while (vcol < op_start_vcol && *pstart)
2151: {
2152: /* Count a tab for what it's worth (if list mode not on) */
2153: incr = lbr_chartabsize(pstart, (colnr_t)vcol);
2154: vcol += incr;
2155: ++pstart;
2156: ++bd->textcol;
2157: }
2158: if (vcol < op_start_vcol) /* line too short */
2159: {
2160: if (!is_del)
2161: bd->endspaces = op_end_vcol - op_start_vcol + 1;
2162: }
2163: else /* vcol >= op_start_vcol */
2164: {
2165: bd->startspaces = vcol - op_start_vcol;
2166: if (is_del && vcol > op_start_vcol)
2167: bd->startspaces = incr - bd->startspaces;
2168: pend = pstart;
2169: if (vcol > op_end_vcol) /* it's all in one character */
2170: {
2171: bd->startspaces = op_end_vcol - op_start_vcol + 1;
2172: if (is_del)
2173: bd->startspaces = incr - bd->startspaces;
2174: }
2175: else
2176: {
2177: while (vcol <= op_end_vcol && *pend)
2178: {
2179: /* Count a tab for what it's worth (if list mode not on) */
2180: incr = lbr_chartabsize(pend, (colnr_t)vcol);
2181: vcol += incr;
2182: ++pend;
2183: }
2184: if (vcol < op_end_vcol && !is_del) /* line too short */
2185: {
2186: bd->endspaces = op_end_vcol - vcol;
2187: }
2188: else if (vcol > op_end_vcol)
2189: {
2190: bd->endspaces = vcol - op_end_vcol - 1;
2191: if (!is_del && pend != pstart && bd->endspaces)
2192: --pend;
2193: }
2194: }
2195: if (is_del && bd->startspaces)
2196: {
2197: --pstart;
2198: --bd->textcol;
2199: }
2200: bd->textlen = (int)(pend - pstart);
2201: }
2202: bd->textstart = pstart;
2203: }
2204:
2205: #define NUMBUFLEN 30
2206:
2207: /*
2208: * add or subtract 'Prenum1' from a number in a line
2209: * 'command' is CTRL-A for add, CTRL-X for subtract
2210: *
2211: * return FAIL for failure, OK otherwise
2212: */
2213: int
2214: do_addsub(command, Prenum1)
2215: int command;
2216: linenr_t Prenum1;
2217: {
2218: register int col;
2219: char_u buf[NUMBUFLEN];
2220: int hex; /* 'X': hexadecimal; '0': octal */
2221: static int hexupper = FALSE; /* 0xABC */
2222: long n;
2223: char_u *ptr;
2224: int i;
2225: int c;
2226: int zeros = 0; /* number of leading zeros */
2227: int digits = 0; /* number of digits in the number */
2228:
2229: ptr = ml_get_curline();
2230: col = curwin->w_cursor.col;
2231:
2232: /* first check if we are on a hexadecimal number */
2233: while (col > 0 && isxdigit(ptr[col]))
2234: --col;
2235: if (col > 0 && (ptr[col] == 'X' || ptr[col] == 'x') &&
2236: ptr[col - 1] == '0' && isxdigit(ptr[col + 1]))
2237: --col; /* found hexadecimal number */
2238: else
2239: {
2240: /* first search forward and then backward for start of number */
2241: col = curwin->w_cursor.col;
2242:
2243: while (ptr[col] != NUL && !isdigit(ptr[col]))
2244: ++col;
2245:
2246: while (col > 0 && isdigit(ptr[col - 1]))
2247: --col;
2248: }
2249:
2250: if (isdigit(ptr[col]) && u_save_cursor() == OK)
2251: {
2252: ptr = ml_get_curline(); /* get it again, because
2253: u_save may have changed it */
2254: curwin->w_set_curswant = TRUE;
2255:
2256: hex = 0; /* default is decimal */
2257: if (ptr[col] == '0') /* could be hex or octal */
2258: {
2259: hex = TO_UPPER(ptr[col + 1]); /* assume hexadecimal */
2260: if (hex != 'X' || !isxdigit(ptr[col + 2]))
2261: {
2262: if (isdigit(hex))
2263: hex = '0'; /* octal */
2264: else
2265: hex = 0; /* 0 by itself is decimal */
2266: }
2267: }
2268:
2269: if (!hex && col > 0 && ptr[col - 1] == '-')
2270: --col;
2271:
2272: ptr += col;
2273: /*
2274: * we copy the number into a buffer because some versions of sscanf
2275: * cannot handle characters with the upper bit set, making some special
2276: * characters handled like digits.
2277: */
2278: for (i = 0; *ptr && !(*ptr & 0x80) && i < NUMBUFLEN - 1; ++i)
2279: buf[i] = *ptr++;
2280: buf[i] = NUL;
2281:
2282: if (hex == '0')
2283: sscanf((char *)buf, "%lo", &n);
2284: else if (hex)
2285: sscanf((char *)buf + 2, "%lx", &n); /* "%X" doesn't work! */
2286: else
2287: n = atol((char *)buf);
2288:
2289: if (command == Ctrl('A'))
2290: n += Prenum1;
2291: else
2292: n -= Prenum1;
2293:
2294: if (hex == 'X') /* skip the '0x' */
2295: col += 2;
2296: else if (hex == '0')
2297: col++; /* skip the '0' */
2298: curwin->w_cursor.col = col;
2299:
2300: c = gchar_cursor();
2301: do /* delete the old number */
2302: {
2303: if (digits == 0 && c == '0')
2304: ++zeros; /* count the number of leading zeros */
2305: else
2306: ++digits; /* count the number of digits */
2307: if (isalpha(c))
2308: {
2309: if (isupper(c))
2310: hexupper = TRUE;
2311: else
2312: hexupper = FALSE;
2313: }
2314: (void)delchar(FALSE);
2315: c = gchar_cursor();
2316: }
2317: while (hex ? (hex == '0' ? c >= '0' && c <= '7' :
2318: isxdigit(c)) : isdigit(c));
2319:
2320: if (hex == 0)
2321: sprintf((char *)buf, "%ld", n);
2322: else
2323: {
2324: if (hex == '0')
2325: sprintf((char *)buf, "%lo", n);
2326: else if (hex && hexupper)
2327: sprintf((char *)buf, "%lX", n);
2328: else if (hex)
2329: sprintf((char *)buf, "%lx", n);
2330: /* adjust number of zeros to the new number of digits, so the
2331: * total length of the number remains the same */
2332: if (zeros)
2333: {
2334: zeros += digits - STRLEN(buf);
2335: if (zeros > 0)
2336: {
2337: vim_memmove(buf + zeros, buf, STRLEN(buf) + 1);
2338: for (col = 0; zeros > 0; --zeros)
2339: buf[col++] = '0';
2340: }
2341: }
2342: }
2343: ins_str(buf); /* insert the new number */
2344: --curwin->w_cursor.col;
2345: updateline();
2346: return OK;
2347: }
2348: else
2349: {
2350: beep_flush();
2351: return FAIL;
2352: }
2353: }
2354:
2355: #ifdef VIMINFO
2356: int
2357: read_viminfo_register(line, fp, force)
2358: char_u *line;
2359: FILE *fp;
2360: int force;
2361: {
2362: int eof;
2363: int do_it = TRUE;
2364: int size;
2365: int limit;
2366: int i;
2367: int set_prev = FALSE;
2368: char_u *str;
2369: char_u **array = NULL;
2370:
2371: /* We only get here (hopefully) if line[0] == '"' */
2372: str = line + 1;
2373: if (*str == '"')
2374: {
2375: set_prev = TRUE;
2376: str++;
2377: }
2378: if (!isalnum(*str) && *str != '-')
2379: {
1.2 ! downsj 2380: if (viminfo_error("Illegal register name", line))
! 2381: return TRUE; /* too many errors, pretend end-of-file */
1.1 downsj 2382: do_it = FALSE;
2383: }
2384: yankbuffer = *str++;
2385: get_yank_buffer(FALSE);
2386: yankbuffer = 0;
2387: if (!force && y_current->y_array != NULL)
2388: do_it = FALSE;
2389: size = 0;
2390: limit = 100; /* Optimized for registers containing <= 100 lines */
2391: if (do_it)
2392: {
2393: if (set_prev)
2394: y_previous = y_current;
2395: vim_free(y_current->y_array);
2396: array = y_current->y_array =
2397: (char_u **)alloc((unsigned)(limit * sizeof(char_u *)));
2398: str = skipwhite(str);
2399: if (STRNCMP(str, "CHAR", 4) == 0)
2400: y_current->y_type = MCHAR;
2401: else if (STRNCMP(str, "BLOCK", 5) == 0)
2402: y_current->y_type = MBLOCK;
2403: else
2404: y_current->y_type = MLINE;
2405: }
2406: while (!(eof = vim_fgets(line, LSIZE, fp)) && line[0] == TAB)
2407: {
2408: if (do_it)
2409: {
2410: if (size >= limit)
2411: {
2412: y_current->y_array = (char_u **)
2413: alloc((unsigned)(limit * 2 * sizeof(char_u *)));
2414: for (i = 0; i < limit; i++)
2415: y_current->y_array[i] = array[i];
2416: vim_free(array);
2417: limit *= 2;
2418: array = y_current->y_array;
2419: }
2420: viminfo_readstring(line);
2421: str = strsave(line + 1);
2422: if (str != NULL)
2423: array[size++] = str;
2424: else
2425: do_it = FALSE;
2426: }
2427: }
2428: if (do_it)
2429: {
2430: if (size == 0)
2431: {
2432: vim_free(array);
2433: y_current->y_array = NULL;
2434: }
2435: else if (size < limit)
2436: {
2437: y_current->y_array =
2438: (char_u **)alloc((unsigned)(size * sizeof(char_u *)));
2439: for (i = 0; i < size; i++)
2440: y_current->y_array[i] = array[i];
2441: vim_free(array);
2442: }
2443: y_current->y_size = size;
2444: }
2445: return eof;
2446: }
2447:
2448: void
2449: write_viminfo_registers(fp)
2450: FILE *fp;
2451: {
2452: int i, j;
2453: char_u *type;
2454: char_u c;
2455: int num_lines;
2456: int max_num_lines;
2457:
2458: fprintf(fp, "\n# Registers:\n");
2459:
2460: max_num_lines = get_viminfo_parameter('"');
2461: if (max_num_lines == 0)
2462: return;
2463: for (i = 0; i < NUM_REGISTERS; i++)
2464: {
2465: if (y_buf[i].y_array == NULL)
2466: continue;
2467: #ifdef USE_GUI
2468: /* Skip '*' register, we don't want it back next time */
2469: if (i == GUI_SELECTION_REGISTER)
2470: continue;
2471: #endif
2472: switch (y_buf[i].y_type)
2473: {
2474: case MLINE:
2475: type = (char_u *)"LINE";
2476: break;
2477: case MCHAR:
2478: type = (char_u *)"CHAR";
2479: break;
2480: case MBLOCK:
2481: type = (char_u *)"BLOCK";
2482: break;
2483: default:
2484: sprintf((char *)IObuff, "Unknown register type %d",
2485: y_buf[i].y_type);
2486: emsg(IObuff);
2487: type = (char_u *)"LINE";
2488: break;
2489: }
2490: if (y_previous == &y_buf[i])
2491: fprintf(fp, "\"");
2492: if (i == DELETION_REGISTER)
2493: c = '-';
2494: else if (i < 10)
2495: c = '0' + i;
2496: else
2497: c = 'a' + i - 10;
2498: fprintf(fp, "\"%c\t%s\n", c, type);
2499: num_lines = y_buf[i].y_size;
2500:
2501: /* If max_num_lines < 0, then we save ALL the lines in the register */
2502: if (max_num_lines > 0 && num_lines > max_num_lines)
2503: num_lines = max_num_lines;
2504: for (j = 0; j < num_lines; j++)
2505: {
2506: putc('\t', fp);
2507: viminfo_writestring(fp, y_buf[i].y_array[j]);
2508: }
2509: }
2510: }
2511: #endif /* VIMINFO */
2512:
2513: #if defined(USE_GUI) || defined(PROTO)
2514: /*
2515: * Text selection stuff that uses the GUI selection register '*'. When using a
2516: * GUI this may be text from another window, otherwise it is the last text we
2517: * had highlighted with VIsual mode. With mouse support, clicking the middle
2518: * button performs the paste, otherwise you will need to do <"*p>.
2519: */
2520:
2521: void
2522: gui_free_selection()
2523: {
2524: struct yankbuf *y_ptr = y_current;
2525:
2526: y_current = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
2527: free_yank_all();
2528: y_current->y_size = 0;
2529: y_current = y_ptr;
2530: }
2531:
2532: /*
2533: * Get the selected text and put it in the gui text register '*'.
2534: */
2535: void
2536: gui_get_selection()
2537: {
2538: struct yankbuf *old_y_previous, *old_y_current;
2539: char_u old_yankbuffer;
2540: FPOS old_cursor, old_visual;
2541: int old_op_type;
2542:
2543: if (gui.selection.owned)
2544: {
2545: if (y_buf[GUI_SELECTION_REGISTER].y_array != NULL)
2546: return;
2547:
2548: /* Get the text between gui.selection.start & gui.selection.end */
2549: old_y_previous = y_previous;
2550: old_y_current = y_current;
2551: old_yankbuffer = yankbuffer;
2552: old_cursor = curwin->w_cursor;
2553: old_visual = VIsual;
2554: old_op_type = op_type;
2555: yankbuffer = '*';
2556: op_type = YANK;
2557: do_pending_operator('y', NUL, FALSE, NULL, NULL, 0, TRUE, TRUE);
2558: y_previous = old_y_previous;
2559: y_current = old_y_current;
2560: yankbuffer = old_yankbuffer;
2561: curwin->w_cursor = old_cursor;
2562: VIsual = old_visual;
2563: op_type = old_op_type;
2564: }
2565: else
2566: {
2567: gui_free_selection();
2568:
2569: /* Try to get selected text from another window */
2570: gui_request_selection();
2571: }
2572: }
2573:
2574: /* Convert from the GUI selection string into the '*' register */
2575: void
2576: gui_yank_selection(type, str, len)
2577: int type;
2578: char_u *str;
2579: long_u len;
2580: {
2581: struct yankbuf *y_ptr = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
2582: int lnum;
2583: int start;
2584: int i;
2585:
2586: gui_free_selection();
2587:
2588: /* Count the number of lines within the string */
2589: y_ptr->y_size = 1;
2590: for (i = 0; i < len; i++)
2591: if (str[i] == '\n')
2592: y_ptr->y_size++;
2593:
2594: if (type != MCHAR && i > 0 && str[i - 1] == '\n')
2595: y_ptr->y_size--;
2596:
2597: y_ptr->y_array = (char_u **)lalloc(y_ptr->y_size * sizeof(char_u *), TRUE);
2598: if (y_ptr->y_array == NULL)
2599: return;
2600: y_ptr->y_type = type;
2601: lnum = 0;
2602: start = 0;
2603: for (i = 0; i < len; i++)
2604: {
2605: if (str[i] == NUL)
2606: str[i] = '\n';
2607: else if (str[i] == '\n')
2608: {
2609: str[i] = NUL;
2610: if (type == MCHAR || i != len - 1)
2611: {
2612: if ((y_ptr->y_array[lnum] = strsave(str + start)) == NULL)
2613: {
2614: y_ptr->y_size = lnum;
2615: return;
2616: }
2617: lnum++;
2618: start = i + 1;
2619: }
2620: }
2621: }
2622: if ((y_ptr->y_array[lnum] = alloc(i - start + 1)) == NULL)
2623: return;
2624: if (i - start > 0)
2625: STRNCPY(y_ptr->y_array[lnum], str + start, i - start);
2626: y_ptr->y_array[lnum][i - start] = NUL;
2627: y_ptr->y_size = lnum + 1;
2628: }
2629:
2630: /*
2631: * Convert the '*' register into a GUI selection string returned in *str with
2632: * length *len.
2633: */
2634: int
2635: gui_convert_selection(str, len)
2636: char_u **str;
2637: long_u *len;
2638: {
2639: struct yankbuf *y_ptr = &y_buf[GUI_SELECTION_REGISTER]; /* '*' register */
2640: char_u *p;
2641: int lnum;
2642: int i, j;
2643:
2644: *str = NULL;
2645: *len = 0;
2646: if (y_ptr->y_array == NULL)
2647: return -1;
2648:
2649: for (i = 0; i < y_ptr->y_size; i++)
2650: *len += STRLEN(y_ptr->y_array[i]) + 1;
2651:
2652: /*
2653: * Don't want newline character at end of last line if we're in MCHAR mode.
2654: */
2655: if (y_ptr->y_type == MCHAR && *len > 1)
2656: (*len)--;
2657:
2658: p = *str = lalloc(*len, TRUE);
2659: if (p == NULL)
2660: return -1;
2661: lnum = 0;
2662: for (i = 0, j = 0; i < *len; i++, j++)
2663: {
2664: if (y_ptr->y_array[lnum][j] == '\n')
2665: p[i] = NUL;
2666: else if (y_ptr->y_array[lnum][j] == NUL)
2667: {
2668: p[i] = '\n';
2669: lnum++;
2670: j = -1;
2671: }
2672: else
2673: p[i] = y_ptr->y_array[lnum][j];
2674: }
2675: return y_ptr->y_type;
2676: }
2677: #endif /* USE_GUI || PROTO */