Archive for the ‘text editing’ Category

TextExpander 3

Smile On My Mac released a new version of TextExpander this week. It has some distinct improvements over the previous version and one disappointment.

TextExpander is a utility—it was a Preference Pane, but now it’s a regular application—that expands abbreviations automatically as you type. You define both the abbreviations and what they expand into to fit the type of writing you do. So if you do a lot of writing on, say, Castigliano’s Second Theorem, you could define an abbreviation like “c2t” that would expand out to the full expression. You can also define snippets (that’s what TextExpander calls its abbreviation/full expansion combinations) for the current date and time, as well as snippets that insert the output of AppleScripts or shell/Perl/Python/Ruby/etc. scripts. It’s a great utility, and I use it a lot.

(TextExpander is, I think, not quite as versatile as the snippet facility built in to TextMate, but it’s getting closer with every update. And it can be used in any application.)

The two big improvements in TextExpander 3 are multi-computer syncing of your snippet library via Dropbox and snippets with several fill-in-the-blank fields.

Syncing via Dropbox is pretty self-explanatory. If you work at more than one Mac, you can keep your snippet library in your Dropbox folder and it will automatically sync across your machines. I haven’t been able to test this, for reasons that I’ll explain later, but if it works it will remove one minor frustration: typing an abbreviation defined on your other computer and not seeing it expand.

Snippets with several fill-in-the-blank fields will be great for certain types of boilerplate text. When one of these snippets is triggered, it pops up a window with the text, and you fill in the empty fields, tabbing from one to the next as you type.

Earlier versions of TextExpander had a less useful version of this. You could create a snippet that put the cursor at a spot in the middle of the text after expansion; this gave you the effect of a single fill-in-the-blank field. Multiple fields will let you use a single snippet to the do the work that used to take several.

So I’m generally happy with the upgrade, but there is a sore point: TextExpander 3 requires Snow Leopard, and one of my computers is a iBook G4, and it can’t run Snow Leopard because it doesn’t have an Intel processor. I don’t know if the Smile On My Mac folks have been listening to Brent Simmons, but this restriction is very disappointing to me. I haven’t replaced the iBook with a newer MacBook because I like its form factor and much of what I do on it is text-based, which doesn’t need a lot of computing power. Now, the latest version of one of my workhorse utilities for text won’t run on it.

Of course, TextExpander 2.x still runs just fine on the iBook, so it’s not like I’ve lost anything. But I can’t take advantage of the Dropbox syncing if only one of my computers has that feature. And it’s really annoying to see this update sheet appear on a machine that can’t install the update.

That’s just rubbing it in.


PNotes

Here are a few miscellaneous paragraphs about my no-server personal wiki system.

I’m tired of calling it “my no-server personal wiki system.” From now on it’ll be called PNotes, which will at least save me some typing. Its GitHub repository will remain the same.

PNotes is missing two things most wikis have: a history of edits and a search field. But it’s easy to overcome both of these limitations.

When I need to create a set of notes for a new project, I copy the PNotes notes folder—my local version of what’s in the GitHub repository—to the new project’s folder and delete the .git subdirectory inside it. I then issue a

git init

command from within notes. This starts up a new git history that will focus not on the programming, which probably won’t change at all, but on the content files. From this point on, I use git add and git commit whenever I think it’s warranted. I’ve thought about putting git commit into the PNotes makefile, forcing a commit whenever I modify or make new HTML pages, but so far I haven’t done so. I prefer the freedom of committing only when I can think up a good commit comment.

Searching hasn’t been as big a deal as I first thought it would be. Normally, I know exactly which note page will have the information I’m looking for, and finding it is simply a matter of scrolling or using the browser’s Find command on that page. For those few occasions when I couldn’t remember where a piece of information is, I just opened a Terminal window in notes and used grep to find what I was looking for. This is not as smooth a solution as having a folder-wide search field available from the browser, but given the rarity of these searches, an in-browser solution just isn’t worth the effort.

