MH-E threads code: use mh-scan variables correctly

* lisp/mh-e/mh-thread.el (mh-thread-current-indentation-level)
(mh-thread-find-children): Fix off-by-one error by using
'mh-scan-field-from-start-offset' directly, as
'mh-thread-parse-scan-line' does.  Previously, these functions would
incorrectly consider the "date note" column as part of the thread
indenting.  Since that column is almost always a Space character, that
almost always worked.
(mh-thread-ancestor): Update caller.
* test/lisp/mh-e/mh-thread-tests.el: New unit tests for affected code.
* lisp/mh-e/mh-scan.el (mh-msg-num-width-to-column): Fix doc string typo.
This commit is contained in:
Stephen Gildea 2021-11-13 07:00:30 -08:00
parent d3666ccdba
commit 4df334a0f7
3 changed files with 137 additions and 6 deletions

View file

@ -509,7 +509,7 @@ with `mh-scan-msg-format-string'."
Note that columns in Emacs start with 0.
If `mh-scan-format-file' is set to \"Use MH-E scan Format\" this
means that either `mh-scan-format-mh' or `mh-scan-format-nmh' are
means that either `mh-scan-format-mh' or `mh-scan-format-nmh' is
in use. This function therefore assumes that the first column is
empty (to provide room for the cursor), the following WIDTH
columns contain the message number, and the column for notations

View file

