Skip to content

Commit

Permalink
Never fail to indent
Browse files Browse the repository at this point in the history
A proper indentation engine should never look past the previous line.
This is because a user frequently wants custom indentation, in all
programming languages. A PureScript example:

```haskell
f1 x = case x of
  true -> true
  _ -> false

f2 x = case x of
        true -> true
        _ -> false
```

So the proper behavior is: "take previous-line indentation, then if
previous line has a modifier increase/decrease it". This is both
simple, robust, typically meets the user expectations, and is AFAIK
what all built-in major modes do.

Unfortunately we're long past that point, the purescript-mode
indentation engine parses a lot of stuff it shouldn't. And frequently
it gives a "parsing error". In my experience all those "errors" are
bugs because the PS code is perfectly valid, but disregarding if it's
a bug or an actual unfinished code in the buffer, engine should never
leave a user with no indentation whatsoever.

So what this commit does is it detects such "errors", and takes
previous indentation level. Even if it's not the correct indentation,
in practice it's only off by `purescript-indentation-left-offset`, so
a user often has much less to type compared to "no indentation" at
all.

-------

Now, it turns out the mode has another bug. As explained in the
function being added, `purescript-newline-and-indent` calls
indentation calculations on the wrong line. This isn't some special
code that only `purescript-newline-and-indent` uses, it is a code
that's being called by the <kbd>TAB</kbd> indentation as well.

As there are huge amounts of poorly documented code that shouldn't
even be there in the first place, and are sometimes using local
variables from other functions, I decided instead of trying to fix the
code it would be more productive to just detect whether we're being
called from `purescript-newline-and-indent` or not.
  • Loading branch information
Hi-Angel committed Oct 2, 2024
1 parent d187b3d commit cc34919
Showing 1 changed file with 32 additions and 14 deletions.
46 changes: 32 additions & 14 deletions purescript-indentation.el
Original file line number Diff line number Diff line change
Expand Up @@ -463,21 +463,39 @@ autofill-mode."
(defun purescript-indentation-first-indentation ()
(if (eq purescript-literate 'bird) '(2) '(0)))

(defun purescript-get-previous-indentation-hack ()
"Return previous indentation level as a list element.
This function is a temporary workaround for
`purescript-newline-and-indent' asking for indent before going to the
new line, which makes it indistinguishable from just attempting to
indent the current line. This has to be fixed elsewhere."
(list
(if (string= this-command "purescript-newline-and-indent")
(current-indentation) ;; current line is actually previous one
(save-excursion
(forward-line -1)
(current-indentation)))))

(defun purescript-indentation-find-indentations ()
(let ((ppss (syntax-ppss)))
(cond
((nth 3 ppss)
(purescript-indentation-first-indentation))
((nth 4 ppss)
(if (save-excursion
(and (skip-syntax-forward "-")
(eolp)
(not (> (forward-line 1) 0))
(not (nth 4 (syntax-ppss)))))
(purescript-indentation-parse-to-indentations)
(purescript-indentation-first-indentation)))
(t
(purescript-indentation-parse-to-indentations)))))
(condition-case nil
(let ((ppss (syntax-ppss)))
(cond
((nth 3 ppss)
(purescript-indentation-first-indentation))
((nth 4 ppss)
(if (save-excursion
(and (skip-syntax-forward "-")
(eolp)
(not (> (forward-line 1) 0))
(not (nth 4 (syntax-ppss)))))
(purescript-indentation-parse-to-indentations)
(purescript-indentation-first-indentation)))
(t
(purescript-indentation-parse-to-indentations))))
;; Ideally it should not return parse error but if it does just use the previous
;; indentation.
(parse-error (purescript-get-previous-indentation-hack))))

(defconst purescript-indentation-unicode-tokens
'(("" . "->") ;; #x2192 RIGHTWARDS ARROW
Expand Down

0 comments on commit cc34919

Please sign in to comment.