Posts Tagged ‘elisp’

Refactoring Configurations

Wednesday, July 29th, 2009

I felt my init.el file was getting too bloated, so I ended up doing a fair amount of refactoring on it. I moved essentially all the code from init.el into a few directories I made in .emacs.d. Structuring your customizations is pretty important if you ever either need to go back to change them or find them to suggest to others; I do both of these a fair amount, so I spend a fair amount of time organizing my files. I probably ended up erring on the side of too many horizontal files, but I think it should be OK for now.

My .emacs.d directory now has four main elisp directories: customizations, major-modes, minor-modes, and utilities. It also has temporary information, documentation, Clojure, and hopefully everything I need to just be able to check it out and have my full working setup. The customizations and utilities directory are currently flat; They contain small files described for what they modify or are for. For example, the Ibuffer customizations I recently suggested are in ibuffer.el. This does sometimes pose organizational problems; Should changing an variable customizing a minor-mode on entering a major-mode be a customization of the minor-mode or major-mode? I currently go for the major-mode, but this could change if I ever have problems finding anything.

Major-modes and minor-modes contain precisely what they describe; All the major and minor modes I have downloaded. Packages that modify other major modes, such as dired+, do not go in these directories; they still go in the customizations file. These two directories can be arbitrarily nested - I just put the modes in however they are distributed.

After moving all the customizations out of init.el, I had the following left:

(let ((default-directory "~/.emacs.d/"))
  (add-to-list 'load-path default-directory)
  (normal-top-level-add-subdirs-to-load-path))
 
(defun load-directory (dir)
  (mapcar '(lambda (x)
             (load-file x))
          (directory-files dir t "\\.el$")))
 
(load-directory "~/.emacs.d/customizations/")
(load-directory "~/.emacs.d/utility/")

The first let expression is a simplification of something I blogged about a while ago; It will add all subdirectories of ~/.emacs.d/ to the load-path; this is necessary so that I don’t have to do manual manipulation of the load-path.

The second function is one I wrote to support my refactorings. It will load every elisp file in a directory. It doesn’t support subdirectories, but this wouldn’t be too hard to add if I ever need it. I then just load up my customizations and utility functions and am good to go. I highly recommend doing something similar to this; Splitting your customizations from one big file and aggregating similarities makes it much easier to manage your configuration.

Emacs Utility Functions

Saturday, July 25th, 2009

I’ve ended up migrating a few of my old functions back to my new setup, as well as creating a few newer ones. These are the ones I’ve added recently - maybe they’ll be useful to you, as well.

I’ve been doing a few book reviews recently, and instead of having to manually add in links I just wrote a function to generate a link based on the ASIN I give it. If you end up using something like this, you’ll probably want to change it so that it links to your Amazon Associate’s account, although I won’t complain if you don’t.

(defun insert-amzn-product (asin)
  "Inserts a link(image + text to an Amazon product using the ASIN"
  (interactive "MAsin:")
  (insert
   (concat "<iframe src=\"http://rcm.amazon.com/e/cm?t=randmusiofaso-20"
           "&o=1&p=8&l=as1&asins="
           (replace-regexp-in-string "\\n" "" asin)
           "&fc1=000000&IS2=1&lt1=_blank&m=amazon&lc1=0000FF&"
           "bc1=000000&bg1=FFFFFF&f=ifr\" style=\"width:120px;height:240px;\""
           "scrolling=\"no\" marginwidth=\"0\" marginheight=\"0\""
           "frameborder=\"0\"></iframe>")))

I like to be able to know how many words are in a buffer, so I found the following function somewhere online. It just runs ‘wc -w’ as a shell command on the contents of the current buffer, which outputs the number of words.

(defun wc nil
  "Count words in buffer"
  (interactive)
  (shell-command-on-region (point-min) (point-max) "wc -w"))

I sometimes use different editors on the same files, and end up having broken indentation a lot of the time this happen. I wrote iwb (for indent-whole-buffer) to fix indentation problems.

(defun iwb ()
  "Indents the entire buffer"
  (interactive)
  (indent-region (point-min) (point-max) nil))

This function I picked up from Steve Yegge’s blog. It prompts for a directory and then moves the buffer you are editing and the associated file to that directory

