summaryrefslogtreecommitdiffstats
path: root/.emacs.d/init.org
blob: 7d13d878eef816e58a6833070546e2187f3c8a7b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
#+TITLE:
#+PROPERTY: tangle init2.el
#+STARTUP: showall
#+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">

* About this file

  Inspired by such other projects as the literal Emacs init from [[http://sachac.github.io/.emacs.d/Sacha.html][Sacha
  Chua]] and also from [[http://www.wisdomandwonder.com/wordpress/wp-content/uploads/2014/03/C3F.html][Grant Rettke]], here is my Emacs initialization
  file.

  *Note:* This is not my entire Emacs initialization file. It's a
  work-in-progress. To keep on top of any changes to this file, or any
  other part of my Emacs init, I recommend you follow [[http://code.ryuslash.org/dot/tom/emacs/][This project]]
  ([[http://code.ryuslash.org/dot/tom/emacs/atom/?h=master][Atom feed]]), which is where I keep my configuration.

** Preparation

   I could use org-babel to load this file, but I don't like my
   initialization file being dependent on too many things, especially
   big things, and org is a big thing. It may be strange for you to
   read this, as I have placed my entire Emacs configuration in an
   org-mode file, but here are the make targets I use to tangle and
   subsequently byte-compile my init file:

   #+BEGIN_SRC makefile :tangle no
     %.elc: %.el
         emacs -Q -batch -eval "(byte-compile-file \"$<\")"

     init.el: init.org
         emacs -Q -batch -l "ob-tangle" -eval "(org-babel-tangle-file \"init.org\")
   #+END_SRC

   Executing the second target (either through make, or manually) will
   get you my Emacs initialization file in plain Emacs Lisp.

   *Note:* If you look at this file in it's org-mode form you will
   notice that I actually tangle ~init.org~ into ~init2.el~. This is a
   temporary measure so that I can gradually move my configuration
   from my existing ~init.el~ file into ~init.org~ without much trouble.
   Once I've emptied out my ~init.el~ I will instruct babel to tangle
   into ~init.el~, this code already reflects that.

* Use lexical binding

  For some of these functions, and general coolness, lexical binding
  is a must. Without it, closures cannot be made.

  #+BEGIN_SRC emacs-lisp :padline no
    ;; -*- lexical-binding: t -*-
  #+END_SRC

* Remove 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

   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
   more easily navigate, but {{{key(M-x)}}} or {{{key(M-`)}}}[fn:1]
   are easier if you don't use the mouse. Long story short: It has got
   to go.

   #+BEGIN_SRC emacs-lisp
     (menu-bar-mode -1)
   #+END_SRC

** 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
   going to click them they don't really server much of a purpose.
   Again: It has got to go.

   #+BEGIN_SRC emacs-lisp
     (tool-bar-mode -1)
   #+END_SRC

** Scroll bar

   The scroll-bar is almost just as informative as the current line
   number and buffer position information shown in the (my) mode line.
   As I don't usually need to know where I am, other than the current
   line number occasionally, and I don't use the mouse, the scroll bar
   doesn't add anything and only takes up space. Once more: It has got
   to go.

   #+BEGIN_SRC emacs-lisp
     (scroll-bar-mode -1)
   #+END_SRC

** 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.

   I've noticed that I don't really lose my cursor position all that
   much, really, so there doesn't seem to be any point in making it
   blink. Here we go again: It has got to go.

   #+BEGIN_SRC emacs-lisp
     (blink-cursor-mode -1)
   #+END_SRC

** Column and 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
   don't often need to know what line I'm on.

   #+BEGIN_SRC emacs-lisp
     (column-number-mode -1)
     (line-number-mode -1)
   #+END_SRC

** Tooltips

   Tooltips are another one of those UI elements that aren't quite
   keyboard-friendly. As usually this information is shown just as well
   in the echo area, this is not necessary.

   #+BEGIN_SRC emacs-lisp
     (tooltip-mode -1)
   #+END_SRC

* 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

* 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.

   #+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

* Don't just quit Emacs with {{{key(C-x C-c)}}} in the daemon

  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
    (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 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:3] 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)
        (let ((from (message-fetch-field "From")))
          (ispell-change-dictionary
           (if (string-match (rx "@aethon.nl>" eol) from) "nl" "en")))))

    (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/org/lisp"
              "~/.emacs.d/vendor-lisp/org/contrib/lisp"
              "~/.emacs.d/vendor-lisp/mozrepl"
              "~/.emacs.d/vendor-lisp/eap" "/usr/share/emacs/site-lisp"
              "/usr/lib/node_modules/tern/emacs/")))
  #+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

** Turn off bidirectional text

   To speed things up a little, and because I have no contacts at all
   (so far) who use right-to-left text, there is no reason for me to
   use bidirectional text. For this reason I tell Emacs to always use
   left-to-right by default, instead of checking each paragraph.

   #+BEGIN_SRC emacs-lisp
     (setq-default bidi-paragraph-direction 'left-to-right)
   #+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] http://stackoverflow.com/questions/22175214/automatically-switch-language-in-gnus-depending-on-recipient