Archive for the ‘Emacs’ Category

Remote Killing from Emacs

Previously, I’ve talked about integrating little perl "services" into emacs that read from stdin and write to stdout.

Sometimes the processes that make up your emacs application are running on different servers, picking up various pieces of information and it might be necessary to kill them independently or in groups. By default, comint binds C-c C-c to SIGINT, but if you have a moderately complex application, you don’t want to go through each comint buffer and kill the processes individually.

Each of your perl scripts needs to output the PID and the server it is running on.

use Sys::Hostname;
my $hostname = hostname();

print "Started PID $$ on $hostname\n";

Then the emacs application code needs to use a filter to read that information into a couple of variables.

(defvar proc-pid nil)
(defvar proc-host nil)

(defconst *re-match-pid-host*
  "Started PID \\([0-9]+\\) on \\([a-z0-9]+\\)")

(defun proc-filter (output)
  (when (string-match *re-match-pid-host* output)
    (setq proc-pid (match-string 1 output))
    (setq proc-host (match-string 2 output)))

(add-hook 'comint-preoutput-filter-functions 'proc-filter)

Running commands remotely is easy with ssh. (Incidentally, how does this work in windows-land?)

(defconst *ssh* "ssh -o StrictHostKeyChecking=no")

(defun kill-proc ()
  (let ((cmd (format "%s %s kill %s" *ssh* proc-host proc-pid)))
    (message cmd)
    (message (shell-command-to-string cmd))))

I’ve demonstrated the make-comint code previously.

(defun start-proc ()
  (let ((buffer (get-buffer "*stdin-proc*")))
    (when buffer (kill-buffer "*stdin-proc*")))
  (apply 'make-comint "stdin-proc" "perl" nil
         (list "./test-stdin.pl")))

And the result is as expected.

Started PID 5008 on saturn

Process stdin-proc terminated

Read Full Post »

Living Without Emacs

I have integrated emacs into most parts of my daily workflow. In a typical day I might need to:

Some of these I have aliases for in my shell already.

A number of database GUIs have template functionality built-in or I could probably substitute the sql templates with scripts if I was sufficiently creative with the command line args.

And if I kept my TODO/Notes list in a wiki, it might be generally useful to the rest of my team.

Yes, thinking about it, I could live without Emacs. But life would be much less pleasant.

Read Full Post »

Clever Emacs Lisp

Here’s another clever trick. Don’t embed the data together with the logic, as I do with my directory aliases. Save it in a separate file and load it in using (read).

Okay, it’s not that clever – I do it all the time in Perl using YAML and what-not. Slightly concerning, though, is that I didn’t automatically translate the knowledge gained from Perl to lisp. What was I thinking?

The code fragment is beautiful:

(defvar variable-name)

  (insert-file-contents-literally <filename>)
  (setq variable-name (read (current-buffer))))

Read Full Post »

Finding Useful Posts

One of the weaknesses of many blogs, including my own, is the difficulty of finding old, useful articles. There are a few ways to find articles written previously, such as the Archives, the categories and the tags. But to be honest, a lot of the stuff I write is only relevant (at best) at the time of publishing. And even I have difficulty finding my useful posts again.

There are several possible solutions, e.g. I could tag pages within delicious as curiousprogrammer/useful. For the moment, I’ve decided to keep a blog highlights page, and list the posts which are useful for me. Later on I might try a more comprehensive index.

Read Full Post »

As Emacs is open source, we don’t need to speculate. We can just read the code. I’m lazy though, so I prefer to speculate ;) If you were making a text editor, what would you use for your buffer type?

Array of Chars

The obvious, naive choice is an array of chars. But that means that, while append may be fast (until you need to resize your array at least), insertion is very slow. To insert a character in the middle of an array of chars, you need to move all of the characters following the insertion point up by one character. If we assume that insertions are evenly distributed, inserting a character will take, on average, time proportional to N/2.

Queue up Inserts

We can be a bit smarter than that. With normal text editor usage, for any given insert, we will probably insert a bunch of characters in the same place. We could append those characters into a preallocated array, and after a certain amount of time or number of characters, insert those characters into the array of chars. This brings the amortized speed cost down to N/M/2 where M is the average number of characters inserted in one go.

A Tree of Characters

