If it won't be simple, it simply won't be. [Hire me, source code] by Miki Tebeka, CEO, 353Solutions

Wednesday, August 29, 2007

Simple launcher for XFCE


I'm using xfce4 as a window manager, it has a nice launcher called xfrun4, however it only tries to execute applications.

I've written a little launcher that uses exo-open to open it's argument. This way I can open PDF files, directories etc.
(It's not as fancy as Mac's QuickSilver or Windows SlickRun, but it does the job)

In order to get quick access, open the keyboard settings, create a new theme (you can't change the default) and add the launcher there. I usually go with "CTRL-SHIFT-K" to activate.


#!/usr/bin/env python
'''Simple lanucher'''

from Tkinter import Tk, Label, Entry
from tkFont import Font
from tkMessageBox import showerror

from os.path import exists, expanduser
from os import environ, popen

def launch(name):
name = expanduser(name)
if not exists(name):
fullname = popen("which %s 2>/dev/null" % name).read().strip()
if not fullname:
raise ValueError("can't find %s" % name)
name = fullname

popen("/usr/bin/exo-open \"%s\"" % name).read()


USER_CANCEL = 0
ROOT = None
COMMAND = None

def quit(event):
global USER_CANCEL

USER_CANCEL = 1
ROOT.quit()

def build_ui():
global ROOT, COMMAND

ROOT = Tk()
ROOT.title("Launchie")
ROOT.bind("<Escape>", quit)
COMMAND = Entry(width=80, font=Font(size=14))
COMMAND.pack()
COMMAND.bind("<Return>", lambda e: ROOT.quit())

def show_ui():
global USER_CANCEL

USER_CANCEL = 0
COMMAND.focus()
ROOT.mainloop()

return COMMAND.get().strip()


def main(argv=None):
if argv is None:
import sys
argv = sys.argv

from optparse import OptionParser

parser = OptionParser("usage: %prog")

opts, args = parser.parse_args(argv[1:])
if len(args) != 0:
parser.error("wrong number of arguments") # Will exit


build_ui()

while 1:
try:
command = show_ui()
if USER_CANCEL:
raise SystemExit

if not command:
showerror("Launchie Error", "Please enter *something*")
continue

launch(command)
break
except ValueError:
showerror("Lanuchie Error", "Can't launch %s" % command)

if __name__ == "__main__":
main()


The reason I chose Tkinter is that it's already installed with Python and it's good enough for simple stuff like this.

Tuesday, August 21, 2007

start

Many times, I open files from the command line.
However each OS has it's own utility for opening file, so I have this little script called start (yes, I started my life on windows ;).

#!/bin/bash
# Open a file from command line, multi OS

# Miki Tebeka <miki.tebeka@gmail.com>

if [ $# -ne 1 ]; then
echo "usage: `basename $0` PATH"
exit 1
fi

if [ ! -e $1 ]; then
echo "error: can't find $1" 1>&2
exit 1
fi

case `uname` in
Linux) open=exo-open;;
Darwin) open=open;;
CYGWIN*) open=cygstart;;
MINGW32*) open=start;;
*) echo "error: no start program for `uname` platform" 1>&2; exit 1;;
esac

$open "$1"

Friday, August 10, 2007

Supporting Search Query Syntax

It's very easy to add support for search-engine like syntax in your program.
The idea is to convert the query to a Python expression and then evaluate it.

We'll support the following syntax:
word1 word2       - word1 and word2
word1 AND word2 - word1 and word2
word1 word2 - word1 and word2
word1 OR word2 - word1 ord word2
NOT word - Not containing word
The code is very simple:
def is_operator(token):
return token in set(["and", "not", "or", "(", ")"])

def should_insert_and(expr, token):
if not expr:
return 0

if is_operator(expr[-1]):
return 0

if is_operator(token):
return 0

return 1

def match(query, text):
words = set(text.lower().split())

expr = []
for token in query.lower().split():

if should_insert_and(expr, token):
expr.append("and")

if is_operator(token):
expr.append(token)
else:
expr.append(token in words)

py_expr = " ".join(map(str, expr))
return eval(py_expr)

def test():
assert match("a", "a"), "a --- a"
assert not match("a", ""), " --- a"
assert match("a AND b", "a c b"), "a c b --- a AND b"
assert not match("a AND b", "a c"), "a c --- a AND b"
assert match("NOT ( a OR b )", "z"), "z --- NOT ( a OR b )"
assert match("a OR b", "b"), "b --- a OR b"
Notes:
1. We don't do any fancy tokenization (text and query), but in most cases this should be enough.
2. We place an AND where it's missing.

Thursday, August 02, 2007

Cheetah Templates

Currently doing some web development and found Cheetah very useful.
I like Cheetah since it's syntax is very similar to Python and I can use my existing Python objects with it.

I have one master template that set the site general site look and feel (with the master CSS of course).
#from time import ctime

#attr NAME = "???"

#def head
#end def

#def body
OOOPS, head will roll...
#end def

<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css" />
$head
</head>
<body>
<div class="header">My Wonderful Site - $NAME</div>
$body

<hr />
<div class="footer">
Generated $ctime()
</div>
</body>
</html>
$head and $body are place holders that the specific pages will fill.
Pages also define $NAME which will be shown in the header.

The an specific page (index.tmpl) can be:

#include "master.tmpl"

#attr NAME = "INDEX"

#def body
This is my site index page, see also <a href="other.cgi">other page</a>. <br />

Oh, and also random = $random;
#end def
And the CGI script:

#!/usr/local/bin/python

from Cheetah.Template import Template

from random import randint


def main():
random = randint(0, 100)

print "Content-Type: text/html"
print

page = Template(file="index.tmpl", searchList=[locals()])
print page.respond()

if __name__ == "__main__":
main()
Note that I pass locals() as the search list. This frees me from creating a mapping dictionary (exporting random to the template).

That's about it, you can use the master template and the site main CSS to have a uniform looking site and let each page implement just the $body and $head if it needs to.

Blog Archive