@ -139,7 +139,7 @@ to the message that started everything."
(cond (thread-root-flag
(while (mh-thread-immediate-ancestor))
(mh-maybe-show))
((equal current-level 1)
((equal current-level 0)
(message "Message has no ancestor"))
(t (mh-thread-immediate-ancestor)
(mh-maybe-show)))))
@ -242,8 +242,8 @@ sibling."
(defun mh-thread-current-indentation-level ()
"Find the number of spaces by which current message is indented."
(save-excursion
(let ((address-start-offset (+ mh-cmd-note mh-scan-date-flag-width
mh-scan-date-width 1))
(let ((address-start-offset (+ mh-cmd-note
mh-scan-field-from-start-offset))
(level 0))
(beginning-of-line)
(forward-char address-start-offset)
@ -275,8 +275,8 @@ at the end."
(beginning-of-line)
(if (eobp)
nil
(let ((address-start-offset (+ mh-cmd-note mh-scan-date-flag-width
mh-scan-date-width 1))
(let ((address-start-offset (+ mh-cmd-note
mh-scan-field-from-start-offset))
(level (mh-thread-current-indentation-level))
spaces begin)
(setq begin (point))

View file

@ -0,0 +1,131 @@
;;; mh-thread-tests.el --- tests for mh-thread.el -*- lexical-binding: t -*-
;; Copyright (C) 2021 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 3 of the License, or
;; (at your option) any later version.
;; GNU Emacs 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 GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
;;; Code:
(require 'ert)
(require 'mh-thread)
(eval-when-compile (require 'cl-lib))
(defun mh-thread-tests-before-from ()
"Generate the fields of a scan line up to where the 'From' field would start.
The exact contents are not important, but the number of characters is."
(concat (make-string mh-cmd-note ?9)
(make-string mh-scan-cmd-note-width ?A)
(make-string mh-scan-destination-width ?t)
(make-string mh-scan-date-width ?/)
(make-string mh-scan-date-flag-width ?*)))
;;; Tests of support routines
(ert-deftest mh-thread-current-indentation-level ()
"Test that `mh-thread-current-indentation-level' identifies the level."
(with-temp-buffer
(insert (mh-thread-tests-before-from) "[Sender One] Subject of msg 1\n")
(insert (mh-thread-tests-before-from) " [Sender Two] Subject of msg 2\n")
(goto-char (point-min))
(should (equal 0 (mh-thread-current-indentation-level)))
(forward-line)
(should (equal 2 (mh-thread-current-indentation-level)))))
(ert-deftest mh-thread-find-children ()
"Test `mh-thread-find-children'."
(let (expected-start expected-end)
(with-temp-buffer
(insert (mh-thread-tests-before-from) "[Sender One] line 1\n")
(setq expected-start (point))
(insert (mh-thread-tests-before-from) " [Sender Two] line 2\n")
(insert (mh-thread-tests-before-from) " [Sender Three] line 3\n")
(insert (mh-thread-tests-before-from) " [Sender Four] line 4\n")
(setq expected-end (1- (point)))
(insert (mh-thread-tests-before-from) " [Sender Five] line 5\n")
(goto-char (1+ expected-start))
(should (equal (list expected-start expected-end)
(mh-thread-find-children))))))
(ert-deftest mh-thread-immediate-ancestor ()
"Test that `mh-thread-immediate-ancestor' moves to the correct message."
(with-temp-buffer
(insert (mh-thread-tests-before-from) "[Sender Other] line 1\n")
(insert (mh-thread-tests-before-from) "[Sender One] line 2\n")
(insert (mh-thread-tests-before-from) " [Sender Two] line 3\n")
(insert (mh-thread-tests-before-from) " [Sender Three] line 4\n")
(insert (mh-thread-tests-before-from) " [Sender Four] line 5\n")
(insert (mh-thread-tests-before-from) " [Sender Five] line 6\n")
(forward-line -1)
(should (equal (line-number-at-pos) 6))
(mh-thread-immediate-ancestor)
(should (equal (line-number-at-pos) 4)) ;skips over sibling
(mh-thread-immediate-ancestor)
(should (equal (line-number-at-pos) 3)) ;goes up only one level at a time
(mh-thread-immediate-ancestor)
(should (equal (line-number-at-pos) 2))
(mh-thread-immediate-ancestor)
(should (equal (line-number-at-pos) 2)))) ;no further motion at thread root
;;; Tests of MH-Folder Commands
(ert-deftest mh-thread-sibling-and-ancestor ()
"Test motion by `mh-thread-ancestor' and `mh-thread-next-sibling'."
(with-temp-buffer
(insert (mh-thread-tests-before-from) "[Sender Other] line 1\n")
(insert (mh-thread-tests-before-from) "[Sender One] line 2\n")
(insert (mh-thread-tests-before-from) " [Sender Two] line 3\n")
(insert (mh-thread-tests-before-from) " [Sender Three] line 4\n")
(insert (mh-thread-tests-before-from) " [Sender Four] line 5\n")
(insert (mh-thread-tests-before-from) " [Sender Five] line 6\n")
(forward-line -1)
(let ((mh-view-ops '(unthread))
(show-count 0))
(cl-letf (((symbol-function 'mh-maybe-show)
(lambda ()
(setq show-count (1+ show-count)))))
(should (equal (line-number-at-pos) 6))
;; test mh-thread-ancestor
(mh-thread-ancestor)
(should (equal (line-number-at-pos) 4)) ;skips over sibling
(should (equal show-count 1))
(mh-thread-ancestor t)
(should (equal (line-number-at-pos) 2)) ;root flag skips to root
(should (equal show-count 2))
(mh-thread-ancestor)
(should (equal (line-number-at-pos) 2)) ;do not move from root
(should (equal show-count 2)) ;do not re-show at root
;; test mh-thread-sibling
(mh-thread-next-sibling)
(should (equal (line-number-at-pos) 2)) ;no next sibling, no motion
(should (equal show-count 2)) ;no sibling, no show
(mh-thread-next-sibling t)
(should (equal (line-number-at-pos) 1))
(should (equal show-count 3))
(mh-thread-next-sibling t)
(should (equal (line-number-at-pos) 1)) ;no previous sibling
(should (equal show-count 3))
(goto-char (point-max))
(forward-line -1)
(should (equal (line-number-at-pos) 6))
(mh-thread-next-sibling t)
(should (equal (line-number-at-pos) 5))
(should (equal show-count 4))
(mh-thread-next-sibling t)
(should (equal (line-number-at-pos) 5)) ;no previous sibling
(should (equal show-count 4))
))))
;;; mh-thread-tests.el ends here