One other thing I typically do when I create a new PNotes folder for a project: I replace the generic folder icon with a Moleskine notebook icon like one of these:

I found one of these, at a larger size, by doing a Google Image search and made the others by fiddling with the band color in Acorn. It’s nice to have the PNotes folder stand out.

A reminder on how to change the icon of a folder:

  1. Open the image you want to use and copy it to the clipboard.
  2. In the Finder, do a Get Info on the folder you want to change.
  3. Select the folder’s icon at the top of the Get Info window by clicking on it.
  4. Paste. The generic folder icon should be replaced by the image on the clipboard.

This post has turned out to be a bit more miscellaneous than I’d planned.


The no-server notes wiki

I’ve just pushed a new version of my unnamed no-server notes wiki to its GitHub repository. Notes can now be organized in subdirectories instead of all being at the top level. Here’s the README.


This is a no-server personal wiki system that I created to keep track of project notes for work. I’ve put it here because it may be useful to others.

Goals

This is what I want:

  1. A self-contained file or folder of files that includes everything needed to write and view the notes. I want it to be easy to copy from one computer to another and to archive to DVD. This eliminates most of the available wiki systems, which store everything in a central database.
  2. The notes themselves to be written in Markdown rather than some specialized wiki markup. I write everything in Markdown and don’t want to shift context when switching from notes to a report. In fact, I’d like to be able to copy directly from my notes—markup included—when writing a report.
  3. To write the notes in my text editor of choice rather than in an HTML text input box or a word processor. Currently, that editor is TextMate, but TextMate itself isn’t the point. The point is to take advantage of the comfort I feel working in my normal editor. There’s a reason old Unix hackers like to do everything in Emacs or vi; it’s just more efficient to do all your text work in one environment.
  4. To be able to change the visual style of the notes as my needs or tastes change.
  5. To create new notes quickly and easily.

Requirements

Apart from what’s in the repository, you’ll need

If you need to include mathematical formulas in your notes, you should consider installing Davide Cervone’s jsMath. Once you’ve installed it, you can activate jsMath in the notes by uncommenting Line 10 of the header.tmpl file and adjusting the jsmathpath variable in the project.info file to point to jsMath’s easy.js file.

File structure

The top level of the notes directory contains all the support files, that is, all the files that are distinct from the notes themselves. These files are:

Notes files contain the actual content. These files should all have the extension .md and can be in both the top-level directory and in subdirectories. Two sample notes files are included: aa-overview.md in the top-level directory, and testing1.md in the Lab subdirectory.

Creating notes

As mentioned above, notes are just plain text files written in Markdown and saved with an .md extension. The first line will be the note’s title and will appear in the sidebar.

I use ATX-style headers, with hash marks indicating the header level, and I start each file with a first-level header, like this:

    # Overview #

The build system is smart enough to get rid of the hash marks when making up the sidebar.

Notes files in subdirectories appear with greater indentation under the name of the directory—like an outline. Within each directory, the notes are ordered alphabetically according to their file names, so you can rearrange the order in which the notes appear in the sidebar by changing the file names without changing their content. At present, there’s no way to change the order of the subdirectories.

Executing make from the top-level directory will generate all the HTML pages, which can be opened with any browser. Subsequent executions of make will generate only those pages whose .md files are new or have been modified. Executing make clean will erase all the HTML files, but will not touch the .md files.

Editing notes

You can, of course, open any .md file in any text editor to make changes. If you’re using TextMate on a Mac, there’s a faster way: click the Edit in TextMate link in the side bar to instantly open the .md file in TextMate—no need to switch to the Finder, open the folder, and double-click the file icon. If you’re a BBEdit user, you can do the same thing, but you’ll probably want to change the name of the link. It’s on Line 33 of header.tmpl.

More details

I wrote a three-part series of blog posts describing this system and its scripts, here, here, and here. The scripts have changed since then, but the basic ideas are the same.

License

