diff --git a/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js b/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js index c633c568bb6..085a971f700 100644 --- a/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js +++ b/app/assets/javascripts/discourse/tests/unit/lib/pretty-text-test.js @@ -18,7 +18,7 @@ const rawOpts = { enable_mentions: true, emoji_set: "twitter", external_emoji_url: "", - highlighted_languages: "json|ruby|javascript", + highlighted_languages: "json|ruby|javascript|xml", default_code_lang: "auto", enable_markdown_linkify: true, markdown_linkify_tlds: "com", @@ -1776,4 +1776,23 @@ var bar = 'bar'; "does not loop infinitely" ); }); + + test("highlighted aliased languages", function (assert) { + // "js" is an alias of "javascript" + assert.cooked( + "```js\nvar foo ='foo';\nvar bar = 'bar';\n```", + `
var foo ='foo';
+var bar = 'bar';
+
`, + "code block with js alias works" + ); + + // "html" is an alias of "xml" + assert.cooked( + "```html\nfun times\n```", + `
<strong>fun</strong> times
+
`, + "code block with html alias work" + ); + }); }); diff --git a/app/assets/javascripts/pretty-text/addon/highlightjs-aliases.js b/app/assets/javascripts/pretty-text/addon/highlightjs-aliases.js new file mode 100644 index 00000000000..9a9f27b3ea5 --- /dev/null +++ b/app/assets/javascripts/pretty-text/addon/highlightjs-aliases.js @@ -0,0 +1,123 @@ +// DO NOT EDIT THIS FILE!!! +// Update it by running `rake javascript:update_constants` + +export const HLJS_ALIASES = { + bash: ["sh"], + c: ["h"], + cpp: ["cc", "c++", "h++", "hpp", "hh", "hxx", "cxx"], + csharp: ["cs", "c#"], + diff: ["patch"], + go: ["golang"], + graphql: ["gql"], + ini: ["toml"], + java: ["jsp"], + javascript: ["js", "jsx", "mjs", "cjs"], + kotlin: ["kt", "kts"], + makefile: ["mk", "mak", "make"], + xml: [ + "html", + "xhtml", + "rss", + "atom", + "xjb", + "xsd", + "xsl", + "plist", + "wsf", + "svg", + ], + markdown: ["md", "mkdown", "mkd"], + objectivec: ["mm", "objc", "obj-c", "obj-c++", "objective-c++"], + perl: ["pl", "pm"], + plaintext: ["text", "txt"], + python: ["py", "gyp", "ipython"], + "python-repl": ["pycon"], + ruby: ["rb", "gemspec", "podspec", "thor", "irb"], + rust: ["rs"], + shell: ["console", "shellsession"], + typescript: ["ts", "tsx"], + vbnet: ["vb"], + yaml: ["yml"], + actionscript: ["as"], + angelscript: ["asc"], + apache: ["apacheconf"], + applescript: ["osascript"], + arduino: ["ino"], + armasm: ["arm"], + asciidoc: ["adoc"], + autohotkey: ["ahk"], + axapta: ["x++"], + brainfuck: ["bf"], + "c-like": [], + capnproto: ["capnp"], + clean: ["icl", "dcl"], + clojure: ["clj", "edn"], + cmake: ["cmake.in"], + coffeescript: ["coffee", "cson", "iced"], + cos: ["cls"], + crmsh: ["crm", "pcmk"], + crystal: ["cr"], + delphi: ["dpr", "dfm", "pas", "pascal"], + django: ["jinja"], + dns: ["bind", "zone"], + dockerfile: ["docker"], + dos: ["bat", "cmd"], + dust: ["dst"], + elixir: ["ex", "exs"], + erlang: ["erl"], + excel: ["xlsx", "xls"], + fortran: ["f90", "f95"], + fsharp: ["fs", "f#"], + gams: ["gms"], + gauss: ["gss"], + gcode: ["nc"], + gherkin: ["feature"], + handlebars: ["hbs", "html.hbs", "html.handlebars", "htmlbars"], + haskell: ["hs"], + haxe: ["hx"], + htmlbars: ["hbs", "html.hbs", "html.handlebars", "htmlbars"], + http: ["https"], + hy: ["hylang"], + inform7: ["i7"], + "jboss-cli": ["wildfly-cli"], + "julia-repl": ["jldoctest"], + lasso: ["ls", "lassoscript"], + latex: ["tex"], + livescript: ["ls"], + mathematica: ["mma", "wl"], + mercury: ["m", "moo"], + mipsasm: ["mips"], + moonscript: ["moon"], + nestedtext: ["nt"], + nginx: ["nginxconf"], + nimrod: ["nim"], + nix: ["nixos"], + ocaml: ["ml"], + openscad: ["scad"], + pf: ["pf.conf"], + pgsql: ["postgres", "postgresql"], + powershell: ["pwsh", "ps", "ps1"], + processing: ["pde"], + puppet: ["pp"], + purebasic: ["pb", "pbi"], + q: ["k", "kdb"], + qml: ["qt"], + reasonml: ["re"], + roboconf: ["graph", "instances"], + routeros: ["mikrotik"], + scilab: ["sci"], + smalltalk: ["st"], + sml: ["ml"], + sql_more: ["mysql", "oracle"], + stan: ["stanfuncs"], + stata: ["do", "ado"], + step21: ["p21", "step", "stp"], + stylus: ["styl"], + tcl: ["tk"], + twig: ["craftcms"], + vbscript: ["vbs"], + verilog: ["v", "sv", "svh"], + xl: ["tao"], + xquery: ["xpath", "xq"], + zephir: ["zep"], +}; diff --git a/app/assets/javascripts/pretty-text/engines/discourse-markdown/code.js b/app/assets/javascripts/pretty-text/engines/discourse-markdown/code.js index fa935ea7682..b79450cc668 100644 --- a/app/assets/javascripts/pretty-text/engines/discourse-markdown/code.js +++ b/app/assets/javascripts/pretty-text/engines/discourse-markdown/code.js @@ -1,3 +1,5 @@ +import { HLJS_ALIASES } from "pretty-text/highlightjs-aliases"; + // we need a custom renderer for code blocks cause we have a slightly non compliant // format with special handling for text and so on const TEXT_CODE_CLASSES = ["text", "pre", "plain"]; @@ -77,10 +79,20 @@ function render(tokens, idx, options, env, slf, md) { export function setup(helper) { helper.registerOptions((opts, siteSettings) => { - opts.defaultCodeLang = siteSettings.default_code_lang; - opts.acceptableCodeClasses = (siteSettings.highlighted_languages || "") + let languageAliases = []; + const languages = (siteSettings.highlighted_languages || "") .split("|") - .filter(Boolean) + .filter(Boolean); + + languages.forEach((lang) => { + if (HLJS_ALIASES[lang]) { + languageAliases = languageAliases.concat(HLJS_ALIASES[lang]); + } + }); + + opts.defaultCodeLang = siteSettings.default_code_lang; + opts.acceptableCodeClasses = languages + .concat(languageAliases) .concat(["auto", "plaintext"]); }); diff --git a/lib/tasks/javascript.rake b/lib/tasks/javascript.rake index cd699034ed6..eb544934d67 100644 --- a/lib/tasks/javascript.rake +++ b/lib/tasks/javascript.rake @@ -182,6 +182,32 @@ task "javascript:update_constants" => :environment do export const replacements = #{Emoji.unicode_replacements_json}; JS + langs = [] + Dir + .glob("vendor/assets/javascripts/highlightjs/languages/*.min.js") + .each { |f| langs << File.basename(f, ".min.js") } + bundle = HighlightJs.bundle(langs) + + ctx = MiniRacer::Context.new + hljs_aliases = ctx.eval(<<~JS) + #{bundle} + + let aliases = {}; + hljs.listLanguages().forEach((lang) => { + if (hljs.getLanguage(lang).aliases) { + aliases[lang] = hljs.getLanguage(lang).aliases; + } + }); + + aliases; + JS + + write_template("pretty-text/addon/highlightjs-aliases.js", task_name, <<~JS) + export const HLJS_ALIASES = #{hljs_aliases.to_json}; + JS + + ctx.dispose + write_template("pretty-text/addon/emoji/version.js", task_name, <<~JS) export const IMAGE_VERSION = "#{Emoji::EMOJI_VERSION}"; JS