1
0
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:
Eli Zaretskii 2020-09-30 17:33:58 +03:00
parent 56d6e29d80
commit a190a446ee
2 changed files with 78 additions and 11 deletions

View File

@ -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
View 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")))