(defun move-buffer-file (dir)
  "Moves both current buffer and file it's visiting to DIR."
  (interactive "DNew directory: ")
  (let* ((name (buffer-name))
	 (filename (buffer-file-name))
	 (dir
	  (if (string-match dir "\\(?:/\\|\\\\)$")
	      (substring dir 0 -1) dir))
	 (newname (concat dir "/" name)))
    (if (not filename)
	(message "Buffer '%s' is not visiting a file!" name)
      (progn
	(copy-file filename newname 1)
	(delete-file filename)
	(set-visited-file-name newname)
	(set-buffer-modified-p nil) 	t))))

Imenu

Thursday, July 16th, 2009

Imenu is a built-in emacs package for navigating around source files. It is a feature that allows you to jump around by scanning on predefined regex’s - mostly to variable of function declarations. Imenu is very useful for quickly navigating around a source file - I recommend you start using it whenever you need to navigate to a different function in the same file. The default for imenu is to use emac’s built in completion for variables; however, I much prefer using ido’s completion, and for that you need the following commands and function in your initialization file:

(require 'imenu)

This just allows you to use the imenu commands.

(defun ido-goto-symbol ()
  "Will update the imenu index and then use ido to select a symbol to navigate to"
  (interactive)
  (imenu--make-index-alist)
  (let ((name-and-pos '())
	(symbol-names '()))
    (flet ((addsymbols (symbol-list)
		       (when (listp symbol-list)
			 (dolist (symbol symbol-list)
			   (let ((name nil) (position nil))
			     (cond
			      ((and (listp symbol) (imenu--subalist-p symbol))
			       (addsymbols symbol))
			      ((listp symbol)
			       (setq name (car symbol))
			       (setq position (cdr symbol)))
			      ((stringp symbol)
			       (setq name symbol)
			       (setq position (get-text-property 1 'org-imenu-marker symbol))))
			     (unless (or (null position) (null name))
			       (add-to-list 'symbol-names name)
			       (add-to-list 'name-and-pos (cons name position))))))))
      (addsymbols imenu--index-alist))
    (let* ((selected-symbol (ido-completing-read "Symbol? " symbol-names))
	   (position (cdr (assoc selected-symbol name-and-pos))))
      (if (markerp position)
	  (goto-char position) (goto-char (overlay-start position))))))

This is the function that uses ido for imenu. Since imenu occasionally has multiple levels - you select whether you want functions or variables, etc - this loops through all those sublists and adds all possibilities to a list. Once the list is compiled, it prompts you using ido for which definition you want to go to.

(setq imenu-auto-rescan t)

This just ensures that whenever you call imenu or the new function ido-goto-symbol you get the latest information, and not only functions which may have been cached.

(global-set-key (kbd "M-s") 'ido-goto-symbol)

I use this function quite frequently, so I rebound it to M-s. M-s is usually a prefix key for a few commands, but the only one I use that this interferes with is occur, but I use that rarely enough that I’m fine with just having to M-x occur. I use ido-goto-symbol enough that I really want it to be as few key presses as possible, so using something like M-s M-s would be pretty irritating.

Summing Columns in Emacs

Wednesday, April 15th, 2009

I recently noticed that I had to do one task in Emacs a fair amount, so I decided to write some code so that I didn’t have to do it manually.

(defun sum-column()
  "Sums a column of numbers starting at point"
  (interactive)
  (save-excursion
    (if (and (not (= (current-column) 0))
	     (re-search-backward "[ \t]" 0 t ))
	(forward-char))
    (let ((retn 0)
	  (old-column (current-column))
	  (old-next-line-add-newlines))
      (setq next-line-add-newlines nil)
      (while (not
	      (looking-at "^[ \t]*$"))
	(move-to-column old-column t)
	(if (and (looking-at "-?[0123456789]+")
		 (eq (current-column) old-column))
		(setq retn (+ retn (string-to-number (current-word)))))
	(next-line)
	(beginning-of-line))
      (next-line)
      (next-line)
      (move-end-of-line 0)
      (inse rt (make-string (- old-column (current-column)) 32))
      (insert (number-to-string retn))
      (setq next-line-add-newlines old-next-line-add-newlines)
      retn)))

This function will sum a column of numbers in a buffer when the point is at the start of them. It will insert the total after the first whitespace-only line, aligned with the rest of the numbers. For example, the following text

10
20
40

Will be replaced with:

10
20
40

70

This works even for columns that are not at the left column of the screen, so

foo 10
bar 20
baz 40

Becomes

foo	10
bar	20
baz	40

	70

If you have multiple columns, you can sum them up individually:

10	20
30	40
50	60

After two calls to sum-column, this becomes:

10	20
30	40
50	60

90	120

Enjoy!