Skip to content

Commit efd33e8

Browse files
committed
Implement electric characters
This defines various keys that will trigger auto reindentation when appropriate. This approach is somewhat similar to how `cc-mode' implements electric keys. Closes #1133.
1 parent 01eb3fc commit efd33e8

File tree

1 file changed

+47
-17
lines changed

1 file changed

+47
-17
lines changed

haskell-indentation.el

Lines changed: 47 additions & 17 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

@@ -87,18 +100,13 @@
87100
It rebinds RET, DEL and BACKSPACE, so that indentations can be
88101
set and deleted as if they were real tabs."
89102
:keymap haskell-indentation-mode-map
90-
(kill-local-variable 'indent-line-function)
91-
(kill-local-variable 'indent-region-function)
92103

93104
(when haskell-indentation-mode
94105
(when (and (bound-and-true-p haskell-indent-mode)
95106
(fboundp 'turn-off-haskell-indent))
96107
(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)))
108+
(setq-local indent-line-function #'haskell-indentation-indent-line)
109+
(setq-local indent-region-function #'haskell-indentation-indent-region)))
102110

103111
;;;###autoload
104112
(defun turn-on-haskell-indentation ()
@@ -135,7 +143,7 @@ set and deleted as if they were real tabs."
135143
Called from a program, takes three arguments, START, END and ARG.
136144
You can remove all indentation from a region by giving a large
137145
negative ARG. Handles bird style literate Haskell too."
138-
(interactive "r\np")
146+
(interactive "*r\np")
139147
(save-excursion
140148
(goto-char end)
141149
(let ((end-marker (point-marker)))
@@ -171,7 +179,7 @@ negative ARG. Handles bird style literate Haskell too."
171179

172180
(defun haskell-indentation-newline-and-indent ()
173181
"Insert newline and indent."
174-
(interactive)
182+
(interactive "*")
175183
;; On RET (or C-j), we:
176184
;; - just jump to the next line if literate haskell, but outside code
177185
(if (haskell-indentation-bird-outside-code-p)
@@ -224,7 +232,7 @@ Do nothing inside multiline comments and multiline strings.
224232
Start enumerating the indentation points to the right. The user
225233
can continue by repeatedly pressing TAB. When there is no more
226234
indentation points to the right, we switch going to the left."
227-
(interactive)
235+
(interactive "*")
228236
;; try to repeat
229237
(when (not (haskell-indentation-indent-line-repeat))
230238
(setq haskell-indentation-dyn-last-direction nil)
@@ -296,7 +304,7 @@ fixes up only indentation."
296304

297305
(defun haskell-indentation-indent-backwards ()
298306
"Indent the current line to the previous indentation point."
299-
(interactive)
307+
(interactive "*")
300308
(cond
301309
((and (memq last-command
302310
'(indent-for-tab-command haskell-indentation-indent-backwards))
@@ -323,7 +331,30 @@ fixes up only indentation."
323331
(car (haskell-indentation-first-indentation)) cursor-in-whitespace)
324332
(haskell-indentation-reindent-to pi cursor-in-whitespace))))))
325333

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

@@ -740,8 +771,7 @@ For example
740771
(throw 'parse-end nil))))))
741772

742773
(defun haskell-indentation-toplevel-where ()
743-
"Parse 'where' that we may hit as a standalone in module
744-
declaration."
774+
"Parse 'where' that we may hit as a standalone in module declaration."
745775
(haskell-indentation-read-next-token)
746776

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

0 commit comments

Comments
 (0)