Skip to content

Commit db874f5

Browse files
committed
Merge pull request #1302 from fice-t/indentation
Implement electric characters
2 parents 9fb8e3a + 82beb7f commit db874f5

File tree

2 files changed

+62
-24
lines changed

2 files changed

+62
-24
lines changed

doc/haskell-mode.texi

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -819,6 +819,13 @@ position, @kbd{S-TAB} selects the previous one. If a block is selected
819819
you can use @kbd{TAB} to indent the block more and @kbd{S-TAB} to indent
820820
the block less.
821821

822+
When @code{electric-indent-mode} is enabled or the variable
823+
@code{haskell-indentation-electric-flag} is non-nil, the insertion of
824+
some characters (by default @kbd{,} @kbd{;} @kbd{)} @kbd{@}} @kbd{]})
825+
may trigger auto reindentation under appropriate conditions. See the
826+
documentation of @code{haskell-indentation-common-electric-command} for
827+
more details.
828+
822829
@item @code{haskell-indent-mode} (optional).
823830

824831
This is a semi-intelligent indentation mode doing a decent job at

haskell-indentation.el

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,23 @@
7474
:type 'integer
7575
:group 'haskell-indentation)
7676

77-
(defconst haskell-indentation-mode-map
77+
(defcustom haskell-indentation-electric-flag nil
78+
"Non-nil means insertion of some characters may auto reindent the line.
79+
If the variable `electric-indent-mode' is non-nil then this variable is
80+
overridden."
81+
:type 'symbol
82+
:group 'haskell-indentation)
83+
(make-variable-buffer-local 'haskell-indentation-electric-flag)
84+
85+
(defvar haskell-indentation-mode-map
7886
(let ((map (make-sparse-keymap)))
79-
(define-key map (kbd "RET") 'haskell-indentation-newline-and-indent)
80-
(define-key map (kbd "<backtab>") 'haskell-indentation-indent-backwards)
87+
(define-key map (kbd "RET") #'haskell-indentation-newline-and-indent)
88+
(define-key map (kbd "<backtab>") #'haskell-indentation-indent-backwards)
89+
(define-key map (kbd ",") #'haskell-indentation-common-electric-command)
90+
(define-key map (kbd ";") #'haskell-indentation-common-electric-command)
91+
(define-key map (kbd ")") #'haskell-indentation-common-electric-command)
92+
(define-key map (kbd "}") #'haskell-indentation-common-electric-command)
93+
(define-key map (kbd "]") #'haskell-indentation-common-electric-command)
8194
map)
8295
"Keymap for `haskell-indentation-mode'.")
8396

@@ -94,11 +107,8 @@ set and deleted as if they were real tabs."
94107
(when (and (bound-and-true-p haskell-indent-mode)
95108
(fboundp 'turn-off-haskell-indent))
96109
(turn-off-haskell-indent))
97-
(when (and (bound-and-true-p haskell-simple-indent-mode)
98-
(fboundp 'haskell-simple-indent-mode))
99-
(haskell-simple-indent-mode 0))
100-
(setq-local indent-line-function 'haskell-indentation-indent-line)
101-
(setq-local indent-region-function 'haskell-indentation-indent-region)))
110+
(setq-local indent-line-function #'haskell-indentation-indent-line)
111+
(setq-local indent-region-function #'haskell-indentation-indent-region)))
102112

103113
;;;###autoload
104114
(defun turn-on-haskell-indentation ()
@@ -135,7 +145,7 @@ set and deleted as if they were real tabs."
135145
Called from a program, takes three arguments, START, END and ARG.
136146
You can remove all indentation from a region by giving a large
137147
negative ARG. Handles bird style literate Haskell too."
138-
(interactive "r\np")
148+
(interactive "*r\np")
139149
(save-excursion
140150
(goto-char end)
141151
(let ((end-marker (point-marker)))
@@ -171,7 +181,7 @@ negative ARG. Handles bird style literate Haskell too."
171181

172182
(defun haskell-indentation-newline-and-indent ()
173183
"Insert newline and indent."
174-
(interactive)
184+
(interactive "*")
175185
;; On RET (or C-j), we:
176186
;; - just jump to the next line if literate haskell, but outside code
177187
(if (haskell-indentation-bird-outside-code-p)
@@ -224,7 +234,7 @@ Do nothing inside multiline comments and multiline strings.
224234
Start enumerating the indentation points to the right. The user
225235
can continue by repeatedly pressing TAB. When there is no more
226236
indentation points to the right, we switch going to the left."
227-
(interactive)
237+
(interactive "*")
228238
;; try to repeat
229239
(when (not (haskell-indentation-indent-line-repeat))
230240
(setq haskell-indentation-dyn-last-direction nil)
@@ -296,7 +306,7 @@ fixes up only indentation."
296306

297307
(defun haskell-indentation-indent-backwards ()
298308
"Indent the current line to the previous indentation point."
299-
(interactive)
309+
(interactive "*")
300310
(cond
301311
((and (memq last-command
302312
'(indent-for-tab-command haskell-indentation-indent-backwards))
@@ -323,7 +333,30 @@ fixes up only indentation."
323333
(car (haskell-indentation-first-indentation)) cursor-in-whitespace)
324334
(haskell-indentation-reindent-to pi cursor-in-whitespace))))))
325335

326-
336+
(defun haskell-indentation-common-electric-command (arg)
337+
"Call `self-insert-command' to insert the character typed ARG times
338+
and indent when all of the following are true:
339+
1) The character is the first non-whitespace character on the line.
340+
2) There is only one possible indentation position.
341+
3) The variable `electric-indent-mode' or `haskell-indentation-electric-flag'
342+
is non-nil.
343+
4) The point is not in a comment, string, or quasiquote."
344+
(interactive "*p")
345+
(let ((col (current-column))
346+
ind)
347+
(self-insert-command arg)
348+
(when (and (or haskell-indentation-electric-flag
349+
electric-indent-mode)
350+
(= (haskell-indentation-current-indentation)
351+
col)
352+
(> arg 0)
353+
(not (nth 8 (syntax-ppss)))
354+
(= 1 (save-excursion
355+
(move-to-column col)
356+
(length (setq ind (haskell-indentation-find-indentations))))))
357+
(haskell-indentation-reindent-to (car ind)))))
358+
359+
327360
;;----------------------------------------------------------------------------
328361
;; Parser Starts Here
329362

@@ -678,16 +711,15 @@ For example
678711
(haskell-indentation-with-starter
679712
#'haskell-indentation-type-1)))))
680713
((string= current-token "where")
681-
(let ((starter-indent-inside (current-column)))
714+
(haskell-indentation-with-starter
715+
#'haskell-indentation-expression-layout nil)
716+
(cond
717+
((equal current-token 'end-tokens)
718+
(when (string= following-token "deriving")
719+
(haskell-indentation-add-left-indent)))
720+
((equal current-token "deriving")
682721
(haskell-indentation-with-starter
683-
#'haskell-indentation-expression-layout nil)
684-
(cond
685-
((equal current-token 'end-tokens)
686-
(when (string= following-token "deriving")
687-
(haskell-indentation-add-left-indent)))
688-
((equal current-token "deriving")
689-
(haskell-indentation-with-starter
690-
#'haskell-indentation-type-1)))))))
722+
#'haskell-indentation-type-1))))))
691723

692724
(defun haskell-indentation-import ()
693725
"Parse import declaration."
@@ -740,8 +772,7 @@ For example
740772
(throw 'parse-end nil))))))
741773

742774
(defun haskell-indentation-toplevel-where ()
743-
"Parse 'where' that we may hit as a standalone in module
744-
declaration."
775+
"Parse 'where' that we may hit as a standalone in module declaration."
745776
(haskell-indentation-read-next-token)
746777

747778
(when (eq current-token 'end-tokens)

0 commit comments

Comments
 (0)