用于HTML文本的简单规则驱动智能格式

分享于 

16分钟阅读

Web开发

  繁體

1 个动机

在一本有趣的工业设计书中,我发现了一个看起来不太明显的建议: 在网页上制作 textarea 元素,因为大多数用户不是软件工程师;他们只是在 textarea 中粘贴文本,大多数人都会在那里键入文本。 当时,我并不期望我会花很多时间在 textarea 中输入文本,但是现在我真的很常用了。 我输入并测试了一些JavaScript代码,就好像 Visual Studio 不够:- )。 我使用了我的JavaScript计算器,因为它帮助我编写小脚本并更快地尝试它们。 我确实让它变得足够方便,至少对于我自己来说。

然而,我的finally 失去了我的耐心,快速发现了我的刺激原因。 这就是所谓的"智能缩进",比如 Visual Studio 和其他一些 IDE ( 因此,本文顶部的图片)。 一个小东西,可能会说,但这真的会使。 注意缺少制表符,因为选项卡在页面上导航,并且这个功能将是完全错误的事情。 对于"智能缩进",这种问题变得无关紧要。 首先,有些重要的特性,首先是整理输入的文本,首先是修复空白。

我的耐心用尽后,我决定填补这个空白。 我没有找到能满足我的代码,甚至是远程的,只有一些想法。 但是,来考虑一下,textarea 在任何地方都是使用的,但是它提供的文本输入能够容易。 让我们看看它有多简单。

但首先

免责声明:

本文提供的脚本非常简单,不会假设任何编程语言的任何综合文本或者语言处理器角色。 它不是上下文敏感的,完全不知道语言语法或者语义,不提供任何类似语法着色的东西。 它适用于纯文本 textarea。 它的主要目标是简单。基本方便。便于定制和缺少任何 3方的方法。

我用本文中描述的代码在 另一种方法和命名参数为JavaScript函数,第二部分: 进行结构化

2 规则集

可以在本文提供的代码中找到整个解决方案。 只有两个文件"index.html"和" smartformatting.js",所有的通用代码都放在JavaScript文件中,只有一个函数。setSmartFormatting 和"index.html"。

因为所有的文本处理都是在这个函数中设置的,所以没有用于 switch 文本处理的函数。 相反,可以使用相同的textarea 参数再次调用这里函数,并使用不同的选项。 如果选项集定义了所有 textarea 事件处理程序,则将移除这些事件处理程序。

所有实现的格式化行为都由对象 defaultOptions 描述的规则集控制。 用户可以重写这里默认规则集的某些或者全部规则。 对此类定制过程的理解的关键在我的前一篇文章中解释 JavaScript函数的命名参数 但是,基本用法可以在"index.html"所示的用法示例中理解。

通过定制规则,用户可以对不同的需求采用规则,首先是不同的语言或者编码样式。 我的默认选项集面向JavaScript编程。

规则集的轮廓可以如下所示:

