/* 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
#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"
: 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)
*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;
}
}
-1, hscroll, 0, w);
}
+/* 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.
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);
+ EMACS_INT old_charpos UNINIT, old_bytepos UNINIT;
+ Lisp_Object lcols;
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);
- cols = INTEGERP (lcols) ? (double) XINT (lcols) : XFLOAT_DATA (lcols);
lines = XCDR (lines);
}
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. */
bool disp_string_at_start_p = 0;
ptrdiff_t nlines = XINT (lines);
int vpos_init = 0;
- double start_col;
- int start_x;
- bool start_x_given = false;
+ double start_col UNINIT;
+ int start_x UNINIT;
int to_x = -1;
- if (!NILP (cur_col))
+ bool start_x_given = !NILP (cur_col);
+ if (start_x_given)
{
- CHECK_NUMBER_OR_FLOAT (cur_col);
- start_col =
- INTEGERP (cur_col)
- ? (double) XINT (cur_col)
- : XFLOAT_DATA (cur_col);
- start_x =
- (int)(start_col * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5);
- start_x_given = true;
+ start_col = extract_float (cur_col);
+ start_x = window_column_x (w, window, start_col, cur_col);
}
itdata = bidi_shelve_cache ();
if (start_x_given)
{
- it.hpos = (int) start_col;
+ it.hpos = start_col;
it.current_x = start_x;
}
else
&& 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
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 (!NILP (lcols))
- to_x = (int)(cols * FRAME_COLUMN_WIDTH (XFRAME (w->frame)) + 0.5);
+ 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)
}
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
while (IT_CHARPOS (it) <= it_start)
{
it.vpos = 0;
+ it.current_y = 0;
move_it_by_lines (&it, 1);
}
if (nlines > 1)
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
/* 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))
- move_it_in_display_line (&it, ZV, first_x + to_x, MOVE_TO_X);
+ if (lcols_given)
+ {
+ 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);
old_charpos, old_bytepos);
}
- RETURN_UNGCPRO (make_number (it.vpos));
+ return make_number (it.vpos);
}