/* Indentation functions.
- Copyright (C) 1985,86,87,88,93,94,95,98, 2000, 2001
- Free Software Foundation, Inc.
+ Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1998, 2000, 2001,
+ 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
This file is part of GNU Emacs.
You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
-the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-Boston, MA 02111-1307, USA. */
+the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+Boston, MA 02110-1301, USA. */
#include <config.h>
#include "lisp.h"
Some things in set last_known_column_point to -1
to mark the memorized value as invalid. */
-int last_known_column;
+double last_known_column;
/* Value of point when current_column was called. */
int last_known_column_modified;
-static int current_column_1 P_ ((void));
-static int position_indentation P_ ((int));
+static double current_column_1 P_ ((void));
+static double position_indentation P_ ((int));
/* Cache of beginning of line found by the last call of
current_column. */
Lisp_Object window;
{
Lisp_Object prop, position, overlay_limit, proplimit;
- Lisp_Object buffer;
+ Lisp_Object buffer, tmp;
int end, inv_p;
XSETFASTINT (position, pos);
/* No matter what. don't go past next overlay change. */
if (XFASTINT (overlay_limit) < XFASTINT (proplimit))
proplimit = overlay_limit;
- end = XFASTINT (Fnext_single_property_change (position, Qinvisible,
- buffer, proplimit));
+ tmp = Fnext_single_property_change (position, Qinvisible,
+ buffer, proplimit);
+ end = XFASTINT (tmp);
#if 0
/* Don't put the boundary in the middle of multibyte form if
there is no actual property change. */
} \
} while (0)
+
DEFUN ("current-column", Fcurrent_column, Scurrent_column, 0, 0, 0,
doc: /* Return the horizontal position of point. Beginning of line is column 0.
This is calculated by adding together the widths of all the displayed
Ignores finite width of frame, which means that this function may return
values greater than (frame-width).
Whether the line is visible (if `selective-display' is t) has no effect;
-however, ^M is treated as end of line when `selective-display' is t. */)
+however, ^M is treated as end of line when `selective-display' is t.
+Text that has an invisible property is considered as having width 0, unless
+`buffer-invisibility-spec' specifies that it is replaced by an ellipsis. */)
()
{
Lisp_Object temp;
- XSETFASTINT (temp, current_column ());
+ XSETFASTINT (temp, (int) current_column ()); /* iftc */
return temp;
}
last_known_column_point = 0;
}
-int
+double
current_column ()
{
register int col;
/* If the buffer has overlays, text properties,
or multibyte characters, use a more general algorithm. */
if (BUF_INTERVALS (current_buffer)
- || !NILP (current_buffer->overlays_before)
- || !NILP (current_buffer->overlays_after)
+ || current_buffer->overlays_before
+ || current_buffer->overlays_after
|| Z != Z_BYTE)
return current_column_1 ();
{
EMACS_INT i, n;
Lisp_Object charvec;
-
+
if (ptr == stop)
{
/* We stopped either for the beginning of the buffer
or for the gap. */
if (ptr == BEGV_ADDR)
break;
-
+
/* It was the gap. Jump back over it. */
stop = BEGV_ADDR;
ptr = GPT_ADDR;
-
+
/* Check whether that brings us to beginning of buffer. */
if (BEGV >= GPT)
break;
}
c = *--ptr;
-
+
if (dp && VECTORP (DISP_CHAR_VECTOR (dp, c)))
{
charvec = DISP_CHAR_VECTOR (dp, c);
charvec = Qnil;
n = 1;
}
-
+
for (i = n - 1; i >= 0; --i)
{
if (VECTORP (charvec))
/* This should be handled the same as
next_element_from_display_vector does it. */
Lisp_Object entry = AREF (charvec, i);
-
+
if (INTEGERP (entry)
&& GLYPH_CHAR_VALID_P (XFASTINT (entry)))
c = FAST_GLYPH_CHAR (XFASTINT (entry));
else
c = ' ';
}
-
+
if (c >= 040 && c < 0177)
col++;
else if (c == '\n'
{
if (tab_seen)
col = ((col + tab_width) / tab_width) * tab_width;
-
+
post_tab += col;
col = 0;
tab_seen = 1;
This function handles characters that are invisible
due to text properties or overlays. */
-static int
+static double
current_column_1 ()
{
register int tab_width = XINT (current_buffer->tab_width);
/* Start the scan at the beginning of this line with column number 0. */
register int col = 0;
int scan, scan_byte;
- int next_boundary, next_boundary_byte;
+ int next_boundary;
int opoint = PT, opoint_byte = PT_BYTE;
scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
scan = PT, scan_byte = PT_BYTE;
SET_PT_BOTH (opoint, opoint_byte);
next_boundary = scan;
- next_boundary_byte = scan_byte;
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
goto endloop;
if (scan != old_scan)
scan_byte = CHAR_TO_BYTE (scan);
- next_boundary_byte = CHAR_TO_BYTE (next_boundary);
}
/* Check composition sequence. */
{
unsigned char *ptr;
int bytes, width, wide_column;
-
+
ptr = BYTE_POS_ADDR (scan_byte);
MULTIBYTE_BYTES_WIDTH (ptr, dp);
scan_byte += bytes;
If BEG is nil, that stands for the beginning of STRING.
If END is nil, that stands for the end of STRING. */
-static int
+static double
string_display_width (string, beg, end)
Lisp_Object string, beg, end;
{
int b, e;
if (NILP (end))
- e = XSTRING (string)->size;
+ e = SCHARS (string);
else
{
CHECK_NUMBER (end);
}
/* Make a pointer for decrementing through the chars before point. */
- ptr = XSTRING (string)->data + e;
+ ptr = SDATA (string) + e;
/* Make a pointer to where consecutive chars leave off,
going backwards from point. */
- stop = XSTRING (string)->data + b;
+ stop = SDATA (string) + b;
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
}
\f
-static int position_indentation P_ ((int));
+static double position_indentation P_ ((int));
DEFUN ("current-indentation", Fcurrent_indentation, Scurrent_indentation,
0, 0, 0,
scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
- XSETFASTINT (val, position_indentation (PT_BYTE));
+ XSETFASTINT (val, (int) position_indentation (PT_BYTE)); /* iftc */
SET_PT_BOTH (opoint, opoint_byte);
return val;
}
-static int
+static double
position_indentation (pos_byte)
register int pos_byte;
{
/* The -1 and +1 arrange to point at the first byte of gap
(if STOP_POS_BYTE is the position of the gap)
rather than at the data after the gap. */
-
+
stop = BYTE_POS_ADDR (stop_pos_byte - 1) + 1;
p = BYTE_POS_ADDR (pos_byte);
}
int
indented_beyond_p (pos, pos_byte, column)
- int pos, pos_byte, column;
+ int pos, pos_byte;
+ double column;
{
- int val;
+ double val;
int opoint = PT, opoint_byte = PT_BYTE;
SET_PT_BOTH (pos, pos_byte);
val = position_indentation (PT_BYTE);
SET_PT_BOTH (opoint, opoint_byte);
- return val >= column;
+ return val >= column; /* hmm, float comparison */
}
\f
DEFUN ("move-to-column", Fmove_to_column, Smove_to_column, 1, 2, "p",
Lisp_Object val;
int prev_col = 0;
int c = 0;
- int next_boundary;
-
- int pos_byte, end_byte, next_boundary_byte;
+ int next_boundary, pos_byte;
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
CHECK_NATNUM (column);
pos = PT;
pos_byte = PT_BYTE;
end = ZV;
- end_byte = ZV_BYTE;
next_boundary = pos;
- next_boundary_byte = PT_BYTE;
/* If we're starting past the desired column,
back up to beginning of line and scan from there. */
pos = skip_invisible (pos, &next_boundary, end, Qnil);
if (pos != prev)
pos_byte = CHAR_TO_BYTE (pos);
- next_boundary_byte = CHAR_TO_BYTE (next_boundary);
if (pos >= end)
goto endloop;
}
goal_pt_byte = PT_BYTE;
Findent_to (make_number (col), Qnil);
SET_PT_BOTH (goal_pt, goal_pt_byte);
-
+
/* Set the last_known... vars consistently. */
col = goal;
}
WIDTH is the number of columns available to display text;
compute_motion uses this to handle continuation lines and such.
+ If WIDTH is -1, use width of window's text area adjusted for
+ continuation glyph when needed.
+
HSCROLL is the number of columns not being displayed at the left
margin; this is usually taken from a window's hscroll member.
TAB_OFFSET is the number of columns of the first tab that aren't
window_width - 1
- (has_vertical_scroll_bars
- ? FRAME_SCROLL_BAR_COLS (XFRAME (window->frame))
- : (window_width + window_left != frame_width))
+ ? WINDOW_CONFIG_SCROLL_BAR_COLS (window)
+ : (window_width + window_left != frame_cols))
where
- window_width is XFASTINT (w->width),
- window_left is XFASTINT (w->left),
+ window_width is XFASTINT (w->total_cols),
+ window_left is XFASTINT (w->left_col),
has_vertical_scroll_bars is
- FRAME_HAS_VERTICAL_SCROLL_BARS (XFRAME (WINDOW_FRAME (window)))
- and frame_width = FRAME_WIDTH (XFRAME (window->frame))
+ WINDOW_HAS_VERTICAL_SCROLL_BAR (window)
+ and frame_cols = FRAME_COLS (XFRAME (window->frame))
- Or you can let window_internal_width do this all for you, and write:
- window_internal_width (w) - 1
+ Or you can let window_box_text_cols do this all for you, and write:
+ window_box_text_cols (w) - 1
The `-1' accounts for the continuation-line backslashes; the rest
accounts for window borders if the window is split horizontally, and
= (INTEGERP (current_buffer->selective_display)
? XINT (current_buffer->selective_display)
: !NILP (current_buffer->selective_display) ? -1 : 0);
- int prev_hpos = 0;
int selective_rlen
= (selective && dp && VECTORP (DISP_INVIS_VECTOR (dp))
? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
int wide_column_end_hpos = 0;
int prev_pos; /* Previous buffer position. */
int prev_pos_byte; /* Previous buffer position. */
+ int prev_hpos = 0;
+ int prev_vpos = 0;
int contin_hpos; /* HPOS of last column of continued line. */
int prev_tab_offset; /* Previous tab offset. */
+ int continuation_glyph_width;
XSETBUFFER (buffer, current_buffer);
XSETWINDOW (window, win);
if (tab_width <= 0 || tab_width > 1000)
tab_width = 8;
+ /* Negative width means use all available text columns. */
+ if (width < 0)
+ {
+ width = window_box_text_cols (win);
+ /* We must make room for continuation marks if we don't have fringes. */
+#ifdef HAVE_WINDOW_SYSTEM
+ if (!FRAME_WINDOW_P (XFRAME (win->frame)))
+#endif
+ width -= 1;
+ }
+
+ continuation_glyph_width = 1;
+#ifdef HAVE_WINDOW_SYSTEM
+ if (FRAME_WINDOW_P (XFRAME (win->frame)))
+ continuation_glyph_width = 0; /* In the fringe. */
+#endif
+
immediate_quit = 1;
QUIT;
pos = prev_pos;
pos_byte = prev_pos_byte;
hpos = prev_hpos;
+ vpos = prev_vpos;
tab_offset = prev_tab_offset;
}
break;
W_ ^---- next after the point
^---- next char. after the point.
----------
- In case of wide-column character
+ In case of wide-column character
The problem here is continuation at a wide-column character.
In this case, the line may shorter less than WIDTH.
{
if (hscroll
|| (truncate_partial_width_windows
- && width + 1 < FRAME_WIDTH (XFRAME (WINDOW_FRAME (win))))
+ && ((width + continuation_glyph_width)
+ < FRAME_COLS (XFRAME (WINDOW_FRAME (win)))))
|| !NILP (current_buffer->truncate_lines))
{
/* Truncating: skip to newline, unless we are already past
if (pos >= next_boundary)
next_boundary = pos + 1;
prev_hpos = width;
+ prev_vpos = vpos;
prev_tab_offset = tab_offset;
}
}
vpos++;
contin_hpos = prev_hpos;
prev_hpos = 0;
+ prev_vpos = vpos;
}
}
pos = prev_pos;
pos_byte = prev_pos_byte;
hpos = prev_hpos;
+ vpos = prev_vpos;
tab_offset = prev_tab_offset;
/* NOTE on contin_hpos, hpos, and prev_hpos.
hpos = contin_hpos;
vpos = vpos - 1;
}
- else if (c == '\n')
- /* If previous character is NEWLINE,
- set VPOS back to previous line */
- vpos = vpos - 1;
break;
}
pos = prev_pos;
pos_byte = prev_pos_byte;
hpos = prev_hpos;
+ vpos = prev_vpos;
tab_offset = prev_tab_offset;
}
break;
break;
prev_hpos = hpos;
+ prev_vpos = vpos;
prev_pos = pos;
prev_pos_byte = pos_byte;
wide_column_end_hpos = 0;
{
EMACS_INT i, n;
Lisp_Object charvec;
-
+
c = FETCH_BYTE (pos_byte);
/* Check composition sequence. */
/* This should be handled the same as
next_element_from_display_vector does it. */
Lisp_Object entry = AREF (charvec, i);
-
+
if (INTEGERP (entry)
&& GLYPH_CHAR_VALID_P (XFASTINT (entry)))
c = FAST_GLYPH_CHAR (XFASTINT (entry));
else
c = ' ';
}
-
+
if (c >= 040 && c < 0177)
hpos++;
else if (c == '\t')
else if (c == '\n')
{
if (selective > 0
- && indented_beyond_p (pos, pos_byte, selective))
+ && indented_beyond_p (pos, pos_byte,
+ (double) selective)) /* iftc */
{
/* If (pos == to), we don't have to take care of
selective display. */
pos_byte = CHAR_TO_BYTE (pos);
}
while (pos < to
- && indented_beyond_p (pos, pos_byte, selective));
+ && indented_beyond_p (pos, pos_byte,
+ (double) selective)); /* iftc */
/* Allow for the " ..." that is displayed for them. */
if (selective_rlen)
{
hpos -= hscroll;
/* Count the truncation glyph on column 0 */
if (hscroll > 0)
- hpos++;
+ hpos += continuation_glyph_width;
tab_offset = 0;
}
contin_hpos = 0;
to position TO or position TOPOS--another cons of the form (HPOS . VPOS)--
and return the ending buffer position and screen location.
+If TOPOS is nil, the actual width and height of the window's
+text area are used.
+
There are three additional arguments:
WIDTH is the number of columns available to display text;
-this affects handling of continuation lines.
-This is usually the value returned by `window-width', less one (to allow
-for the continuation glyph).
+this affects handling of continuation lines. A value of nil
+corresponds to the actual number of available text columns.
OFFSETS is either nil or a cons cell (HSCROLL . TAB-OFFSET).
HSCROLL is the number of columns not being displayed at the left
Lisp_Object from, frompos, to, topos;
Lisp_Object width, offsets, window;
{
+ struct window *w;
Lisp_Object bufpos, hpos, vpos, prevhpos;
struct position *pos;
int hscroll, tab_offset;
CHECK_NUMBER_CAR (frompos);
CHECK_NUMBER_CDR (frompos);
CHECK_NUMBER_COERCE_MARKER (to);
- CHECK_CONS (topos);
- CHECK_NUMBER_CAR (topos);
- CHECK_NUMBER_CDR (topos);
- CHECK_NUMBER (width);
+ if (!NILP (topos))
+ {
+ CHECK_CONS (topos);
+ CHECK_NUMBER_CAR (topos);
+ CHECK_NUMBER_CDR (topos);
+ }
+ if (!NILP (width))
+ CHECK_NUMBER (width);
+
if (!NILP (offsets))
{
CHECK_CONS (offsets);
window = Fselected_window ();
else
CHECK_LIVE_WINDOW (window);
+ w = XWINDOW (window);
if (XINT (from) < BEGV || XINT (from) > ZV)
args_out_of_range_3 (from, make_number (BEGV), make_number (ZV));
pos = compute_motion (XINT (from), XINT (XCDR (frompos)),
XINT (XCAR (frompos)), 0,
- XINT (to), XINT (XCDR (topos)),
- XINT (XCAR (topos)),
- XINT (width), hscroll, tab_offset,
+ XINT (to),
+ (NILP (topos)
+ ? window_internal_height (w)
+ : XINT (XCDR (topos))),
+ (NILP (topos)
+ ? (window_box_text_cols (w)
+ - (
+#ifdef HAVE_WINDOW_SYSTEM
+ FRAME_WINDOW_P (XFRAME (w->frame)) ? 0 :
+#endif
+ 1))
+ : XINT (XCAR (topos))),
+ (NILP (width) ? -1 : XINT (width)),
+ hscroll, tab_offset,
XWINDOW (window));
XSETFASTINT (bufpos, pos->bufpos);
register int from, vtarget;
struct window *w;
{
- int width = window_internal_width (w) - 1;
int hscroll = XINT (w->hscroll);
struct position pos;
/* vpos is cumulative vertical position, changed as from is changed */
register int vpos = 0;
- Lisp_Object prevline;
+ int prevline;
register int first;
int from_byte;
int lmargin = hscroll > 0 ? 1 - hscroll : 0;
{
Lisp_Object propval;
- XSETFASTINT (prevline, find_next_newline_no_quit (from - 1, -1));
- while (XFASTINT (prevline) > BEGV
+ prevline = find_next_newline_no_quit (from - 1, -1);
+ while (prevline > BEGV
&& ((selective > 0
- && indented_beyond_p (XFASTINT (prevline),
- CHAR_TO_BYTE (XFASTINT (prevline)),
- selective))
- /* watch out for newlines with `invisible' property */
- || (propval = Fget_char_property (prevline,
+ && indented_beyond_p (prevline,
+ CHAR_TO_BYTE (prevline),
+ (double) selective)) /* iftc */
+ /* Watch out for newlines with `invisible' property.
+ When moving upward, check the newline before. */
+ || (propval = Fget_char_property (make_number (prevline - 1),
Qinvisible,
text_prop_object),
TEXT_PROP_MEANS_INVISIBLE (propval))))
- XSETFASTINT (prevline,
- find_next_newline_no_quit (XFASTINT (prevline) - 1,
- -1));
- pos = *compute_motion (XFASTINT (prevline), 0,
- lmargin + (XFASTINT (prevline) == BEG
- ? start_hpos : 0),
+ prevline = find_next_newline_no_quit (prevline - 1, -1);
+ pos = *compute_motion (prevline, 0,
+ lmargin + (prevline == BEG ? start_hpos : 0),
0,
- from,
+ from,
/* Don't care for VPOS... */
1 << (BITS_PER_SHORT - 1),
/* ... nor HPOS. */
1 << (BITS_PER_SHORT - 1),
- width, hscroll,
+ -1, hscroll,
/* This compensates for start_hpos
so that a tab as first character
still occupies 8 columns. */
- (XFASTINT (prevline) == BEG
- ? -start_hpos : 0),
+ (prevline == BEG ? -start_hpos : 0),
w);
vpos -= pos.vpos;
first = 0;
- from = XFASTINT (prevline);
+ from = prevline;
}
/* If we made exactly the desired vertical distance,
{
Lisp_Object propval;
- XSETFASTINT (prevline, find_next_newline_no_quit (from, -1));
- while (XFASTINT (prevline) > BEGV
+ prevline = find_next_newline_no_quit (from, -1);
+ while (prevline > BEGV
&& ((selective > 0
- && indented_beyond_p (XFASTINT (prevline),
- CHAR_TO_BYTE (XFASTINT (prevline)),
- selective))
- /* watch out for newlines with `invisible' property */
- || (propval = Fget_char_property (prevline, Qinvisible,
+ && indented_beyond_p (prevline,
+ CHAR_TO_BYTE (prevline),
+ (double) selective)) /* iftc */
+ /* Watch out for newlines with `invisible' property.
+ When moving downward, check the newline after. */
+ || (propval = Fget_char_property (make_number (prevline),
+ Qinvisible,
text_prop_object),
TEXT_PROP_MEANS_INVISIBLE (propval))))
- XSETFASTINT (prevline,
- find_next_newline_no_quit (XFASTINT (prevline) - 1,
- -1));
- pos = *compute_motion (XFASTINT (prevline), 0,
- lmargin + (XFASTINT (prevline) == BEG
+ prevline = find_next_newline_no_quit (prevline - 1, -1);
+ pos = *compute_motion (prevline, 0,
+ lmargin + (prevline == BEG
? start_hpos : 0),
0,
- from,
+ from,
/* Don't care for VPOS... */
1 << (BITS_PER_SHORT - 1),
/* ... nor HPOS. */
1 << (BITS_PER_SHORT - 1),
- width, hscroll,
- (XFASTINT (prevline) == BEG ? -start_hpos : 0),
+ -1, hscroll,
+ (prevline == BEG ? -start_hpos : 0),
w);
did_motion = 1;
}
}
return compute_motion (from, vpos, pos.hpos, did_motion,
ZV, vtarget, - (1 << (BITS_PER_SHORT - 1)),
- width, hscroll,
+ -1, hscroll,
pos.tab_offset - (from == BEG ? start_hpos : 0),
w);
}
old_buffer = w->buffer;
XSETBUFFER (w->buffer, current_buffer);
}
-
- SET_TEXT_POS (pt, PT, PT_BYTE);
- start_display (&it, w, pt);
- move_it_by_lines (&it, XINT (lines), 0);
- SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+
+ if (noninteractive)
+ {
+ struct position pos;
+ pos = *vmotion (PT, XINT (lines), w);
+ SET_PT_BOTH (pos.bufpos, pos.bytepos);
+ }
+ else
+ {
+ int it_start;
+ int oselective;
+ int start_on_image_or_stretch_p;
+
+ SET_TEXT_POS (pt, PT, PT_BYTE);
+ start_display (&it, w, pt);
+
+ /* 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. The effect is, in continuation lines, that
+ we end up with the iterator placed at where it thinks X is 0,
+ while the end position is really at some X > 0, the same X that
+ PT had. */
+ it_start = IT_CHARPOS (it);
+ start_on_image_or_stretch_p = (it.method == GET_FROM_IMAGE
+ || it.method == GET_FROM_STRETCH);
+ reseat_at_previous_visible_line_start (&it);
+ it.current_x = it.hpos = 0;
+ /* Temporarily disable selective display so we don't move too far */
+ oselective = it.selective;
+ it.selective = 0;
+ move_it_to (&it, PT, -1, -1, -1, MOVE_TO_POS);
+ it.selective = oselective;
+
+ /* Move back if we got too far. This may happen if
+ truncate-lines is on and PT is beyond right margin.
+ It may also happen if it_start is on an image or a stretch
+ glyph -- in that case, don't go back. */
+ if (IT_CHARPOS (it) > it_start && XINT (lines) > 0
+ && !start_on_image_or_stretch_p)
+ move_it_by_lines (&it, -1, 0);
+
+ it.vpos = 0;
+ /* Do this even if LINES is 0, so that we move back
+ to the beginning of the current line as we ought. */
+ if (XINT (lines) >= 0 || IT_CHARPOS (it) > 0)
+ move_it_by_lines (&it, XINT (lines), 0);
+
+ SET_PT_BOTH (IT_CHARPOS (it), IT_BYTEPOS (it));
+ }
if (BUFFERP (old_buffer))
w->buffer = old_buffer;
-
+
RETURN_UNGCPRO (make_number (it.vpos));
}
defsubr (&Svertical_motion);
defsubr (&Scompute_motion);
}
+
+/* arch-tag: 9adfea44-71f7-4988-8ee3-96da15c502cc
+ (do not change this comment) */