Tuesday, December 16

More Emacs Help

As well as keying the help provided by Google in Emacs to the major-mode, it's possible to use it with multiple libraries as well. For instance, the following snippet lets me look up documentation for one library (OGRE) by pressing 'o' and for another by pressing 'a' , rather like the Slime selector, discussed previously. It's a huseful way of pulling together doxygen API documentation when working on clonk-loads of libraries, as is all to typical of C++ or Java development.


(defun search-site-url (keyword &optional site inurl lucky)
"Do a Google search for KEYWORD. Restrict to SITE and INURL, if specified.
Jump to best match (I Feel Lucky) if LUCKY set.
"
;; (message (list keyword site inurl lucky))
(concat "http://www.google.com/"
(format "search?q=%s" (url-hexify-string keyword))
(if site (format "+site:%s" (url-hexify-string site)))
(if inurl (format "+inurl:%s" (url-hexify-string inurl)))
(if lucky "&btnI")))


(defun help-selector ()
(interactive)
(message "Select [%s]: "
(apply #'string (mapcar #'car help-selector-methods)))
(let* ((ch (save-window-excursion
(select-window (minibuffer-window))
(read-char)))
(params (find ch help-selector-methods :key #'car)))
(browse-url (apply #'search-site-url (thing-at-point 'symbol) (list (third params) (fourth params) (fifth params))))))

(defvar help-selector-methods '(( ?a "Assimp"
"assimp.sourceforge.net" "/lib_html/" t)
( ?o "Ogre"
"www.ogre3d.org" "/docs/api/html/" t)
( ?w "WxWidgets"
"docs.wxwidgets.org" "/stable/" t)))

(global-set-key [(shift f1)] 'help-selector)

Thursday, August 21

Lambda of the Daleks


As promised, the Daleks appear. They have been loaded dynamically from an md2 whilst the framework was running. Sometimes I find myself fighting my C++ reflexes. There's no need to bring the framework down in order to change it. It still seems like magic when I edit a function definition, compile it and *bam* the change appears in the game window...






...one day, all software will be developed this way. Onwards..

Sunday, August 17

And now for a bit of swank..


Now my testbed talks happily to emacs via slime. That's the "exploratory" part of "exploratory game developement.". Next up: Daleks...

And now for something completley different.


You guessed it - another testbed. This time, in 100% Common Lisp (SBCL), just for comparison.

Wednesday, August 13

More testbed


I've done some more playing around with that testbed, integrating ECL and G3Ds Shape API. It works ok, apart from a few wrinkles. It might even be the beginnings of a nice educational app for learning 3d transforms and the like. The main improvement is that the REPL gives you error feedback rather than crashing the app when you give it a bad form. A distinct must for interactivity...

Tuesday, July 22

What next?


Embedding ECLS in a 3D Engine - G3D - proved remarkably easy. The question is - now what. What should live on the Lisp side and what should live on the C++ side? Geometry for C++? AI for Lisp..what about collisions, then? Hmm..

Wednesday, July 16

Using Google for Context Sensitive Help in Emacs


Here's a hack that combines three of the most useful things in the known Universe: Google, Emacs and Firefox. Emacs 22.x has a standard method for invoking a browser: the browse URL function. To customise it use:


M-x customize-group browse-url
We are interested in the settings: Browse Url Browser Function which should be set to
browse-url-firefox
Then there is Browse Url Firefox Program which should be set to the full path of wherever firefox lives on your machine, and Browse Url Firefox New Window Is Tab which should be on to prevent multiple firefoxen cluttering up your windows when you try this.


Now that you have customized everything, you drop a crafted function into your .emacs and bind it to a key:



;; -- INTEGRATED HELP
(require 'url)
(defun search-site-url (site url keyword)
(concat "http://www.google.com/"
(format "search?q=%s+site:%s+inurl:%s&btnI"
(url-hexify-string keyword)
(url-hexify-string site)
(url-hexify-string url))))

(defun wxhelp ()
"Open a window showing the wxWidgets documentation for the word under the point"
(interactive)
(browse-url (search-site-url "docs.wxwidgets.org" "2\\\\.8\\\\.6"
(thing-at-point 'symbol))))

(global-set-key "\C-h\C-w" 'wxhelp)



Now, if you type Control H Control W while the cursor is over a symbol, Emacs will look it up via Google. For instance, if your cursor is over wxApp, by the magic of "I'm feeling Lucky", Google will find http://docs.wxwidgets.org/2.8.6/wx_wxapp.html which is the manual page for wxApp



Obviously the interesting function here is

site-search-url
which munges up an URL to feed to google to make it search a specific site for a keyword, filtering URLs that do not contain a certian string. The highly escaped \\\\ is to ensure that 2\.8\.6 appears in the final URL so that Google treats . as a literal.



The great utility of this hack is its universiality. It will work for any language or library with a sanely organised reference web site. Language specific lookup functions based on sites like cppreference.com are left as an exercise for the reader...

Friday, March 14

Emacs Selectors

One of the nicer things that comes with slime is the slime-selector: it's just a little buffer switching thing, that lets you press r to switch to the repl buffer, d to switch to the debugger buffer, s to switch to the scratch buffer and so forth. Bound to a function key, it's an extraordinarily convenient way of switching to a specific buffer.



Of course, it's geared to SLIME and Lisp, but when coding C++ on the day job I often find myself switching between code, the debugger, shell and compilation buffer, so without further ado, here is the C equivalent, which is easily hacked up to include other buffers, too: actually, I'm beginning to think something like this functionality should be in emacs by default, as it eliminates a lot of keyboard gymnastics.







;; slime selector clone for c ----------------------------------

(defvar c-selector-methods nil)

(defun c-selector ()
(interactive)
(message "Select [%s]: "
(apply #'string (mapcar #'car c-selector-methods)))
(let* ((ch (save-window-excursion
(select-window (minibuffer-window))
(read-char)))
(method (find ch c-selector-methods :key #'car)))
(cond ((null method)
(message (format "No method for charachter: %s" ch))
(ding)
(sleep-for 1)
(discard-input)
(c-selector))
(t
(funcall (third method))))))


(defmacro def-c-selector-method (key description &rest body)
`(setq c-selector-methods
(sort* (cons (list ,key ,description
(lambda ()
(let ((buffer (progn ,@body)))
(cond ((get-buffer buffer)
(switch-to-buffer buffer))
(t
(message "No such buffer")
(ding))))))
(remove* ,key c-selector-methods :key #'car))
#'< :key #'car)))

(def-c-selector-method ?d "GDB debugger buffer"
gud-comint-buffer)

(def-c-selector-method ?g "Grep buffer"
grep-last-buffer)

(def-c-selector-method ?l "Buffer List"
(let ((result (get-buffer "*buffer-selection*")))
(if result
result
((bs-show)
(get-buffer "*buffer-selection*")))))

(def-c-selector-method ?c "Compilation buffer"
(let ((result (get-buffer "*compilation*")))
(if result
result
(compilation-find-buffer))))

(def-c-selector-method ?s "Shell buffer"
(get-buffer "*shell*"))

Friday, February 22

ASDF for the slightly confused

Well, you have a shiny new lisp compiler/interpreter/environment on your machine, and like an eager and smart newbie you want to do something with it. Right there and then many lisp newbies go SPLAT and end up as a bug on a windscreen, later to be scraped off and fed to Guido's pet snake. So here is ASDF for confused newbies (a very different proposition from a dummy, who should go back to reading bright yellow paperbacks and programming Java in the enterprise shop window).


ASDF is about 500 lines of lisp source, and a dot asd file is the lisp equivalent of the ubqutious make; you can't do anything in a serious modern lisp environment without it, so lets take you through it step by step. An asd file describes a system that contains modules and components. Components are usually individual files. Modules are collections of files, usually in subdirectories. Let's look at an example dot asd file: this one is for cowl - a simple opengl gui written by William Robinson who is working on Cityscape, a promising
game found at this address.


(defsystem #:cowl-ftgl
:depends-on (#:cffi)
:description "FTGL Common Lisp wrapper for Cowl."
:components ((:module "src"
:components
((:file "cowl-ftgl")))))


The defsystem form then defines a system with one component which is a module called src which in turn contains one component in a file called cowl-ftgl, which will be a lisp file, naturally: since it's in a module called src, it will be loaded in the src directory below the directory that holds the dot asd file. Sometimes it is necessary to wrap the defsystem form in it's own package using defpackage and a throwaway package name. We do not do that here because we do not define any symbols that we would need to refer to externally, but we would need to if we were defining new component classes or methods to be used in the system, examples of which will follow later in the article.


Components, modules and systems are defined as CLOS objects in asdf.lisp, so of course they can be operated upon with generic functions, and there are quite a few that come with asdf. The key one is named with Arc-like gnomicness: "oos" - which I imagine is short for "Operate on System". It takes at least two parameters: the operation to perform and the system to perform it on.


The operation you are most likely to perfom is load-op: this loads and compiles a system, and the form is simply:


(asdf:oos 'asdf:load-op 'system-name)

Other operations are compile-op, and test-op: the latter will only have meaning if the author of your system has provided tests, as some packages do.


ASDF will search for systems using the list of functions referred to by *system-definition-search-functions* used to search for .asd files in the filesystem. By default this contains only one function, (sysdef-central-registry-search) which is perfectly adequate for file systems with symbolic links. The modus operandi on such system is to have a share/common-lisp/systems directory populated with symbolic links to dot asd files which may be downloaded and untarred in any part of the fs tree to which the user has access. Then the (sysdef-central-registry-search) scans the list of directories referred to by *central-registry* for dot asd files containing the system which it needs to operate on.



To put it another way, procedurally this translates to:


  1. Download your asdf package

  2. Unzip - say to ~/thinngy/cl-blab

  3. Note that ~/thinngy/cl-blab/cl-blab.asd is the system.

  4. Create a ~/share/common-lisp/systems directory for systems
  5. cd ~/share/common-lisp/system
  6. ln -s ~/thinggy/cl-blab/cl-blab.asd cl-blab.asd
  7. now fire up your lisp and enter..

    ;; for systems that don't do (require 'asdf)
    (load #"/path/to/asdf.lisp")

    ;; the / on the end of the path is important, don't forget it
    (push #"/home/me/share/common-lisp/systems/" asdf:*central-registry*)

    (asdf:oos 'asdf:load-op 'cl-blab)

For Windows the situation is sligtly more complicated: either you write your own search function *or*, more practically apply a patch that lets you use shortcuts in place of symlinks.



You'd be right to point out that this is on the laborious side, but the purpose of this article is to demonstrate how asdf *works*. There are two packages for automating lisp package and asdf system installation: asdf-install and clbuild, which I encourage newbies to investigate, in the usual sadistic exercise for the reader.



Why go through all this palaver with asdf? Well the beauty of asdf is that systems, components and modules are in fact CLOS objects, so we can do tricks like this:




(cffi:load-foreign-library
(make-pathname
:name "cftgl"
:type "so"
:directory (directory-namestring (asdf:component-pathname
(asdf:find-system :cowl-ftgl)))))

..which loads "clftgl.so" which is found in the same directory as the dot asd file containing the system definition. Highly useful when distributing a C shared lib that wraps a C++ library so that it can be called into from Lisp.


The fact that source files are component, lets us write specialist methods for different kinds of source file such as c-source-file, java-source-file, html-file (all defined in asdf.lisp) allows asdf to work as a make replacement, operating on non-lisp source, thus:



(defmethod output-files ((op compile-op) (c c-source-file))
(list (make-pathname :type "o" :defaults
(component-pathname c))))

(defmethod perform ((op compile-op) (c c-source-file))
(unless
(= 0 (run-shell-command "/usr/bin/gcc -fPIC -o ~S -c ~S"
(unix-name (car (output-files op c)))
(unix-name (component-pathname c))))
(error 'operation-error :operation op :component c)))

(defmethod perform ((operation load-op) (c c-source-file))
t)

There is an extended example of this kind of thing where asdf is extended to work with a fortran to lisp converter here.

To conclude: like many things in Lisp, asdf is prickly for newbies and takes time to get to know and use well. However, when you do you can do things with it for which you'd normally need another build system, independent of your language. As Brucio would observe: Lisp does not have this limitation and Common Lispers laugh at things like ant.