aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorSean Whitton <spwhitton@spwhitton.name>2020-05-13 11:41:50 -0700
committerSean Whitton <spwhitton@spwhitton.name>2020-05-13 11:41:50 -0700
commit88fe919d2b6af8b81c25fdad291c2dd062dff7f4 (patch)
tree9a239afee4b37531d2935bac257ac226ec1afb57
parentefbe6610ab6ef3cebd0708f5c34b72c346b0228d (diff)
downloadhaskell-tab-indent-88fe919d2b6af8b81c25fdad291c2dd062dff7f4.tar.gz
rewrite algorithm, changing what we treat as a special case
Signed-off-by: Sean Whitton <spwhitton@spwhitton.name>
-rw-r--r--NEWS.md26
-rw-r--r--haskell-tab-indent.el55
2 files changed, 47 insertions, 34 deletions
diff --git a/NEWS.md b/NEWS.md
index b4f7838..d46fcd5 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,15 +1,27 @@
0.3 (unreleased)
----------------
-- When checking whether we're on the first line of a where clause,
- require 'where' followed by end of line, rather than just a line
- starting with 'where'.
+- When checking for the first line of a where clause, require 'where'
+ followed by end of line, rather than just a line starting with
+ 'where'.
-- Recognise all declarations, not just top level declarations, in code
- handling the case where the last command was `newline-and-indent'.
+- Recognise all declarations, not just top level declarations. On
+ lines following a declaration, always indent to the same level as
+ the previous line, rather than indenting one further.
-- Attempt to line up the first line of definitions with declarations
- on the previous line, rather than indenting further.
+ Lines following declarations should either be indented to the same
+ level as the declaration, or be blank.
+
+- Always indent the first line of the contents of a where clause to
+ one plus the level of the line containing 'where'.
+
+- When one of the above cases does not apply, default to indenting to
+ the same level of the previous line, unless the user explicitly
+ invoked `indent-for-tab-command' (e.g. by hitting the tab key), in
+ which case cycle between possible indents.
+
+ This replaces treating the case where the current command is
+ `newline-and-indent' specially.
- Reset indentation when current indentation is at least one more than
the previous line, rather than just when it is exactly one more than
diff --git a/haskell-tab-indent.el b/haskell-tab-indent.el
index e6c58a4..15686cb 100644
--- a/haskell-tab-indent.el
+++ b/haskell-tab-indent.el
@@ -59,7 +59,8 @@
(length (seq-filter (lambda (c) (equal c ?\t))
(buffer-substring
(line-beginning-position)
- (point)))))))
+ (point))))))
+ (tabs (n) (make-string n ?\t)))
(defun haskell-tab-indent ()
"Auto indentation on TAB for `haskell-tab-indent-mode'."
(interactive)
@@ -73,34 +74,34 @@
(prev-line-decl
(save-excursion
(beginning-of-line 0)
- (looking-at "[[:space:]]*[^[:space:]]+ ::"))))
+ (looking-at "^[[:blank:]]*[^[:graph:]]+ :: ")))
+ (prev-line-where
+ (save-excursion
+ (beginning-of-line 0)
+ (looking-at "^[[:blank:]]*where$"))))
(save-excursion
(back-to-indentation)
- (if (looking-at "where$")
- (setf (buffer-substring (line-beginning-position) (point)) " ")
- ;; if the previous line is a declaration, then this line
- ;; should be either empty, or at the same indent level as
- ;; that declaration
- (if prev-line-decl
- (setf (buffer-substring (line-beginning-position) (point))
- (make-string prev-line-tabs ?\t))
- ;; check for special case of being called by
- ;; `newline-and-indent': if the user has `electric-indent-mode'
- ;; on and RET bound to `newline-and-indent', we'll end up
- ;; indenting too far, or not enough if the previous line was a
- ;; declaration
- (unless (or
- ;; avoid indenting too far
- (and (equal this-command 'newline-and-indent)
- (= this-line-tabs prev-line-tabs)
- (not prev-line-decl))
- ;; avoid indenting too little
- (and prev-line-decl (= 1 this-line-tabs)))
- (if (>= this-line-tabs (1+ prev-line-tabs))
- ;; reset
- (delete-region (line-beginning-position) (point))
- ;; indent
- (insert "\t")))))))
+ (let ((indent
+ (if (looking-at "where$")
+ (concat (tabs prev-line-tabs) " ")
+ (tabs
+ (cond
+ ;; if the previous line is a declaration, then this
+ ;; line should be either empty, or at the same indent
+ ;; level as that declaration
+ (prev-line-decl prev-line-tabs)
+ ;; if the previous line was the beginning of a where
+ ;; clause, indent should be exactly one more
+ (prev-line-where (1+ prev-line-tabs))
+ ;; if the user explicitly requested an indent
+ ;; change, cycle through the plausible indents
+ ((eq this-command 'indent-for-tab-command)
+ (if (>= this-line-tabs (1+ prev-line-tabs))
+ 0
+ (1+ this-line-tabs)))
+ ;; otherwise, indent to same level as previous line
+ (t prev-line-tabs))))))
+ (setf (buffer-substring (line-beginning-position) (point)) indent))))
;; on a line with only indentation, ensure point is at the end
(when (save-excursion (beginning-of-line) (looking-at "[[:space:]]*$"))
(end-of-line))))