home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / gnu / lucid / lemacs-19.6 / src / indent.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-01-11  |  24.8 KB  |  902 lines

  1. /* Indentation functions.
  2.    Copyright (C) 1992, 1993 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 2, 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 "extents.h"
  25. #include "indent.h"
  26. #include "screen.h"
  27. #include "window.h"
  28. #include "insdel.h"
  29. #include "termchar.h"
  30. #include "termopts.h"
  31. #include "disptab.h"
  32. #ifdef HAVE_X_WINDOWS
  33. #include "xterm.h"
  34. #endif
  35.  
  36. /* Indentation can insert tabs if this is non-zero;
  37.    otherwise always uses spaces */
  38. int indent_tabs_mode;
  39.  
  40. #define min(a, b) ((a) < (b) ? (a) : (b))
  41. #define max(a, b) ((a) > (b) ? (a) : (b))
  42.  
  43. #define CR 015
  44.  
  45. /* Avoid recalculation by remembering things in these variables. */
  46.  
  47. /* Last value returned by current_column.
  48.  
  49.    Some things set last_known_column_point to -1
  50.    to mark the memoized value as invalid */
  51. int last_known_column;
  52.  
  53. /* Last buffer searched by current_column */
  54. static struct buffer *last_known_column_buffer;
  55.  
  56. /* Value of point when current_column was called */
  57. int last_known_column_point;
  58.  
  59. /* Value of MODIFF when current_column was called */
  60. static int last_known_column_modified;
  61.  
  62. extern int minibuf_prompt_width;
  63.  
  64. extern int minibuf_prompt_pix_width;
  65.  
  66. /* Get the display table to use for the current buffer.  */
  67.  
  68. struct Lisp_Vector *
  69. buffer_display_table (struct buffer* buffer)
  70. {
  71.   Lisp_Object thisbuf;
  72.  
  73.   thisbuf = buffer->display_table;
  74.   if (VECTORP (thisbuf)
  75.       && XVECTOR (thisbuf)->size == DISP_TABLE_SIZE)
  76.     return XVECTOR (thisbuf);
  77.  
  78.   if (VECTORP (Vstandard_display_table)
  79.       && XVECTOR (Vstandard_display_table)->size == DISP_TABLE_SIZE)
  80.     return XVECTOR (Vstandard_display_table);
  81.  
  82.   return 0;
  83. }
  84.  
  85. #if 0
  86. static int
  87. list_length (list)
  88.      Lisp_Object list;
  89. {
  90.   int length = 0;
  91.  
  92.   while (CONSP (list))
  93.     {
  94.       length++;
  95.       list = XCONS (list)->cdr;
  96.     }
  97.   return length;
  98. }
  99. #endif
  100.  
  101. int
  102. current_column ()
  103. {
  104.   register struct buffer *buffer = current_buffer;
  105.   struct Lisp_Vector *dp = buffer_display_table (buffer);
  106.   register int col;
  107.   register int tab_seen;
  108.   register int tab_width = XINT (buffer->tab_width);
  109.   register int pos;
  110.   int post_tab;
  111.   struct glyphs_from_chars *displayed_glyphs;
  112.  
  113.   if (buffer == last_known_column_buffer
  114.       && BUF_PT (buffer) == last_known_column_point
  115.       && BUF_MODIFF (buffer) == last_known_column_modified)
  116.     return last_known_column;
  117.  
  118.   pos = BUF_PT (buffer);
  119.   col = tab_seen = post_tab = 0;
  120.  
  121.   while (1)
  122.     {
  123.       if (pos == BUF_BEGV (buffer))
  124.     break;
  125.  
  126.       pos--;
  127.       if (BUF_CHAR_AT (buffer, pos) == '\t')
  128.       {
  129.     if (tab_seen)
  130.         col = ((col + tab_width) / tab_width) * tab_width;
  131.  
  132.       post_tab += col;
  133.       col = 0;
  134.       tab_seen = 1;
  135.     }
  136.       else if (BUF_CHAR_AT (buffer, pos) == '\n')
  137.     break;
  138.       else
  139.     {
  140.       displayed_glyphs = glyphs_from_bufpos (selected_screen, buffer, pos,
  141.                          dp, 0, col, 0, 0, 0);
  142.       col += (displayed_glyphs->columns
  143.           - (displayed_glyphs->begin_columns
  144.              + displayed_glyphs->end_columns));
  145.     }
  146.     }
  147.  
  148.   if (tab_seen)
  149.     {
  150.       col = ((col + tab_width) / tab_width) * tab_width;
  151.       col += post_tab;
  152.     }
  153.  
  154.   last_known_column_buffer = buffer;
  155.   last_known_column = col;
  156.   last_known_column_point = BUF_PT (buffer);
  157.   last_known_column_modified = BUF_MODIFF (buffer);
  158.  
  159.   return col;
  160. }
  161.  
  162. DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
  163.   "Return the horizontal position of point.  Beginning of line is column 0.\n\
  164. This is calculated by adding together the widths of all the displayed\n\
  165. representations of the character between the start of the previous line\n\
  166. and point.  (eg control characters will have a width of 2 or 4, tabs\n\
  167. will have a variable width)\n\
  168. Ignores finite width of screen, which means that this function may return\n\
  169. values greater than (screen-width).\n\
  170. Whether the line is visible (if `selective-display' is t) has no effect;\n\
  171. however, ^M is treated as end of line when `selective-display' is t.")
  172.   ()
  173. {
  174.   Lisp_Object temp;
  175.   XFASTINT (temp) = current_column ();
  176.   return temp;
  177. }
  178.  
  179. DEFUN ("indent-to", Findent_to, Sindent_to, 1, 2, "NIndent to column: ",
  180.   "Indent from point with tabs and spaces until COLUMN is reached.\n\
  181. Optional second argument MIN says always do at least MIN spaces\n\
  182. even if that goes past COLUMN; by default, MIN is zero.")
  183.   (col, minimum)
  184.      Lisp_Object col, minimum;
  185. {
  186.   int mincol;
  187.   register int fromcol;
  188.   register int tab_width = XINT (current_buffer->tab_width);
  189.   int opoint = 0;
  190.   EXTENT extent = extent_at (point, current_buffer, EF_INVISIBLE);
  191.  
  192.   CHECK_FIXNUM (col, 0);
  193.   if (NILP (minimum))
  194.     XFASTINT (minimum) = 0;
  195.   CHECK_FIXNUM (minimum, 1);
  196.  
  197.   fromcol = current_column ();
  198.   mincol = fromcol + XINT (minimum);
  199.   if (mincol < XINT (col)) mincol = XINT (col);
  200.  
  201.   if (fromcol == mincol)
  202.     return make_number (mincol);
  203.  
  204.   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
  205.  
  206.   
  207.   if (extent)
  208.     {
  209.       int last_visible = last_visible_position (point, current_buffer);
  210.       opoint = point;
  211.  
  212.       if (last_visible >= BEGV)
  213.     SET_PT (last_visible);
  214.       else 
  215.         error ("Visible portion of buffer not modifiable");
  216.     }
  217.  
  218.   if (indent_tabs_mode)
  219.     {
  220.       Lisp_Object n;
  221.       XFASTINT (n) = mincol / tab_width - fromcol / tab_width;
  222.       if (XFASTINT (n) != 0)
  223.     {
  224.       Finsert_char (make_number ('\t'), n);
  225.  
  226.       fromcol = (mincol / tab_width) * tab_width;
  227.     }
  228.     }
  229.  
  230.   XFASTINT (col) = mincol - fromcol;
  231.   Finsert_char (make_number (' '), col);
  232.  
  233.   last_known_column_buffer = current_buffer;
  234.   last_known_column = mincol;
  235.   last_known_column_point = point;
  236.   last_known_column_modified = MODIFF;
  237.  
  238.   if (opoint > 0)
  239.     SET_PT (opoint);
  240.  
  241.   XSETINT (col, mincol);
  242.   return col;
  243. }
  244.  
  245. int
  246. position_indentation (pos)
  247.      register int pos;
  248. {
  249.   register int col = 0;
  250.   register int c;
  251.   register int end = ZV;
  252.   register int tab_width = XINT (current_buffer->tab_width);
  253.  
  254.   if (extent_at (pos, current_buffer, EF_INVISIBLE))
  255.     return 0;
  256.  
  257.   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
  258.  
  259.   while (pos < end &&
  260.      (c = CHAR_AT (pos),
  261.       c == '\t' ? (col += tab_width - col % tab_width)
  262.           : (c == ' ' ? ++col : 0)))
  263.     pos++;
  264.  
  265.   return col;
  266. }
  267.  
  268. DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
  269.   0, 0, 0,
  270.   "Return the indentation of the current line.\n\
  271. This is the horizontal position of the character\n\
  272. following any initial whitespace.")
  273.   ()
  274. {
  275.   Lisp_Object val;
  276.  
  277.   XFASTINT (val) = position_indentation (find_next_newline (point, -1));
  278.   return val;
  279. }
  280.  
  281. DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, 0,
  282.   "Move point to column COLUMN in the current line.\n\
  283. The column of a character is calculated by adding together the widths\n\
  284. as displayed of the previous characters in the line.\n\
  285. This function ignores line-continuation;\n\
  286. there is no upper limit on the column number a character can have\n\
  287. and horizontal scrolling has no effect.\n\n\
  288. If specified column is within a character, point goes after that character.\n\
  289. If it's past end of line, point goes to end of line.\n\n\
  290. A non-nil second (optional) argument FORCE means, if the line\n\
  291. is too short to reach column COLUMN then add spaces/tabs to get there,\n\
  292. and if COLUMN is in the middle of a tab character, change it to spaces.")
  293.   (column, force)
  294.      Lisp_Object column, force;
  295. {
  296.   register int pos;
  297.   register int col = current_column ();
  298.   register int goal;
  299.   register int end;
  300.   register int tab_width = XINT (current_buffer->tab_width);
  301.   Lisp_Object ctl_arrow = current_buffer->ctl_arrow;
  302.   register struct Lisp_Vector *dp = buffer_display_table (current_buffer);
  303.  
  304.   Lisp_Object val;
  305.   int prev_col;
  306.   int c;
  307.  
  308.   if (tab_width <= 0 || tab_width > 20) tab_width = 8;
  309.   CHECK_NATNUM (column, 0);
  310.   goal = XINT (column);
  311.  
  312.  retry:
  313.   pos = point;
  314.   end = ZV;
  315.  
  316.   /* If we're starting past the desired column,
  317.      back up to beginning of line and scan from there.  */
  318.   if (col > goal)
  319.     {
  320.       pos = find_next_newline (pos, -1);
  321.       col = 0;
  322.     }
  323.  
  324.   while (col < goal && pos < end)
  325.     {
  326.       c = CHAR_AT (pos);
  327.       if (c == '\n')
  328.     break;
  329.       if (c == '\r' && EQ (current_buffer->selective_display, Qt))
  330.     break;
  331.       pos++;
  332.       if (c == '\t')
  333.     {
  334.       prev_col = col;
  335.       col += tab_width;
  336.       col = col / tab_width * tab_width;
  337.     }
  338.       else if (dp != 0 && STRINGP (DISP_CHAR_ROPE (dp, c)))
  339.     col += XSTRING (DISP_CHAR_ROPE (dp, c))->size / sizeof (GLYPH);
  340.       else if (!NILP (ctl_arrow) && (c < 040 || c == 0177))
  341.         col++;
  342.       else if (c < 040 ||
  343.            ((NILP (ctl_arrow) || EQ (ctl_arrow, Qt)) && c > 0177))
  344.         col += 3;
  345.       else
  346.     col++;
  347.     }
  348.  
  349.   SET_PT (pos);
  350.  
  351.   /* If a tab char made us overshoot, change it to spaces
  352.      and scan through it again.  */
  353.   if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
  354.     {
  355.       del_range (point - 1, point);
  356.       Findent_to (make_number (col - 1), 0);
  357.       insert_char (' ');
  358.       goto retry;
  359.     }
  360.  
  361.   /* If line ends prematurely, add space to the end.  */
  362.   if (col < goal && !NILP (force))
  363.     Findent_to (make_number (col = goal), 0);
  364.  
  365.   last_known_column_buffer = current_buffer;
  366.   last_known_column = col;
  367.   last_known_column_point = point;
  368.   last_known_column_modified = MODIFF;
  369.  
  370.   XFASTINT (val) = col;
  371.   return val;
  372. }
  373.  
  374. static struct position val_compute_motion;
  375.  
  376. /* Note that `cpos' is CURRENT_VPOS << SHORTBITS + CURRENT_HPOS,
  377.    and that CURRENT_HPOS may be negative.  Use these macros
  378.    to extract the hpos or the vpos from cpos or anything like it. */
  379. #ifndef SHORT_CAST_BUG
  380. #define HPOS(VAR) (short) (VAR)
  381. #else
  382. #define HPOS(VAR) (((VAR) & (1 << (SHORTBITS - 1)) \
  383.             ? ~((1 << SHORTBITS) - 1) : 0) \
  384.            | (VAR) & ((1 << SHORTBITS) - 1))
  385. #endif /* SHORT_CAST_BUG */
  386.  
  387. #define VPOS(VAR) (((VAR) >> SHORTBITS) + (HPOS (VAR) < 0))
  388.  
  389. #ifdef HAVE_X_WINDOWS
  390. #define CHECK_PIX_WIDTH (SCREEN_IS_TERMCAP (screen) || pix_width < max_width)
  391. #ifdef LINE_INFO_COLUMN
  392. #define RESET_PIX_WIDTH (pix_width = screen->display.x->line_info_column_width)
  393. #else
  394. #define RESET_PIX_WIDTH (pix_width = 0)
  395. #endif
  396. #define INC_PIX_WIDTH (pix_width += displayed_glyphs->pixel_width)
  397. #define PIX_VALUES 1
  398. #define CHECK_PIX_OVERFLOW (SCREEN_IS_X (screen)            \
  399.                 && pix_width >= max_width            \
  400.                 && BUF_CHAR_AT (buffer, pos + 1) != '\n')
  401. #else  /* not X */
  402. #define CHECK_PIX_WIDTH 1
  403. #define RESET_PIX_WIDTH
  404. #define INC_PIX_WIDTH
  405. #define PIX_VALUES 0
  406. #define CHECK_PIX_OVERFLOW 0
  407. #endif /* not X */
  408.  
  409. #ifdef LINE_INFO_COLUMN
  410. #define INFO_COLUMN_ADJUST(cpos) (cpos)++
  411. #define INFO_COLUMNS(cpos) (HPOS(cpos) - 1)
  412. #else
  413. #define INFO_COLUMN_ADJUST(cpos)
  414. #define INFO_COLUMNS(cpos) (HPOS(cpos))
  415. #endif
  416.  
  417. /* Marker for where to display an arrow on top of the buffer text.  */
  418. Lisp_Object Voverlay_arrow_position;
  419.  
  420. /* String to display for the arrow.  */
  421. Lisp_Object Voverlay_arrow_string;
  422.  
  423. /* New version of compute motion. */
  424.  
  425. struct position *
  426. compute_motion (window, from, fromvpos, fromhpos, to,
  427.         tovpos, tohpos, width, hscroll, tab_offset, hpos_pix_width,
  428.         column)
  429.      int from, fromvpos, fromhpos, to, tovpos, tohpos, hpos_pix_width, column;
  430.      register int width;
  431.      int hscroll, tab_offset;
  432.      Lisp_Object window;
  433. {
  434.   struct buffer *buffer = XBUFFER (XWINDOW (window)->buffer);
  435.   struct Lisp_Vector *dp = buffer_display_table (buffer);
  436.   SCREEN_PTR screen = XSCREEN (WINDOW_SCREEN (XWINDOW (window)));
  437.   SCREEN_PTR s = screen;
  438.   struct window *w = XWINDOW (window);
  439. #ifdef LINE_INFO_COLUMN
  440.   int cpos = fromhpos + (fromvpos << SHORTBITS) + 1;
  441. #else
  442.   int cpos = fromhpos + (fromvpos << SHORTBITS);
  443. #endif
  444.   register int target = tohpos + (tovpos << SHORTBITS);
  445.   register UCHAR c;
  446.   register int pos;
  447.   int prevcpos, pix_width, nextcpos;
  448.   struct glyphs_from_chars *displayed_glyphs;
  449.   int overlay_arrow_seen = 0;
  450.  
  451. #ifdef HAVE_X_WINDOWS
  452.   int truncate = hscroll
  453.     || (truncate_partial_width_windows
  454.     && XFASTINT (w->width) < SCREEN_WIDTH (s))
  455.       || !NILP (current_buffer->truncate_lines);
  456.   register int max_width =
  457.     (SCREEN_IS_X (screen) ?
  458.      MAX_LINE_WIDTH (screen) - EOL_CURSOR_WIDTH
  459.      : 0);
  460.   /* max_truncated_or_continued_width is widest possible line that is
  461.      truncated or continued */
  462.   int max_truncated_or_continued_width =
  463.         (SCREEN_IS_X (screen) ?
  464.      (truncate
  465.       ? TRUNCATE_WIDTH (screen)
  466.       : CONTINUE_WIDTH (screen))
  467.      : max_width);
  468.   int position_before_continuer = 0;
  469.   int cpos_before_continuer;
  470. #endif
  471.  
  472.   pix_width = hpos_pix_width;
  473.   pos = from;
  474.   prevcpos = cpos;
  475.  
  476.   while (1)
  477.     {
  478.       /* There are no glyphs at this position */
  479.       displayed_glyphs = 0;
  480.       if (pos == ZV)
  481.     break;
  482.  
  483.       /* Deal with the overlay arrow. */
  484.       if (MARKERP (Voverlay_arrow_position)
  485.       && current_buffer == XMARKER (Voverlay_arrow_position)->buffer
  486.       && (pos == BEGV
  487.           || BUF_CHAR_AT (buffer, pos - 1) == '\n')
  488.       && pos == marker_position (Voverlay_arrow_position)
  489.       && STRINGP (Voverlay_arrow_string)
  490.       && ! overlay_arrow_seen)
  491.     {
  492.       cpos++;
  493.       pix_width += builtin_rarrow_pixmap.width;
  494.       overlay_arrow_seen = 1;
  495.     }
  496.  
  497.       c = BUF_CHAR_AT (buffer, pos);
  498.       /* Increment columns by the number of glyphs at this buffer position,
  499.      and increment pix_width by the pixel_width of these glyphs. */
  500.       displayed_glyphs = glyphs_from_bufpos (screen, buffer, pos, dp,
  501.                          hscroll, column,
  502.                          tab_offset, 0, 0);
  503.       nextcpos = cpos + displayed_glyphs->columns;
  504.       cpos = nextcpos;
  505.       column += displayed_glyphs->columns - (displayed_glyphs->begin_columns
  506.                          + displayed_glyphs->end_columns);
  507.       INC_PIX_WIDTH;
  508.       
  509.       /* If we've reached the continuer position,
  510.      take note of the pos and cpos before this position. */
  511.  
  512.       if (!position_before_continuer
  513.       && pix_width > max_truncated_or_continued_width)
  514.         {
  515.           position_before_continuer = pos - 1;
  516.           cpos_before_continuer = prevcpos;
  517.         }
  518.  
  519.       /* If we've reached the maximum position, go back to the continuer
  520.          position and continue on the next line starting with the position
  521.          immediately following position_before_continuer */
  522.       if (pix_width > max_truncated_or_continued_width)
  523.         {
  524.           /* Exceeded max_width, go to the next line, starting at
  525.          position_before_continuer. */
  526.           prevcpos = cpos_before_continuer;
  527.           pos = position_before_continuer + 1;
  528.  
  529.           if (truncate)
  530.         {
  531.           while (pos < to
  532.              && BUF_CHAR_AT (buffer, pos) != '\n')
  533.             pos++;
  534.           if (BUF_CHAR_AT (buffer, pos) == '\n')
  535.             {
  536.               displayed_glyphs = 0;
  537.               nextcpos = cpos + (1 << SHORTBITS) - HPOS (cpos);
  538.               nextcpos -= hscroll;
  539.               INFO_COLUMN_ADJUST (nextcpos);
  540.               if (hscroll > 0)
  541.             nextcpos++;    /* Count the ! on column 0 */
  542.               tab_offset = 0;
  543.               column = 0;
  544.               RESET_PIX_WIDTH;
  545.               position_before_continuer = 0;
  546.             }
  547.           if (pos < to || BUF_CHAR_AT (buffer, pos) == '\n')
  548.             continue;
  549.         }
  550.           else
  551.         {
  552.           cpos += (1 << SHORTBITS) - HPOS (cpos);
  553.           cpos -= hscroll;
  554.           INFO_COLUMN_ADJUST (cpos);
  555.           if (hscroll > 0)
  556.             cpos++;    /* Count the ! on column 0 */
  557.           tab_offset = 0;
  558.           column = 0;
  559.           RESET_PIX_WIDTH;
  560.           position_before_continuer = 0;
  561.           continue;
  562.         }
  563.         }
  564.       if (c == '\n')
  565.     {
  566.       /* If the character is a newline, go to the next display line
  567.          positioned at the beginning after any extras like the info
  568.          column and the hscroll ! indicator */
  569.       displayed_glyphs = 0;    /* Don't adjust cursor for end glyphs on EOL */
  570.       nextcpos = cpos + (1 << SHORTBITS) - HPOS (cpos);
  571.       nextcpos -= hscroll;
  572.       INFO_COLUMN_ADJUST (nextcpos);
  573.  
  574.       if (hscroll > 0)
  575.         nextcpos++;        /* Count the ! on column 0 */
  576.       tab_offset = 0;
  577.       RESET_PIX_WIDTH;
  578.       column = 0;
  579.       /* continued_from_position = 0; */
  580.       position_before_continuer = 0;
  581.     }
  582.  
  583.       if (pos >= to || cpos >= target)
  584.     {
  585.       /* We've found the buffer position we want, but we need to
  586.          be sure we aren't in the line wrap zone. */
  587.       if (position_before_continuer)
  588.         {
  589.           /* If we're in the line wrap zone, we must look ahead to
  590.          see if this position is on this line or the next line.
  591.          If a line break or end of buffer occurs before max_width,
  592.          it's on this line, otherwise it's on the next line. */
  593.           int look_c;
  594.           int lookahead_pos = pos;
  595.           int lookahead_pix_width = pix_width;
  596.           struct glyphs_from_chars *lookahead_glyphs;
  597.  
  598.           while (1)
  599.         {
  600.           lookahead_pos++;
  601.           if (lookahead_pos > ZV)
  602.             break;
  603.           look_c = BUF_CHAR_AT (buffer, lookahead_pos);
  604.           if (look_c == '\n')
  605.             /* Found a newline, so we stay on this line */
  606.             break;
  607.           lookahead_glyphs = glyphs_from_bufpos (screen, buffer,
  608.                              lookahead_pos, dp,
  609.                              hscroll,
  610.                              INFO_COLUMNS (cpos),
  611.                              tab_offset, 0, 0);
  612.           lookahead_pix_width += lookahead_glyphs->pixel_width;
  613.           if (lookahead_pix_width > max_truncated_or_continued_width)
  614.             {
  615.               /* Exceeded max_width, go to the next line, starting at
  616.              position_before_continuer. */
  617.               prevcpos = cpos_before_continuer;
  618.               pos = position_before_continuer + 1;
  619.  
  620.               if (truncate)
  621.             {
  622.               while (pos < to
  623.                  && BUF_CHAR_AT (buffer, pos) != '\n')
  624.                 pos++;
  625.               if (pos >= to)
  626.                 cpos = cpos_before_continuer + 2;
  627.               /* Prevent adjustment after breaking */
  628.               displayed_glyphs = 0;
  629.             }
  630.               else
  631.             {
  632.               cpos += (1 << SHORTBITS) - HPOS (cpos);
  633.               cpos -= hscroll;
  634.               INFO_COLUMN_ADJUST (cpos);
  635.               if (hscroll > 0)
  636.                 cpos++; /* Count the ! on column 0 */
  637.               tab_offset = 0;
  638.               RESET_PIX_WIDTH;
  639.               column = 0;
  640.               position_before_continuer = 0;
  641.             }
  642.               break;
  643.             }
  644.         }
  645.           if (pos >= to)
  646.         break;
  647.         }
  648.       else
  649.         {
  650.           /* We aren't in the line wrap zone, so we're done.
  651.          prevpos points to the previous position. */
  652.           break;
  653.         }
  654.     }
  655.       else
  656.     {
  657.       prevcpos = (displayed_glyphs
  658.               ? (cpos - (displayed_glyphs->columns
  659.                  - displayed_glyphs->begin_columns))
  660.               : cpos);
  661.       cpos = nextcpos;
  662.       pos++;
  663.     }
  664.     }
  665.  
  666.   /* cpos now points to the character following this position, so we must
  667.      subtract all but the begin glyphs to get this position.  If this
  668.      position is at a newline or in the truncation zone, there are no glyphs
  669.      and cpos points to this position and needs no adjustment. */
  670.   if (displayed_glyphs)
  671.     {
  672.       cpos -= (displayed_glyphs->columns
  673.            - displayed_glyphs->begin_columns);
  674.       pix_width -= displayed_glyphs->pixel_width;
  675.       column -= (displayed_glyphs->columns
  676.          - (displayed_glyphs->begin_columns + displayed_glyphs->end_columns));
  677.     }
  678.  
  679.   val_compute_motion.bufpos = pos;
  680.   val_compute_motion.hpos = HPOS (cpos);
  681.   val_compute_motion.vpos = VPOS (cpos);
  682.   val_compute_motion.prevhpos = HPOS (prevcpos);
  683.   val_compute_motion.pixpos = pix_width;
  684.   val_compute_motion.column = column;
  685.  
  686.   /* Nonzero if have just continued a line */
  687.   val_compute_motion.contin = ((pos != from
  688.                 && (val_compute_motion.vpos != VPOS (prevcpos))
  689.                 && c != '\n')
  690.                    ? (pos - 1)
  691.                    : 0);
  692.  
  693.   return &val_compute_motion;
  694. }
  695.  
  696.  
  697. #undef HPOS
  698. #undef VPOS
  699.  
  700. int pos_tab_offset (struct window *, int);
  701.  
  702. DEFUN ("motion", Fmotion, Smotion, 3, 3, 0,
  703.   "Move forward from point by N characters.  Stop if we reach\n\
  704. TOHPOS, TOVPOS first.")
  705.   (n, tohpos, tovpos)
  706.      Lisp_Object n, tohpos, tovpos;
  707. {
  708.   int fromhpos = 0;
  709.   int fromvpos = SCREEN_CURSOR_Y (selected_screen);
  710.   int width = XFASTINT (XWINDOW (selected_window)->width);
  711.   int hscroll = XINT (XWINDOW (selected_window)->hscroll);
  712.   struct position *pos;
  713.  
  714.   pos = compute_motion (selected_window,
  715.             point, fromvpos, fromhpos, (point + n),
  716.             XINT (tovpos), XINT (tohpos),
  717.             width, hscroll,
  718.             pos_tab_offset (XWINDOW (selected_window), point),
  719.             0, 0);
  720.   SET_PT (pos->bufpos);
  721.   return Fcons (make_number (pos->vpos),
  722.         Fcons (make_number (pos->hpos), Qnil));
  723. }
  724.  
  725. /* Return the column of position POS in window W's buffer,
  726.    rounded down to a multiple of the internal width of W.
  727.    This is the amount of indentation of position POS
  728.    that is not visible in its horizontal position in the window.  */
  729.  
  730. int
  731. pos_tab_offset (w, pos)
  732.      struct window *w;
  733.      register int pos;
  734. {
  735.   return 0;
  736. #if 0
  737.   int opoint = point;
  738.   int col;
  739.   int width = XFASTINT (w->width) - 1
  740.     - (XFASTINT (w->width) + XFASTINT (w->left)
  741.        != SCREEN_WIDTH (XSCREEN (w->screen)));
  742.   EXTENT extent = extent_at (pos, current_buffer, EF_INVISIBLE);
  743.  
  744.   if ((pos == BEGV) || (CHAR_AT (pos - 1) == '\n') || extent)
  745.     return 0;
  746.  
  747.   SET_PT (pos);
  748.   col = current_column ();
  749.   SET_PT (opoint);
  750.   return col - (col % width);
  751. #endif
  752. }
  753.  
  754. /* start_hpos is the hpos of the first character of the buffer:
  755.    zero except for the minibuffer window,
  756.    where it is the width of the prompt.  */
  757.  
  758. static struct position val_vmotion;
  759.  
  760. struct position *
  761. vmotion (from, vtarget, width, hscroll, window)
  762.      register int from, vtarget, width;
  763.      int hscroll;
  764.      Lisp_Object window;
  765. {
  766.   struct position pos;
  767.   /* vpos is cumulative vertical position, changed as from is changed */
  768.   register int vpos = 0;
  769.   register int prevline;
  770.   register int first;
  771.   int lmargin = hscroll > 0 ? 1 - hscroll : 0;
  772.   int selective
  773.     = FIXNUMP (current_buffer->selective_display)
  774.       ? XINT (current_buffer->selective_display)
  775.     : !NILP (current_buffer->selective_display) ? -1 : 0;
  776.   int start_hpos = (EQ (window, minibuf_window) ? minibuf_prompt_width : 0);
  777.   int start_pixpos = (EQ (window, minibuf_window) ? minibuf_prompt_pix_width : 0);
  778.   
  779.  
  780.  retry:
  781.   if (vtarget > vpos)
  782.     {
  783.       /* Moving downward is simple, but must calculate from beg of line 
  784.      to determine hpos of starting point */
  785.       if (from > BEGV && CHAR_AT (from - 1) != '\n')
  786.     {
  787.       prevline = find_next_newline (from, -1);
  788.       while (selective > 0
  789.          && prevline > BEGV
  790.          && position_indentation (prevline) >= selective)
  791.         prevline = find_next_newline (prevline - 1, -1);
  792.       pos = *compute_motion (window,
  793.                  prevline, 0,
  794.                  lmargin + (prevline == 1 ? start_hpos : 0),
  795.                  from, 10000, 10000,
  796.                  width, hscroll, 0, start_pixpos, 0);
  797.     }
  798.       else
  799.     {
  800.       pos.hpos = lmargin + (from == 1 ? start_hpos : 0);
  801.       pos.pixpos = (from == 1 ? start_pixpos : 0);
  802.       pos.column = 0;
  803.       pos.vpos = 0;
  804.     }
  805.       return compute_motion (window,
  806.                  from, vpos, pos.hpos,
  807.                  ZV, vtarget, - (1 << (SHORTBITS - 1)),
  808.                  width, hscroll, pos.vpos * width,
  809.                  pos.pixpos, pos.column);
  810.     }
  811.  
  812.   /* To move upward, go a line at a time until
  813.      we have gone at least far enough */
  814.  
  815.   first = 1;
  816.  
  817.   while ((vpos > vtarget || first) && from > BEGV)
  818.     {
  819.       prevline = from;
  820.       while (1)
  821.     {
  822.       prevline = find_next_newline (prevline - 1, -1);
  823.       if (prevline == BEGV
  824.           || selective <= 0
  825.           || position_indentation (prevline) < selective)
  826.         break;
  827.     }
  828.       pos = *compute_motion (window,
  829.                  prevline, 0,
  830.                  lmargin + (prevline == 1 ? start_hpos : 0),
  831.                  from, 10000, 10000,
  832.                  width, hscroll, 0, start_pixpos, 0);
  833.       vpos -= pos.vpos;
  834.       first = 0;
  835.       from = prevline;
  836.     }
  837.  
  838.   /* If we made exactly the desired vertical distance,
  839.      or if we hit beginning of buffer,
  840.      return point found */
  841.   if (vpos >= vtarget)
  842.     {
  843.       val_vmotion.bufpos = from;
  844.       val_vmotion.vpos = vpos;
  845.       val_vmotion.hpos = lmargin;
  846.       val_vmotion.pixpos = 0;
  847.       val_vmotion.column = 0;
  848.       val_vmotion.contin = 0;
  849.       val_vmotion.prevhpos = 0;
  850.       return &val_vmotion;
  851.     }
  852.   
  853.   /* Otherwise find the correct spot by moving down */
  854.   goto retry;
  855. }
  856.  
  857. DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,
  858.   "Move to start of screen line LINES lines down.\n\
  859. If LINES is negative, this is moving up.\n\
  860. Sets point to position found; this may be start of line\n\
  861.  or just the start of a continuation line.\n\
  862. Returns number of lines moved; may be closer to zero than LINES\n\
  863.  if beginning or end of buffer was reached.\n\
  864. Optional second argument is WINDOW to move in.")
  865.   (lines, window)
  866.      Lisp_Object lines, window;
  867. {
  868.   if (NILP (window))
  869.     window = selected_window;
  870.   {
  871.     struct position pos;
  872.     register struct window *w  = XWINDOW (window);
  873.     int width = XFASTINT (w->width) - 1
  874.       - (XFASTINT (w->width) + XFASTINT (w->left)
  875.      != SCREEN_WIDTH (XSCREEN (w->screen)));
  876.  
  877.     CHECK_FIXNUM (lines, 0);
  878.  
  879.     pos = *vmotion (point, XINT (lines), width,
  880.             XINT (w->hscroll), window);
  881.  
  882.     SET_PT (pos.bufpos);
  883.     return make_number (pos.vpos);
  884.   }
  885. }
  886.  
  887. void
  888. syms_of_indent ()
  889. {
  890.   DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
  891.     "*Indentation can insert tabs if this is non-nil.\n\
  892. Setting this variable automatically makes it local to the current buffer.");
  893.   indent_tabs_mode = 1;
  894.  
  895.   defsubr (&Scurrent_indentation);
  896.   defsubr (&Sindent_to);
  897.   defsubr (&Scurrent_column);
  898.   defsubr (&Smove_to_column);
  899.   defsubr (&Svertical_motion);
  900.   defsubr (&Smotion);
  901. }
  902.