Inspired by Danny O'Brien's lucky Google VIM macro, but being both an Emacs user and even lazier than him, I've whipped up some automatic lucky Google macros.

Proper nouns, acronyms, and anything in {{double braces}} gets linked to a Google search for that term, with the "I'm Feeling Lucky" option turned on.

I'm sure there's problems with them -- in particular, I'm worried about the proper noun one leading to nested <A>s -- but they seem to be working pretty well, and they're kinda spiffy, so here you go.

I may turn off the completely automatic ones after a while, but I think I'll be keeping the double braces.

Update: I'm now running a new version of these, with the following improvements:

  • the double-brace one matches inner-braces rather than leftmost-braces, making the display on my example look better
  • the REs are spread out and somewhat commented, using perl's /x mode, so there's some hope of understanding what they do
  • the nested <a> problem is taken care of. Unfortunately, this required a new feature in the macros plugin, a 'redo' flag, which causes the macro to keep being run over a block of text as long as it's still changing it; the nested-anchor stripper needs this to be able to deal with an arbitrary number of anchors within another anchor; for any specific maximum, you could just repeat the macro definition that many times.

If you want to use these now, you can as always grab a copy of the actual plugins that I'm running, but as those are by definition works-in-progress they're more likely to have problems (and be harder to install, and be underdocumented) than the real releases.

Tamara asked on the Blosxom mailing list if my macros plugin was capable of making external links open in new windows like this.

My first answer was no -- it's missing two features that that uses, <MTIfMatches> and MTMacros' 'rebuild'. Furthermore, I don't really think MTIfMatches belongs in macros; it's a better fit for a somewhat fancier interpolate-conditional.

I'm not sure how exactly MTMacros' 'rebuild' works, and it may well be a useful feature to steal borrow...I should look at that.

I realized this morning that there is in fact a way, though; it's not quite as clean as Adam Kelsey's, since it's simply text based rather than tag-based, but it seems to work just fine.

The magic is in these macros (use the download link to get a good straight-text version):

define_macro({
  type => 'pattern',
  pattern => qr'<a\s(?![^>]*class)([^>]*href="/)'ms,
  body => '<a class="relative" ${1}',
  inhtml => 1
});

That looks for 'a' tags that don't have a 'class' attribute, with an 'href' attribute that starts with a slash, and adds a 'class="relative"' attribute.

define_macro({
  type => 'pattern',
  pattern => qr'<a\s(?![^>]*class)([^>]*href="http://[^/]*molehill\.org[:/])'ms,
  body => '<a class="local" ${1}',
  inhtml => 1
});

That looks for 'a' elements that don't have a 'class' attribute, with an 'href' attribute that starts with an a "http://", and has my domain name before the next / or :, and gives them a 'class="local"' attribute.

define_macro({
  type => 'pattern',
  pattern => qr'<a\s(?![^>]*class)([^>]*href)'ms,
  body => '<a class="remote" ${1}',
  inhtml => 1
});

That looks for 'a' elements that don't have a 'class' attribute, but do have an 'href' attribute (that prevents it from applying to anchors used just for naming); and gives them a 'class="remote"' attribute; that's right, since every non-remote link has been given a 'local' or 'relative' class.

I'm also using some stylesheet magic:

a.remote {
	padding-right:		12px;
	background-image:	url(/icon/aoutside.gif);
	background-position:	right;
	background-repeat:	no-repeat;
}

and an icon apparently from WebGragpics.

I didn't add "target" attributes, but it should be clear how to do that -- simply put them before the 'class' in the replacement text.

As I said, this isn't quite as clean, and it's not 100% correct -- the word "class" in an href could confuse it, for instance. But it's pretty close, and it's doable now. (it could be improved by replacing the (?![>]*class)s with (?![>]*\bclass=")s, but that still wouldn't be 100% right, and I wanted to present what I'm actually using and have tested).

This is the first general release of my macros plugin, a highly generalized macro package modelled on (but not actually based on, code-wise) Brad Choate's MT-Macros package.

This release includes string macros, pattern macros, tag macros (html-like tags without content, like html's <img>) and content tag macros (html-like tags with content, like html's <a>...</a>). String and pattern macros may be restricted to only match in content areas, not in markup. Any macro can be set to only match once per story.

See the documentation in the plugin itself, or the macro files I actually use or that I test with, for documentation and examples of the syntax.

To install:

  1. download and unzip the plugin.
  2. Copy it to your plugins directory. Make sure it's world-readable.
  3. Create a $plugin_state_dir/.macros directory, and put macro definition files in it.
  4. Use it!
  5. Drop me a note to let me know you're using it; if you're having problems, let me know and I might be able to help. If everything's working okay, please let me know that, too.

Things that are missing (not all of them appear useful, though):

  • MT-Macros 'recursion' option isn't available. If this is a real problem for you, please let me know, preferably with a good example of what you can't accomplish currently (remember, macros are invoked in the order they're defined, which you can control with filename naming)
  • tag and ctag macros can't be used in HTML markup. This would be a big problem for Movable Type, where parameter replacement is done with psuedo-HTML, but doesn't seem to be a problem for Blosxom. If it is for you, please let me know, again along with an example.
  • MT-Macros 'no_case' option isn't available. This can be done by including (?i) in your patterns or defining them with qr//i, instead.
  • tag and ctag macros can't be explicitely named, because the 'name' parameter is already being used. Future versions may change tag and ctag to use 'string' or 'pattern' for what 'name' is currently used for, and use 'name' to define a macro. That will only be done if there's a good use for names, though.
  • Once defined, macros are always active. They can't be deactivated on a per-story basis. This might be handled with a meta- header at some point, if someone gives me a reasonable example for why they need it.
  • There's no built-in data-based macro definition syntax. It's not clear to me that a literal define_macro() call is any more difficult than MT-Macros' HTML-looking (but not HTML-acting) definition syntax, though, and as shown above simpler syntaxes ban be custom-built as appropriate. I'd be more than happy to include a simpler syntax, though, if someone were to develop one that were obviously better than define_syntax().

Plugins that I think could be replaced with this:

  • strip_unix_comments (pattern ^#.*?$ -> '')
  • asin
  • dictionary (macro definition file that reads the dictionary file to create macros)
  • citysearchtag
  • macrolinks
  • galleryref
  • amps

Plugins that can't be, but maybe should be -- missing functionality?

  • wikiwordish (would need to be able to invoke a user function to get replacement text)
  • functions (same as wikiwordish)
  • date_fullname (would need to be able to repalce text after interpolation, and to run against date as well as story)
  • date_translate
  • seemore (would need to be able to enable/disable macro based on $path or parameter)