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: }

Defined functions

DEFSIMPLE defined in line 50; never used
DEFUN defined in line 493; never used
ToCol defined in line 118; used 1 times
current_column defined in line 50; used 10 times
pos_tab_offset defined in line 385; used 12 times
position_indentation defined in line 189; used 6 times
syms_of_indent defined in line 519; used 1 times
vmotion defined in line 406; used 8 times

Defined variables

indent_tabs_mode defined in line 32; used 3 times
last_known_column defined in line 42; used 4 times
last_known_column_modified defined in line 46; used 4 times
last_known_column_point defined in line 44; used 5 times
val_compute_motion defined in line 261; used 7 times
val_vmotion defined in line 404; used 6 times

Defined macros

CR defined in line 30; used 1 times
HPOS defined in line 277; used 9 times
VPOS defined in line 280; used 2 times
max defined in line 35; never used
min defined in line 34; used 2 times
Last modified: 1986-04-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1022
Valid CSS Valid XHTML 1.0 Strict