среда, 20 ноября 2013 г.

Emacs interractive functions for everyday use.

Abstract


Working with source files I prefer having all the white spaces and non viewable symbols being actually visible to me. This is useful to not mix spaces and tabs in source code, not leave trailing spaces, and especially handy it became when I had to work with yml files. They are very sensitive to tabs - files were just not imported by ruby library without meaningful message.
So, whitespace mode is permanent for my workspace in emacs. But there are people, who are not so pedantic to this question. Especially eclipse users (developers, they call themselves some times ;) ). Result is that opening simple .java file I get ton of red-highlighted trailing tabs and spaces, and I have to clean them somehow.
Any developer can solve this trouble with single regular expression, and we will watch how easy this is in emacs, using emacs lisp.

Disclamer

First, people who use eclipse can be good developers.
Second, I believe there is better solution in emacs to fight with trailing garbage, but I did not find it yet. And actually the fact that I can write this kind of functionality on the fly in emacs, makes it choice of mine.

Phase 1. Develop.

First, we have to check if our regexp works well, and would be good to evaluate future code just now. Emacs allow us to do that. M-: shortcut spawns "Eval:" prompt for us, so we can just put our code there. We just push
Eval: (replace-regexp "[\s\t]+$" "")
As we can see - all the trailing spaces are gone!

Phase 2. Integrate.

Now, we would love this piece of code to:
  1. Be available on the fly.
  2. Run every time when we open java source code.

Emacs load routine

First, we have to know, what emacs runs when it is started. ~/.emacs.el it is. Second, where should we put our custom code? ~/.emacs.d/ it is.
So, let's say, we will work on file ~/.emacs.d/whitespace-killer.el and load it using:
< style="background-color: black;">01 (add-to-list 'load-path "/home/dima/.emacs.d/")
02 (load "whitespace-killer")


First line of this code should be already present in your config file. It might differ - move you file with custom code accordingly, or you can add this line as well - this will not harm.
Second line loads .el file from available 'load-path alist. Read about alists.

Interactive functions

Inside whitespace-killer.el file we can define our function:
01 (defun kill-whitespaces()
02   (interactive)
03   "Removes all trailing spaces in the current buffer."
04   (replace-regexp "[\s\t]+$" "")
05   )

On the first line we define our function with the name, we wish to refer it.
Second line says to emacs that this function will be exported to use together with M-x family of calls. Basically, after this we can call it by typing:
M-x kill-whitespaces
Third line is optional, it is called document line. Emacs documentation tools use it to describe functionality of the function.
Next, goes body of the function. It is not flawless. Among it's drawbacks we can outline the fact, that it will be applied to code only after the current caret position. Other pretty bad thing, is that it actually leaves cursor after the last replacement.
These bugs are not a big deal, we can easily over come them. But we are not interested in this right now.

Hooks

As java file is opened, so-called java-mode-hook is fired. We can stick to it, and run arbitrary code:
(add-hook 'java-mode-hook 'kill-whitespaces)
So, next time you open java file - you will see no trailing whitespaces.

Phase 3. Debug.

What if emacs does not want to load after you do all the instructions? This happens, don't worry, just add --debug-init flag to emacs invocation command:
[dima@work java-project]$ emacs --debug-init Some.java
Observe the output:
Debugger entered--Lisp error: (file-error "Cannot open load file" "whitespace-killerff")
  load("whitespace-killerff")
  eval-buffer(#<buffer  *load*> nil "/home/dima/.emacs.el" nil t)  ; Reading at buffer position 1060
  load-with-code-conversion("/home/dima/.emacs.el" "/home/dima/.emacs.el" t t)
  load("~/.emacs" t t)
  #[0 " \205\262

and fix the problem. This time I don't have file whitespace-killerff, well, this happens - just rename the file, or fix typo.

Final code.

01 (defun kill-whitespaces() 
02   (interactive) 
03   "Removes all trailing spaces in the current buffer." 
04   (save-excursion
05     (goto-char 1)
06     (replace-regexp "[\s\t]+$" "")))

Useful links

[1] Hooks
[3] Alists

Комментариев нет:

Отправить комментарий