So much for arrays. How about a tree? Assuming the tree, is balanced, insertion will take log2 N. The downside is that traversal is a lot slower (still order N, but a decent constant factor slower). And we are also likely to lose cache locality.

Side note: I often surprised that the main ‘scripting’ languages don’t provide much more than the equivalent of perl scalars, arrays and hashes. Sure, Python has tuples and Ruby has symbols (okay, I do miss symbols in Perl), but where are the built-in trees? Even Lisp has them. I had a quick look for trees in the CPAN and found Tree::Binary and Tree::RedBlack. I couldn’t find at a quick glance whether Tree::Binary self-balances or not. Hmmm…

A Rope

The final simple option is a rope (PDF). This is a binary tree where the leaves, instead of being characters, are arrays of characters. This improves cache locality (depending on the average size of the array), and traversal speed, although it isn’t as fast as a simple array of characters.

What would you use?

Read Full Post »

When I set up an emacs process filter, I never know how much input the process will deliver me at one time. Therefore I generally buffer the input and process (say) a line at a time.

(defvar buffer "")

(defun process-input (input)
  (setq buffer (concat input buffer))
  (let ((count 0)
        (pos 0))
    (while (string-match "^\\([^\n]+\\)\n" buffer pos)
      (message "Before: [%s] [%d]" (match-string 1 buffer) (match-end 1))
      (process-line (match-string 1 buffer))
      (message "After: [%s] [%d]" (match-string 1 buffer) (match-end 1))

      ;; error handling in case of runaway loops
      (incf count)
      (when (> count 10)
        (error "Looped too many times!"))

      (setq pos (1+ (match-end 1))))
    (when pos (setq buffer (substring buffer pos))))
  (message "REMAINDER: [%s]" buffer))

Given a simple (process-line ...) we can see the results from a simple test.

(defun process-line (line)
  (message "[%s]" line))

(process-input "XXX (line 1)\n13.15 (line 2)\n")
Before: XXX (line 1) 12
[XXX (line 1)]
After: XXX (line 1) 12
Before: 13.15 (line 2) 27
[13.15 (line 2)]
After: 13.15 (line 2) 27

An Infinite Loop

Now say I want to add some special handling for lines with a number in, what do you think happens?

(defun process-line (line)
  (when (string-match "\\([0-9]+\.[0-9]+\\)" line)
    (message "[%s]" line)))
