From c0bd13db0c3817aa23fffc790dbe4a1c5a0ad03b Mon Sep 17 00:00:00 2001 From: Sean Whitton Date: Wed, 13 May 2020 10:11:30 -0700 Subject: improve behaviour when the previous line was a declaration Signed-off-by: Sean Whitton --- NEWS.md | 6 ++++++ haskell-tab-indent.el | 59 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 42 insertions(+), 23 deletions(-) diff --git a/NEWS.md b/NEWS.md index 8d68021..b5cc9f5 100644 --- a/NEWS.md +++ b/NEWS.md @@ -5,6 +5,12 @@ 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'. + +- Attempt to line up the first line of definitions with declarations + on the previous line, rather than indenting further. + - Drop reference to an old git subtrees script from README.md. - Code cleanup. diff --git a/haskell-tab-indent.el b/haskell-tab-indent.el index 06b64c8..723786d 100644 --- a/haskell-tab-indent.el +++ b/haskell-tab-indent.el @@ -59,7 +59,13 @@ (length (seq-filter (lambda (c) (equal c ?\t)) (buffer-substring (line-beginning-position) - (point))))))) + (point)))))) + (line-first-word () (save-excursion + (back-to-indentation) + (let ((beg (point))) + (while (not (looking-at "[[:space:]]")) + (forward-char)) + (buffer-substring-no-properties beg (point)))))) (defun haskell-tab-indent () "Auto indentation on TAB for `haskell-tab-indent-mode'." (interactive) @@ -69,34 +75,41 @@ (cl-loop do (beginning-of-line 0) while (looking-at "[[:space:]]*$")) (count-line-tabs))) - ;; determine whether previous line is a top-level declaration - (prev-line-topdecl + (this-first-word (line-first-word)) + (prev-first-word (save-excursion + (beginning-of-line 0) + (line-first-word))) + ;; determine whether previous line is a declaration + (prev-line-decl (save-excursion (beginning-of-line 0) - (eq 'haskell-definition-face - (get-text-property (point) 'face))))) + (looking-at "[[:space:]]*[^[:space:]]+ ::")))) (save-excursion (back-to-indentation) (if (looking-at "where$") (setf (buffer-substring (line-beginning-position) (point)) " ") - ;; 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 - ;; top level declaration - (unless (or - ;; avoid indenting too far - (and (equal this-command 'newline-and-indent) - (= this-line-tabs prev-line-tabs) - (not prev-line-topdecl)) - ;; avoid indenting too little - (and prev-line-topdecl - (= 1 this-line-tabs))) - (if (= (1+ prev-line-tabs) this-line-tabs) - ;; reset - (delete-region (line-beginning-position) (point)) - ;; indent - (insert "\t")))))) + ;; attempt to line up declarations and definitions + (if (and prev-line-decl + (string= this-first-word prev-first-word)) + (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 (= (1+ prev-line-tabs) this-line-tabs) + ;; reset + (delete-region (line-beginning-position) (point)) + ;; indent + (insert "\t"))))))) ;; 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