= HTML tags.
Luckily it's trivial to teach it. It does know about == HTML
tags, and basically I just want == tags to be treated almost as
== tags, so to do that we just have to define a =shr-tag-code=
function. I've copied the =shr-tag-pre= function and removed the calls
to =ensure-newline=, because == tags are inline tags.
In order to remain a little future-proof, it should only be done if
it doesn't already exist.
*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 shr-folding-mode)
(declare-function shr-indent "shr")
(declare-function shr-generic "shr")
(with-eval-after-load 'shr
(unless (fboundp 'shr-tag-code)
(defun shr-tag-code (cont)
(let ((shr-folding-mode 'none))
(shr-indent)
(shr-generic cont)))))
#+END_SRC
* Use scheme-mode for scsh interpreted files
Set the major mode for files interpreted by scsh (for example, by
having ~#!/usr/local/bin/scsh~ at the top) to use =scheme-mode=.
#+BEGIN_SRC emacs-lisp
(add-to-list 'interpreter-mode-alist '("scsh" . scheme-mode))
#+END_SRC
* Set default scheme implementation
Set the default implementation for geiser to guile so it doesn't ask
which implementation to use every time.
#+BEGIN_SRC emacs-lisp
(defvar geiser-default-implementation)
(with-eval-after-load 'geiser
(setq geiser-default-implementation 'guile))
#+END_SRC
* Setup eww-lnum
As recommended in the [[https://github.com/m00natic/eww-lnum][README]], set the keys in the =eww-mode-map=.
#+BEGIN_SRC emacs-lisp
(defvar eww-mode-map)
(with-eval-after-load 'eww
(define-key eww-mode-map "f" 'eww-lnum-follow)
(define-key eww-mode-map "F" 'eww-lnum-universal))
#+END_SRC
* Don't compile scss files
By default =scss-mode= tries compiling a file each time it's saved. I
don't have SCSS properly installed globally so this always fails,
highly annoying.
#+BEGIN_SRC emacs-lisp
(defvar scss-compile-at-save)
(with-eval-after-load 'scss-mode
(setq scss-compile-at-save nil))
#+END_SRC
* Change listings in dired
The number of bytes a file is doesn't usually tell me much when it's
something like ~292837~. I prefer seeing just how many Kb or Mb a
certain file is. I also don't need to see the ~.~ and ~..~ directories
when I insert directories into the current dired buffer, as there is
a great chance that the current and parent directory are already
shown in the buffer.
#+BEGIN_SRC emacs-lisp
(defvar dired-subdir-switches)
(with-eval-after-load 'dired
(setq dired-listing-switches "-alh"
dired-subdir-switches "-Alh"))
#+END_SRC
* Useful functions
During your editing in Emacs you will undoubtedly find the need to
define your own editing functions or macros. Here are mine.
** Delete the contents of the string at point
First we define the function. It was inspired by [[http://www.masteringemacs.org/][Mickey's post on
swapping quote symbols]], mostly copied even. First we check if we
are even in a string, and if not we throw an error, after that we
move back to the beginning of the string, store that point, go to
the end of the string (using =forward-sexp=) and then delete the
region between the two points (non-inclusive).
#+BEGIN_SRC emacs-lisp
(defun oni:delete-string-contents ()
(interactive)
(unless (nth 3 (syntax-ppss))
(error "You must be in a string for this command to work"))
(save-excursion
(while (nth 3 (syntax-ppss)) (forward-char -1))
(let ((bos (point)))
(forward-sexp)
(delete-region (1+ bos) (1- (point))))))
#+END_SRC
Since for interactive functions it's kind of a pain to have to use
a personal "namespace" I prefer naming them regularly as if they're
just part of the environment. If ever Emacs comes up with a similar
function with the same name, I'd prefer using the built-in version.
#+BEGIN_SRC emacs-lisp
(unless (fboundp 'delete-string-contents)
(defalias 'delete-string-contents 'oni:delete-string-contents))
#+END_SRC
Lastly, any function worth using often should probably be easily
accessible with a keybinding. In my case the {{{key(C-c i s)}}} is
inspired by the Vim keybindings like {{{key(ci")}}}.
#+BEGIN_SRC emacs-lisp
(global-set-key (kbd "C-c i s") 'delete-string-contents)
#+END_SRC
* Show eldoc when evaluating expressions
Thanks to [[http://endlessparentheses.com/sweet-new-features-in-24-4.html][this post]] it was brought to my attention that eldoc mode
can be enabled when evaluating expressions using {{{key(M-:)}}}.
I vaguely remember having had this before, I just don't know how or
why it stopped working.
#+BEGIN_SRC emacs-lisp
(add-hook 'eval-expression-minibuffer-setup-hook #'eldoc-mode)
#+END_SRC
* Remove whitespace when closing delimiters
In =electric-pair-mode=, skip over and delete white space if it stands
between the cursor and the closing delimiter.
#+BEGIN_SRC emacs-lisp
(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
programmable itself. It also offers modes for a lot of programming
languages and 3rd-party packages offer even more.
** SCSS
- Enable auto-completion
#+BEGIN_SRC emacs-lisp
(declare-function auto-complete-mode "auto-complete")
(add-hook 'scss-mode-hook #'auto-complete-mode)
#+END_SRC
- Enable imenu
#+BEGIN_SRC emacs-lisp
(declare-function scss-imenu-setup "scss-imenu")
(add-hook 'scss-mode-hook #'scss-imenu-setup)
#+END_SRC
** PHP
*** Show tabs and spaces in indent
I'm working with some WordPress plugins nowadays and their style
guide insists on using tabs, not spaces... I'd like to know that
I'm following this rule.
#+BEGIN_SRC emacs-lisp
(add-hook 'php-mode-hook #'oni:whitespace-only-tabs)
#+END_SRC
*** Use web-mode for HTML-heavy files
I have to work with a lot of PHP and HTML interspersed. This makes
a difficult case since ~php-mode~ very deliberately doesn't support
that very well. On the other hand I really don't like ~web-mode~ for
PHP /without/ any HTML in it. So I decided to name the files that
contain mostly HTML with some PHP ~.html.php~ and have them load
~web-mode~ instead of ~php-mode~, whilst keeping the association for
plain ~.php~ files as it is.
Something tricky about doing this is that if this setting gets
evaluated /before/ ~php-mode~ is loaded it'll be further down the list
from ~php-mode~'s definition. This would cause the ~php-mode~ auto
mode definition from being accepted first (since ~.html.php~ also
matches ~.php~) and consequently render this definition useless.
#+BEGIN_SRC emacs-lisp
(oni:eval-after-init
(add-to-list 'auto-mode-alist '("\\.html\\.php$" . web-mode)))
#+END_SRC
** Web
~web-mode~ has some quirks, such as not being able to handle the
fact that ~fci-mode~ puts a red line at the 80-column margin. This is
annoying to say the least.
#+BEGIN_SRC emacs-lisp
(declare-function fci-mode "fci-mode")
(add-hook 'web-mode-hook (turn-off fci-mode))
#+END_SRC
Just like in ~php-mode~ I want to see the tabs.
#+BEGIN_SRC emacs-lisp
(add-hook 'web-mode-hook #'oni:whitespace-only-tabs)
#+END_SRC
Set =indent-tabs-mode= for ~web-mode~ as well.
#+BEGIN_SRC emacs-lisp
(defvar web-mode-code-indent-offset)
(defvar web-mode-markup-indent-offset)
(add-hook 'web-mode-hook
(change-settings indent-tabs-mode t
web-mode-code-indent-offset 4
web-mode-markup-indent-offset 4))
#+END_SRC
Use it for ~.html.erb~ files.
#+BEGIN_SRC emacs-lisp
(oni:eval-after-init
(add-to-list 'auto-mode-alist '("\\.html\\.erb$" . web-mode)))
#+END_SRC
** PO mode
Autoload =po-mode=, because it didn't come with an autloads file or
cookie.
#+BEGIN_SRC emacs-lisp
(autoload 'po-mode "po-mode" nil t)
#+END_SRC
Automatically enable =po-mode= for files that end in =.po= or that have
a =.po= extension followed by others (such as =.po.erb=).
#+BEGIN_SRC emacs-lisp
(add-to-list 'auto-mode-alist '("\\.po\\'\\|\\.po\\." . po-mode))
#+END_SRC
* Minor modes
Emacs offers a lot of minor modes and even more can be found in the
ELPA, MELPA and Marmalade repositories. These offer a lot of
customization possibilities and added features.
** Electric indent
Automatically indenting code upon typing certain characters can be
very useful for certain modes where the indentation level can
easily be determined. One of the first things I liked about Emacs
was the way the {{{key(TAB)}}} key worked: It indents to the
"proper" level of indentation, instead of adding a tab character.
It quickly grew into a habit to press tab several times when
editing a line or a block of code. Electric indent is just an
extension of this that, for the most part, allows me to forget
about pressing tab.
It doesn't fit all modes though. When I worked in Python a lot I
was fighting the electric indent a lot more than it was helping me.
This is because instead of scope influencing indentation as in most
languages I've worked with, indentation determines scope in Python,
as anyone who's looked at it for more than a minute or two will
know. This means that any line can usually have several "proper"
indentation levels, depending on the meaning of meaning of that
line.
So, almost all modes use =electric-indent-local-mode=, but a few
don't. So I'm also very happy that recently this mode was added,
because =electric-indent-mode= is a global minor mode and I only want
to use it in some 99% of the available modes.
#+BEGIN_SRC emacs-lisp
(add-hook 'css-mode-hook #'electric-indent-local-mode)
(add-hook 'js2-mode-hook #'electric-indent-local-mode)
(add-hook 'php-mode-hook #'electric-indent-local-mode)
(add-hook 'ruby-mode-hook #'electric-indent-local-mode)
(add-hook 'scss-mode-hook #'electric-indent-local-mode)
#+END_SRC
*** Switch keys back
When =electric-indent-mode= is enabled the default function bound to
{{{key(C-j)}}} (=electric-newline-and-maybe-indent=) stops indenting
after adding a newline, whilst {{{key(RET)}}} starts doing it.
Since I use {{{key(C-j)}}} almost exclusively and don't use
{{{key(RET)}}} at all, it's really not useful to me. So I want to
switch the two when =electric-indent-mode= is enabled.
This is very simple. First I define a simple function that checks
if the =electric-indent-mode= variable is set (which it should be if
the mode is turned on) and if so I set the proper keys /locally/. If
=electric-indent-mode= is /not/ set, which happens when the mode is
turned off, I remove the local keybindings.
#+BEGIN_SRC emacs-lisp
(defun oni:switch-newline-keys ()
"Switch the `C-j' and `RET' keys in the local buffer."
(if electric-indent-mode
(progn
(local-set-key (kbd "C-j") 'newline)
(local-set-key (kbd "RET") 'electric-newline-and-maybe-indent))
(local-unset-key (kbd "C-j"))
(local-unset-key (kbd "RET"))))
#+END_SRC
And then I add it to the electric indent mode's hook.
#+BEGIN_SRC emacs-lisp
(add-hook 'electric-indent-local-mode-hook #'oni:switch-newline-keys)
#+END_SRC
** Electric pairing
Electric pairing of delimiters is one of those features that is
just so essential to my feeling comfortable with an editor. Most of
the time I don't even use it, really. It's just that I'm so used to
having it and when I /do/ expect it to be there it is so frustrating
when it's not, or when it doesn't work properly.
This functionality, much like [[Electric indent]] isn't something I
want enabled in all modes, though for different reasons, and for a
time there was only the global =electric-pair-mode=. Again I'm very
happy that a local version was added.
The reason that I don't want it enabled for all modes is that some
modes (mostly Lisp-like language modes) have better alternatives.
But most non-Lisp-like language modes I really do need to have it.
#+BEGIN_SRC emacs-lisp
(add-hook 'c-mode-hook #'electric-pair-local-mode)
(add-hook 'coffee-mode-hook #'electric-pair-local-mode)
(add-hook 'css-mode-hook #'electric-pair-local-mode)
(add-hook 'haml-mode-hook #'electric-pair-local-mode)
(add-hook 'java-mode-hook #'electric-pair-local-mode)
(add-hook 'js2-mode-hook #'electric-pair-local-mode)
(add-hook 'lua-mode-hook #'electric-pair-local-mode)
(add-hook 'python-mode-hook #'electric-pair-local-mode)
(add-hook 'ruby-mode-hook #'electric-pair-local-mode)
(add-hook 'scss-mode-hook #'electric-pair-local-mode)
#+END_SRC
** Auto completion
#+BEGIN_SRC emacs-lisp :tangle no
(depends-on "auto-complete")
#+END_SRC
I'm not a great fan of any type of auto completion functionality in
programming. I think it's basically only good for getting really
long names in your file faster. I started programming in C#, in
Visual Studio, and they have their very powerful Intellisense
mechanism, which I used a lot. What I noticed though was that it
was keeping me from learning the APIs. Whenever I wrote some code,
all but the most basic and most-used calls I wrote from memory.
Many others were done after a few seconds of browsing through the
Intellisense pop-up.
Because of this, I disable the normal auto-complete pop-up.
#+NAME: auto-complete-dont-show
#+BEGIN_SRC emacs-lisp :tangle no
(setq ac-auto-show-menu nil)
#+END_SRC
On the rare occasion that I do call up the pop-up to see what the
completions I have available to me are, I don't want it to show the
quick help. The quick help usually shows up as a big extra pop-up
next to the completion list and it gets very messy when combined
with some other modes that add overlays to the buffer.
#+NAME: auto-complete-no-quickhelp
#+BEGIN_SRC emacs-lisp :tangle no
(setq ac-use-quick-help nil)
#+END_SRC
To keep the byte-compiler from complaining about undefined
variables, I only want this to be done after =auto-complete= is
loaded, not sooner.
#+BEGIN_SRC emacs-lisp :noweb yes
(stante-after auto-complete
<>
<>)
#+END_SRC
** Highlight indentation
#+BEGIN_SRC emacs-lisp :tangle no
(depends-on "hl-indent")
#+END_SRC
Some languages base their ideas of scope on levels of indentation.
When these languages get long functions/branches it can get tricky
to see where these blocks end. Of course if you have such large
functions you might have other problems, but this is sometimes out
of your hands. To help, I use =hl-indent-mode=.
For other languages it might look fun for a little while as well,
but since they don't care about indentation as much it can
sometimes get messy.
First, =hl-indent-mode= doesn't have an =;;;###autoload= cookie for its
main entry-point, so I add it manually:
#+BEGIN_SRC emacs-lisp
(autoload 'hl-indent-mode "hl-indent" nil t)
#+END_SRC
Then I enable it for the languages I want.
#+BEGIN_SRC emacs-lisp
(add-hook 'python-mode-hook #'hl-indent-mode)
(add-hook 'yaml-mode-hook #'hl-indent-mode)
(add-hook 'haml-mode-hook #'hl-indent-mode)
#+END_SRC
** Django helper
:PROPERTIES:
:ORDERED: t
:END:
#+BEGIN_SRC emacs-lisp :tangle no
(depends-on "pony-mode")
#+END_SRC
Autoload =pony-mode= because it doesn't come with an autoload cookie.
#+BEGIN_SRC emacs-lisp
(autoload 'pony-mode "pony-mode" nil t)
#+END_SRC
Turn on =compilation-shell-minor-mode= when =pony-mode= is enabled.
#+BEGIN_SRC emacs-lisp
(defun oni:turn-on-compilation-shell-for-pony ()
"Turn on option `compilation-shell-minor-mode' for `pony-minor-mode'."
(add-hook 'pony-minor-mode-hook 'compilation-shell-minor-mode nil t))
(add-hook 'comint-mode-hook #'oni:turn-on-compilation-shell-for-pony)
#+END_SRC
** Automatic syntax checking on-the-fly
#+BEGIN_SRC emacs-lisp :tangle no
(depends-on "flycheck")
(depends-on "flycheck-cask")
(depends-on "flycheck-commit-check" :git "git://github.com/ryuslash/flycheck-commit-check.git")
#+END_SRC
Flycheck provides awesome syntax checkers for many languages.
Enable it for the languages I use.
#+BEGIN_SRC emacs-lisp
(add-hook 'haml-mode-hook 'flycheck-mode)
(add-hook 'emacs-lisp-mode-hook 'flycheck-mode)
(add-hook 'git-commit-mode-hook 'flycheck-mode)
(add-hook 'go-mode-hook 'flycheck-mode)
(add-hook 'html-mode-hook 'flycheck-mode)
(add-hook 'js2-mode-hook 'flycheck-mode)
(add-hook 'lua-mode-hook 'flycheck-mode)
(add-hook 'perl-mode-hook 'flycheck-mode)
(add-hook 'php-mode-hook 'flycheck-mode)
(add-hook 'python-mode-hook 'flycheck-mode)
(add-hook 'rst-mode-hook 'flycheck-mode)
(add-hook 'ruby-mode-hook 'flycheck-mode)
(add-hook 'rust-mode-hook 'flycheck-mode)
(add-hook 'sh-mode-hook 'flycheck-mode)
(add-hook 'texinfo-mode-hook 'flycheck-mode)
#+END_SRC
Whenever flycheck is started, try using it with Cask.
#+BEGIN_SRC emacs-lisp
(add-hook 'flycheck-mode-hook 'flycheck-cask-setup)
#+END_SRC
Load my own git commit checker.
#+NAME: flycheck-commit-checker
#+BEGIN_SRC emacs-lisp :tangle no
(require 'flycheck-commit-check)
#+END_SRC
Disable certain checkers.
#+NAME: flycheck-delete-checkers
#+BEGIN_SRC emacs-lisp :tangle no
(mapc (lambda (c) (delq c flycheck-checkers))
'(python-pylint python-pyflakes))
#+END_SRC
Set the highlighting mode to columns so I can see (if possible)
where errors/warnings belong.
#+NAME: flycheck-columns
#+BEGIN_SRC emacs-lisp :tangle no
(setq flycheck-highlighting-mode 'columns)
#+END_SRC
Try not to display the errors. A jumpy echo area makes me nervous
and {{{key(C-c ! l)}}} is a nicer way to look at it usually. It
still doesn't keep it from being displayed, only when nothing else
is displayed though.
#+NAME: flycheck-display
#+BEGIN_SRC emacs-lisp :tangle no
(setq flycheck-display-errors-function (lambda (_) nil))
#+END_SRC
Do most of these things after flycheck is loaded.
#+BEGIN_SRC emacs-lisp :noweb yes
(stante-after flycheck
<>
<>
<>
<>)
#+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
message whenever you don't tell it that you've already seen it. To
tell it you've already seen the message you need to specify the
following.
#+BEGIN_SRC emacs-lisp
(eval-and-compile
(defvar magit-last-seen-setup-instructions "1.4.0"))
#+END_SRC
I use a =defvar= here in order to keep the byte-compiler from
complaining about an undefined variable. It needs to be specified
before magit is loaded otherwise magit will keep complaining.
** Project directory
I keep all my projects in =~/projects/=, so Magit shouldn't have to
look anywhere else.
#+NAME: magit-repo-dirs
#+BEGIN_SRC emacs-lisp :tangle no
(setq magit-repo-dirs '("~/projects/"))
#+END_SRC
** Show fine differences
I like to see all the little differences in diffs that I can. They
really help reading diffs. I also just want to see them on all
diffs and not the selected one, which would make an unnecessary
amount of navigation required to properly read the diffs.
#+NAME: magit-diff-refine-hunk
#+BEGIN_SRC emacs-lisp :tangle no
(setq magit-diff-refine-hunk 'all)
#+END_SRC
** Don't revert all the buffers
I'd never noticed it much before, but lately magit's habit of
reverting all the buffers after almost every action I perform has
become disturbingly slow. I personally don't rely on that
functionality being either off or on, so turning it off shouldn't
bother me too much.
#+NAME: magit-auto-revert-mode
#+BEGIN_SRC emacs-lisp :tangle no
(setq magit-auto-revert-mode nil)
#+END_SRC
** Delay setting
The settings in the previous sections should only be set after
Magit has loaded.
#+BEGIN_SRC emacs-lisp :noweb yes
(stante-after magit
<>
<>
<>)
#+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
Here are some random or somewhat general notes about things you may
run into when looking through my Emacs init.
** Vacuous defvar
A =defvar= without a value like =(defvar some-variable)= tells the
byte-compiler that the variable will appear, but doesn't give it a
value. It should only count for the file where it is used and once
the file with the /actual/ =defvar= is loaded it will be populated with
its value, contrary to what would happen if you'd given it a value
before loading its original file.
** Function declarations
The function =declare-function= tells the byte-compiler where to find
a certain function. This keeps the byte-compiler from complaining
about certain functions possibly not being defined at run-time.
* Footnotes
[fn:1] This runs =tmm-menubar=, which lets you navigate the menubar in a
text-driven way. I don't ever use it because I know what all my
favorite functions are called, but it seems a great deal more
efficient than having to click on everything.
[fn:2] https://github.com/sabof/svg-mode-line-themes
[fn:3] It works fine for me with something like jabber chats and the
like.
[fn:4] I like to program in Lisp, parentheses are important to me!
Parentheses should be nice and round, not almost like bars!
[fn:5] https://github.com/belluzj/fantasque-sans
[fn:6] Used to be Cosmic Sans Neue Mono, the name changed because
people misread it as "Comic" (me included, which was the original
reason I checked it out, for laughs) and hate Comic Sans, and also
because there was already a Cosmic Sans font as well, which could
cause confusion.
[fn:7] http://stackoverflow.com/questions/22175214/automatically-switch-language-in-gnus-depending-on-recipient
[fn:8] I still use 2 spaces for some languages, like HTML.
[fn:9] http://code.ryuslash.org/desktop-registry/about/