]> code.delx.au - gnu-emacs/blobdiff - src/indent.c
Minor cleanups for character name escapes
[gnu-emacs] / src / indent.c
index 8660400e1cec8775f416098e7b848bd4aa442206..0ef8903501d6d43a977cddf8685f36fa3cb211db 100644 (file)
@@ -1,13 +1,13 @@
 /* Indentation functions.
 /* 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
    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
 
 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 "category.h"
 #include "composite.h"
 #include "indent.h"
-#include "keyboard.h"
 #include "frame.h"
 #include "window.h"
 #include "frame.h"
 #include "window.h"
-#include "termchar.h"
 #include "disptab.h"
 #include "intervals.h"
 #include "dispextern.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),
         : 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)
        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);
            *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;
        }
     }
          return width;
        }
     }
@@ -1928,7 +1940,22 @@ vmotion (register ptrdiff_t from, register ptrdiff_t from_byte,
                         -1, hscroll, 0, w);
 }
 
                         -1, hscroll, 0, w);
 }
 
-DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 2, 0,
+/* In window W (derived from WINDOW), return x coordinate for column
+   COL (derived from COLUMN).  */
+static int
+window_column_x (struct window *w, Lisp_Object window,
+                double col, Lisp_Object column)
+{
+  double x = col * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5;
+
+  /* FIXME: Should this be limited to W's dimensions?  */
+  if (! (INT_MIN <= x && x <= INT_MAX))
+    args_out_of_range (window, column);
+
+  return x;
+}
+
+DEFUN ("vertical-motion", Fvertical_motion, Svertical_motion, 1, 3, 0,
        doc: /* Move point to start of the screen line LINES lines down.
 If LINES is negative, this means moving up.
 
        doc: /* Move point to start of the screen line LINES lines down.
 If LINES is negative, this means moving up.
 
@@ -1951,28 +1978,32 @@ is).  If the line is scrolled horizontally, COLS is interpreted
 visually, i.e., as addition to the columns of text beyond the left
 edge of the window.
 
 visually, i.e., as addition to the columns of text beyond the left
 edge of the window.
 
+The optional third argument CUR-COL specifies the horizontal
+window-relative coordinate of point, in units of frame's canonical
+character width, where the function is invoked.  If this argument is
+omitted or nil, the function will determine the point coordinate by
+going back to the beginning of the line.
+
 `vertical-motion' always uses the current buffer,
 regardless of which buffer is displayed in WINDOW.
 This is consistent with other cursor motion functions
 and makes it possible to use `vertical-motion' in any buffer,
 whether or not it is currently displayed in some window.  */)
 `vertical-motion' always uses the current buffer,
 regardless of which buffer is displayed in WINDOW.
 This is consistent with other cursor motion functions
 and makes it possible to use `vertical-motion' in any buffer,
 whether or not it is currently displayed in some window.  */)
