Begin main content

Piping to an emacs buffer with emacsclient

GNU Emacs buffs will know all about emacsclient - it's a commandline program that allows you to open files in a new buffer in an already running emacs instance. It's very handy. What you may not know is you can also evaluate arbitrary Emacs lisp using emacsclient. Using this fact and based on an existing example from EmacsWiki I have written a perl script that you can pipe to, and the piped data will appear in a buffer via emacsclient.

My ultimate aim is for a PAGER script to use instead of less in my emacs shell. While this isn't quite perfect for that use, it's still pretty useful.

NB: The code below is probably out of date by the time you read this - see this gist for the latest version that you can clone, fork etc.

#!/usr/bin/perl

use strict;
use warnings;

use IO::Select;

my $emacsclient = "/usr/local/bin/emacsclient";

# This script uses emacsclient, be sure to have a running server session.
# A server-session can be started by "M-x server-start".

exit 1
    if 0 != system("$emacsclient -n --eval '(progn (pop-to-buffer (get-buffer-create \"*piped*\")))'");

my $s = IO::Select->new;
$s->add(\*STDIN);

while (1)
{
    # block until data available
    my $data = <STDIN>;

    # exit if STDIN closed
    exit(0)
        if ! $data;

    # keep reading while data is available, or we have a bunch of lines
    my $lines = 0;
    $data .= <STDIN>
        while $lines++ < 100 && $s->can_read(.5);

    $data =~ s/"/\\"/g;
    $data =~ s/'/'\\''/g;
    $data =~ s/\\/\\\\/g;
    system(qq{$emacsclient -n --eval '(with-current-buffer "*piped*" (goto-char (point-max)) (insert "}
            . $data . qq{"))'});
}

10:23 AM, 03 Mar 2011 by Mark Aufflick Permalink | Short Link | Comments (2)

Aquamacs copying styled text

Some time ago I switched from X11 GNU emacs to Aquamacs - the Aqua Mac native port of GNU emacs. The latest version of Aquamacs has a neat Edit menu item "Copy as HTML" which basically makes a convenient way to use the htmlize.el package to put a colourised version, in HTML format, of the current selection on the Mac clipboard.

That's great for posting into, for example, a blog post—but what about into other Cocoa apps? For that you still only need html, but it has to have the correct UTI on the clipboard to be recognised. The Aquamacs/GNU Emacs copy internals for the Mac nearly work flawlessly, and the following slightly hacky function will put a "Copy as Styled Text" into your edit menu:


(defun copy-as-styled-text (beg end)
  "Copies the region as HTML styled text into the clipboard."
  (interactive "r")
  (when (or (not transient-mark-mode) mark-active)
    (let ((x-select-enable-clipboard t)
      (buf (aquamacs-convert-to-html-buffer beg end)))
      ;; the copy as html is more reliable if we've copied plain text first
      ;; (which seems to clear the clipboard of all types)
      (with-current-buffer buf
    (copy-region-as-kill (point-min) (point-max)))
      (with-current-buffer buf
        (ns-store-cut-buffer-internal 'PRIMARY (buffer-string) 'html))
      (kill-buffer buf))))

(define-key-after menu-bar-edit-menu [copy-styled]
  '("Copy as Styled Text" . copy-as-styled-text) 'copy-html)

07:33 PM, 24 Sep 2010 by Mark Aufflick Permalink | Short Link | Comments (0)

Ruby, HTML, s-expressions, lambdas? Oh my!

I've been noodling around with various lisps lately, and one of the sources of lisp's elegance is the lack of separation between data and code. A practical example of that is the cl-who library which creates html from an s-expression representation, ensuring all tags are correctly closed. For example:

(with-html-output (*http-stream*)
  (loop for (link . title) in '(("http://zappa.com/" . "Frank Zappa")
                                ("http://marcusmiller.com/" . "Marcus Miller")
                                ("http://www.milesdavis.com/" . "Miles Davis"))
        do (htm (:a :href link
                  (:b (str title)))
                :br)))

There are a number of ways to replicate this style in other languages. You can do it by building up a big string, but I want to print to a stream like the example above. Using lambdas we can make a pretty good approximation in Ruby. Here's some Ruby code using a simple module I whipped up (see below) to achieve the same output as the cl-who lisp code above:

engines = [["http://google.com/", "Google"],
           ["http://yahoo.com/", "Yahoo!"],
           ["http://webcrawler.com/", "Showing my age"]]

Htm.htm(engines.map { |e| Htm.htm(:a, :href, e[0], [:b, Htm.str(e[1])],
                                :br, nil)}).call

Lets say we realise that the br tags are nasty and want to put the list of links into a list:

Htm.htm(:ul, engines.map \
        { |e| Htm.htm(:li,
                      [:a, :href, e[0], [:b, Htm.str(e[1])]])}).call

It's not quite as elegant as the lisp equivalent because we are mixing lambdas and arrays - both as nesting constructs. Here is the final output (indented for clarity - the Htm module below does no indenting):

<ul>
  <li><a href="http://google.com/"><b>Google</b></a></li>
  <li><a href="http://yahoo.com/"><b>Yahoo!</b></a></li>
  <li><a href="http://webcrawler.com/"><b>Showing my age</b></a></li>
</ul>

Now even though we are controlling the order of execution such that the various parts will be printed to the stream in the right order, we still can't print until we have closed our outermost tag (usually html). To be able to stream output while also auto-closing the tags we're going to need to use continuations - I'll cook up an example of that for a later blog. There's also other neat ways we can have self-closing tags that will allow streaming - I'll post about that later also.

Here is the Htm module in full:

require 'cgi'

module Htm
  def Htm.str(content)
    lambda { print CGI.escapeHTML(content.to_s) }
  end

  def Htm._build_tag(tag, args)

    # open the tag
    print '<' + tag.to_s

    tok = args.shift

    # find any tag attribute key/value pairs
    while tok.kind_of? Symbol
      print ' ' + tok.to_s + '="' +
        CGI.escapeHTML(args.shift.to_s) + '"'
      tok = args.shift
    end

    if tok.nil?
      # self-close tag if no content
      print ' />'
    else
      # finish open tag
      print '>'

      # output tag content
      Htm._eval_content(
                        tok.kind_of?(Symbol) ? Htm.htm(tok, args) : tok )

      # close tag
      print '</' + tag.to_s + '>'
    end
  end

  def Htm._eval_content(content)
    while content.kind_of? Proc
      content = content.call
    end

    if content.kind_of? Array
      Htm._eval_content(Htm.htm( *content ))
    elsif ! content.nil?
      print content
    end
  end

  def Htm.htm( *args )
    lambda do

      tok = args.shift

      while ! tok.nil?
        if tok.kind_of? Symbol
          Htm._build_tag(tok, args)
        else
          Htm._eval_content(tok)
        end
        tok = args.shift
      end
    end
  end
end

09:13 PM, 06 May 2009 by Mark Aufflick Permalink | Short Link | Comments (0)

XML

Blog Categories

software (39)
..cocoa (21)
  ..heads up 'tunes (5)
..ruby (6)
..lisp (3)
..perl (4)
..openacs (1)
mac (20)
embedded (2)
..microprocessor (2)
  ..avr (1)
electronics (3)
design (1)
photography (25)
..black and white (6)
..A day in Sydney (18)
..The Daily Shoot (6)
food (2)
Book Review (2)

Notifications

Icon of Envelope Request notifications

Syndication Feed

XML

Recent Comments

  1. Unregistered Visitor: An other Script
  2. Unregistered Visitor: A message in there?
  3. Unregistered Visitor: using Amazon S3
  4. Unregistered Visitor: Thank you ! Thank you ! Thank you !
  5. Unregistered Visitor: Umbrello on leopard
  6. Unregistered Visitor: Script gor generate for library
  7. Unregistered Visitor: Similar but different
  8. Unregistered Visitor: Thanks for fixing my problem!
  9. Unregistered Visitor: Pop up once the category is been defined
  10. Unregistered Visitor: smal amendment