Back in 2004 I wrote a small Gtk+ app to help me keep track of my time, and
called it GTimeLog. I shared it with
my coworkers, put it on the web (on the general "release early, release often"
principles), and it got sort-of popular before I found the time to polish it
into a state where I wouldn't be ashamed to show it to other people.
Fast-forward to 2008: there are actual users out there (much to my
surprise), I still haven't added the originally-envisioned spit and polish,
haven't done anything to foster a development community, am wracked by guilt of
not doing my maintainerly duties properly, which leads to depression and
burnout. So I do the only thing I can think of: run away from the project and
basically ignore its existence for a year. Unreviewed patches accumulate in my
inbox.
It seems that the sabbatical helped: yesterday, triggered by a new Debian bug report, I sat down,
fixed the bug, implemented a feature, applied a
couple of patches
languishing in the bug tracker, and released version 0.3 (which
was totally broken thanks to setuptools magic that suddenly stopped
working; so released 0.3.1 just now). Then went through my old unread email,
created bugs in Launchpad and sent
replies to everyone. Except Pierre-Luc
Beaudoin, since his @collabora.co.uk email address bounced. If anyone
knows how to contact him, I'd appreciate a note.

There are also some older changes that I made before I emerged out of the
funk and so hadn't widely announced:
-
There's a mailing
list for user and developer discussions (if there still are any ;).
-
GTimeLog's source code
now lives on Launchpad (actually, I mentioned this on my
blog once).
Unix is an IDE. I do my
development (Python web apps mostly) with Vim
with a bunch of custom plugins, shell
(in GNOME Terminal: tabs rule!), GNU make, ctags, find + grep,
svn/bzr/hg/git.
The current working directory is my project configuration/state. I run
tests here (bin/test), I search for code here (vim -t TagName, find + grep), I
run applications here (make run or bin/appname). I can multitask
freely, for example, if I'm in the middle of typing an SVN commit message, I
can hit Ctrl+Shift+T, get a new terminal tab in the same working directory, and
look something up. No aliases/environment variables/symlinks. I can work on multiple projects at the
same time. I can work remotely (over ssh).
Gary Bernhardt's screencasts on
Vimeo show how productive you can get if you learn Vim and tailor it
to your needs. I have Vim scripts that let me
-
See the name of the class and function that I'm editing in the statusbar,
even if the class/function definition is offscreen:
pythonhelper.vim.
-
See all pyflakes warnings and errors in a list as soon as I press F2 to
save the file: python_check_syntax.vim.
-
Add a "from foo.bar import Something" line at the top of the file if I
press F5 when my cursor is on Something, looking up the package and module
from ctags: python-imports.vim.
-
Switch between production code and unit tests with a single key if the
project uses one of several conventions for tests (e.g. ./foo.py
<-> ./tests/test_foo.py):
py-test-switcher.vim.
-
Generate a command line for running one particular unit test (the one
my cursor is inside) and copy it into the system clipboard, so I can
run that test by Alt-Tabbing into my terminal window and pasting.
py-test-runner.vim.
-
Open the right file and move the cursor to the right line if I
triple-click a line of traceback in a shell (or an email) then press F7 in
my gvim window:
py-test-locator.vim.
-
Compare my version of the code with the pristine version in source control
in an interactive side-by-side diff that lets me revert bits I no longer
want:
vcscommand.vim.
-
Highlight which lines of the source are covered by my tests, if I have
coverage information in trace.py format:
py-coverage-highlight.vim.
-
Show the signature of a function/class's __init__ when I type the name
of that class/function and an open parenthesis (looked up from tags):
py-function-signature.vim.
-
Fold code into an outline so I only see names of methods or classes
instead of their full bodies:
vimrc, function PythonFoldLevel.
-
Fold diff files so I can see whole hunks/files and can delete those with
a single key (well, two keys -- dd). Useful for reviewing large
diffs (tens of thousands of lines):
vimrc, function DiffFoldLevel.
Some of these come from www.vim.org, some
I've written myself, some I've taken and modified a little bit to avoid an
irritating quirk or add a missing feature. Some things I don't have (and envy
Emacs or IDE users for having -- like an integrated debugger for Python apps,
and, generally, integration with other tools, running in the background).
It's been my plan for a long time to polish my plugins, release them
somewhere (github? bitbucket? launchpad?) and upload to vim.org, but as it
doesn't seem to be happening, I thought I'd at least put an svn
export of my ~/.vim on the web.
zope.schema has Text and TextLine. The former is for multiline text, the
latter is for a single line, as the name suggests. Zope 3 forms will use a
text area for Text fields and an input box for TextLine fields. Display
widgets, however, apply no special formatting (other than HTML-quoting of
characters like <, > and &), and since newlines are treated the same
way as spaces in HTML, your multiline text gets collapsed into a single
paragraph.
Here's a pattern I've been using in Zope 3 to display multiline user-entered
text as several paragraphs:
import cgi
from zope.component import adapts
from zope.publisher.browser import BrowserView
from zope.publisher.interfaces import IRequest
class SplitToParagraphsView(BrowserView):
"""Splits a string into paragraphs via newlines."""
adapts(None, IRequest)
def paragraphs(self):
if self.context is None:
return []
return filter(None, [s.strip() for s in self.context.splitlines()])
def __call__(self):
return "".join('<p>%s</p>\n' % cgi.escape(p)
for p in self.paragraphs())
View registration
<configure
xmlns="http://namespaces.zope.org/zope">
<view
for="*"
name="paragraphs"
type="zope.publisher.interfaces.browser.IBrowserRequest"
factory=".views.SplitToParagraphsView"
permission="zope.Public"
/>
</configure>
and usage
<p tal:replace="structure object/attribute/@@paragraphs" />
Update: The view really ought to be registered twice: once
for basestring and once for NoneType. I was too lazy to figure out the dotted
names for those (or check if zope.interface has external interface declarations
for them), so I registered it for "*". You should know that this makes the
view available for arbitrary objects (but won't work for most of them, since
they don't have a splitlines method), and that it is, sadly, accessible to
users who may try to hack your system by typing things like @@paragraphs in the
browser's address bar. Ignas Mikalajūnas offers an alternative
solution using TALES path adapters.