3

I'm getting up-list: Scan error: "Unbalanced parentheses" from this position:

(foo "bar|")

Snippet from up-list doc:

This command assumes point is not in a string or comment.

So this is the expected behavior. But I don't care. I just want to go upwards from a list. Could someone suggest an up-list clone that does the proper thing?

I'm looking for something better than this naive code:

(defun up-list-naive ()
  (interactive)
  (while (not (ignore-errors (up-list) t))
    (forward-char)))
Drew
  • 29,895
  • 7
  • 74
  • 104
abo-abo
  • 20,038
  • 3
  • 50
  • 71

2 Answers2

3

EDIT: incorporated Andreas Rohler's suggestion:

This works for me in your test case:

(defun my-up-list ()
  (interactive)
  (let ((s (syntax-ppss)))
    (when (nth 3 s)
      (goto-char (nth 8 s))))
  (ignore-errors (up-list)))

syntax-ppss returns a list, the third element of which exists if you're inside a string, and the 8th element is the beginning of the string (if you're in one, otherwise nil).

abo-abo
  • 20,038
  • 3
  • 50
  • 71
Tyler
  • 9,872
  • 2
  • 33
  • 57
  • Thanks, @Tyler, but your code looks to me as naive as mine: parse, move one char, parse, move one char ... . I'm looking for something that parses only once. – abo-abo Sep 20 '13 at 17:27
  • I don't think that's possible. I can't find any single function that does what you want without stepping through the quote. See for example the code in https://github.com/magnars/expand-region.el/blob/master/er-basic-expansions.el line 116 onwards (;; Quotes) – Tyler Sep 20 '13 at 17:42
  • 1
    If (nth 3 (syntax-ppss) is true, exist beginning-position at (nth 8 (syntax-ppss). No "while" needed, jump directly. BTW that's a kind of long cherished bugs, see also http://debbugs.gnu.org/cgi/bugreport.cgi?bug=3416 – Andreas Röhler Sep 20 '13 at 18:29
  • @AndreasRöhler thanks, I stand corrected! Long-cherised indeed - four years for such a basic issue to remain in place. – Tyler Sep 20 '13 at 18:52
  • Just for the record: forward- backward-sexp are likewise buggy - and easily to cure the similar way. Maybe some more people file bug-reports, so it gets done. Cheers – Andreas Röhler Sep 20 '13 at 19:07
  • When no further list is ahead. BTW will publish a variant which sends a "nil" than, as user should receive some info being at the end. Draft also deals with comments - (nth 8 ...) is all needed finally. – Andreas Röhler Sep 21 '13 at 06:57
  • Would it be possible to provide a symmetrical `down-list` solution, if trivial? – modeller Aug 16 '14 at 21:59
1

In extension of answers given: deal with comments also, send "nil" when no further list found. When interactively called, message result.

(defun ar-up-list (arg)
  "Move forward out of one level of parentheses.
With ARG, do this that many times.

A negative argument means move backward but still to a less deep spot."
  (interactive "p")
  (let ((orig (point))
        (pps (syntax-ppss))
        erg)
    (and (nth 8 pps) (goto-char (nth 8 pps)))
    (ignore-errors (up-list arg))
    (and (< orig (point)) (setq erg (point)))
    (when (interactive-p) (message "%s" erg))
    erg))

And it's complement:

(defun ar-down-list (arg)
"Move forward down one level of parentheses.
With ARG, do this that many times.

A negative argument means move backward but still go down a level. "
  (interactive "p")
  (let ((orig (point))
        (pps (syntax-ppss))
        erg)
    (and (nth 8 pps) (goto-char (nth 8 pps)))
    (ignore-errors (down-list arg))
    (and (< orig (point)) (setq erg (point)))
    (when (interactive-p) (message "%s" erg))
    erg))
Andreas Röhler
  • 4,804
  • 14
  • 18