]> code.delx.au - gnu-emacs/blobdiff - src/indent.c
* test/lisp/help-fns-tests.el: Add several tests for 'describe-function'.
[gnu-emacs] / src / indent.c
index ce78308c95b0af82654ae5647678d3f082a38dcb..bc59239f20fb8b37e03fda75a265a4af3959cba3 100644 (file)
@@ -1,13 +1,13 @@
 /* Indentation functions.
-   Copyright (C) 1985-1988, 1993-1995, 1998, 2000-2015 Free Software
+   Copyright (C) 1985-1988, 1993-1995, 1998, 2000-2016 Free Software
    Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -26,10 +26,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "category.h"
 #include "composite.h"
 #include "indent.h"
-#include "keyboard.h"
 #include "frame.h"
 #include "window.h"
-#include "termchar.h"
 #include "disptab.h"
 #include "intervals.h"
 #include "dispextern.h"
@@ -485,7 +483,9 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos)
         : MOST_POSITIVE_FIXNUM);
 
       if ((prop = Fplist_get (plist, QCwidth),
-          RANGED_INTEGERP (0, prop, INT_MAX)))
+          RANGED_INTEGERP (0, prop, INT_MAX))
+         || (prop = Fplist_get (plist, QCrelative_width),
+             RANGED_INTEGERP (0, prop, INT_MAX)))
        width = XINT (prop);
       else if (FLOATP (prop) && 0 <= XFLOAT_DATA (prop)
               && XFLOAT_DATA (prop) <= INT_MAX)
@@ -504,6 +504,18 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos)
            *endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
          else
            get_property_and_range (pos, Qdisplay, &val, &start, endpos, Qnil);
+
+         /* For :relative-width, we need to multiply by the column
+            width of the character at POS, if it is greater than 1.  */
+         if (!NILP (Fplist_get (plist, QCrelative_width))
+             && !NILP (BVAR (current_buffer, enable_multibyte_characters)))
+           {
+             int b, wd;
+             unsigned char *p = BYTE_POS_ADDR (CHAR_TO_BYTE (pos));
+
+             MULTIBYTE_BYTES_WIDTH (p, buffer_display_table (), b, wd);
+             width *= wd;
+           }
          return width;
        }
     }
@@ -1983,8 +1995,7 @@ whether or not it is currently displayed in some window.  */)
   struct text_pos pt;
   struct window *w;
   Lisp_Object old_buffer;
-  EMACS_INT old_charpos IF_LINT (= 0), old_bytepos IF_LINT (= 0);
-  struct gcpro gcpro1;
+  EMACS_INT old_charpos UNINIT, old_bytepos UNINIT;
   Lisp_Object lcols;
   void *itdata = NULL;
 
@@ -2000,7 +2011,6 @@ whether or not it is currently displayed in some window.  */)
   w = decode_live_window (window);
 
   old_buffer = Qnil;
-  GCPRO1 (old_buffer);
   if (XBUFFER (w->contents) != current_buffer)
     {
       /* Set the window's buffer temporarily to the current buffer.  */
@@ -2026,8 +2036,8 @@ whether or not it is currently displayed in some window.  */)
       bool disp_string_at_start_p = 0;
       ptrdiff_t nlines = XINT (lines);
       int vpos_init = 0;
-      double start_col;
-      int start_x IF_LINT (= 0);
+      double start_col UNINIT;
+      int start_x UNINIT;
       int to_x = -1;
 
       bool start_x_given = !NILP (cur_col);
@@ -2120,6 +2130,15 @@ whether or not it is currently displayed in some window.  */)
              && it.method == GET_FROM_BUFFER
              && it.c == '\n')
            it_overshoot_count = 1;
+         else if (it_overshoot_count == 1 && it.vpos == 0
+                  && it.current_x < it.last_visible_x)
+           {
+             /* If we came to the same screen line as the one where
+                we started, we didn't overshoot the line, and won't
+                need to backtrack after all.  This happens, for
+                example, when PT is in the middle of a composition.  */
+             it_overshoot_count = 0;
+           }
          else if (disp_string_at_start_p && it.vpos > 0)
            {
              /* This is the case of a display string that spans
@@ -2128,29 +2147,38 @@ whether or not it is currently displayed in some window.  */)
                 screen lines we need to backtrack.  */
              it_overshoot_count = it.vpos;
            }
