|
|
1.1 ! root 1: /* Indentation functions. ! 2: Copyright (C) 1985 Richard M. Stallman. ! 3: ! 4: This file is part of GNU Emacs. ! 5: ! 6: GNU Emacs is distributed in the hope that it will be useful, ! 7: but WITHOUT ANY WARRANTY. No author or distributor ! 8: accepts responsibility to anyone for the consequences of using it ! 9: or for whether it serves any particular purpose or works at all, ! 10: unless he says so in writing. Refer to the GNU Emacs General Public ! 11: License for full details. ! 12: ! 13: Everyone is granted permission to copy, modify and redistribute ! 14: GNU Emacs, but only under the conditions described in the ! 15: GNU Emacs General Public License. A copy of this license is ! 16: supposed to have been given to you along with GNU Emacs so you ! 17: can know your rights and responsibilities. It should be in a ! 18: file named COPYING. Among other things, the copyright notice ! 19: and this notice must be preserved on all copies. */ ! 20: ! 21: ! 22: #include "config.h" ! 23: #include "lisp.h" ! 24: #include "buffer.h" ! 25: #include "indent.h" ! 26: #include "window.h" ! 27: #include "termchar.h" ! 28: #include "termopts.h" ! 29: ! 30: #define CR '\015' ! 31: ! 32: int indent_tabs_mode; ! 33: ! 34: #define min(a, b) ((a) < (b) ? (a) : (b)) ! 35: #define max(a, b) ((a) > (b) ? (a) : (b)) ! 36: ! 37: /* These three values memoize the current column to avoid recalculation */ ! 38: /* Some things in buflow.c set last_known_column_point to -1 ! 39: to mark the memoized value as invalid */ ! 40: ! 41: /* Last value returned by current_column */ ! 42: int last_known_column; ! 43: /* Value of point when current_column was called */ ! 44: int last_known_column_point; ! 45: /* Value of bf_modified when current_column was called */ ! 46: int last_known_column_modified; ! 47: ! 48: extern int minibuf_prompt_width; ! 49: ! 50: DEFSIMPLE ("current-column", Fcurrent_column, Scurrent_column, ! 51: "Return the horizontal position of point. The left margin is column 0.\n\ ! 52: Ignores finite width of screen,", ! 53: Lisp_Int, XSETINT, current_column ()) ! 54: ! 55: current_column () ! 56: { ! 57: register int col; ! 58: register unsigned char *ptr, *stop, c; ! 59: register int tab_seen; ! 60: register int post_tab; ! 61: register int tab_width = XINT (bf_cur->tab_width); ! 62: int ctl_arrow = !NULL (bf_cur->ctl_arrow); ! 63: ! 64: if (point == last_known_column_point ! 65: && bf_modified == last_known_column_modified) ! 66: return last_known_column; ! 67: ! 68: ptr = &CharAt (point - 1) + 1; ! 69: stop = point <= bf_s1 + 1 ? bf_p1 + 1 : bf_p2 + bf_s1 + 1; ! 70: if (tab_width <= 0) tab_width = 1; ! 71: ! 72: col = 0, tab_seen = 0, post_tab = 0; ! 73: ! 74: while (1) ! 75: { ! 76: if (ptr == stop) ! 77: { ! 78: if (ptr == bf_p1 + 1) ! 79: break; ! 80: stop = bf_p1 + 1; ! 81: ptr = stop + bf_s1; ! 82: if (!bf_s1) break; ! 83: } ! 84: ! 85: c = *--ptr; ! 86: if (c >= 040 && c < 0177) ! 87: { ! 88: col++; ! 89: } ! 90: else if (c == '\n') ! 91: break; ! 92: else if (c == '\t') ! 93: { ! 94: if (tab_seen) ! 95: col = ((col + tab_width) / tab_width) * tab_width; ! 96: ! 97: post_tab += col; ! 98: col = 0; ! 99: tab_seen = 1; ! 100: } ! 101: else ! 102: col += (ctl_arrow && c < 0200) ? 2 : 4; ! 103: } ! 104: ! 105: if (tab_seen) ! 106: { ! 107: col = ((col + tab_width) / tab_width) * tab_width; ! 108: col += post_tab; ! 109: } ! 110: ! 111: last_known_column = col; ! 112: last_known_column_point = point; ! 113: last_known_column_modified = bf_modified; ! 114: ! 115: return col; ! 116: } ! 117: ! 118: ToCol (col) ! 119: int col; ! 120: { ! 121: register int fromcol = current_column (); ! 122: register int n; ! 123: register int tab_width = XINT (bf_cur->tab_width); ! 124: ! 125: if (fromcol > col) ! 126: return; ! 127: ! 128: if (tab_width <= 0) tab_width = 1; ! 129: ! 130: if (indent_tabs_mode) ! 131: { ! 132: n = col / tab_width - fromcol / tab_width; ! 133: if (n) ! 134: { ! 135: while (n-- > 0) ! 136: InsCStr ("\t", 1); ! 137: ! 138: fromcol = (col / tab_width) * tab_width; ! 139: } ! 140: } ! 141: ! 142: while (fromcol < col) ! 143: { ! 144: InsCStr (" ", min (8, col - fromcol)); ! 145: fromcol += min (8, col - fromcol); ! 146: } ! 147: ! 148: last_known_column = col; ! 149: last_known_column_point = point; ! 150: last_known_column_modified = bf_modified; ! 151: } ! 152: ! 153: DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "nIndent to column: ", ! 154: "Indent from point with tabs and spaces until COLUMN is reached.\n\ ! 155: Always do at least MIN spaces even if that goes past COLUMN;\n\ ! 156: by default, MIN is zero.") ! 157: (col, minimum) ! 158: Lisp_Object col, minimum; ! 159: { ! 160: int mincol; ! 161: ! 162: CHECK_NUMBER (col, 0); ! 163: if (NULL (minimum)) ! 164: XFASTINT (minimum) = 0; ! 165: CHECK_NUMBER (minimum, 1); ! 166: ! 167: mincol = current_column () + XINT (minimum); ! 168: if (mincol < XINT (col)) mincol = XINT (col); ! 169: ! 170: ToCol (mincol); ! 171: ! 172: XSETINT (col, mincol); ! 173: return col; ! 174: } ! 175: ! 176: DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation, ! 177: 0, 0, 0, ! 178: "Return the indentation of the current line.\n\ ! 179: This is the horizontal position of the character\n\ ! 180: following any initial whitespace.") ! 181: () ! 182: { ! 183: Lisp_Object val; ! 184: ! 185: XFASTINT (val) = position_indentation (ScanBf ('\n', point, -1)); ! 186: return val; ! 187: } ! 188: ! 189: position_indentation (pos) ! 190: register int pos; ! 191: { ! 192: register int col = 0; ! 193: register int c; ! 194: register int end = NumCharacters + 1; ! 195: register int tab_width = XINT (bf_cur->tab_width); ! 196: ! 197: if (tab_width <= 0) tab_width = 1; ! 198: ! 199: while (pos < end && ! 200: (c = CharAt (pos), ! 201: c == '\t' ? (col += tab_width - col % tab_width) ! 202: : (c == ' ' ? ++col : 0))) ! 203: pos++; ! 204: ! 205: return col; ! 206: } ! 207: ! 208: DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 1, 0, ! 209: "Move point to column COLUMN in the current line.\n\ ! 210: Does not change the text, only point.\n\ ! 211: Ignores finite width of screen.") ! 212: (column) ! 213: Lisp_Object column; ! 214: { ! 215: register int pos = point; ! 216: register int col = current_column (); ! 217: register int goal; ! 218: register int end = NumCharacters; ! 219: register int tab_width = XINT (bf_cur->tab_width); ! 220: register int ctl_arrow = !NULL (bf_cur->ctl_arrow); ! 221: ! 222: Lisp_Object val; ! 223: ! 224: if (tab_width <= 0) tab_width = 1; ! 225: CHECK_NUMBER (column, 0); ! 226: goal = XINT (column); ! 227: if (col > goal) ! 228: { ! 229: pos = ScanBf ('\n', pos, -1); ! 230: col = 0; ! 231: } ! 232: ! 233: while (col < goal && pos <= end) ! 234: { ! 235: char c = CharAt (pos); ! 236: if (c == '\n') ! 237: break; ! 238: pos++; ! 239: col++; ! 240: if (c == '\t') ! 241: { ! 242: col += tab_width - 1; ! 243: col = col / tab_width * tab_width; ! 244: } ! 245: else if (ctl_arrow && (c < 040 || c == 0177)) ! 246: col++; ! 247: else if (c < 040 || c >= 0177) ! 248: col += 3; ! 249: } ! 250: ! 251: SetPoint (pos); ! 252: ! 253: last_known_column = col; ! 254: last_known_column_point = point; ! 255: last_known_column_modified = bf_modified; ! 256: ! 257: XFASTINT (val) = col; ! 258: return val; ! 259: } ! 260: ! 261: struct position val_compute_motion; ! 262: ! 263: struct position * ! 264: compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset) ! 265: int from, fromvpos, fromhpos, to, tovpos, tohpos; ! 266: register int width; ! 267: int hscroll, tab_offset; ! 268: { ! 269: /* Note that cpos is CURRENT_VPOS << SHORTBITS + CURRENT_HPOS, ! 270: and the CURRENT_HPOS may be negative. Use these macros ! 271: to extract the hpos or the vpos from cpos or anything like it. */ ! 272: #ifdef celerity ! 273: /* On the Celerity, the usual definition fails to work. ! 274: This definition (which ought to be equivalent) does work. */ ! 275: #define HPOS(VAR) (((VAR) & 0x8000 ? 0xffff0000 : 0) | ((VAR) & 0xffff)) ! 276: #else ! 277: #define HPOS(VAR) (short) (VAR) ! 278: #endif ! 279: ! 280: #define VPOS(VAR) (((VAR) >> SHORTBITS) + (HPOS (VAR) < 0)) ! 281: ! 282: #ifndef TAHOE_REGISTER_BUG ! 283: register ! 284: #endif /* TAHOE_REGISTER_BUG */ ! 285: int cpos = fromhpos + (fromvpos << SHORTBITS); ! 286: register int target = tohpos + (tovpos << SHORTBITS); ! 287: register int pos; ! 288: register int c; ! 289: register int tab_width = XFASTINT (bf_cur->tab_width); ! 290: register int ctl_arrow = !NULL (bf_cur->ctl_arrow); ! 291: int selective ! 292: = XTYPE (bf_cur->selective_display) == Lisp_Int ! 293: ? XINT (bf_cur->selective_display) ! 294: : !NULL (bf_cur->selective_display) ? -1 : 0; ! 295: int prevpos; ! 296: struct position val; ! 297: ! 298: if (tab_width <= 0) tab_width = 1; ! 299: for (pos = from; pos < to && cpos < target; pos++) ! 300: { ! 301: prevpos = cpos; ! 302: c = CharAt (pos); ! 303: if (c >= 040 && c < 0177) ! 304: cpos++; ! 305: else if (c == '\t') ! 306: { ! 307: cpos += tab_width ! 308: - HPOS (cpos + tab_offset + hscroll - (hscroll > 0) ! 309: /* Add tab_width here to make sure positive. ! 310: cpos can be negative after continuation ! 311: but can't be less than -tab_width. */ ! 312: + tab_width) ! 313: % tab_width; ! 314: } ! 315: else if (c == '\n') ! 316: { ! 317: if (selective > 0 && position_indentation (pos + 1) >= selective) ! 318: { ! 319: /* Skip any number of invisible lines all at once */ ! 320: do ! 321: { ! 322: while (++pos < to && CharAt(pos) != '\n'); ! 323: } ! 324: while (selective > 0 && position_indentation (pos + 1) >= selective); ! 325: pos--; ! 326: /* Allow for the " ..." that is displayed for them. */ ! 327: cpos += 4; ! 328: if (HPOS (cpos) >= width) ! 329: cpos -= HPOS (cpos) - width; ! 330: } ! 331: else ! 332: cpos += (1 << SHORTBITS) - HPOS (cpos); ! 333: cpos -= hscroll; ! 334: if (hscroll > 0) cpos++; /* Count the ! on column 0 */ ! 335: tab_offset = 0; ! 336: } ! 337: else if (c == CR && selective < 0) ! 338: { ! 339: /* In selective display mode, ! 340: everything from a ^M to the end of the line is invisible */ ! 341: while (pos < to && CharAt(pos) != '\n') pos++; ! 342: pos--; ! 343: } ! 344: else ! 345: cpos += (ctl_arrow && c < 0200) ? 2 : 4; ! 346: ! 347: if (HPOS (cpos) >= width ! 348: && (HPOS (cpos) > width ! 349: || (pos < NumCharacters ! 350: && CharAt (pos + 1) != '\n'))) ! 351: { ! 352: if (cpos >= target) ! 353: break; ! 354: if (hscroll ! 355: || (truncate_partial_width_windows ! 356: && width + 1 < screen_width) ! 357: || !NULL (bf_cur->truncate_lines)) ! 358: { ! 359: while (pos < to && CharAt(pos) != '\n') pos++; ! 360: pos--; ! 361: } ! 362: else ! 363: { ! 364: cpos += (1 << SHORTBITS) - width; ! 365: tab_offset += width; ! 366: } ! 367: ! 368: } ! 369: } ! 370: ! 371: val_compute_motion.bufpos = pos; ! 372: val_compute_motion.hpos = HPOS (cpos); ! 373: val_compute_motion.vpos = VPOS (cpos); ! 374: val_compute_motion.prevhpos = HPOS (prevpos); ! 375: ! 376: /* Nonzero if have just continued a line */ ! 377: val_compute_motion.contin ! 378: = pos != from ! 379: && (val_compute_motion.vpos != VPOS (prevpos)) ! 380: && c != '\n'; ! 381: ! 382: return &val_compute_motion; ! 383: } ! 384: ! 385: pos_tab_offset (w, pos) ! 386: struct window *w; ! 387: register int pos; ! 388: { ! 389: int opoint = point; ! 390: int col; ! 391: ! 392: if (pos == FirstCharacter || CharAt (pos - 1) == '\n') ! 393: return 0; ! 394: SetPoint (pos); ! 395: col = current_column (); ! 396: SetPoint (opoint); ! 397: return col - (col % (XFASTINT (w->width) - 1)); ! 398: } ! 399: ! 400: /* start_hpos is the hpos of the first character of the buffer: ! 401: zero except for the minibuffer window, ! 402: where it is the width of the prompt. */ ! 403: ! 404: struct position val_vmotion; ! 405: ! 406: struct position * ! 407: vmotion (from, vtarget, width, hscroll, window) ! 408: register int from, vtarget, width; ! 409: int hscroll; ! 410: Lisp_Object window; ! 411: { ! 412: struct position pos; ! 413: /* vpos is cumulative vertical position, changed as from is changed */ ! 414: register int vpos = 0; ! 415: register int prevline; ! 416: register int first; ! 417: int lmargin = hscroll > 0 ? 1 - hscroll : 0; ! 418: int selective ! 419: = XTYPE (bf_cur->selective_display) == Lisp_Int ! 420: ? XINT (bf_cur->selective_display) ! 421: : !NULL (bf_cur->selective_display) ? -1 : 0; ! 422: int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0); ! 423: ! 424: retry: ! 425: if (vtarget > vpos) ! 426: { ! 427: /* Moving downward is simple, but must calculate from beg of line ! 428: to determine hpos of starting point */ ! 429: if (from > FirstCharacter && CharAt (from - 1) != '\n') ! 430: { ! 431: prevline = ScanBf ('\n', from, -1); ! 432: while (selective > 0 ! 433: && prevline > FirstCharacter ! 434: && position_indentation (prevline) >= selective) ! 435: prevline = ScanBf ('\n', prevline - 1, -1); ! 436: pos = *compute_motion (prevline, 0, ! 437: lmargin + (prevline == 1 ? start_hpos : 0), ! 438: from, 10000, 10000, ! 439: width, hscroll, 0); ! 440: } ! 441: else ! 442: { ! 443: pos.hpos = lmargin + (from == 1 ? start_hpos : 0); ! 444: pos.vpos = 0; ! 445: } ! 446: return compute_motion (from, vpos, pos.hpos, ! 447: 1 + NumCharacters, vtarget, - (1 << (SHORTBITS - 1)), ! 448: width, hscroll, pos.vpos * width); ! 449: } ! 450: ! 451: /* To move upward, go a line at a time until ! 452: we have gone at least far enough */ ! 453: ! 454: first = 1; ! 455: ! 456: while ((vpos > vtarget || first) && from > FirstCharacter) ! 457: { ! 458: prevline = from; ! 459: while (1) ! 460: { ! 461: prevline = ScanBf ('\n', prevline - 1, -1); ! 462: if (prevline == FirstCharacter ! 463: || selective <= 0 ! 464: || position_indentation (prevline) < selective) ! 465: break; ! 466: } ! 467: pos = *compute_motion (prevline, 0, ! 468: lmargin + (prevline == 1 ? start_hpos : 0), ! 469: from, 10000, 10000, ! 470: width, hscroll, 0); ! 471: vpos -= pos.vpos; ! 472: first = 0; ! 473: from = prevline; ! 474: } ! 475: ! 476: /* If we made exactly the desired vertical distance, ! 477: or if we hit beginning of buffer, ! 478: return point found */ ! 479: if (vpos >= vtarget) ! 480: { ! 481: val_vmotion.bufpos = from; ! 482: val_vmotion.vpos = vpos; ! 483: val_vmotion.hpos = lmargin; ! 484: val_vmotion.contin = 0; ! 485: val_vmotion.prevhpos = 0; ! 486: return &val_vmotion; ! 487: } ! 488: ! 489: /* Otherwise find the correct spot by moving down */ ! 490: goto retry; ! 491: } ! 492: ! 493: DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 1, 0, ! 494: "Move to start of screen line LINES lines down.\n\ ! 495: If LINES is negative, this is moving up.\n\ ! 496: Sets point to position found; this may be start of line\n\ ! 497: or just the start of a continuation line.\n\ ! 498: Returns number of lines moved; may be closer to zero than LINES\n\ ! 499: if end of buffer was reached.") ! 500: (lines) ! 501: Lisp_Object lines; ! 502: { ! 503: struct position pos; ! 504: register struct window *w = XWINDOW (selected_window); ! 505: ! 506: CHECK_NUMBER (lines, 0); ! 507: ! 508: pos = *vmotion (point, XINT (lines), ! 509: XFASTINT (w->width) - 1 ! 510: - (XFASTINT (w->width) + XFASTINT (w->left) ! 511: != XFASTINT (XWINDOW (minibuf_window)->width)), ! 512: /* Not XFASTINT since perhaps could be negative */ ! 513: XINT (w->hscroll), selected_window); ! 514: ! 515: SetPoint (pos.bufpos); ! 516: return make_number (pos.vpos); ! 517: } ! 518: ! 519: syms_of_indent () ! 520: { ! 521: DefBoolVar ("indent-tabs-mode", &indent_tabs_mode, ! 522: "*Indentation can insert tabs if this is non-nil."); ! 523: indent_tabs_mode = 1; ! 524: ! 525: defsubr (&Scurrent_indentation); ! 526: defsubr (&Sindent_to); ! 527: defsubr (&Scurrent_column); ! 528: defsubr (&Smove_to_column); ! 529: defsubr (&Svertical_motion); ! 530: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.