posts tagged "scheme"


3 October 2012 2:35 AM (scheme | xdg | coding)

Since I have nothing better to say and still want to say something, here is some nonsense:

I've been having an issue with loading configuration and data files. The problem is that I like the XDG Base Directory Specification and am trying to write my software in such a way that it supports both this and the usual(/old) folder in $HOME approach.

This doesn't sound all that difficult, nor is it, but still I was making a lot of mistakes with it, because I don't just want to support something, I don't want to force whomever (nobody but me, really) uses my software to be forced in to anything. So first I need to check if the XDG environment variables exist, if they do then I have to see if the file I want to load exists in that directory, if it doesn't and one does exist in $HOME I want that one, but if the one in home doesn't exist either, I want the one in the XDG folder again. It gets messy.

I feel that I may have it now, though8239

(define (stored-file xdg-env file)
  "Try to get FILE stored either in XDG-ENV or the home directory."
  (let ((xdg (getenv xdg-env))
        (stored-file (string-append
                      (getenv "HOME") "/.project/" file)))
    (unless (or (file-exists? stored-file) (not xdg))
      (set! stored-file (string-append xdg "/project/" file)))

(define (config-file file)
  (stored-file "XDG_CONFIG_HOME"))

(define (data-file file)
  (stored-file "XDG_DATA_HOME"))

(define (rc-file)
  (config-file "rc.scm"))

(define (list-file)
  (data-file "list.scm"))

The stored-file function first assumes that we will want to grab it from the directory in $HOME, when it can't verify that that particular file exists and knows that the XDG variable isn't empty it will instead return a reference to the file in that directory.

All the other functions are just there to make it clear and convenient to load these files and not specifically necessary. The good part of this function, in my opinion, is that is separates configuration and data files from each other in code, but will just grab it all from the same directory when working with the $HOME directory. This, of course, can create naming conflicts, but if you have naming conflicts this way you might get confused by what you're doing here or there anyway.


3 July 2012 2:25 AM (gitto | project | scheme | guile | git)

I've been meaning to do two things for quite some time:

  • Write a utility for tracking the status of my various git

  • Write a program in Guile scheme.

A few days ago I accomplished both and I named it gitto.

It is a simple utility that allows you to register some repositories on your computer and it will list how many changes there are to push and pull, if the working directory is "dirty" and how old the last known commit on the upstream branch it, which it shows as last updated.

More details can be found here, including a link to the source. It requires at least guile 2.0.x and some version of git.

I still have to at least add docstrings and perhaps even a texinfo document, and I haven't released any version yet, but feel free to try it and be sure to let me know any suggestions/complaints/rants/bugs you might have or find.

A strange HLWM configuration

29 January 2012 0:00 AM (guile | hlwm | scheme)

Heh, I only realized later that I'd posted snippets from my strange herbstluftwm config without explaining it. So you get lispy commands instead of bashy ones.

First, I'll say something to those people who don't know herbstluftwm, or its configuration method.

herbstluftwm uses a special program to send commands to the window manager while it's running. And the only configuration you can do is actually calling that program multiple times during startup. This may sound limiting in the way that I'm saying it, but it really isn't.

herbstluftwm calls the ~~/.config/herbstluftwm/autostart~ file. This file should contain some shell-executable code and should be executable by you. This means that it can be pretty much anything as long as it sends the right commands to the window manager.

By default a nice bash script is provided, as a starting point if you will. Now, as I'm almost certainly crazy (even just for trying this), I have replaced that original bash script with a guile script. Guile is the official GNU Extension Language and is an implementation of scheme, which is a lisp dialect. Since using emacs I have come to find lisp very interesting, and I've heard good things about guile, so I've always wanted to work with it more. Since I'm not really writing much at the moment, I'm looking for other ways to use it, like this one.

It wasn't all that hard, guile has some very nice and easy process management functions, and all I needed to do, really, was call the herbstclient program over and over again. So I wrote a function for that:

(define (hc command)
  "Calls the herbstclient program to execute a command"
  (system (string-append "herbstclient " command)))

This basically just calls the herbstclient program and appends the string command to it.

Then, there are some functions to help with setting up all the settings:

(define (keybind modkey key command)
  "Binds a keyboard key to a command, also prints it for testing
  (display (string-append "keybind " modkey "-" key " " command "\n"))
  (hc (string-append "keybind " modkey "-" key " " command)))

(define (mousebind modkey button command)
  "Binds a mouse button to a command"
  (hc (string-append "mousebind " modkey "-" button " " command)))

(define (add-tag name)
  "Create a new tag"
  (hc (string-append "add " name)))

(define (set variable value)
  "Set the value of a variable"
  (hc (string-append "set " variable " " value)))

(define (unrule)
  "Clear all rules from memory"
  (hc "unrule -F"))

(define (rule spec)
  "Add a new rule"
  (hc (string-append "rule " spec)))

(define modkey "Mod4")

(define (create-tag name)
  (add-tag name)
  (keybind modkey name (string-append "use " name))
  (keybind modkey
           (string-append "Shift-" name)
           (string-append "move "  name)))

(define (dmenu-command fn nb nf)
  (string-append "dmenu_run -fn '" fn "' -nb '" nb "' -nf '" nf "'"))

(define (set-layout layout)
  (display (string-append "set_layout " layout "\n"))
  (hc (string-append "set_layout " layout)))

I've given them some docstrings, they should be fairly self explanatory that way. For the ones that don't have a docstring: create-tag creates a new tag (desktop) to be used, dmenu-command as a function I use to more easily change the values dmenu uses, set-layout sets a certain layout to be used and prints this for testing purposes.

This makes it easy to do many things, although having to do everything with strings is probably not very efficiƫnt. I'm still looking into creating a guile extension for herbstluftwm, but I have very little experience with IPCs, guile and X programming, so I'm not going very fast with that.

I hope that explains the lispy config snippets in my last post.