Start cleaning up basic structure

This commit is contained in:
Tom Willemse 2015-09-23 14:24:02 +02:00
parent dea9949d4b
commit 85fe9b1ab3

View file

@ -1,6 +1,6 @@
#+TITLE: Emacs init
#+PROPERTY: tangle init2.el
#+STARTUP: showall
#+STARTUP: content
#+OPTIONS: author:nil num:nil toc:nil
#+MACRO: key @@html:<kbd>$1</kbd>@@@@ascii:`$1'@@
#+HTML_HEAD: <link href="https://ryuslash.org/org.css" rel="stylesheet" type="text/css">
@ -122,79 +122,51 @@
(cask-initialize))
#+END_SRC
* Some general-purpose functions and macros
** Some helper functions
A configuration as big as mine is bound to have some functions and
macros that are used in many places.
Certain functions make life a lot easier when configuring Emacs.
These don't generally belong to any one specific customization, but
make things look a lot prettier.
** Turn off
*** Optimized ~with-eval-after-load~
This macro creates a function that will turn off a minor mode that
passed to it.
First offered [[http://www.lunaryorn.com/2013/05/01/byte-compiling-eval-after-load.html][here]] and then later updated [[http://www.lunaryorn.com/2013/06/25/introducing-with-eval-after-load.html][here]] (when
~with-eval-after-load~ was added). Makes for very nice on-demand
settings loading.
#+BEGIN_SRC emacs-lisp
;; http://www.lunaryorn.com/2013/06/25/introducing-with-eval-after-load/
(defmacro stante-after (feature &rest forms)
"After FEATURE is loaded, evaluate FORMS.
FEATURE may be an unquoted feature symbol or a file name, see
`eval-after-load'."
(declare (indent 1) (debug t))
`(,(if (or (not byte-compile-current-file)
(if (symbolp feature)
(require feature nil :noerror)
(load feature :no-message :no-error)))
`progn
(message "stante-after: cannot find %s" feature)
'with-no-warnings)
(with-eval-after-load ',feature ,@forms)))
#+END_SRC
* General customization
These customizations don't belong with any specific mode.
** Set some personal information
This information is used by some emacs commands and modules to make
your life easier.
#+BEGIN_SRC emacs-lisp
(defmacro turn-off (func)
"Create a function that will turn off FUNC when called."
`(lambda () (eval (,func -1))))
(setq user-full-name "Tom Willemse"
user-mail-address "tom@ryuslash.org")
#+END_SRC
** Change setting
Sometimes a mode just needs to change a certain setting to a
specific value.
#+BEGIN_SRC emacs-lisp
(defmacro change-settings (&rest settings)
"Create a function that changes the value of NAME to VALUE."
`(lambda () (setq ,@settings)))
#+END_SRC
** Whitespace only with tabs
In some modes I want to see the tabs in a buffer. Though I don't
want to be overwhelmed by seeing all spaces and line endings.
#+BEGIN_SRC emacs-lisp
(defvar whitespace-style)
(defun oni:whitespace-only-tabs ()
(setq-local whitespace-style '(face tabs))
(whitespace-mode))
#+END_SRC
** Eval after init
Some things can only really work after all other initialization
functions have completed. For example, any functions that require
any ELPA packages to be loaded, unless you want to load it in your
init manually (and have it loaded again later on after your config
has run).
#+BEGIN_SRC emacs-lisp
(defmacro oni:eval-after-init (&rest body)
"Defer execution of BODY until after Emacs init."
(declare (indent 0))
`(add-hook 'emacs-startup-hook #'(lambda () ,@body)))
#+END_SRC
* Set some personal information
This information is used by some emacs commands and modules to make
your life easier.
#+BEGIN_SRC emacs-lisp
(setq user-full-name "Tom Willemse"
user-mail-address "tom@ryuslash.org")
#+END_SRC
* Clean up some UI elements
Some elements are only really useful if you use the mouse. Which I
don't, not if I can help it. Only when browsing the web or using the
odd graphical application do I touch the mouse, and even then as
little as I can.
** Menu bar
** Turn-off menu bar
The menu bar is one of the UI elements which work best with mouses.
Sure you can change your toolkit's key bindings to allow you to
@ -206,7 +178,7 @@
(menu-bar-mode -1)
#+END_SRC
** Tool bar
** Turn-off tool bar
The toolbar is another such thing, and it takes up quite a bit more
space too. Icons can look pretty cool, but in the end if you're not
@ -217,7 +189,7 @@
(tool-bar-mode -1)
#+END_SRC
** Blinking cursor
** Turn-off blinking cursor
I suppose a blinking cursor doesn't get lost very easily. But on
the other hand, it can induce quite a few more headaches.
@ -230,17 +202,17 @@
(blink-cursor-mode -1)
#+END_SRC
** Line numbers
** Turn-off line numbers
As I'm currently using svg-mode-line-themes[fn:2] for my ~mode-line~ I
don't need to show these. Also I didn't really use them much, I
As I'm currently using svg-mode-line-themes[fn:2] for my ~mode-line~
I don't need to show these. Also I didn't really use them much, I
don't often need to know what line I'm on.
#+BEGIN_SRC emacs-lisp
(line-number-mode -1)
#+END_SRC
** Tooltips
** Turn-off tooltips
Tooltips are another one of those UI elements that aren't quite
keyboard-friendly. As usually this information is shown just as well
@ -250,7 +222,7 @@
(tooltip-mode -1)
#+END_SRC
** Cursor type
** Change cursor type
I prefer using a bar as a cursor, as opposed to a box. Using a bar
is a better way of representing the location of the cursor, in my
@ -260,18 +232,16 @@
(setq-default cursor-type 'bar)
#+END_SRC
** Cursors in inactive windows
I use a bar cursor that's already pretty thin, so having an even
thinner one in inactive windows is not very clear. Even when I
was using a box cursor I didn't like seeing a hollow box everywhere
my focus /wasn't/.
thinner one in inactive windows is not very clear. Even when I was
using a box cursor I didn't like seeing a hollow box everywhere my
focus /wasn't/.
#+BEGIN_SRC emacs-lisp
(setq-default cursor-in-non-selected-windows nil)
#+END_SRC
** Long lines
** Truncate long lines
Sometimes, very long lines can't help but show up in code. The
default of wrapping lines around to the next line and showing an
@ -282,7 +252,7 @@
(setq-default truncate-lines t)
#+END_SRC
** The default frame
** Change default frame settings
Usually, most of these settings would be done with functions like
=set-frame-font= or =scroll-bar-mode=, but working with the Emacs
@ -290,7 +260,7 @@
start a graphical environment at some point (I usually do
immediately), but the startup process isn't.
*** Internal border
*** Remove internal border
Set the internal border width to 0. This makes a small difference,
with my current setup it causes my window's width to increase from
@ -302,7 +272,7 @@
(internal-border-width . 0)
#+END_SRC
*** A fantastic font
*** Use a fantastic font
I've tried several fonts, and all of them were nice, but came up
short on some way. Some didn't have italic variants, some had
@ -329,7 +299,7 @@
(font . "Fantasque Sans Mono-13")
#+END_SRC
*** Scroll bar
*** Hide the scroll bar
The scroll-bar is almost just as informative as the current line
number and buffer position information shown in the (my) mode
@ -352,7 +322,7 @@
(vertical-scroll-bars . nil)
#+END_SRC
*** Setting the option
*** Bringing it all together
So I've explained the reasons for each individual setting, but to
get them to work they have to be put in the =default-frame-alist=.
@ -365,7 +335,7 @@
<<default-frame-scroll-bar>>))
#+END_SRC
** Frame title
** Set the frame title
Show the buffer name in the frame title to make multiple frames
identifiable by the buffer they're showing.
@ -435,316 +405,113 @@
(setq frame-resize-pixelwise t)
#+END_SRC
* Add org-mode appointments to the diary
** Don't just quit Emacs with {{{key(C-x C-c)}}} in the daemon
Diary offers reminders, which can be useful when scheduling
appointments.
#+BEGIN_SRC emacs-lisp
(defadvice org-agenda-redo (after ext:org-agenda-redo-add-appts)
"Pressing `r' on the agenda will also add appointments."
(setq appt-time-msg-list nil)
(org-agenda-to-appt))
#+END_SRC
* Close ansi-term buffer after exit
After the ansi-term process ends it leaves a buffer. I don't use
ansi term in such a way that this has ever been useful, so just kill
the ansi-term buffer after the process quits, no matter the exit
status. Usually this comes about when I press {{{kbd(C-d)}}} at the
command prompt.
#+BEGIN_SRC emacs-lisp
(defadvice term-handle-exit (after oni:kill-buffer-after-exit activate)
"Kill the term buffer if the process finished."
(kill-buffer (current-buffer)))
#+END_SRC
* Stumpwm integration
This variable, macro and function help with integrating Emacs and
Stumpwm. They are used by some other functions to make the two seem
extra connected.
#+BEGIN_SRC emacs-lisp
(defvar oni:stumpish-program
(expand-file-name
"~/.local/share/quicklisp/local-projects/stumpwm/contrib/util/stumpish/stumpish")
"The location of the stumpish executable.")
(defmacro oni:stumpwm (&rest body)
"Execute BODY in stumpwm."
(declare (indent 0))
`(call-process oni:stumpish-program nil nil nil
,(format "eval '%S'" `(progn ,@body))))
(defun oni:stumpwm-command (cmd)
"Execute CMD in stumpwm."
(call-process oni:stumpish-program nil nil nil cmd))
(defun oni:stumpwm-echo (message)
(call-process oni:stumpish-program nil nil nil (format "echo %s" message)))
#+END_SRC
** Fall back on stumpwm when moving around
Using the function specified in [[Stumpwm integration]] wrap the
=windmove-do-window-select= function and catch any error produced,
hoping it's the error that there's no more window to move to and
then request that stumpwm move the focus in the same direction as
windmove would have.
When working with Emacs as a daemon, which I do almost all of the
time, I prefer using {{{key(C-x C-c)}}} to close the current frame
instead of the entire session. Before this change I would
occasionally close my session by mistake.
#+BEGIN_SRC emacs-lisp
(defadvice windmove-do-window-select
(around oni:windmove-stumpwm activate)
"If no window can be moved to, move stumpwm."
(condition-case err
ad-do-it
(error (oni:stumpwm-command
(format "move-focus %s" (ad-get-arg 0))))))
(defun oni:close-client-window ()
"Close a client's frames."
(interactive)
(server-save-buffers-kill-terminal nil))
(when (daemonp)
(global-set-key (kbd "C-x C-c") 'oni:close-client-window))
#+END_SRC
* Don't just quit Emacs with {{{key(C-x C-c)}}} in the daemon
** Don't minimize the frame with {{{key(C-z)}}}
When working with Emacs as a daemon, which I do almost all of the
time, I prefer using {{{key(C-x C-c)}}} to close the current frame
instead of the entire session. Before this change I would
occasionally close my session by mistake.
One of the more annoying things that can happen is accidentally
minimizing the frame you're working with. This doesn't really matter
if you're working on a normal stacking window manager, but with a
tiling window manager and no task bar this just causes the Emacs
frame to hang until it is refocused or disappear with no way to get
it back.
#+BEGIN_SRC emacs-lisp
(defun oni:close-client-window ()
"Close a client's frames."
(interactive)
(server-save-buffers-kill-terminal nil))
#+BEGIN_SRC emacs-lisp
(when (or window-system (daemonp))
(global-unset-key (kbd "C-z")))
#+END_SRC
(when (daemonp)
(global-set-key (kbd "C-x C-c") 'oni:close-client-window))
#+END_SRC
** Lazily load some buffers
* Don't minimize the frame with {{{key(C-z)}}}
One of the more annoying things that can happen is accidentally
minimizing the frame you're working with. This doesn't really matter
if you're working on a normal stacking window manager, but with a
tiling window manager and no task bar this just causes the Emacs
frame to hang until it is refocused or disappear with no way to get
it back.
#+BEGIN_SRC emacs-lisp
(when (or window-system (daemonp))
(global-unset-key (kbd "C-z")))
#+END_SRC
* Use the right dictionary
One of the caveats of using two (or more) languages in a single
installation of Gnus is that ispell sometimes gets confused. Having
come across a stackoverflow question[fn:7] about just this subject
it was easy to modify the source code posted there to come up with
this.
*Note:* See my [[Function declarations][note]] on function declarations about the use of
=declare-function=.
#+BEGIN_SRC emacs-lisp
(declare-function message-narrow-to-headers-or-head "message")
(declare-function message-fetch-field "message")
(defun oni:switch-ispell-dictionary ()
(save-excursion
(message-narrow-to-headers-or-head)
(when (string-match (rx (and "@" (or "aethon" "picturefix") ".nl>") eol)
(message-fetch-field "From"))
(ispell-change-dictionary "nl_NL"))))
(add-hook 'message-setup-hook 'oni:switch-ispell-dictionary)
#+END_SRC
* Don't let shr use background color
Reading mail in Gnus is very nice, but shr has become a little too
good at its job. Add to this the many occasions when a background is
specified without specifying a foreground, plus a color theme that
is the inverse of what is usually expected, and you can get
hard-to-read HTML messages, gray foreground and gray background.
I've looked at the other possible renderers, but they don't look
very nice compared to shr. So just remove its ability to add
background colors.
*Note:* See my [[Function declarations][note]] on function declarations about the use of
=declare-function=.
#+BEGIN_SRC emacs-lisp
(declare-function shr-colorize-region "shr")
(defun oni:shr-colorize-remove-last-arg (args)
"If ARGS has more than 3 items, remove the last one."
(if (> (length args) 3)
(butlast args)
args))
(with-eval-after-load 'shr
(advice-add #'shr-colorize-region :filter-args
#'oni:shr-colorize-remove-last-arg))
#+END_SRC
* Optimized ~with-eval-after-load~
First offered [[http://www.lunaryorn.com/2013/05/01/byte-compiling-eval-after-load.html][here]] and then later updated [[http://www.lunaryorn.com/2013/06/25/introducing-with-eval-after-load.html][here]] (when
~with-eval-after-load~ was added). Makes for very nice on-demand
settings loading.
#+BEGIN_SRC emacs-lisp
;; http://www.lunaryorn.com/2013/06/25/introducing-with-eval-after-load/
(defmacro stante-after (feature &rest forms)
"After FEATURE is loaded, evaluate FORMS.
FEATURE may be an unquoted feature symbol or a file name, see
`eval-after-load'."
(declare (indent 1) (debug t))
`(,(if (or (not byte-compile-current-file)
(if (symbolp feature)
(require feature nil :noerror)
(load feature :no-message :no-error)))
`progn
(message "stante-after: cannot find %s" feature)
'with-no-warnings)
(with-eval-after-load ',feature ,@forms)))
#+END_SRC
* Remember SQL input
Remembering input between sessions is a good thing.
#+BEGIN_SRC emacs-lisp
(stante-after sql
(setf sql-input-ring-file-name
(expand-file-name "~/.emacs.d/sqliinput")))
#+END_SRC
* Lazily load some buffers
Don't load all buffers right away. Having a lot of buffers and
switching between projects a lot can take up quite a bit of time.
*Note:* See my [[Vacuous defvar][note]] on vacuous defvar for this use of =defvar=.
#+BEGIN_SRC emacs-lisp
(defvar desktop-restore-eager)
(setq desktop-restore-eager 5)
#+END_SRC
* Fix some term keybindings
=ansi-term= passes along a lot of characters correctly, but things
like =forward-delete-word= are not, by default. This is confusing when
you see one thing and another is sent. Passing the correct keys
directly to the terminal fixes this problem.
*Note:* See my [[Vacuous defvar][note]] on vacuous defvar for this use of =defvar=.
*Note:* See my [[Function declarations][note]] on function declarations about the use of
=declare-function=.
#+BEGIN_SRC emacs-lisp
(defvar term-raw-map)
(declare-function term-send-raw-string "term")
(defun oni:set-term-keys ()
(cl-flet ((zcommand (key)
(lambda ()
(interactive) (term-send-raw-string key))))
(define-key term-raw-map
(kbd "C-<backspace>") (zcommand "\C-H"))))
(add-hook 'term-mode-hook #'oni:set-term-keys)
#+END_SRC
* Ask for a ~y~ or ~n~, not ~yes~ or ~no~.
Emacs starts out asking for you to type ~yes~ or ~no~ with most
important questions. It is possible that this is used for such
important questions where accidentally saying ~yes~ when you meant ~no~
would be catastrophic (or at least could be). However, I've never
(so far) had this problem, and I find it quite tedious to have to
write out ~yes~ or ~no~ and then press {{{kbd(RET)}}}, give me a simple
~y~ or ~n~ with no {{{kdb(RET)}}} required and I'm quite happy.
#+BEGIN_SRC emacs-lisp
(defalias 'yes-or-no-p 'y-or-n-p)
#+END_SRC
* Use =hippie-expand=, not =dabbrev-expand=
I've never actually used =dabbrev-expand=, and only rarely use
=hippie-expand= really, but since =hippie-expand= also includes a
=dabbrev= expander and a lot more than just that, it seems alright to
do this.
#+BEGIN_SRC emacs-lisp
(defalias 'dabbrev-expand 'hippie-expand)
#+END_SRC
* Setting up =load-path=
First, to help, I create a function that takes a path, adds it to
=load-path= and then checks to see if there is a file named
~loaddefs.el~ in the given path. If there is, it loads it. This
~loaddefs.el~ file is something that is created from autoload cookies
in the files in some of these paths.
Since the =load-path= is also important during byte-compilation, this
function should be defined both at run-time and compile-time.
#+BEGIN_SRC emacs-lisp
(eval-and-compile
(defun oni:loadpath-add-and-autoload (path)
"Add PATH to `load-path' and load a `loaddefs.el' if it exists."
(add-to-list 'load-path path)
(let ((loaddefs (concat path "/loaddefs.el")))
(when (file-exists-p loaddefs)
(load loaddefs)))))
#+END_SRC
After that I add some directories to my =load-path= so I can use these
libraries when wanted. One of these is the ~site-lisp~ directory in my
~.emacs.d~ directory, which is where I keep most of my personal
non-ELPA modules (like module-specific initialization files). There
are also some directories I include in ~vendor-lisp~, which is where I
keep modules that I didn't write myself and, for some reason, can't
or don't want to use ELPA for. Again it is important to realize that
this information is relevant both at run-time and compile-time, so
we wrap it with an =eval-and-compile=.
#+BEGIN_SRC emacs-lisp
(eval-and-compile
(mapc #'oni:loadpath-add-and-autoload
'("~/.emacs.d/site-lisp"
"~/.emacs.d/vendor-lisp/mozrepl"
"~/.emacs.d/vendor-lisp/eap" "/usr/share/emacs/site-lisp"
"/usr/lib/node_modules/tern/emacs/"
"~/.emacs.d/vendor-lisp/habitrpg.el")))
#+END_SRC
* Some unconditional settings
Here are some settings that either need to be changed before certain
modules load, or that don't belong in any specific module.
** Gnus init file
I put my gnus initialization file right where I put all my
module-specific initialization files. Gnus is special, though: It
loads the file every time you start it. That keeps it from using a
simple =(eval-after-load 'gnus '(load "gnus-init"))=.
Don't load all buffers right away. Having a lot of buffers and
switching between projects a lot can take up quite a bit of time.
*Note:* See my [[Vacuous defvar][note]] on vacuous defvar for this use of =defvar=.
#+BEGIN_SRC emacs-lisp
(defvar gnus-init-file)
(setq gnus-init-file "~/.emacs.d/site-lisp/gnus-init")
(defvar desktop-restore-eager)
(setq desktop-restore-eager 5)
#+END_SRC
** Ask for a ~y~ or ~n~, not ~yes~ or ~no~.
Emacs starts out asking for you to type ~yes~ or ~no~ with most
important questions. It is possible that this is used for such
important questions where accidentally saying ~yes~ when you meant ~no~
would be catastrophic (or at least could be). However, I've never
(so far) had this problem, and I find it quite tedious to have to
write out ~yes~ or ~no~ and then press {{{kbd(RET)}}}, give me a simple
~y~ or ~n~ with no {{{kdb(RET)}}} required and I'm quite happy.
#+BEGIN_SRC emacs-lisp
(defalias 'yes-or-no-p 'y-or-n-p)
#+END_SRC
** Use =hippie-expand=, not =dabbrev-expand=
I've never actually used =dabbrev-expand=, and only rarely use
=hippie-expand= really, but since =hippie-expand= also includes a
=dabbrev= expander and a lot more than just that, it seems alright to
do this.
#+BEGIN_SRC emacs-lisp
(defalias 'dabbrev-expand 'hippie-expand)
#+END_SRC
** Setting up =load-path=
First, to help, I create a function that takes a path, adds it to
=load-path= and then checks to see if there is a file named
~loaddefs.el~ in the given path. If there is, it loads it. This
~loaddefs.el~ file is something that is created from autoload cookies
in the files in some of these paths.
Since the =load-path= is also important during byte-compilation, this
function should be defined both at run-time and compile-time.
#+BEGIN_SRC emacs-lisp
(eval-and-compile
(defun oni:loadpath-add-and-autoload (path)
"Add PATH to `load-path' and load a `loaddefs.el' if it exists."
(add-to-list 'load-path path)
(let ((loaddefs (concat path "/loaddefs.el")))
(when (file-exists-p loaddefs)
(load loaddefs)))))
#+END_SRC
After that I add some directories to my =load-path= so I can use these
libraries when wanted. One of these is the ~site-lisp~ directory in my
~.emacs.d~ directory, which is where I keep most of my personal
non-ELPA modules (like module-specific initialization files). There
are also some directories I include in ~vendor-lisp~, which is where I
keep modules that I didn't write myself and, for some reason, can't
or don't want to use ELPA for. Again it is important to realize that
this information is relevant both at run-time and compile-time, so
we wrap it with an =eval-and-compile=.
#+BEGIN_SRC emacs-lisp
(eval-and-compile
(mapc #'oni:loadpath-add-and-autoload
'("~/.emacs.d/site-lisp"
"~/.emacs.d/vendor-lisp/mozrepl"
"~/.emacs.d/vendor-lisp/eap" "/usr/share/emacs/site-lisp"
"/usr/lib/node_modules/tern/emacs/"
"~/.emacs.d/vendor-lisp/habitrpg.el")))
#+END_SRC
** Turn off bidirectional text
@ -802,6 +569,276 @@
(setq message-log-max 1000)
#+END_SRC
** Reject SSL/TLS certificates that don't check out
You just can't trust the internet. And I'd prefer to know if
something goes wrong.
#+BEGIN_SRC emacs-lisp
(defvar gnutls-verify-error)
(setq gnutls-verify-error t)
#+END_SRC
** Use Conkeror to browse URLs
Use the generic browse-url function to open URLs in Conkeror.
#+BEGIN_SRC emacs-lisp
(stante-after browse-url
(setq browse-url-browser-function 'browse-url-generic)
(setq browse-url-generic-program "conkeror"))
#+END_SRC
* Major mode customization
Many major modes offer and require some customization.
** Org mode
Org mode offers /a lot/ of customization options. Most of mine are in
a separate file.
*** Add org-mode appointments to the diary
Diary offers reminders, which can be useful when scheduling
appointments.
#+BEGIN_SRC emacs-lisp
(defadvice org-agenda-redo (after ext:org-agenda-redo-add-appts)
"Pressing `r' on the agenda will also add appointments."
(setq appt-time-msg-list nil)
(org-agenda-to-appt))
#+END_SRC
** Ansi term
I don't use ansi term much. Though I probably should do it more.
Eshell is much nicer for many reasons but it can't handle
everything.
*** Close ansi-term buffer after exit
After the ansi-term process ends it leaves a buffer. I don't use
ansi term in such a way that this has ever been useful, so just kill
the ansi-term buffer after the process quits, no matter the exit
status. Usually this comes about when I press {{{kbd(C-d)}}} at the
command prompt.
#+BEGIN_SRC emacs-lisp
(defadvice term-handle-exit (after oni:kill-buffer-after-exit activate)
"Kill the term buffer if the process finished."
(kill-buffer (current-buffer)))
#+END_SRC
* Some general-purpose functions and macros
A configuration as big as mine is bound to have some functions and
macros that are used in many places.
** Turn off
This macro creates a function that will turn off a minor mode that
passed to it.
#+BEGIN_SRC emacs-lisp
(defmacro turn-off (func)
"Create a function that will turn off FUNC when called."
`(lambda () (eval (,func -1))))
#+END_SRC
** Change setting
Sometimes a mode just needs to change a certain setting to a
specific value.
#+BEGIN_SRC emacs-lisp
(defmacro change-settings (&rest settings)
"Create a function that changes the value of NAME to VALUE."
`(lambda () (setq ,@settings)))
#+END_SRC
** Whitespace only with tabs
In some modes I want to see the tabs in a buffer. Though I don't
want to be overwhelmed by seeing all spaces and line endings.
#+BEGIN_SRC emacs-lisp
(defvar whitespace-style)
(defun oni:whitespace-only-tabs ()
(setq-local whitespace-style '(face tabs))
(whitespace-mode))
#+END_SRC
** Eval after init
Some things can only really work after all other initialization
functions have completed. For example, any functions that require
any ELPA packages to be loaded, unless you want to load it in your
init manually (and have it loaded again later on after your config
has run).
#+BEGIN_SRC emacs-lisp
(defmacro oni:eval-after-init (&rest body)
"Defer execution of BODY until after Emacs init."
(declare (indent 0))
`(add-hook 'emacs-startup-hook #'(lambda () ,@body)))
#+END_SRC
* Stumpwm integration
This variable, macro and function help with integrating Emacs and
Stumpwm. They are used by some other functions to make the two seem
extra connected.
#+BEGIN_SRC emacs-lisp
(defvar oni:stumpish-program
(expand-file-name
"~/.local/share/quicklisp/local-projects/stumpwm/contrib/util/stumpish/stumpish")
"The location of the stumpish executable.")
(defmacro oni:stumpwm (&rest body)
"Execute BODY in stumpwm."
(declare (indent 0))
`(call-process oni:stumpish-program nil nil nil
,(format "eval '%S'" `(progn ,@body))))
(defun oni:stumpwm-command (cmd)
"Execute CMD in stumpwm."
(call-process oni:stumpish-program nil nil nil cmd))
(defun oni:stumpwm-echo (message)
(call-process oni:stumpish-program nil nil nil (format "echo %s" message)))
#+END_SRC
** Fall back on stumpwm when moving around
Using the function specified in [[Stumpwm integration]] wrap the
=windmove-do-window-select= function and catch any error produced,
hoping it's the error that there's no more window to move to and
then request that stumpwm move the focus in the same direction as
windmove would have.
#+BEGIN_SRC emacs-lisp
(defadvice windmove-do-window-select
(around oni:windmove-stumpwm activate)
"If no window can be moved to, move stumpwm."
(condition-case err
ad-do-it
(error (oni:stumpwm-command
(format "move-focus %s" (ad-get-arg 0))))))
#+END_SRC
* Use the right dictionary
One of the caveats of using two (or more) languages in a single
installation of Gnus is that ispell sometimes gets confused. Having
come across a stackoverflow question[fn:7] about just this subject
it was easy to modify the source code posted there to come up with
this.
*Note:* See my [[Function declarations][note]] on function declarations about the use of
=declare-function=.
#+BEGIN_SRC emacs-lisp
(declare-function message-narrow-to-headers-or-head "message")
(declare-function message-fetch-field "message")
(defun oni:switch-ispell-dictionary ()
(save-excursion
(message-narrow-to-headers-or-head)
(when (string-match (rx (and "@" (or "aethon" "picturefix") ".nl>") eol)
(message-fetch-field "From"))
(ispell-change-dictionary "nl_NL"))))
(add-hook 'message-setup-hook 'oni:switch-ispell-dictionary)
#+END_SRC
* Don't let shr use background color
Reading mail in Gnus is very nice, but shr has become a little too
good at its job. Add to this the many occasions when a background is
specified without specifying a foreground, plus a color theme that
is the inverse of what is usually expected, and you can get
hard-to-read HTML messages, gray foreground and gray background.
I've looked at the other possible renderers, but they don't look
very nice compared to shr. So just remove its ability to add
background colors.
*Note:* See my [[Function declarations][note]] on function declarations about the use of
=declare-function=.
#+BEGIN_SRC emacs-lisp
(declare-function shr-colorize-region "shr")
(defun oni:shr-colorize-remove-last-arg (args)
"If ARGS has more than 3 items, remove the last one."
(if (> (length args) 3)
(butlast args)
args))
(with-eval-after-load 'shr
(advice-add #'shr-colorize-region :filter-args
#'oni:shr-colorize-remove-last-arg))
#+END_SRC
* Remember SQL input
Remembering input between sessions is a good thing.
#+BEGIN_SRC emacs-lisp
(stante-after sql
(setf sql-input-ring-file-name
(expand-file-name "~/.emacs.d/sqliinput")))
#+END_SRC
* Fix some term keybindings
=ansi-term= passes along a lot of characters correctly, but things
like =forward-delete-word= are not, by default. This is confusing when
you see one thing and another is sent. Passing the correct keys
directly to the terminal fixes this problem.
*Note:* See my [[Vacuous defvar][note]] on vacuous defvar for this use of =defvar=.
*Note:* See my [[Function declarations][note]] on function declarations about the use of
=declare-function=.
#+BEGIN_SRC emacs-lisp
(defvar term-raw-map)
(declare-function term-send-raw-string "term")
(defun oni:set-term-keys ()
(cl-flet ((zcommand (key)
(lambda ()
(interactive) (term-send-raw-string key))))
(define-key term-raw-map
(kbd "C-<backspace>") (zcommand "\C-H"))))
(add-hook 'term-mode-hook #'oni:set-term-keys)
#+END_SRC
* Some unconditional settings
Here are some settings that either need to be changed before certain
modules load, or that don't belong in any specific module.
** Gnus init file
I put my gnus initialization file right where I put all my
module-specific initialization files. Gnus is special, though: It
loads the file every time you start it. That keeps it from using a
simple =(eval-after-load 'gnus '(load "gnus-init"))=.
*Note:* See my [[Vacuous defvar][note]] on vacuous defvar for this use of =defvar=.
#+BEGIN_SRC emacs-lisp
(defvar gnus-init-file)
(setq gnus-init-file "~/.emacs.d/site-lisp/gnus-init")
#+END_SRC
** Don't start =elnode= when Emacs starts
Elnode is an awesome project and I'm still looking for a moment
@ -1093,17 +1130,6 @@
(setq electric-pair-skip-whitespace 'chomp)
#+END_SRC
* Reject SSL/TLS certificates that don't check out
You just can't trust the internet. And I'd prefer to know if
something goes wrong.
#+BEGIN_SRC emacs-lisp
(defvar gnutls-verify-error)
(setq gnutls-verify-error t)
#+END_SRC
* Programming
Emacs is a real programmer's editor, especially so because it's so
@ -1495,16 +1521,6 @@
<<flycheck-display>>)
#+END_SRC
* Use Conkeror to browse URLs
Use the generic browse-url function to open URLs in Conkeror.
#+BEGIN_SRC emacs-lisp
(stante-after browse-url
(setq browse-url-browser-function 'browse-url-generic)
(setq browse-url-generic-program "conkeror"))
#+END_SRC
* Magit
Recently Magit gained the annoying habit of producing a /huge/ warning
@ -1568,19 +1584,24 @@
<<magit-auto-revert-mode>>)
#+END_SRC
* Load custom file
* Final touches
I don't really use the Emacs customization interface much, but I
have used it as a kind-of persistent datastore, specifically for
desktop-registry[fn:9]. I do very much like the idea of it, it's a
very cool thing to have. I also use ~custom.el~ for storing some
things that I really can't store in a public viewing location like
this file or the git repository it lives in.
These options and calls need to come last so they don't interfere
with the rest of the initialization process, or get interfered with.
#+BEGIN_SRC emacs-lisp
(setq custom-file "~/.emacs.d/custom.el")
(load custom-file)
#+END_SRC
** Load custom file
I don't really use the Emacs customization interface much, but I
have used it as a kind-of persistent datastore, specifically for
desktop-registry[fn:9]. I do very much like the idea of it, it's a
very cool thing to have. I also use ~custom.el~ for storing some
things that I really can't store in a public viewing location like
this file or the git repository it lives in.
#+BEGIN_SRC emacs-lisp
(setq custom-file "~/.emacs.d/custom.el")
(load custom-file)
#+END_SRC
* Notes