Author: T.v.Dein
URL: https://github.com/tlinden/autoscratch
This simple major mode can be used as the initial major mode for the scratch buffer. It automatically switches to another major mode based on regexes triggered by text input.
In the default configuration it responds to the first
non-whitespace character entered into the scratch buffer and
switches major mode based on this. See the variable
autoscratch-triggers-alist
for the defaults. For example, if you
enter a paren, it will switch to emacs-lisp-mode
.
I use emacs for more than 20 years now. I love it, I am addicted, I can't even do anything productive without it. However, there was one problem left: the scratch buffer. This is a non-file buffer, which always exists always in emacs. By default it has emacs-lisp-mode enabled and you can use it to hack short elisp sexps for testing. In fact I use it for exactly this purpose.
But sometimes I hate it as well! I get a phone call and need to take a note quickly, scratch is already open, so I use this. But the mode doesn't really fit. So I switch to text-mode and then enter the notes. I did it this way almost since day one of my emacs usage.
A couple of months ago I came up with a "solution", I just create a text buffer on startup with text-mode already enabled in my .emacs. But I still need to switch to it everytime I need it. Still too annoying!
So now, here's my final solution, which tries to fix this mess once and for all: autoscratch.
This major mode is really simple. Basically it consits of an alist with instructions on how to automatically switch the scratch* buffer mode. Enter an "(" and it switches to emacs-lisp-mode, enter "*" and it switches to org-mode, enter some letter a-z, and it switches to text-mode. You get the idea.
It also solves another problem I (and many other users according to google) have: once I set the scratch buffer mode to, say, text-mode with some text in there, I don't have an elisp scratch buffer left anymore. I'd need another one, but how to create a second scratch buffer? Obviously you'll need to rename the current text-mode buffer first and then create a new empty buffer. The emacs wiki contains lots of suggestions for this kind of problem.
No more of this! Autoscratch can just "fork" the buffer, if enabled (set autoscratch-fork-after-trigger to t which is the default). Here's how it works: type a "(" into the empty autoscratch-enabled scratch buffer. Autoscratch renames this buffer to emacs-lisp-scratch, enables emacs-lisp-mode and creates a new scratch buffer in the background. So, if you need some scratch space, it'll be there for you waiting bravely for input.
Put autoscratch.el
into your load-path or use package-install
to install it.
If you're using use-package
, then add this:
(use-package autoscratch
:ensure t
:config
(setq initial-major-mode 'autoscratch-mode))
The minimum configuration looks like this:
(require 'autoscratch)
(setq initial-major-mode 'autoscratch-mode)
(setq initial-scratch-message "")
(setq inhibit-startup-screen t)
You may, however, configure the trigger list
autoscratch-triggers-alist
according to your preferences. This
list consists of cons cells, where the car
is a regexp and the
cdr
an emacs lisp form (e.g. a lambda or defun). If you want to
use regexps which match more than one character, then you need to
set autoscratch-trigger-on-first-char
to nil
and possibly tune
autoscratch-trigger-after
accordingly.
If no regexp matches and/or autoscratch-trigger-after
is
exceeded, then the autoscratch-default-trigger
form will be
executed, which by default is fundamental-mode
, but you can of
course change this.
(("[(;]" . (emacs-lisp-mode))
("#" . (autoscratch-select
'(("perl" . (cperl-mode))
("ruby" . (ruby-mode))
("python" . (python-mode))
("conf" . (conf-unix-mode))
("shell" . (shell-script-mode)))))
("[-a-zA-Z0-9]" . (text-mode))
("/" . (c-mode))
("*" . (progn (insert " ") (org-mode)))
("." . (fundamental-mode)))
Please note the trigger of the #
character: an interactive prompt
will ask you which mode to select.
Autoscratch can also be configured to rename the current buffer
after it switched mode based on a trigger and create a new
autoscratch-buffer
in the background. In order to enable this
feature, set autoscratch-fork-after-trigger
to t.
This is my own config:
(use-package autoscratch
:ensure t
:config
(setq initial-major-mode 'autoscratch-mode)
(add-hook 'autoscratch-mode-hook '(lambda ()
(setq autoscratch-triggers-alist
'(("[(;]" . (progn
(call-interactively 'emacs-lisp-mode)
(call-interactively 'enable-paredit-mode)
(call-interactively 'electric-pair-mode)))
("#" . (progn
(call-interactively 'config-general-mode)
(electric-indent-local-mode t)))
("[-a-zA-Z0-9]" . (text-mode))
("/" . (c-mode))
("*" . (progn (insert " ") (org-mode)))
("." . (fundamental-mode)))
autoscratch-trigger-on-first-char t
autoscratch-reset-default-directory t)
(electric-indent-local-mode nil)))
(defalias 'scratch 'autoscratch-buffer))
I'd also recommend to use persistent-scratch in combination with autoscratch, here's my config for this:
(defun tvd-autoscratch-p ()
"Return non-nil if the current buffer is a scratch buffer"
(string-match "scratch*" (buffer-name)))
(use-package persistent-scratch
:config
(setq persistent-scratch-save-file (expand-file-name "scratches.el" user-emacs-directory))
(persistent-scratch-setup-default)
(setq persistent-scratch-scratch-buffer-p-function 'tvd-autoscratch-p))
If you're using evil mode than, you might better setup an initial state for autoscratch (it doesn't make much sense otherwise):
(evil-set-initial-state 'autoscratch-mode 'insert)
Variable | Setting | Default Value |
---|---|---|
autoscratch-triggers-alist |
List of single char commands with their triggering lisp | see above default trigger list |
autoscratch-trigger-on-first-char |
Trigger after the first character has been entered, no matter what. | t |
autoscratch-default-trigger |
Default form to execute when nothing else matches. | '(fundamental-mode) |
autoscratch-fork-after-trigger |
Create a new autoscratch buffer after the trigger fired. | t |
autoscratch-trigger-after |
Max chars to be entered to force trigger the default form. | 5 |
autoscratch-reset-default-directory |
Reset default directory when a new scratch buffer is created. | nil |
Hook | Purpose |
---|---|
autoscratch-trigger-hook |
Hooks called after executing a matching trigger form. |
autoscratch-rename-hook |
Hooks called after renaming the current buffer. |