diff --git a/ace-modes.d.ts b/ace-modes.d.ts index 544811a4c8b..e1a88ebc78c 100644 --- a/ace-modes.d.ts +++ b/ace-modes.d.ts @@ -553,6 +553,9 @@ declare module "ace-code/src/mode/jssm_highlight_rules" { declare module "ace-code/src/mode/jsx" { export const Mode: new () => import(".").Ace.SyntaxMode; } +declare module "ace-code/src/mode/jsx_highlight_rules" { + export const JsxHighlightRules: new () => import(".").Ace.HighlightRules; +} declare module "ace-code/src/mode/julia" { export const Mode: new () => import(".").Ace.SyntaxMode; } diff --git a/demo/kitchen-sink/docs/jsx.jsx b/demo/kitchen-sink/docs/jsx.jsx index c74ead6cddb..fbbeb662689 100644 --- a/demo/kitchen-sink/docs/jsx.jsx +++ b/demo/kitchen-sink/docs/jsx.jsx @@ -1,9 +1,9 @@ -import * as React from "react"; - -export default () => { - return ( -
- Keywords here are not highlighted, for example class or instance. -
- ); +/*EXPECTED +hello world! +*/ +class Test { + static function run() : void { + // console.log("hello world!"); + log "hello world!"; + } } \ No newline at end of file diff --git a/src/ext/modelist.js b/src/ext/modelist.js index 791174fe07d..96a03f35672 100644 --- a/src/ext/modelist.js +++ b/src/ext/modelist.js @@ -126,7 +126,7 @@ var supportedModes = { Jack: ["jack"], Jade: ["jade|pug"], Java: ["java"], - JavaScript: ["js|jsm|cjs|mjs"], + JavaScript: ["js|jsm|jsx|cjs|mjs"], JEXL: ["jexl"], JSON: ["json"], JSON5: ["json5"], diff --git a/src/mode/_test/tokens_jsx.json b/src/mode/_test/tokens_jsx.json index 75f747fc08c..d1a740b0907 100644 --- a/src/mode/_test/tokens_jsx.json +++ b/src/mode/_test/tokens_jsx.json @@ -1,62 +1,51 @@ [[ + "comment", + ["comment","/*EXPECTED"] +],[ + "comment", + ["comment","hello world!"] +],[ "start", - ["keyword","import"], - ["text"," "], - ["keyword.operator","*"], - ["text"," "], - ["identifier","as"], - ["text"," "], - ["identifier","React"], + ["comment","*/"] +],[ + "start", + ["keyword","class"], ["text"," "], - ["keyword","from"], + ["language.support.class","Test"], ["text"," "], - ["string","\"react\""], - ["punctuation.operator",";"] -],[ - "start" + ["paren.lparen","{"] ],[ "start", - ["keyword","export"], + ["text"," "], + ["keyword","static"], ["text"," "], - ["keyword","default"], + ["storage.type","function"], ["text"," "], + ["entity.name.function","run"], ["paren.lparen","("], ["paren.rparen",")"], ["text"," "], - ["storage.type","=>"], + ["punctuation.operator",":"], + ["text"," "], + ["keyword","void"], ["text"," "], ["paren.lparen","{"] ],[ "start", - ["text"," "], - ["keyword","return"], - ["text"," "], - ["paren.lparen","("] -],[ - ["jsx",1], - ["text"," "], - ["meta.tag.punctuation.tag-open.xml","<"], - ["meta.tag.tag-name.xml","div"], - ["text.tag-whitespace.xml"," "], - ["entity.other.attribute-name.xml","variant"], - ["keyword.operator.attribute-equals.xml","="], - ["string.attribute-value.xml","\"p\""], - ["meta.tag.punctuation.tag-close.xml",">"] -],[ - ["jsx",1], - ["string"," Keywords here are not highlighted, for example class or instance."] + ["text"," "], + ["comment","// console.log(\"hello world!\");"] ],[ "start", - ["string"," "], - ["meta.tag.punctuation.end-tag-open.xml",""] + ["text"," "], + ["keyword","log"], + ["text"," "], + ["string","\"hello world!\""], + ["punctuation.operator",";"] ],[ "start", - ["text"," "], - ["paren.rparen",")"], - ["punctuation.operator",";"] + ["text"," "], + ["paren.rparen","}"] ],[ - "no_regex", + "start", ["paren.rparen","}"] ]] \ No newline at end of file diff --git a/src/mode/jsx.js b/src/mode/jsx.js index be92ef48b9b..e2d588beb8b 100644 --- a/src/mode/jsx.js +++ b/src/mode/jsx.js @@ -1,19 +1,52 @@ "use strict"; var oop = require("../lib/oop"); -var jsMode = require("./javascript").Mode; +var TextMode = require("./text").Mode; +var JsxHighlightRules = require("./jsx_highlight_rules").JsxHighlightRules; +var MatchingBraceOutdent = require("./matching_brace_outdent").MatchingBraceOutdent; +var CStyleFoldMode = require("./folding/cstyle").FoldMode; function Mode() { - jsMode.call(this); - this.$highlightRuleConfig = {jsx: true}; + this.HighlightRules = JsxHighlightRules; + this.$outdent = new MatchingBraceOutdent(); + this.$behaviour = this.$defaultBehaviour; + this.foldingRules = new CStyleFoldMode(); } -oop.inherits(Mode, jsMode); +oop.inherits(Mode, TextMode); (function() { - // disable jshint - this.createWorker = function() { - return null; + + this.lineCommentStart = "//"; + this.blockComment = {start: "/*", end: "*/"}; + + this.getNextLineIndent = function(state, line, tab) { + var indent = this.$getIndent(line); + + var tokenizedLine = this.getTokenizer().getLineTokens(line, state); + var tokens = tokenizedLine.tokens; + + if (tokens.length && tokens[tokens.length-1].type == "comment") { + return indent; + } + + if (state == "start") { + var match = line.match(/^.*[\{\(\[]\s*$/); + if (match) { + indent += tab; + } + } + + return indent; }; + + this.checkOutdent = function(state, line, input) { + return this.$outdent.checkOutdent(line, input); + }; + + this.autoOutdent = function(state, doc, row) { + this.$outdent.autoOutdent(doc, row); + }; + this.$id = "ace/mode/jsx"; }).call(Mode.prototype); diff --git a/src/mode/jsx_highlight_rules.js b/src/mode/jsx_highlight_rules.js new file mode 100644 index 00000000000..0fef0aa7f48 --- /dev/null +++ b/src/mode/jsx_highlight_rules.js @@ -0,0 +1,117 @@ +var oop = require("../lib/oop"); +var lang = require("../lib/lang"); +var DocCommentHighlightRules = require("./doc_comment_highlight_rules").DocCommentHighlightRules; +var TextHighlightRules = require("./text_highlight_rules").TextHighlightRules; + +var JsxHighlightRules = function() { + var keywords = lang.arrayToMap( + ("break|do|instanceof|typeof|case|else|new|var|catch|finally|return|void|continue|for|switch|default|while|function|this|" + + "if|throw|" + + "delete|in|try|" + + "class|extends|super|import|from|into|implements|interface|static|mixin|override|abstract|final|" + + "number|int|string|boolean|variant|" + + "log|assert").split("|") + ); + + var buildinConstants = lang.arrayToMap( + ("null|true|false|NaN|Infinity|__FILE__|__LINE__|undefined").split("|") + ); + + var reserved = lang.arrayToMap( + ("debugger|with|" + + "const|export|" + + "let|private|public|yield|protected|" + + "extern|native|as|operator|__fake__|__readonly__").split("|") + ); + + var identifierRe = "[a-zA-Z_][a-zA-Z0-9_]*\\b"; + + this.$rules = { + "start" : [ + { + token : "comment", + regex : "\\/\\/.*$" + }, + DocCommentHighlightRules.getStartRule("doc-start"), + { + token : "comment", // multi line comment + regex : "\\/\\*", + next : "comment" + }, { + token : "string.regexp", + regex : "[/](?:(?:\\[(?:\\\\]|[^\\]])+\\])|(?:\\\\/|[^\\]/]))*[/]\\w*\\s*(?=[).,;]|$)" + }, { + token : "string", // single line + regex : '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' + }, { + token : "string", // single line + regex : "['](?:(?:\\\\.)|(?:[^'\\\\]))*?[']" + }, { + token : "constant.numeric", // hex + regex : "0[xX][0-9a-fA-F]+\\b" + }, { + token : "constant.numeric", // float + regex : "[+-]?\\d+(?:(?:\\.\\d*)?(?:[eE][+-]?\\d+)?)?\\b" + }, { + token : "constant.language.boolean", + regex : "(?:true|false)\\b" + }, { + token : [ + "storage.type", + "text", + "entity.name.function" + ], + regex : "(function)(\\s+)(" + identifierRe + ")" + }, { + token : function(value) { + if (value == "this") + return "variable.language"; + else if (value == "function") + return "storage.type"; + else if (keywords.hasOwnProperty(value) || reserved.hasOwnProperty(value)) + return "keyword"; + else if (buildinConstants.hasOwnProperty(value)) + return "constant.language"; + else if (/^_?[A-Z][a-zA-Z0-9_]*$/.test(value)) + return "language.support.class"; + else + return "identifier"; + }, + // TODO: Unicode escape sequences + // TODO: Unicode identifiers + regex : identifierRe + }, { + token : "keyword.operator", + regex : "!|%|&|\\*|\\-\\-|\\-|\\+\\+|\\+|~|==|=|!=|<=|>=|<<=|>>=|>>>=|<>|<|>|!|&&|\\|\\||\\?\\:|\\*=|%=|\\+=|\\-=|&=|\\^=|\\b(?:in|instanceof|new|delete|typeof|void)" + }, { + token : "punctuation.operator", + regex : "\\?|\\:|\\,|\\;|\\." + }, { + token : "paren.lparen", + regex : "[[({<]" + }, { + token : "paren.rparen", + regex : "[\\])}>]" + }, { + token : "text", + regex : "\\s+" + } + ], + "comment" : [ + { + token : "comment", // closing comment + regex : "\\*\\/", + next : "start" + }, { + defaultToken : "comment" + } + ] + }; + + this.embedRules(DocCommentHighlightRules, "doc-", + [ DocCommentHighlightRules.getEndRule("start") ]); +}; + +oop.inherits(JsxHighlightRules, TextHighlightRules); + +exports.JsxHighlightRules = JsxHighlightRules;