diff --git a/components.js b/components.js index 97a59fc7e1..7a221fc78a 100644 --- a/components.js +++ b/components.js @@ -223,6 +223,11 @@ var components = { "title": "Haskell", "owner": "bholst" }, + "haxe": { + "title": "Haxe", + "require": "clike", + "owner": "Golmote" + }, "http": { "title": "HTTP", "owner": "danielgtaylor" diff --git a/components/prism-haxe.js b/components/prism-haxe.js new file mode 100644 index 0000000000..70d9add988 --- /dev/null +++ b/components/prism-haxe.js @@ -0,0 +1,43 @@ +Prism.languages.haxe = Prism.languages.extend('clike', { + // Strings can be multi-line + 'string': { + pattern: /(["'])(?:(?!\1)[^\\]|\\[\s\S])*\1/, + inside: { + 'interpolation': { + pattern: /(^|[^\\])\$(?:\w+|\{[^}]+\})/, + lookbehind: true, + inside: { + 'interpolation': { + pattern: /^\$\w*/, + alias: 'variable' + } + // See rest below + } + } + } + }, + // The final look-ahead prevents highlighting of keywords if expressions such as "haxe.macro.Expr" + 'keyword': /\bthis\b|\b(?:abstract|as|break|case|cast|catch|class|continue|default|do|dynamic|else|enum|extends|extern|from|for|function|if|implements|import|in|inline|interface|macro|new|null|override|public|private|return|static|super|switch|throw|to|try|typedef|using|var|while)(?!\.)\b/, + 'operator': /\.{3}|\+\+?|-[->]?|[=!]=?|&&?|\|\|?|<[<=]?|>[>=]?|[*\/%~^]/ +}); +Prism.languages.insertBefore('haxe', 'class-name', { + 'regex': { + pattern: /~\/(?:[^\/\\\r\n]|\\.)+\/[igmsu]*/ + } +}); +Prism.languages.insertBefore('haxe', 'keyword', { + 'preprocessor': { + pattern: /#\w+/, + alias: 'builtin' + }, + 'metadata': { + pattern: /@:?\w+/, + alias: 'symbol' + }, + 'reification': { + pattern: /\$(?:\w+|(?=\{))/, + alias: 'variable' + } +}); +Prism.languages.haxe['string'].inside['interpolation'].inside.rest = Prism.util.clone(Prism.languages.haxe); +delete Prism.languages.haxe['class-name']; \ No newline at end of file diff --git a/components/prism-haxe.min.js b/components/prism-haxe.min.js new file mode 100644 index 0000000000..42f05b0cfa --- /dev/null +++ b/components/prism-haxe.min.js @@ -0,0 +1 @@ +Prism.languages.haxe=Prism.languages.extend("clike",{string:{pattern:/(["'])(?:(?!\1)[^\\]|\\[\s\S])*\1/,inside:{interpolation:{pattern:/(^|[^\\])\$(?:\w+|\{[^}]+\})/,lookbehind:!0,inside:{interpolation:{pattern:/^\$\w*/,alias:"variable"}}}}},keyword:/\bthis\b|\b(?:abstract|as|break|case|cast|catch|class|continue|default|do|dynamic|else|enum|extends|extern|from|for|function|if|implements|import|in|inline|interface|macro|new|null|override|public|private|return|static|super|switch|throw|to|try|typedef|using|var|while)(?!\.)\b/,operator:/\.{3}|\+\+?|-[->]?|[=!]=?|&&?|\|\|?|<[<=]?|>[>=]?|[*\/%~^]/}),Prism.languages.insertBefore("haxe","class-name",{regex:{pattern:/~\/(?:[^\/\\\r\n]|\\.)+\/[igmsu]*/}}),Prism.languages.insertBefore("haxe","keyword",{preprocessor:{pattern:/#\w+/,alias:"builtin"},metadata:{pattern:/@:?\w+/,alias:"symbol"},reification:{pattern:/\$(?:\w+|(?=\{))/,alias:"variable"}}),Prism.languages.haxe.string.inside.interpolation.inside.rest=Prism.util.clone(Prism.languages.haxe),delete Prism.languages.haxe["class-name"]; \ No newline at end of file diff --git a/examples/prism-haxe.html b/examples/prism-haxe.html new file mode 100644 index 0000000000..88f8e373f2 --- /dev/null +++ b/examples/prism-haxe.html @@ -0,0 +1,53 @@ +

Haxe

+

To use this language, use the class "language-haxe".

+ +

Strings and string interpolation

+
"Foo
+bar $baz"
+'Foo
+bar'
+"${4 + 2}"
+ +

Regular expressions

+
~/haxe/i
+~/[A-Z0-9._%-]+@[A-Z0-9.-]+.[A-Z][A-Z][A-Z]?/i
+~/(dog|fox)/g
+ +

Conditional compilation

+
#if !debug
+  trace("ok");
+#elseif (debug_level > 3)
+  trace(3);
+#else
+  trace("debug level too low");
+#end
+ +

Metadata

+
@author("Nicolas")
+@debug
+class MyClass {
+  @range(1, 8)
+  var value:Int;
+
+  @broken
+  @:noCompletion
+  static function method() { }
+}
+ +

Reification

+
macro static function add(e:Expr) {
+  return macro $e + $e;
+}
+ +

Known failures

+

There are certain edge cases where Prism will fail. + There are always such cases in every regex-based syntax highlighter. + However, Prism dares to be open and honest about them. + If a failure is listed here, it doesn’t mean it will never be fixed. This is more of a “known bugs” list, just with a certain type of bug. +

+ +

Comment-like substrings

+
"foo // var"
+ +

Two quotes of the same type (i.e. both single or both double) inside a regex

+
~/"foo"/
\ No newline at end of file diff --git a/plugins/autoloader/prism-autoloader.js b/plugins/autoloader/prism-autoloader.js index 85c02d7fec..0d04b72bc4 100644 --- a/plugins/autoloader/prism-autoloader.js +++ b/plugins/autoloader/prism-autoloader.js @@ -4,7 +4,7 @@ } // The dependencies map is built automatically with gulp - var lang_dependencies = /*languages_placeholder[*/{"javascript":"clike","actionscript":"javascript","aspnet":"markup","bison":"c","c":"clike","csharp":"clike","cpp":"c","coffeescript":"javascript","crystal":"ruby","css-extras":"css","d":"clike","dart":"clike","fsharp":"clike","glsl":"clike","go":"clike","groovy":"clike","haml":"ruby","handlebars":"markup","jade":"javascript","java":"clike","less":"css","markdown":"markup","nginx":"clike","objectivec":"c","parser":"markup","php":"clike","php-extras":"php","processing":"clike","qore":"clike","jsx":["markup","javascript"],"ruby":"clike","sass":"css","scss":"css","scala":"java","smarty":"markup","swift":"clike","textile":"markup","twig":"markup","typescript":"javascript","wiki":"markup"}/*]*/; + var lang_dependencies = /*languages_placeholder[*/{"javascript":"clike","actionscript":"javascript","aspnet":"markup","bison":"c","c":"clike","csharp":"clike","cpp":"c","coffeescript":"javascript","crystal":"ruby","css-extras":"css","d":"clike","dart":"clike","fsharp":"clike","glsl":"clike","go":"clike","groovy":"clike","haml":"ruby","handlebars":"markup","haxe":"clike","jade":"javascript","java":"clike","less":"css","markdown":"markup","nginx":"clike","objectivec":"c","parser":"markup","php":"clike","php-extras":"php","processing":"clike","qore":"clike","jsx":["markup","javascript"],"ruby":"clike","sass":"css","scss":"css","scala":"java","smarty":"markup","swift":"clike","textile":"markup","twig":"markup","typescript":"javascript","wiki":"markup"}/*]*/; var lang_data = {}; diff --git a/plugins/autoloader/prism-autoloader.min.js b/plugins/autoloader/prism-autoloader.min.js index 59a1a57a25..ef40ff60e6 100644 --- a/plugins/autoloader/prism-autoloader.min.js +++ b/plugins/autoloader/prism-autoloader.min.js @@ -1 +1 @@ -!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.createElement){var e={javascript:"clike",actionscript:"javascript",aspnet:"markup",bison:"c",c:"clike",csharp:"clike",cpp:"c",coffeescript:"javascript",crystal:"ruby","css-extras":"css",d:"clike",dart:"clike",fsharp:"clike",glsl:"clike",go:"clike",groovy:"clike",haml:"ruby",handlebars:"markup",jade:"javascript",java:"clike",less:"css",markdown:"markup",nginx:"clike",objectivec:"c",parser:"markup",php:"clike","php-extras":"php",processing:"clike",qore:"clike",jsx:["markup","javascript"],ruby:"clike",sass:"css",scss:"css",scala:"java",smarty:"markup",swift:"clike",textile:"markup",twig:"markup",typescript:"javascript",wiki:"markup"},c={},a=Prism.plugins.autoloader={languages_path:"components/",use_minified:!0},s=function(e,c,a){var s=document.createElement("script");s.src=e,s.async=!0,s.onload=function(){document.body.removeChild(s),c&&c()},s.onerror=function(){document.body.removeChild(s),a&&a()},document.body.appendChild(s)},r=function(e){return a.languages_path+"prism-"+e+(a.use_minified?".min":"")+".js"},n=function(e,a){var s=c[e];s||(s=c[e]={});var r=a.getAttribute("data-dependencies");!r&&a.parentNode&&"pre"===a.parentNode.tagName.toLowerCase()&&(r=a.parentNode.getAttribute("data-dependencies")),r=r?r.split(/\s*,\s*/g):[],i(r,function(){t(e,function(){Prism.highlightElement(a)})})},i=function(e,c,a){"string"==typeof e&&(e=[e]);var s=0,r=e.length,n=function(){r>s?t(e[s],function(){s++,n()},function(){a&&a(e[s])}):s===r&&c&&c(e)};n()},t=function(a,n,t){var u=function(){var e=!1;a.indexOf("!")>=0&&(e=!0,a=a.replace("!",""));var i=c[a];if(i||(i=c[a]={}),n&&(i.success_callbacks||(i.success_callbacks=[]),i.success_callbacks.push(n)),t&&(i.error_callbacks||(i.error_callbacks=[]),i.error_callbacks.push(t)),!e&&Prism.languages[a])l(a);else if(!e&&i.error)o(a);else if(e||!i.loading){i.loading=!0;var u=r(a);s(u,function(){i.loading=!1,l(a)},function(){i.loading=!1,i.error=!0,o(a)})}},p=e[a];p&&p.length?i(p,u):u()},l=function(e){c[e]&&c[e].success_callbacks&&c[e].success_callbacks.length&&c[e].success_callbacks.forEach(function(c){c(e)})},o=function(e){c[e]&&c[e].error_callbacks&&c[e].error_callbacks.length&&c[e].error_callbacks.forEach(function(c){c(e)})};Prism.hooks.add("complete",function(e){e.element&&e.language&&!e.grammar&&n(e.language,e.element)})}}(); \ No newline at end of file +!function(){if("undefined"!=typeof self&&self.Prism&&self.document&&document.createElement){var e={javascript:"clike",actionscript:"javascript",aspnet:"markup",bison:"c",c:"clike",csharp:"clike",cpp:"c",coffeescript:"javascript",crystal:"ruby","css-extras":"css",d:"clike",dart:"clike",fsharp:"clike",glsl:"clike",go:"clike",groovy:"clike",haml:"ruby",handlebars:"markup",haxe:"clike",jade:"javascript",java:"clike",less:"css",markdown:"markup",nginx:"clike",objectivec:"c",parser:"markup",php:"clike","php-extras":"php",processing:"clike",qore:"clike",jsx:["markup","javascript"],ruby:"clike",sass:"css",scss:"css",scala:"java",smarty:"markup",swift:"clike",textile:"markup",twig:"markup",typescript:"javascript",wiki:"markup"},c={},a=Prism.plugins.autoloader={languages_path:"components/",use_minified:!0},s=function(e,c,a){var s=document.createElement("script");s.src=e,s.async=!0,s.onload=function(){document.body.removeChild(s),c&&c()},s.onerror=function(){document.body.removeChild(s),a&&a()},document.body.appendChild(s)},r=function(e){return a.languages_path+"prism-"+e+(a.use_minified?".min":"")+".js"},n=function(e,a){var s=c[e];s||(s=c[e]={});var r=a.getAttribute("data-dependencies");!r&&a.parentNode&&"pre"===a.parentNode.tagName.toLowerCase()&&(r=a.parentNode.getAttribute("data-dependencies")),r=r?r.split(/\s*,\s*/g):[],i(r,function(){t(e,function(){Prism.highlightElement(a)})})},i=function(e,c,a){"string"==typeof e&&(e=[e]);var s=0,r=e.length,n=function(){r>s?t(e[s],function(){s++,n()},function(){a&&a(e[s])}):s===r&&c&&c(e)};n()},t=function(a,n,t){var u=function(){var e=!1;a.indexOf("!")>=0&&(e=!0,a=a.replace("!",""));var i=c[a];if(i||(i=c[a]={}),n&&(i.success_callbacks||(i.success_callbacks=[]),i.success_callbacks.push(n)),t&&(i.error_callbacks||(i.error_callbacks=[]),i.error_callbacks.push(t)),!e&&Prism.languages[a])l(a);else if(!e&&i.error)o(a);else if(e||!i.loading){i.loading=!0;var u=r(a);s(u,function(){i.loading=!1,l(a)},function(){i.loading=!1,i.error=!0,o(a)})}},p=e[a];p&&p.length?i(p,u):u()},l=function(e){c[e]&&c[e].success_callbacks&&c[e].success_callbacks.length&&c[e].success_callbacks.forEach(function(c){c(e)})},o=function(e){c[e]&&c[e].error_callbacks&&c[e].error_callbacks.length&&c[e].error_callbacks.forEach(function(c){c(e)})};Prism.hooks.add("complete",function(e){e.element&&e.language&&!e.grammar&&n(e.language,e.element)})}}(); \ No newline at end of file diff --git a/tests/languages/haxe/keyword_feature.test b/tests/languages/haxe/keyword_feature.test new file mode 100644 index 0000000000..6a26bd0962 --- /dev/null +++ b/tests/languages/haxe/keyword_feature.test @@ -0,0 +1,93 @@ +this +abstract +as +break +case +cast +catch +class +continue +default +do +dynamic +else +enum +extends +extern +from +for +function +if +implements +import +in +inline +interface +macro +new +null +override +public +private +return +static +super +switch +throw +to +try +typedef +using +var +while + +---------------------------------------------------- + +[ + ["keyword", "this"], + ["keyword", "abstract"], + ["keyword", "as"], + ["keyword", "break"], + ["keyword", "case"], + ["keyword", "cast"], + ["keyword", "catch"], + ["keyword", "class"], + ["keyword", "continue"], + ["keyword", "default"], + ["keyword", "do"], + ["keyword", "dynamic"], + ["keyword", "else"], + ["keyword", "enum"], + ["keyword", "extends"], + ["keyword", "extern"], + ["keyword", "from"], + ["keyword", "for"], + ["keyword", "function"], + ["keyword", "if"], + ["keyword", "implements"], + ["keyword", "import"], + ["keyword", "in"], + ["keyword", "inline"], + ["keyword", "interface"], + ["keyword", "macro"], + ["keyword", "new"], + ["keyword", "null"], + ["keyword", "override"], + ["keyword", "public"], + ["keyword", "private"], + ["keyword", "return"], + ["keyword", "static"], + ["keyword", "super"], + ["keyword", "switch"], + ["keyword", "throw"], + ["keyword", "to"], + ["keyword", "try"], + ["keyword", "typedef"], + ["keyword", "using"], + ["keyword", "var"], + ["keyword", "while"] +] + +---------------------------------------------------- + +Checks for keywords. \ No newline at end of file diff --git a/tests/languages/haxe/metadata_feature.test b/tests/languages/haxe/metadata_feature.test new file mode 100644 index 0000000000..312114d9a5 --- /dev/null +++ b/tests/languages/haxe/metadata_feature.test @@ -0,0 +1,15 @@ +@author("Nicolas") +@debug +@:noCompletion + +---------------------------------------------------- + +[ + ["metadata", "@author"], ["punctuation", "("], ["string", ["\"Nicolas\""]], ["punctuation", ")"], + ["metadata", "@debug"], + ["metadata", "@:noCompletion"] +] + +---------------------------------------------------- + +Checks for metadata. \ No newline at end of file diff --git a/tests/languages/haxe/operator_feature.test b/tests/languages/haxe/operator_feature.test new file mode 100644 index 0000000000..6963f80066 --- /dev/null +++ b/tests/languages/haxe/operator_feature.test @@ -0,0 +1,29 @@ +... ++ ++ +- -- -> += == +! != +& && +| || +< <= << +> >= >> +* / % ~ ^ + +---------------------------------------------------- + +[ + ["operator", "..."], + ["operator", "+"], ["operator", "++"], + ["operator", "-"], ["operator", "--"], ["operator", "->"], + ["operator", "="], ["operator", "=="], + ["operator", "!"], ["operator", "!="], + ["operator", "&"], ["operator", "&&"], + ["operator", "|"], ["operator", "||"], + ["operator", "<"], ["operator", "<="], ["operator", "<<"], + ["operator", ">"], ["operator", ">="], ["operator", ">>"], + ["operator", "*"], ["operator", "/"], ["operator", "%"], ["operator", "~"], ["operator", "^"] +] + +---------------------------------------------------- + +Checks for operators. \ No newline at end of file diff --git a/tests/languages/haxe/preprocessor_feature.test b/tests/languages/haxe/preprocessor_feature.test new file mode 100644 index 0000000000..3cadacf654 --- /dev/null +++ b/tests/languages/haxe/preprocessor_feature.test @@ -0,0 +1,17 @@ +#if +#elseif +#else +#end + +---------------------------------------------------- + +[ + ["preprocessor", "#if"], + ["preprocessor", "#elseif"], + ["preprocessor", "#else"], + ["preprocessor", "#end"] +] + +---------------------------------------------------- + +Checks for preprocessor directives. \ No newline at end of file diff --git a/tests/languages/haxe/regex_feature.test b/tests/languages/haxe/regex_feature.test new file mode 100644 index 0000000000..577cab7b9a --- /dev/null +++ b/tests/languages/haxe/regex_feature.test @@ -0,0 +1,15 @@ +~/ha\/xe/i +~/[A-Z0-9._%-]+@[A-Z0-9.-]+.[A-Z][A-Z][A-Z]?/i +~/(dog|fox)/igmsu + +---------------------------------------------------- + +[ + ["regex", "~/ha\\/xe/i"], + ["regex", "~/[A-Z0-9._%-]+@[A-Z0-9.-]+.[A-Z][A-Z][A-Z]?/i"], + ["regex", "~/(dog|fox)/igmsu"] +] + +---------------------------------------------------- + +Checks for regexes. \ No newline at end of file diff --git a/tests/languages/haxe/reification_feature.test b/tests/languages/haxe/reification_feature.test new file mode 100644 index 0000000000..6d382b7cc6 --- /dev/null +++ b/tests/languages/haxe/reification_feature.test @@ -0,0 +1,16 @@ +$e +${4+2} + +---------------------------------------------------- + +[ + ["reification", "$e"], + ["reification", "$"], + ["punctuation", "{"], + ["number", "4"], ["operator", "+"], ["number", "2"], + ["punctuation", "}"] +] + +---------------------------------------------------- + +Checks for reification. \ No newline at end of file diff --git a/tests/languages/haxe/string_feature.test b/tests/languages/haxe/string_feature.test new file mode 100644 index 0000000000..61f1985fcc --- /dev/null +++ b/tests/languages/haxe/string_feature.test @@ -0,0 +1,37 @@ +"" +"Foo +\"bar\" +baz" +"$bar ${4+2}" +'' +'Foo +\'bar\' +baz' + +---------------------------------------------------- + +[ + ["string", ["\"\""]], + ["string", ["\"Foo\r\n\\\"bar\\\"\r\nbaz\""]], + ["string", [ + "\"", + ["interpolation", [ + ["interpolation", "$bar"] + ]], + ["interpolation", [ + ["interpolation", "$"], + ["punctuation", "{"], + ["number", "4"], + ["operator", "+"], + ["number", "2"], + ["punctuation", "}"] + ]], + "\"" + ]], + ["string", ["''"]], + ["string", ["'Foo\r\n\\'bar\\'\r\nbaz'"]] +] + +---------------------------------------------------- + +Checks for strings and string interpolation. \ No newline at end of file