[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[nongnu] elpa/haskell-tng-mode 1009082 140/385: append indentation test
From: |
ELPA Syncer |
Subject: |
[nongnu] elpa/haskell-tng-mode 1009082 140/385: append indentation test |
Date: |
Tue, 5 Oct 2021 23:59:18 -0400 (EDT) |
branch: elpa/haskell-tng-mode
commit 10090824cd2998ad90625a4983e741cdb900b198
Author: Tseen She <ts33n.sh3@gmail.com>
Commit: Tseen She <ts33n.sh3@gmail.com>
append indentation test
---
haskell-tng-layout.el | 14 ++++
haskell-tng-mode.el | 9 ++-
haskell-tng-smie.el | 2 +-
test/haskell-tng-indent-test.el | 127 +++++++++++++++++++++++-----------
test/src/indentation.hs.append.indent | 102 +++++++++++++++++++++++++++
5 files changed, 210 insertions(+), 44 deletions(-)
diff --git a/haskell-tng-layout.el b/haskell-tng-layout.el
index 0a4f311..f4af977 100644
--- a/haskell-tng-layout.el
+++ b/haskell-tng-layout.el
@@ -32,8 +32,14 @@
;;
;; Anything more complicated that small brain needs improved testing.
+(require 'dash)
+
(require 'haskell-tng-util)
+;; FIXME only search up to one line for the WLDO opener, otherwise close it out
+;; with {} This is not valid compiling Haskell code, but it allows SMIE to
close
+;; off the s-expression.
+
;; Easiest cache... full buffer parse with full invalidation on any insertion.
(defvar-local haskell-tng-layout:cache nil)
@@ -74,6 +80,14 @@ Designed to be called repeatedly, managing its own caching."
(push ";" breaks))))))
(append (reverse closes) (reverse breaks))))))
+(defun haskell-tng-layout:has-virtual-at-point ()
+ "t if there is a virtual at POINT"
+ ;; avoids a measured performance hit (append indentation)
+ (unless haskell-tng-layout:cache
+ (haskell-tng-layout:rebuild-cache-full))
+ (--any (member (point) it)
+ haskell-tng-layout:cache))
+
(defun haskell-tng-layout:rebuild-cache-full ()
(let (case-fold-search
cache)
diff --git a/haskell-tng-mode.el b/haskell-tng-mode.el
index fbc9e4f..86594bc 100644
--- a/haskell-tng-mode.el
+++ b/haskell-tng-mode.el
@@ -73,10 +73,13 @@ Load `prettify-symbols-mode' in `haskell-tng-mode-hook'."
font-lock-multiline t
font-lock-extend-region-functions haskell-tng:extend-region-functions
- ;; whitespace is meaningful, no electric indentation
- electric-indent-inhibit t
-
prettify-symbols-alist haskell-tng-mode:prettify-symbols)
+
+ ;; whitespace is meaningful, disable electric indentation. Note that
+ ;; `electric-indent-inhibit' causes a performance regression in SMIE
+ ;; indentation, so it's best to just make sure it is disabled.
+ (electric-indent-mode 0)
+
(setq-local projectile-tags-command "fast-tags -Re --exclude=dist-newstyle
.")
(setq-local smie-blink-matching-inners nil) ;; c.f. `smie-closer-alist'
diff --git a/haskell-tng-smie.el b/haskell-tng-smie.el
index 8caab9f..db485c9 100644
--- a/haskell-tng-smie.el
+++ b/haskell-tng-smie.el
@@ -242,7 +242,7 @@ current line."
(forward-line))
(goto-char start)
(while (< (point) bound)
- (when (haskell-tng-layout:virtuals-at-point)
+ (when (haskell-tng-layout:has-virtual-at-point)
(push (current-column) relevant))
(forward-char))
relevant))
diff --git a/test/haskell-tng-indent-test.el b/test/haskell-tng-indent-test.el
index 07c3128..213de04 100644
--- a/test/haskell-tng-indent-test.el
+++ b/test/haskell-tng-indent-test.el
@@ -12,31 +12,48 @@
(require 'haskell-tng-testutils
"test/haskell-tng-testutils.el")
- ;; Three indentation regression tests are possible:
- ;;
- ;; 1. newline-and-indent with the rest of the file deleted (append)
- ;; 2. newline-and-indent with the rest of the file intact (insert)
- ;; 3. indent-line-function at the beginning of each line (re-indent)
- ;;
- ;; each maybe with alternative indentation suggestions.
- ;;
- ;; Expectations could use lines of symbols such as | and . or digits to
- ;; indicate where the indentation(s) go.
- ;;
- ;; Test 1 involves a lot of buffer refreshing and will be very slow.
-
-(ert-deftest haskell-tng-newline-indent-file-tests ()
- (should (have-expected-newline-indent-insert (testdata
"src/indentation.hs")))
-
- ;; (should (have-expected-newline-indent-insert (testdata "src/layout.hs")))
- ;; (should (have-expected-newline-indent-insert (testdata "src/medley.hs")))
+;; Three indentation regression tests are possible:
+;;
+;; 1. newline-and-indent with the rest of the file deleted (append)
+;; 2. newline-and-indent with the rest of the file intact (insert)
+;; 3. indent-line-function at the beginning of each line (re-indent)
+;;
+;; each maybe with alternative indentation suggestions.
+;;
+;; Expectations could use lines of symbols such as | and . or digits to
+;; indicate where the indentation(s) go.
+;;
+;; Test 1 involves a lot of buffer refreshing and will be very slow.
+
+(ert-deftest haskell-tng-append-indent-file-tests ()
+ ;; this is a very slow test
+
+ ;; (require 'profiler)
+ ;; (profiler-start 'cpu)
+
+ (should (have-expected-append-indent (testdata "src/indentation.hs")))
+
+ ;; (profiler-report)
+ ;; (profiler-report-write-profile "indentation.profile")
+ ;; (profiler-stop)
+
+ ;; To interactively inspect
+ ;; (profiler-find-profile "../indentation.profile")
+ )
+
+
+(ert-deftest haskell-tng-indent-file-tests ()
+ (should (have-expected-insert-indent (testdata "src/indentation.hs")))
+
+ ;; (should (have-expected-insert-indent (testdata "src/layout.hs")))
+ ;; (should (have-expected-insert-indent (testdata "src/medley.hs")))
)
(ert-deftest haskell-tng-reindent-file-tests ()
- (should (have-expected-reindent-insert (testdata "src/indentation.hs")))
+ (should (have-expected-reindent (testdata "src/indentation.hs")))
- ;; (should (have-expected-reindent-insert (testdata "src/layout.hs")))
- ;; (should (have-expected-reindent-insert (testdata "src/medley.hs")))
+ ;; (should (have-expected-reindent (testdata "src/layout.hs")))
+ ;; (should (have-expected-reindent (testdata "src/medley.hs")))
)
(defun current-line-string ()
@@ -44,13 +61,22 @@
(line-beginning-position)
(- (line-beginning-position 2) 1)))
-(defun haskell-tng-indent-test:indent-insert (return-mode)
- ;; FIXME the slow append test
- (let (indents)
+(defun haskell-tng-indent-test:work (mode)
+ "MODE can be 'insert, 'reindent, or 'append.
+
+'append is VERY slow."
+ ;; each line could be done in parallel, if emacs allowed such a thing...
+ (let (indents kill)
(while (not (eobp))
;; the command loop is necessary for this/last-command
(cl-flet ((RET ()
(end-of-line)
+ (pcase mode
+ ('append
+ (setq kill ;; kill-region/yank is noisy
+ (buffer-substring-no-properties
+ (point) (point-max)))
+ (delete-region (point) (point-max))))
(ert-simulate-command '(newline-and-indent))
(current-column))
(TAB ()
@@ -59,28 +85,40 @@
(let ((orig (current-indentation))
(line (current-line-string))
- (prime (if return-mode (RET) (TAB)))
+ (prime (pcase mode
+ ((or 'insert 'append) (RET))
+ ('reindent (TAB))))
alts)
(while (and (TAB)
(not (eq (current-column) prime))
(not (member (current-column) alts)))
(push (current-column) alts))
- (push `(, return-mode ,line . (,prime . ,(reverse alts))) indents)
+ (push `(,(pcase mode ((or 'insert 'append) t))
+ ,line . (,prime . ,(reverse alts)))
+ indents)
;; unfortunately killing resets this-command so we can't test double
;; newline insertions, which could accidentally trigger alts only.
- (if return-mode
- (kill-whole-line)
- (indent-line-to orig)
- (ert-simulate-command '(forward-line))))))
+ (pcase mode
+ ('insert (kill-whole-line))
+ ('reindent
+ (indent-line-to orig)
+ (ert-simulate-command '(forward-line)))
+ ('append
+ (forward-line -1)
+ (end-of-line)
+ (save-excursion
+ (insert kill)
+ (delete-region (point) (point-max)))
+ (ert-simulate-command '(forward-line)))))))
(reverse indents)))
(defun haskell-tng-indent-test:indents-to-string (indents)
"INDENTS is a list of INDENT.
-INDENT is a non-empty list of (RETURN-MODE . (LINE . (INDENT .
-ALTS))) where RETURN-MODE is t for newline insertions (i.e. LINE
-is a string of the previous line) and nil for reindent (i.e. LINE
-is a string of the current line).
+INDENT is a non-empty list of (RET . (LINE . (INDENT . ALTS)))
+where RET is t for newline insertions (i.e. LINE is a string of
+the previous line) and nil for reindent (i.e. LINE is a string of
+the current line).
INDENT is the integer suggested next line indentation column and
ALTS is a list of integer alternative indentations."
@@ -88,7 +126,7 @@ ALTS is a list of integer alternative indentations."
(-map #'haskell-tng-indent-test:indent-to-string indents))))
(defun haskell-tng-indent-test:indent-to-string (indent)
- (let* ((return-mode (car indent))
+ (let* ((ret (car indent))
(line (cadr indent))
(prime (caddr indent))
(alts (cdddr indent))
@@ -106,26 +144,35 @@ ALTS is a list of integer alternative indentations."
(t " "))
repr))
(let ((indents (s-join "" (reverse repr))))
- (if return-mode
+ (if ret
(list line indents)
(list indents line)))))
-(defun have-expected-newline-indent-insert (file)
+(defun have-expected-insert-indent (file)
(haskell-tng-testutils:assert-file-contents
file
#'haskell-tng-mode
(lambda ()
(haskell-tng-indent-test:indents-to-string
- (haskell-tng-indent-test:indent-insert t)))
+ (haskell-tng-indent-test:work 'insert)))
"insert.indent"))
-(defun have-expected-reindent-insert (file)
+(defun have-expected-reindent (file)
(haskell-tng-testutils:assert-file-contents
file
#'haskell-tng-mode
(lambda ()
(haskell-tng-indent-test:indents-to-string
- (haskell-tng-indent-test:indent-insert nil)))
+ (haskell-tng-indent-test:work 'reindent)))
"reindent"))
+(defun have-expected-append-indent (file)
+ (haskell-tng-testutils:assert-file-contents
+ file
+ #'haskell-tng-mode
+ (lambda ()
+ (haskell-tng-indent-test:indents-to-string
+ (haskell-tng-indent-test:work 'append)))
+ "append.indent"))
+
;;; haskell-tng-indent-test.el ends here
diff --git a/test/src/indentation.hs.append.indent
b/test/src/indentation.hs.append.indent
new file mode 100644
index 0000000..b630885
--- /dev/null
+++ b/test/src/indentation.hs.append.indent
@@ -0,0 +1,102 @@
+-- | Idealised indentation scenarios.
+v
+--
+v
+-- Bugs and unexpected behaviour in (re-)indentation may be documented here.
+v
+--
+v
+-- Lines marked "manual correction" indicate where we expect the user to
+v
+-- re-indent because it goes against our prediction. In some of these cases,
+v
+-- we could improve the guess with semantic information (e.g. if we know that
+v
+-- the RHS of a bind is only partially applied, then we probably mean to
+v
+-- continue that line instead of start a new one).
+v
+module Indentation where
+v
+
+v
+import Foo.Bar
+v
+import Foo.Baz hiding ( gaz,
+1 v
+ baz
+1 v
+ )
+v 1 2
+
+v 1 2
+basic_do = do
+v
+ foo <- blah blah blah
+v 1
+ bar <- blah blah
+v 1
+ blah -- manual correction
+v 2 1
+ blah -- manual correction
+v 2 1
+ sideeffect
+v 1 2
+ sideeffect' blah
+v 1 2
+ let baz = blah blah
+v 2 1 3
+ blah -- manual correction
+v 2 3 4 1
+ gaz = blah
+v 2 1 3 4
+ haz =
+v 2 1 3 4
+ blah
+v 2 3 14 5
+ pure faz -- manual correction
+v 1 2 34 5
+
+v 1 2 34 5
+nested_do = -- manual correction
+v
+ do foo <- blah
+v 1
+ do bar <- blah -- same level as foo
+v 2 1
+ baz -- same level as bar
+v 2 1
+
+v 1 2
+nested_where a b = foo a b
+v
+ where -- TODO 2
+v
+ foo = bar baz -- indented
+v 1
+ baz = blah blah -- same level as foo
+v 1
+ where -- manual correction
+v 1
+ gaz a = blah -- indented
+v 2 1
+ faz = blah -- same level as gaz
+v 2 1
+
+v 1 2
+-- TODO case statements
+v 1 2
+-- TODO let / in
+v 1 2
+
+v 1 2
+-- TODO coproduct definitions, the | should align with =
+v 1 2
+
+v 1 2
+-- TODO lists, records, tuples
+v 1 2
+
+v 1 2
+-- TODO long type signatures vs definitions
+v 1 2
\ No newline at end of file
- [nongnu] elpa/haskell-tng-mode 6cf67bf 105/385: indentation can't handle mismatched parens, don't test for it, (continued)
- [nongnu] elpa/haskell-tng-mode 6cf67bf 105/385: indentation can't handle mismatched parens, don't test for it, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 25b15eb 102/385: indentation alternatives wiring, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode e023657 107/385: SMIE wishlist, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 497214b 119/385: syntax tests and bugfixes, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode df5d2c5 122/385: better whitespace gap detection, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 3b7cd02 123/385: some todos, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode fc4d3e3 127/385: compilation mode supports multiline error spans, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 88bad65 128/385: visually distinguish compile errors and warnings, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 9dc0abc 129/385: alt indentation levels should be ordered, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 879fc34 130/385: thots, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 1009082 140/385: append indentation test,
ELPA Syncer <=
- [nongnu] elpa/haskell-tng-mode 88b17d4 137/385: started indentation rules, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode cf22f3a 138/385: simplify indentation testing, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode a0f777e 166/385: Revert "duplicate ; tokens to be used as terminators", ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 2320b89 167/385: alternative to smie-rules-* in :elem and :list-intro, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 60d8c20 149/385: indent "case of", ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 7f9afd2 159/385: list indentation, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 6e70344 165/385: duplicate ; tokens to be used as terminators, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode ab5252b 169/385: rearrange alts, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode e1aba33 168/385: fix a layout bug in lists and records, ELPA Syncer, 2021/10/06
- [nongnu] elpa/haskell-tng-mode 2c6c772 150/385: better WLDO indentation, ELPA Syncer, 2021/10/06