= 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
*** Setup eww-lnum
#+BEGIN_SRC emacs-lisp :tangle no
(depends-on "eww-lnum")
#+END_SRC
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
** Scheme
I really like programming in Lisp. One of the more comfortable
Lisps is Scheme because most of the implementations I've worked
with are more like other compiled or interpreted languages, whereas
Common Lisp usually re-compiles on every load. Aside from that,
there are some neat programs written in some scheme dialects and of
course scsh is the most awesome shell scripting language ever
conceived.
*** 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
(stante-after geiser-impl
(setq geiser-default-implementation 'guile))
#+END_SRC
** SCSS
SCSS is a CSS preprocessor that makes writing CSS files much more
fun. Add autocompletion and some custom imenu function.
#+BEGIN_SRC emacs-lisp
(add-hook 'scss-mode-hook 'auto-complete-mode)
(add-hook 'scss-mode-hook 'scss-imenu-setup)
#+END_SRC
** Dired
Dired is an excellent file manager.
*** 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
** PHP
I occasionally write PHP for work. Not usually in my free time, but
there are some open source PHP projects that I sometimes tinker
with.
*** 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
** Web
Web mode is good for files that contain a lot of HTML, CSS and
JavaScript together. Most other major modes or multi-major modes
don't quite do it.
*** Turn off the fill column indicator
~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
*** Show tabs in indentation
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
*** Use tabs for indentation
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 Embedded Ruby HTML files
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
*** Use it for HTML-heavy PHP 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
** 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
** 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-repository-directories '("~/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
*** 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
** Circe
These settings will be tangled to =site-lisp/circe-init.el= and
loaded when Circe is loaded.
#+BEGIN_SRC emacs-lisp
(with-eval-after-load 'circe
(require 'circe-init))
#+END_SRC
#+INCLUDE: init-circe.org :minlevel 3
** Twig
Since twig is essentially a HTML template language, many tags must
be edited. Tagedit is good for restructuring existing tag
structures and adding single tags, whereas emmet mode is good when
you know more about the HTML hierarchy you're going to add.
#+BEGIN_SRC emacs-lisp
(add-hook 'twig-mode-hook 'tagedit-mode)
(add-hook 'twig-mode-hook 'emmet-mode)
#+END_SRC
Since Twig is a /template/ language, and thus not just HTML, electric
pairing is a blessing.
#+BEGIN_SRC emacs-lisp
(add-hook 'twig-mode-hook 'electric-pair-local-mode)
#+END_SRC
Both HTML and Twig mode aren't traditional text modes, so
=auto-fill-mode= doesn't make sense.
#+BEGIN_SRC emacs-lisp
(add-hook 'twig-mode-hook (turn-off auto-fill-mode))
#+END_SRC
* Minor mode customization
Many minor modes also offer a bit of customization possibilities.
** Robe
#+BEGIN_SRC emacs-lisp :tangle no
(depends-on "robe")
#+END_SRC
Robe is a Ruby completion and documentation lookup library.
*** Adding completions to autocomplete
To add Robe completions to autocomplete whenever robe is started,
I use the =robe-mode-hook= to enable this so that it doesn't try to
get any completions when robe isn't running.
#+BEGIN_SRC emacs-lisp
(add-hook 'robe-mode-hook #'ac-robe-setup)
#+END_SRC
** Eldoc
Seeing the arguments to a function whilst typing its name is
excellent.
*** 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
** Electric pair
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)
(add-hook 'sh-mode-hook #'electric-pair-local-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
** 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)
(add-hook 'sh-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
** 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
** Show a “beacon” when cursor position changes
#+BEGIN_SRC emacs-lisp :tangle no
(depends-on "beacon")
#+END_SRC
=beacon-mode= is a new minor mode that shows a temporary gradient
whenever the cursor screen position changes in a (somewhat)
unpredictable way. For example, when you switch buffers, when the
window scrolls because you’ve reached the top of the window, etc.
#+BEGIN_SRC emacs-lisp
(beacon-mode)
#+END_SRC
*** Don’t show a beacon everywhere
Beacon by default already doesn’t show in certain buffers with
certain major modes, currently only =magit-status-mode= disables the
beacon. I have some more that I’d like to add.
#+BEGIN_SRC emacs-lisp
(stante-after beacon
(setq beacon-dont-blink-major-modes
(append beacon-dont-blink-major-modes
'(circe-channel-mode
circe-server-mode
magit-diff-mode
gnus-summary-mode
gnus-group-mode))))
#+END_SRC
*** Show a beacon when recentering
Somehow I always get confused when I recenter my screen, is it in
the center, top or bottom? Beacon disables itself for the
recentering command, and I want it enabled, even though this is
completely predictable.
#+BEGIN_SRC emacs-lisp
(stante-after beacon
(setq beacon-dont-blink-commands
(delq 'recenter-top-bottom beacon-dont-blink-commands)))
#+END_SRC
** Hightlight numbers mode
I find this regular expression to work better at identifying
general numbers as the default one doesn't consider numbers
starting with a sign or a decimal point.
#+BEGIN_SRC emacs-lisp
(stante-after highlight-numbers
(setq highlight-numbers-generic-regexp
"\\_<[-+]?[[:digit:]]+\\(?:\.[[:digit:]]+\\)?.*?\\_>"))
#+END_SRC
* Final touches
These options and calls need to come last so they don't interfere
with the rest of the initialization process, or get interfered with.
** 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/