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. */
-
-static double
-current_column_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);
int multibyte = !NILP (current_buffer->enable_multibyte_characters);
/* Start the scan at the beginning of this line with column number 0. */
- register EMACS_INT col = 0;
+ 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;
}
+ /* 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;
}
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);
}
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
(column, force)
Lisp_Object column, force;
{
- register EMACS_INT pos;
- register EMACS_INT col = current_column ();
- register EMACS_INT goal;
- register EMACS_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;
- EMACS_INT prev_col = 0;
- int c = 0;
- EMACS_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;
- }
+ SET_PT (pos);
- next_boundary = 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)
- {
- EMACS_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 = AREF (charvec, i);
-
- if (GLYPH_CODE_P (entry)
- && GLYPH_CODE_CHAR_VALID_P (entry))
- c = GLYPH_CODE_CHAR (entry);
- else
- c = ' ';
+ EMACS_INT pos_byte = PT_BYTE;
+ DEC_POS (pos_byte);
+ int c = FETCH_CHAR (pos_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
+ 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)
- {
- 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;
}
/* 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 */