This work is licensed under a Creative Commons Attribution-Share Alike 3.0 Unported License. Do what you want with it, but provide a link back to either my blog posts or to my repository.


HTML notes

Every once in a while, I spend a little time Googling to see if someone has made a personal wiki system—or any wiki system, really—that will work better for my project notes than the home-grown system I developed a couple of years ago. When I took one of those trips around the internet last week, I returned, as always, empty handed and with a growing sense that I was never going to find what I was looking for. So I’ve decided to put a little effort into my existing system and make it easier to use.

I wrote about this note-taking system, a serverless wiki, in a series of three posts back in 2008. The first of those posts described what I wanted out of the system, and the latter two posts went into how I use it and some details of the programming. At the risk of being repetitive, this is what I want in a personal wiki:

  1. A self-contained file or folder of files that includes everything needed to write and view the notes. I want it to be easy to copy from one computer to another and to archive to DVD.
  2. The notes themselves to be written in Markdown. I write everything in Markdown and don’t want to change.
  3. To write my notes in my text editor of choice. Currently, that editor is TextMate, but TextMate itself isn’t the point. The point is to take advantage of the comfort I feel working in my normal editor.
  4. To be able to change the visual style of the notes as my needs or tastes change.
  5. To create new notes quickly and easily.

Were it not for Items 2 and 3, I’d be using VoodooPad. Were it not for Items 3 and 4 (and a small incompatibility with Safari), I’d be using TiddlyWiki or one of its offshoots. But I’m not interested in compromising on these things, so it looks like I’ll be sticking with my self-made system. Which works, but could use some polish and a new feature or two.

To that end, I did a little code cleanup, put it under revision control, and set up a repository for it on GitHub in anticipation of making some improvements over the next few weeks. I want to:

In addition, I may change the build system that drives the conversion of notes from Markdown (for writing) to HTML. Currently, I’m using make, which has the advantage of ubiquity, but which also has a clumsy syntax that I’ve never felt confident in using. I know there are several alternatives, but I don’t know enough about them yet to choose among them.

I probably won’t write any more about it until I think these improvements are complete, but you can follow the repository if you want to track my progress.


Simple thanks

Like many people, I first learned of Simplenote through John Gruber’s Daring Fireball post from last summer. I bought the app and liked it from the beginning, even though it had some user interface problems. Using Simplenote paid off yesterday, when I became one of the WhySimplenote contest winners. (Twitter links to these two posts were my entries.)

Winners got a $30 iTunes gift card, which I’ll put to use immediately, and an upgrade to Premium service, which may give me the kick in the pants I need to start work on the syncing script I’ve had in mind ever since the Simplenote API came out. Thanks, Cloud Factory!

My favorite part of the winners announcement was the descriptions of what the other winners were doing with Simplenote. I was particularly taken with Andrew’s entry:

In my college share room, there’s five of us, but it’s my job to get the groceries. Each of us have access to the online component of Simplenote.

Whenever someone remembers something we/they need from the shops (often while daydreaming in lectures), they just type it onto the web app from their laptop.

Then, when I’m at the shops, I just take out my iPhone to look at the collaborative shopping list that’s been generated over the week. I never forget to get anything since I have a list, everyone has everything they need for the week, and there’s minimal stress since everyone can do it in their own time - not when I’m going out the door shouting to ask whether anyone needs anything.

Works great.

This is something I never would have thought of, but it fits Simplenote perfectly. Makes me sure there are more clever uses that I’m missing.


Extending the Calendar Events bundle for TextMate

I’ve added a new command to my Calendar Events bundle for TextMate (described in this post and available in this GitHub repository). The new command saves the generated iCalendar document to a temporary file and opens that file in iCal (or, presumably, BusyCal, if that’s your default calendar program). When an iCalendar file is opened in iCal, it asks you which calendar you want to put the new events into:

Clicking the popup menu will let you choose any of your existing calendars and will also let you create a new one.

