Annotation of 43BSDReno/contrib/emacs-18.55/src/indent.c, revision 1.1.1.1

1.1       root        1: /* Indentation functions.
                      2:    Copyright (C) 1985, 1986, 1987, 1988 Free Software Foundation, Inc.
                      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: /* Indentation can insert tabs if this is non-zero;
                     33:    otherwise always uses spaces */
                     34: int indent_tabs_mode;
                     35: 
                     36: #define min(a, b) ((a) < (b) ? (a) : (b))
                     37: #define max(a, b) ((a) > (b) ? (a) : (b))
                     38: 
                     39: /* These three values memoize the current column to avoid recalculation */
                     40: /* Some things in set last_known_column_point to -1
                     41:   to mark the memoized value as invalid */
                     42: /* Last value returned by current_column */
                     43: int last_known_column;
                     44: /* Value of point when current_column was called */
                     45: int last_known_column_point;
                     46: /* Value of bf_modified when current_column was called */
                     47: int last_known_column_modified;
                     48: 
                     49: extern int minibuf_prompt_width;
                     50: 
                     51: DEFSIMPLE ("current-column", Fcurrent_column, Scurrent_column,
                     52:   "Return the horizontal position of point.  Beginning of line is column 0.\n\
                     53: This is calculated by adding together the widths of all the displayed\n\
                     54: representations of the character between the start of the previous line\n\
                     55: and point.  (eg control characters will have a width of 2 or 4, tabs\n\
                     56: will have a variable width)\n\
                     57: Ignores finite width of screen, which means that this function may return\n\
                     58: values greater than (screen-width).\n\
                     59: Whether the line is visible (if `selective-display' is t) has no effect.",
                     60:   Lisp_Int, XSETINT, current_column ())
                     61: 
                     62: int
                     63: current_column ()
                     64: {
                     65:   register int col;
                     66:   register unsigned char *ptr, *stop, c;
                     67:   register int tab_seen;
                     68:   register int post_tab;
                     69:   register int tab_width = XINT (bf_cur->tab_width);
                     70:   int ctl_arrow = !NULL (bf_cur->ctl_arrow);
                     71: 
                     72:   if (point == last_known_column_point
                     73:       && bf_modified == last_known_column_modified)
                     74:     return last_known_column;
                     75: 
                     76:   ptr = &CharAt (point - 1) + 1;
                     77:   stop = point <= bf_s1 + 1 ? bf_p1 + 1 : bf_p2 + bf_s1 + 1;
                     78:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                     79: 
                     80:   col = 0, tab_seen = 0, post_tab = 0;
                     81: 
                     82:   while (1)
                     83:     {
                     84:       if (ptr == stop)
                     85:        {
                     86:          if (ptr == bf_p1 + 1)
                     87:            break;
                     88:          stop = bf_p1 + 1;
                     89:          ptr = stop + bf_s1;
                     90:          if (!bf_s1) break;
                     91:        }
                     92: 
                     93:       c = *--ptr;
                     94:       if (c >= 040 && c < 0177)
                     95:        {
                     96:          col++;
                     97:        }
                     98:       else if (c == '\n')
                     99:        break;
                    100:       else if (c == '\r' && EQ (bf_cur->selective_display, Qt))
                    101:        break;
                    102:       else if (c == '\t')
                    103:        {
                    104:          if (tab_seen)
                    105:            col = ((col + tab_width) / tab_width) * tab_width;
                    106: 
                    107:          post_tab += col;
                    108:          col = 0;
                    109:          tab_seen = 1;
                    110:        }
                    111:       else
                    112:        col += (ctl_arrow && c < 0200) ? 2 : 4;
                    113:     }
                    114: 
                    115:   if (tab_seen)
                    116:     {
                    117:       col = ((col + tab_width) / tab_width) * tab_width;
                    118:       col += post_tab;
                    119:     }
                    120: 
                    121:   last_known_column = col;
                    122:   last_known_column_point = point;
                    123:   last_known_column_modified = bf_modified;
                    124: 
                    125:   return col;
                    126: }
                    127: 
                    128: ToCol (col)
                    129:      int col;
                    130: {
                    131:   register int fromcol = current_column ();
                    132:   register int n;
                    133:   register int tab_width = XINT (bf_cur->tab_width);
                    134: 
                    135:   if (fromcol > col)
                    136:     return;
                    137: 
                    138:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                    139: 
                    140:   if (indent_tabs_mode)
                    141:     {
                    142:       n = col / tab_width - fromcol / tab_width;
                    143:       if (n)
                    144:        {
                    145:          while (n-- > 0)
                    146:            InsCStr ("\t", 1);
                    147: 
                    148:          fromcol = (col / tab_width) * tab_width;
                    149:        }
                    150:     }
                    151: 
                    152:   while (fromcol < col)
                    153:     {
                    154:       InsCStr ("        ", min (8, col - fromcol));
                    155:       fromcol += min (8, col - fromcol);
                    156:     }
                    157: 
                    158:   last_known_column = col;
                    159:   last_known_column_point = point;
                    160:   last_known_column_modified = bf_modified;
                    161: }
                    162: 
                    163: DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
                    164:   "Indent from point with tabs and spaces until COLUMN is reached.\n\
                    165: Always do at least MIN spaces even if that goes past COLUMN;\n\
                    166: by default, MIN is zero.")
                    167:   (col, minimum)
                    168:      Lisp_Object col, minimum;
                    169: {
                    170:   int mincol;
                    171: 
                    172:   CHECK_NUMBER (col, 0);
                    173:   if (NULL (minimum))
                    174:     XFASTINT (minimum) = 0;
                    175:   CHECK_NUMBER (minimum, 1);
                    176: 
                    177:   mincol = current_column () + XINT (minimum);
                    178:   if (mincol < XINT (col)) mincol = XINT (col);
                    179: 
                    180:   ToCol (mincol);
                    181: 
                    182:   XSETINT (col, mincol);
                    183:   return col;
                    184: }
                    185: 
                    186: DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
                    187:   0, 0, 0,
                    188:   "Return the indentation of the current line.\n\
                    189: This is the horizontal position of the character\n\
                    190: following any initial whitespace.")
                    191:   ()
                    192: {
                    193:   Lisp_Object val;
                    194: 
                    195:   XFASTINT (val) = position_indentation (find_next_newline (point, -1));
                    196:   return val;
                    197: }
                    198: 
                    199: position_indentation (pos)
                    200:      register int pos;
                    201: {
                    202:   register int col = 0;
                    203:   register int c;
                    204:   register int end = NumCharacters + 1;
                    205:   register int tab_width = XINT (bf_cur->tab_width);
                    206: 
                    207:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                    208: 
                    209:   while (pos < end &&
                    210:         (c = CharAt (pos),
                    211:          c == '\t' ? (col += tab_width - col % tab_width)
                    212:            : (c == ' ' ? ++col : 0)))
                    213:     pos++;
                    214: 
                    215:   return col;
                    216: }
                    217: 
                    218: DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 1, 0,
                    219:   "Move point to column COLUMN in the current line.\n\
                    220: COLUMN is calculated by adding together the widths of all the displayed\n\
                    221: representations of the character between the start of the previous line\n\
                    222: and point.  (eg control characters will have a width of 2 or 4, tabs\n\
                    223: will have a variable width)\n\
                    224: Ignores finite width of screen, which means that this function may be\n\
                    225: passed values greater than (screen-width)")
                    226:   (column)
                    227:      Lisp_Object column;
                    228: {
                    229:   register int pos = point;
                    230:   register int col = current_column ();
                    231:   register int goal;
                    232:   register int end = NumCharacters;
                    233:   register int tab_width = XINT (bf_cur->tab_width);
                    234:   register int ctl_arrow = !NULL (bf_cur->ctl_arrow);
                    235: 
                    236:   Lisp_Object val;
                    237: 
                    238:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                    239:   CHECK_NUMBER (column, 0);
                    240:   goal = XINT (column);
                    241:   if (col > goal)
                    242:     {
                    243:       pos = find_next_newline (pos, -1);
                    244:       col = 0;
                    245:     }
                    246: 
                    247:   while (col < goal && pos <= end)
                    248:     {
                    249:       int c = CharAt (pos);
                    250:       if (c == '\n')
                    251:        break;
                    252:       if (c == '\r' && EQ (bf_cur->selective_display, Qt))
                    253:        break;
                    254:       pos++;
                    255:       col++;
                    256:       if (c == '\t')
                    257:        {
                    258:          col += tab_width - 1;
                    259:          col = col / tab_width * tab_width;
                    260:        }
                    261:       else if (ctl_arrow && (c < 040 || c == 0177))
                    262:         col++;
                    263:       else if (c < 040 || c >= 0177)
                    264:         col += 3;
                    265:     }
                    266: 
                    267:   SetPoint (pos);
                    268: 
                    269:   last_known_column = col;
                    270:   last_known_column_point = point;
                    271:   last_known_column_modified = bf_modified;
                    272: 
                    273:   XFASTINT (val) = col;
                    274:   return val;
                    275: }
                    276: 
                    277: struct position val_compute_motion;
                    278: 
                    279: struct position *
                    280: compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset)
                    281:      int from, fromvpos, fromhpos, to, tovpos, tohpos;
                    282:      register int width;
                    283:      int hscroll, tab_offset;
                    284: {
                    285: /* Note that `cpos' is CURRENT_VPOS << SHORTBITS + CURRENT_HPOS,
                    286:    and that CURRENT_HPOS may be negative.  Use these macros
                    287:    to extract the hpos or the vpos from cpos or anything like it.
                    288:  */
                    289: #ifndef SHORT_CAST_BUG
                    290: #define HPOS(VAR) (short) (VAR)
                    291: #else
                    292: #define HPOS(VAR) (((VAR) & (1 << (SHORTBITS - 1)) \
                    293:                    ? ~((1 << SHORTBITS) - 1) : 0) \
                    294:                   | (VAR) & ((1 << SHORTBITS) - 1))
                    295: /* #define HPOS(VAR) (((VAR) & 0x8000 ? 0xffff0000 : 0) | ((VAR) & 0xffff)) */
                    296: #endif /* SHORT_CAST_BUG */
                    297: 
                    298: #define VPOS(VAR) (((VAR) >> SHORTBITS) + (HPOS (VAR) < 0))
                    299: 
                    300: 
                    301: #ifndef TAHOE_REGISTER_BUG
                    302:   register
                    303: #endif /* TAHOE_REGISTER_BUG */
                    304:     int cpos = fromhpos + (fromvpos << SHORTBITS);
                    305:   register int target = tohpos + (tovpos << SHORTBITS);
                    306:   register int pos;
                    307:   register int c;
                    308:   register int tab_width = XFASTINT (bf_cur->tab_width);
                    309:   register int ctl_arrow = !NULL (bf_cur->ctl_arrow);
                    310:   int selective
                    311:     = XTYPE (bf_cur->selective_display) == Lisp_Int
                    312:       ? XINT (bf_cur->selective_display)
                    313:        : !NULL (bf_cur->selective_display) ? -1 : 0;
                    314:   int prevpos;
                    315: 
                    316:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                    317:   for (pos = from; pos < to && cpos < target; pos++)
                    318:     {
                    319:       prevpos = cpos;
                    320:       c = CharAt (pos);
                    321:       if (c >= 040 && c < 0177)
                    322:        cpos++;
                    323:       else if (c == '\t')
                    324:        {
                    325:          cpos += tab_width
                    326:            - HPOS (cpos + tab_offset + hscroll - (hscroll > 0)
                    327:                    /* Add tab_width here to make sure positive.
                    328:                       cpos can be negative after continuation
                    329:                       but can't be less than -tab_width.  */
                    330:                    + tab_width)
                    331:              % tab_width;
                    332:        }
                    333:       else if (c == '\n')
                    334:        {
                    335:          if (selective > 0 && position_indentation (pos + 1) >= selective)
                    336:            {
                    337:              /* Skip any number of invisible lines all at once */
                    338:              do
                    339:                {
                    340:                  while (++pos < to && CharAt(pos) != '\n');
                    341:                }
                    342:              while (selective > 0 && position_indentation (pos + 1) >= selective);
                    343:              pos--;
                    344:              /* Allow for the " ..." that is displayed for them. */
                    345:              if (!NULL (bf_cur->selective_display_ellipses))
                    346:                {
                    347:                  cpos += 4;
                    348:                  if (HPOS (cpos) >= width)
                    349:                    cpos -= HPOS (cpos) - width;
                    350:                }
                    351:            }
                    352:          else
                    353:            cpos += (1 << SHORTBITS) - HPOS (cpos);
                    354:          cpos -= hscroll;
                    355:          if (hscroll > 0) cpos++; /* Count the ! on column 0 */
                    356:          tab_offset = 0;
                    357:        }
                    358:       else if (c == CR && selective < 0)
                    359:        {
                    360:          /* In selective display mode,
                    361:             everything from a ^M to the end of the line is invisible */
                    362:          while (pos < to && CharAt(pos) != '\n') pos++;
                    363:          pos--;
                    364:          /* Allow for the " ..." that is displayed for them. */
                    365:          if (!NULL (bf_cur->selective_display_ellipses))
                    366:            {
                    367:              cpos += 4;
                    368:              if (HPOS (cpos) >= width)
                    369:                cpos -= HPOS (cpos) - width;
                    370:            }
                    371:        }
                    372:       else
                    373:        cpos += (ctl_arrow && c < 0200) ? 2 : 4;
                    374: 
                    375:       if (HPOS (cpos) >= width
                    376:          && (HPOS (cpos) > width
                    377:              || (pos < NumCharacters
                    378:                  && CharAt (pos + 1) != '\n')))
                    379:        {
                    380:          if (cpos >= target)
                    381:            break;
                    382:          if (hscroll
                    383:              || (truncate_partial_width_windows
                    384:                  && width + 1 < screen_width)
                    385:              || !NULL (bf_cur->truncate_lines))
                    386:            {
                    387:              while (pos < to && CharAt(pos) != '\n') pos++;
                    388:              pos--;
                    389:            }
                    390:          else
                    391:            {
                    392:              cpos += (1 << SHORTBITS) - width;
                    393:              tab_offset += width;
                    394:            }
                    395: 
                    396:        }
                    397:     }
                    398: 
                    399:   val_compute_motion.bufpos = pos;
                    400:   val_compute_motion.hpos = HPOS (cpos);
                    401:   val_compute_motion.vpos = VPOS (cpos);
                    402:   val_compute_motion.prevhpos = HPOS (prevpos);
                    403: 
                    404:   /* Nonzero if have just continued a line */
                    405:   val_compute_motion.contin
                    406:     = pos != from
                    407:       && (val_compute_motion.vpos != VPOS (prevpos))
                    408:       && c != '\n';
                    409: 
                    410:   return &val_compute_motion;
                    411: }
                    412: #undef HPOS
                    413: #undef VPOS
                    414: 
                    415: 
                    416: pos_tab_offset (w, pos)
                    417:      struct window *w;
                    418:      register int pos;
                    419: {
                    420:   int opoint = point;
                    421:   int col;
                    422: 
                    423:   if (pos == FirstCharacter || CharAt (pos - 1) == '\n')
                    424:     return 0;
                    425:   SetPoint (pos);
                    426:   col = current_column ();
                    427:   SetPoint (opoint);
                    428:   return col - (col % (XFASTINT (w->width) - 1));
                    429: }
                    430: 
                    431: /* start_hpos is the hpos of the first character of the buffer:
                    432:    zero except for the minibuffer window,
                    433:    where it is the width of the prompt.  */
                    434: 
                    435: struct position val_vmotion;
                    436: 
                    437: struct position *
                    438: vmotion (from, vtarget, width, hscroll, window)
                    439:      register int from, vtarget, width;
                    440:      int hscroll;
                    441:      Lisp_Object window;
                    442: {
                    443:   struct position pos;
                    444:   /* vpos is cumulative vertical position, changed as from is changed */
                    445:   register int vpos = 0;
                    446:   register int prevline;
                    447:   register int first;
                    448:   int lmargin = hscroll > 0 ? 1 - hscroll : 0;
                    449:   int selective
                    450:     = XTYPE (bf_cur->selective_display) == Lisp_Int
                    451:       ? XINT (bf_cur->selective_display)
                    452:        : !NULL (bf_cur->selective_display) ? -1 : 0;
                    453:   int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0);
                    454: 
                    455:  retry:
                    456:   if (vtarget > vpos)
                    457:     {
                    458:       /* Moving downward is simple, but must calculate from beg of line 
                    459:         to determine hpos of starting point */
                    460:       if (from > FirstCharacter && CharAt (from - 1) != '\n')
                    461:        {
                    462:          prevline = find_next_newline (from, -1);
                    463:          while (selective > 0
                    464:                 && prevline > FirstCharacter
                    465:                 && position_indentation (prevline) >= selective)
                    466:            prevline = find_next_newline (prevline - 1, -1);
                    467:          pos = *compute_motion (prevline, 0,
                    468:                                 lmargin + (prevline == 1 ? start_hpos : 0),
                    469:                                 from, 10000, 10000,
                    470:                                 width, hscroll, 0);
                    471:        }
                    472:       else
                    473:        {
                    474:          pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
                    475:          pos.vpos = 0;
                    476:        }
                    477:       return compute_motion (from, vpos, pos.hpos,
                    478:                             1 + NumCharacters, vtarget, - (1 << (SHORTBITS - 1)),
                    479:                             width, hscroll, pos.vpos * width);
                    480:     }
                    481: 
                    482:   /* To move upward, go a line at a time until
                    483:      we have gone at least far enough */
                    484: 
                    485:   first = 1;
                    486: 
                    487:   while ((vpos > vtarget || first) && from > FirstCharacter)
                    488:     {
                    489:       prevline = from;
                    490:       while (1)
                    491:        {
                    492:          prevline = find_next_newline (prevline - 1, -1);
                    493:          if (prevline == FirstCharacter
                    494:              || selective <= 0
                    495:              || position_indentation (prevline) < selective)
                    496:            break;
                    497:        }
                    498:       pos = *compute_motion (prevline, 0,
                    499:                             lmargin + (prevline == 1 ? start_hpos : 0),
                    500:                             from, 10000, 10000,
                    501:                             width, hscroll, 0);
                    502:       vpos -= pos.vpos;
                    503:       first = 0;
                    504:       from = prevline;
                    505:     }
                    506: 
                    507:   /* If we made exactly the desired vertical distance,
                    508:      or if we hit beginning of buffer,
                    509:      return point found */
                    510:   if (vpos >= vtarget)
                    511:     {
                    512:       val_vmotion.bufpos = from;
                    513:       val_vmotion.vpos = vpos;
                    514:       val_vmotion.hpos = lmargin;
                    515:       val_vmotion.contin = 0;
                    516:       val_vmotion.prevhpos = 0;
                    517:       return &val_vmotion;
                    518:     }
                    519:   
                    520:   /* Otherwise find the correct spot by moving down */
                    521:   goto retry;
                    522: }
                    523: 
                    524: DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 1, 0,
                    525:   "Move to start of screen line LINES lines down.\n\
                    526: If LINES is negative, this is moving up.\n\
                    527: Sets point to position found; this may be start of line\n\
                    528:  or just the start of a continuation line.\n\
                    529: Returns number of lines moved; may be closer to zero than LINES\n\
                    530:  if beginning or end of buffer was reached.")
                    531:   (lines)
                    532:      Lisp_Object lines;
                    533: {
                    534:   struct position pos;
                    535:   register struct window *w = XWINDOW (selected_window);
                    536: 
                    537:   CHECK_NUMBER (lines, 0);
                    538: 
                    539:   pos = *vmotion (point, XINT (lines),
                    540:                  XFASTINT (w->width) - 1
                    541:                  - (XFASTINT (w->width) + XFASTINT (w->left)
                    542:                     != XFASTINT (XWINDOW (minibuf_window)->width)),
                    543:                  /* Not XFASTINT since perhaps could be negative */
                    544:                  XINT (w->hscroll), selected_window);
                    545: 
                    546:   SetPoint (pos.bufpos);
                    547:   return make_number (pos.vpos);
                    548: }
                    549: 
                    550: syms_of_indent ()
                    551: {
                    552:   DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
                    553:     "*Indentation can insert tabs if this is non-nil.\n\
                    554: Setting this variable automatically makes it local to the current buffer.");
                    555:   indent_tabs_mode = 1;
                    556: 
                    557:   defsubr (&Scurrent_indentation);
                    558:   defsubr (&Sindent_to);
                    559:   defsubr (&Scurrent_column);
                    560:   defsubr (&Smove_to_column);
                    561:   defsubr (&Svertical_motion);
                    562: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.