/* Indentation functions.
Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1998, 2000, 2001,
- 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+ 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 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 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Emacs is distributed in the hope that it will be useful,
Boston, MA 02110-1301, USA. */
#include <config.h>
+#include <stdio.h>
+
#include "lisp.h"
#include "buffer.h"
-#include "charset.h"
+#include "character.h"
#include "category.h"
#include "indent.h"
#include "keyboard.h"
/* Indentation can insert tabs if this is non-zero;
otherwise always uses spaces. */
-int indent_tabs_mode;
+static int indent_tabs_mode;
#define CR 015
Some things in set last_known_column_point to -1
to mark the memorized value as invalid. */
-double last_known_column;
+static double last_known_column;
/* Value of point when current_column was called. */
-int last_known_column_point;
+EMACS_INT last_known_column_point;
/* Value of MODIFF when current_column was called. */
-int last_known_column_modified;
+static int last_known_column_modified;
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. */
-int current_column_bol_cache;
+static EMACS_INT current_column_bol_cache;
/* Get the display table to use for the current buffer. */
return 0;
}
-/* Return true iff the display table DISPTAB specifies the same widths
+/* Return true if the display table DISPTAB specifies the same widths
for characters as WIDTHTAB. We use this to decide when to
invalidate the buffer's width_run_cache. */
characters immediately following, then *NEXT_BOUNDARY_P
will equal the return value. */
-int
+EMACS_INT
skip_invisible (pos, next_boundary_p, to, window)
- int pos;
- int *next_boundary_p;
- int to;
+ EMACS_INT pos;
+ EMACS_INT *next_boundary_p;
+ EMACS_INT to;
Lisp_Object window;
{
Lisp_Object prop, position, overlay_limit, proplimit;
Lisp_Object buffer, tmp;
- int end, inv_p;
+ EMACS_INT end;
+ int inv_p;
XSETFASTINT (position, pos);
XSETBUFFER (buffer, current_buffer);
int *len, *len_byte, *width;
{
Lisp_Object prop;
- int start, end;
+ EMACS_INT start, end;
int id;
if (! find_composition (pos, -1, &start, &end, &prop, Qnil)
if (dp != 0 && VECTORP (DISP_CHAR_VECTOR (dp, c))) \
width = XVECTOR (DISP_CHAR_VECTOR (dp, c))->size; \
else \
- width = WIDTH_BY_CHAR_HEAD (*p); \
+ width = CHAR_WIDTH (c); \
if (width > 1) \
wide_column = width; \
} \
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));
+ if (GLYPH_CODE_P (entry)
+ && GLYPH_CODE_CHAR_VALID_P (entry))
+ c = GLYPH_CODE_CHAR (entry);
else
c = ' ';
}
return col;
}
\f
-/* Return the column number of position POS
- by scanning forward from the beginning of the line.
- This function handles characters that are invisible
- due to text properties or overlays. */
+extern Lisp_Object Qspace, QCwidth, QCalign_to;
-static double
-current_column_1 ()
+/* Check the presence of a display property and compute its width.
+ If a property was found and its width was found as well, return
+ its width (>= 0) and set the position of the end of the property
+ in ENDPOS.
+ Otherwise just return -1. */
+static int
+check_display_width (EMACS_INT pos, EMACS_INT col, EMACS_INT *endpos)
{
- register int tab_width = XINT (current_buffer->tab_width);
+ Lisp_Object val, overlay;
+
+ if (CONSP (val = get_char_property_and_overlay
+ (make_number (pos), Qdisplay, Qnil, &overlay))
+ && EQ (Qspace, XCAR (val)))
+ { /* FIXME: Use calc_pixel_width_or_height, as in term.c. */
+ Lisp_Object plist = XCDR (val), prop;
+ int width = -1;
+
+ if ((prop = Fplist_get (plist, QCwidth), NATNUMP (prop)))
+ width = XINT (prop);
+ else if (FLOATP (prop))
+ width = (int)(XFLOAT_DATA (prop) + 0.5);
+ else if ((prop = Fplist_get (plist, QCalign_to), NATNUMP (prop)))
+ width = XINT (prop) - col;
+ else if (FLOATP (prop))
+ width = (int)(XFLOAT_DATA (prop) + 0.5) - col;
+
+ if (width >= 0)
+ {
+ EMACS_INT start;
+ if (OVERLAYP (overlay))
+ *endpos = OVERLAY_POSITION (OVERLAY_END (overlay));
+ else
+ get_property_and_range (pos, Qdisplay, &val, &start, endpos, Qnil);
+ return width;
+ }
+ }
+ return -1;
+}
+
+/* Scanning from the beginning of the current line, stop at the buffer
+ position ENDPOS or at the column GOALCOL or at the end of line, whichever
+ comes first.
+ Return the resulting buffer position and column in ENDPOS and GOALCOL.
+ PREVCOL gets set to the column of the previous position (it's always
+ strictly smaller than the goal column). */
+static void
+scan_for_column (EMACS_INT *endpos, EMACS_INT *goalcol, EMACS_INT *prevcol)
+{
+ register EMACS_INT tab_width = XINT (current_buffer->tab_width);
register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
register struct Lisp_Char_Table *dp = buffer_display_table ();
int multibyte = !NILP (current_buffer->enable_multibyte_characters);
/* Start the scan at the beginning of this line with column number 0. */
- register int col = 0;
- int scan, scan_byte;
- int next_boundary;
- int opoint = PT, opoint_byte = PT_BYTE;
-
+ register EMACS_INT col = 0, prev_col = 0;
+ EMACS_INT goal = goalcol ? *goalcol : MOST_POSITIVE_FIXNUM;
+ EMACS_INT end = endpos ? *endpos : PT;
+ EMACS_INT scan, scan_byte;
+ EMACS_INT next_boundary;
+ {
+ EMACS_INT opoint = PT, opoint_byte = PT_BYTE;
scan_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, 1);
current_column_bol_cache = PT;
scan = PT, scan_byte = PT_BYTE;
SET_PT_BOTH (opoint, opoint_byte);
next_boundary = scan;
+ }
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
/* Scan forward to the target position. */
- while (scan < opoint)
+ while (scan < end)
{
int c;
/* Occasionally we may need to skip invisible text. */
while (scan == next_boundary)
{
- int old_scan = scan;
+ EMACS_INT old_scan = scan;
/* This updates NEXT_BOUNDARY to the next place
where we might need to skip more invisible text. */
- scan = skip_invisible (scan, &next_boundary, opoint, Qnil);
- if (scan >= opoint)
- goto endloop;
+ scan = skip_invisible (scan, &next_boundary, end, Qnil);
if (scan != old_scan)
scan_byte = CHAR_TO_BYTE (scan);
+ if (scan >= end)
+ goto endloop;
}
- /* Check composition sequence. */
- {
+ /* Test reaching the goal column. We do this after skipping
+ invisible characters, so that we put point before the
+ character on which the cursor will appear. */
+ if (col >= goal)
+ break;
+ prev_col = col;
+
+ { /* Check composition sequence. */
int len, len_byte, width;
- if (check_composition (scan, scan_byte, opoint,
+ if (check_composition (scan, scan_byte, end,
&len, &len_byte, &width))
{
scan += len;
scan_byte += len_byte;
- if (scan <= opoint)
+ if (scan <= end)
col += width;
continue;
}
}
+ { /* Check display property. */
+ EMACS_INT end;
+ int width = check_display_width (scan, col, &end);
+ if (width >= 0)
+ {
+ col += width;
+ if (end > scan) /* Avoid infinite loops with 0-width overlays. */
+ {
+ scan = end; scan_byte = charpos_to_bytepos (scan);
+ continue;
+ }
+ }
+ }
+
c = FETCH_BYTE (scan_byte);
+ /* See if there is a display table and it relates
+ to this character. */
+
if (dp != 0
&& ! (multibyte && BASE_LEADING_CODE_P (c))
&& VECTORP (DISP_CHAR_VECTOR (dp, c)))
EMACS_INT i, n;
/* This character is displayed using a vector of glyphs.
- Update the column based on those glyphs. */
+ Update the column/position based on those glyphs. */
charvec = DISP_CHAR_VECTOR (dp, c);
n = ASIZE (charvec);
{
/* This should be handled the same as
next_element_from_display_vector does it. */
- Lisp_Object entry;
- entry = AREF (charvec, i);
+ Lisp_Object entry = AREF (charvec, i);
- if (INTEGERP (entry)
- && GLYPH_CHAR_VALID_P (XFASTINT (entry)))
- c = FAST_GLYPH_CHAR (XFASTINT (entry));
+ if (GLYPH_CODE_P (entry)
+ && GLYPH_CODE_CHAR_VALID_P (entry))
+ c = GLYPH_CODE_CHAR (entry);
else
c = ' ';
}
else
{
- /* The display table says nothing for this character.
- Display it as itself. */
+ /* The display table doesn't affect this character;
+ it displays as itself. */
if (c == '\n')
goto endloop;
}
else if (multibyte && BASE_LEADING_CODE_P (c))
{
+ /* Start of multi-byte form. */
unsigned char *ptr;
int bytes, width, wide_column;
ptr = BYTE_POS_ADDR (scan_byte);
MULTIBYTE_BYTES_WIDTH (ptr, dp);
- scan_byte += bytes;
/* Subtract one to compensate for the increment
that is going to happen below. */
- scan_byte--;
+ scan_byte += bytes - 1;
col += width;
}
else if (ctl_arrow && (c < 040 || c == 0177))
last_known_column_point = PT;
last_known_column_modified = MODIFF;
+ if (goalcol)
+ *goalcol = col;
+ if (endpos)
+ *endpos = scan;
+ if (prevcol)
+ *prevcol = prev_col;
+}
+
+/* Return the column number of position POS
+ by scanning forward from the beginning of the line.
+ This function handles characters that are invisible
+ due to text properties or overlays. */
+
+static double
+current_column_1 ()
+{
+ EMACS_INT col = MOST_POSITIVE_FIXNUM;
+ EMACS_INT opoint = PT;
+
+ scan_for_column (&opoint, &col, NULL);
return col;
}
\f
position_indentation (pos_byte)
register int pos_byte;
{
- register int column = 0;
- register int tab_width = XINT (current_buffer->tab_width);
+ register EMACS_INT column = 0;
+ register EMACS_INT tab_width = XINT (current_buffer->tab_width);
register unsigned char *p;
register unsigned char *stop;
unsigned char *start;
- int next_boundary_byte = pos_byte;
- int ceiling = next_boundary_byte;
+ EMACS_INT next_boundary_byte = pos_byte;
+ EMACS_INT ceiling = next_boundary_byte;
if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
{
while (p == stop)
{
- int stop_pos_byte;
+ EMACS_INT stop_pos_byte;
/* If we have updated P, set POS_BYTE to match.
The first time we enter the loop, POS_BYTE is already right. */
return column;
if (pos_byte == next_boundary_byte)
{
- int next_boundary;
- int pos = BYTE_TO_CHAR (pos_byte);
+ EMACS_INT next_boundary;
+ EMACS_INT pos = BYTE_TO_CHAR (pos_byte);
pos = skip_invisible (pos, &next_boundary, ZV, Qnil);
pos_byte = CHAR_TO_BYTE (pos);
next_boundary_byte = CHAR_TO_BYTE (next_boundary);
(column, force)
Lisp_Object column, force;
{
- register int pos;
- register int col = current_column ();
- register int goal;
- register int end;
- register int tab_width = XINT (current_buffer->tab_width);
- register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
- register struct Lisp_Char_Table *dp = buffer_display_table ();
- register int multibyte = !NILP (current_buffer->enable_multibyte_characters);
+ EMACS_INT pos;
+ EMACS_INT col, prev_col;
+ EMACS_INT goal;
- Lisp_Object val;
- int prev_col = 0;
- int c = 0;
- int next_boundary, pos_byte;
-
- if (tab_width <= 0 || tab_width > 1000) tab_width = 8;
CHECK_NATNUM (column);
goal = XINT (column);
- pos = PT;
- pos_byte = PT_BYTE;
- end = ZV;
+ col = goal;
+ pos = ZV;
+ scan_for_column (&pos, &col, &prev_col);
- /* If we're starting past the desired column,
- back up to beginning of line and scan from there. */
- if (col > goal)
- {
- end = pos;
- pos = current_column_bol_cache;
- pos_byte = CHAR_TO_BYTE (pos);
- col = 0;
- }
-
- next_boundary = pos;
+ SET_PT (pos);
- while (pos < end)
+ /* If a tab char made us overshoot, change it to spaces
+ and scan through it again. */
+ if (!NILP (force) && col > goal)
{
- while (pos == next_boundary)
- {
- int prev = pos;
- pos = skip_invisible (pos, &next_boundary, end, Qnil);
- if (pos != prev)
- pos_byte = CHAR_TO_BYTE (pos);
- if (pos >= end)
- goto endloop;
- }
-
- /* Test reaching the goal column. We do this after skipping
- invisible characters, so that we put point before the
- character on which the cursor will appear. */
- if (col >= goal)
- break;
-
- /* Check composition sequence. */
- {
- int len, len_byte, width;
-
- if (check_composition (pos, pos_byte, Z, &len, &len_byte, &width))
- {
- pos += len;
- pos_byte += len_byte;
- col += width;
- continue;
- }
- }
-
- c = FETCH_BYTE (pos_byte);
-
- /* See if there is a display table and it relates
- to this character. */
-
- if (dp != 0
- && ! (multibyte && BASE_LEADING_CODE_P (c))
- && VECTORP (DISP_CHAR_VECTOR (dp, c)))
- {
- Lisp_Object charvec;
- EMACS_INT i, n;
-
- /* This character is displayed using a vector of glyphs.
- Update the position based on those glyphs. */
-
- charvec = DISP_CHAR_VECTOR (dp, c);
- n = ASIZE (charvec);
-
- for (i = 0; i < n; i++)
- {
- /* This should be handled the same as
- next_element_from_display_vector does it. */
-
- Lisp_Object entry;
- entry = AREF (charvec, i);
-
- if (INTEGERP (entry)
- && GLYPH_CHAR_VALID_P (XFASTINT (entry)))
- c = FAST_GLYPH_CHAR (XFASTINT (entry));
- else
- c = ' ';
+ int c;
+ EMACS_INT pos_byte = PT_BYTE;
- if (c == '\n')
- goto endloop;
- if (c == '\r' && EQ (current_buffer->selective_display, Qt))
- goto endloop;
- if (c == '\t')
- {
- prev_col = col;
- col += tab_width;
- col = col / tab_width * tab_width;
- }
- else
- ++col;
- }
- }
- else
+ DEC_POS (pos_byte);
+ c = FETCH_CHAR (pos_byte);
+ if (c == '\t' && prev_col < goal)
{
- /* The display table doesn't affect this character;
- it displays as itself. */
-
- if (c == '\n')
- goto endloop;
- if (c == '\r' && EQ (current_buffer->selective_display, Qt))
- goto endloop;
- if (c == '\t')
- {
- prev_col = col;
- col += tab_width;
- col = col / tab_width * tab_width;
- }
- else if (ctl_arrow && (c < 040 || c == 0177))
- col += 2;
- else if (c < 040 || c == 0177)
- col += 4;
- else if (c < 0177)
- col++;
- else if (multibyte && BASE_LEADING_CODE_P (c))
- {
- /* Start of multi-byte form. */
- unsigned char *ptr;
- int bytes, width, wide_column;
-
- ptr = BYTE_POS_ADDR (pos_byte);
- MULTIBYTE_BYTES_WIDTH (ptr, dp);
- pos_byte += bytes - 1;
- col += width;
- }
- else
- col += 4;
+ EMACS_INT goal_pt, goal_pt_byte;
+
+ /* Insert spaces in front of the tab to reach GOAL. Do this
+ first so that a marker at the end of the tab gets
+ adjusted. */
+ SET_PT_BOTH (PT - 1, PT_BYTE - 1);
+ Finsert_char (make_number (' '), make_number (goal - prev_col), Qt);
+
+ /* Now delete the tab, and indent to COL. */
+ del_range (PT, PT + 1);
+ goal_pt = PT;
+ 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;
}
-
- pos++;
- pos_byte++;
- }
- endloop:
-
- SET_PT_BOTH (pos, pos_byte);
-
- /* If a tab char made us overshoot, change it to spaces
- and scan through it again. */
- if (!NILP (force) && col > goal && c == '\t' && prev_col < goal)
- {
- int goal_pt, goal_pt_byte;
-
- /* Insert spaces in front of the tab to reach GOAL. Do this
- first so that a marker at the end of the tab gets
- adjusted. */
- SET_PT_BOTH (PT - 1, PT_BYTE - 1);
- Finsert_char (make_number (' '), make_number (goal - prev_col), Qt);
-
- /* Now delete the tab, and indent to COL. */
- del_range (PT, PT + 1);
- goal_pt = PT;
- 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;
}
/* If line ends prematurely, add space to the end. */
last_known_column_point = PT;
last_known_column_modified = MODIFF;
- XSETFASTINT (val, col);
- return val;
+ return make_number (col);
}
\f
/* compute_motion: compute buffer posn given screen posn and vice versa */
struct position *
compute_motion (from, fromvpos, fromhpos, did_motion, to, tovpos, tohpos, width, hscroll, tab_offset, win)
- int from, fromvpos, fromhpos, to, tovpos, tohpos;
+ EMACS_INT from, fromvpos, fromhpos, to, tovpos, tohpos;
int did_motion;
- register int width;
- int hscroll, tab_offset;
+ EMACS_INT width;
+ EMACS_INT hscroll, tab_offset;
struct window *win;
{
- register int hpos = fromhpos;
- register int vpos = fromvpos;
+ register EMACS_INT hpos = fromhpos;
+ register EMACS_INT vpos = fromvpos;
- register int pos;
- int pos_byte;
+ register EMACS_INT pos;
+ EMACS_INT pos_byte;
register int c = 0;
- register int tab_width = XFASTINT (current_buffer->tab_width);
+ register EMACS_INT tab_width = XFASTINT (current_buffer->tab_width);
register int ctl_arrow = !NILP (current_buffer->ctl_arrow);
register struct Lisp_Char_Table *dp = window_display_table (win);
int selective
? XVECTOR (DISP_INVIS_VECTOR (dp))->size : 0);
/* The next location where the `invisible' property changes, or an
overlay starts or ends. */
- int next_boundary = from;
+ EMACS_INT next_boundary = from;
/* For computing runs of characters with similar widths.
Invariant: width_run_width is zero, or all the characters
from width_run_start to width_run_end have a fixed width of
width_run_width. */
- int width_run_start = from;
- int width_run_end = from;
- int width_run_width = 0;
+ EMACS_INT width_run_start = from;
+ EMACS_INT width_run_end = from;
+ EMACS_INT width_run_width = 0;
Lisp_Object *width_table;
Lisp_Object buffer;
/* The next buffer pos where we should consult the width run cache. */
- int next_width_run = from;
+ EMACS_INT next_width_run = from;
Lisp_Object window;
int multibyte = !NILP (current_buffer->enable_multibyte_characters);
/* If previous char scanned was a wide character,
this is the column where it ended. Otherwise, this is 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;
+ EMACS_INT wide_column_end_hpos = 0;
+ EMACS_INT prev_pos; /* Previous buffer position. */
+ EMACS_INT prev_pos_byte; /* Previous buffer position. */
+ EMACS_INT prev_hpos = 0;
+ EMACS_INT prev_vpos = 0;
+ EMACS_INT contin_hpos; /* HPOS of last column of continued line. */
+ EMACS_INT prev_tab_offset; /* Previous tab offset. */
+ EMACS_INT continuation_glyph_width;
XSETBUFFER (buffer, current_buffer);
XSETWINDOW (window, win);
{
while (pos == next_boundary)
{
- int pos_here = pos;
- int newpos;
+ EMACS_INT pos_here = pos;
+ EMACS_INT newpos;
/* Don't skip invisible if we are already at the margin. */
if (vpos > tovpos || (vpos == tovpos && hpos >= tohpos))
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));
+ if (GLYPH_CODE_P (entry)
+ && GLYPH_CODE_CHAR_VALID_P (entry))
+ c = GLYPH_CODE_CHAR (entry);
else
c = ' ';
}
struct position *
vmotion (from, vtarget, w)
- register int from, vtarget;
+ register EMACS_INT from, vtarget;
struct window *w;
{
- int hscroll = XINT (w->hscroll);
+ EMACS_INT hscroll = XINT (w->hscroll);
struct position pos;
/* vpos is cumulative vertical position, changed as from is changed */
register int vpos = 0;
- int prevline;
- register int first;
- int from_byte;
- int lmargin = hscroll > 0 ? 1 - hscroll : 0;
+ EMACS_INT prevline;
+ register EMACS_INT first;
+ EMACS_INT from_byte;
+ EMACS_INT lmargin = hscroll > 0 ? 1 - hscroll : 0;
int selective
= (INTEGERP (current_buffer->selective_display)
? XINT (current_buffer->selective_display)
: !NILP (current_buffer->selective_display) ? -1 : 0);
Lisp_Object window;
- int start_hpos = 0;
+ EMACS_INT start_hpos = 0;
int did_motion;
/* This is the object we use for fetching character properties. */
Lisp_Object text_prop_object;
syms_of_indent ()
{
DEFVAR_BOOL ("indent-tabs-mode", &indent_tabs_mode,
- doc: /* *Indentation can insert tabs if this is non-nil.
-Setting this variable automatically makes it local to the current buffer. */);
+ doc: /* *Indentation can insert tabs if this is non-nil. */);
indent_tabs_mode = 1;
defsubr (&Scurrent_indentation);