4 # SmartyPants - A Plug-In for Movable Type, Blosxom, and BBEdit
6 # http://daringfireball.net
8 # See the readme or POD for details, installation instructions, and
11 # Copyright (c) 2003-2004 John Gruber
16 use vars
qw($VERSION);
21 # Configurable variables:
22 my $smartypants_attr = "1"; # Blosxom and BBEdit users: change this to configure.
23 # 1 => "--" for em-dashes; no en-dash support
24 # 2 => "---" for em-dashes; "--" for en-dashes
25 # 3 => "--" for em-dashes; "---" for en-dashes
26 # See docs for more configuration options.
30 my $tags_to_skip = qr!<(/?)(?:pre|code|kbd|script|math)[\s>]!;
33 # Blosxom plug-in interface:
36 my($pkg, $path, $filename, $story_ref, $title_ref, $body_ref) = @_;
38 $$title_ref = SmartyPants($$title_ref, $smartypants_attr, undef);
39 $$body_ref = SmartyPants($$body_ref, $smartypants_attr, undef);
44 # Movable Type plug-in interface:
45 eval {require MT::Template::Context}; # Test to see if we're running in MT.
47 require MT::Template::Context;
48 import MT::Template::Context;
49 MT::Template::Context->add_global_filter( smarty_pants => \&SmartyPants);
50 MT::Template::Context->add_global_filter( smart_quotes => \&SmartQuotes);
51 MT::Template::Context->add_global_filter( smart_dashes => \&SmartDashes);
52 MT::Template::Context->add_global_filter( smart_ellipses => \&SmartEllipses);
53 MT::Template::Context->add_tag( SmartyPantsVersion => \&SmartyPantsVersion);
55 # If Markdown is loaded, add a combo Markdown/SmartyPants text filter:
56 my $filters = MT->all_text_filters();
57 if (exists( $filters->{'markdown'} )) {
58 my $markdown_ref = $filters->{'markdown'}{on_format};
60 MT->add_text_filter('markdown_with_smartypants' => {
61 label => 'Markdown With SmartyPants',
64 $text = &$markdown_ref($text);
65 $text = SmartyPants($text, $smartypants_attr);
67 docs => 'http://daringfireball.net/projects/markdown/'
73 # BBEdit text filter interface; needs to be hidden from MT
74 # (and Blosxom when running in static mode).
76 # Set up a do-nothing variable to keep Perl from warning us that
77 # we're only using $blosxom::version once. The right way to do this
78 # is to use "no warnings", but that doesn't work in Perl 5.005.
79 my $in_blosxom = defined($blosxom::version);
81 unless ( defined($blosxom::version) ) {
82 #### Check for command-line switches: ###########################
85 Getopt::Long::Configure('pass_through');
86 GetOptions(\%cli_opts,
93 if ($cli_opts{'version'}) { # Version info
94 print "\nThis is Markdown, version $VERSION.\n";
95 print "Copyright 2004 John Gruber\n";
96 print "http://daringfireball.net/projects/markdown/\n";
99 if ($cli_opts{'shortversion'}) { # Just the version number string.
103 if ($cli_opts{'1'}) { $smartypants_attr = 1 };
104 if ($cli_opts{'2'}) { $smartypants_attr = 2 };
105 if ($cli_opts{'3'}) { $smartypants_attr = 3 };
108 #### Process incoming text: #####################################
110 undef $/; # slurp the whole file
113 print SmartyPants($text, $smartypants_attr, undef);
120 my $text = shift; # text to be parsed
121 my $attr = shift; # value of the smart_quotes="" attribute
122 my $ctx = shift; # MT context object (unused)
124 # Options to specify which transformations to make:
125 my ($do_quotes, $do_backticks, $do_dashes, $do_ellipses, $do_stupefy);
126 my $convert_quot = 0; # should we translate " entities into normal quotes?
131 # 2 : set all, using old school en- and em- dash shortcuts
132 # 3 : set all, using inverted old school en and em- dash shortcuts
135 # b : backtick quotes (``double'' only)
136 # B : backtick quotes (``double'' and `single')
138 # D : old school dashes
139 # i : inverted old school dashes
141 # w : convert " entities to " for Dreamweaver users
147 elsif ($attr eq "1") {
148 # Do everything, turn all options on.
154 elsif ($attr eq "2") {
155 # Do everything, turn all options on, use old school dash shorthand.
161 elsif ($attr eq "3") {
162 # Do everything, turn all options on, use inverted old school dash shorthand.
168 elsif ($attr eq "-1") {
169 # Special "stupefy" mode.
173 my @chars = split(//, $attr);
174 foreach my $c (@chars) {
175 if ($c eq "q") { $do_quotes = 1; }
176 elsif ($c eq "b") { $do_backticks = 1; }
177 elsif ($c eq "B") { $do_backticks = 2; }
178 elsif ($c eq "d") { $do_dashes = 1; }
179 elsif ($c eq "D") { $do_dashes = 2; }
180 elsif ($c eq "i") { $do_dashes = 3; }
181 elsif ($c eq "e") { $do_ellipses = 1; }
182 elsif ($c eq "w") { $convert_quot = 1; }
184 # Unknown attribute option, ignore.
189 my $tokens ||= _tokenize($text);
191 my $in_pre = 0; # Keep track of when we're inside <pre> or <code> tags.
193 my $prev_token_last_char = ""; # This is a cheat, used to get some context
194 # for one-character tokens that consist of
195 # just a quote char. What we do is remember
196 # the last character of the previous text
197 # token, to use as context to curl single-
198 # character quote tokens correctly.
200 foreach my $cur_token (@$tokens) {
201 if ($cur_token->[0] eq "tag") {
202 # Don't mess with quotes inside tags.
203 $result .= $cur_token->[1];
204 if ($cur_token->[1] =~ m/$tags_to_skip/) {
205 $in_pre = defined $1 && $1 eq '/' ? 0 : 1;
208 my $t = $cur_token->[1];
209 my $last_char = substr($t, -1); # Remember last char of this token before processing.
211 $t = ProcessEscapes($t);
218 $t = EducateDashes($t) if ($do_dashes == 1);
219 $t = EducateDashesOldSchool($t) if ($do_dashes == 2);
220 $t = EducateDashesOldSchoolInverted($t) if ($do_dashes == 3);
223 $t = EducateEllipses($t) if $do_ellipses;
225 # Note: backticks need to be processed before quotes.
227 $t = EducateBackticks($t);
228 $t = EducateSingleBackticks($t) if ($do_backticks == 2);
233 # Special case: single-character ' token
234 if ($prev_token_last_char =~ m/\S/) {
242 # Special case: single-character " token
243 if ($prev_token_last_char =~ m/\S/) {
252 $t = EducateQuotes($t);
256 $t = StupefyEntities($t) if $do_stupefy;
258 $prev_token_last_char = $last_char;
269 my $text = shift; # text to be parsed
270 my $attr = shift; # value of the smart_quotes="" attribute
271 my $ctx = shift; # MT context object (unused)
273 my $do_backticks; # should we educate ``backticks'' -style quotes?
280 # smarten ``backticks'' -style quotes
287 # Special case to handle quotes at the very end of $text when preceded by
288 # an HTML tag. Add a space to give the quote education algorithm a bit of
289 # context, so that it can guess correctly that it's a closing quote:
290 my $add_extra_space = 0;
291 if ($text =~ m/>['"]\z/) {
292 $add_extra_space = 1; # Remember, so we can trim the extra space later.
296 my $tokens ||= _tokenize($text);
298 my $in_pre = 0; # Keep track of when we're inside <pre> or <code> tags
300 my $prev_token_last_char = ""; # This is a cheat, used to get some context
301 # for one-character tokens that consist of
302 # just a quote char. What we do is remember
303 # the last character of the previous text
304 # token, to use as context to curl single-
305 # character quote tokens correctly.
307 foreach my $cur_token (@$tokens) {
308 if ($cur_token->[0] eq "tag") {
309 # Don't mess with quotes inside tags
310 $result .= $cur_token->[1];
311 if ($cur_token->[1] =~ m/$tags_to_skip/) {
312 $in_pre = defined $1 && $1 eq '/' ? 0 : 1;
315 my $t = $cur_token->[1];
316 my $last_char = substr($t, -1); # Remember last char of this token before processing.
318 $t = ProcessEscapes($t);
320 $t = EducateBackticks($t);
324 # Special case: single-character ' token
325 if ($prev_token_last_char =~ m/\S/) {
333 # Special case: single-character " token
334 if ($prev_token_last_char =~ m/\S/) {
343 $t = EducateQuotes($t);
347 $prev_token_last_char = $last_char;
352 if ($add_extra_space) {
353 $result =~ s/ \z//; # Trim trailing space if we added one earlier.
361 my $text = shift; # text to be parsed
362 my $attr = shift; # value of the smart_dashes="" attribute
363 my $ctx = shift; # MT context object (unused)
365 # reference to the subroutine to use for dash education, default to EducateDashes:
366 my $dash_sub_ref = \&EducateDashes;
373 # use old smart dash shortcuts, "--" for en, "---" for em
374 $dash_sub_ref = \&EducateDashesOldSchool;
377 # inverse of 2, "--" for em, "---" for en
378 $dash_sub_ref = \&EducateDashesOldSchoolInverted;
382 $tokens ||= _tokenize($text);
385 my $in_pre = 0; # Keep track of when we're inside <pre> or <code> tags
386 foreach my $cur_token (@$tokens) {
387 if ($cur_token->[0] eq "tag") {
388 # Don't mess with quotes inside tags
389 $result .= $cur_token->[1];
390 if ($cur_token->[1] =~ m/$tags_to_skip/) {
391 $in_pre = defined $1 && $1 eq '/' ? 0 : 1;
394 my $t = $cur_token->[1];
396 $t = ProcessEscapes($t);
397 $t = $dash_sub_ref->($t);
408 my $text = shift; # text to be parsed
409 my $attr = shift; # value of the smart_ellipses="" attribute
410 my $ctx = shift; # MT context object (unused)
418 $tokens ||= _tokenize($text);
421 my $in_pre = 0; # Keep track of when we're inside <pre> or <code> tags
422 foreach my $cur_token (@$tokens) {
423 if ($cur_token->[0] eq "tag") {
424 # Don't mess with quotes inside tags
425 $result .= $cur_token->[1];
426 if ($cur_token->[1] =~ m/$tags_to_skip/) {
427 $in_pre = defined $1 && $1 eq '/' ? 0 : 1;
430 my $t = $cur_token->[1];
432 $t = ProcessEscapes($t);
433 $t = EducateEllipses($t);
446 # Returns: The string, with "educated" curly quote HTML entities.
448 # Example input: "Isn't this fun?"
449 # Example output: “Isn’t this fun?”
454 # Tell perl not to gripe when we use $1 in substitutions,
455 # even when it's undefined. Use $^W instead of "no warnings"
456 # for compatibility with Perl 5.005:
460 # Make our own "punctuation" character class, because the POSIX-style
461 # [:PUNCT:] is only available in Perl 5.6 or later:
462 my $punct_class = qr/[!"#\$\%'()*+,-.\/:;<=>?\@\[\\\]\^_`{|}~]/;
464 # Special case if the very first character is a quote
465 # followed by punctuation at a non-word-break. Close the quotes by brute force:
466 s/^'(?=$punct_class\B)/’/;
467 s/^"(?=$punct_class\B)/”/;
470 # Special case for double sets of quotes, e.g.:
471 # <p>He said, "'Quoted' words in a larger quote."</p>
472 s/"'(?=\w)/“‘/g;
473 s/'"(?=\w)/‘“/g;
475 # Special case for decade abbreviations (the '80s):
476 s/'(?=\d{2}s)/’/g;
478 my $close_class = qr![^\ \t\r\n\[\{\(\-]!;
479 my $dec_dashes = qr/–|—/;
481 # Get most opening single quotes:
484 \s | # a whitespace char, or
485 | # a non-breaking space entity, or
487 &[mn]dash; | # named dash entities
488 $dec_dashes | # or decimal entities
489 &\#x201[34]; # or hex
492 (?=\w) # followed by a word character
494 # Single closing quotes:
498 (?(1)| # If $1 captured, then do nothing;
499 (?=\s | s\b) # otherwise, positive lookahead for a whitespace
500 ) # char or an 's' at a word ending position. This
501 # is a special case to handle something like:
502 # "<i>Custer</i>'s Last Stand."
505 # Any remaining single quotes should be opening ones:
509 # Get most opening double quotes:
512 \s | # a whitespace char, or
513 | # a non-breaking space entity, or
515 &[mn]dash; | # named dash entities
516 $dec_dashes | # or decimal entities
517 &\#x201[34]; # or hex
520 (?=\w) # followed by a word character
523 # Double closing quotes:
527 (?(1)|(?=\s)) # If $1 captured, then do nothing;
528 # if not, then make sure the next char is whitespace.
531 # Any remaining quotes should be opening ones.
538 sub EducateBackticks {
541 # Returns: The string, with ``backticks'' -style double quotes
542 # translated into HTML curly quote entities.
544 # Example input: ``Isn't this fun?''
545 # Example output: “Isn't this fun?”
555 sub EducateSingleBackticks {
558 # Returns: The string, with `backticks' -style single quotes
559 # translated into HTML curly quote entities.
561 # Example input: `Isn't this fun?'
562 # Example output: ‘Isn’t this fun?’
576 # Returns: The string, with each instance of "--" translated to
577 # an em-dash HTML entity.
586 sub EducateDashesOldSchool {
590 # Returns: The string, with each instance of "--" translated to
591 # an en-dash HTML entity, and each "---" translated to
592 # an em-dash HTML entity.
596 s/---/—/g; # em
602 sub EducateDashesOldSchoolInverted {
606 # Returns: The string, with each instance of "--" translated to
607 # an em-dash HTML entity, and each "---" translated to
608 # an en-dash HTML entity. Two reasons why: First, unlike the
609 # en- and em-dash syntax supported by
610 # EducateDashesOldSchool(), it's compatible with existing
611 # entries written before SmartyPants 1.1, back when "--" was
612 # only used for em-dashes. Second, em-dashes are more
613 # common than en-dashes, and so it sort of makes sense that
614 # the shortcut should be shorter to type. (Thanks to Aaron
615 # Swartz for the idea.)
619 s/---/–/g; # en
625 sub EducateEllipses {
628 # Returns: The string, with each instance of "..." translated to
629 # an ellipsis HTML entity. Also converts the case where
630 # there are spaces between the dots.
632 # Example input: Huh...?
633 # Example output: Huh…?
638 s/\. \. \./…/g;
643 sub StupefyEntities {
646 # Returns: The string, with each SmartyPants HTML entity translated to
647 # its ASCII counterpart.
649 # Example input: “Hello — world.”
650 # Example output: "Hello -- world."
655 s/–/-/g; # en-dash
656 s/—/--/g; # em-dash
658 s/‘/'/g; # open single quote
659 s/’/'/g; # close single quote
661 s/“/"/g; # open double quote
662 s/”/"/g; # close double quote
664 s/…/.../g; # ellipsis
670 sub SmartyPantsVersion {
678 # Returns: The string, with after processing the following backslash
679 # escape sequences. This is useful if you want to force a "dumb"
680 # quote or other character to appear.
706 # Parameter: String containing HTML markup.
707 # Returns: Reference to an array of the tokens comprising the input
708 # string. Each token is either a tag (possibly with nested,
709 # tags contained therein, such as <a href="<MTFoo>">, or a
710 # run of text between tags. Each element of the array is a
711 # two-element array; the first is either 'tag' or 'text';
712 # the second is the actual value.
715 # Based on the _tokenize() subroutine from Brad Choate's MTRegex plugin.
716 # <http://www.bradchoate.com/past/mtregex.php>
721 my $len = length $str;
725 my $nested_tags = join('|', ('(?:<(?:[^<>]') x $depth) . (')*>)' x $depth);
726 my $match = qr/(?s: <! ( -- .*? -- \s* )+ > ) | # comment
727 (?s: <\? .*? \?> ) | # processing instruction
728 $nested_tags/x; # nested tags
730 while ($str =~ m/($match)/g) {
732 my $sec_start = pos $str;
733 my $tag_start = $sec_start - length $whole_tag;
734 if ($pos < $tag_start) {
735 push @tokens, ['text', substr($str, $pos, $tag_start - $pos)];
737 push @tokens, ['tag', $whole_tag];
740 push @tokens, ['text', substr($str, $pos, $len - $pos)] if $pos < $len;
758 B<SmartyPants.pl> [ B<-1> ] [ B<-2> ] [ B<-3> ] [ B<--version> ] [ B<--shortversion> ]
764 SmartyPants is a web publishing utility that translates plain ASCII
765 punctuation characters into "smart" typographic punctuation HTML
766 entities. SmartyPants can perform the following transformations:
772 Straight quotes ( " and ' ) into "curly" quote HTML entities
776 Backticks-style quotes (``like this'') into "curly" quote HTML entities
780 Dashes (C<--> and C<--->) into en- and em-dash entities
784 Three consecutive dots (C<...>) into an ellipsis entity
788 SmartyPants is a combination plug-in -- the same file works with Movable
789 Type, Blosxom, BBEdit, and as a standalone Perl script. Version
790 requirements and installation instructions for each of these tools can
791 be found in the readme file that accompanies this script.
793 SmartyPants does not modify characters within C<< <pre> >>, C<< <code> >>,
794 C<< <kbd> >>, C<< <script> >>, or C<< <math> >> tag blocks.
795 Typically, these tags are used to display text where smart quotes and
796 other "smart punctuation" would not be appropriate, such as source code
800 =head2 Backslash Escapes
802 If you need to use literal straight quotes (or plain hyphens and
803 periods), SmartyPants accepts the following backslash escape sequences
804 to force non-smart punctuation. It does so by transforming the escape
805 sequence into a decimal-encoded HTML entity:
807 Escape Value Character
808 ------ ----- ---------
816 This is useful, for example, when you want to use straight quotes as
817 foot and inch marks: 6'2" tall; a 17" iMac.
822 Use "--" to end switch parsing. For example, to open a file named "-z", use:
831 Performs default SmartyPants transformations: quotes (including
832 backticks-style), em-dashes, and ellipses. '--' (dash dash) is used to
833 signify an em-dash; there is no support for en-dashes.
838 Same as B<-1>, except that it uses the old-school typewriter shorthand
839 for dashes: '--' (dash dash) for en-dashes, '---' (dash dash dash) for
845 Same as B<-2>, but inverts the shorthand for dashes: '--'
846 (dash dash) for em-dashes, and '---' (dash dash dash) for en-dashes.
849 =item B<-v>, B<--version>
851 Display SmartyPants's version number and copyright information.
854 =item B<-s>, B<--shortversion>
856 Display the short-form version number.
865 To file bug reports or feature requests (other than topics listed in the
866 Caveats section above) please send email to:
868 smartypants@daringfireball.net
870 If the bug involves quotes being curled the wrong way, please send example
874 =head2 Algorithmic Shortcomings
876 One situation in which quotes will get curled the wrong way is when
877 apostrophes are used at the start of leading contractions. For example:
879 'Twas the night before Christmas.
881 In the case above, SmartyPants will turn the apostrophe into an opening
882 single-quote, when in fact it should be a closing one. I don't think
883 this problem can be solved in the general case -- every word processor
884 I've tried gets this wrong as well. In such cases, it's best to use the
885 proper HTML entity for closing single-quotes (C<’>) by hand.
889 =head1 VERSION HISTORY
891 1.5.1: Fri 12 Mar 2004
893 + Fixed a goof where if you had SmartyPants 1.5.0 installed,
894 but didn't have Markdown installed, when SmartyPants checked
895 for Markdown's presence, it created a blank entry in MT's
896 global hash of installed text filters. This showed up in MT's
897 Text Formatting pop-up menu as a blank entry.
902 + Integration with Markdown. If Markdown is already loaded
903 when SmartyPants loads, SmartyPants will add a new global
904 text filter, "Markdown With Smartypants".
906 + Preliminary command-line options parsing. -1 -2 -3
909 + dot-space-dot-space-dot now counts as an ellipsis.
910 This is the style used by Project Gutenberg:
911 http://www.gutenberg.net/faq/index.shtml#V.110
912 (Thanks to Fred Condo for the patch.)
914 + Added `<math>` to the list of tags to skip (pre, code, etc.).
917 1.4.1: Sat 8 Nov 2003
919 + The bug fix from 1.4 for dashes followed by quotes with no
920 intervening spaces now actually works.
922 + " " now counts as whitespace where necessary. (Thanks to
923 Greg Knauss for the patch.)
928 + Improved the HTML tokenizer so that it will parse nested <> pairs
929 up to five levels deep. Previously, it only parsed up to two
930 levels. What we *should* do is allow for any arbitrary level of
931 nesting, but to do so, we would need to use Perl's ?? construct
932 (see Fried's "Mastering Regular Expressions", 2nd Ed., pp.
933 328-331), and sadly, this would only work in Perl 5.6 or later.
934 SmartyPants still supports Perl 5.00503. I suppose we could test
935 for the version and build a regex accordingly, but I don't think
936 I want to maintain two separate patterns.
938 + Thanks to Stepan Riha, the tokenizer now handles HTML comments:
941 and PHP-style processor instructions:
944 + The quote educator now handles situations where dashes are used
945 without whitespace, e.g.:
947 "dashes"--without spaces--"are tricky"
949 + Special case for decade abbreviations like this: the '80s.
950 This only works for the sequence appostrophe-digit-digit-s.
955 + Plugged the biggest hole in SmartyPants's smart quotes algorithm.
956 Previous versions were hopelessly confused by single-character
957 quote tokens, such as:
959 <p>"<i>Tricky!</i>"</p>
961 The problem was that the EducateQuotes() function works on each
962 token separately, with no means of getting surrounding context
963 from the previous or next tokens. The solution is to curl these
964 single-character quote tokens as a special case, *before* calling
967 + New single-quotes backtick mode for smarty_pants attribute.
968 The only way to turn it on is to include "B" in the configuration
969 string, e.g. to translate backtick quotes, dashes, and ellipses:
973 + Fixed a bug where an opening quote would get curled the wrong way
974 if the quote started with three dots, e.g.:
976 <p>"...meanwhile"</p>
978 + Fixed a bug where opening quotes would get curled the wrong way
979 if there were double sets of quotes within each other, e.g.:
981 <p>"'Some' people."</p>
983 + Due to popular demand, four consecutive dots (....) will now be
984 turned into an ellipsis followed by a period. Previous versions
985 would turn this into a period followed by an ellipsis. If you
986 really want a period-then-ellipsis sequence, escape the first
987 period with a backslash: \....
989 + Removed "&" from our home-grown punctuation class, since it
990 denotes an entity, not a literal ampersand punctuation
991 character. This fixes a bug where SmartyPants would mis-curl
992 the opening quote in something like this:
996 + SmartyPants has always had a special case where it looks for
997 "'s" in situations like this:
999 <i>Custer</i>'s Last Stand
1001 This special case is now case-insensitive.
1004 1.2.2: Thu Mar 13, 2003
1006 + 1.2.1 contained a boneheaded addition which prevented SmartyPants
1007 from compiling under Perl 5.005. This has been remedied, and is
1008 the only change from 1.2.1.
1011 1.2.1: Mon Mar 10, 2003
1013 + New "stupefy mode" for smarty_pants attribute. If you set
1017 SmartyPants will perform reverse transformations, turning HTML
1018 entities into plain ASCII equivalents. E.g. "“" is turned
1019 into a simple double-quote ("), "—" is turned into two
1020 dashes, etc. This is useful if you are using SmartyPants from Brad
1021 Choate's MT-Textile text filter, but wish to suppress smart
1022 punctuation in specific MT templates, such as RSS feeds. Text
1023 filters do their work before templates are processed; but you can
1024 use smarty_pants="-1" to reverse the transformations in specific
1027 + Replaced the POSIX-style regex character class [:punct:] with an
1028 ugly hard-coded normal character class of all punctuation; POSIX
1029 classes require Perl 5.6 or later, but SmartyPants still supports
1032 + Several small changes to allow SmartyPants to work when Blosxom
1033 is running in static mode.
1036 1.2: Thu Feb 27, 2003
1038 + SmartyPants is now a combination plug-in, supporting both
1039 Movable Type (2.5 or later) and Blosxom (2.0 or later).
1040 It also works as a BBEdit text filter and standalone
1041 command-line Perl program. Thanks to Rael Dornfest for the
1042 initial Blosxom port (and for the excellent Blosxom plug-in
1045 + SmartyPants now accepts the following backslash escapes,
1046 to force non-smart punctuation. It does so by transforming
1047 the escape sequence into a decimal-encoded HTML entity:
1049 Escape Value Character
1050 ------ ----- ---------
1058 Note that this could produce different results than previous
1059 versions of SmartyPants, if for some reason you have an article
1060 containing one or more of these sequences. (Thanks to Charles
1061 Wiltgen for the suggestion.)
1063 + Added a new option to support inverted en- and em-dash notation:
1064 "--" for em-dashes, "---" for en-dashes. This is compatible with
1065 SmartyPants' original "--" syntax for em-dashes, but also allows
1066 you to specify en-dashes. It can be invoked by using
1067 smart_dashes="3", smarty_pants="3", or smarty_pants="i".
1068 (Suggested by Aaron Swartz.)
1070 + Added a new option to automatically convert " entities into
1071 regular double-quotes before sending text to EducateQuotes() for
1072 processing. This is mainly for the benefit of people who write
1073 posts using Dreamweaver, which substitutes this entity for any
1074 literal quote char. The one and only way to invoke this option
1075 is to use the letter shortcuts for the smarty_pants attribute;
1076 the shortcut for this option is "w" (for Dream_w_eaver).
1077 (Suggested by Jonathon Delacour.)
1079 + Added <script> to the list of tags in which SmartyPants doesn't
1082 + Fixed a very subtle bug that would occur if a quote was the very
1083 last character in a body of text, preceded immediately by a tag.
1084 Lacking any context, previous versions of SmartyPants would turn
1085 this into an opening quote mark. It's now correctly turned into
1088 + Opening quotes were being curled the wrong way when the
1089 subsequent character was punctuation. E.g.: "a '.foo' file".
1092 + New MT global template tag: <$MTSmartyPantsVersion$>
1093 Prints the version number of SmartyPants, e.g. "1.2".
1096 1.1: Wed Feb 5, 2003
1098 + The smart_dashes template attribute now offers an option to
1099 use "--" for *en* dashes, and "---" for *em* dashes.
1101 + The default smart_dashes behavior now simply translates "--"
1102 (dash dash) into an em-dash. Previously, it would look for
1103 " -- " (space dash dash space), which was dumb, since many
1104 people do not use spaces around their em dashes.
1106 + Using the smarty_pants attribute with a value of "2" will
1107 do the same thing as smarty_pants="1", with one difference:
1108 it will use the new shortcuts for en- and em-dashes.
1110 + Closing quotes (single and double) were incorrectly curled in
1111 situations like this:
1113 where the comma could be just about any punctuation character.
1116 + Added <kbd> to the list of tags in which text shouldn't be
1120 1.0: Wed Nov 13, 2002
1128 http://daringfireball.net
1131 =head1 ADDITIONAL CREDITS
1133 Portions of this plug-in are based on Brad Choate's nifty MTRegex plug-in.
1134 Brad Choate also contributed a few bits of source code to this plug-in.
1135 Brad Choate is a fine hacker indeed. (http://bradchoate.com/)
1137 Jeremy Hedley (http://antipixel.com/) and Charles Wiltgen
1138 (http://playbacktime.com/) deserve mention for exemplary beta testing.
1140 Rael Dornfest (http://raelity.org/) ported SmartyPants to Blosxom.
1143 =head1 COPYRIGHT AND LICENSE
1145 Copyright (c) 2003 John Gruber
1146 (http://daringfireball.net/)
1147 All rights reserved.
1149 Redistribution and use in source and binary forms, with or without
1150 modification, are permitted provided that the following conditions are met:
1152 * Redistributions of source code must retain the above copyright
1153 notice, this list of conditions and the following disclaimer.
1155 * Redistributions in binary form must reproduce the above copyright
1156 notice, this list of conditions and the following disclaimer in the
1157 documentation and/or other materials provided with the distribution.
1159 * Neither the name "SmartyPants" nor the names of its contributors may
1160 be used to endorse or promote products derived from this software
1161 without specific prior written permission.
1163 This software is provided by the copyright holders and contributors "as is"
1164 and any express or implied warranties, including, but not limited to, the
1165 implied warranties of merchantability and fitness for a particular purpose
1166 are disclaimed. In no event shall the copyright owner or contributors be
1167 liable for any direct, indirect, incidental, special, exemplary, or
1168 consequential damages (including, but not limited to, procurement of
1169 substitute goods or services; loss of use, data, or profits; or business
1170 interruption) however caused and on any theory of liability, whether in
1171 contract, strict liability, or tort (including negligence or otherwise)
1172 arising in any way out of the use of this software, even if advised of the
1173 possibility of such damage.