The new command is called “Add to calendar,” and it’s bound to the ⌃⌥⌘A keyboard shortcut.

So the process of adding events to your calendar is now:

  1. Open a new document in TextMate and press ⌃⌥⇧E to make it an Events document.
  2. Use the “ev” and/or “ad” snippets to add timed events or all-day events to the document in a simple pipe-separated format.
  3. Press ⌃⌥⌘C to create an iCalendar document with those events.
  4. Assuming the iCalendar document is correct, press ⌃⌥⌘A to add those events to an iCal calendar chosen via the window shown above.

Calendar events bundle for TextMate

I think most users would agree that entering new events in iCal has always been clumsy and the Snow Leopard update just made it clumsier. I mentioned in a post last week that BusyCal’s entry method was distinctly better, although overall, BusyCal wasn’t enough of an improvement to get me to switch. In the past, I’ve used TextMate to create files using a simple pipe-separated format for the events; these are converted through a TM command into iCalendar files, which can be dragged to iCal to add the events. I’ve now improved that command and made a TextMate bundle for generating calendar events.

You can get the bundle from its GitHub repository. You install it by either

Although it’s not necessary, it would help if you also install my fork of the iCalendar bundle. This adds just one feature to the standard iCalendar bundle: it recognizes the file type based on a first line of BEGIN:VCALENDAR. This makes saving the generated iCalendar file with the proper extension a little bit easier.

To use the Calendar Events bundle, open a new document and press ⌃⌥⇧E to change the document’s language to Event. You now have two tab-triggered snippets available to enter events. For timed events, type “ev” and tab to get

Event|01/07/10 9:00 am|1.00|Location|Notes

This is the pipe-separated format for defining an event. The five fields are:

  1. The event name, which is the top line in the usual iCal event bubble.
  2. The event’s starting time, which is both a date and time. There are three TextMate tab stops within this field: one for the month and day, one for the year, and one for the time. The date parts default to the current date, and the time defaults to 9:00 am.
  3. The event’s duration in hours, which defaults to 1.
  4. The event’s location.
  5. Any other notes you may want to describe the event.

The location and notes fields may be blank, but the pipe characters between them must be present.

For all-day events, type “ad” and tab to get

Event|01/07/10|all day|Location|Notes

There is no time associated with the start of the event and therefore only two tab stops in this field. The duration is set to “all day” and is skipped over when tabbing through the snippet. The other three fields are the same as before.

When you’ve entered all the events, invoke the “Make ICS” command, either by choosing it from the gear popup menu at the bottom of the window or by typing ⌃⌥⌘C. That will generate a new document with the events transformed into the iCalendar format. If you’ve made a formatting error in the Events document, it will (probably) be flagged as such in the iCalendar document. Here’s an example in which

Project conf call|1/7/10 9:00 am|1.00|office|Pull drawings from file
All day event|1/20/10|all day||
Wrong # of fields|8/23/10 9:00 am|1.00|Location
Project meeting|1/10/10 10am|2|Chicago|Bring drawings
Bad start time|1/40/10 9:00 am|1.00|home|
Personal day|1/30/10|all day||
Bad duration|1/12/10 9:00 am|bad|office|whatever
Basketball|1/15/10 7pm|2|Stadium|

is transformed into

BEGIN:VCALENDAR
VERSION:2.0
BEGIN:VEVENT
DTSTART:20100107T090000
DTEND::20100107T100000
SUMMARY:Project conf call
LOCATION:office
DESCRIPTION:Pull drawings from file
END:VEVENT
BEGIN:VEVENT
DTSTART;VALUE=DATE:20100120
DTEND:;VALUE=DATE:20100121
SUMMARY:All day event
LOCATION:
DESCRIPTION:
END:VEVENT
!!!!!!!!!!!!!!!!!!!! This event has the wrong number of fields
BEGIN:VEVENT
DTSTART:20100110T100000
DTEND::20100110T120000
SUMMARY:Project meeting
LOCATION:Chicago
DESCRIPTION:Bring drawings
END:VEVENT
!!!!!!!!!!!!!!!!!!!! This event has a bad start time
BEGIN:VEVENT
DTSTART;VALUE=DATE:20100130
DTEND:;VALUE=DATE:20100131
SUMMARY:Personal day
LOCATION:
DESCRIPTION:
END:VEVENT
!!!!!!!!!!!!!!!!!!!! This event has a bad duration
BEGIN:VEVENT
DTSTART:20100115T190000
DTEND::20100115T210000
SUMMARY:Basketball
LOCATION:Stadium
DESCRIPTION:
END:VEVENT
END:VCALENDAR

