From d966583854d7c7f4a7df25c0e2a8d6b9e217a12c Mon Sep 17 00:00:00 2001 From: Jermolene Date: Wed, 12 Jul 2017 16:46:13 +0100 Subject: [PATCH] Add new "\whitespace" pragma MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This will allow us to simplify some of the more unreadable core wikitext tiddlers… --- .../parsers/wikiparser/rules/whitespace.js | 72 +++++++++++++++++++ core/modules/parsers/wikiparser/wikiparser.js | 24 +++++-- editions/tw5.com/tiddlers/concepts/Pragma.tid | 4 +- 3 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 core/modules/parsers/wikiparser/rules/whitespace.js diff --git a/core/modules/parsers/wikiparser/rules/whitespace.js b/core/modules/parsers/wikiparser/rules/whitespace.js new file mode 100644 index 000000000..e3b0c8e3f --- /dev/null +++ b/core/modules/parsers/wikiparser/rules/whitespace.js @@ -0,0 +1,72 @@ +/*\ +title: $:/core/modules/parsers/wikiparser/rules/whitespace.js +type: application/javascript +module-type: wikirule + +Wiki pragma rule for whitespace specifications + +``` +\whitespace trim +\whitespace notrim +``` + +\*/ +(function(){ + +/*jslint node: true, browser: true */ +/*global $tw: false */ +"use strict"; + +exports.name = "whitespace"; +exports.types = {pragma: true}; + +/* +Instantiate parse rule +*/ +exports.init = function(parser) { + this.parser = parser; + // Regexp to match + this.matchRegExp = /^\\whitespace[^\S\n]/mg; +}; + +/* +Parse the most recent match +*/ +exports.parse = function() { + var self = this; + // Move past the pragma invocation + this.parser.pos = this.matchRegExp.lastIndex; + // Parse whitespace delimited tokens terminated by a line break + var reMatch = /[^\S\n]*(\S+)|(\r?\n)/mg, + tokens = []; + reMatch.lastIndex = this.parser.pos; + var match = reMatch.exec(this.parser.source); + while(match && match.index === this.parser.pos) { + this.parser.pos = reMatch.lastIndex; + // Exit if we've got the line break + if(match[2]) { + break; + } + // Process the token + if(match[1]) { + tokens.push(match[1]); + } + // Match the next token + match = reMatch.exec(this.parser.source); + } + // Process the tokens + $tw.utils.each(tokens,function(token) { + switch(token) { + case "trim": + self.parser.configTrimWhiteSpace = true; + break; + case "notrim": + self.parser.configTrimWhiteSpace = false; + break; + } + }); + // No parse tree nodes to return + return []; +}; + +})(); diff --git a/core/modules/parsers/wikiparser/wikiparser.js b/core/modules/parsers/wikiparser/wikiparser.js index 2a55399dd..673176038 100644 --- a/core/modules/parsers/wikiparser/wikiparser.js +++ b/core/modules/parsers/wikiparser/wikiparser.js @@ -50,6 +50,8 @@ var WikiParser = function(type,text,options) { this.type = type || "text/vnd.tiddlywiki"; this.source = text || ""; this.sourceLength = this.source.length; + // Flag for ignoring whitespace + this.configTrimWhiteSpace = false; // Set current parse position this.pos = 0; // Instantiate the pragma parse rules @@ -285,7 +287,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) { while(this.pos < this.sourceLength && nextMatch) { // Process the text preceding the run rule if(nextMatch.matchIndex > this.pos) { - tree.push({type: "text", text: this.source.substring(this.pos,nextMatch.matchIndex)}); + this.pushTextWidget(tree,this.source.substring(this.pos,nextMatch.matchIndex)); this.pos = nextMatch.matchIndex; } // Process the run rule @@ -295,7 +297,7 @@ WikiParser.prototype.parseInlineRunUnterminated = function(options) { } // Process the remaining text if(this.pos < this.sourceLength) { - tree.push({type: "text", text: this.source.substr(this.pos)}); + this.pushTextWidget(tree,this.source.substr(this.pos)); } this.pos = this.sourceLength; return tree; @@ -315,7 +317,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option if(terminatorMatch) { if(!inlineRuleMatch || inlineRuleMatch.matchIndex >= terminatorMatch.index) { if(terminatorMatch.index > this.pos) { - tree.push({type: "text", text: this.source.substring(this.pos,terminatorMatch.index)}); + this.pushTextWidget(tree,this.source.substring(this.pos,terminatorMatch.index)); } this.pos = terminatorMatch.index; if(options.eatTerminator) { @@ -328,7 +330,7 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option if(inlineRuleMatch) { // Preceding text if(inlineRuleMatch.matchIndex > this.pos) { - tree.push({type: "text", text: this.source.substring(this.pos,inlineRuleMatch.matchIndex)}); + this.pushTextWidget(tree,this.source.substring(this.pos,inlineRuleMatch.matchIndex)); this.pos = inlineRuleMatch.matchIndex; } // Process the inline rule @@ -342,12 +344,24 @@ WikiParser.prototype.parseInlineRunTerminated = function(terminatorRegExp,option } // Process the remaining text if(this.pos < this.sourceLength) { - tree.push({type: "text", text: this.source.substr(this.pos)}); + this.pushTextWidget(tree,this.source.substr(this.pos)); } this.pos = this.sourceLength; return tree; }; +/* +Push a text widget onto an array, respecting the configTrimWhiteSpace setting +*/ +WikiParser.prototype.pushTextWidget = function(array,text) { + if(this.configTrimWhiteSpace) { + text = $tw.utils.trim(text); + } + if(text) { + array.push({type: "text", text: text}); + } +}; + /* Parse zero or more class specifiers `.classname` */ diff --git a/editions/tw5.com/tiddlers/concepts/Pragma.tid b/editions/tw5.com/tiddlers/concepts/Pragma.tid index ee1c49e14..f1377b708 100644 --- a/editions/tw5.com/tiddlers/concepts/Pragma.tid +++ b/editions/tw5.com/tiddlers/concepts/Pragma.tid @@ -1,5 +1,5 @@ created: 20150219175930000 -modified: 20150221215112000 +modified: 20170712154519026 tags: Concepts title: Pragma type: text/vnd.tiddlywiki @@ -14,3 +14,5 @@ The following pragmas are available: : for defining a [[macro|Macros]] ;`\rules` : for adjusting the set of rules used to parse the text +;`\whitespace trim` or `\whitespace notrim` +: Control whether whitespace is trimmed from the start and end of text runs (the default is ''notrim''). This setting can be useful when the whitespace generated by linebreaks disturbs formatting