Annotation of 43BSD/contrib/emacs/src/indent.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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