On my system, the two documents look like this:

Because I have my iCalendar bundle installed, the generated document is automatically recognized as an iCalendar file and is syntax-highlighted appropriately. When I save it, the .ics extension will be present by default. If you don’t have my iCalendar bundle, TextMate won’t recognize it as an iCalendar file and you’ll have to change the extension from whatever your default is (probably .txt).

You’ll also notice that the pipe characters are colored in my Events document. That’s because I added an entry for tabular separators to the theme (IDLE) that I use.

This highlighting will also work for CSV and TSV files if you have the Tabular bundle installed. If you want special highlighting for the field separators, just add a line with a scope of punctuation.separator.tabular.field to the theme you use. The highlighting isn’t a requirement; the snippets and command will work without it.

The Make ICS command uses the parse function from Python’s datetime the dateutil module to interpret the date and time in the second field. This is a fairly forgiving function; you don’t need to include leading zeros, and as you can see from the example above, even something like “7pm” is interpreted correctly.

Update 1/8/10
Not sure what I was thinking when I wrote datetime in the previous paragraph. The module used is dateutil, which isn’t a standard Python module. On my iMac, it’s in a subdirectory of /System/Library/Frameworks/Python.framework, which suggests that it’s supplied by Apple and not something I installed and later forgot about. I’ll look into it and update here when I get the answer…

OK, I’m back, and I’m pretty sure now that dateutils has been included by Apple since Leopard. So if you’re running OS X 10.5.x or 10.6.x, the Make ICS command will work. If you’re running 10.4.x or earlier, you have three choices. In decreasing order of desirability, they are:

  1. Upgrade to Leopard or Snow Leopard, i.e., get with the program. Look, my home computer is an iBook that came with Jaguar, and it’s perfectly happy with Leopard—I’d have upgraded it to Snow Leopard if it weren’t Intel-only. There’s no reason for you to be that far behind.
  2. Download dateutils from Labix and install it according to their directions.
  3. Just don’t bother with the Calendar Events bundle at all.

I deliberately added errors to three lines in the Events document so you can see how they are handled. The position of the error messages in the iCalendar document will tell you which lines need to be fixed.

After saving the iCalendar document, you can drag it onto one of the calendar names in iCal to get all the events added to that calendar. iCal won’t accept a file with formatting errors, so if you forget to make the necessary corrections, iCal will tell you.

Is this faster than iCal’s normal entry method? Certainly not if you’re just adding one or two events. But if you need to add several events, especially when the events span several weeks or months, it’s much faster. I also find that I make fewer errors because I don’t get frustrated with all the keystrokes and/or mouse clicks iCal demands.


PHP Markdown Extra Math

Tuesday’s MathJax post reminded me that I’ve never made public my modifications to PHP Markdown Extra that allow me to easily write equations here on the blog. So I took a virgin copy of Michel Fortin’s latest version of PHP Markdown Extra, applied my modifications, and put the result in a GitHub repository. From the repository’s README:


PHP Markdown Extra Math is an extension of Michel Fortin’s PHP Markdown Extra, a PHP script for converting text written in Markdown to HTML. The extension consist of adding support for mathematical equations written in LaTeX to be processed by Davide Cervone’s jsMath system.

Here’s how it works. The author, writing in Markdown, inserts inline equations like this

