Posts Tagged ‘text editing’
Ack
June 18th, 2010 at 11:03 pm
At the end of last week’s post about trusses, I mentioned that I had found an old photo of a roof truss by greping for the word “truss” in a folder of project reports on my work computer. I should not have grep’d; I should have ack’d.
Ack is a Perl script that’s meant to be a replacement of and improvement on the venerable Unix search tool grep. I’d read about ack quite a while ago—there’s a TextMate bundle called Ack in Project that’s well thought of—but kept forgetting to install it. Now that I have it installed, I see some obvious improvements.
- Speed. I haven’t done any formal timing tests, but
ackis clearly faster. - Presentation.
Ackshows its results in a much clearer format. I must say, though, that I’m not thrilled with some of the colors it uses in the output—maybe those can be changed in the.ackrcconfiguration file. - Better regular expressions. And by that I mean Perl’s regular expressions.
- Subdirectory search by default. I usually want my searches to walk down into the subdirectories but am always forgetting to turn on
grep’s recursive search option (-r), so having recursive search as the default is a big help. - No searching in revision control subdirectories. For me, that means the default is to avoid my
.gitfolders, butackalso knows to avoid folders named.svn,.hg,.bzr,CVS,RCS, and so on.
A couple of ack’s defaults are not to my liking.
- It doesn’t search in files that it considers “text” files. Since a lot of my searching is in just these kinds of files—mostly Markdown—this default works against me.
- It’s searches are case-sensitive. This is no different than
grep’s default, but that doesn’t mean I like having to always use the-iswitch.
These defaults betray ack’s origins as a programmer’s tool. Programmers usually want to search through their source code and avoid extraneous hits in, say, the documentation files. And most of today’s languages are case-sensitive, so it only makes sense for the default searches to be so as well.
Luckily for me, ack’s defaults can be changed through an .ackrc file in my home directory. Right now my .ackrc has just two lines:
--type=text
--smart-case
The first line tells ack to go ahead and search the text files. The second tells it to do case-insensitive searches unless the search term has a capital letter. The format of the .ackrc is simple: each line represents a command line switch and is written just as if you were adding it to an ack command—there’s no special dotfile syntax.
I’ll probably add more lines to my .ackrc as I learn more about it. For now, I’m just wondering why I didn’t switch from grep earlier.
Relative links in PNotes
May 31st, 2010 at 4:13 pm
In the last big change to my no-server wiki system—which I now call PNotes—I added the ability to categorize notes by subdirectory. This made PNotes more organized, but because I took some shortcuts in the programming I lost some of the portability of the system. In the last few days I’ve fixed the code to get portability back and uploaded the fixes to the PNotes GitHub repository.

One of my goals with PNotes was to create a wiki-like system that was self-contained within a folder—no reliance on a database system. I wanted to be able to move the PNotes folder anywhere—from place to place on my main computer, to my notebook, to someone else’s computer, to a CDROM or DVD, to my iPhone—and still have it work. When I added the ability to have notes in subdirectories, I decided to use a <base> tag in the <head> of each note to make it easier to generate the list of links in the sidebar.

The <base> tag made all the sidebar links absolute instead of relative, and this broke the portability I wanted. I could still move a PNotes folder anywhere on any of my computers because my computers have all the utility programs needed to regenerate the HTML files in their new location—all I had to do was reset the <base> and run make clean; make in the new directory. But I couldn’t zip up a copy of a PNotes folder and send it someone else, nor could I put it on my iPhone; the <base> would be wrong and screw up all the links.
Now, through a combination of Python and JavaScript, PNotes portability has been restored. You’ll need one line in the project.info file,
dirname = notes
to tell the system the name of the PNotes folder. I’ve always just used “notes,” but you can use any name as long as you set the dirname option accordingly. (I strongly suggest you stick to alphanumeric characters; the folder name is used in a regular expression, so special characters like parentheses and hyphens could mess things up)
Strictly speaking, the new PNotes isn’t perfectly portable. For example, the two “Edit” links in the sidebar won’t work unless the computer understands the txmt:// URL scheme for opening a file in TextMate (or BBEdit). And the contacts links won’t work unless it understands the addressbook:// scheme and has the same list of contacts with the same Address Book IDs. But all the links to notes should work on any computer.
The latest changes have made the GitHub README for PNotes a little out of date. I’ll be fixing it up in the next few days.
TextExpander abbreviation design
March 15th, 2010 at 12:17 pm
You’ve probably seen Merlin Mann’s little screencast about TextExpander 3. He does a nice job of showing dynamically what I tried to show statically in this post: TE3’s new feature that lets you define snippets with multiple fill-in-the-blank fields. Watching the video, I learned a couple of things about Merlin’s use of TextExpander:
- He has his abbreviations expanded immediately instead of using a delimiter.
- He uses simple abbreviations without any special characters.
Because I also have my abbreviations expanded immediately, I’m a bit surprised Merlin doesn’t use a “signal character” to distinguish his abbreviations. Let me explain what I do and why.
First, delimiters. TextExpander’s Preferences give you the option of expanding snippets as soon as you finish typing the abbreviation or waiting until you’ve typed a delimiter.

