mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2025-01-20 18:17:20 +00:00
Fix 'move-to-column' when invisible text follows a TAB
* src/indent.c (scan_for_column): Accept 2 more arguments, and report through them the position corresponding to PREVCOL. All callers changed. (Fmove_to_column): Use the prev_col's position to test for a TAB instead of assuming that the TAB is just before point (which is false when there's invisible text around). (Bug#43587) * test/src/indent-tests.el: New file.
This commit is contained in:
parent
56d6e29d80
commit
a190a446ee
30
src/indent.c
30
src/indent.c
@ -524,9 +524,11 @@ check_display_width (ptrdiff_t pos, ptrdiff_t col, ptrdiff_t *endpos)
|
||||
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). */
|
||||
strictly smaller than the goal column), and PREVPOS and PREVBPOS get set
|
||||
to the corresponding buffer character and byte positions. */
|
||||
static void
|
||||
scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
|
||||
scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol,
|
||||
ptrdiff_t *prevpos, ptrdiff_t *prevbpos, ptrdiff_t *prevcol)
|
||||
{
|
||||
int tab_width = SANE_TAB_WIDTH (current_buffer);
|
||||
bool ctl_arrow = !NILP (BVAR (current_buffer, ctl_arrow));
|
||||
@ -540,10 +542,12 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
|
||||
register ptrdiff_t col = 0, prev_col = 0;
|
||||
EMACS_INT goal = goalcol ? *goalcol : MOST_POSITIVE_FIXNUM;
|
||||
ptrdiff_t end = endpos ? *endpos : PT;
|
||||
ptrdiff_t scan, scan_byte, next_boundary;
|
||||
ptrdiff_t scan, scan_byte, next_boundary, prev_pos, prev_bpos;
|
||||
|
||||
scan = find_newline (PT, PT_BYTE, BEGV, BEGV_BYTE, -1, NULL, &scan_byte, 1);
|
||||
next_boundary = scan;
|
||||
prev_pos = scan;
|
||||
prev_bpos = scan_byte;
|
||||
|
||||
window = Fget_buffer_window (Fcurrent_buffer (), Qnil);
|
||||
w = ! NILP (window) ? XWINDOW (window) : NULL;
|
||||
@ -576,6 +580,8 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
|
||||
if (col >= goal)
|
||||
break;
|
||||
prev_col = col;
|
||||
prev_pos = scan;
|
||||
prev_bpos = scan_byte;
|
||||
|
||||
{ /* Check display property. */
|
||||
ptrdiff_t endp;
|
||||
@ -705,6 +711,10 @@ scan_for_column (ptrdiff_t *endpos, EMACS_INT *goalcol, ptrdiff_t *prevcol)
|
||||
*goalcol = col;
|
||||
if (endpos)
|
||||
*endpos = scan;
|
||||
if (prevpos)
|
||||
*prevpos = prev_pos;
|
||||
if (prevbpos)
|
||||
*prevbpos = prev_bpos;
|
||||
if (prevcol)
|
||||
*prevcol = prev_col;
|
||||
}
|
||||
@ -720,7 +730,7 @@ current_column_1 (void)
|
||||
EMACS_INT col = MOST_POSITIVE_FIXNUM;
|
||||
ptrdiff_t opoint = PT;
|
||||
|
||||
scan_for_column (&opoint, &col, NULL);
|
||||
scan_for_column (&opoint, &col, NULL, NULL, NULL);
|
||||
return col;
|
||||
}
|
||||
|
||||
@ -988,7 +998,7 @@ to reach COLUMN, add spaces/tabs to get there.
|
||||
The return value is the current column. */)
|
||||
(Lisp_Object column, Lisp_Object force)
|
||||
{
|
||||
ptrdiff_t pos, prev_col;
|
||||
ptrdiff_t pos, prev_pos, prev_bpos, prev_col;
|
||||
EMACS_INT col;
|
||||
EMACS_INT goal;
|
||||
|
||||
@ -997,7 +1007,7 @@ The return value is the current column. */)
|
||||
|
||||
col = goal;
|
||||
pos = ZV;
|
||||
scan_for_column (&pos, &col, &prev_col);
|
||||
scan_for_column (&pos, &col, &prev_pos, &prev_bpos, &prev_col);
|
||||
|
||||
SET_PT (pos);
|
||||
|
||||
@ -1006,18 +1016,16 @@ The return value is the current column. */)
|
||||
if (!NILP (force) && col > goal)
|
||||
{
|
||||
int c;
|
||||
ptrdiff_t pos_byte = PT_BYTE;
|
||||
|
||||
pos_byte -= prev_char_len (pos_byte);
|
||||
c = FETCH_CHAR (pos_byte);
|
||||
if (c == '\t' && prev_col < goal)
|
||||
c = FETCH_CHAR (prev_bpos);
|
||||
if (c == '\t' && prev_col < goal && prev_bpos < PT_BYTE)
|
||||
{
|
||||
ptrdiff_t 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);
|
||||
SET_PT_BOTH (prev_pos, prev_bpos);
|
||||
Finsert_char (make_fixnum (' '), make_fixnum (goal - prev_col), Qt);
|
||||
|
||||
/* Now delete the tab, and indent to COL. */
|
||||
|
59
test/src/indent-tests.el
Normal file
59
test/src/indent-tests.el
Normal file
@ -0,0 +1,59 @@
|
||||
;;; indent-tests.el --- tests for src/indent.c -*- lexical-binding:t -*-
|
||||
|
||||
;; Copyright (C) 2020 Free Software Foundation, Inc.
|
||||
|
||||
;; This file is part of GNU Emacs.
|
||||
|
||||
;; This program 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.
|
||||
;;
|
||||
;; This program is distributed in the hope that it will be useful, but
|
||||
;; WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
;; General Public License for more details.
|
||||
;;
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see `https://www.gnu.org/licenses/'.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
|
||||
(ert-deftest indent-tests-move-to-column-invis-1tab ()
|
||||
"Test `move-to-column' when a TAB is followed by invisible text."
|
||||
(should
|
||||
(string=
|
||||
(with-temp-buffer
|
||||
(insert "\tLine starting with INVISIBLE text after TAB\n")
|
||||
(add-text-properties 2 21 '(invisible t))
|
||||
(goto-char (point-min))
|
||||
(move-to-column 7 t)
|
||||
(buffer-substring-no-properties 1 8))
|
||||
" ")))
|
||||
|
||||
(ert-deftest indent-tests-move-to-column-invis-2tabs ()
|
||||
"Test `move-to-column' when 2 TABs are followed by invisible text."
|
||||
(should
|
||||
(string=
|
||||
(with-temp-buffer
|
||||
(insert "\t\tLine starting with INVISIBLE text after TAB\n")
|
||||
(add-text-properties 3 22 '(invisible t))
|
||||
(goto-char (point-min))
|
||||
(move-to-column 12 t)
|
||||
(buffer-substring-no-properties 1 11))
|
||||
"\t \tLine")))
|
||||
|
||||
(ert-deftest indent-tests-move-to-column-invis-between-tabs ()
|
||||
"Test `move-to-column' when 2 TABs are mixed with invisible text."
|
||||
(should
|
||||
(string=
|
||||
(with-temp-buffer
|
||||
(insert "\txxx\tLine starting with INVISIBLE text after TAB\n")
|
||||
(add-text-properties 6 25 '(invisible t))
|
||||
(add-text-properties 2 5 '(invisible t))
|
||||
(goto-char (point-min))
|
||||
(move-to-column 12 t)
|
||||
(buffer-substring-no-properties 1 14))
|
||||
"\txxx \tLine")))
|
Loading…
Reference in New Issue
Block a user