diff --git a/demo/kitchen-sink/docs/latte.latte b/demo/kitchen-sink/docs/latte.latte
new file mode 100644
index 00000000000..e2731bfcd4a
--- /dev/null
+++ b/demo/kitchen-sink/docs/latte.latte
@@ -0,0 +1,36 @@
+
+
+
+ {$title}
+ {*
+ comment
+ *}
+
+
+ My Webpage
+
+
+
+ {$variable}
+ {=$variable}
+ {XXXX::func($variable /* comment */)|filter}
+ {$variable?->obj|filter:10, abc, 'x$var', "x$var"|filter2}
+
+ {if} ... {/if true}
+
+
+
+
+
+
diff --git a/lib/ace/ext/modelist.js b/lib/ace/ext/modelist.js
index bd4226c59c5..e863dc170bc 100644
--- a/lib/ace/ext/modelist.js
+++ b/lib/ace/ext/modelist.js
@@ -119,6 +119,7 @@ var supportedModes = {
Julia: ["jl"],
Kotlin: ["kt|kts"],
LaTeX: ["tex|latex|ltx|bib"],
+ Latte: ["latte"],
LESS: ["less"],
Liquid: ["liquid"],
Lisp: ["lisp"],
@@ -195,7 +196,7 @@ var supportedModes = {
Textile: ["textile"],
Toml: ["toml"],
TSX: ["tsx"],
- Twig: ["latte|twig|swig"],
+ Twig: ["twig|swig"],
Typescript: ["ts|typescript|str"],
Vala: ["vala"],
VBScript: ["vbs|vb"],
diff --git a/lib/ace/keyboard/vim.js b/lib/ace/keyboard/vim.js
index 8e87d78c5ce..a56a4525afa 100644
--- a/lib/ace/keyboard/vim.js
+++ b/lib/ace/keyboard/vim.js
@@ -2921,7 +2921,8 @@ dom.importCssString(".normal-mode .ace_cursor{\
}
var prevLineEnd = new Pos(anchor.line - 1, Number.MAX_VALUE);
var wasLastLine = cm.firstLine() == cm.lastLine();
- if (head.line > cm.lastLine() && args.linewise && !wasLastLine) {
+ var isFirstLine = cm.firstLine() == anchor.line;
+ if (head.line > cm.lastLine() && args.linewise && !wasLastLine && !isFirstLine) {
cm.replaceRange('', prevLineEnd, head);
} else {
cm.replaceRange('', anchor, head);
diff --git a/lib/ace/keyboard/vim_test.js b/lib/ace/keyboard/vim_test.js
index 86f2b657ff0..625f6fbade4 100644
--- a/lib/ace/keyboard/vim_test.js
+++ b/lib/ace/keyboard/vim_test.js
@@ -1091,6 +1091,12 @@ testVim('dd_only_line', function(cm, vim, helpers) {
var register = helpers.getRegisterController().getRegister();
eq(expectedRegister, register.toString());
}, { value: "thisistheonlyline" });
+testVim('cG', function(cm, vim, helpers) {
+ cm.setCursor(0, 0);
+ helpers.doKeys('c', 'G', 'inserted');
+ eq('inserted\n', cm.getValue());
+ helpers.assertCursorAt(0, 8);
+}, { value: 'line1\nline2'});
// Yank commands should behave the exact same as d commands, expect that nothing
// gets deleted.
testVim('yw_repeat', function(cm, vim, helpers) {
diff --git a/lib/ace/mode/_test/tokens_latte.json b/lib/ace/mode/_test/tokens_latte.json
new file mode 100644
index 00000000000..df1a5312e8f
--- /dev/null
+++ b/lib/ace/mode/_test/tokens_latte.json
@@ -0,0 +1,309 @@
+[[
+ "start",
+ ["xml-pe.doctype.xml",""]
+],[
+ "start",
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.tag-name.xml","html"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.tag-name.xml","head"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.tag-name.xml","title"],
+ ["meta.tag.punctuation.tag-close.xml",">"],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["variable","$title"],
+ ["meta.tag.punctuation.tag-close.latte","}"],
+ ["meta.tag.punctuation.end-tag-open.xml",""],
+ ["meta.tag.tag-name.xml","title"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "comment.start.latte",
+ ["text.xml"," "],
+ ["comment.start.latte","{*"],
+ ["comment"," "]
+],[
+ "comment.start.latte",
+ ["comment"," \tcomment"]
+],[
+ "start",
+ ["comment.end.latte"," *}"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.end-tag-open.xml",""],
+ ["meta.tag.tag-name.xml","head"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.tag-name.xml","body"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start",
+ ["text.xml"," \t"],
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.tag-name.xml","h1"],
+ ["text.tag-whitespace.xml"," "],
+ ["meta.attribute.latte","n:inner-if"],
+ ["keyword.operator.attribute-equals.xml","="],
+ ["constant.numeric","0"],
+ ["meta.tag.punctuation.tag-close.xml",">"],
+ ["entity.other.attribute-name.xml","My"],
+ ["text.tag-whitespace.xml"," "],
+ ["entity.other.attribute-name.xml","Webpage"],
+ ["text",""],
+ ["entity.other.attribute-name.xml","h1"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start"
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.tag-name.xml","ul"],
+ ["text.tag-whitespace.xml"," "],
+ ["meta.attribute.latte","n:if"],
+ ["keyword.operator.attribute-equals.xml","="],
+ ["string.attribute-value.xml","\""],
+ ["string.unquoted","count"],
+ ["paren.lparen","("],
+ ["variable","$navigation"],
+ ["paren.rparen",")"],
+ ["keyword.operator"," > "],
+ ["constant.numeric","0"],
+ ["string.attribute-value.xml","\""],
+ ["text.tag-whitespace.xml"," "],
+ ["entity.other.attribute-name.xml","id"],
+ ["keyword.operator.attribute-equals.xml","="],
+ ["string.attribute-value.xml","\"navigation\""],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["meta.tag.latte","foreach"],
+ ["keyword.operator"," "],
+ ["paren.lparen","["],
+ ["string.unquoted","a"],
+ ["keyword.operator",", "],
+ ["string.unquoted","b"],
+ ["keyword.operator",", "],
+ ["string.start","'"],
+ ["string","x"],
+ ["string.end","'"],
+ ["keyword.operator",", "],
+ ["constant.numeric","10"],
+ ["paren.rparen","]"],
+ ["keyword.operator"," "],
+ ["keyword.control","as"],
+ ["keyword.operator"," "],
+ ["variable","$item"],
+ ["meta.tag.punctuation.tag-close.latte","}"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.tag-name.xml","li"],
+ ["meta.tag.punctuation.tag-close.xml",">"],
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.anchor.tag-name.xml","a"],
+ ["text.tag-whitespace.xml"," "],
+ ["entity.other.attribute-name.xml","href"],
+ ["keyword.operator.attribute-equals.xml","="],
+ ["string.attribute-value.xml","\""],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["variable","$item"],
+ ["meta.tag.punctuation.tag-close.latte","}"],
+ ["string.attribute-value.xml","\""],
+ ["meta.tag.punctuation.tag-close.xml",">"],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["meta.tag.latte","test"],
+ ["paren.lparen","("],
+ ["variable","$item"],
+ ["keyword.operator","->"],
+ ["string.unquoted","caption"],
+ ["paren.rparen",")"],
+ ["meta.tag.punctuation.tag-close.latte","}"],
+ ["meta.tag.punctuation.end-tag-open.xml",""],
+ ["meta.tag.anchor.tag-name.xml","a"],
+ ["meta.tag.punctuation.tag-close.xml",">"],
+ ["meta.tag.punctuation.end-tag-open.xml",""],
+ ["meta.tag.tag-name.xml","li"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.latte","{/"],
+ ["meta.tag.latte","foreach"],
+ ["meta.tag.punctuation.tag-close.latte","}"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.end-tag-open.xml",""],
+ ["meta.tag.tag-name.xml","ul"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start"
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["variable","$variable"],
+ ["meta.tag.punctuation.tag-close.latte","}"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["meta.tag.latte","="],
+ ["variable","$variable"],
+ ["meta.tag.punctuation.tag-close.latte","}"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["variable","$variable"],
+ ["keyword.operator","|"],
+ ["string.unquoted","filter"],
+ ["meta.tag.punctuation.tag-close.latte","}"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["variable","$variable"],
+ ["keyword.operator","|"],
+ ["string.unquoted","filter"],
+ ["keyword.operator",":"],
+ ["constant.numeric","10"],
+ ["keyword.operator",","],
+ ["constant.numeric","20"],
+ ["keyword.operator","|"],
+ ["string.unquoted","filter2"],
+ ["meta.tag.punctuation.tag-close.latte","}"]
+],[
+ "start"
+],[
+ "js-start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.script.tag-name.xml","script"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "js-start",
+ ["text","\t "],
+ ["storage.type","var"],
+ ["text"," "],
+ ["identifier","a"],
+ ["text"," "],
+ ["keyword.operator","="],
+ ["text"," "],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["variable","$a"],
+ ["meta.tag.punctuation.tag-close.latte","}"],
+ ["punctuation.operator",","],
+ ["text"," "],
+ ["identifier","b"],
+ ["text"," "],
+ ["keyword.operator","="],
+ ["text"," "],
+ ["paren.lparen","{"],
+ ["string","'a'"],
+ ["punctuation.operator",":"],
+ ["text"," "],
+ ["constant.numeric","1"],
+ ["paren.rparen","}"],
+ ["punctuation.operator",","],
+ ["text"," "],
+ ["identifier","c"],
+ ["text"," "],
+ ["keyword.operator","="],
+ ["text"," "],
+ ["paren.lparen","{"],
+ ["string","'a'"],
+ ["punctuation.operator",":"],
+ ["text"," "],
+ ["constant.numeric","1"],
+ ["paren.rparen","}"],
+ ["punctuation.operator",";"]
+],[
+ "js-start",
+ ["text","\t "],
+ ["keyword","if"],
+ ["text"," "],
+ ["paren.lparen","("],
+ ["constant.language.boolean","true"],
+ ["paren.rparen",")"],
+ ["text"," "],
+ ["paren.lparen","{"]
+],[
+ "js-start",
+ ["text","\t \t"],
+ ["support.function","alert"],
+ ["paren.lparen","("],
+ ["paren.rparen",")"],
+ ["punctuation.operator",";"]
+],[
+ "js-no_regex",
+ ["text","\t "],
+ ["paren.rparen","}"]
+],[
+ "start",
+ ["text"," "],
+ ["meta.tag.punctuation.end-tag-open.xml",""],
+ ["meta.tag.script.tag-name.xml","script"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start"
+],[
+ "css-start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.tag-open.xml","<"],
+ ["meta.tag.style.tag-name.xml","style"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "css-start",
+ ["text"," \t"],
+ ["constant","body"],
+ ["text"," "],
+ ["paren.lparen","{"],
+ ["text"," "],
+ ["support.type","color"],
+ ["punctuation.operator",":"],
+ ["text"," "],
+ ["meta.tag.punctuation.tag-open.latte","{"],
+ ["variable","$color"],
+ ["meta.tag.punctuation.tag-close.latte","}"],
+ ["text"," "],
+ ["paren.rparen","}"]
+],[
+ "start",
+ ["text"," "],
+ ["meta.tag.punctuation.end-tag-open.xml",""],
+ ["meta.tag.style.tag-name.xml","style"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start",
+ ["text.xml"," "],
+ ["meta.tag.punctuation.end-tag-open.xml",""],
+ ["meta.tag.tag-name.xml","body"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start",
+ ["meta.tag.punctuation.end-tag-open.xml",""],
+ ["meta.tag.tag-name.xml","html"],
+ ["meta.tag.punctuation.tag-close.xml",">"]
+],[
+ "start"
+]]
\ No newline at end of file
diff --git a/lib/ace/mode/css/csslint.js b/lib/ace/mode/css/csslint.js
index 2dc5e44d16e..9be23ed05ea 100644
--- a/lib/ace/mode/css/csslint.js
+++ b/lib/ace/mode/css/csslint.js
@@ -7300,34 +7300,6 @@ CSSLint.addRule({
});
-/*
- * Rule: box-sizing doesn't work in IE6 and IE7.
- */
-
-CSSLint.addRule({
-
- //rule information
- id: "box-sizing",
- name: "Disallow use of box-sizing",
- desc: "The box-sizing properties isn't supported in IE6 and IE7.",
- browsers: "IE6, IE7",
- tags: ["Compatibility"],
-
- //initialization
- init: function(parser, reporter){
- var rule = this;
-
- parser.addListener("property", function(event){
- var name = event.property.text.toLowerCase();
-
- if (name === "box-sizing"){
- reporter.report("The box-sizing property isn't supported in IE6 and IE7.", event.line, event.col, rule);
- }
- });
- }
-
-});
-
/*
* Rule: Use the bulletproof @font-face syntax to avoid 404's in old IE
* (http://www.fontspring.com/blog/the-new-bulletproof-font-face-syntax)
@@ -7843,82 +7815,6 @@ CSSLint.addRule({
});
-CSSLint.addRule({
-
- //rule information
- id: "fallback-colors",
- name: "Require fallback colors",
- desc: "For older browsers that don't support RGBA, HSL, or HSLA, provide a fallback color.",
- browsers: "IE6,IE7,IE8",
-
- //initialization
- init: function(parser, reporter){
- var rule = this,
- lastProperty,
- propertiesToCheck = {
- color: 1,
- background: 1,
- "border-color": 1,
- "border-top-color": 1,
- "border-right-color": 1,
- "border-bottom-color": 1,
- "border-left-color": 1,
- border: 1,
- "border-top": 1,
- "border-right": 1,
- "border-bottom": 1,
- "border-left": 1,
- "background-color": 1
- },
- properties;
-
- function startRule(){
- properties = {};
- lastProperty = null;
- }
-
- parser.addListener("startrule", startRule);
- parser.addListener("startfontface", startRule);
- parser.addListener("startpage", startRule);
- parser.addListener("startpagemargin", startRule);
- parser.addListener("startkeyframerule", startRule);
-
- parser.addListener("property", function(event){
- var property = event.property,
- name = property.text.toLowerCase(),
- parts = event.value.parts,
- i = 0,
- colorType = "",
- len = parts.length;
-
- if(propertiesToCheck[name]){
- while(i < len){
- if (parts[i].type === "color"){
- if ("alpha" in parts[i] || "hue" in parts[i]){
-
- if (/([^\)]+)\(/.test(parts[i])){
- colorType = RegExp.$1.toUpperCase();
- }
-
- if (!lastProperty || (lastProperty.property.text.toLowerCase() !== name || lastProperty.colorType !== "compat")){
- reporter.report("Fallback " + name + " (hex or RGB) should precede " + colorType + " " + name + ".", event.line, event.col, rule);
- }
- } else {
- event.colorType = "compat";
- }
- }
-
- i++;
- }
- }
-
- lastProperty = event;
- });
-
- }
-
-});
-
/*
* Rule: You shouldn't use more than 10 floats. If you do, there's probably
* room for some abstraction.
diff --git a/lib/ace/mode/latte.js b/lib/ace/mode/latte.js
new file mode 100644
index 00000000000..5a2bb566efa
--- /dev/null
+++ b/lib/ace/mode/latte.js
@@ -0,0 +1,73 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2013, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Ajax.org B.V. nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var oop = require("../lib/oop");
+var HtmlMode = require("./html").Mode;
+var LatteHighlightRules = require("./latte_highlight_rules").LatteHighlightRules;
+var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent;
+
+var Mode = function() {
+ HtmlMode.call(this);
+ this.HighlightRules = LatteHighlightRules;
+ this.$outdent = new MatchingBraceOutdent();
+};
+oop.inherits(Mode, HtmlMode);
+
+(function() {
+ this.blockComment = {start: "{*", end: "*}"};
+
+ this.getNextLineIndent = function(state, line, tab) {
+ var indent = this.$getIndent(line);
+
+ if (state == "start") {
+ var match = line.match(/^.*\{(?:if|else|elseif|ifset|elseifset|ifchanged|switch|case|foreach|iterateWhile|for|while|first|last|sep|try|capture|spaceless|snippet|block|define|embed|snippetArea)\b[^{]*$/);
+ if (match) {
+ indent += tab;
+ }
+ }
+
+ return indent;
+ };
+
+ this.checkOutdent = function(state, line, input) {
+ return /^\s+\{\/$/.test(line + input);
+ };
+
+ this.autoOutdent = function(state, doc, row) {
+ };
+
+ this.$id = "ace/mode/latte";
+}).call(Mode.prototype);
+
+exports.Mode = Mode;
+});
\ No newline at end of file
diff --git a/lib/ace/mode/latte_highlight_rules.js b/lib/ace/mode/latte_highlight_rules.js
new file mode 100644
index 00000000000..62749a9b53f
--- /dev/null
+++ b/lib/ace/mode/latte_highlight_rules.js
@@ -0,0 +1,192 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Distributed under the BSD license:
+ *
+ * Copyright (c) 2013, Ajax.org B.V.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Ajax.org B.V. nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+define(function(require, exports, module) {
+"use strict";
+
+var oop = require("../lib/oop");
+var HtmlHighlightRules = require("./html_highlight_rules").HtmlHighlightRules;
+var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules;
+
+var LatteHighlightRules = function() {
+ // inherit from html
+ HtmlHighlightRules.call(this);
+
+ // add latte start tags to the HTML
+ for (var rule in this.$rules) {
+ this.$rules[rule].unshift(
+ {
+ token : "comment.start.latte",
+ regex : "\\{\\*",
+ push : [{
+ token : "comment.end.latte",
+ regex : ".*\\*\\}",
+ next : "pop"
+ }, {
+ defaultToken : "comment"
+ }]
+ }, {
+ token : "meta.tag.punctuation.tag-open.latte",
+ regex : "\\{(?![\\s'\"{}]|$)/?",
+ push : [{
+ token : "meta.tag.latte",
+ regex : "(?:_|=|[a-z]\\w*(?:[.:-]\\w+)*)?",
+ next: [{
+ token : "meta.tag.punctuation.tag-close.latte",
+ regex : "\\}",
+ next : "pop"
+ }, {
+ include: "latte-content"
+ }]
+ }]
+ });
+ }
+
+ // add n:attribute to HTML tag
+ this.$rules['tag_stuff'].unshift({
+ token : "meta.attribute.latte",
+ regex : "n:[\\w-]+",
+ next : [{
+ include: "tag_whitespace"
+ }, {
+ token : "keyword.operator.attribute-equals.xml",
+ regex : "=",
+ next : [{
+ token : "string.attribute-value.xml",
+ regex : "'",
+ next : [
+ {token : "string.attribute-value.xml", regex: "'", next: "tag_stuff"},
+ {include : "latte-content"}
+ ]
+ }, {
+ token : "string.attribute-value.xml",
+ regex : '"',
+ next : [
+ {token : "string.attribute-value.xml", regex: '"', next: "tag_stuff"},
+ {include : "latte-content"}
+ ]
+ }, {
+ token : "text.tag-whitespace.xml",
+ regex : "\\s",
+ next: "tag_stuff"
+ }, {
+ token : "meta.tag.punctuation.tag-close.xml",
+ regex : "/?>",
+ next: "tag_stuff"
+ }, {
+ include : "latte-content"
+ }]
+ }, {
+ token : "empty",
+ regex : "",
+ next : "tag_stuff"
+ }]
+ });
+
+
+ // PHP content
+ this.$rules["latte-content"] = [
+ {
+ token : "comment.start.latte", // multi line comment
+ regex : "\\/\\*",
+ push : [
+ {
+ token : "comment.end.latte",
+ regex : "\\*\\/",
+ next : "pop"
+ }, {
+ defaultToken : "comment"
+ }
+ ]
+ }, {
+ token : "string.start", // " string start
+ regex : '"',
+ push : [
+ {
+ token : "constant.language.escape",
+ regex : '\\\\(?:[nrtvef\\\\"$]|[0-7]{1,3}|x[0-9A-Fa-f]{1,2})'
+ }, {
+ token : "variable",
+ regex : /\$[\w]+(?:\[[\w\]+]|[=\-]>\w+)?/
+ }, {
+ token : "variable",
+ regex : /\$\{[^"\}]+\}?/ // this is wrong but ok for now
+ },
+ {token : "string.end", regex : '"', next : "pop"},
+ {defaultToken : "string"}
+ ]
+ }, {
+ token : "string.start", // ' string start
+ regex : "'",
+ push : [
+ {token : "constant.language.escape", regex : /\\['\\]/},
+ {token : "string.end", regex : "'", next : "pop"},
+ {defaultToken : "string"}
+ ]
+ }, {
+ token : "keyword.control",
+ regex : "\\b(?:INF|NAN|and|or|xor|AND|OR|XOR|clone|new|instanceof|return|continue|break|as)\\b"
+ }, {
+ token : "constant.language",
+ regex : "\\b(?:true|false|null|TRUE|FALSE|NULL)\\b"
+ }, {
+ token : "variable",
+ regex : /\$\w+/
+ }, {
+ token : "constant.numeric",
+ regex : "[+-]?[0-9]+(?:\\.[0-9]+)?(?:e[0-9]+)?"
+ }, {
+ token : ["support.class", "keyword.operator"],
+ regex : "\\b(\\w+)(::)"
+ }, {
+ token : "constant.language", // constants
+ regex : "\\b(?:[A-Z0-9_]+)\\b"
+ }, {
+ token : "string.unquoted",
+ regex : "\\w+(?:-+\\w+)*"
+ }, {
+ token : "paren.lparen",
+ regex : "[[({]"
+ }, {
+ token : "paren.rparen",
+ regex : "[\\])}]"
+ }, {
+ token : "keyword.operator",
+ regex : "::|=>|->|\\?->|\\?\\?->|\\+\\+|--|<<|>>|<=>|<=|>=|===|!==|==|!=|<>|&&|\\|\\||\\?\\?|\\?>|\\*\\*|\\.\\.\\.|[^'\"]" // =>, any char except quotes
+ }
+ ];
+
+ this.normalizeRules();
+};
+
+oop.inherits(LatteHighlightRules, TextHighlightRules);
+
+exports.LatteHighlightRules = LatteHighlightRules;
+});