A delimiter is typically a “word-ending” character: a space, a tab, or any one of a number of punctuation marks.

The idea behind delimiters is to keep TextExpander from doing an expansion sooner than you want it to. For example, a natural abbreviation for “TextExpander” is “te,” but if you have that as your abbreviation and you use immediate expansion, you’d never be able to type a word like “tell”—as soon as you hit the “e,” TextExpander would do the expansion, and you’d end up with “TextExpanderll.” Using delimiters, the expansion will only occur when you type “te” as a separate word.
Unfortunately, forcing TextExpander to wait until a delimiter is typed isn’t a complete solution. Depending on context, “te” might make a great variable name, and if I wanted a program line like
te = sys.argv[2]
TextExpander would turn it into
TextExpander = sys.argv[2]
You can tell TextExpander not to expand abbreviations in certain applications, but that does me no good, as I write both regular text and programs in the same application. (At the beginning of Merlin’s screencast, you see that he uses “sdate” as one of his abbreviations. That’s an even better variable name than “te.”)
Also, I have TextExpander fix some of my common typos. I have an “hte” snippet that expands to “the.”1 By using immediate expansion instead of delimiters, that snippet works to correct “htere” and “hten” as well as “hte” itself.
So, since delimited expansion doesn’t get me what I want, I use immediate expansion and a trick. The trick is to always start my abbreviations with a semicolon. There are no situations in my writing or programming in which a semicolon will be followed by anything other than whitespace. In English, a semicolon is always followed by a space; and in programming it’s almost always a statement delimiter—illegal to use in a variable name. Yes, most languages allow you to squeeze statements together,
a=5;b=6;
but that’s not considered good style unless you’re doing a Perl one-liner on the command line. It’s not something that comes up in my programming.
The semicolon is the perfect special character for abbreviations not only because of its use in English and programming, but also because of its position on the keyboard. It’s one of the home keys and it doesn’t require a Shift. Typing it is almost effortless.
With my system, an abbreviation like ;te works perfectly, as do abbreviations like
;bill, which gives me the fill-in-the-blanks expansion I showed in my earlier post;apple, which expands2 to the Apple character, ;shift, which expands to the Shift key character, ⇧;times, which expands to the multiplication symbol, ×
These are, I think, the natural abbreviations to use, and because they are real words, they wouldn’t work as abbreviations if it weren’t for the leading semicolon.
I know I’m not the only one who does this. I’m pretty sure I once saw a Twitter exchange between Jason Snell and John Gruber in which they each learned that the other used leading semicolons. When I saw that, I knew I was in good company.
Sadly, the semicolon trick is a poor match for the iPhone version of TextExpander because the semicolon key isn’t on the iPhone’s main keyboard. The few snippets I have on the iPhone—mostly date and time stamps—use a trailing “z” to distinguish them from real words. It’s not as good as the semicolon trick, but it works with a limited number of snippets.
TextExpander 3
March 11th, 2010 at 10:59 pm
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
February 11th, 2010 at 10:35 pm
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:
- Open the image you want to use and copy it to the clipboard.
- In the Finder, do a Get Info on the folder you want to change.
- Select the folder’s icon at the top of the Get Info window by clicking on it.
- 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
February 10th, 2010 at 4:32 pm
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:
- 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.
- 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.
- 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.
- To be able to change the visual style of the notes as my needs or tastes change.
- To create new notes quickly and easily.
Requirements
Apart from what’s in the repository, you’ll need
- Python. The two build scripts,
buildPage.pyandbuildNotesList.py, are written in Python. - GNU make. The build scripts are controlled by a makefile.
- A Markdown processor. I use a self-customized version of Fletcher Penney’s MultiMarkdown. Whatever you use, you’ll have to provide the name of that command on Line 16 of
buildPage.py. - A SmartyPants processor. I use Gruber’s SmartyPants. Again, you’ll have to provide the name of that command on Line 16 of
buildPage.py.
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:
header.tmpl, the HTML template file with all the common code above the content.footer.tmpl, the HTML template file with all the common code below the content.project.info, a file of project-specific data, including the project name and number, the list of contacts (including links to Address Book entries if you’re on a Mac), and thefile://URI for the top-level directory.notes.css, the style file for browsing.notes-print.css, the style file for printing.styleLineNumbers.js, a pair of JavaScript functions that improve the formatting of source code.buildPage.py, a Python script that combines a Markdown input file with the template files and produces a single HTML file.buildNotesList.py, a Python script that searches the directory (and subdirectories) for notes files and generates a list of links to all the notes for display in the sidebar.Makefile, the makefile that controls the build scripts.
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.










