I have been a long-time vim user, and started using Emacs because of the awesome org-mode feature, it provides. Definitely, I have been impressed. People were right for once! I have, only, been using Emacs for a couple of weeks, and I’m already in love with it, primarily, because:
- it has the neatest organizer in this world: the
org-mode
. - it uses
elisp
to pragmatically change itself.
So, soon I was dwelling inside the dark world of getting my new editor resonate with myself. I tried several starter packages, viz.:
And, I really enjoyed my couple of days of flirting with these kits, and they were really nice, but somehow, they did not represent me.
My editor felt like someone else’ baby in my hands - it was adorable, and cute and what not, but it wasn’t mine. :)
So, I started working on my own take at Emacs’ configuration, finally, and proudly, called it: Emacs’ Preamble - made it, remade it, and remade it again and again and each time, I switched the way it represented itself. I had already seen Sacha Chua’s Emacs Configuration, and wanted my own to be based upon org-babel, as well.
org-babel
is awesome. It empowers Org-mode to execute source code within Org-mode documents. It
is built upon the principles of Literate Programming, and can embed multiple languages within a
single document.
Extending upon the same, the current Org-mode file documents my configuration for Emacs, sanely
named as Emacs’ Preamble. The source code inside elisp
source blocks is tangled by Babel, and
is then loaded as configuration via org-babel-load-file
function. We make sure that only
emacs-lisp
based code is tangled by org-mode
, as follows:
(org-babel-tangle-file "preamble.org" "output/preamble.el" "emacs-lisp")
Emacs’ Preamble exists in a repository on Github, and can be read there, as Github easily converts
org-mode
documents in a readable format. However, I have created a dedicated section on my
website, where the documentation (i.e. this file, itself) can be read in a much prettier format.
This configuration for Emacs, i.e. Emacs’ Preamble is heavily inspired form (in order):
Copyright (C) 2013 Nikhil Gupta <me@nikhgupta.com> Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. Code in this document is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
This document http://doc.nikhgupta.com/emacs-preamble.html which describes my current Emacs configuration (either in its HTML format or in its Org format) is licensed under the GNU Free Documentation License version 1.3 or later (http://www.gnu.org/copyleft/fdl.html).
The code examples and CSS stylesheets are licensed under the GNU General Public License v3 or later (http://www.gnu.org/licenses/gpl.html).
I am really unsure about the requirements, but I’m using this configuration in Mac OSX 10.8.2 (Mountain Lion), GNU Emacs 24.1.1, and org-mode v8.2.
Emacs’ Preamble was designed on
Emacs v24.1.1
, and therefore, I am sure that it will perform, as intended, on Emacs v24+. Older versions of Emacs might not work properly.
I tried to make sure that Emacs’ Preamble can be installed in as minimum steps, as possible. At
the moment, you can simply clone the Github repository on your computer and link ~/.emacs.d
to
that directory, e.g.:
git clone http://github.com/nikhgupta/preamble ~/Code/github/emacs-preamble
ln -nfs ~/Code/github/emacs-preamble ~/.emacs.d
That’s it. Now, I’ll fire my emacs
to install the dependencies and packages. I’ll sit back for a
while, and maybe, a coffee will do me just good, at the moment.
It all started with a big-bang! (in this case, a meager init.el
file)
Oh, yes! Did I mention? I’m a great fan of The Big Bang Theory.
The above file, basically, checks to see whether the Org-mode version is above 8.0
. If not, it
upgrades Org-mode by installing it via Emacs’ Package Manager, and then tangles and loads elisp
source codes inside the current file by using org-babel-load-file
function.
At the moment, I leave the Emacs Server running on my machine, when it boots up (I, later, plan to
run it on my VPS, and connect remotely), and use the emacsclient
commands to connect to it. This
way, this configuration is loaded/tangled only once, providing super-fast experience for my
use-cases.
;;; preamble.el --- Emacs' Preamble
;; Author : Nikhil Gupta
;; Email : me@nikhgupta.com
;;; Commentary:
;; -----------------------------------------
;; Do not edit the generated file, as it has
;; been generated, as a tangled file, by the
;; stupendous org-mode.
;;
;; Make the changes in the corresponding
;; preamble.org file, instead.
;; -----------------------------------------
;;; Code:
Since, this configuration uses features that are new to Emacs v24
, and since I don’t have time
enough to work out a compatible configuration for older version of Emacs, display a friendly
warning, if the Emacs version is below v24
.
(when (version< emacs-version "24")
(warn "Only Emacs version 24 and up are supported."))
When working with such a configuration as this one, I often tend to pull my hair out.. This section helps me track down possible causes of such erratic behavior of mine and be more insane, instead. Also, I hate those pesky plugins which make my Emacs’ Preamble configuration far too slow. This section, further, helps me benchmark my configuration for the exact same purpose.
The settings of this section are turned on or off via the following variable:
(setq debug-on-error 'nil) ; set to 't to enable debugging messages
Since, this is one huge file, it is often hard to debug where a particular error has occurred, and
therefore, I need some visual clue of some type, a.k.a. checkpoints
. The following functions,
together, help me with that. I can, simply, make a call to the preamble/checkpoint
function, in
order to echo something inside my *Messages*
buffer, and immediately, know nearby location of
where Emacs has stopped loading this configuration. Not to mention, these checkpoints, further, help
me by acting as indirect comments.
;; subtract two time entities
(defun preamble/time-subtract-millis (b a)
"Function that can subtract time string A from time string B."
(* 1000.0 (float-time (time-subtract b a))))
;; convenient function to measure load-time since initialization
(defun preamble/load-time()
"Return total load-time from the initialization."
(preamble/time-subtract-millis (current-time) before-init-time))
;; function to display which section is being loaded..
(defun preamble/checkpoint (msg)
"Echo MSG to *Messages*, thereby, making it act as a checkpoint."
(if debug-on-error (message "- At =%.2fms=, I %s.." (preamble/load-time) msg)))
;; an example of above
(preamble/checkpoint "initialized benchmarking")
Moreover, since, I am a quantified-geek, I love to measure various things. Why not measure time taken by our Emacs configuration, as well?
This section, also, enables me to measure the time taken by various features in requiring them, as
well as total time taken by the Emacs to load this configuration. When Emacs load this
configuration, it displays which features were require
‘d, and how much time that took. This is,
especially, useful for debugging which module is making our Emacs start-up, so slow.
;; function to display how much time a particular feature took to require..
(defun preamble/require-time-message(package time)
(if debug-on-error ( message
"- At =%.2fms=, I required a feature: =%s=, which took me =%0.2fms=."
(preamble/load-time) package time)))
(defvar feature-required-time nil "Require time for a specific feature.")
(defvar preamble/require-times nil
"A list of (FEATURE . LOAD-DURATION).
LOAD-DURATION is the time taken in milliseconds to load FEATURE.")
(defadvice require
(around build-require-times (feature &optional filename noerror) activate)
"Note in `preamble/require-times' the time taken to require each feature."
(let* ((already-loaded (memq feature features))
(require-start-time (and (not already-loaded) (current-time))))
(prog1
ad-do-it
(when (and (not already-loaded) (memq feature features) debug-on-error)
(setq feature-required-time
(preamble/time-subtract-millis (current-time) require-start-time))
(preamble/require-time-message feature feature-required-time)
(add-to-list 'preamble/require-times
(cons feature
(preamble/time-subtract-millis (current-time)
require-start-time))
t)))))
Now that, I have Emacs v24
with me, I would first disable some of the GUI features early in the
start-up so as to ensure that the screen does not flicker when turning them off, otherwise.
(if (fboundp 'menu-bar-mode) (menu-bar-mode -1))
(if (fboundp 'tool-bar-mode) (tool-bar-mode -1))
(if (fboundp 'scroll-bar-mode) (scroll-bar-mode -1))
(setq inhibit-startup-message 't) ; disable ugly start screen
(defvar preamble-dir
(file-name-directory (file-truename load-file-name))
"The root directory for Emacs' Preamble configuration.")
(defvar preamble-vendor-dir (concat preamble-dir "/vendors")
"The directory which contains files from our vendors.")
(defvar preamble/bookmark-file (expand-file-name ".bookmarks.el" preamble-dir)
"The file where all the bookmarks will be saved.")
(defconst *is-mac* (eq system-type 'darwin))
(defconst *is-linux* (eq system-type 'gnu/linux))
(defconst *is-windows* (eq system-type 'windows-nt))
(defconst *is-cygwin* (eq system-type 'cygwin))
(defconst *is-mac-gui* (and *is-mac* window-system))
(defconst *is-cocoa-emacs* (and *is-mac* (eq window-system 'ns)))
(defconst *spell-check-support-enabled* nil)
(defmacro after (feature &rest body)
"After FEATURE is loaded, evaluate BODY."
(declare (indent defun))
`(eval-after-load ,feature
'(progn ,@body)))
(defun preamble/eval-after-init (form)
"Add `(lambda () FORM)' to `after-init-hook'.
If Emacs has already finished initialization, also eval FORM immediately."
(let ((func (list 'lambda nil form)))
(add-hook 'after-init-hook func)
(when after-init-time
(eval form))))
(defun preamble/greet-user-with-load-time()
"Greet and display load time to the user."
(message (concat "--------------------------------------------------------------------\n"
"*Welcome to Emacs' Preamble.*\n"
"Emacs' Preamble was loaded in =%.2fms=.") (preamble/load-time)))
I have added the following function to add all sub-directories inside a given directory to the
load-path
.
(defun preamble/add-subfolders-to-load-path (parent-dir)
"Add all level PARENT-DIR subdirs to the `load-path'."
(dolist (f (directory-files parent-dir))
(let ((name (expand-file-name f parent-dir)))
(when (and (file-directory-p name)
(not (equal f ".."))
(not (equal f ".")))
(add-to-list 'load-path name)
(preamble/add-subfolders-to-load-path name)))))
Define a really handy function to quickly split the current window to open the most recent buffer.
;; Borrowed from http://postmomentum.ch/blog/201304/blog-on-emacs
(defun preamble/split-window()
"Split the window to see the most recent buffer in the other window.
Call a second time to restore the original window configuration."
(interactive)
(if (eq last-command 'preamble/split-window)
(progn
(jump-to-register :preamble/split-window)
(setq this-command 'preamble/unsplit-window))
(window-configuration-to-register :preamble/split-window)
(switch-to-buffer-other-window nil)))
Emacs uses a custom file to store changes done via Emacs’ Easy Customization method. I’m, simply, setting it up below, so that all the custom configuration exists in a separate file.
(setq custom-file (expand-file-name "custom.el" preamble-dir))
(load custom-file)
vendors
directory was created for the purpose of putting up unpublished packages inside it, via
git repository cloning. I’m just adding all of its sub-directories to the load path.
(mapc 'load (directory-files preamble-vendor-dir 't "^[^#].*el$"))
(preamble/add-subfolders-to-load-path preamble-vendor-dir)
Setup encoding used by the Emacs to utf-8
, thereby, easing out my life.
(setq locale-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(set-selection-coding-system 'utf-8)
(prefer-coding-system 'utf-8)
(global-auto-revert-mode)
(setq global-auto-revert-non-file-buffers t
auto-revert-verbose nil)
(eval-when-compile (require 'cl)) ; load common lisp
(fset 'yes-or-no-p 'y-or-n-p) ; shut up, and be concise
(setq-default gc-cons-threshold 50000000 ; perform garbage collection at 50MB (instead of 0.76MB)
buffers-menu-max-size 30 ; max num of entries in Buffers menu
compilation-scroll-output t ; scroll down to show last line in compilation mode
make-backup-files nil ; do not make backups for files
mouse-yank-at-point t ; mouse yank at point instead of at click
save-interprogram-paste-before-kill t ; save clipboard into kill ring b4 replacing it
scroll-preserve-screen-position 'always ; point keeps its position when scrolling
set-mark-command-repeat-pop t ; repeating C-SPC after popping mark pops it again
grep-scroll-output t
grep-highlight-matches t
bookmark-default-file preamble/bookmark-file ; default bookmark file
ediff-split-window-function 'split-window-horizontally
ediff-window-setup-function 'ediff-setup-windows-plain
ring-bell-function 'ignore)
(global-linum-mode) ; display line numbers
(setq-default blink-cursor-delay 0 ; seconds after which cursor starts to blink
blink-cursor-interval 0.4 ; length of cursor blink interval
line-spacing 0.2 ; space to put between lines
)
(column-number-mode) ; display column number in mode line
I despise whitespace
, esp. the freaky trailing ones. So, I explicitely set them to be visible,
and automatically remove them when buffer is saved.
(setq show-trailing-whitespace 't) ; show trailing whitespace in editor
(add-hook 'before-save-hook 'delete-trailing-whitespace) ; delete them when buffer is saved
;; do not show trailing whitespace in some modes
(dolist (hook '(term-mode-hook comint-mode-hook compilation-mode-hook))
(add-hook hook (lambda () (setq show-trailing-whitespace nil))))
(setq-default truncate-lines nil ; display continuation lines
truncate-partial-width-windows nil)
I love syntax highlighting.
(global-font-lock-mode 1)
Specify the default font as Source Code Pro
, which should already be downloaded and installed.
(set-frame-font "Source Code Pro")
(set-face-attribute 'default nil :font "Source Code Pro" :height 140)
(set-face-font 'default "Source Code Pro")
(setq use-file-dialog 'nil) ; use mini-buffer for file dialogs
(setq use-dialog-box 'nil) ; use mini-buffer for everythin' else..
(eval '(setq inhibit-startup-echo-area-message "nikhgupta"))
(setq-default tooltip-delay 1.5 ; seconds to wait before displaying tooltip
visible-bell t ; try to flash the frame to represent bell
indicate-empty-lines t ; show an indicator in left fringe for lines not in buffer
)
(electric-pair-mode) ; automatically insert delimiter pairs
(delete-selection-mode) ; typed text replaces the active selection
(transient-mark-mode) ; highlight the region when mark is active
(cua-selection-mode 't) ; for rectangular selections, CUA is nice
(show-paren-mode) ; show matching parenthesis
(global-visual-line-mode) ; soft wrapping of lines
(setq-default case-fold-search t ; searches and matches should ignore case
indent-tabs-mode nil ; indentation can not insert tabs
tab-width 2 ; a TAB is 2 spaces, by default
fill-column 100)
We do not want to disable narrowing commands, or case-change functions.
(put 'narrow-to-region 'disabled nil)
(put 'narrow-to-page 'disabled nil)
(put 'narrow-to-defun 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(autoload 'zap-up-to-char "misc" "Kill up to, but not including
ARGth occurrence of CHAR.")
(defun Preamble/duplicate-region (beg end)
"Insert a copy of the current region after the region."
(interactive "r")
(save-excursion
(goto-char end)
(insert (buffer-substring beg end))))
(defun preamble/duplicate-line-or-region (prefix)
"Duplicate either the current line or any current region."
(interactive "*p")
(whole-line-or-region-call-with-region 'preamble/duplicate-region prefix t))
(defun preamble/kill-back-to-indentation ()
"Kill from point back to the first non-whitespace character on the line."
(interactive)
(let ((prev-pos (point)))
(back-to-indentation)
(kill-region (point) prev-pos)))
(defun preamble/sort-lines-random (beg end)
"Sort lines in region randomly."
(interactive "r")
(save-excursion
(save-restriction
(narrow-to-region beg end)
(goto-char (point-min))
(let ;; To make `end-of-line' and etc. to ignore fields.
((inhibit-field-text-motion t))
(sort-subr nil 'forward-line 'end-of-line nil nil
(lambda (s1 s2) (eq (random 2) 0)))))))
(defun preamble/open-line-with-reindent (n)
"A version of `open-line' which reindents the start and end positions.
If there is a fill prefix and/or a `left-margin', insert them
on the new line if the line would have been blank.
With arg N, insert N newlines."
(interactive "*p")
(let* ((do-fill-prefix (and fill-prefix (bolp)))
(do-left-margin (and (bolp) (> (current-left-margin) 0)))
(loc (point-marker))
;; Don't expand an abbrev before point.
(abbrev-mode nil))
(delete-horizontal-space t)
(newline n)
(indent-according-to-mode)
(when (eolp)
(delete-horizontal-space t))
(goto-char loc)
(while (> n 0)
(cond ((bolp)
(if do-left-margin (indent-to (current-left-margin)))
(if do-fill-prefix (insert-and-inherit fill-prefix))))
(forward-line 1)
(setq n (1- n)))
(goto-char loc)
(end-of-line)
(indent-according-to-mode)))
(require 'server)
(unless (server-running-p)
(server-start))
OK, so I am using the default Package Manager that is shipped with Emacs 24 to load my packages
(anything else, does not make sense, anyways). However, I must, first, tell it to use more sources
to search for a given package (a.k.a. yum
). I am using Marmalade, MELPA, & Org ELPA repositories,
for this purpose.
(require 'package)
(setq package-archives
'(("marmalade" . "http://marmalade-repo.org/packages/")
("org" . "http://orgmode.org/elpa/")
("melpa" . "http://melpa.milkbox.net/packages/")))
(package-initialize)
I have added some convenient functions to install a package, only when it is explicitely told to do
so, which means that instead of adding these packages to the list of our packages (that need to be
installed and checked on every run of Emacs) in the next section, we are now able to install
them
right along with the rest of their configuration. This is called On Demand Installation of the
packages.
;; on-demand installation of a package
(defun preamble/require-package (package &optional min-version no-refresh)
"Install given PACKAGE, optionally requiring MIN-VERSION.
If NO-REFRESH is non-nil, the available package lists will not be
re-downloaded in order to locate PACKAGE."
(if (package-installed-p package min-version)
t
(if (or (assoc package package-archive-contents) no-refresh)
(package-install package)
(progn
(package-refresh-contents)
(preamble/require-package package min-version t)))))
;; on-demand installation of multiple packages
(defun preamble/require-packages(packages-list)
"Install packages from a given PACKAGES-LIST, using `preamble-require-package' function."
(mapc #'preamble/require-package packages-list))
Some packages are really trivial in nature, and nearly, need no configuration, at all. I have marked such packages to be installed, in this section. That way, I won’t have to clobber up the configuration with different headings, and the likes.
(defun preamble/install-packages ()
"Install all packages listed in `preamble-trivial-packages'."
(unless (every #'package-installed-p preamble-trivial-packages)
(preamble/require-packages preamble-trivial-packages)))
(defvar preamble-trivial-packages '( dash
diminish
expand-region
flycheck
regex-tool
smex)
"A list of trivial packages that are installed on startup.")
(preamble/install-packages)
I have added a macro preamble/auto-install
to automatically install the appropriate mode for a
file with given extension, when it is opened. Furthermore, the macro ensures that the file is, then,
opened in that mode. This can be used to automatically install the required packages for a specific
filetype.
(defvar preamble/auto-install-alist
'(("\\.clj\\'" clojure-mode clojure-mode)
("\\.coffee\\'" coffee-mode coffee-mode)
("\\.css\\'" css-mode css-mode)
("\\.csv\\'" csv-mode csv-mode)
("\\.d\\'" d-mode d-mode)
("\\.dart\\'" dart-mode dart-mode)
("\\.erl\\'" erlang erlang-mode)
("\\.feature\\'" feature-mode feature-mode)
("\\.go\\'" go-mode go-mode)
("\\.groovy\\'" groovy-mode groovy-mode)
("\\.haml\\'" haml-mode haml-mode)
("\\.hs\\'" haskell-mode haskell-mode)
("\\.latex\\'" auctex LaTeX-mode)
("\\.less\\'" less-css-mode less-css-mode)
("\\.lua\\'" lua-mode lua-mode)
("\\.markdown\\'" markdown-mode markdown-mode)
("\\.mkd\\'" markdown-mode markdown-mode)
("\\.md\\'" markdown-mode markdown-mode)
("\\.ml\\'" tuareg tuareg-mode)
("\\.pp\\'" puppet-mode puppet-mode)
("\\.php\\'" php-mode php-mode)
("PKGBUILD\\'" pkgbuild-mode pkgbuild-mode)
("\\.sass\\'" sass-mode sass-mode)
("\\.scala\\'" scala-mode2 scala-mode)
("\\.scss\\'" scss-mode scss-mode)
("\\.slim\\'" slim-mode slim-mode)
("\\.textile\\'" textile-mode textile-mode)
("\\.yml\\'" yaml-mode yaml-mode))
"A list of filetype vs mode mappings.")
(defmacro preamble/auto-install (extension package mode)
"When file with EXTENSION is opened triggers auto-install of PACKAGE.
PACKAGE is installed only if not already present. The file is opened in MODE."
`(add-to-list 'auto-mode-alist
`(,extension . (lambda ()
(unless (package-installed-p ',package)
(package-install ',package))
(,mode)))))
(mapc (lambda (entry)
(let ((extension (car entry))
(package (cadr entry))
(mode (cadr (cdr entry))))
(unless (package-installed-p package)
(preamble/auto-install extension package mode))))
preamble/auto-install-alist)
;; some modes don't have autoloads for the auto-mode-alist
;; so we add them manually if package is already installed
(when (package-installed-p 'markdown-mode)
(add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)))
(when (package-installed-p 'pkgbuild-mode)
(add-to-list 'auto-mode-alist '("PKGBUILD\\'" . pkgbuild-mode)))
An editor can only improve my efficiency, if it pleases my eyes. — Nikhil Gupta
This is true, since I work for almost 12-16 hours on my computer, with almost 70% time either in my Shell or in my Editor, and hence, these two things need to be so adorable, and so damn impressive, that I would never want to leave them alone.
;; ensures that themes will be applied even if they have not been customized
(defun preamble/reapply-themes ()
"Forcibly load the themes listed in `custom-enabled-themes'."
(dolist (theme custom-enabled-themes)
(unless (custom-theme-p theme) (load-theme theme)))
(custom-set-variables `(custom-enabled-themes (quote ,custom-enabled-themes))))
;; lets run the above function after Emacs has loaded this configuration.
(add-hook 'after-init-hook 'preamble/reapply-themes)
I am in love with elegance, and only prefer the themes which show such elegance. Emacs’ Preamble uses a very specific set of 5 themes (or theme groups) at any time, since as per me, I would never need more than that, even if I am bored.
(preamble/require-packages '( noctilux-theme zenburn-theme sublime-themes
color-theme-sanityinc-solarized
color-theme-sanityinc-tomorrow base16-theme ))
(setq-default custom-enabled-themes '(sanityinc-tomorrow-eighties))
;; quick access for some themes, I use often.
(defun light() "Activate a light color theme."
(interactive) (color-theme-sanityinc-solarized-light))
(defun dark() "Activate a dark color theme."
(interactive) (color-theme-sanityinc-solarized-dark))
(defun eighties() "Activate an 80's theme."
(interactive) (color-theme-sanityinc-tomorrow-eighties))
(defun day() "Activate theme for a day."
(interactive) (color-theme-sanityinc-tomorrow-day))
(defun night() "Activate theme for a night."
(interactive) (color-theme-sanityinc-tomorrow-night))
Simple fullscreen support for Emacs. Note that, Emacs in OSX already has a fullscreen support, and a similar support is built-in inside Emacs v24.4+.
(defun preamble/fullscreen ()
"Make Emacs window fullscreen.
This follows freedesktop standards, should work in X servers."
(interactive)
(if (eq window-system 'x)
(x-send-client-message nil 0 nil "_NET_WM_STATE" 32
'(2 "_NET_WM_STATE_FULLSCREEN" 0))
(error "Only X server is supported")))
(setq frame-title-format
'((:eval (if (buffer-file-name)
(abbreviate-file-name (buffer-file-name)) "%b"))))
(defun preamble/adjust-opacity (frame incr)
(let* ((oldalpha (or (frame-parameter frame 'alpha) 100))
(newalpha (+ incr oldalpha)))
(when (and (<= frame-alpha-lower-limit newalpha) (>= 100 newalpha))
(modify-frame-parameters frame (list (cons 'alpha newalpha))))))
When making new Terminal, i.e. tty
frames in Emacs, I want to ensure that I am able to use mouse
there, as well as paste by clicking mouse middle button.
(xterm-mouse-mode)
(when (fboundp 'mwheel-install) (mwheel-install))
(setq mouse-wheel-scroll-amount '(1 ((shift) . 1))) ;; one line at a time
(setq mouse-wheel-progressive-speed nil) ;; don't accelerate scrolling
(setq mouse-wheel-follow-mouse 't) ;; scroll window under mouse
(setq scroll-step 1) ;; keyboard scroll one line at a time
(setq scroll-conservatively 10000)
(setq auto-window-vscroll nil)
Switching windows, when more than 2 of them are open, with C-x o
is a real pain in the fingers
and eyes, therefore, I make use of the really nice switch-window package, as well as the
winner-mode
built-in Emacs. Winner Mode allows us to undo (and redo) changes in the window
configuration with the key commands C-c left
, and C-c right
(which, is pretty neat!)
(when (fboundp 'winner-mode) (winner-mode))
(preamble/require-package 'switch-window)
(require 'switch-window)
;; we must bind the "C-x o" key appropriately, now.
(setq switch-window-shortcut-style 'quail)
Modules defines either a package or a mode or both, and this section defines various modules along
with the relevant configuration required by them. Each module is tagged with appropriate tags to
refer to the kind of feature, it provides, e.g. a module can be tagged as editor
, which means that
the module provides a feature related to the editing inside Emacs.
AutoComplete is an excellent auto-completion feature with popup menu for quick selection. It can complete words at the point from a number of different sources, and includes fuzzy-matching, in-built.
I have, first, setup AutoComplete as the default completion function, by hooking it inside
auto-complete-mode
.
(preamble/require-package 'auto-complete)
(require 'auto-complete-config)
(defun preamble/auto-complete-at-point ()
"Use AutoComplete to provide completion at the current point."
(when (and (not (minibufferp))
(fboundp 'auto-complete-mode)
auto-complete-mode)
(auto-complete)))
;; hook AC into completion-at-point
(defun preamble/set-auto-complete-as-completion-at-point-function ()
"Set AutoComplete as Completion-At-Point function."
(add-to-list 'completion-at-point-functions 'preamble/auto-complete-at-point))
(add-hook 'auto-complete-mode-hook 'preamble/set-auto-complete-as-completion-at-point-function)
I want to customize behavior of AC to match my workflow, and have setup TAB
key to trigger
completions. Further, I want to exclude very large buffer from interfering with AC.
(global-auto-complete-mode) ; enable auto-complete mode globally
(after 'auto-complete
(setq ac-expand-on-auto-complete t ; auto-complete whole match on TAB
ac-auto-start 3 ; enable auto-complete after 3 chars
ac-dwim nil ; get pop-ups with docs even if word is uniquely completed
tab-always-indent 'complete ; use TAB to trigger auto-complete
dabbrev-friend-buffer-function
'(lambda() (< (buffer-size other-buffer (1024 1024))))) ; exclude large buffers
(add-to-list 'completion-styles 'initials t))
Finally, define some sources for AC, and setup some modes to use AC, by default.
(after 'auto-complete
;; define sources for auto-completion
(set-default 'ac-sources '( ac-source-imenu ac-source-dictionary
ac-source-words-in-buffer
ac-source-words-in-same-mode-buffers
ac-source-words-in-all-buffer))
;; add various modes to auto-complete
(dolist (mode '(magit-log-edit-mode log-edit-mode org-mode
text-mode haml-mode ruby-mode sass-mode yaml-mode
csv-mode espresso-mode haskell-mode html-mode
nxml-mode sh-mode smarty-mode clojure-mode
lisp-mode textile-mode markdown-mode tuareg-mode
js3-mode css-mode less-css-mode sql-mode
ielm-mode))
(add-to-list 'ac-modes mode)))
Diminished modes is an internal feature, which lets us fight mode-line clutter by diminishing (removing or abbreviating) minor mode indicators in the modeline.
(preamble/require-package 'diminish)
(add-hook 'emacs-lisp-mode-hook (lambda() (setq mode-name "eL"))) ; emacs lisp
Dired+ enhances our file-exploring experience, and provides additional features to Dired Mode.
(preamble/require-package 'dired+)
(setq diredp-hide-details-initially-flag nil
global-dired-hide-details-mode -1)
(after 'dired
(require 'dired+)
(setq dired-recursive-deletes 'top))
;; disable line wrapping in dired mode
(add-hook 'dired-mode-hook (lambda () (setq truncate-lines t)))
(after 'dired
(define-key dired-mode-map [mouse-2] 'dired-find-file))
Many modern editors and IDEs can graphically indicate the location of the fill column by drawing a
thin line (in design parlance, a “rule”) down the length of the editing window. fci-mode
,
i.e. Fill Column Indicator implements this facility in Emacs.
(preamble/require-package 'fill-column-indicator)
(after 'fill-column-indicator
(setq fci-rule-width 10)
(setq fci-rule-character ?❚)
; (setq fci-rule-character-color "#999999")
(setq fci-dash-pattern 1.00))
However, I only want to see column indicator when one of the org-mode
, text-mode
or prog-mode
is active. Moreover, whenever I switch themes, I would like to regenerate the indicator. Lastly,
fci-mode
is not compatible with show-trailing-whitespace
property, and hence, I have added a
function to properly activate fci-mode
in this case.
(defun preamble/fci-mode-settings()
"Turn of `fci-mode' properly, when trailing whitespace is being shown."
(turn-on-fci-mode)
(when show-trailing-whitespace
(set (make-local-variable 'whitespace-style) '(face trailing))
(whitespace-mode)))
;; enable `fci-mode' in `org-mode' and programming mode
(add-hook 'prog-mode-hook 'preamble/fci-mode-settings)
(add-hook 'org-mode-hook 'preamble/fci-mode-settings)
;; regenerate fci-mode line images after switching themes
(defadvice enable-theme (after recompute-fci-face activate)
(dolist (buffer (buffer-list))
(with-current-buffer buffer
(when (and (boundp 'fci-mode) fci-mode)
(turn-on-fci-mode)))))
FlyCheck is a modern on-the-fly syntax-checker for GNU Emacs, which selects syntax-checkers based on the major mode of the current buffer.
(preamble/require-package 'flycheck)
(add-hook 'after-init-hook 'global-flycheck-mode)
HippieExpand looks at the word before point and tries to expand it in various ways including expanding from a fixed list (like
expand-abbrev
), expanding from matching text found in a buffer (likedabbrev-expand
) or expanding in ways defined by your own functions. Which of these it tries and in what order is controlled by a configurable list of functions.
As stated above, hippie-expand
uses a list of functions, which has been defined below in our case:
(after 'hippie-expand
(setq hippie-expand-try-functions-list
'(try-complete-file-name-partially
try-complete-file-name
try-expand-dabbrev
try-expand-dabbrev-all-buffers
try-expand-dabbrev-from-kill)))
ibuffer-vc adds functionality to Emacs’ iBuffer Mode by grouping buffers according to their parent
VC (version-control) root directory, and by displaying and/or sorting files by their VC status.
Therefore, ibuffer-mode
will, now, show different groups of buffers based on the git
repository
path. Pretty Awesome!
First, lets make sure that the buffers are grouped according to version control system, they are in, then by filename or process name.
(preamble/require-package 'ibuffer-vc)
(after 'ibuffer (require 'ibuffer-vc))
(defun preamble/ibuffer-set-up-preferred-filters ()
"Sort ibuffers according to Version Control or Filename or Process."
(ibuffer-vc-set-filter-groups-by-vc-root)
(unless (eq ibuffer-sorting-mode 'filename/process)
(ibuffer-do-sort-by-filename/process)))
(add-hook 'ibuffer-hook 'preamble/ibuffer-set-up-preferred-filters)
Now, the default display of dired
command is a bit non-resonating with what my eyes want to see,
and therefore, lets change the configuration of ibuffer
to suit my pair of eyes.
(after 'ibuffer
;; use human readable size column instead of original one
(define-ibuffer-column size-h
(:name "Size" :inline t)
(cond
((> (buffer-size) 1000000) (format "%7.1fM" (/ (buffer-size) 1000000.0)))
((> (buffer-size) 1000) (format "%7.1fk" (/ (buffer-size) 1000.0)))
(t (format "%8d" (buffer-size))))))
;; modify the default ibuffer-formats
(setq ibuffer-formats
'((mark modified read-only vc-status-mini " "
(name 18 18 :left :elide) " "
(size-h 9 -1 :right) " "
(mode 16 16 :left :elide) " "
(vc-status 16 16 :left) " "
filename-and-process)))
(setq ibuffer-filter-group-name-face 'font-lock-doc-face)
IDO Mode is, simply, amazin’! It lets us do things interactively with buffers and files. When combined with IDO Ubiquitous and Smex, it creates a powerful combination of fuzzy-file searching and the same power is available for executings commands, as well as a heap of other places.
;; suppress warnings from ido-ubiquitous
(defvar predicate 'nil)
(defvar inherit-input-method 'nil)
(defvar ido-cur-item 'nil)
(defvar ido-default-item 'nil)
(defvar ido-cur-list 'nil)
(preamble/require-packages '( smex idomenu ido-ubiquitous))
(ido-mode) ; enable ido mode
(ido-everywhere) ; use ido-mode wherever possible
(ido-ubiquitous-mode) ; enable ido-ubiquitous
(setq ido-enable-flex-matching 't ; enable fuzzy search
ido-use-filename-at-point 'nil ; look for filename at point
ido-use-virtual-buffers 't ; allow me to open closed buffers, even
ido-auto-merge-work-directories-length 0
ido-default-buffer-method 'selected-window) ; allow buffer to be open in different frames
(defun preamble/ido-choose-from-recentf ()
"Use ido to select a recently opened file from the `recentf-list'."
(interactive)
(if (and ido-use-virtual-buffers (fboundp 'ido-toggle-virtual-buffers))
(ido-switch-buffer)
(find-file (ido-completing-read "Open file: " recentf-list nil t))))
Incremental Search, i.e. Emacs’ isearch
is the Incremental Search feature of Emacs, and while it
is really nice on its own, it may need some basic extensions and features related to it.
;; Search back/forth for the symbol at point
;; See http://www.emacswiki.org/emacs/SearchAtPoint
(defun preamble/isearch-yank-symbol ()
"*Put symbol at current point into search string."
(interactive)
(let ((sym (symbol-at-point)))
(if sym
(progn
(setq isearch-regexp t
isearch-string (concat "\\_<" (regexp-quote (symbol-name sym)) "\\_>")
isearch-message (mapconcat 'isearch-text-char-description isearch-string "")
isearch-yank-flag t))
(ding)))
(isearch-search-and-update))
;; http://www.emacswiki.org/emacs/ZapToISearch
(defun zap-to-isearch (rbeg rend)
"Kill the region between the mark and the closest portion of
the isearch match string. The behaviour is meant to be analogous
to zap-to-char; let's call it zap-to-isearch. The deleted region
does not include the isearch word. This is meant to be bound only
in isearch mode. The point of this function is that oftentimes
you want to delete some portion of text, one end of which happens
to be an active isearch word. The observation to make is that if
you use isearch a lot to move the cursor around (as you should,
it is much more efficient than using the arrows), it happens a
lot that you could just delete the active region between the mark
and the point, not include the isearch word."
(interactive "r")
(when (not mark-active)
(error "Mark is not active"))
(let* ((isearch-bounds (list isearch-other-end (point)))
(ismin (apply 'min isearch-bounds))
(ismax (apply 'max isearch-bounds))
)
(if (< (mark) ismin)
(kill-region (mark) ismin)
(if (> (mark) ismax)
(kill-region ismax (mark))
(error "Internal error in isearch kill function.")))
(isearch-exit)
))
;; http://www.emacswiki.org/emacs/ZapToISearch
(defun isearch-exit-other-end (rbeg rend)
"Exit isearch, but at the other end of the search string.
This is useful when followed by an immediate kill."
(interactive "r")
(isearch-exit)
(goto-char isearch-other-end))
(define-key isearch-mode-map (kbd "C-y") 'isearch-yank-kill)
(define-key isearch-mode-map (kbd "C-M-w") 'isearch-yank-symbol)
(define-key isearch-mode-map (kbd "M-z") 'zap-to-isearch)
(define-key isearch-mode-map (kbd "C-RET") 'isearch-exit-other-end)
(define-key isearch-mode-map (kbd "C-o") 'isearch-occur)
Multiple Major Modes is a minor mode for Emacs that allows multiple major modes to coexist in one buffer. It is well-suited to editing:
- Preprocessed code, e.g. server-side Ruby, Perl or PHP embedded in HTML
- Code generating code, such as HTML output by CGI scripts
- Embedded code, such as Javascript in HTML
- Literate programming: code interspersed with documentation, e.g. Noweb
(preamble/require-package 'mmm-mode)
(require 'mmm-auto)
; only enable when `mmm' is required
(setq mmm-global-mode 'buffers-with-submode-classes)
(setq mmm-submode-decoration-level 2)
Recent Files is a minor mode that builds a list of recently opened files. This list is is auto-saved across Emacs sessions. You can then access this list through a menu, or keybinding.
(require 'recentf)
(recentf-mode)
(after 'recentf
(setq recentf-max-menu-items 25
recentf-max-saved-items 1000
recentf-exclude '("/tmp/" "/ssh:")))
The Silver Searcher (ag
) is an awesome utility, somewhat like ack
, but faster. This module
allows me to use the power of ag
inside Emacs’ Preamble. The github repository for this package
can be found at: Github: The Silver Searcher.
(when (executable-find "ag")
(preamble/require-packages '(ag wgrep-ag))
(setq-default ag-highlight-search t))
(setq tramp-default-method "ftp")
UndoTree is amazin’. It visually describes your change history for the current buffer in a nice ascii-tree like structure. From there, it is trivially easy to view your changes, and easily undo/redo according to Emacs’ undo structure.
(preamble/require-package 'undo-tree)
(global-undo-tree-mode)
(diminish 'undo-tree-mode)
Uniquify is a built-in library that makes buffer names unique, when two files with same name are open, so as to make them distinguishable.
(require 'uniquify)
(after 'uniquify
(setq uniquify-buffer-name-style 'reverse)
(setq uniquify-separator " • ")
(setq uniquify-after-kill-buffer-p t)
(setq uniquify-ignore-buffers-re "^\\*"))
(preamble/require-packages
'( unfill ; join several lines inside a region/para
whole-line-or-region ; kill whole region/line based on if region is active
mic-paren ; matching parenthesis even if outside current screen
pointback ; per-window memory of buffer-point positions
multiple-cursors ; self-explanatory
ace-jump-mode ; quickly jump to a character on screen
page-break-lines ; display ^L page breaks as tidy horizontal lines
move-text ; move text easily up and down
visual-regexp ; get visual indications for matched regexp
highlight-escape-sequences ))
;; settings for `highlight-escape-sequences' package
(hes-mode)
;; settings for `page-break-lines' package
(global-page-break-lines-mode)
(after 'page-break-lines (diminish 'page-break-lines-mode))
;; settings for `pointback' package
(global-pointback-mode)
(after 'skeleton
(defadvice skeleton-insert (before disable-pointback activate)
"Disable pointback when using skeleton functions like `sgml-tag'."
(when pointback-mode
(message "Disabling pointback.")
(pointback-mode -1))))
;; settings for `whole-line-or-region' package
(whole-line-or-region-mode)
(after 'whole-line-or-region
(diminish 'whole-line-or-region-mode)
(make-variable-buffer-local 'whole-line-or-region-mode))
(preamble/require-packages '(paredit paredit-everywhere))
(autoload 'enable-paredit-mode "paredit")
(after 'paredit (diminish 'paredit-mode " Par"))
;; enable some handy paredit functions in all prog modes
(add-hook 'prog-mode-hook 'paredit-everywhere-mode)
(after 'paredit
(dolist (binding (list (kbd "C-<left>") (kbd "C-<right>")
(kbd "C-M-<left>") (kbd "C-M-<right>")))
(define-key paredit-mode-map binding nil))
;; disable kill-sentence, which is easily confused with the kill-sexp binding, but doesn't
;; preserve sexp structure
(define-key paredit-mode-map [remap kill-sentence] nil)
(define-key paredit-mode-map [remap backward-kill-sentence] nil))
;; use paredit in the minibuffer
;; http://emacsredux.com/blog/2013/04/18/evaluate-emacs-lisp-in-the-minibuffer/
(defvar paredit-minibuffer-commands '(eval-expression
pp-eval-expression
eval-expression-with-eldoc
ibuffer-do-eval
ibuffer-do-view-and-eval)
"Interactive commands for which paredit should be enabled in the minibuffer.")
(defun conditionally-enable-paredit-mode ()
"Enable paredit during lisp-related minibuffer commands."
(if (memq this-command paredit-minibuffer-commands)
(enable-paredit-mode)))
(add-hook 'minibuffer-setup-hook 'conditionally-enable-paredit-mode)
(when *spell-check-support-enabled*
(require 'ispell)
(when (executable-find ispell-program-name)
(require 'init-flyspell)))
;; set directories used by `org-mode'
(setq org-directory (expand-file-name "~/Organizer"))
(setq org-archive-location (concat org-directory "/archives" ))
(setq org-special-directory (concat org-directory "/special"))
(setq org-global-properties
'(("Effort_ALL". "0 0:10 0:30 1:00 2:00 3:00 4:00")))
;; replace initial/scratch buffer with our primary `.org' file
(setq initial-buffer-choice (concat org-special-directory "/start.org"))
(add-to-list 'auto-mode-alist '("\\.\\(org\\|org_archive\\|txt\\)$" . org-mode))
(setq org-log-done t ; record information when task is marked as DONE
org-completion-use-ido t ; use ido-completion when possible
org-edit-timestamp-down-means-later t ; S-down will increase time in timestamp
org-fast-tag-selection-single-key 'expert ; fast tag selection
org-tags-column -100 ; indent tags to the right
org-special-ctrl-a/e 't ; make them jump to start/end of headings
org-src-fontify-natively t ; syntax-highlight source blocks
org-export-kill-product-buffer-when-displayed t)
(after 'org-mode (setq 'fill-column 100)) ; set column width to 100 for org-mode files
(add-hook 'org-mode-hook 'turn-on-auto-fill) ; Turn on `auto-fill'
(setq org-agenda-start-on-weekday nil ; monday as week's start
org-agenda-span 14 ; show 2 weeks of agenda, by default
; org-agenda-include-diary 't ; include `diary' in agenda
; org-agenda-window-setup 'other-window ; use `other-window' for agenda
org-deadline-warning-days 14
org-agenda-skip-scheduled-if-done 't
org-habit-show-habits-only-for-today 't
org-agenda-dim-blocked-tasks 't
org-agenda-files (quote ("~/Organizer"
"~/Organizer/articles"
"~/Organizer/ideas"
"~/Organizer/special"
"~/Organizer/tidbits"
"~/Organizer/work")))
(add-hook 'org-agenda-mode-hook '(lambda () (hl-line-mode 1)))
(setq org-agenda-custom-commands
'(("n" "Next Tasks to Work on" todo "NEXT"
((org-agenda-max-entries 5)
(org-agenda-sorting-strategy '(priority-up effort-down))))
("r" "Tasks that need refiling" tags-todo "REFILE")
("i" "Important Tasks" tags-todo "important")))
I am using MacOSX, and I want my org-mode
to interact with various applications on it, e.g. I
want to capture links from my Mac applications and add them to org-mode
, as well as with
iCal
. Moreover, I often require to put a file-system subtree inside my org-mode
documents.
(preamble/require-package 'org-fstree)
(when *is-mac*
(preamble/require-packages '(org-mac-link org-mac-iCal))
(autoload 'omlg-grab-link "org-mac-link"))
I have defined some configuration to make refiling easier.
; Refile targets include this file and any file contributing to the agenda - up to 2 levels deep
(setq org-refile-targets (quote ((nil :maxlevel . 3) (org-agenda-files :maxlevel . 3))))
; Use full outline paths for refile targets - we file directly with IDO
(setq org-refile-use-outline-path t)
; Targets complete directly with IDO
(setq org-outline-path-complete-in-steps nil)
; Allow refile to create parent tasks with confirmation
(setq org-refile-allow-creating-parent-nodes (quote confirm))
; Use IDO for org-completion
(setq org-completion-use-ido t)
; Use the current window for indirect buffer display
(setq org-indirect-buffer-display 'current-window)
;;;; Refile settings
; Exclude DONE state tasks from refile targets
(defun preamble/verify-refile-target ()
"Exclude todo keywords with a done state from refile targets"
(not (member (nth 2 (org-heading-components)) org-done-keywords)))
(setq org-refile-target-verify-function 'preamble/verify-refile-target)
; timestamp refiling
(setq org-log-refile 'time)
; update counters
(add-hook 'org-after-refile-insert-hook 'org-update-parent-todo-statistics)
I have set org-mode
to log the time when a task is repeated (for habit-tracking) and when it is
rescheduled. Furthermore, I would like to take a quick note, when I am changing the deadline for a
task. I am using custom workflows for task management:
- TODO: a task.
- STARTED: when I have started working on a TODO.
- NEXT: TODOs I want to work on, next. Possibly, a next action in a project.
- REVIEW: tasks that I have completed, but I need to check if there is something I need to check or share from the experience of this task. Furthermore, it is a persistent tag for some of the review processes, I use in my workflow, e.g. reviewing this emacs setup once a month.
- DONE: a completed task, which will be either archived using org-archive or deleted within 7 days.
- ARCHIVE: a completed task that I will like to keep for a longer time.
Being a developer, I need an additional set of workflow, which tackles bug-fixing scenario.
A last set of todo workflow involves keywords such as WAITING, HOLD, SOMEDAY, CANCELLED, etc. and give a special meaning to the task.
- WAITING: a part of the task was delegated and can not be continued for this reason.
- HOLD: tasks that I have started working on, but can not continue for some reason.
- SOMEDAY: tasks I would like to finish in future, but have no specific deadlines.
- CANCELLED: tasks which have been cancelled for some reason.
For me, a project is any task which has sub-tasks. Easy for me to remember and less burden classifying what constitutes a project and what not.
(setq org-log-repeat 'time
org-log-redeadline 'note
org-log-reschedule 'time
org-use-fast-todo-selection 't
org-enforce-todo-dependencies 't
org-enforce-todo-checkbox-dependencies 't
org-treat-S-cursor-todo-selection-as-state-change 'nil
org-hierarchical-todo-statistics 'nil)
(setq org-enable-priority-commands t)
(setq org-highest-priority ?A)
(setq org-default-priority ?E)
(setq org-lowest-priority ?E)
(setq org-todo-keywords
(quote ((sequence "TODO(t)" "STARTED(s!)" "NEXT(n)" "REVIEW(r@/!)" "|" "DONE(d!)" "ARCHIVED(a)")
(sequence "REPORT(R!)" "BUG(b@/!)" "KNOWNCAUSE(k@/!)" "|" "FIXED(f@/!)")
(sequence "WAITING(w@/!)" "HOLD(h@/!)" "SOMEDAY(S)" "|" "CANCELLED(c@/!)" "DUPE(D)"))))
;; Setting Colours (faces) for todo states to give clearer view of work
(setq org-todo-keyword-faces
'(("TODO" . org-warning)
("STARTED" . "yellow")
("NEXT" . "magenta")
("REVIEW" . "orange")
("DONE" . "green")
("ARCHIVED" . "blue")
("WAITING" . "cyan")
("HOLD" . "cyan")
("SOMEDAY" . "grey")
("CANCELLED" . outline-9)))
; position the habit graph on the agenda to the right of the default
(setq org-habit-graph-column 50)
(run-at-time "10:00" 86400 '(lambda () (setq org-habit-show-habits t)))
;; configure most used tags for fast access
;; (setq org-tag-alist '(("@work" . ?w) ("@home" . ?h) ("laptop" . ?l) (:newline . nil)
;; ("@personal" . ?p)
;; ("relationships" . ?r) ("introspection" . ?i) (:newline . nil)
;; ("@devesh" . ?d)
;; ("code" . ?c) ("emacs" . ?e) ("zsh" . ?z) (:newline . nil)))
;; save the running clock and all clock history when exiting Emacs, load it on startup
(setq org-clock-persist t
org-clock-in-resume t
org-clock-persistence-insinuate t
org-clock-in-switch-to-state "STARTED" ;; change task state to STARTED when clocking in
org-clock-into-drawer t ;; save clock data and notes in the LOGBOOK drawer
org-clock-out-remove-zero-time-clocks t ;; removes clocked tasks with 0:00 duration
)
;; show the clocked-in task - if any - in the header line
(defun preamble/show-org-clock-in-header-line ()
(setq-default header-line-format '((" " org-mode-line-string " "))))
(defun preamble/hide-org-clock-from-header-line ()
(setq-default header-line-format nil))
(add-hook 'org-clock-in-hook 'preamble/show-org-clock-in-header-line)
(add-hook 'org-clock-out-hook 'preamble/hide-org-clock-from-header-line)
(add-hook 'org-clock-cancel-hook 'preamble/hide-org-clock-from-header-line)
;; set files used by `org-capture'
(setq org-journal-file (concat org-special-directory "/diary.org"))
(setq org-default-notes-file (concat org-special-directory "/refile.org"))
(setq org-default-tasks-file (concat org-special-directory "/tasks.org"))
(defun org-journal-entry-time() (format-time-string "%I:%M %p"))
;; customizations for `org-capture'
(setq org-capture-templates
'(("t" "Todo" entry (file+headline org-default-tasks-file "Captured")
"* TODO %?\n%i\n")
("n" "Note" entry (file+datetree org-default-notes-file "Notes")
"* %? :NOTE:\n%U\n%a\n%?" :clock-in t :clock-resume t)
("j" "Journal" entry (file+datetree org-journal-file "Journal")
"* at %(org-journal-entry-time) :crypt:\n %U\n %?" :clock-in t :clock-resume t)
("l" "Link" plain (file org-default-notes-file "Links")
"- %?\n %x\n")
("r" "respond" entry (file org-default-notes-file)
"* NEXT Respond to %:from on %:subject\nSCHEDULED: %t\n%U\n%a\n" :clock-in t :clock-resume t :immediate-finish t)
("w" "org-protocol" entry (file org-default-notes-file)
"* TODO Review %c\n%U\n" :immediate-finish t)
("m" "Meeting" entry (file org-default-notes-file)
"* MEETING with %? :MEETING:\n%U" :clock-in t :clock-resume t)
("p" "Phone call" entry (file org-default-notes-file)
"* PHONE %? :PHONE:\n%U" :clock-in t :clock-resume t)
("h" "Habit" entry (file+headline org-default-tasks-file "Captured")
"* NEXT %?\n%U\n%a\nSCHEDULED: %(format-time-string \"<%Y-%m-%d %a .+1d/3d>\")\n:PROPERTIES:\n:STYLE: habit\n:REPEAT_TO_STATE: NEXT\n:END:\n")))
;;; file encryption
(setq epa-file-inhibit-auto-save 't)
;;; encryption sections of a file
(require 'org-crypt)
(org-crypt-use-before-save-magic)
(setq org-tags-exclude-from-inheritance (quote ("crypt")))
;; GPG key to use for encryption
;; Either the Key ID or set to nil to use symmetric encryption.
(setq org-crypt-key "me@nikhgupta.com")
(setq org-crypt-disable-auto-save 'encrypt)
(after 'org
(define-key org-mode-map (kbd "C-M-<up>") 'org-up-element)
(when *is-mac*
(define-key org-mode-map (kbd "M-h") nil)
(define-key org-mode-map (kbd "C-c g") 'omlg-grab-link)))
;; Standard key bindings
(global-set-key (kbd "C-c l") 'org-store-link)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c b") 'org-iswitchb)
(global-set-key (kbd "C-c c") 'org-capture)
(preamble/require-packages '(ruby-mode
ruby-hash-syntax
inf-ruby
robe
ruby-compilation
yari
yaml-mode
tagedit
rinari))
;; files recognized by ruby mode
(add-to-list 'auto-mode-alist '("Rakefile\\'" "\\.rake\\'" "\\.rxml\\'"
"\\.rjs\\'" ".irbrc\\'" "\\.builder\\'" "\\.ru\\'"
"\\.gemspec\\'" "Gemfile\\'" "Kirkfile\\'" . 'ruby-mode))
(defalias 'ri 'yari)
(setq ruby-use-encoding-map nil)
(after 'ruby-mode
;; stupidly the non-bundled ruby-mode isn't a derived mode of
;; prog-mode: we run the latter's hooks anyway in that case.
(add-hook 'ruby-mode-hook
'(lambda () (unless (derived-mode-p 'prog-mode) (run-hooks 'prog-mode-hook)))))
;;; robe: Code navigation, documentation and completion for Ruby
(after 'ruby-mode (add-hook 'ruby-mode-hook 'robe-mode))
(after 'robe (add-hook 'robe-mode-hook
(lambda ()
(add-to-list 'ac-sources 'ac-source-robe)
(set-auto-complete-as-completion-at-point-function))))
(after 'rinari (diminish 'rinari-minor-mode "Rin"))
(global-rinari-mode)
(defun update-rails-ctags ()
(interactive)
(let ((default-directory (or (rinari-root) default-directory)))
(shell-command (concat "ctags -a -e -f " rinari-tags-file-name
" --tag-relative -R app lib vendor test"))))
(require 'derived)
(defun preamble/ensure-mmm-erb-loaded () (require 'mmm-erb))
(defun preamble/set-up-mode-for-erb (mode)
(add-hook (derived-mode-hook-name mode) 'preamble/ensure-mmm-erb-loaded)
(mmm-add-mode-ext-class mode "\\.erb\\'" 'erb))
(dolist (mode '(html-mode html-erb-mode nxml-mode))
(progn
(preamble/set-up-mode-for-erb mode)
(mmm-add-mode-ext-class mode "\\.r?html\\(\\.erb\\)?\\'" 'html-js)
(mmm-add-mode-ext-class mode "\\.r?html\\(\\.erb\\)?\\'" 'html-css)))
(mapc 'preamble/set-up-mode-for-erb
'(coffee-mode js-mode js2-mode js3-mode markdown-mode textile-mode))
(add-to-list 'auto-mode-alist '("\\.rhtml\\'" "\\.html\\.erb\\'" . 'html-erb-mode))
(add-to-list 'auto-mode-alist '("\\.jst\\.ejs\\'" . html-erb-mode))
(mmm-add-mode-ext-class 'yaml-mode "\\.yaml\\'" 'erb)
(mmm-add-mode-ext-class 'html-erb-mode "\\.jst\\.ejs\\'" 'ejs)
(dolist (mode (list 'js-mode 'js2-mode 'js3-mode))
(mmm-add-mode-ext-class mode "\\.js\\.erb\\'" 'erb))
(after 'ruby-mode
(define-key ruby-mode-map (kbd "RET") 'reindent-then-newline-and-indent)
(define-key ruby-mode-map (kbd "TAB") 'indent-for-tab-command))
;; ruby compilation
(let ((m ruby-mode-map))
(define-key m [S-f7] 'ruby-compilation-this-buffer)
(define-key m [f7] 'ruby-compilation-this-test)
(define-key m [f6] 'recompile))
(preamble/require-packages '(php-mode smarty-mode))
(preamble/require-packages '( json js2-mode ac-js2 rainbow-delimiters coffee-mode))
(defvar preferred-javascript-indent-level 2)
(defcustom preferred-javascript-mode
(first (remove-if-not #'fboundp '(js2-mode js-mode)))
"Javascript mode to use for .js files."
:type 'symbol
:group 'programming
:options '(js2-mode js-mode))
;; json
(add-to-list 'auto-mode-alist '("\\.json\\'" . js-mode))
;; js-mode
(setq js-indent-level preferred-javascript-indent-level)
(setq javascript-indent-level preferred-javascript-indent-level)
;; node interpreter
(add-to-list 'interpreter-mode-alist (cons "node" preferred-javascript-mode))
;; javascript (even inside erb)
(setq auto-mode-alist (cons `("\\.js\\(\\.erb\\)?\\'" . ,preferred-javascript-mode)
(loop for entry in auto-mode-alist
unless (eq preferred-javascript-mode (cdr entry))
collect entry)))
(setq js2-use-font-lock-faces t
js2-mode-must-byte-compile nil
js2-basic-offset preferred-javascript-indent-level
js2-indent-on-enter-key t
js2-auto-indent-p t
js2-bounce-indent-p nil)
(after 'js2-mode
(add-hook 'js2-mode-hook '(lambda() (setq mode-name "JS2")))
(js2-imenu-extras-setup))
(after 'coffee-mode
(setq coffee-js-mode preferred-javascript-mode
coffee-tab-width preferred-javascript-indent-level))
(add-to-list 'auto-mode-alist '("\\.coffee\\.erb\\'" . coffee-mode))
(preamble/require-package 'textile-mode)
(autoload 'textile-mode "textile-mode" "Mode for editing Textile documents" t)
(add-to-list 'auto-mode-alist '("\\.textile\\'" . textile-mode))
(preamble/require-package 'markdown-mode)
(add-to-list 'auto-mode-alist '("\\.\\(md\\|markdown\\)\\'" . markdown-mode))
(add-to-list 'auto-mode-alist '("\\.\\(xml\\|xsd\\|sch\\|rng\\|xslt\\|svg\\|rss\\|gpx\\|tcx\\)\\'" . nxml-mode))
; generic xml-mode
(fset 'xml-mode 'nxml-mode)
(setq magic-mode-alist (cons '("<\\?xml " . nxml-mode) magic-mode-alist))
(add-hook 'nxml-mode-hook
'(lambda () (set (make-local-variable 'ido-use-filename-at-point) nil)))
(setq nxml-slash-auto-complete-flag t)
;; see: http://sinewalker.wordpress.com/2008/06/26/pretty-printing-xml-with-emacs-nxml-mode/
(defun pp-xml-region (begin end)
"Pretty format XML markup in region. The function inserts
linebreaks to separate tags that have nothing but whitespace
between them. It then indents the markup by using nxml's
indentation rules."
(interactive "r")
(save-excursion
(nxml-mode)
(goto-char begin)
(while (search-forward-regexp "\>[ \\t]*\<" nil t)
(backward-char) (insert "\n"))
(indent-region begin end)))
(preamble/require-package 'tidy)
(add-hook 'nxml-mode-hook (lambda () (tidy-build-menu nxml-mode-map)))
(add-hook 'html-mode-hook (lambda () (tidy-build-menu html-mode-map)))
(preamble/require-packages '(css-eldoc haml-mode htmlize))
(require 'rainbow-mode)
;;; colourise hex colors
(dolist (hook '(css-mode-hook html-mode-hook sass-mode-hook)) (add-hook hook 'rainbow-mode))
;; use eldoc for syntax hints
(autoload 'turn-on-css-eldoc "css-eldoc")
(add-hook 'css-mode-hook 'turn-on-css-eldoc)
;; to enable Skewer mode, check:
;; https://github.com/purcell/emacs.d/blob/master/init-css.el
;; SASS, SCSS, and Less
(preamble/require-packages '(sass-mode scss-mode less-css-mode))
(setq-default scss-compile-at-save nil)
;;; auto-complete CSS keywords
(after 'auto-complete
(dolist (hook '(css-mode-hook sass-mode-hook scss-mode-hook))
(add-hook hook 'ac-css-mode-setup)))
(after 'mmm-vars
(mmm-add-group
'html-css
'((css-cdata
:submode css-mode
:face mmm-code-submode-face
:front "<style[^>]*>[ \t\n]*\\(//\\)?<!\\[CDATA\\[[ \t]*\n?"
:back "[ \t]*\\(//\\)?]]>[ \t\n]*</style>"
:insert ((?j js-tag nil @ "<style type=\"text/css\">"
@ "\n" _ "\n" @ "</script>" @)))
(css
:submode css-mode
:face mmm-code-submode-face
:front "<style[^>]*>[ \t]*\n?"
:back "[ \t]*</style>"
:insert ((?j js-tag nil @ "<style type=\"text/css\">"
@ "\n" _ "\n" @ "</style>" @)))
(css-inline
:submode css-mode
:face mmm-code-submode-face
:front "style=\""
:back "\""))))
(preamble/require-packages '(elisp-slime-nav ; use M-.|M- to jump-in and out of definitions
lively ; interactively updated text: http://git.io/gbjLUw
pretty-mode ; redisplay parts of buffer as pretty symbols
auto-compile ; automatically compile emacs-lisp libraries
hl-sexp ; highlight current `sexp'
rainbow-delimiters ; colorize parenthesis
redshank ; common-lisp editing extensions
macrostep)) ; interactive macro expension inside eLisp
(global-pretty-mode)
(after 'redshank (diminish 'redshank-mode))
;; activate `emacs-slime-nav'
(dolist (hook '(emacs-lisp-mode-hook ielm-mode-hook))
(add-hook hook 'turn-on-elisp-slime-nav-mode))
;; `hl-sexp': prevent flickery behaviour as `hl-sexp-mode' unhighlights before each command
(after 'hl-sexp
(defadvice hl-sexp-mode (after unflicker (&optional turn-on) activate)
(when turn-on
(remove-hook 'pre-command-hook #'hl-sexp-unhighlight))))
(require 'derived)
(defun preamble/emacs-lisp-setup ()
"Enable features useful when working with elisp."
(elisp-slime-nav-mode)
(ac-emacs-lisp-mode-setup))
(defconst preamble/elispy-modes
'(emacs-lisp-mode ielm-mode)
"Major modes relating to elisp.")
(dolist (hook (mapcar #'derived-mode-hook-name preamble/elispy-modes))
(add-hook hook 'preamble/emacs-lisp-setup))
(add-to-list 'auto-mode-alist '("\\.emacs-project\\'" . emacs-lisp-mode))
(add-to-list 'auto-mode-alist '("archive-contents\\'" . emacs-lisp-mode))
(define-key emacs-lisp-mode-map (kbd "C-x C-a") 'pp-macroexpand-last-sexp)
(define-key emacs-lisp-mode-map (kbd "C-x C-e") 'pp-eval-last-sexp)
(auto-compile-on-save-mode)
(auto-compile-on-load-mode)
(require 'derived)
(defun preamble/lisp-setup ()
"Enable features useful in any Lisp mode."
(rainbow-delimiters-mode)
(enable-paredit-mode)
(turn-on-eldoc-mode)
(redshank-mode)
(hl-sexp-mode))
(defconst preamble/lispy-modes
(append preamble/elispy-modes
'(lisp-mode inferior-lisp-mode lisp-interaction-mode))
"All lispy major modes.")
(dolist (hook (mapcar #'derived-mode-hook-name preamble/lispy-modes))
(add-hook hook 'preamble/lisp-setup))
(defun preamble/maybe-check-parens ()
"Run `check-parens' if this is a lispy mode."
(when (memq major-mode preamble/lispy-modes)
(check-parens)))
(add-hook 'after-save-hook #'preamble/maybe-check-parens)
(preamble/require-packages '( crontab-mode
csv-mode
csv-nav
sql-indent ))
;; crontab
(add-to-list 'auto-mode-alist '("\\.?cron\\(tab\\)?\\'" . 'crontab-mode))
;; csv
(add-to-list 'auto-mode-alist '("\\.[Cc][Ss][Vv]\\'" . 'csv_mode))
(setq csv-separators '("," ";" "|" " "))
(after 'sql
(require 'sql-indent)
(when (package-installed-p 'dash-at-point)
(defun preamble/maybe-set-dash-db-docset ()
(when (eq sql-product 'postgres)
(setq dash-at-point-docset "psql")))
(add-hook 'sql-mode-hook 'preamble/maybe-set-dash-db-docset)
(add-hook 'sql-interactive-mode-hook 'preamble/maybe-set-dash-db-docset)
(defadvice sql-set-product (after set-dash-docset activate)
(preamble/maybe-set-dash-db-docset))))
(setq-default sql-input-ring-file-name
(expand-file-name ".sqli_history" preamble-dir))
;; save a list of open files in ~/.emacs.d/.emacs.desktop
; (setq desktop-path (list preamble-dir))
; (desktop-save-mode)
;; display time taken in restoring desktop
(defadvice desktop-read (around time-restore activate)
(let ((start-time (current-time)))
(prog1
ad-do-it
(message "Desktop restored in %.2fms"
(preamble/time-subtract-millis (current-time) start-time)))))
;; display time taken in restoring a buffer
(defadvice desktop-create-buffer (around time-create activate)
(let ((start-time (current-time))
(filename (ad-get-arg 1)))
(prog1
ad-do-it
(message "Desktop: took me %.2fms to restore %s"
(preamble/time-subtract-millis (current-time) start-time)
(when filename
(abbreviate-file-name filename))))))
;; restore histories and registers after saving
(preamble/require-package 'session)
(setq session-save-file (expand-file-name ".session" preamble-dir))
(add-hook 'after-init-hook 'session-initialize)
;; save a bunch of variables to the desktop file
;; for lists specify the len of the maximal saved data also
(setq desktop-globals-to-save
(append '((extended-command-history . 30)
(file-name-history . 100)
(ido-last-directory-list . 100)
(ido-work-directory-list . 100)
(ido-work-file-list . 100)
(grep-history . 30)
(compile-history . 30)
(minibuffer-history . 50)
(query-replace-history . 60)
(read-expression-history . 60)
(regexp-history . 60)
(regexp-search-ring . 20)
(search-ring . 20)
(comint-input-ring . 50)
(shell-command-history . 50)
desktop-missing-file-warning
tags-file-name
register-alist)))
(when (eval-when-compile (string< emacs-version "24.3.50"))
(unless (boundp 'desktop-restore-frames)
(preamble/require-package 'frame-restore)
(frame-restore)))
Version management is the heart of my projects, in particular, git. This section defines various settings so as to allow me to version control my projects from within Emacs’ Preamble.
(preamble/require-packages
'( magit ;; awesome git interface inside Emacs
git-blame ;; emacs frontend for `git-blame' tool
gitignore-mode ;; major mode for gitignore
gitconfig-mode ;; major mode for gitconfig
git-commit-mode ;; major mode for git commit
git-rebase-mode ;; major mode for git rebase
git-messenger ;; display why a line was changed as per git commits
git-gutter-fringe ;; display git status of lines in gutter
yagist ;; gist management
github-browse-file ;; view the file we're editing in Github
bug-reference-github ;; Automatically set bug-reference-url-format and enable
;; bug-reference-prog-mode buffers from Github repositories.
))
;; activate `bug-reference-github' in programming mode
(after 'bug-reference-github
(add-hook 'prog-mode-hook 'bug-reference-prog-mode))
Now, all I need is to setup magit as I intend it to perform inside my workflow.
(setq-default magit-save-some-buffers nil
magit-process-popup-time 10
magit-diff-refine-hunk t
magit-completing-read-function 'magit-ido-completing-read)
(after 'magit
;; don't let magit-status mess up window configurations
;; http://whattheemacsd.com/setup-magit.el-01.html
(defadvice magit-status (around magit-fullscreen activate)
(window-configuration-to-register :magit-fullscreen)
ad-do-it
(delete-other-windows))
(defadvice magit-quit-window (around magit-restore-screen activate)
ad-do-it
(jump-to-register :magit-fullscreen)))
;;; when we start working on git-backed files, use git-wip if available
(after 'vc-git
(global-magit-wip-save-mode)
(diminish 'magit-wip-save-mode))
When working on my Macbook Pro ‘13, I prefer my keys to work a bit differently, and want some opitons to behave differently. The following code summarises so:
(when *is-mac*
(setq-default locate-command "mdfind")
(setq mac-command-modifier 'meta)
(setq mac-option-modifier 'none)
(setq default-input-method "MacOSX")
;; make mouse wheel / trackpad scrolling less jerky
(setq mouse-wheel-scroll-amount '(0.001)))
;; when using cocoa-emacs
(when *is-mac-gui*
;; Woohoo!!
(global-set-key (kbd "M-`") 'ns-next-frame)
(global-set-key (kbd "M-h") 'ns-do-hide-emacs)
;; what describe-key reports for cmd-option-h
(global-set-key (kbd "M-ˍ") 'ns-do-hide-others)
(after-load 'nxml-mode (define-key nxml-mode-map (kbd "M-h") nil)))
(global-set-key (kbd "C-x C-m") 'execute-extended-command)
(global-set-key (kbd "C-c l") 'org-store-link)
(global-set-key (kbd "C-c a") 'org-agenda)
(global-set-key (kbd "C-c p") 'duplicate-line-or-region)
(global-set-key (kbd "C-f") 'ace-jump-char-mode)
(global-set-key (kbd "<mouse-4>") 'scroll-down-line)
(global-set-key (kbd "<mouse-5>") 'scroll-up-line)
(global-set-key (kbd "C-=") 'er/expand-region)
(global-set-key (kbd "C-x g") 'magit-status)
(global-set-key (kbd "C-c C-\\") '(lambda() (interactive) (indent-region (point-min) (point-max))))
(global-set-key (kbd "C-x v f") 'vc-git-grep)
(global-set-key (kbd "C-x v p") #'git-messenger:popup-message)
(global-set-key (kbd "C-c j") '(lambda()(interactive)(join-line -1)))
(global-set-key (kbd "M-x") 'smex)
(global-set-key (kbd "C-x o") 'switch-window)
; (global-set-key (kbd "C-c c r") 'set-rectangular-region-anchor)
; (global-set-key (kbd "C-c c c") 'mc/edit-lines)
; (global-set-key (kbd "C-c c e") 'mc/edit-ends-of-lines)
; (global-set-key (kbd "C-c c a") 'mc/edit-beginnings-of-lines)
(global-set-key (kbd "RET") 'newline-and-indent)
(global-set-key (kbd "<f7>") 'preamble/split-window)
(global-set-key (kbd "<f6>") '(lambda() (interactive)(switch-to-buffer nil)))
(global-set-key (kbd "C-x C-b") 'ibuffer)
(global-set-key (kbd "M-/") 'hippie-expand)
(global-set-key (kbd "C-x C-d") 'preamble/ido-choose-from-recentf)
(global-set-key (kbd "C-.") 'set-mark-command)
(global-set-key (kbd "C-x C-.") 'pop-global-mark)
;; multiple-cursors
(global-set-key (kbd "C-<") 'mc/mark-previous-like-this)
(global-set-key (kbd "C->") 'mc/mark-next-like-this)
(global-set-key (kbd "C-+") 'mc/mark-next-like-this)
(global-set-key (kbd "C-c C-<") 'mc/mark-all-like-this)
; key (kbd "M-Z") 'zap-up-to-char)
(global-set-key (kbd "C-M-=") 'preamble/increase-default-font-height)
(global-set-key (kbd "C-M--") 'preamble/decrease-default-font-height)
;; stop C-z from minimizing windows under OS X
(global-set-key (kbd "C-z") '(lambda ()
(interactive) (unless *is-mac-gui*) (suspend-frame)))
(when (and *is-mac* (fboundp 'toggle-frame-fullscreen))
;; Command-Option-f to toggle fullscreen mode
;; Hint: Customize `ns-use-native-fullscreen'
(global-set-key (kbd "M-ƒ") 'toggle-frame-fullscreen))
(global-set-key (kbd "M-C-8") '(lambda () (interactive) (adjust-opacity nil -5)))
(global-set-key (kbd "M-C-9") '(lambda () (interactive) (adjust-opacity nil 5)))
(global-set-key (kbd "M-C-0") '(lambda () (interactive) (modify-frame-parameters nil `((alpha . 100)))))
(global-set-key [remap query-replace-regexp] 'vr/query-replace)
(global-set-key [remap replace-regexp] 'vr/replace)
(after 'move-text (move-text-default-bindings))
(global-set-key [M-S-up] 'move-text-up)
(global-set-key [M-S-down] 'move-text-down)
(global-set-key [remap backward-up-list] 'backward-up-sexp) ; C-M-u, C-M-up
(global-set-key [remap open-line] 'sanityinc/open-line-with-reindent)
(global-set-key [remap query-replace-regexp] 'vr/query-replace)
(global-set-key [remap replace-regexp] 'vr/replace)
(global-set-key (kbd "C-M-<backspace>") 'kill-back-to-indentation)
Emacs’ Preamble is really smart! It can update itself, on the go.
(defun preamble/recompile-init ()
"Byte-compile all your dotfiles again."
(interactive)
(byte-recompile-directory preamble-dir 0))
(defun preamble/update ()
"Update Preamble to its latest version."
(interactive)
(when (y-or-n-p "Do you want to update Preamble? ")
(message "Updating Preamble...")
(cd preamble-dir)
(shell-command "git pull")
(preamble/recompile-init)
(message "Update finished. Restart Emacs to complete the process.")))
Things that need to be run at the end of the configuration have been specified here.
; (require 'init-locales)
(provide 'preamble)
;;; preamble.el ends here
Using HTMLize and FCI-mode together produces arbitrary garbage characters when this file is exported, in the source blocks.
- State “DONE” from “TODO” [2013-09-29 Sun 01:34]
(auto-fill-mode 't)
(global-linum-mode 1)
(xterm-mouse-mode 1)
(setq-default fill-column 100)
- State “DONE” from “TODO” [2013-10-22 Tue 16:34]
maybe we can use the function which prelude uses
- State “DONE” from “TODO” [2013-10-22 Tue 16:34]
This file should only be tangled when changes are detected to this file. This can be done by
generating MD5 hash of the current file, and then calling appropriate function to call either the
readme.el
or readme.org
for initialization purpose.
- State “DONE” from “TODO” [2013-10-22 Tue 16:35]
A hotkey should create a new *scratch*
buffer with mode set to the
current mode. Moreover, I should be able to press C-c C-c
to execute the
current line/expression there in (kinda like a repl within Emacs)
- State “DONE” from “TODO” [2013-10-22 Tue 16:35]
Can't preview LaTex fragment in a non-file buffer