4
** cquotes: a TADS 3 output filter for making single curly quotes
6
** To use, just add to your project. The PreinitObject at the end
7
** of this file automatically registers the curly quote output filter.
9
** You may use this module in your own game. You may distribute
10
** modified versions of this file, though I would prefer you contact
11
** me first at stephen@granades.com and see about having me add your
12
** changes to my source.
14
** Version: 0.2 (2 Feb 2004)
15
** Added in fixes for patIsHTMLTag and patIsFormatTag from
20
** Copyright (c) 2002, 2004 by Stephen Granade. All Rights Reserved.
26
// A filter to change single quotes "'" to curly ones. Comes in two
29
// non-aggressive: will only change the single quotes that are part
30
// of English contractions (like "won't") into ‘
31
// aggressive: will change every single left quote it can find. Any
32
// single quote that is preceeded by a letter or punctuation is
33
// turned into ‘.
35
// To choose between them, set cquoteOutputFilter.aggressive to
36
// true (for aggressive changing) or nil (for non-aggressive matching).
38
// No translation is done to single quotes which a) fall within HTML
39
// tags (i.e. <font face='courier'>), or b) fall within
40
// formatting tags (i.e. {It's obj})
41
cquoteOutputFilter: OutputFilter
44
// Patterns for our searches
45
patIsHTMLTag = static new RexPattern('<langle><^rangle>+<squote><^rangle>*<rangle>')
46
patIsFormatTag = static new RexPattern('{[^}]+<squote>[^}]*}')
47
patAggressive = static new RexPattern('(<alphanum|punct>)<squote>')
48
patIsCont1Tag = static new RexPattern('(<alpha>)<squote>(s|m|d|ve|re|ll)')
49
patIsCont2Tag = static new RexPattern('(<alpha>)n<squote>t')
50
patIsPossTag = static new RexPattern('(<alpha>)s<squote>')
52
filterText(ostr, val) {
55
// Look for an HTML tag. We only need to find the first one,
56
// because we'll be recursing through the string
57
ret = rexSearch(patIsHTMLTag, val);
59
// Look for a formatting tag
60
ret = rexSearch(patIsFormatTag, val);
62
// If we got a match either from the HTML or the formatting
63
// tag, ignore that match recursively; that is, run the output
64
// filter on the text before and after the match. This is
65
// assuming that the whole start wasn't prefixed by a backslash
66
// (since e.g. "\<font face='courier>" isn't really an HTML tag)
67
if (ret != nil && (ret[1] == 1 ||
68
val.substr(ret[1] - 1, 1) != '\\')) {
69
return filterText(ostr, val.substr(1, ret[1] - 1)) + ret[3] +
70
filterText(ostr, val.substr(ret[1] + ret[2],
71
val.length() - (ret[1]+ret[2])
75
// Do the appropriate replacements. First, aggressive
77
val = rexReplace(patAggressive, val, '%1’',
81
// We recognize the contractions 's, 'm, 'd, 've, 're,
82
// 'll, and n't, as well as the plural possessive s'.
83
// (Possessive 's is handled by the contraction.) All
84
// must be preceeded by a letter.
85
val = rexReplace(patIsCont1Tag,
86
val, '%1’%2', ReplaceAll);
87
val = rexReplace(patIsCont2Tag, val, '%1n’t',
89
val = rexReplace(patIsPossTag, val, '%1s’',
97
// When we first start up, register us as an output filter
100
mainOutputStream.addOutputFilter(cquoteOutputFilter);