where \(\alpha = (t_1 - t_0)/L\) is the rate at which the thickness increases

enclosing the math in a \( … \) pair, just as if writing in LaTeX. PHP Markdown Extra Math converts that to

where <span class="math"> \alpha = (t_1 - t_0)/L </span> is the rate at which the thickness increases

which is then converted by jsMath into

where \alpha = (t_1 - t_0)/L is the rate at which the thickness increases

Similarly, display Math is written like this:

Putting this into Castigliano's equation, we get

\[\Delta = \frac{\partial U^*}{\partial F} = \frac{12F}{Eb} \int_0^L \frac{x^2}{(t_0 + \alpha x)^3} dx\]

which PHP Markdown Extra Math will turn into this HTML

<p>Putting this into the Castigliano equation, we get</p>

<div class="math">\Delta = \frac{\partial U^*}{\partial F} = \frac{12F}{Eb} \int_0^L \frac{x^2}{(t_0 + \alpha x)^3} dx</div>  

which, in turn, will be rendered by jsMath like this:

Putting this into Castigliano’s equation, we get

\Delta = \frac{\partial U^*}{\partial F} = \frac{12F}{Eb} \int_0^L \frac{x^2}{(t_0 + \alpha x)^3} dx

The examples were taken directly from my post on Castigliano’s Second Theorem.

For posts that have just one or two equations, there’s not much to be gained by using the \( … \) and \[ … \] notation in place of <span class="math"> … </span> and <div class="math"> … </div>, but it’s a real timesaver when the equations start to pile up.

If you’re a jsMath aficionado, you may be wondering why I don’t take advantage of its tex2math extension, which will interpret the \( … \) and \[ … \] notation directly. It’s because Markdown already has a backslash escape syntax that works with parentheses and brackets, and there’s no way for me to keep the notation straight if Markdown and jsMath fighting with each other. So I have the tex2math extensions turned off.


Simplenote cursor problem fixed

Today I installed the latest version of Simplenote, the autosyncing, web-enabled, Helvetica-using note-taking application for the iPhone. The previous two versions of Simplenote had what I considered a terrible flaw: when typing in landscape mode, the text wouldn’t scroll enough to keep the cursor from hiding itself under the onscreen virtual keyboard. I complained about this problem, first here and then here. This is an example of what would happen:

With Simplenote version 2.12 this problem is fixed, and the program is finally—within its niche—just about perfect: it looks good, it works well, and it automatically syncs its data to the cloud, where you can retrieve it from any computer.

And with the new API, some tools for syncing from the cloud to your computer are starting to appear. The most recent is from Fletcher Penney, of MultiMarkdown fame. His syncing utility is close to what I want, but is both

  1. too restrictive, in that it syncs to only one folder on your computer; and
  2. too inclusive, in that it syncs every Simplenote note to that folder.

I’ll probably need to roll my own to get exactly what I want.

Tags:


Simplenote update

The new version of Simplenote came out today, and although it’s fixed many bugs, it still has the bug that bothered me the most.

When you’re typing in landscape mode and you get down to where the virtual keyboard sits, what you’re typing goes under the keyboard where you can’t see it. Simplenote is the only application I know of that has this problem; every other app that I type in scrolls up when the cursor gets to the top of the keyboard. For a note-taking application, seeing what you’re typing should have a higher priority than getting a better-looking icon.1

In other Simplenote news that annoys me, Cloud Factory has apparently released it beta API to a select group that doesn’t include me, despite my being told that I was in the beta group. Listen, Cloud Factory, a super programmer like Alex Paine isn’t going stress test your API the way a klutz like I could.

I guess I’ll just have to grab Simplenote.py from al3x’s GitHub repository.

Update 8/31/09
It’s hard to stay mad at guys who apologize so quickly. But I still don’t understand how the scrolling bug slipped through again.

Tags:


  1. And frankly, the new and improved icon is nothing to write home about. It’s basically an index card with a reversed-colors AirPort Utility icon pasted on top.