Debugger entered--Lisp error: (error "Looped too many times!")
Before: [XXX (line 1)] [12]
After: [XXX (line 1)] [12]
Before: [13.15 (line 2)] [27]
[13.15 (line 2)]
After: [XXX (] [5]
Before: [13.15 (line 2)] [27]
[13.15 (line 2)]
After: [XXX (] [5]

The string match against the number has reset a hidden global variable used by (match-end ...) which has sent us into an infinite loop. Surprising action at a distance indeed!

Perl Regex Globals

Perl also uses global variables such as $1, $2, @- and @+ for its regular expressions, so could this cause a similar problem?

No. Fortunately, these globals are dynamically scoped so the appropriate values are maintained up the call stack.

Read Full Post »

Lisp Macros and Types

(message ...) already accepts a format string, but if it didn’t it would be easy to add that functionality with a macro.

(defmacro message* (str &rest vars)
  `(message (format ,str ,@vars)))

But it only accepts a single format string. Perhaps I would like to concatenate a few strings or variables together. But then if I only pass a string in, I want that to work correctly too. Macros can generate different code if you pass in different types. (I fix the underlying format* so I can use it in message, error, etc.)

(defmacro format* (str &rest vars)
  (if (stringp str)
      `(format ,str ,@vars)
    `(format (concat ,@(mapcar #'identity str)) ,@vars)))

The result looks a little strange. When I see an unquoted list, the first element has to be the name of the function that is being called.

(defvar x "xxx")
(format* (x " " "%s") 1) ;; --> "xxx 1"

Read Full Post »

Bad Hash Tables

Quick pop quiz. In emacs lisp what does this expression evaluate to?

(let ((%h (make-hash-table)))
  (puthash "key" "value" %h)
  (gethash "key" %h))

Okay, put your hands down, the lispers at the back. Anyone else?

That’s right, the answer is nil.

"Eh nil? Is that the same as false? Why’s that?" you may be asking. The answer is that by default hash tables use eql as the comparison function. (eql "x" "x") evaluates to nil. (equal "x" "x") evaluates to t.

What you actually want is this.

(let ((%h (make-hash-table :test 'equal)))
  (puthash "key" "value" %h)
  (gethash "key" %h))

Quite why you would want a hash where you can’t retrieve a string key is beyond me. Okay, I guess it possibly makes sense if you consider symbols, but damn, it’s not right.

Anyway, no worries, I can fix it. I’ll only ever use my _h macro rather than using make-hash-table, puthash or gethash directly, and I’ll extend it to create hash tables using :test 'equal.

(the original title for this page was Why do Emacs Lisp Hash Tables use Eql)

Read Full Post »

A while ago, I was trying to work around the emacs maintainers’ curious decision to always load a .elc file in preference to a .el file, even if the .el file is newer.

I didn’t want to settle for that. My solution was to recompile my emacs lisp files prior to running emacs.

I see now that there is a better alternative: replace the built-in require with my own version. And it is not just because it is open source that I can do this. I can fix it as a user too.

(require feature &optional filename noerror)

require performs the following steps:

  • do nothing if the feature has already been loaded (this protects against recursive loads)
  • finds the appropriate file in load-path
  • loads either the .el or .elc file
  • throws an error if the required feature is not provided
  • provides a mechanism for supressing errors
  • provides a mechanism to load a feature from a specific file

If I wanted a drop-in replacement, I should do all of those things, and replicate the function signature. However, I don’t need the error suppression or loading from a specific file. I also like to be able to force a load even if a library has been loaded previously. If this doesn’t match your requirements, it should be easy to adapt the code below.

(defun require* (feature &optional force)
  (when (or force (not (featurep feature)))
    (setq feature (symbol-name feature))
    (let ((path load-path)
          (found-filename nil)
          head el-attribs elc-attribs)
      (while (and (not found-filename) path)
        (setq head (pop path))
        (let ((el-filename (format "%s/%s.el" head feature))
              (elc-filename (format "%s/%s.elc" head feature)))
          ;; if .el and .elc both exist, pick the newest
          ;; otherwise pick the one that exists if any
          (cond ((and (file-exists-p el-filename)
                      (file-exists-p elc-filename))
                 (if (file-newer-than-file-p el-filename elc-filename)
                     (setq found-filename el-filename)
                   (setq found-filename elc-filename)))
                ((file-exists-p el-filename)
                 (setq found-filename el-filename))
                ((file-exists-p elc-filename)
                 (setq found-filename elc-filename)))
          ;; load file if found
          (when found-filename
            (message (format "Found: [%s]" found-filename))
            (let ((load-suffixes ()))
              (load found-filename)))))
      (unless found-filename (error "Unable to find %s" feature)))))

The brave might choose to do (defun require ...) instead of (defun require* ...)

Read Full Post »

Why Not Hashes

Someone asked me, why with all of the associated problems does emacs lisp use vectors rather than hashes to represent objects.

There are three reasons that come immediately to mind.

  • speed efficiency
  • space efficiency
  • you generally need to know the type anyway

Speed Efficiency

(person-age dave) ultimately expands to (aref dave 1) which is an array access. Array access and hash access should both be O(1) operations. However, the k for hash access will be much greater.

First of all, you need to call the hash function. Even if that is just mod [size of hash] that will probably more than halve the speed. And then you have collision handling on top of that.

Space Efficiency

A default hash table starts with 65 slots.

(make-hash-table) ;; --> #<hash-table 'eql nil 0/65 0x298a880>

That is quite a lot of overhead for an object with just a few fields. You can select a different initial size, but as you might expact, a hash does take more space than a similarly sized vector.

You Need to Know the Type Anyway

In practice, you need to know the type of an object before you can do anything useful with it. Say I have a variable called dave. How do I know if I can fire dave unless I know that dave is of type employee?

Can you think of any operation you can do on a variable without knowing the type? Stringify perhaps.

So, why was I making a big deal before?

Not having to know the exact type can give you a degree of genericity. I can have a whole bunch of things related to people that I can call age on. Maybe I’ll have an iterator field in a bunch of containers called iterator.

But really, I don’t care about that. I’m into aesthetics and I just like a terse language. I just find, dave.age, or even (*s dave.age) is much nicer than (person-age dave).

Read Full Post »

Older Posts »


Get every new post delivered to your Inbox.