+         /* We will overshoot if lines are truncated and point lies
+            beyond the right margin of the window.  */
+         if (it.line_wrap == TRUNCATE && it.current_x >= it.last_visible_x
+             && it_overshoot_count == 0)
+           it_overshoot_count = 1;
          if (it_overshoot_count > 0)
            move_it_by_lines (&it, -it_overshoot_count);
 
          overshoot_handled = 1;
        }
       else if (IT_CHARPOS (it) == PT - 1
-              && FETCH_BYTE (PT - 1) == '\n'
-              && nlines < 0)
+              && FETCH_BYTE (PT_BYTE - 1) == '\n'
+              && nlines <= 0)
        {
          /* The position we started from was covered by a display
             property, so we moved to position before the string, and
-            backed up one line, because the character at PT - 1 is a
-            newline.  So we need one less line to go up.  */
+            backed up one line, because the character at PT - 1 is
+            a newline.  So we need one less line to go up (or exactly
+            one line to go down if nlines == 0).  */
          nlines++;
          /* But we still need to record that one line, in order to
             return the correct value to the caller.  */
          vpos_init = -1;
+
+         overshoot_handled = 1;
        }
       if (lcols_given)
        to_x = window_column_x (w, window, extract_float (lcols), lcols);
       if (nlines <= 0)
        {
          it.vpos = vpos_init;
+         it.current_y = 0;
          /* Do this even if LINES is 0, so that we move back to the
             beginning of the current line as we ought.  */
          if ((nlines < 0 && IT_CHARPOS (it) > 0)
@@ -2159,7 +2187,8 @@ whether or not it is currently displayed in some window.  */)
        }
       else if (overshoot_handled)
        {
-         it.vpos = 0;
+         it.vpos = vpos_init;
+         it.current_y = 0;
          move_it_by_lines (&it, min (PTRDIFF_MAX, nlines));
        }
       else
@@ -2173,6 +2202,7 @@ whether or not it is currently displayed in some window.  */)
              while (IT_CHARPOS (it) <= it_start)
                {
                  it.vpos = 0;
+                 it.current_y = 0;
                  move_it_by_lines (&it, 1);
                }
              if (nlines > 1)
@@ -2181,6 +2211,7 @@ whether or not it is currently displayed in some window.  */)
          else  /* it_start = ZV */
            {
              it.vpos = 0;
+             it.current_y = 0;
              move_it_by_lines (&it, min (PTRDIFF_MAX, nlines));
              /* We could have some display or overlay string at ZV,
                 in which case it.vpos will be nonzero now, while
@@ -2194,7 +2225,27 @@ whether or not it is currently displayed in some window.  */)
         was originally hscrolled, the goal column is interpreted as
         an addition to the hscroll amount.  */
       if (lcols_given)
-       move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
+       {
+         move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
+         /* If we find ourselves in the middle of an overlay string
+            which includes a newline after current string position,
+            we need to move by lines until we get out of the string,
+            and then reposition point at the requested X coordinate;
+            if we don't, the cursor will be placed just after the
+            string, which might not be the requested column.  */
+         if (nlines > 0 && it.area == TEXT_AREA)
+           {
+             while (it.method == GET_FROM_STRING
+                    && !it.string_from_display_prop_p
+                    && memchr (SSDATA (it.string) + IT_STRING_BYTEPOS (it),
+                               '\n',
+                               SBYTES (it.string) - IT_STRING_BYTEPOS (it)))
+               {
+                 move_it_by_lines (&it, 1);
+                 move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
+               }
+           }
+       }
 
       SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
       bidi_unshelve_cache (itdata, 0);
@@ -2207,7 +2258,7 @@ whether or not it is currently displayed in some window.  */)
                       old_charpos, old_bytepos);
     }
 
-  RETURN_UNGCPRO (make_number (it.vpos));
+  return make_number (it.vpos);
 }