Skip to content

Commit a1c9d62

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 a1c9d62

File tree

1 file changed

+47
-15
lines changed

1 file changed

+47
-15
lines changed

haskell-indentation.el

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

@@ -740,8 +773,7 @@ For example
740773
(throw 'parse-end nil))))))
741774

742775
(defun haskell-indentation-toplevel-where ()
743-
"Parse 'where' that we may hit as a standalone in module
744-
declaration."
776+
"Parse 'where' that we may hit as a standalone in module declaration."
745777
(haskell-indentation-read-next-token)
746778

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

0 commit comments

Comments
 (0)