-  (Lisp_Object lines, Lisp_Object window)
+  (Lisp_Object lines, Lisp_Object window, Lisp_Object cur_col)
 {
   struct it it;
   struct text_pos pt;
   struct window *w;
   Lisp_Object old_buffer;
   EMACS_INT old_charpos IF_LINT (= 0), old_bytepos IF_LINT (= 0);
 {
   struct it it;
   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;
-  Lisp_Object lcols = Qnil;
-  double cols IF_LINT (= 0);
+  Lisp_Object lcols;
   void *itdata = NULL;
 
   /* Allow LINES to be of the form (HPOS . VPOS) aka (COLUMNS . LINES).  */
   void *itdata = NULL;
 
   /* Allow LINES to be of the form (HPOS . VPOS) aka (COLUMNS . LINES).  */
-  if (CONSP (lines) && (NUMBERP (XCAR (lines))))
+  bool lcols_given = CONSP (lines);
+  if (lcols_given)
     {
       lcols = XCAR (lines);
     {
       lcols = XCAR (lines);
-      cols = INTEGERP (lcols) ? (double) XINT (lcols) : XFLOAT_DATA (lcols);
       lines = XCDR (lines);
     }
 
       lines = XCDR (lines);
     }
 
@@ -1980,7 +2011,6 @@ whether or not it is currently displayed in some window.  */)
   w = decode_live_window (window);
 
   old_buffer = Qnil;
   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.  */
   if (XBUFFER (w->contents) != current_buffer)
     {
       /* Set the window's buffer temporarily to the current buffer.  */
@@ -2006,6 +2036,16 @@ 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;
       bool disp_string_at_start_p = 0;
       ptrdiff_t nlines = XINT (lines);
       int vpos_init = 0;
+      double start_col IF_LINT (= 0);
+      int start_x IF_LINT (= 0);
+      int to_x = -1;
+
+      bool start_x_given = !NILP (cur_col);
+      if (start_x_given)
+       {
+         start_col = extract_float (cur_col);
+         start_x = window_column_x (w, window, start_col, cur_col);
+       }
 
       itdata = bidi_shelve_cache ();
       SET_TEXT_POS (pt, PT, PT_BYTE);
 
       itdata = bidi_shelve_cache ();
       SET_TEXT_POS (pt, PT, PT_BYTE);
@@ -2042,11 +2082,19 @@ whether or not it is currently displayed in some window.  */)
        it_overshoot_count =
          !(it.method == GET_FROM_IMAGE || it.method == GET_FROM_STRETCH);
 
        it_overshoot_count =
          !(it.method == GET_FROM_IMAGE || it.method == GET_FROM_STRETCH);
 
-      /* Scan from the start of the line containing PT.  If we don't
-        do this, we start moving with IT->current_x == 0, while PT is
-        really at some x > 0.  */
-      reseat_at_previous_visible_line_start (&it);
-      it.current_x = it.hpos = 0;
+      if (start_x_given)
+       {
+         it.hpos = start_col;
+         it.current_x = start_x;
+       }
+      else
+       {
+         /* Scan from the start of the line containing PT.  If we don't
+            do this, we start moving with IT->current_x == 0, while PT is
+            really at some x > 0.  */
+         reseat_at_previous_visible_line_start (&it);
+         it.current_x = it.hpos = 0;
+       }
       if (IT_CHARPOS (it) != PT)
        /* We used to temporarily disable selective display here; the
           comment said this is "so we don't move too far" (2005-01-19
       if (IT_CHARPOS (it) != PT)
        /* We used to temporarily disable selective display here; the
           comment said this is "so we don't move too far" (2005-01-19
@@ -2082,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;
              && 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
          else if (disp_string_at_start_p && it.vpos > 0)
            {
              /* This is the case of a display string that spans
@@ -2090,35 +2147,46 @@ whether or not it is currently displayed in some window.  */)
                 screen lines we need to backtrack.  */
              it_overshoot_count = it.vpos;
            }
                 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
          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
        {
          /* 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;
          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;
          /* 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.vpos = vpos_init;
          /* 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)
+         if ((nlines < 0 && IT_CHARPOS (it) > 0)
+             || (nlines == 0 && !(start_x_given && start_x <= to_x)))
            move_it_by_lines (&it, max (PTRDIFF_MIN, nlines));
        }
       else if (overshoot_handled)
        {
            move_it_by_lines (&it, max (PTRDIFF_MIN, nlines));
        }
       else if (overshoot_handled)
        {
-         it.vpos = 0;
+         it.vpos = vpos_init;
          move_it_by_lines (&it, min (PTRDIFF_MAX, nlines));
        }
       else
          move_it_by_lines (&it, min (PTRDIFF_MAX, nlines));
        }
       else
@@ -2152,11 +2220,27 @@ whether or not it is currently displayed in some window.  */)
       /* Move to the goal column, if one was specified.  If the window
         was originally hscrolled, the goal column is interpreted as
         an addition to the hscroll amount.  */
       /* Move to the goal column, if one was specified.  If the window
         was originally hscrolled, the goal column is interpreted as
         an addition to the hscroll amount.  */
-      if (!NILP (lcols))
+      if (lcols_given)
        {
        {
-         int to_x = (int)(cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5);
-
          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));
        }
 
       SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
@@ -2170,7 +2254,7 @@ whether or not it is currently displayed in some window.  */)
                       old_charpos, old_bytepos);
     }
 
                       old_charpos, old_bytepos);
     }
 
-  RETURN_UNGCPRO (make_number (it.vpos));
+  return make_number (it.vpos);
 }
 
 
 }