Keepass global autotype in Xmonad

I’m remigrating to xmonad and wanted to set up a key in my config to perform global auto-type for keepass2. No problem, right? Something like this:

myKeymap = [
            -- ...
            , (prefix "a"       , spawn "/usr/bin/keepass2 --auto-type")

Well, it works on the xmonad side of things, because keepass responds with the error,

"For global auto-type, the 'xdotool' utility/package is required (version 2.20100818.3004 or higher!)"

Xdotool is installed, because ‘which’ says so, and because globabl auto-type works fine in Unity.

After hour or more of unsuccessful googling I decided to experiment with xdotool in the terminal and see what was happening.

~> xdotool getactivewindow getwindowname
Your windowmanager claims not to support _NET_ACTIVE_WINDOW, so the attempt to query the active window aborted.
xdo_get_active_window reported an error

This finally gave me something more specific to search for, and the relevant package for the fix is XMonad.Hooks.EwmhDesktops. Be aware, though, that the top search result here has obsolete configuration instructions.

All I had to do was add this

import XMonad.Hooks.EwmhDesktops

and then change the call to xmonad at the end to this

  main = xmonad $ ewmh myConfig

Moral of the story: it would have been really helpful if Keepass said something like, “xdotool was found, but it’s not returning the _NET_ACTIVE_WINDOW. Check your window manager.” Maybe that’s not possible for some reason specific to keepass or mono, but it’s a lesson to keep in mind when I’m writing my own code.

No Comments

My new favorite alias: apt-get missing commands

Debian’s apt-get and related tools are pretty fantastic.  I especially love the command_not_found_handle–though I know not everyone does–which tells you the package to install if you want the command you’re trying to run.

~> pacman
The program 'pacman' is currently not installed. You can install it by typing:
sudo apt-get install pacman
~> # okay fine let me type or copy/paste that
~> sudo apt-get install pacman

I don’t want that message to have an interactive prompt at the end (“Go ahead and install it? (y/n):“) but I do want a quick way of doing what it says.  The computer just told me exactly what needs to be typed, so why do I need to type it myself?

This alias reruns your last command, grabs the last line from the error message, and runs it.

alias doit='$($(history -p \!\!) 2>&1 | tail -n1)'
~> pacman
The program 'pacman' is currently not installed. You can install it by typing:
sudo apt-get install pacman
~> # I've been expecting you
~> doit
Reading package lists... Done
[...]

If it wasn’t so long, I’d like to name it go_ahead_and_do_it_yourself_then_jeez.

No Comments

lossfully: a music library transcoder

I’ll just explain my situation, but say “you” instead of “I” because I’ll assume it applies to you, too. If it doesn’t, you won’t have much use for this library anyway.

You have a large collection of music. After several misguided attempts at ripping all your CDs to mp3s or something, it’s finally mostly ripped (“for the last time”) to a lossless format like FLAC. But you still have a bunch of other lossy formats thrown in because…well, just because.

Now you want to take some of that music, shrink it in size, and put it on a portable device. You fire up some GUI program, drag the folders you want onto it, and ask it to give you back some Oggs. Or mp3s. Or whatever.

Ah yes, but now you’ve incurred the wrath of the information theory gods, for while you succeeded in shrinking your pristine FLACs, you have also indiscriminately transcoded your lossy files into a different lossy format. Depending on how smart the program was, you maybe even encoded a file into the same lossy format but using a higher bitrate. Scandalous!

Plus, you don’t just have one portable device. You have a phone, your wife has a tablet, there are three or four mp3 players floating around the house that belong to different people, and you want some music on your work laptop. But some of those have more memory than others, plus you only want some of your massive library on any one of them.

Lossfully isn’t your usual, “drag a bunch of music files on me and press go” music converter. You write a small script to describe what actions to take on all or a subset of your music library. Something along the lines of, “convert all of my lossless files to vorbis, and go ahead and convert all the lossy stuff too as long as it has a bitrate over 192 kbps.” You would do that by writing

require 'lossfully'
 
Lossfully.generate '~/share/music' => '~/share/music_lossy' do
  threads 2
  clobber true
 
  encode :lossless => ['.ogg', 6]
  encode [:lossy, 192] => ['.ogg', 4]
end

It might be easy enough for someone who doesn’t even know ruby, as long as they have some examples they can stare at and modify. Check out the documentation on RubyGems.org for more examples and to learn how to write your own. Code is on GitHub.

It uses sox to do the actual conversion, so you have to, you know, have that. And you might need to recompile it if your distribution has LAME support turned off. Might work on Windows, or it might not. And it definitely will throw nasty errors at you if you call it the wrong way, for now anyway.

, ,

No Comments

Relisp 1.1.0

For all three of you who will read this (though there has been about 1000 downloads–that’s exciting) there’s a new version of Relisp. Check out the changelog, or look at the new examples in the gem. I promise that there’s documentation, even if rubygems.org isn’t currently showing it.

https://rubygems.org/gems/relisp

, ,

No Comments

Relisp: Rubyfied Emacs Lisp

Okay, look. If you use Emacs extensively and have never wished you could use something, anything, to customize it besides Lisp…well, then, 100 hacker points for you. But not this project. This project is not for you.

This purpose of Relisp is to:

  • call Ruby from Emacs
  • call Elisp from Ruby
  • manipulate Emacs without using Elisp to some extent (Ruby wrappers around some Elisp functions and objects)
  • reduce the number of blog entries titled “Is Ruby an acceptable Lisp?” and flame wars under the title “ruby vs. lisp vs. scheme vs. haskell vs. …”

How about some examples?

Call Ruby from Emacs

(relisp-start-slave)
(ruby-eval "1 + 2 + 3")
;    => 6
(ruby-eval "'ruby string'.reverse")
;    => "gnirts ybur"

Emacs starts a ruby process and they both pass questions and answers back and forth. Simple enough. But it’s more than just handing each other strings:

(type-of (ruby-eval "{:first => 'john', :last => 'doe'}"))
;    => hash-table
(setq list '(3 5 2 6 4 1))
(ruby-eval (concat (relisp-to-ruby list) ".class"))
;    => Relisp::Cons
(ruby-eval (concat (relisp-to-ruby list) ".to_list.class"))
;    => Relisp::List [a subclass of Array]
(ruby-eval (concat (relisp-to-ruby list) ".to_list.sort"))
;    => (1 2 3 4 5 6)
(type-of (ruby-eval (concat (relisp-to-ruby list) ".to_list.sort")))
;    => cons

Whenever objects are passed from Elisp to Ruby or back again they’re translated to the appropriate analogous type/class in the other language. An Elisp integer becomes a Ruby Fixnum, a vector becomes an Array, things like that.

Call Elisp from Ruby

I’ll admit it—I initially added this functionality just so I could run Relisp’s unit tests from the Ruby side. But if you ever want to use some Lisp in your Ruby programs, you can do that now.

require 'relisp'
 
emacs = Relisp::ElispSlave.new
emacs.elisp_eval( "(+ 1 2)" )
#    => 3
emacs.elisp_eval( '(concat "two " "words")' )
#    => "two words"

Looks sort of like the Lisp version, right? Using the typical method_missing magic, unknown ElispSlave methods are translated into calls to Lisp functions:

emacs.*(5, 2)
#    => 10 [calls (* 5 2)]
emacs.create_file_buffer( "blah.txt" )
#    =>  #<Relisp::Buffer:0x7f3839cf8168 ...> [calls (create-file-buffer "blah.txt")]

The result to that last example sort of gives away the grand finale. Wouldn’t it be nice to have a Ruby interface to things like buffers, windows and frames? Yes. Yes it would:

new_buffer = Relisp::Buffer.new("name_of_new_buffer")
new_buffer.switch_to
Relisp::Frame.new({:width => 80, :height => 20, :name => "ruby frame"})

Installation

For all of the glorious details, see the documentation at http://relisp.rubyforge.org/. To get the gem, just pull up the terminal:

[sudo] gem install relisp

There’s one little extra step after installing the gem that involves putting the relisp.el file in your ~/.elisp directory. The instructions will come up when you install the gem.

, ,

4 Comments