Annotation of 43BSD/contrib/emacs/src/indent.c, revision 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.