Archive for March, 2009

Gaz asks:

Is there an easy way to select (via buffer-name regex or similar) a subset of terminals in elisp, and then squirt the same command into each one?

Sure Gaz, that sounds fairly straightforward. The shell wrappers already stores the terminal buffers in sw-buffers. We just need to think of how we want to select the buffers. And it probably doesn’t come as any surprise that I’m going to use ido.

Ido provides regex matching by pressing C-t or defining ido-enable-regexp. It also has flex matching with ido-enable-flex-matching and you can continuously refine selections using C-SPC. It really is amazingly cool.

Surprisingly, I couldn’t find a straightforward way of accessing the interim matches. Nor is there a hook that executes at selection time. Instead, we will override RETURN. Dynamic scoping means we can define an effectively global variable, sw-buffer-matches to store the interim matches for later use. Then, we iterate over these matches and send the command using term-simple-send.

We only want RETURN to be overridden for this particular usage of ido, so we set the keymap on the ido-setup-hook.

(defun sw-ido-save-matches ()
  (setq sw-buffer-matches ido-matches)

(defun sw-ido-my-keys ()
  (define-key ido-completion-map (kbd "RET") 'sw-ido-save-matches))

(defun sw-multi-cmd (&optional cmd)
  (interactive "sCommand: ")
  (let ((ido-setup-hook 'sw-ido-my-keys)
        (sw-buffer-matches ""))
    (ido-completing-read "choose buffers: " sw-buffers)
    (dolist (buffer sw-buffer-matches)
      (term-simple-send (sw-shell-get-process buffer) cmd))))

Read Full Post »

Nik Conwell posted about the Firefox extension mozex which reminds me I need to set that up. I imagine that this will combine nicely with the emacs client trick mentioned in windows and daemons.

I’ve started a mini-series on Emacs comint as I feel it deserves a lot more love than it gets, considering how incredibly useful it is.

Last year, emacs-fu wrote about extending ansi-term. My own recent post on wrapping ansi-term goes even further, configuring the mouse to auto-copy on highlight and using ido to quickly and easily switch between multiple shell buffers.

Still on the ansi-term topic, sadly it doesn’t work for me in windows. And by default, M-x shell starts a DOS prompt. martinez has a fix for this in NTEmacs although the following works a little better for me in EmacsW32 1.58.

(setq explicit-bash-args '("--login" "-i"))
(setq explicit-shell-file-name "c:/packages/cygwin/bin/bash")
(setenv "SHELL" explicit-shell-file-name)

(add-hook 'comint-output-filter-functions 'comint-strip-ctrl-m)

I can’t think of a time I would like to keep trailing whitespace. However, if you need it, flameyes has a solution to selectively remove it or keep it under different directories subtrees. This nicely demonstrates directory local variables (which have been mentioned by previous commenters on this blog).

Read Full Post »

I use both vim and emacs regularly1. For me, the most important difference between the two isn’t the modal/modeless thing. Nor is it even that emacs encourages working on multiple buffers within a single instance whereas vim users generally fire up a new instance for each file2.

No, what emacs has that vim does not is its superb handling of asynchronous processes.

The magic of comint

Comint is an emacs lisp library designed to simplify interaction with external interpreters. Here is an example of controlling a DOS prompt.

(require 'comint)

  (apply 'make-comint "cmd" "cmd" nil '())
  (switch-to-buffer-other-window "*cmd*")
  (other-window -1))

(comint-send-string (get-buffer-process "*cmd*") "dir\n")

And lo and behold, scroll up and scroll down work properly!

Sure, for a trivial example like this you would probably use dired, eshell or even my shell wrappers. However, in a similar way to expect, comint makes it easy to interact with anything that provides a stdin/stdout interface. The potential applications are limitless.

In my next comint post, I’ll show you how to interact with a simple subscriber.

1. Is that the sound of 90% of my readers leaving?

2. Yes, I’m aware that vim can work on multiple buffers. In my experience most vimmers (myself included) don’t work like that.

Read Full Post »

Emacs Buttons

Have you ever used emacs buttons? If you’ve used M-x grep then you have used similar functionality. When you click on one of the links it opens the file and goes to the appropriate line. If your mouse is hovering over the link then it highlights it.

How can you make your own button? First of all, you make a function that is called when you click the button.

(defun myfun (button)
  (message (format "Button [%s]" (button-label button))))

Then you make a button template. Buttons are actually made with an overlay that overrides the current keymap. By default, buttons run their action on button 2. I prefer left click so I set follow-link to true. You can make a hierarchy of button types using :supertype.

(define-button-type 'my-button
  'action 'myfun
  'follow-link t
  'help-echo "Click button")

Then insert the button using your template. These automatically highlight when your mouse is hovering over it.

(insert-text-button "xyz" :type 'my-button)

Read Full Post »

I spend a lot of time in the shell and I’ve never found a terminal emulator I really like. Konsole is okay, but the cut and paste is rubbish. PuTTY isn’t too bad either, but it doesn’t have tabs. Wouldn’t it be nice if there was something like PuTTY that gave me something similar to buffers in emacs?

You might be thinking that screen + PuTTY would work but that replaces some of the shortcuts I use all the time (C-a for example). Does eshell give me what I want? What about ansi-term?

Actually, ansi-term is pretty close to what I want. It also reconfigures some of the keys1 but I can easily fix that. So let me make a shortlist of the features I want:

  • fix the key bindings
  • get the mouse cut and paste working properly
  • Have a frame just for the shell
  • Have some kind of alias mapping to shells
  • Have multiple shells in different buffers

Let’s get started.

The #includes.

(require 'cl)
(require 'term)

Connecting to a remote host and a reasonable shell-like font.

(defconst sw-ssh "ssh -q -o StrictHostKeyChecking=no")
(defconst sw-shell-font "-*-courier new-*-r-*-*-18-*-*-*-*-*-iso8859-1")

Somewhere to store the frame for the shell and the buffers.

(defvar sw-frame nil)
(defvar sw-buffers nil)

Configuration variables: does the shell open in a name frame, and if the shell has exited for some reason do we keep it in the list?

(defvar sw-open-in-new-frame nil)
(defvar sw-remove-dead-terms t)

I like to build my software in layers. The lowest layer is the most primitive and provides functions to get processes if they exist and to kill buffers that don’t have a process.

(defun sw-shell-get-process (buffer-name)
  (let ((buffer (get-buffer (concat "*" buffer-name "*"))))
    (and (buffer-live-p buffer) (get-buffer-process buffer))))

(defun sw-get-process-if-live (buffer-name)
  (let ((proc (sw-shell-get-process buffer-name)))
    (and (processp proc)
         (equal (process-status proc) 'run)

(defun sw-kill-buffer-if-no-process (buffer-name)
  (let* ((buffer (get-buffer (concat "*" buffer-name "*")))
         (proc (sw-get-process-if-live buffer-name)))
    (when (and (not proc) (buffer-live-p buffer)) (kill-buffer buffer))))

(defalias 'sw-shell-exists-p 'sw-get-process-if-live)

The next layer provides two functions for wrapping basic buffer selection/creation. The plan is to ensure that there is a shell running in the buffer when the function finishes, but we don’t kill it if it exists already. Then there is another function that allows us to create or select a shell and send commands to it.

(defun sw-basic-shell (buffer-name)
  (sw-kill-buffer-if-no-process buffer-name)
  ;; If there is a process running, leave it, otherwise
  ;; create the new buffer
  (if (sw-shell-exists-p buffer-name)
      (message "Buffer already exists")
    (ansi-term "bash" buffer-name))
  (switch-to-buffer (concat "*" buffer-name "*")))

(defun sw-shell/commands (buffer-name &rest commands)
  (sw-basic-shell buffer-name)
  (let ((proc (sw-shell-get-process buffer-name)))
    (dolist (cmd commands)
      (term-simple-send proc cmd))))

This layer has methods for creating my standard shell locally (sw-standard-shell) and remotely (sw-server-login). I generally need to exec bash -l and su - after I’ve logged in. I could have done this in the .bashrc of course. You can adapt these start-up commands for your own usage.

(defun sw-standard-shell (buffer-name)
  (if (sw-shell-exists-p buffer-name)
      (switch-to-buffer (concat "*" buffer-name "*"))
    (sw-shell/commands buffer-name
                       "exec bash -l"
                       "su -")))

(defun sw-server-login (host &optional buffer-name)
  (setq buffer-name (or buffer-name host))
  (if (sw-shell-exists-p buffer-name)
      (switch-to-buffer (concat "*" buffer-name "*"))
    (sw-shell/commands buffer-name
                       (concat sw-ssh " " host)
                       "exec bash -l"
                       "su -")))

Set up my preferred colors and fonts.

(defun sw-set-display ()
  (set-background-color "black")
  (set-foreground-color "orange")
  (set-frame-font sw-shell-font))

I need to override a few keys. This should all be fairly obvious.

(defun sw-set-keymap ()
  (term-set-escape-char ?\C-z)
  (define-key term-raw-map "\C-c" 'term-interrupt-subjob)
  (define-key term-raw-map "\C-y" 'yank)
  (define-key term-raw-map (kbd "\M-x") 'execute-extended-command)
  (define-key term-raw-map "\e" 'term-send-raw)
  (define-key term-raw-map (kbd "") 'scroll-down)
  (define-key term-raw-map (kbd "") 'scroll-up))


I like highlighted regions to be automatically copied and to paste with the right-hand mouse button. This more-or-less works although it would need some tweaking to get it to send exactly the command you see on the screen.

;; Functions to get the mouse working more-or-less as I like it

(defun sw-mouse-paste-clipboard (click arg)
  (interactive "e\nP")
  (let ((proc (get-buffer-process (current-buffer))))
    (term-send-string proc (current-kill 0)))
  (setq deactivate-mark t))

(defun sw-mouse-copy-region-to-clipboard (click)
  (interactive "e")
  (mouse-set-region click)
  (let ((transient-mark-mode nil))
    (copy-region-as-kill (region-beginning) (region-end))))

(define-key term-raw-map

(define-key term-raw-map [mouse-3] 'sw-mouse-paste-clipboard)

Functions to read a buffer name from the user and select the shell-specific frame if we’ve set sw-open-in-new-frame.

(defun sw-read-buffer-name ()
  (when sw-remove-dead-terms
    ;; Remove dead terms before offering them to the user
    (setq sw-buffers (delete-if-not 'sw-shell-exists-p sw-buffers)))
  (let ((buffer-name
          "Choose buffer name: "

    (if (stringp buffer-name)
      (error "Invalid buffer name"))))

(defun sw-get-buffer-proc ()
  (sw-get-process-if-live (sw-read-buffer-name)))

(defun sw-select-frame ()
  (if (not sw-open-in-new-frame)
    (unless (frame-live-p sw-frame)
      (setq sw-frame (make-frame))
      (select-frame-set-input-focus sw-frame)
    (select-frame-set-input-focus sw-frame)))

This actually selects the buffer, reading the buffer-name from the user if necessary.

(defun sw-choose-buffer (&optional buffer-name)

  (unless (stringp buffer-name)
    (setq buffer-name (sw-read-buffer-name)))

  (unless (sw-shell-exists-p buffer-name)
    (sw-kill-buffer-if-no-process buffer-name)
    (setq sw-buffers (delete buffer-name sw-buffers)))

  (let ((already-existed t))
    (if (member buffer-name sw-buffers)
        (switch-to-buffer (concat "*" buffer-name "*"))
      (setq already-existed nil)
      (push buffer-name sw-buffers))

    (list buffer-name already-existed)))

And these are the top level commands – sw-open-shell and sw-open-remote-shell. They build on sw-standard-shell and sw-server-login respectively but read a buffer name and remote server name as appropriate.

(defun sw-open-shell (&optional buffer-name)
  (multiple-value-bind (buffer-name already-existed)
      (sw-choose-buffer buffer-name)
    (unless already-existed
      (sw-standard-shell buffer-name))))

(defun sw-open-remote-shell (&optional buffer-name server-name)
  (multiple-value-bind (buffer-name already-existed)
      (sw-choose-buffer buffer-name)
    (unless already-existed
      (unless (stringp server-name)
        (setq server-name (read-string "Server: " buffer-name)))
      (sw-server-login server-name buffer-name))))

(provide 'shell-wrappers)

And there we go. sw-shell/commands is generally useful for firing up shells and executing arbitrary commands. I use this all over the place.

Let me know if you have any tips or suggestions for improvement.

If you liked this post, why not subscribe to my RSS feed.

1.For example changing C-c to C-c C-c is very bad. One day I might need to kill that runaway rm -rf / command very urgently and maybe I’ll have forgotten that C-c is broken.

Read Full Post »

It has been two weeks since the last time I did a round-up of emacs news. That previous post is still 20th on emacs reddit. Is there really so little emacs-related news of note?

Mr Michael Will demonstrates how to fill a paragraph in SGML-mode where presumably there aren’t any convenient line breaks to prevent it from filling the entire buffer. I’d also mention C-x ( ... C-x ) to record a macro if it is something you’re doing a lot, or even add a binding to fill-region-as-paragraph.

beatak has a couple of useful beginner tips on his blog. I’ve added his code for versioned auto-save to my own start-up and he also has some notes an generating a tagfile generating a tagfile.

I have written far too much about emacs muse in the past couple of weeks, and part 1 and part 4 may be useful for beginners to muse.

I presented a way of compiling your start-up code when you run emacs to avoid the problem of emacs preferring compiled code over newer uncompiled code.

Marc Abramowitz wrote about remote compilation back in 2006 but he needs to fix his link to his rcompile patch. (it currently goes to marc-abramowitz.info).

There are posts on searching multiple buffers, emacs version control and emacs buttons within the same blog.

I’ve found another guy compiling emacs news.

Read Full Post »

Deriving Muse Styles

Following some useful comments from Peter Jones, I now have a better way to publish content for this blog – I can derive a style from html and selectively override the strings I want.

The definition of regex-replace is here.

The Constants

(defconst cur-src-prefix
  (concat "<pre style=\"font-size: 130%; border: 1px solid #bbb; "
          "background: #eee; overflow: auto; "
          "margin: 15px 5px; padding: 5px;\">"))

(defconst cur-code-prefix
  (concat "<code style=\"font-size:130%; "
          "background: #eee; padding: 3px;\">"))

(defconst curious-strings
  (list (cons 'begin-literal cur-code-prefix)
        (cons 'end-literal "</code>")))

Deriving The Style

(defun curious-htmlize ()
  (regex-replace "<pre class=\"src\">" cur-src-prefix))

(muse-derive-style "html-curious" "html"
                   :strings 'curious-strings
                   :after 'curious-htmlize)

Much nicer.

Although as far as I am aware, to get nicely font-locked code for Squidoo lenses I still need to add the extra hook as described in my earlier post. Any correction from muse users would be appreciated.

Read Full Post »

Older Posts »