We're growing into something new. Read More
moopet

Ben Sinclair


(function($) {
    $(document).ready(function($) {
        $('#changelist-search input[type=submit]').hide();
        $('label[for=searchbar]').html('Filter:');
        $('#searchbar').keyup(function(e) {
            if (e.keyCode === 27) {
                if (!$(this).val()) {
                    return;
                }
                $(this).val('');
            }
            $('#changelist-form').load(window.location.pathname + '?q=' + $(this).val() + ' #changelist-form');
        }).focus();
    });
})(django.jQuery);

Django admin ajax search filter

I had the urge to make a find-as-you type modification to Django's admin search box. I didn't find anything that did this with a few brief search, but I don't believe for a minute it hasn't been done before. All the hits I got were for people writing foreign-key typeahead widgets and so on. This snippet, however, rewrites the search form to refresh the results on every keypress, clears the filter on pressing ESC and automatically gives the filter box focus when the page loads. It means you can just start bashing away at keys as soon as the page is rendered. Just save the above as a javascript file somewhere convenient then stick a reference in your ModelAdmin class for whatever model you want to override: search_fields = ('name', 'girth', 'eloquence', 'best_friend__wallet_capacity') # whatever class Media: js = ("/static/js/admin/instantsearch.js",) # or wherever you put it Raw Code » and it'll turn the search box into a live filter. See the admin docs for more details on search_fields; they're good at making life easier for other people with staff access to your system. In particular they're good because you can search in related fields in the same way you filter any normal queryset, so it's more powerful than just searching what's visible in the list on screen.

#!/bin/bash

if [[ "$1" == [tT]* ]]; then
    perl -pi -e 's/^DEBUG = False/DEBUG = True/' settings.py
elif [[ "$1" == [fF]* ]]; then
    perl -pi -e 's/^DEBUG = True/DEBUG = False/' settings.py
else
    echo "usage: $0 True|False"
fi
grep "^DEBUG" settings.py

Tiny scripts do the work so you don't have to

Here is a script I wrote this morning to turn DEBUG mode on and off in Django. I'm using it to illustrate how sometimes writing a script to save just 20 seconds can be worth it. Instead of opening up vim, editing a file and saving it, I can run debug false Raw Code » or debug true Raw Code » presuming I named the script "debug" of course, and the script will edit the django configuration file for me and save it with the altered variable. Everything's hard-coded, but you can extend the idea to take things into consideration like virtual environments or complex variables if you want, but these sorts of scripts which are little more than shell aliases lend themselves to making individual changes. It's an old trick, and this is obviously complete example code to demonstrate a point. The few seconds saved each time might not add up to as much time saved by other learned habits during the day or by, in this instance, just keeping a copy of settings.py open in a buffer anyway, but it feels like it saves me time, and that's what makes it worthwhile to me. How many times a day do you do something small and repetitive and think to yourself that you could write a script to do it, but you don't because you can't be bothered? Disclaimer: automating editing important files by regular expression should only be attempted by a responsible adult.

if !has("python")
        finish
endif

" Map a keystroke for Visual Mode only (default:F2)
:vmap <f2> :PasteCode<cr>

" Send to pastebin
:command -range             PasteCode :py PBSendPOST(<line1>,<line2>)
" Pastebin the complete file
:command                    PasteFile :py PBSendPOST()

python << EOF
import vim
import urllib
import os
import sys

################### BEGIN USER CONFIG ###################
# Set this to your preferred pastebin
service = 'pastebin'
# Set this to your preferred username, or "auto" to take your shell username
user = 'auto'
# subdomain is optional, and will affect the resulting URL only
subdomain = None
private = False
email = 'someone@example.com'
#################### END USER CONFIG ####################

service_config = {
    'pastebin': {
        'api': 'http://pastebin.com/api_public.php',
        'keys': {
            'user': 'paste_name',
            'code': 'paste_code',
            'format': 'paste_format',
            'subdomain': 'paste_subdomain',
            'email': 'paste_email',
            'private': 'paste_private',
        },
        'filetypes': {
            'bash': ('sh'),
            'c': ('c'),
            'cpp': ('cpp'),
            'css': ('css'),
            'java': ('java'),
            'javascript': ('javascript'),
            'make': ('make'),
            'perl': ('perl'),
            'php': ('php'),
            'python': ('python'),
            'robots': ('robots'),
            'sql': ('sql'),
            'vala': ('vala'),
            'vim': ('vim'),
            'xml': ('xml'),
        }
    }
}

def get_format_from_filetype(service='pastebin'):
    ft = vim.eval('&ft')
    for name in service_config[service]['filetypes']:
        if ft in service_config[service]['filetypes'][name]:
            return name
    return 'text'

