#!/usr/bin/env python import os import sys import getopt import popen2 class dmenu_wrapper: def __init__ (self): self.prompt = "run:" self.history_file = None self.first = "" self.run = None self.number = 20 self.font = "-nil-profont-medium-r-normal--15-150-72-72-c-70-iso8859-1" self.normal_bg = "#505050" self.normal_fg = "#eeeeee" self.selected_bg = "#373737" self.selected_fg = "#ffffff" def usage (self): """Displays a message showing how to use the program.""" print "Usage:\n" print " -r, --run The command to run the selected entry with" print " -p, --prompt The text prompt" print " -c, --commands The text file to read previous commands from" print " -f, --first The entry to select first" print " -n, --number The number of entries to limit the command file to" def display (self): commands = [] try: history_file = open (self.history_file, "r") # add each line to the entries list for line in history_file: line = line.rstrip ("\n") if not line in commands and line != self.first: commands.append (line) history_file.close () if self.first: commands.append (self.first) except IOError: if self.first: commands.append (self.first) # reverse the list so the commands are in the right order commands.reverse () # form the dmenu command dmenu_command = "echo -e '%s' | dmenu -fn '%s' -nb '%s' -nf '%s' -sb '%s' -sf '%s' -p '%s'" \ % ("\n".join (commands), self.font, self.normal_bg, self.normal_fg, self.selected_bg, self.selected_fg, self.prompt) # reverse them again so they're in the right order for saving commands.reverse () # open the dmenu process pipe = popen2.Popen4 (dmenu_command) try: # get the selection command = pipe.fromchild.readlines ()[0] except IndexError: # no selection picked command = "" # get the return code return_code = pipe.wait () # quit if they pressed escape or ^G if return_code != 0: sys.exit () # remove the selection from the list try: commands.remove (command) except ValueError: pass # don't append the selection if it's already the last one or if it's empty if command and command != " " and command not in commands: commands.append (command) # save the new entries if commands: # keep the number of entries to a minimum commands = commands[-self.number:] try: history_file = open (self.history_file, "w") history_file.write ("\n".join (commands)) history_file.close () except IOError: print "Failed to open command file, commands will not be saved\n" # put the executable in front of the selection if self.run: command = self.run + " " + command # run the command args = command.split(" ") executable = args[0] os.execvp (executable, args) def main (self, argv): try: # Top, right, bottom and left take arguments. Help doesn't opts, args = getopt.getopt (argv, "hp:c:f:r:n:", ["help", "prompt=", "commands=", "first=", "run=", "number="]) except getopt.GetoptError: # Display the usage message then exit self.usage () sys.exit () # Make sense of the arguments for opt, arg in opts: if opt in ("-h", "--help"): self.usage () sys.exit () elif opt in ("-p", "--prompt"): self.prompt = arg elif opt in ("-c", "--commands"): self.history_file = arg elif opt in ("-f", "--first"): self.first = arg elif opt in ("-r", "--run"): self.run = arg elif opt in ("-n", "--number"): self.number = int (arg) + 1 if self.history_file: self.display () else: print "No command file given" self.usage () if __name__ == "__main__": dmenu_wrapper ().main (sys.argv[1:])