Annotation of GNUtools/emacs/src/indent.c, revision 1.1.1.1

1.1       root        1: /* Indentation functions.
                      2:    Copyright (C) 1985, 1986, 1987, 1988, 1990 Free Software Foundation, Inc.
                      3: 
                      4: This file is part of GNU Emacs.
                      5: 
                      6: GNU Emacs is free software; you can redistribute it and/or modify
                      7: it under the terms of the GNU General Public License as published by
                      8: the Free Software Foundation; either version 1, or (at your option)
                      9: any later version.
                     10: 
                     11: GNU Emacs is distributed in the hope that it will be useful,
                     12: but WITHOUT ANY WARRANTY; without even the implied warranty of
                     13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     14: GNU General Public License for more details.
                     15: 
                     16: You should have received a copy of the GNU General Public License
                     17: along with GNU Emacs; see the file COPYING.  If not, write to
                     18: the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
                     19: 
                     20: 
                     21: #include "config.h"
                     22: #include "lisp.h"
                     23: #include "buffer.h"
                     24: #include "indent.h"
                     25: #include "window.h"
                     26: #include "termchar.h"
                     27: #include "termopts.h"
                     28: 
                     29: #define CR '\015'
                     30: 
                     31: /* Indentation can insert tabs if this is non-zero;
                     32:    otherwise always uses spaces */
                     33: int indent_tabs_mode;
                     34: 
                     35: #define min(a, b) ((a) < (b) ? (a) : (b))
                     36: #define max(a, b) ((a) > (b) ? (a) : (b))
                     37: 
                     38: /* These three values memoize the current column to avoid recalculation */
                     39: /* Some things in set last_known_column_point to -1
                     40:   to mark the memoized value as invalid */
                     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 MODIFF when current_column was called */
                     46: int last_known_column_modified;
                     47: 
                     48: extern int minibuf_prompt_width;
                     49: 
                     50: DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
                     51:   "Return the horizontal position of point.  Beginning of line is column 0.\n\
                     52: This is calculated by adding together the widths of all the displayed\n\
                     53: representations of the character between the start of the previous line\n\
                     54: and point.  (eg control characters will have a width of 2 or 4, tabs\n\
                     55: will have a variable width)\n\
                     56: Ignores finite width of screen, which means that this function may return\n\
                     57: values greater than (screen-width).\n\
                     58: Whether the line is visible (if `selective-display' is t) has no effect.")
                     59:   ()
                     60: {
                     61:   Lisp_Object temp;
                     62:   XFASTINT (temp) = current_column ();
                     63:   return temp;
                     64: }
                     65: 
                     66: /* Cancel any recorded value of the horizontal position.  */
                     67: 
                     68: invalidate_current_column ()
                     69: {
                     70:   last_known_column_point = 0;
                     71: }
                     72: 
                     73: int
                     74: current_column ()
                     75: {
                     76:   register int col;
                     77:   register unsigned char *ptr, *stop, c;
                     78:   register int tab_seen;
                     79:   register int post_tab;
                     80:   register int tab_width = XINT (current_buffer->tab_width);
                     81:   int ctl_arrow = !NULL (current_buffer->ctl_arrow);
                     82: 
                     83:   if (point == last_known_column_point
                     84:       && MODIFF == last_known_column_modified)
                     85:     return last_known_column;
                     86: 
                     87:   /* Make a pointer for decrementing through the chars before point.  */
                     88:   ptr = &FETCH_CHAR (point - 1) + 1;
                     89:   /* Make a pointer to where consecutive chars leave off,
                     90:      going backwards from point.  */
                     91:   if (point == BEGV)
                     92:     stop = ptr;
                     93:   else if (point <= GPT || BEGV > GPT)
                     94:     stop = BEGV_ADDR;
                     95:   else
                     96:     stop = GAP_END_ADDR;
                     97: 
                     98:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                     99: 
                    100:   col = 0, tab_seen = 0, post_tab = 0;
                    101: 
                    102:   while (1)
                    103:     {
                    104:       if (ptr == stop)
                    105:        {
                    106:          /* We stopped either for the beginning of the buffer
                    107:             or for the gap.  */
                    108:          if (ptr == BEGV_ADDR)
                    109:            break;
                    110:          /* It was the gap.  Jump back over it.  */
                    111:          stop = BEGV_ADDR;
                    112:          ptr = GPT_ADDR;
                    113:          /* Check whether that brings us to beginning of buffer.  */
                    114:          if (BEGV >= GPT) break;
                    115:        }
                    116: 
                    117:       c = *--ptr;
                    118:       if (c >= 040 && c < 0177)
                    119:        {
                    120:          col++;
                    121:        }
                    122:       else if (c == '\n')
                    123:        break;
                    124:       else if (c == '\r' && EQ (current_buffer->selective_display, Qt))
                    125:        break;
                    126:       else if (c == '\t')
                    127:        {
                    128:          if (tab_seen)
                    129:            col = ((col + tab_width) / tab_width) * tab_width;
                    130: 
                    131:          post_tab += col;
                    132:          col = 0;
                    133:          tab_seen = 1;
                    134:        }
                    135:       else
                    136:        col += (ctl_arrow && c < 0200) ? 2 : 4;
                    137:     }
                    138: 
                    139:   if (tab_seen)
                    140:     {
                    141:       col = ((col + tab_width) / tab_width) * tab_width;
                    142:       col += post_tab;
                    143:     }
                    144: 
                    145:   last_known_column = col;
                    146:   last_known_column_point = point;
                    147:   last_known_column_modified = MODIFF;
                    148: 
                    149:   return col;
                    150: }
                    151: 
                    152: ToCol (col)
                    153:      int col;
                    154: {
                    155:   register int fromcol = current_column ();
                    156:   register int n;
                    157:   register int tab_width = XINT (current_buffer->tab_width);
                    158: 
                    159:   if (fromcol > col)
                    160:     return;
                    161: 
                    162:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                    163: 
                    164:   if (indent_tabs_mode)
                    165:     {
                    166:       n = col / tab_width - fromcol / tab_width;
                    167:       if (n)
                    168:        {
                    169:          while (n-- > 0)
                    170:            insert ("\t", 1);
                    171: 
                    172:          fromcol = (col / tab_width) * tab_width;
                    173:        }
                    174:     }
                    175: 
                    176:   while (fromcol < col)
                    177:     {
                    178:       insert ("        ", min (8, col - fromcol));
                    179:       fromcol += min (8, col - fromcol);
                    180:     }
                    181: 
                    182:   last_known_column = col;
                    183:   last_known_column_point = point;
                    184:   last_known_column_modified = MODIFF;
                    185: }
                    186: 
                    187: DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
                    188:   "Indent from point with tabs and spaces until COLUMN is reached.\n\
                    189: Always do at least MIN spaces even if that goes past COLUMN;\n\
                    190: by default, MIN is zero.")
                    191:   (col, minimum)
                    192:      Lisp_Object col, minimum;
                    193: {
                    194:   int mincol;
                    195:   register int fromcol;
                    196:   register int tab_width = XINT (current_buffer->tab_width);
                    197: 
                    198:   CHECK_NUMBER (col, 0);
                    199:   if (NULL (minimum))
                    200:     XFASTINT (minimum) = 0;
                    201:   CHECK_NUMBER (minimum, 1);
                    202: 
                    203:   fromcol = current_column ();
                    204:   mincol = fromcol + XINT (minimum);
                    205:   if (mincol < XINT (col)) mincol = XINT (col);
                    206: 
                    207:   if (fromcol == mincol)
                    208:     return make_number (fromcol);
                    209: 
                    210:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                    211: 
                    212:   if (indent_tabs_mode)
                    213:     {
                    214:       Lisp_Object n;
                    215:       XFASTINT (n) = mincol / tab_width - fromcol / tab_width;
                    216:       if (XFASTINT (n) != 0)
                    217:        {
                    218:          Finsert_char (make_number ('\t'), n);
                    219: 
                    220:          fromcol = (mincol / tab_width) * tab_width;
                    221:        }
                    222:     }
                    223: 
                    224:   XFASTINT (col) = mincol - fromcol;
                    225:   Finsert_char (make_number (' '), col);
                    226: 
                    227:   last_known_column = mincol;
                    228:   last_known_column_point = point;
                    229:   last_known_column_modified = MODIFF;
                    230: 
                    231:   XSETINT (col, mincol);
                    232:   return col;
                    233: }
                    234: 
                    235: DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
                    236:   0, 0, 0,
                    237:   "Return the indentation of the current line.\n\
                    238: This is the horizontal position of the character\n\
                    239: following any initial whitespace.")
                    240:   ()
                    241: {
                    242:   Lisp_Object val;
                    243: 
                    244:   XFASTINT (val) = position_indentation (find_next_newline (point, -1));
                    245:   return val;
                    246: }
                    247: 
                    248: position_indentation (pos)
                    249:      register int pos;
                    250: {
                    251:   register int column = 0;
                    252:   register int tab_width = XINT (current_buffer->tab_width);
                    253:   register unsigned char *p;
                    254:   register unsigned char *stop;
                    255: 
                    256:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                    257: 
                    258:   stop = &FETCH_CHAR (BufferSafeCeiling (pos)) + 1;
                    259:   p = &FETCH_CHAR (pos);
                    260:   while (1)
                    261:     {
                    262:       while (p == stop)
                    263:        {
                    264:          if (pos == ZV)
                    265:            return column;
                    266:          pos += p - &FETCH_CHAR (pos);
                    267:          p = &FETCH_CHAR (pos);
                    268:          stop = &FETCH_CHAR (BufferSafeCeiling (pos)) + 1;
                    269:        }
                    270:       switch (*p++)
                    271:        {
                    272:        case ' ':
                    273:          column++;
                    274:          break;
                    275:        case '\t':
                    276:          column += tab_width - column % tab_width;
                    277:          break;
                    278:        default:
                    279:          return column;
                    280:        }
                    281:     }
                    282: }
                    283: 
                    284: DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 1, 0,
                    285:   "Move point to column COLUMN in the current line.\n\
                    286: COLUMN is calculated by adding together the widths of all the displayed\n\
                    287: representations of the character between the start of the previous line\n\
                    288: and point.  (eg control characters will have a width of 2 or 4, tabs\n\
                    289: will have a variable width)\n\
                    290: Ignores finite width of screen, which means that this function may be\n\
                    291: passed values greater than (screen-width)")
                    292:   (column)
                    293:      Lisp_Object column;
                    294: {
                    295:   register int pos = point;
                    296:   register int col = current_column ();
                    297:   register int goal;
                    298:   register int end = ZV;
                    299:   register int tab_width = XINT (current_buffer->tab_width);
                    300:   register int ctl_arrow = !NULL (current_buffer->ctl_arrow);
                    301: 
                    302:   Lisp_Object val;
                    303: 
                    304:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                    305:   CHECK_NUMBER (column, 0);
                    306:   goal = XINT (column);
                    307:   if (col > goal)
                    308:     {
                    309:       pos = find_next_newline (pos, -1);
                    310:       col = 0;
                    311:     }
                    312: 
                    313:   while (col < goal && pos < end)
                    314:     {
                    315:       int c = FETCH_CHAR (pos);
                    316:       if (c == '\n')
                    317:        break;
                    318:       if (c == '\r' && EQ (current_buffer->selective_display, Qt))
                    319:        break;
                    320:       pos++;
                    321:       col++;
                    322:       if (c == '\t')
                    323:        {
                    324:          col += tab_width - 1;
                    325:          col = col / tab_width * tab_width;
                    326:        }
                    327:       else if (ctl_arrow && (c < 040 || c == 0177))
                    328:         col++;
                    329:       else if (c < 040 || c >= 0177)
                    330:         col += 3;
                    331:     }
                    332: 
                    333:   SET_PT (pos);
                    334: 
                    335:   last_known_column = col;
                    336:   last_known_column_point = point;
                    337:   last_known_column_modified = MODIFF;
                    338: 
                    339:   XFASTINT (val) = col;
                    340:   return val;
                    341: }
                    342: 
                    343: struct position val_compute_motion;
                    344: 
                    345: struct position *
                    346: compute_motion (from, fromvpos, fromhpos, to, tovpos, tohpos, width, hscroll, tab_offset)
                    347:      int from, fromvpos, fromhpos, to, tovpos, tohpos;
                    348:      register int width;
                    349:      int hscroll, tab_offset;
                    350: {
                    351:   register int hpos = fromhpos;
                    352:   register int vpos = fromvpos;
                    353: 
                    354:   register int pos;
                    355:   register int c;
                    356:   register int tab_width = XFASTINT (current_buffer->tab_width);
                    357:   register int ctl_arrow = !NULL (current_buffer->ctl_arrow);
                    358:   int selective
                    359:     = XTYPE (current_buffer->selective_display) == Lisp_Int
                    360:       ? XINT (current_buffer->selective_display)
                    361:        : !NULL (current_buffer->selective_display) ? -1 : 0;
                    362:   int prev_vpos, prev_hpos;
                    363: 
                    364:   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
                    365:   for (pos = from; pos < to; pos++)
                    366:     {
                    367:       /* Stop if past the target screen position.  */
                    368:       if (vpos > tovpos
                    369:          || (vpos == tovpos && hpos >= tohpos))
                    370:        break;
                    371: 
                    372:       prev_vpos = vpos;
                    373:       prev_hpos = hpos;
                    374: 
                    375:       c = FETCH_CHAR (pos);
                    376:       if (c >= 040 && c < 0177)
                    377:        hpos++;
                    378:       else if (c == '\t')
                    379:        {
                    380:          hpos += tab_width - ((hpos + tab_offset + hscroll - (hscroll > 0)
                    381:                                /* Add tab_width here to make sure positive.
                    382:                                   hpos can be negative after continuation
                    383:                                   but can't be less than -tab_width.  */
                    384:                                + tab_width)
                    385:                               % tab_width);
                    386:        }
                    387:       else if (c == '\n')
                    388:        {
                    389:          if (selective > 0 && position_indentation (pos + 1) >= selective)
                    390:            {
                    391:              /* Skip any number of invisible lines all at once */
                    392:              do
                    393:                {
                    394:                  while (++pos < to && FETCH_CHAR (pos) != '\n');
                    395:                }
                    396:              while (pos < to && position_indentation (pos + 1) >= selective);
                    397:              pos--;
                    398:              /* Allow for the " ..." that is displayed for them. */
                    399:              if (!NULL (current_buffer->selective_display_ellipses))
                    400:                {
                    401:                  hpos += 4;
                    402:                  if (hpos >= width)
                    403:                    hpos = width;
                    404:                }
                    405:              /* We have skipped the invis text, but not the newline after.  */
                    406:            }
                    407:          else
                    408:            {
                    409:              /* A visible line follows.
                    410:                 Skip this newline and advance to next line.  */
                    411:              vpos++;
                    412:              hpos = 0;
                    413:              hpos -= hscroll;
                    414:              if (hscroll > 0) hpos++; /* Count the ! on column 0 */
                    415:              tab_offset = 0;
                    416:            }
                    417:        }
                    418:       else if (c == CR && selective < 0)
                    419:        {
                    420:          /* In selective display mode,
                    421:             everything from a ^M to the end of the line is invisible */
                    422:          while (pos < to && FETCH_CHAR (pos) != '\n') pos++;
                    423:          /* Stop *before* the real newline.  */
                    424:          pos--;
                    425:          /* Allow for the " ..." that is displayed for them. */
                    426:          if (!NULL (current_buffer->selective_display_ellipses))
                    427:            {
                    428:              hpos += 4;
                    429:              if (hpos >= width)
                    430:                hpos = width;
                    431:            }
                    432:        }
                    433:       else
                    434:        hpos += (ctl_arrow && c < 0200) ? 2 : 4;
                    435: 
                    436:       /* Handle right margin.  */
                    437:       if (hpos >= width
                    438:          && (hpos > width
                    439:              || (pos < ZV - 1
                    440:                  && FETCH_CHAR (pos + 1) != '\n')))
                    441:        {
                    442:          if (vpos > tovpos
                    443:              || (vpos == tovpos && hpos >= tohpos))
                    444:            break;
                    445:          if (hscroll
                    446:              || (truncate_partial_width_windows
                    447:                  && width + 1 < screen_width)
                    448:              || !NULL (current_buffer->truncate_lines))
                    449:            {
                    450:              /* Truncating: skip to newline.  */
                    451:              while (pos < to && FETCH_CHAR (pos) != '\n') pos++;
                    452:              pos--;
                    453:              hpos = width;
                    454:            }
                    455:          else
                    456:            {
                    457:              /* Continuing.  */
                    458:              vpos++;
                    459:              hpos -= width;
                    460:              tab_offset += width;
                    461:            }
                    462: 
                    463:        }
                    464:     }
                    465: 
                    466:   val_compute_motion.bufpos = pos;
                    467:   val_compute_motion.hpos = hpos;
                    468:   val_compute_motion.vpos = vpos;
                    469:   val_compute_motion.prevhpos = prev_hpos;
                    470: 
                    471:   /* Nonzero if have just continued a line */
                    472:   val_compute_motion.contin
                    473:     = (pos != from
                    474:        && (val_compute_motion.vpos != prev_vpos)
                    475:        && c != '\n');
                    476: 
                    477:   return &val_compute_motion;
                    478: }
                    479: 
                    480: pos_tab_offset (w, pos)
                    481:      struct window *w;
                    482:      register int pos;
                    483: {
                    484:   int opoint = point;
                    485:   int col;
                    486: 
                    487:   if (pos == BEGV || FETCH_CHAR (pos - 1) == '\n')
                    488:     return 0;
                    489:   SET_PT (pos);
                    490:   col = current_column ();
                    491:   SET_PT (opoint);
                    492:   return (col
                    493:          - (col % (XFASTINT (w->width) - 1
                    494:                    - (XFASTINT (w->width) + XFASTINT (w->left)
                    495:                       != screen_width))));
                    496: }
                    497: 
                    498: /* start_hpos is the hpos of the first character of the buffer:
                    499:    zero except for the minibuffer window,
                    500:    where it is the width of the prompt.  */
                    501: 
                    502: struct position val_vmotion;
                    503: 
                    504: struct position *
                    505: vmotion (from, vtarget, width, hscroll, window)
                    506:      register int from, vtarget, width;
                    507:      int hscroll;
                    508:      Lisp_Object window;
                    509: {
                    510:   struct position pos;
                    511:   /* vpos is cumulative vertical position, changed as from is changed */
                    512:   register int vpos = 0;
                    513:   register int prevline;
                    514:   register int first;
                    515:   int lmargin = hscroll > 0 ? 1 - hscroll : 0;
                    516:   int selective
                    517:     = XTYPE (current_buffer->selective_display) == Lisp_Int
                    518:       ? XINT (current_buffer->selective_display)
                    519:        : !NULL (current_buffer->selective_display) ? -1 : 0;
                    520:   int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0);
                    521: 
                    522:  retry:
                    523:   if (vtarget > vpos)
                    524:     {
                    525:       /* Moving downward is simple, but must calculate from beg of line 
                    526:         to determine hpos of starting point */
                    527:       if (from > BEGV && FETCH_CHAR (from - 1) != '\n')
                    528:        {
                    529:          prevline = find_next_newline (from, -1);
                    530:          while (selective > 0
                    531:                 && prevline > BEGV
                    532:                 && position_indentation (prevline) >= selective)
                    533:            prevline = find_next_newline (prevline - 1, -1);
                    534:          pos = *compute_motion (prevline, 0,
                    535:                                 lmargin + (prevline == 1 ? start_hpos : 0),
                    536:                                 from, 1 << (INTBITS - 2), 0,
                    537:                                 width, hscroll, 0);
                    538:        }
                    539:       else
                    540:        {
                    541:          pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
                    542:          pos.vpos = 0;
                    543:        }
                    544:       return compute_motion (from, vpos, pos.hpos,
                    545:                             ZV, vtarget, - (1 << (INTBITS - 2)),
                    546:                             width, hscroll, pos.vpos * width);
                    547:     }
                    548: 
                    549:   /* To move upward, go a line at a time until
                    550:      we have gone at least far enough */
                    551: 
                    552:   first = 1;
                    553: 
                    554:   while ((vpos > vtarget || first) && from > BEGV)
                    555:     {
                    556:       prevline = from;
                    557:       while (1)
                    558:        {
                    559:          prevline = find_next_newline (prevline - 1, -1);
                    560:          if (prevline == BEGV
                    561:              || selective <= 0
                    562:              || position_indentation (prevline) < selective)
                    563:            break;
                    564:        }
                    565:       pos = *compute_motion (prevline, 0,
                    566:                             lmargin + (prevline == 1 ? start_hpos : 0),
                    567:                             from, 1 << (INTBITS - 2), 0,
                    568:                             width, hscroll, 0);
                    569:       vpos -= pos.vpos;
                    570:       first = 0;
                    571:       from = prevline;
                    572:     }
                    573: 
                    574:   /* If we made exactly the desired vertical distance,
                    575:      or if we hit beginning of buffer,
                    576:      return point found */
                    577:   if (vpos >= vtarget)
                    578:     {
                    579:       val_vmotion.bufpos = from;
                    580:       val_vmotion.vpos = vpos;
                    581:       val_vmotion.hpos = lmargin;
                    582:       val_vmotion.contin = 0;
                    583:       val_vmotion.prevhpos = 0;
                    584:       return &val_vmotion;
                    585:     }
                    586:   
                    587:   /* Otherwise find the correct spot by moving down */
                    588:   goto retry;
                    589: }
                    590: 
                    591: DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 1, 0,
                    592:   "Move to start of screen line LINES lines down.\n\
                    593: If LINES is negative, this is moving up.\n\
                    594: Sets point to position found; this may be start of line\n\
                    595:  or just the start of a continuation line.\n\
                    596: Returns number of lines moved; may be closer to zero than LINES\n\
                    597:  if beginning or end of buffer was reached.")
                    598:   (lines)
                    599:      Lisp_Object lines;
                    600: {
                    601:   struct position pos;
                    602:   register struct window *w = XWINDOW (selected_window);
                    603: 
                    604:   CHECK_NUMBER (lines, 0);
                    605: 
                    606:   pos = *vmotion (point, XINT (lines),
                    607:                  XFASTINT (w->width) - 1
                    608:                  - (XFASTINT (w->width) + XFASTINT (w->left)
                    609:                     != XFASTINT (XWINDOW (minibuf_window)->width)),
                    610:                  /* Not XFASTINT since perhaps could be negative */
                    611:                  XINT (w->hscroll), selected_window);
                    612: 
                    613:   SET_PT (pos.bufpos);
                    614:   return make_number (pos.vpos);
                    615: }
                    616: 
                    617: syms_of_indent ()
                    618: {
                    619:   DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
                    620:     "*Indentation can insert tabs if this is non-nil.\n\
                    621: Setting this variable automatically makes it local to the current buffer.");
                    622:   indent_tabs_mode = 1;
                    623: 
                    624:   defsubr (&Scurrent_indentation);
                    625:   defsubr (&Sindent_to);
                    626:   defsubr (&Scurrent_column);
                    627:   defsubr (&Smove_to_column);
                    628:   defsubr (&Svertical_motion);
                    629: }

unix.superglobalmegacorp.com

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