|
11 | 11 |
|
12 | 12 | (defconst raku-smie-grammar |
13 | 13 | (smie-prec2->grammar |
14 | | - (smie-precs->prec2 '((assoc ";") (assoc ",") (left ":"))))) |
| 14 | + (smie-precs->prec2 |
| 15 | + '((assoc ";") (assoc "=") (assoc ",") (left ":"))))) |
15 | 16 |
|
16 | 17 | (defcustom raku-indent-offset 4 |
17 | 18 | "Basic size of one indentation step." |
18 | 19 | :type 'integer |
19 | 20 | :group 'raku) |
20 | 21 |
|
21 | 22 | (defun raku-smie--not-interpolation-p () |
22 | | - (save-excursion |
23 | | - (forward-char -1) |
24 | | - (or (zerop (skip-chars-backward "-[:alnum:]")) |
25 | | - (not (looking-back "#{\\$" (- (point) 3)))))) |
| 23 | + (save-excursion ;; Prepare for excursion |
| 24 | + (forward-char -1) ;; Retreat one char |
| 25 | + |
| 26 | + (or |
| 27 | + ;; Backtrack til we hit something that _isn't_ alnum |
| 28 | + ;; If we did not backtrack, we're not in interpolation |
| 29 | + (zerop (skip-chars-backward "-[:alnum:]")) |
| 30 | + |
| 31 | + ;; If we did backtrack, see if #{\$ (EOL) occurs three |
| 32 | + ;; or more characters prior to point (??????????) |
| 33 | + ;; if this does NOT match, we are not in an interpolation |
| 34 | + (not (looking-back "#{\\$" (- (point) 3)))))) |
26 | 35 |
|
27 | 36 | (defun raku-smie--forward-token () |
28 | 37 | (cond |
29 | | - ((and (eq (char-before) ?\}) |
30 | | - (raku-smie--not-interpolation-p) |
31 | | - ;; FIXME: If the next char is not whitespace, what should we do? |
32 | | - (or (memq (char-after) '(?\s ?\t ?\n)) |
33 | | - (looking-at comment-start-skip))) |
34 | | - (if (memq (char-after) '(?\s ?\t ?\n)) |
35 | | - (forward-char 1) (forward-comment 1)) |
36 | | - ";") |
37 | | - ((progn (forward-comment (point-max)) |
38 | | - (looking-at "[;,:]")) |
39 | | - (forward-char 1) (match-string 0)) |
40 | | - (t (smie-default-forward-token)))) |
| 38 | + ;; Return `;` to fudge end-of-block indentation (I think), as ; is optional after a block |
| 39 | + ((and (eq (char-before) ?\}) ;; Character immediately prior to point is `}` |
| 40 | + (raku-smie--not-interpolation-p) ;; And, not in an interpolation |
| 41 | + ;; FIXME: If the next char is not whitespace, what should we do? |
| 42 | + (or (memq (char-after) '(?\s ?\t ?\n)) ;; And, point is followed by \s, \t, or \n |
| 43 | + (looking-at comment-start-skip))) ;; or point is looking-at /#+ */ |
| 44 | + |
| 45 | + (if (memq (char-after) '(?\s ?\t ?\n)) ;; If the above is true, and point is followed by /[\s\t\n]/ |
| 46 | + (forward-char 1) (forward-comment 1)) ;; Then, advance by one character, and one whole comment |
| 47 | + ";") |
| 48 | + |
| 49 | + ((eq (char-after) ?\=) ;; Spit out '=' to kick off proper indentation for hanging assignment |
| 50 | + (forward-char 1) |
| 51 | + "=") |
| 52 | + |
| 53 | + ((progn (forward-comment (point-max)) ;; Read past ALL comments |
| 54 | + (looking-at "[;,:]")) ;; Are we looking at ; , or : |
| 55 | + |
| 56 | + (forward-char 1) ;; If so, advance one character |
| 57 | + (match-string 0)) ;; And then return whatever looking-at found (?) |
| 58 | + |
| 59 | + (t (smie-default-forward-token)))) ;; If none of the above matched, defer to SMIE default search |
41 | 60 |
|
42 | 61 | (defun raku-smie--backward-token () |
43 | 62 | (let ((pos (point))) |
44 | | - (forward-comment (- (point))) |
| 63 | + (forward-comment (- (point))) ;; Retreate past ALL comments up to point |
45 | 64 | (cond |
46 | 65 | ;; FIXME: If the next char is not whitespace, what should we do? |
47 | | - ((and (eq (char-before) ?\}) (raku-smie--not-interpolation-p) |
48 | | - (> pos (point))) ";") |
49 | | - ((memq (char-before) '(?\; ?\, ?\:)) |
50 | | - (forward-char -1) (string (char-after))) |
51 | | - (t (smie-default-backward-token))))) |
| 66 | + ;; Cond #1 - Same end-of-block hack, I think |
| 67 | + ((and (eq (char-before) ?\}) ;; Point is preceded immediately by `}` |
| 68 | + (raku-smie--not-interpolation-p) ;; And, not in an interpolation |
| 69 | + (> pos (point))) ;; And, point has moved backward |
| 70 | + |
| 71 | + ";") ;; If so, yield ';' |
| 72 | + |
| 73 | + ((eq (char-before) ?\=) |
| 74 | + (forward-char -1) |
| 75 | + "=") |
| 76 | + |
| 77 | + ;; Cond #2 - Get whatever precedes [,:;] |
| 78 | + ((memq (char-before) '(?\; ?\, ?\:)) ;; Point is preceded immediately by `;`, `,`, or `:` |
| 79 | + (forward-char -1) ;; Retreat one char |
| 80 | + (string (char-after))) ;; Return char after point (the char we just retreated past) |
| 81 | + |
| 82 | + (t (smie-default-backward-token))))) ;; If none of the above matched, defer to SMIE default search |
52 | 83 |
|
53 | 84 | (defun raku-smie-rules (kind token) |
54 | 85 | (pcase (cons kind token) |
| 86 | + ;; Basic indent offset |
55 | 87 | (`(:elem . basic) raku-indent-offset) |
| 88 | + |
| 89 | + ;; Indent offset for function args |
56 | 90 | (`(:elem . arg) 0) |
| 91 | + |
57 | 92 | (`(:list-intro . ,(or `";" `"")) t) ;"" stands for BOB (bug#15467). |
| 93 | + |
| 94 | + ;; Make sure that hanging assignment gets indented |
| 95 | + (`(:before . "=") |
| 96 | + (if (smie-rule-hanging-p) |
| 97 | + (smie-rule-parent raku-indent-offset))) |
| 98 | + |
58 | 99 | (`(:before . "{") |
59 | | - (when (smie-rule-hanging-p) |
60 | | - (smie-backward-sexp ";") |
| 100 | + (when (smie-rule-hanging-p) ; is `{` the last thing on this line? |
| 101 | + (smie-backward-sexp ";") ; y tho |
61 | 102 | (smie-indent-virtual))) |
| 103 | + |
62 | 104 | (`(:before . ,(or "{" "(")) |
63 | | - (if (smie-rule-hanging-p) (smie-rule-parent 0))))) |
| 105 | + (if (smie-rule-hanging-p) |
| 106 | + (smie-rule-parent 0))))) |
64 | 107 |
|
65 | 108 | (provide 'raku-indent) |
66 | 109 |
|
|
0 commit comments