3

I am trying to search backwards and find [ but skip all square brackets within strings. I came across (nth 3 (syntax-ppss)); but I can't figure out how to use it with let in the following code:

(defun ext-ess-symbol-at-point-modified ()
  "Return the name of a symbol to the left of \"[\"."
  (interactive)
  (save-excursion
    (let* ((cpoint (point))
           (sbt0 (search-backward "[" 1 t))
           (sbt1 (search-forward "]" cpoint t)))
      (if (and sbt0 (not sbt1))
          (progn (goto-char (1- sbt0))
                 (message "%s" (buffer-substring
                                (search-backward-regexp "^\\|[[:space:]]")
                                sbt0)))
        (error "Could not find open square bracket \"[\"")))))

I would like something along the lines of

(let* ((cpoint (point))
       (sbt0 (while (nth 3 (syntax-ppss))
               (search-backward "[" 1 t)))
Basil
  • 12,383
  • 43
  • 69
Arktik
  • 972
  • 4
  • 17
  • Just to address your title - while always returns nil, so if you want to subsequently return something else you need to place the loop within some other construct, e.g. let/progn/etc. – Basil Mar 01 '18 at 23:59

2 Answers2

1

I would like something along the lines of

(let* ((cpoint (point))
       (sbt0 (while (nth 3 (syntax-ppss))
               (search-backward "[" 1 t)))

As Basil pointed out, you're looking for progn, e.g.:

(let* ((cpoint (point))
       (sbt0 (progn (while (nth 3 (syntax-ppss))
                      (search-backward "[" 1 t))
                    (point)))

Actually, I was wondering if there is a function that will get the location of the open square bracket to the left (even if it is on lines above). For example the first [ in

data2[col1 %in% data1[grepl("[[:num:]]+", some_col), another_col], point_here]

Try syntax-ppss: (goto-char (car (last (nth 9 (syntax-ppss)))))

(Avoiding wrong-type-argument when point is not within any brackes left as an exercise for the reader. Also, skipping over non-square parens.)

(syntax-ppss &optional POS)

Parse-Partial-Sexp State at POS, defaulting to point.
The returned value is the same as that of ‘parse-partial-sexp’ [...]

(parse-partial-sexp FROM TO &optional TARGETDEPTH STOPBEFORE OLDSTATE
COMMENTSTOP)

[...]    
Value is a list of elements describing final state of parsing:
 [...]
 9. List of positions of currently open parens, outermost first.
npostavs
  • 9,203
  • 1
  • 24
  • 53
  • Thanks! I've written something that seems to work fine (no the code in my answer) but looked rather cumbersome. I will try to re-write using your advice above. Thanks again for the pointers! – Arktik Mar 04 '18 at 12:20
  • I had checked whether a point was outside any brackets with: (< (nth 0 (syntax-ppss)) 1). – Arktik Mar 04 '18 at 12:37
  • @A.Blizzard Switching syntax tables is possible, but you have to be careful about the syntax-ppss cache getting messed up (e.g., Bug#29710). I would recommend looping over the (reverse (nth 9 (syntax-ppss))) list until you reach a square bracket instead. – npostavs Mar 04 '18 at 13:02
  • Yes, I think that's the way to go. Thanks again! – Arktik Mar 04 '18 at 13:21
0

I've finally written this

(defun ext-ess-symbol-at-point-modified ()
  "Get the name of a symbol to the left of '[' from inside '[ ]'."
  (interactive)
  (save-excursion
    (let ((cpoint (point))
          (sbt0 (search-backward "[" 1 t)))
      (while (nth 3 (syntax-ppss))
        (setq sbt0 (search-backward "[" 1 t)))
      (setq sbt1 (search-forward "]" cpoint t))
      (when (and sbt1 (nth 3 (syntax-ppss)))
        (let (anynill)
          (while (not anynill)
            (setq sbt1 (search-forward "]" cpoint t))
            (unless (and sbt1 (nth 3 (syntax-ppss)))
              (setq anynill t)))))
      (if (and sbt0 (not sbt1))
          (message "%s" (buffer-substring
                          (+ (search-backward-regexp "[^[:alnum:]_.]") 1) sbt0))                             
        (error "Couldn't find open square bracket '['")))))

Not sure whether it's the best way. Couldn't figure out how to do it inside let.

Actually, I was wondering if there is a function that will get the location of the open square bracket to the left (even if it is on lines above). For example the first [ in

data2[col1 %in% data1[grepl("[[:num:]]+", some_col), another_col], point_here]

when the cursor is on point_here. And if inside square brackets of data1 then it will find the bracket in data1[. I would have thought there would be a ready function for finding open brackets?!

Arktik
  • 972
  • 4
  • 17