I've written this little minor mode to get the TAB key to continue indenting after the major mode has performed the initial indent behaviour and/or to force indentation when the major mode thinks no indent is necessary.
It has been pointed out to me that the combination setq
and make-local-variable
can probably be simplified into a let
scope. Given that this needs to work across multiple buffers concurrently, how would one change this to use let
instead of make-local-variable
?
;;; dwim-tab.el --- minor mode to force indentation when TAB would otherwise stall
; internal tracking variables
(setq dwim-tab-point-before nil)
(setq dwim-tab-point-after nil)
(defun dwim-tab ()
"Indents normally once, then switches to tab-to-tab-stop if invoked again.
Always performs tab-to-tab-stop if the first TAB press does not cause the
point to move."
(interactive)
(setq dwim-tab-point-before (point))
(if (eq dwim-tab-point-before dwim-tab-point-after) ; pressed TAB again
(tab-to-tab-stop)
(indent-for-tab-command))
(if (eq (point) dwim-tab-point-before) ; point didn't move
(tab-to-tab-stop))
(setq dwim-tab-point-after (point)))
(define-minor-mode dwim-tab-mode
"Toggle dwim-tab-mode.
With a non-nil argument, turns on dwim-tab-mode. With a nil argument, turns it
off.
When dwim-tab-mode is enabled, pressing the TAB key once will behave as normal,
but pressing it subsequent times, will continue to indent, using
tab-to-tab-stop.
If dwim-tab determines that the first TAB key press resulted in no movement of
the point, it will indent according to tab-to-tab-stop instead."
:init-value nil
:lighter " DWIM"
:keymap '(("\t" . dwim-tab))
(make-local-variable 'dwim-tab-point-before)
(make-local-variable 'dwim-tab-point-after))
(provide 'dwim-tab)
Does this do what you want? Look ma, no variables!
The last-command check isn't strictly necessary assuming
indent-for-tab-command
won't magically start indenting again. But it's slightly more CPU efficient.