From 88fe919d2b6af8b81c25fdad291c2dd062dff7f4 Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 13 May 2020 11:41:50 -0700 Subject: rewrite algorithm, changing what we treat as a special case Signed-off-by: Sean Whitton --- NEWS.md | 26 +++++++++++++++++------- haskell-tab-indent.el | 55 ++++++++++++++++++++++++++------------------------- 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)))) -- cgit v1.2.3