[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#37045: lisp-indent-region hangs in lisp-indent-calc-next when indent
From: |
eschulte |
Subject: |
bug#37045: lisp-indent-region hangs in lisp-indent-calc-next when indenting the three characters "|#\n" |
Date: |
Thu, 15 Aug 2019 23:46:06 -0400 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/26.2 (gnu/linux) |
Hi,
Indent-region sometimes hangs when indenting a lisp file. A minimal
example is the file just containing the characters "|#" followed by a
newline. This hang is due to an infinite loop in the while loop in the
`lisp-indent-calc-next' function. The following version of this
function fixes this problem, but is certainly not the appropriate
long-term fix.
;;; Work around a bug in `lisp-indent-calc-next' in which it can hang
;;; on a dangling '|#'. The change in the code below against the
;;; original is the addition of a block and a throw to this block when
;;; we're infinite looping (when the newly added last-last-sexp
;;; matches last-sexp). On the off chance it is possible in normal
;;; execution for last-sexp to stay the same for some number of loop
;;; iterations this patch only aborts if they're equal 100 times in a
;;; row.
(defun lisp-indent-calc-next (state)
"Move to next line and return calculated indent for it.
STATE is updated by side effect, the first state should be
created by `lisp-indent-initial-state'. This function may move
by more than one line to cross a string literal."
(pcase-let* (((cl-struct lisp-indent-state
(stack indent-stack) ppss ppss-point)
state)
(indent-depth (car ppss)) ; Corresponding to indent-stack.
(depth indent-depth)
(last-last-sexp nil) (counter 0))
(block nil
;; Parse this line so we can learn the state to indent the
;; next line.
(while (let ((last-sexp (nth 2 ppss)))
(setq ppss (parse-partial-sexp
ppss-point (progn (end-of-line) (point))
nil nil ppss))
;; Preserve last sexp of state (position 2) for
;; `calculate-lisp-indent', if we're at the same depth.
(if (and (not (nth 2 ppss)) (= depth (car ppss)))
(setf (nth 2 ppss) last-sexp)
(setq last-sexp (nth 2 ppss)))
(setq depth (car ppss))
(if (and (>= counter 100) (equal last-sexp last-last-sexp))
(progn (setf indent-stack nil) (return))
(setq last-last-sexp last-sexp
counter (1+ counter)))
;; Skip over newlines within strings.
(nth 3 ppss))
(let ((string-start (nth 8 ppss)))
(setq ppss (parse-partial-sexp (point) (point-max)
nil nil ppss 'syntax-table))
(setf (nth 2 ppss) string-start) ; Finished a complete string.
(setq depth (car ppss)))
(setq ppss-point (point)))
(setq ppss-point (point))
(let* ((depth-delta (- depth indent-depth)))
(cond ((< depth-delta 0)
(setq indent-stack (nthcdr (- depth-delta) indent-stack)))
((> depth-delta 0)
(setq indent-stack (nconc (make-list depth-delta nil)
indent-stack))))))
(prog1
(let (indent)
(cond ((= (forward-line 1) 1) nil)
;; Negative depth, probably some kind of syntax error.
((null indent-stack)
;; Reset state.
(setq ppss (parse-partial-sexp (point) (point))))
((car indent-stack))
((integerp (setq indent (calculate-lisp-indent ppss)))
(setf (car indent-stack) indent))
((consp indent) ; (COLUMN CONTAINING-SEXP-START)
(car indent))
;; This only happens if we're in a string.
(t (error "This shouldn't happen"))))
(setf (lisp-indent-state-stack state) indent-stack)
(setf (lisp-indent-state-ppss-point state) ppss-point)
(setf (lisp-indent-state-ppss state) ppss))))
Thanks,
Eric
P.S. I hope this isn't a duplicate report, I tried to search both the
archive https://lists.gnu.org/archive/html/bug-gnu-emacs/ and the
previous bug reports https://debbugs.gnu.org/ but I didn't find anything
relevant.
--
Eric Schulte, Ph.D.
Director of Automated Software Engineering
GrammaTech, Inc.
PGP Fingerprint: FA8D C2C3 E8A0 A749 34CD 9DCF 3C1B 8581 614C A05D
Pronouns: he, him, his
signature.asc
Description: PGP signature
- bug#37045: lisp-indent-region hangs in lisp-indent-calc-next when indenting the three characters "|#\n",
eschulte <=