var defaultOptions = {
 features: {
 // the members define which sets of rules to apply// also define tab characters },
 formattingRules: {
 indent: [
 // smart indent rules ],
 autoBracket: [
 // automatically adding closing brackets ],
 tidy: [
 // replacement of some characters/words with other words// to improve readability of text ],
 tidyVerbatim: [
 // define exclusions for tidy rule,// to treat content inside string literals verbatim  ],
 autoComplete: [
 // define text patterns which can optionally be auto-completed// after some part of them is entered ]
 }
}

查看" smartformatting.js"中所有细节的完整规则集。 below,我将解释每个规则的用法。

3 Bra和 Ket

首先,我想澄清在规则大部分中使用的对象命名。 它不仅方便地命名了括号,而且它也是量子力学中使用的符号的标志,在 1939年由 引入了。 保罗。狄拉克https://en.wikipedia.org/wiki/Bra%E2%80%93ket_notation

4 缩进

缩进规则是最重要的规则,我在整个活动中开始的。 这是同一"智能缩进"特性的两条规则。 默认规则显示一对括号的两条相同规则: [] 和 {}:

{
 bra: "[", ket: "]",
 endOfLineKet: true, matchLeftWord: false, matchRightWord: false}

这些规则定义了在插入文本插入点时按下Enter键时创建的智能缩进。 规则的布尔元素当然需要一些解释。

第一,endOfLineKet 意味着第二对括号( bra']'在本示例中) 可以丢失,但在插入点位于线的末尾时,将应用智能缩进。 换句话说,行以'['结束,插入点放置在结束行。 我希望对此选项的需求很明显: 如果需要在支架后面添加一条新的缩进线,就需要它,例如

var myArray = [
 |
 2,
 3];

在所有输入文本示例中,我将用符号'|'表示插入点。 在这里示例中,它显示了智能格式的结果,即按下键输入后。 当你第一次添加 2和 3到 array 时很有用,并且决定以后添加 1.

另外两个规则元素 matchLeftWordmatchRightWord 与概念"匹配整个世界"相关。 当这种选项设置为 true 时,意味着胸罩或者键单词只能使用它的他文字的空格分隔。 换句话说,举个例子

//If matchLeftWord and matchRightWord are true,
//smart indent won't be done with this
myObject = someArray[|]
//or this line:
myObject = someArray [|];
//but will be applied to 
myObject = someArray [|]?

在默认规则集中,我不使用这两个选项,即在 braket 之间按Enter键时总是使用智能缩进。

现在,这种格式如何生成智能缩进,而且,重要的是,在程序文本中通常使用嵌套缩进? 这是根据当前或者下一行的缩进来完成的,它由最左边的空白空间和/或者选项卡字符确定。 按一条没有缩进的直线和 ket 之间的回车时,会创建两条新行,并在最后一行中缩进第一行和第一条。 在这条线上输入,再次在胸罩和键之间输入,新的缩进被添加到现有的缩进中。 添加的缩进由选项集的属性 features 定义,请参见 功能

智能缩进的实现相当简单。 函数 countTabs(string) 检测到现有的缩进。 所有规则都是基于将现有 textarea 文本分析到对象中的插入点位置和文本元素来实现的: 字符,字和行这是函数 parseCursorContext:

var parseCursorContext = function (editor) {
 var pos = getCursor(editor);
 var allText = editor.value;
 var leftChar = allText[pos - 1];
 var rightChar = allText[pos];
 var leftChar = allText[pos - 1];
 var rightChar = allText[pos];
 if (!leftChar) return;
 var left = allText.substring(0, pos);
 var right = allText.substring(pos);
 var rightmost = right.indexOf(newLine);
 if (rightmost> = 0)
 right = right.substr(0, rightmost);
 var leftmost = left.lastIndexOf(newLine);
 if (leftmost> = 0)
 left = left.substr(leftmost + newLine.length, pos);
 var leftWord = findWords(left, false);
 var rightWord = findWords(right, true);
 return {
 cursor: pos,
 left: { char: leftChar, word: leftWord, line: left },
 right: { char: rightChar, word: rightWord, line: right } };
} //parseCursorContext

在事件处理程序 keyDownHandler 中应用了大多数规则,包括智能格式,但是整个规则集使用事件 keydownkeypresskeyupclickpaste。 请参见" smartformatting.js"以完成完整实现。

5 自动括号

自动括号规则在输入 bra 单词后立即添加一个正确的单词。 它有一个额外的规则元素,endOfLineOnly。 例如,如果你已经有了"[]",并尝试插入索引表达式 inside,我发现它非常烦人。 在默认规则集中,只有在行末尾有一个类型时,两个格式规则才适用。

6 整理

默认情况下,"整理"特性只修改空白字符集,使代码看起来更好更可以读。 整齐规则用规则对象的两个数组表示: 使用以下命令创建一个字符串,其中包含修改字符串的规则,在使用 array before 定义的目标字符串的前,后和后两边都有一个空白元素。 规则 tidyVerbatim 集是 tidy 规则的规则"阻止"应用集。 因为我的默认规则集是为JavaScript代码设计的,所以它只适用于 tidy 规则 inside 表达式的引号。 但这不是一个很简单的事情。

我通过本地 JavaScript 使用正则表达式正则表达式 但是,正则表达式在很多情况下都很好写,但它们不可读,因而不适合规则驱动( 读取: 高度可以自定义方法。因此,在初始化( 对 setSmartFormatting的调用一次) 时,我为规则的每个 before 元素生成 正规表达式,但在规则中保留正则表达式语法,该元素应替换规则时使用的元素。 例如 " $1" 表示空格应该在单词之前和之后添加,而 " $1" 或者 "$1" 只在单词之前和之后添加空白空间,而不是空格。 注意,实际上在最后应用了一个未定义的规则: 所有空白字符都是"规范化化",以消除任何重复。 这是在 before 元素的array 中快速生成 RegExp 对象的实现:

var tidyRegex = (function createRegexTidyRules(rules) {
 var regex = [];
 for (var rule in rules) {
 var newRule = { before: constants.empty, after: rules[rule].after };
 var last = rules[rule].before.length;
 for (var wordIndex = 0; wordIndex <last; ++wordIndex) {
 var word = constants.empty;
 for (var charIndex in rules[rule].before[wordIndex])
 word += ""//"//escape each character + rules[rule].before[wordIndex][charIndex];
 if (newRule.before!= constants.empty)
 newRule.before += "|";
 newRule.before += word;
 } //loop word newRule.before = "(" + newRule.before + ")";
 newRule.before = new RegExp(newRule.before, "g");
 regex.push(newRule);
 } //loop rulereturn regex;
})(options.formattingRules.tidy); //createRegexTidyRules

这些规则也适用于按回车键。

同样,正规表达式 是从 tidyVerbatim 规则飞出的。 这些规则仅仅定义了括号标记了不应应用整齐规则的上下文:

{ bra: "'", ket: "'" },
{ bra: """, ket: """ }

7 自动完成

自动完整规则定义了可以根据部分输入的文本完成的Pattern。 让我们只考虑一个示例:

{ pattern: "do* {|} while ()", breakPoint: "*", insertPoint: "|" }

这只是规则元素 pattern 所定义的所需完整的文本。 在它的字符串值中,使用了两个"特殊"字符: '*'用于标记输入 Pattern的左部分后特征可以用的位置;然后添加写部件;并将它的添加到'|'字符定义在添加自动完成文本后插入点的位置。 但是如果其中一个或者两个字符需要成为 Pattern的一部分,该怎么办? 为此,通过两个其他规则元素 breakPointinsertPoint 使它们成为可选的。

自动完成也可以在按回车键的情况下执行。 若要在这里选项处于活动状态时显示用户,函数 setSmartFormatting 具有函数参数 autoCompleteMatchNotification。 然后,用户有三个选项: 1 ) 忽略并继续键入;如果仍然匹配,则自动完成仍可以使用;) 按Enter键完成自动完成;3 ) 按esc键。 唯一需要转移的实际需求是允许用户按 Enter,而不需要自动完成,使用默认的输入函数。

8 个特性

规则集的这个元素仅仅定义应应用哪些规则集。 对于智能缩进规则,还定义了缩进字符。 特别是,它们只适用于新输入的文本。 也就是说,已经键入的文本从不修改。 但是,如果在现有文本中包含制表符,则它看起来可以改变。 因为 tabSize 也是为制表符设置的;这是通过 textarea 样式完成的。 我希望这个对象的结构是自我解释的:

features: {
 useSmartIndent: true, useTabs: true, tabSize: 4,
 useAutoBracket: true, useTidy: true, useCodeCompletion: true}

9 个结论

它只是工作。我的刺激消失了,因为我改善了规则和它们的实现步骤。 我希望这种行为不会惹恼我的读者,甚至看起来很方便。 我将对( 不一定是构造的) 和任何建议都非常感谢。


for  文本  TEX  form  Drive  格式  
相关文章