def get_user():
    if user == 'auto':
        if sys.platform == 'linux2':
            return os.getenv('USER')
        if sys.platform == 'win32':
            return os.getenv('USERNAME')
        return 'anonymous'
    elif user is not None:
        return user
    return 'anonymous'

def PBSendPOST(start=None, end=None):
    if start is None and end is None:
        code = '\n'.join(vim.current.buffer)
    else:
        code = '\n'.join(vim.current.buffer[int(start) - 1:int(end)])

    data = {}
    config = service_config[service]
    data[config['keys']['code']] = code
    data[config['keys']['format']] = get_format_from_filetype(service)
    if config['keys'].has_key('user'):
        data[config['keys']['user']] = get_user()
    if subdomain is not None and config['keys'].has_key('subdomain'):
        data[config['keys']['subdomain']] = subdomain
    if email is not None and config['keys'].has_key('email'):
        data[config['keys']['email']] = email
    if private and config['keys'].has_key('private'):
        data[config['keys']['private']] = 1 if private else 0

    u = urllib.urlopen(config['api'], urllib.urlencode(data))
    print u.read()
EOF

pastebin vim plugin

I was looking around for a vim plugin to allow posting chunks of code to a pastebin-type site and came across something done by a chap called djcraven back in 2006. It didn't work, so I set about updating it. In the process, I googled and found someone else had had a go on github, but that didn't work right either. So I forked their repo and made a bunch of changes. Now it supports more options like automatically getting the username from your current login - optional, I said, optional - and allows for expansion by being customisable to other services. Through a big honking config dictionary. I see a lot of ways I could improve it further. Apart from adding more services, I could shift some of the config out of this file, add prompts, fallback services, stuff like that. Maybe write it so it supports things like jsfiddle with multiple buffers? It's all been done before. But I like python, and I like vim - and I don't much like vimscript. So this is my teach-myself-how-easy-it-is first time. github.com/moopet/…

#!/usr/bin/env python
from xml.parsers.expat import ExpatError
from xml.dom import minidom
import sys

def main():
    DEFAULT_ENTRY = { 
        'username': None,
        'password': None,
        'local_dir': None,
        'remote_dir': None,
    }

    try:
        xmldoc = minidom.parse(sys.stdin)
    except ExpatError:
        print >> sys.stderr, 'Error parsing input file'
        sys.exit(1)

    entries = {}
    for server in xmldoc.getElementsByTagName('Server'):
        entry = DEFAULT_ENTRY.copy()

        tmp = server.getElementsByTagName('Host')
        if not tmp:
            continue
        hostname = tmp[0].firstChild.nodeValue

        tmp = server.getElementsByTagName('User')
        if tmp and tmp[0].firstChild:
            entry['username'] = tmp[0].firstChild.nodeValue

        tmp = server.getElementsByTagName('Pass')
        if tmp and tmp[0].firstChild:
            entry['password'] = tmp[0].firstChild.nodeValue

        tmp = server.getElementsByTagName('LocalDir')
        if tmp and tmp[0].firstChild:
            entry['local_dir'] = tmp[0].firstChild.nodeValue

        tmp = server.getElementsByTagName('RemoteDir')
        if tmp and tmp[0].firstChild:
            entry['remote_dir'] = tmp[0].firstChild.nodeValue.split()[-1]

        entries[hostname] = entry

    if entries:
        for hostname in entries.keys():
            entry = entries[hostname]
            print 'machine', hostname
            if entry['username']:
                print 'login', entry['username']
                if entry['password']:
                    print 'password', entry['password']
            if entry['local_dir'] or entry['remote_dir']:
                print 'macdef init'
                if entry['local_dir']:
                    print 'lcd', entry['local_dir']
                if entry['remote_dir']:
                    print 'cd', entry['remote_dir']
                print
            print

if __name__ == '__main__':
    main()

Cloning FileZilla settings for command-line use

At work we have a large shared FileZilla settings file, and I wanted to extract a username and password combination, so I exported the settings to an XML file. I thought, while I'm there, I might as well knock up a quick script to save these settings in .netrc format so I can have access to all that goodness from the command line and from scripts without having to hard code FTP passwords in scripts. While I'll likely never use it by hand again, I can cron it to keep the configurations in sync. If there is more than one entry for the same hostname, it takes the last one. It's my first console python script, and I can obviously see a number of areas for improvement. Python might like XSLT, for example, or I could add a couple of classes to model different file formats and give each read and write methods to make it more generic. I could add getopt to handle a bunch of different switches and optional filenames and stuff. But for my purposes, and for now, reading from stdin and writing to stdout are all I want. $ python thisscript.py < FileZilla.xml >~/.netrc