diff --git a/.eslintrc.js b/.eslintrc.js index 1d36330ef0..61ad70d2e8 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -28,9 +28,10 @@ module.exports = { // for now ignore diff between types of quoting quotes: "off", // this is the style we are already using - "operator-linebreak": ["error", "before", { overrides: { - "=": "after" - } + "operator-linebreak": ["error", "before", { + overrides: { + "=": "after" + } }], // sometimes we declare variables with extra spacing indent: ["error", 2, { VariableDeclarator: 2 }], diff --git a/.github/ISSUE_TEMPLATE/1_incorrect-syntax-highlighting.md b/.github/ISSUE_TEMPLATE/1_incorrect-syntax-highlighting.md index 0083dfb43d..2da7594b42 100644 --- a/.github/ISSUE_TEMPLATE/1_incorrect-syntax-highlighting.md +++ b/.github/ISSUE_TEMPLATE/1_incorrect-syntax-highlighting.md @@ -24,7 +24,7 @@ Please specify exactly *which* language grammar you are using to highlight (`pyt Please include plain text examples of the code that fails to highlight properly or can reproduce the bug you are seeing. If you attach a screenshot PLEASE also provide the actually code that we can copy/paste if necessary to help resolve the issue. A jsfiddle can sometimes be even better. You can fork an example test case: -https://jsfiddle.net/ajoshguy/gfzujpyt/ +https://jsfiddle.net/ajoshguy/cjhvre2k/ --> diff --git a/.github/workflows/size_report.yml b/.github/workflows/size_report.yml new file mode 100644 index 0000000000..c542bff3e2 --- /dev/null +++ b/.github/workflows/size_report.yml @@ -0,0 +1,21 @@ +# This workflow computes the size of a CDN build's output on all Javascript files. +# Reported file sizes are after the result of gzip compression. +# Compression action used: https://github.com/preactjs/compressed-size-action + +name: Size Report (gzip) + +on: [pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Compute Compressed Size + uses: preactjs/compressed-size-action@v2 + with: + build-script: "build-cdn" + compression: "gzip" + pattern: "./build/{*.min.js,es/*.min.js,languages/*.min.js,es/languages/*.min.js}" diff --git a/CHANGES.md b/CHANGES.md index da390042c7..7973fa6ff6 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,3 +1,77 @@ +## Version 11.4.0 + +New Language: + +- Added 3rd party Pine Script grammar to SUPPORTED_LANGUAGES [Jeylani B][] +- Added 3rd party cURL grammar to SUPPORTED_LANGUAGES [highlightjs-curl](https://github.com/highlightjs/highlightjs-curl) + +Themes: + +- `Default` is now much closer WCAG AA (contrast) (#3402) [Josh Goebel] +- `Dark` now meets WCAG AA (contrast) (#3402) [Josh Goebel] +- Added `intellij-light` theme [Pegasis] + +These changes should be for the better and should not be super noticeable but if you're super picky about your colors you may want to intervene here or copy over the older themes from 11.3 or prior. + +Grammars: + +- enh(arcade) updated to ArcGIS Arcade version 1.16 [John Foster][] +- enh(php) Left and right-side of double colon [Wojciech Kania][] +- enh(php) add PHP constants [Wojciech Kania][] +- enh(php) add PHP 8.1 keywords [Wojciech Kania][] +- fix(cpp) fix `vector<<` template false positive (#3437) [Josh Goebel][] +- enh(php) support First-class Callable Syntax (#3427) [Wojciech Kania][] +- enh(php) support class constructor call (#3427) [Wojciech Kania][] +- enh(php) support function invoke (#3427) [Wojciech Kania][] +- enh(php) Switch highlighter to partially case-insensitive (#3427) [Wojciech Kania][] +- enh(php) improve `namespace` and `use` highlighting (#3427) [Josh Goebel][] +- enh(php) `$this` is a `variable.language` now (#3427) [Josh Goebel][] +- enh(php) add `__COMPILER_HALT_OFFSET__` (#3427) [Josh Goebel][] +- enh(js/ts) fix => async function title highlights (#3405) [Josh Goebel][] +- enh(twig) update keywords list (#3415) [Matthieu Lempereur][] +- fix(python) def, class keywords detected mid-identifier (#3381) [Josh Goebel][] +- fix(python) Fix recognition of numeric literals followed by keywords without whitespace (#2985) [Richard Gibson][] +- enh(swift) add SE-0290 unavailability condition (#3382) [Bradley Mackey][] +- fix(fsharp) Highlight operators, match type names only in type annotations, support quoted identifiers, and other smaller fixes. [Melvyn Laïly][] +- enh(java) add `sealed` and `non-sealed` keywords (#3386) [Bradley Mackey][] +- enh(js/ts) improve `CLASS_REFERENCE` (#3411) [Josh Goebel][] +- enh(nsis) Update defines pattern to allow `!` (#3417) [idleberg][] +- enh(nsis) Update language strings pattern to allow `!` (#3420) [idleberg][] +- fix(stan) Updated for Stan 2.28 and other misc. improvements (#3410) +- enh(nsis) Update variables pattern (#3416) [idleberg][] +- fix(clojure) Several issues with Clojure highlighting (#3397) [Björn Ebbinghaus][] + - fix(clojure) `comment` macro catches more than it should (#3395) + - fix(clojure) `$` in symbol breaks highlighting + - fix(clojure) Add complete regex for number detection + - enh(clojure) Add character mode for character literals + - fix(clojure) Inconsistent namespaced map highlighting + - enh(clojure) Add `regex` mode to regex literal + - fix(clojure) Remove inconsistent/broken highlighting for metadata + - enh(clojure) Add `punctuation` mode for commas. +- fix(julia) Enable the `jldoctest` alias (#3432) [Fons van der Plas][] + +Developer Tools: + +- (chore) add gzip size compression report (#3400) [Bradley Mackey][] + +Themes: + +- Modified background color in css for Gradient Light and Gradient Dark themes [Samia Ali][] + +[John Foster]: https://github.com/jf990 +[Pegasis]: https://github.com/PegasisForever +[Wojciech Kania]: https://github.com/wkania +[Jeylani B]: https://github.com/jeyllani +[Richard Gibson]: https://github.com/gibson042 +[Bradley Mackey]: https://github.com/bradleymackey +[Melvyn Laïly]: https://github.com/mlaily +[Björn Ebbinghaus]: https://github.com/MrEbbinghaus +[Josh Goebel]: https://github.com/joshgoebel +[Samia Ali]: https://github.com/samiaab1990 +[Matthieu Lempereur]: https://github.com/MrYamous +[idleberg]: https://github.com/idleberg +[Fons van der Plas]: https://github.com/fonsp + ## Version 11.3.1 Build: @@ -707,6 +781,7 @@ Parser Engine: - (fix) When ignoring a potential match highlighting can terminate early (#2649) [Josh Goebel][] + New themes: - *Gradient Light* by [Samia Ali]() @@ -742,7 +817,6 @@ Language Improvements: [eytienne]: https://github.com/eytienne [sirosen]: https://github.com/sirosen - ## Version 10.1.1 Fixes: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c67163c962..7c7c60b823 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -66,7 +66,7 @@ If you wish we supported a language we don't, first read [On requesting new lang ## Reporting Issues If you find a bug or think of an improvement, feel free to [open an issue](https://github.com/highlightjs/highlight.js/issues/new/choose). -- If you've found a language highlighting issue, you can use [this JSFiddle](https://jsfiddle.net/ajoshguy/2bmdswn6/) to create a test case. +- If you've found a language highlighting issue, you can use [this JSFiddle](https://jsfiddle.net/ajoshguy/cjhvre2k/) to create a test case. ## Fixing Issues (PRs) diff --git a/README.md b/README.md index 96a8ca1c06..e4f00a20e3 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ [![discord](https://badgen.net/badge/icon/discord?icon=discord&label&color=pink)](https://discord.gg/M24EbU7ja9) [![open issues](https://badgen.net/github/open-issues/highlightjs/highlight.js?label=issues)](https://github.com/highlightjs/highlight.js/issues) [![help welcome issues](https://badgen.net/github/label-issues/highlightjs/highlight.js/help%20welcome/open)](https://github.com/highlightjs/highlight.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+welcome%22) -[![good first issue](https://badgen.net/github/label-issues/highlightjs/highlight.js/good%20first%20issue/open)](https://github.com/highlightjs/highlight.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22beginner+friendly%22) +[![good first issue](https://badgen.net/github/label-issues/highlightjs/highlight.js/good%20first%20issue/open)](https://github.com/highlightjs/highlight.js/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22) @@ -48,6 +48,9 @@ detection. - [ES6 Modules / `import`](#es6-modules--import) - [Getting the Library](#getting-the-library) - [Fetch via CDN](#fetch-via-cdn) + - [cdnjs (link)](#cdnjs-link) + - [jsdelivr (link)](#jsdelivr-link) + - [unpkg (link)](#unpkg-link) - [Download prebuilt CDN assets](#download-prebuilt-cdn-assets) - [Download from our website](#download-from-our-website) - [Install via NPM package](#install-via-npm-package) @@ -76,7 +79,7 @@ The bare minimum for using highlight.js on a web page is linking to the library along with one of the themes and calling [`highlightAll`][1]: ```html - + ``` @@ -268,13 +271,16 @@ const highlightedCode = hljs.highlight('Hello World!', {language: ' ### ES6 Modules / `import` +*Note: You can also import directly from fully static URLs, such as our very own pre-built +ES6 Module CDN resources. See [Fetch via CDN](#fetch-via-cdn) for specific examples.* + The default import will register all languages: ```js import hljs from 'highlight.js'; ``` - It is more efficient to import only the library and register the languages you need: +It is more efficient to import only the library and register the languages you need: ```js import hljs from 'highlight.js/lib/core'; @@ -317,33 +323,78 @@ A prebuilt version of Highlight.js bundled with many common languages is hosted When using Highlight.js via CDN you can use Subresource Integrity for additional security. For details see [DIGESTS.md](https://github.com/highlightjs/cdn-release/blob/main/DIGESTS.md). -**cdnjs** ([link](https://cdnjs.com/libraries/highlight.js)) +#### cdnjs ([link](https://cdnjs.com/libraries/highlight.js)) + +##### Common JS ```html - - + + - + ``` -**jsdelivr** ([link](https://www.jsdelivr.com/package/gh/highlightjs/cdn-release)) +##### ES6 Modules + +````html + + + +```` + + +#### jsdelivr ([link](https://www.jsdelivr.com/package/gh/highlightjs/cdn-release)) + +##### Common JS ```html - - + + - + ``` -**unpkg** ([link](https://unpkg.com/browse/@highlightjs/cdn-assets/)) +##### ES6 Modules ```html - - + + +``` + +#### unpkg ([link](https://unpkg.com/browse/@highlightjs/cdn-assets/)) + +##### Common JS + +```html + + - + +``` + +##### ES6 Modules + +```html + + ``` + **Note:** *The CDN-hosted `highlight.min.js` package doesn't bundle every language.* It would be very large. You can find our list of "common" languages that we bundle by default on our [download page][5]. diff --git a/SUPPORTED_LANGUAGES.md b/SUPPORTED_LANGUAGES.md index 6d53724dde..c73a294af5 100644 --- a/SUPPORTED_LANGUAGES.md +++ b/SUPPORTED_LANGUAGES.md @@ -52,6 +52,7 @@ The table below shows the full list of languages (and corresponding classes/alia | CpcdosC+ | cpc | [highlightjs-cpcdos](https://github.com/SPinti-Software/highlightjs-cpcdos) | | Crmsh | crmsh, crm, pcmk | | | Crystal | crystal, cr | | +| cURL | curl | [highlightjs-curl](https://github.com/highlightjs/highlightjs-curl) | | Cypher (Neo4j) | cypher | [highlightjs-cypher](https://github.com/highlightjs/highlightjs-cypher) | | D | d | | | Dafny | dafny | [highlightjs-dafny](https://github.com/ConsenSys/highlightjs-dafny)| @@ -87,6 +88,7 @@ The table below shows the full list of languages (and corresponding classes/alia | Golo | golo, gololang | | | Gradle | gradle | | | Groovy | groovy | | +| GSQL | gsql | [highlightjs-gsql](https://github.com/DanBarkus/highlightjs-gsql) | | HTML, XML | xml, html, xhtml, rss, atom, xjb, xsd, xsl, plist, svg | | | HTTP | http, https | | | Haml | haml | | @@ -145,6 +147,7 @@ The table below shows the full list of languages (and corresponding classes/alia | Papyrus | papyrus, psc |[highlightjs-papyrus](https://github.com/Pickysaurus/highlightjs-papyrus) | | Parser3 | parser3 | | | Perl | perl, pl, pm | | +| Pine Script | pine, pinescript | [highlightjs-pine](https://github.com/jeyllani/highlightjs-pine) | | Plaintext | plaintext, txt, text | | | Pony | pony | | | PostgreSQL & PL/pgSQL | pgsql, postgres, postgresql | | diff --git a/demo/demo.js b/demo/demo.js index 079080e67a..49f6bcef1f 100644 --- a/demo/demo.js +++ b/demo/demo.js @@ -1,8 +1,10 @@ hljs.debugMode(); hljs.highlightAll(); -document.querySelectorAll(".categories > li").forEach((category) => { +document.querySelectorAll(".categories li a").forEach((category) => { category.addEventListener("click", (event) => { + event.preventDefault(); + const current = document.querySelector(".categories .current"); const currentCategory = current.dataset.category; const nextCategory = event.target.dataset.category; @@ -23,15 +25,21 @@ document.querySelectorAll(".categories > li").forEach((category) => { }); }); -document.querySelectorAll(".styles > li").forEach((style) => { +document.querySelectorAll(".styles li a").forEach((style) => { style.addEventListener("click", (event) => { + event.preventDefault(); + const current = document.querySelector(".styles .current"); const currentStyle = current.textContent; const nextStyle = event.target.textContent; if (currentStyle !== nextStyle) { - document.querySelector(`link[title="${nextStyle}"]`).removeAttribute("disabled"); - document.querySelector(`link[title="${currentStyle}"]`).setAttribute("disabled", "disabled"); + document + .querySelector(`link[title="${nextStyle}"]`) + .removeAttribute("disabled"); + document + .querySelector(`link[title="${currentStyle}"]`) + .setAttribute("disabled", "disabled"); current.classList.remove("current"); event.target.classList.add("current"); diff --git a/demo/index.html b/demo/index.html index f7ee27df84..ad6371748c 100644 --- a/demo/index.html +++ b/demo/index.html @@ -23,14 +23,14 @@

highlight.js demo

Language Categories

Themes

diff --git a/demo/style.css b/demo/style.css index 9073c14c24..e23f06d2e7 100644 --- a/demo/style.css +++ b/demo/style.css @@ -102,16 +102,19 @@ aside ul::-webkit-scrollbar-thumb:active { background: #5d3333; } -aside li { - padding: 1px 1em; - cursor: pointer; +aside ul a { + display: block; + padding: 1px 0.5em 1px 1em; + text-decoration: none; } -aside li:hover { +aside ul a:focus, +aside ul a:hover { background: #500; + outline: none; } -aside li.current:before { +aside ul a.current:before { content: "▶"; font-size: smaller; position: absolute; diff --git a/docs/conf.py b/docs/conf.py index 3fd4634487..95fb287478 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,14 +46,14 @@ # General information about the project. project = u'highlight.js' -copyright = u'2012–2021, Ivan Sagalaev' +copyright = u'2012–2022, Ivan Sagalaev' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The full version, including alpha/beta/rc tags. -release = '11.3.1' +release = '11.4.0' # The short X.Y version. version = ".".join(release.split(".")[:2]) diff --git a/docs/css-classes-reference.rst b/docs/css-classes-reference.rst index 70d45e4dc4..9cea743642 100644 --- a/docs/css-classes-reference.rst +++ b/docs/css-classes-reference.rst @@ -70,6 +70,8 @@ in mind so a better choice (for best theme support) might possibly be ``string`` +--------------------------+-------------------------------------------------------------+ | title.function | name of a function | +--------------------------+-------------------------------------------------------------+ +| title.function.invoke | name of a function (when being invoked) | ++--------------------------+-------------------------------------------------------------+ | params | block of function arguments (parameters) at the | | | place of declaration | +--------------------------+-------------------------------------------------------------+ diff --git a/highlight.js b/highlight.js new file mode 160000 index 0000000000..10b322dc43 --- /dev/null +++ b/highlight.js @@ -0,0 +1 @@ +Subproject commit 10b322dc436333b04df8295c9bdf4bad324849e0 diff --git a/package-lock.json b/package-lock.json index 877b12bf68..349ec60b07 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { "name": "highlight.js", - "version": "11.3.1", + "version": "11.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "version": "11.3.1", + "version": "11.4.0", "license": "BSD-3-Clause", "devDependencies": { "@rollup/plugin-commonjs": "^21.0.0", @@ -19,6 +19,7 @@ "colors": "^1.1.2", "commander": "8.2", "css": "^3.0.0", + "css-color-names": "^1.0.1", "deep-freeze-es6": "^1.4.1", "del": "^6.0.0", "dependency-resolver": "^2.0.1", @@ -38,7 +39,8 @@ "should": "^13.2.3", "terser": "^5.7.0", "tiny-worker": "^2.3.0", - "typescript": "^4.4.4" + "typescript": "^4.4.4", + "wcag-contrast": "^3.0.0" }, "engines": { "node": ">=12.0.0" @@ -1042,6 +1044,15 @@ "source-map-resolve": "^0.6.0" } }, + "node_modules/css-color-names": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-1.0.1.tgz", + "integrity": "sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -3358,6 +3369,15 @@ "node": ">=8" } }, + "node_modules/relative-luminance": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/relative-luminance/-/relative-luminance-2.0.1.tgz", + "integrity": "sha512-wFuITNthJilFPwkK7gNJcULxXBcfFZvZORsvdvxeOdO44wCeZnuQkf3nFFzOR/dpJNxYsdRZJLsepWbyKhnMww==", + "dev": true, + "dependencies": { + "esm": "^3.0.84" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -4075,6 +4095,15 @@ "node": ">=12" } }, + "node_modules/wcag-contrast": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/wcag-contrast/-/wcag-contrast-3.0.0.tgz", + "integrity": "sha512-RWbpg/S7FOXDCwqC2oFhN/vh8dHzj0OS6dpyOSDHyQFSmqmR+lAUStV/ziTT1GzDqL9wol+nZQB4vCi5yEak+w==", + "dev": true, + "dependencies": { + "relative-luminance": "^2.0.0" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -5111,6 +5140,12 @@ "source-map-resolve": "^0.6.0" } }, + "css-color-names": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-1.0.1.tgz", + "integrity": "sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA==", + "dev": true + }, "cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -6839,6 +6874,15 @@ "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", "dev": true }, + "relative-luminance": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/relative-luminance/-/relative-luminance-2.0.1.tgz", + "integrity": "sha512-wFuITNthJilFPwkK7gNJcULxXBcfFZvZORsvdvxeOdO44wCeZnuQkf3nFFzOR/dpJNxYsdRZJLsepWbyKhnMww==", + "dev": true, + "requires": { + "esm": "^3.0.84" + } + }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -7399,6 +7443,15 @@ "xml-name-validator": "^4.0.0" } }, + "wcag-contrast": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/wcag-contrast/-/wcag-contrast-3.0.0.tgz", + "integrity": "sha512-RWbpg/S7FOXDCwqC2oFhN/vh8dHzj0OS6dpyOSDHyQFSmqmR+lAUStV/ziTT1GzDqL9wol+nZQB4vCi5yEak+w==", + "dev": true, + "requires": { + "relative-luminance": "^2.0.0" + } + }, "webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", diff --git a/package.json b/package.json index 6f88716be7..0687273b47 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "syntax" ], "homepage": "https://highlightjs.org/", - "version": "11.3.1", + "version": "11.4.0", "author": { "name": "Ivan Sagalaev", "email": "maniac@softwaremaniacs.org" @@ -37,7 +37,7 @@ "types": "./types/index.d.ts", "scripts": { "mocha": "mocha", - "lint": "eslint src/*.js src/lib/*.js demo/*.js", + "lint": "eslint src/*.js src/lib/*.js demo/*.js tools/**/*.js --ignore-pattern vendor", "lint-languages": "eslint --no-eslintrc -c .eslintrc.lang.js src/languages/**/*.js", "build_and_test": "npm run build && npm run test", "build_and_test_browser": "npm run build-browser && npm run test-browser", @@ -65,6 +65,7 @@ "colors": "^1.1.2", "commander": "8.2", "css": "^3.0.0", + "css-color-names": "^1.0.1", "deep-freeze-es6": "^1.4.1", "del": "^6.0.0", "dependency-resolver": "^2.0.1", @@ -84,6 +85,7 @@ "should": "^13.2.3", "terser": "^5.7.0", "tiny-worker": "^2.3.0", - "typescript": "^4.4.4" + "typescript": "^4.4.4", + "wcag-contrast": "^3.0.0" } } diff --git a/src/highlight.js b/src/highlight.js index 6f546e6ccc..ed0e187fd5 100644 --- a/src/highlight.js +++ b/src/highlight.js @@ -734,7 +734,8 @@ const HLJS = function(hljs) { if (element.children.length > 0) { if (!options.ignoreUnescapedHTML) { console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."); - console.warn("https://github.com/highlightjs/highlight.js/issues/2886"); + console.warn("https://github.com/highlightjs/highlight.js/wiki/security"); + console.warn("The element with unescaped HTML:"); console.warn(element); } if (options.throwUnescapedHTML) { diff --git a/src/languages/arcade.js b/src/languages/arcade.js index 45abb1ea18..6de745189d 100644 --- a/src/languages/arcade.js +++ b/src/languages/arcade.js @@ -10,22 +10,223 @@ export default function(hljs) { const IDENT_RE = '[A-Za-z_][0-9A-Za-z_]*'; const KEYWORDS = { - keyword: - 'if for while var new function do return void else break', - literal: - 'BackSlash DoubleQuote false ForwardSlash Infinity NaN NewLine null PI SingleQuote Tab TextFormatting true undefined', - built_in: - 'Abs Acos Angle Attachments Area AreaGeodetic Asin Atan Atan2 Average Bearing Boolean Buffer BufferGeodetic ' + - 'Ceil Centroid Clip Console Constrain Contains Cos Count Crosses Cut Date DateAdd ' + - 'DateDiff Day Decode DefaultValue Dictionary Difference Disjoint Distance DistanceGeodetic Distinct ' + - 'DomainCode DomainName Equals Exp Extent Feature FeatureSet FeatureSetByAssociation FeatureSetById FeatureSetByPortalItem ' + - 'FeatureSetByRelationshipName FeatureSetByTitle FeatureSetByUrl Filter First Floor Geometry GroupBy Guid HasKey Hour IIf IndexOf ' + - 'Intersection Intersects IsEmpty IsNan IsSelfIntersecting Length LengthGeodetic Log Max Mean Millisecond Min Minute Month ' + - 'MultiPartToSinglePart Multipoint NextSequenceValue Now Number OrderBy Overlaps Point Polygon ' + - 'Polyline Portal Pow Random Relate Reverse RingIsClockWise Round Second SetGeometry Sin Sort Sqrt Stdev Sum ' + - 'SymmetricDifference Tan Text Timestamp Today ToLocal Top Touches ToUTC TrackCurrentTime ' + - 'TrackGeometryWindow TrackIndex TrackStartTime TrackWindow TypeOf Union UrlEncode Variance ' + - 'Weekday When Within Year ' + keyword: [ + "if", + "for", + "while", + "var", + "new", + "function", + "do", + "return", + "void", + "else", + "break" + ], + literal: [ + "BackSlash", + "DoubleQuote", + "false", + "ForwardSlash", + "Infinity", + "NaN", + "NewLine", + "null", + "PI", + "SingleQuote", + "Tab", + "TextFormatting", + "true", + "undefined" + ], + built_in: [ + "Abs", + "Acos", + "All", + "Angle", + "Any", + "Area", + "AreaGeodetic", + "Array", + "Asin", + "Atan", + "Atan2", + "Attachments", + "Average", + "Back", + "Bearing", + "Boolean", + "Buffer", + "BufferGeodetic", + "Ceil", + "Centroid", + "Clip", + "Concatenate", + "Console", + "Constrain", + "Contains", + "ConvertDirection", + "Cos", + "Count", + "Crosses", + "Cut", + "Date", + "DateAdd", + "DateDiff", + "Day", + "Decode", + "DefaultValue", + "Densify", + "DensifyGeodetic", + "Dictionary", + "Difference", + "Disjoint", + "Distance", + "DistanceGeodetic", + "Distinct", + "Domain", + "DomainCode", + "DomainName", + "EnvelopeIntersects", + "Equals", + "Erase", + "Exp", + "Expects", + "Extent", + "Feature", + "FeatureSet", + "FeatureSetByAssociation", + "FeatureSetById", + "FeatureSetByName", + "FeatureSetByPortalItem", + "FeatureSetByRelationshipName", + "Filter", + "Find", + "First", + "Floor", + "FromCharCode", + "FromCodePoint", + "FromJSON", + "GdbVersion", + "Generalize", + "Geometry", + "GetFeatureSet", + "GetUser", + "GroupBy", + "Guid", + "Hash", + "HasKey", + "Hour", + "IIf", + "Includes", + "IndexOf", + "Insert", + "Intersection", + "Intersects", + "IsEmpty", + "IsNan", + "ISOMonth", + "ISOWeek", + "ISOWeekday", + "ISOYear", + "IsSelfIntersecting", + "IsSimple", + "Left|0", + "Length", + "Length3D", + "LengthGeodetic", + "Log", + "Lower", + "Map", + "Max", + "Mean", + "Mid", + "Millisecond", + "Min", + "Minute", + "Month", + "MultiPartToSinglePart", + "Multipoint", + "NextSequenceValue", + "None", + "Now", + "Number", + "Offset|0", + "OrderBy", + "Overlaps", + "Point", + "Polygon", + "Polyline", + "Pop", + "Portal", + "Pow", + "Proper", + "Push", + "Random", + "Reduce", + "Relate", + "Replace", + "Resize", + "Reverse", + "Right|0", + "RingIsClockwise", + "Rotate", + "Round", + "Schema", + "Second", + "SetGeometry", + "Simplify", + "Sin", + "Slice", + "Sort", + "Splice", + "Split", + "Sqrt", + "Stdev", + "SubtypeCode", + "SubtypeName", + "Subtypes", + "Sum", + "SymmetricDifference", + "Tan", + "Text", + "Timestamp", + "ToCharCode", + "ToCodePoint", + "Today", + "ToHex", + "ToLocal", + "Top|0", + "Touches", + "ToUTC", + "TrackAccelerationAt", + "TrackAccelerationWindow", + "TrackCurrentAcceleration", + "TrackCurrentDistance", + "TrackCurrentSpeed", + "TrackCurrentTime", + "TrackDistanceAt", + "TrackDistanceWindow", + "TrackDuration", + "TrackFieldWindow", + "TrackGeometryWindow", + "TrackIndex", + "TrackSpeedAt", + "TrackSpeedWindow", + "TrackStartTime", + "TrackWindow", + "Trim", + "TypeOf", + "Union", + "Upper", + "UrlEncode", + "Variance", + "Week", + "Weekday", + "When", + "Within", + "Year" + ] }; const SYMBOL = { className: 'symbol', @@ -34,15 +235,9 @@ export default function(hljs) { const NUMBER = { className: 'number', variants: [ - { - begin: '\\b(0[bB][01]+)' - }, - { - begin: '\\b(0[oO][0-7]+)' - }, - { - begin: hljs.C_NUMBER_RE - } + { begin: '\\b(0[bB][01]+)' }, + { begin: '\\b(0[oO][0-7]+)' }, + { begin: hljs.C_NUMBER_RE } ], relevance: 0 }; @@ -76,6 +271,7 @@ export default function(hljs) { return { name: 'ArcGIS Arcade', + case_insensitive: true, keywords: KEYWORDS, contains: [ hljs.APOS_STRING_MODE, @@ -88,16 +284,20 @@ export default function(hljs) { { // object attr container begin: /[{,]\s*/, relevance: 0, - contains: [{ - begin: IDENT_RE + '\\s*:', - returnBegin: true, - relevance: 0, - contains: [{ - className: 'attr', - begin: IDENT_RE, - relevance: 0 - }] - }] + contains: [ + { + begin: IDENT_RE + '\\s*:', + returnBegin: true, + relevance: 0, + contains: [ + { + className: 'attr', + begin: IDENT_RE, + relevance: 0 + } + ] + } + ] }, { // "value" container begin: '(' + hljs.RE_STARTERS_RE + '|\\b(return)\\b)\\s*', @@ -111,25 +311,23 @@ export default function(hljs) { begin: '(\\(.*?\\)|' + IDENT_RE + ')\\s*=>', returnBegin: true, end: '\\s*=>', - contains: [{ - className: 'params', - variants: [ - { - begin: IDENT_RE - }, - { - begin: /\(\s*\)/ - }, - { - begin: /\(/, - end: /\)/, - excludeBegin: true, - excludeEnd: true, - keywords: KEYWORDS, - contains: PARAMS_CONTAINS - } - ] - }] + contains: [ + { + className: 'params', + variants: [ + { begin: IDENT_RE }, + { begin: /\(\s*\)/ }, + { + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, + keywords: KEYWORDS, + contains: PARAMS_CONTAINS + } + ] + } + ] } ], relevance: 0 @@ -154,9 +352,7 @@ export default function(hljs) { ], illegal: /\[|%/ }, - { - begin: /\$[(.]/ - } + { begin: /\$[(.]/ } ], illegal: /#(?!!)/ }; diff --git a/src/languages/axapta.js b/src/languages/axapta.js index f5768bddd9..90edecc6f6 100644 --- a/src/languages/axapta.js +++ b/src/languages/axapta.js @@ -8,6 +8,7 @@ Category: enterprise /** @type LanguageFn */ export default function(hljs) { + const IDENT_RE = hljs.UNDERSCORE_IDENT_RE; const BUILT_IN_KEYWORDS = [ 'anytype', 'boolean', @@ -144,6 +145,30 @@ export default function(hljs) { literal: LITERAL_KEYWORDS }; + const CLASS_DEFINITION = { + variants: [ + { + match: [ + /(class|interface)\s+/, + IDENT_RE, + /\s+(extends|implements)\s+/, + IDENT_RE + ] + }, + { + match: [ + /class\s+/, + IDENT_RE + ] + } + ], + scope: { + 2: "title.class", + 4: "title.class.inherited" + }, + keywords: KEYWORDS + }; + return { name: 'X++', aliases: ['x++'], @@ -159,19 +184,7 @@ export default function(hljs) { begin: '#', end: '$' }, - { - className: 'class', - beginKeywords: 'class interface', - end: /\{/, - excludeEnd: true, - illegal: ':', - contains: [ - { - beginKeywords: 'extends implements' - }, - hljs.UNDERSCORE_TITLE_MODE - ] - } + CLASS_DEFINITION ] }; } diff --git a/src/languages/cal.js b/src/languages/cal.js index 94cee44a0c..bcbbecc822 100644 --- a/src/languages/cal.js +++ b/src/languages/cal.js @@ -7,9 +7,35 @@ Website: https://docs.microsoft.com/en-us/dynamics-nav/programming-in-c-al /** @type LanguageFn */ export default function(hljs) { - const KEYWORDS = - 'div mod in and or not xor asserterror begin case do downto else end exit for if of repeat then to ' + - 'until while with var'; + const regex = hljs.regex; + const KEYWORDS = [ + "div", + "mod", + "in", + "and", + "or", + "not", + "xor", + "asserterror", + "begin", + "case", + "do", + "downto", + "else", + "end", + "exit", + "for", + "local", + "if", + "of", + "repeat", + "then", + "to", + "until", + "while", + "with", + "var" + ]; const LITERALS = 'false true'; const COMMENT_MODES = [ hljs.C_LINE_COMMENT_MODE, @@ -52,12 +78,17 @@ export default function(hljs) { }; const PROCEDURE = { - className: 'function', - beginKeywords: 'procedure', - end: /[:;]/, - keywords: 'procedure|10', + match: [ + /procedure/, + /\s+/, + /[a-zA-Z_][\w@]*/, + /\s*/ + ], + scope: { + 1: "keyword", + 3: "title.function" + }, contains: [ - hljs.TITLE_MODE, { className: 'params', begin: /\(/, @@ -65,20 +96,49 @@ export default function(hljs) { keywords: KEYWORDS, contains: [ STRING, - CHAR_STRING + CHAR_STRING, + hljs.NUMBER_MODE ] - } - ].concat(COMMENT_MODES) + }, + ...COMMENT_MODES + ] }; + const OBJECT_TYPES = [ + "Table", + "Form", + "Report", + "Dataport", + "Codeunit", + "XMLport", + "MenuSuite", + "Page", + "Query" + ]; const OBJECT = { - className: 'class', - begin: 'OBJECT (Table|Form|Report|Dataport|Codeunit|XMLport|MenuSuite|Page|Query) (\\d+) ([^\\r\\n]+)', - returnBegin: true, - contains: [ - hljs.TITLE_MODE, - PROCEDURE - ] + match: [ + /OBJECT/, + /\s+/, + regex.either(...OBJECT_TYPES), + /\s+/, + /\d+/, + /\s+(?=[^\s])/, + /.*/, + /$/ + ], + relevance: 3, + scope: { + 1: "keyword", + 3: "type", + 5: "number", + 7: "title" + } + }; + + const PROPERTY = { + match: /[\w]+(?=\=)/, + scope: "attribute", + relevance: 0 }; return { @@ -90,6 +150,7 @@ export default function(hljs) { }, illegal: /\/\*/, contains: [ + PROPERTY, STRING, CHAR_STRING, DATE, diff --git a/src/languages/capnproto.js b/src/languages/capnproto.js index 9986f7292a..5fa4ec5577 100644 --- a/src/languages/capnproto.js +++ b/src/languages/capnproto.js @@ -27,7 +27,7 @@ export default function(hljs) { "from", "fixed" ]; - const BUILT_INS = [ + const TYPES = [ "Void", "Bool", "Int8", @@ -51,12 +51,33 @@ export default function(hljs) { "true", "false" ]; + const CLASS_DEFINITION = { + variants: [ + { + match: [ + /(struct|enum|interface)/, /\s+/, + hljs.IDENT_RE + ] + }, + { + match: [ + /extends/, /\s*\(/, + hljs.IDENT_RE, + /\s*\)/ + ] + } + ], + scope: { + 1: "keyword", + 3: "title.class" + } + }; return { name: 'Cap’n Proto', aliases: ['capnp'], keywords: { keyword: KEYWORDS, - built_in: BUILT_INS, + type: TYPES, literal: LITERALS }, contains: [ @@ -72,30 +93,7 @@ export default function(hljs) { className: 'symbol', begin: /@\d+\b/ }, - { - className: 'class', - beginKeywords: 'struct enum', - end: /\{/, - illegal: /\n/, - contains: [hljs.inherit(hljs.TITLE_MODE, { - starts: { - endsWithParent: true, - excludeEnd: true - } // hack: eating everything after the first title - })] - }, - { - className: 'class', - beginKeywords: 'interface', - end: /\{/, - illegal: /\n/, - contains: [hljs.inherit(hljs.TITLE_MODE, { - starts: { - endsWithParent: true, - excludeEnd: true - } // hack: eating everything after the first title - })] - } + CLASS_DEFINITION ] }; } diff --git a/src/languages/clojure.js b/src/languages/clojure.js index c34d0527a6..a5565e0680 100644 --- a/src/languages/clojure.js +++ b/src/languages/clojure.js @@ -8,8 +8,8 @@ Category: lisp /** @type LanguageFn */ export default function(hljs) { - const SYMBOLSTART = 'a-zA-Z_\\-!.?+*=<>&#\''; - const SYMBOL_RE = '[' + SYMBOLSTART + '][' + SYMBOLSTART + '0-9/;:]*'; + const SYMBOLSTART = 'a-zA-Z_\\-!.?+*=<>&\''; + const SYMBOL_RE = '[#]?[' + SYMBOLSTART + '][' + SYMBOLSTART + '0-9/;:$#]*'; const globals = 'def defonce defprotocol defstruct defmulti defmethod defn- defn defmacro deftype defrecord'; const keywords = { $pattern: SYMBOL_RE, @@ -45,20 +45,45 @@ export default function(hljs) { 'lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize' }; - const SIMPLE_NUMBER_RE = '[-+]?\\d+(\\.\\d+)?'; - const SYMBOL = { begin: SYMBOL_RE, relevance: 0 }; const NUMBER = { - className: 'number', - begin: SIMPLE_NUMBER_RE, - relevance: 0 + scope: 'number', + relevance: 0, + variants: [ + {match: /[-+]?0[xX][0-9a-fA-F]+N?/}, // hexadecimal // 0x2a + {match: /[-+]?0[0-7]+N?/}, // octal // 052 + {match: /[-+]?[1-9][0-9]?[rR][0-9a-zA-Z]+N?/}, // variable radix from 2 to 36 // 2r101010, 8r52, 36r16 + {match: /[-+]?[0-9]+\/[0-9]+N?/}, // ratio // 1/2 + {match: /[-+]?[0-9]+((\.[0-9]*([eE][+-]?[0-9]+)?M?)|([eE][+-]?[0-9]+M?|M))/}, // float // 0.42 4.2E-1M 42E1 42M + {match: /[-+]?([1-9][0-9]*|0)N?/}, // int (don't match leading 0) // 42 42N + ] }; + const CHARACTER = { + scope: 'character', + variants: [ + {match: /\\o[0-3]?[0-7]{1,2}/}, // Unicode Octal 0 - 377 + {match: /\\u[0-9a-fA-F]{4}/}, // Unicode Hex 0000 - FFFF + {match: /\\(newline|space|tab|formfeed|backspace|return)/}, // special characters + {match: /\\\S/, relevance: 0} // any non-whitespace char + ] + } + const REGEX = { + scope: 'regex', + begin: /#"/, + end: /"/, + contains: [hljs.BACKSLASH_ESCAPE] + } const STRING = hljs.inherit(hljs.QUOTE_STRING_MODE, { illegal: null }); + const COMMA = { + scope: 'punctuation', + match: /,/, + relevance: 0 + } const COMMENT = hljs.COMMENT( ';', '$', @@ -71,15 +96,10 @@ export default function(hljs) { begin: /\b(true|false|nil)\b/ }; const COLLECTION = { - begin: '[\\[\\{]', + begin: "\\[|(#::?" + SYMBOL_RE + ")?\\{", end: '[\\]\\}]', relevance: 0 }; - const HINT = { - className: 'comment', - begin: '\\^' + SYMBOL_RE - }; - const HINT_COL = hljs.COMMENT('\\^\\{', '\\}'); const KEY = { className: 'symbol', begin: '[:]{1,2}' + SYMBOL_RE @@ -100,10 +120,11 @@ export default function(hljs) { starts: BODY }; const DEFAULT_CONTAINS = [ + COMMA, LIST, + CHARACTER, + REGEX, STRING, - HINT, - HINT_COL, COMMENT, KEY, COLLECTION, @@ -132,24 +153,23 @@ export default function(hljs) { }; LIST.contains = [ - hljs.COMMENT('comment', ''), GLOBAL, NAME, BODY ]; BODY.contains = DEFAULT_CONTAINS; COLLECTION.contains = DEFAULT_CONTAINS; - HINT_COL.contains = [ COLLECTION ]; return { name: 'Clojure', aliases: [ 'clj', 'edn' ], illegal: /\S/, contains: [ + COMMA, LIST, + CHARACTER, + REGEX, STRING, - HINT, - HINT_COL, COMMENT, KEY, COLLECTION, diff --git a/src/languages/coffeescript.js b/src/languages/coffeescript.js index fd333c4c2b..51bf00cd05 100644 --- a/src/languages/coffeescript.js +++ b/src/languages/coffeescript.js @@ -155,6 +155,30 @@ export default function(hljs) { }] }; + const CLASS_DEFINITION = { + variants: [ + { + match: [ + /class\s+/, + JS_IDENT_RE, + /\s+extends\s+/, + JS_IDENT_RE + ] + }, + { + match: [ + /class\s+/, + JS_IDENT_RE + ] + } + ], + scope: { + 2: "title.class", + 4: "title.class.inherited" + }, + keywords: KEYWORDS + }; + return { name: 'CoffeeScript', aliases: [ @@ -190,21 +214,7 @@ export default function(hljs) { contains: [PARAMS] }] }, - { - className: 'class', - beginKeywords: 'class', - end: '$', - illegal: /[:="\[\]]/, - contains: [ - { - beginKeywords: 'extends', - endsWithParent: true, - illegal: /[:="\[\]]/, - contains: [TITLE] - }, - TITLE - ] - }, + CLASS_DEFINITION, { begin: JS_IDENT_RE + ':', end: ':', diff --git a/src/languages/cpp.js b/src/languages/cpp.js index e2cf5a9d28..54e3bced7d 100644 --- a/src/languages/cpp.js +++ b/src/languages/cpp.js @@ -558,7 +558,7 @@ export default function(hljs) { [ PREPROCESSOR, { // containers: ie, `vector rooms (9);` - begin: '\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function)\\s*<', + begin: '\\b(deque|list|queue|priority_queue|pair|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array|tuple|optional|variant|function)\\s*<(?!<)', end: '>', keywords: CPP_KEYWORDS, contains: [ diff --git a/src/languages/elixir.js b/src/languages/elixir.js index c43101ad5e..c9b08a9570 100644 --- a/src/languages/elixir.js +++ b/src/languages/elixir.js @@ -262,10 +262,8 @@ export default function(hljs) { { className: 'variable', begin: '(\\$\\W)|((\\$|@@?)(\\w+))' - }, - { - begin: '->' } + // -> has been removed, capnproto always uses this grammar construct ]; SUBST.contains = ELIXIR_DEFAULT_CONTAINS; diff --git a/src/languages/fsharp.js b/src/languages/fsharp.js index 81f30539d3..f130d0c71f 100644 --- a/src/languages/fsharp.js +++ b/src/languages/fsharp.js @@ -119,7 +119,9 @@ export default function(hljs) { "__SOURCE_FILE__" ]; - const TYPES = [ + // Since it's possible to re-bind/shadow names (e.g. let char = 'c'), + // these builtin types should only be matched when a type name is expected. + const KNOWN_TYPES = [ // basic types "bool", "byte", @@ -157,7 +159,9 @@ export default function(hljs) { "nativeptr", "obj", "outref", - "voidptr" + "voidptr", + // other important FSharp types + "Result" ]; const BUILTINS = [ @@ -172,6 +176,7 @@ export default function(hljs) { "dict", "readOnlyDict", "set", + "get", "enum", "sizeof", "typeof", @@ -201,7 +206,6 @@ export default function(hljs) { ]; const ALL_KEYWORDS = { - type: TYPES, keyword: KEYWORDS, literal: LITERALS, built_in: BUILTINS, @@ -221,16 +225,138 @@ export default function(hljs) { ] }; - // 'a or ^a + // Most identifiers can contain apostrophes + const IDENTIFIER_RE = /[a-zA-Z_](\w|')*/; + + const QUOTED_IDENTIFIER = { + scope: 'variable', + begin: /``/, + end: /``/ + }; + + // 'a or ^a where a can be a ``quoted identifier`` + const BEGIN_GENERIC_TYPE_SYMBOL_RE = /\B('|\^)/ const GENERIC_TYPE_SYMBOL = { - match: regex.concat(/('|\^)/, hljs.UNDERSCORE_IDENT_RE), scope: 'symbol', + variants: [ + // the type name is a quoted identifier: + { match: regex.concat(BEGIN_GENERIC_TYPE_SYMBOL_RE, /``.*?``/) }, + // the type name is a normal identifier (we don't use IDENTIFIER_RE because there cannot be another apostrophe here): + { match: regex.concat(BEGIN_GENERIC_TYPE_SYMBOL_RE, hljs.UNDERSCORE_IDENT_RE) } + ], relevance: 0 }; + const makeOperatorMode = function({ includeEqual }) { + // List or symbolic operator characters from the FSharp Spec 4.1, minus the dot, and with `?` added, used for nullable operators. + let allOperatorChars; + if (includeEqual) + allOperatorChars = "!%&*+-/<=>@^|~?"; + else + allOperatorChars = "!%&*+-/<>@^|~?"; + const OPERATOR_CHARS = Array.from(allOperatorChars); + const OPERATOR_CHAR_RE = regex.concat('[', ...OPERATOR_CHARS.map(regex.escape), ']'); + // The lone dot operator is special. It cannot be redefined, and we don't want to highlight it. It can be used as part of a multi-chars operator though. + const OPERATOR_CHAR_OR_DOT_RE = regex.either(OPERATOR_CHAR_RE, /\./); + // When a dot is present, it must be followed by another operator char: + const OPERATOR_FIRST_CHAR_OF_MULTIPLE_RE = regex.concat(OPERATOR_CHAR_OR_DOT_RE, regex.lookahead(OPERATOR_CHAR_OR_DOT_RE)); + const SYMBOLIC_OPERATOR_RE = regex.either( + regex.concat(OPERATOR_FIRST_CHAR_OF_MULTIPLE_RE, OPERATOR_CHAR_OR_DOT_RE, '*'), // Matches at least 2 chars operators + regex.concat(OPERATOR_CHAR_RE, '+'), // Matches at least one char operators + ); + return { + scope: 'operator', + match: regex.either( + // symbolic operators: + SYMBOLIC_OPERATOR_RE, + // other symbolic keywords: + // Type casting and conversion operators: + /:\?>/, + /:\?/, + /:>/, + /:=/, // Reference cell assignment + /::?/, // : or :: + /\$/), // A single $ can be used as an operator + relevance: 0 + }; + } + + const OPERATOR = makeOperatorMode({ includeEqual: true }); + // This variant is used when matching '=' should end a parent mode: + const OPERATOR_WITHOUT_EQUAL = makeOperatorMode({ includeEqual: false }); + + const makeTypeAnnotationMode = function(prefix, prefixScope) { + return { + begin: regex.concat( // a type annotation is a + prefix, // should be a colon or the 'of' keyword + regex.lookahead( // that has to be followed by + regex.concat( + /\s*/, // optional space + regex.either( // then either of: + /\w/, // word + /'/, // generic type name + /\^/, // generic type name + /#/, // flexible type name + /``/, // quoted type name + /\(/, // parens type expression + /{\|/, // anonymous type annotation + )))), + beginScope: prefixScope, + // BUG: because ending with \n is necessary for some cases, multi-line type annotations are not properly supported. + // Examples where \n is required at the end: + // - abstract member definitions in classes: abstract Property : int * string + // - return type annotations: let f f' = f' () : returnTypeAnnotation + // - record fields definitions: { A : int \n B : string } + end: regex.lookahead( + regex.either( + /\n/, + /=/)), + relevance: 0, + // we need the known types, and we need the type constraint keywords and literals. e.g.: when 'a : null + keywords: hljs.inherit(ALL_KEYWORDS, { type: KNOWN_TYPES }), + contains: [ + COMMENT, + GENERIC_TYPE_SYMBOL, + hljs.inherit(QUOTED_IDENTIFIER, { scope: null }), // match to avoid strange patterns inside that may break the parsing + OPERATOR_WITHOUT_EQUAL + ] + }; + } + + const TYPE_ANNOTATION = makeTypeAnnotationMode(/:/, 'operator'); + const DISCRIMINATED_UNION_TYPE_ANNOTATION = makeTypeAnnotationMode(/\bof\b/, 'keyword'); + + // type MyType<'a> = ... + const TYPE_DECLARATION = { + begin: [ + /(^|\s+)/, // prevents matching the following: `match s.stype with` + /type/, + /\s+/, + IDENTIFIER_RE + ], + beginScope: { + 2: 'keyword', + 4: 'title.class' + }, + end: regex.lookahead(/\(|=|$/), + keywords: ALL_KEYWORDS, // match keywords in type constraints. e.g.: when 'a : null + contains: [ + COMMENT, + hljs.inherit(QUOTED_IDENTIFIER, { scope: null }), // match to avoid strange patterns inside that may break the parsing + GENERIC_TYPE_SYMBOL, + { + // For visual consistency, highlight type brackets as operators. + scope: 'operator', + match: /<|>/ + }, + TYPE_ANNOTATION // generic types can have constraints, which are type annotations. e.g. type MyType<'T when 'T : delegate> = + ] + }; + const COMPUTATION_EXPRESSION = { // computation expressions: scope: 'computation-expression', + // BUG: might conflict with record deconstruction. e.g. let f { Name = name } = name // will highlight f match: /\b[_a-z]\w*(?=\s*\{)/ }; @@ -365,10 +491,13 @@ export default function(hljs) { CHAR_LITERAL, BANG_KEYWORD_MODE, COMMENT, + QUOTED_IDENTIFIER, + TYPE_ANNOTATION, COMPUTATION_EXPRESSION, PREPROCESSOR, NUMBER, - GENERIC_TYPE_SYMBOL + GENERIC_TYPE_SYMBOL, + OPERATOR ]; const STRING = { variants: [ @@ -397,42 +526,32 @@ export default function(hljs) { BANG_KEYWORD_MODE, STRING, COMMENT, + QUOTED_IDENTIFIER, + TYPE_DECLARATION, { - // type MyType<'a> = ... - begin: [ - /type/, - /\s+/, - hljs.UNDERSCORE_IDENT_RE - ], - beginScope: { - 1: 'keyword', - 3: 'title.class' - }, - end: regex.lookahead(/\(|=|$/), - contains: [ - GENERIC_TYPE_SYMBOL - ] - }, - { - // [] + // e.g. [] or [<``module``: MyCustomAttributeThatWorksOnModules>] + // or [] scope: 'meta', - begin: /^\s*\[\]/), + begin: /\[\]/, relevance: 2, contains: [ - { - scope: 'string', - begin: /"/, - end: /"/ - }, + QUOTED_IDENTIFIER, + // can contain any constant value + TRIPLE_QUOTED_STRING, + VERBATIM_STRING, + QUOTED_STRING, + CHAR_LITERAL, NUMBER ] }, + DISCRIMINATED_UNION_TYPE_ANNOTATION, + TYPE_ANNOTATION, COMPUTATION_EXPRESSION, PREPROCESSOR, NUMBER, - GENERIC_TYPE_SYMBOL + GENERIC_TYPE_SYMBOL, + OPERATOR ] }; } diff --git a/src/languages/groovy.js b/src/languages/groovy.js index 99aefed333..04e3d3f4ed 100644 --- a/src/languages/groovy.js +++ b/src/languages/groovy.js @@ -66,19 +66,78 @@ export default function(hljs) { } ); + const CLASS_DEFINITION = { + match: [ + /(class|interface|trait|enum|extends|implements)/, + /\s+/, + hljs.UNDERSCORE_IDENT_RE + ], + scope: { + 1: "keyword", + 3: "title.class", + } + }; + const TYPES = [ + "byte", + "short", + "char", + "int", + "long", + "boolean", + "float", + "double", + "void" + ]; + const KEYWORDS = [ + // groovy specific keywords + "def", + "as", + "in", + "assert", + "trait", + // common keywords with Java + "abstract", + "static", + "volatile", + "transient", + "public", + "private", + "protected", + "synchronized", + "final", + "class", + "interface", + "enum", + "if", + "else", + "for", + "while", + "switch", + "case", + "break", + "default", + "continue", + "throw", + "throws", + "try", + "catch", + "finally", + "implements", + "extends", + "new", + "import", + "package", + "return", + "instanceof" + ]; + return { name: 'Groovy', keywords: { - built_in: 'this super', + "variable.language": 'this super', literal: 'true false null', - keyword: - 'byte short char int long boolean float double void ' + - // groovy specific keywords - 'def as in assert trait ' + - // common keywords with Java - 'abstract static volatile transient public private protected synchronized final ' + - 'class interface enum if else for while switch case break default continue ' + - 'throw throws try catch finally implements extends new import package return instanceof' + type: TYPES, + keyword: KEYWORDS }, contains: [ hljs.SHEBANG({ @@ -89,18 +148,7 @@ export default function(hljs) { STRING, REGEXP, NUMBER, - { - className: 'class', - beginKeywords: 'class interface trait enum', - end: /\{/, - illegal: ':', - contains: [ - { - beginKeywords: 'extends implements' - }, - hljs.UNDERSCORE_TITLE_MODE - ] - }, + CLASS_DEFINITION, { className: 'meta', begin: '@[A-Za-z]+', diff --git a/src/languages/java.js b/src/languages/java.js index 17e73e66ea..8c55aae215 100644 --- a/src/languages/java.js +++ b/src/languages/java.js @@ -73,7 +73,8 @@ export default function(hljs) { 'module', 'requires', 'exports', - 'do' + 'do', + 'sealed' ]; const BUILT_INS = [ @@ -179,6 +180,11 @@ export default function(hljs) { 3: "title.class" } }, + { + // Exceptions for hyphenated keywords + match: /non-sealed/, + scope: "keyword" + }, { begin: [ JAVA_IDENT_RE, diff --git a/src/languages/javascript.js b/src/languages/javascript.js index b09065dd85..e3ec15a04c 100644 --- a/src/languages/javascript.js +++ b/src/languages/javascript.js @@ -290,10 +290,14 @@ export default function(hljs) { regex.either( // Hard coded exceptions /\bJSON/, - // Float32Array - /\b[A-Z][a-z]+([A-Z][a-z]+|\d)*/, - // CSSFactory - /\b[A-Z]{2,}([A-Z][a-z]+|\d)+/, + // Float32Array, OutT + /\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/, + // CSSFactory, CSSFactoryT + /\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/, + // FPs, FPsT + /\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/, + // P + // single letters are not highlighted // BLAH // this will be flagged as a UPPER_CASE_CONSTANT instead ), @@ -406,8 +410,10 @@ export default function(hljs) { /const|var|let/, /\s+/, IDENT_RE, /\s*/, /=\s*/, + /(async\s*)?/, // async is optional regex.lookahead(FUNC_LEAD_IN_RE) ], + keywords: "async", className: { 1: "keyword", 3: "title.function" diff --git a/src/languages/julia-repl.js b/src/languages/julia-repl.js index 6772b86641..8094c4fa9f 100644 --- a/src/languages/julia-repl.js +++ b/src/languages/julia-repl.js @@ -35,14 +35,14 @@ export default function(hljs) { // least six spaces in the beginning end: /^(?![ ]{6})/, subLanguage: 'julia' + }, }, - // jldoctest Markdown blocks are used in the Julia manual and package docs indicate - // code snippets that should be verified when the documentation is built. They can be - // either REPL-like or script-like, but are usually REPL-like and therefore we apply - // julia-repl highlighting to them. More information can be found in Documenter's - // manual: https://juliadocs.github.io/Documenter.jl/latest/man/doctests.html - aliases: ['jldoctest'] - } - ] + ], + // jldoctest Markdown blocks are used in the Julia manual and package docs indicate + // code snippets that should be verified when the documentation is built. They can be + // either REPL-like or script-like, but are usually REPL-like and therefore we apply + // julia-repl highlighting to them. More information can be found in Documenter's + // manual: https://juliadocs.github.io/Documenter.jl/latest/man/doctests.html + aliases: ['jldoctest'], } } diff --git a/src/languages/lib/kws_swift.js b/src/languages/lib/kws_swift.js index d54e6ed3a7..be06394ba8 100644 --- a/src/languages/lib/kws_swift.js +++ b/src/languages/lib/kws_swift.js @@ -141,7 +141,7 @@ export const precedencegroupKeywords = [ ]; // Keywords that start with a number sign (#). -// #available is handled separately. +// #(un)available is handled separately. export const numberSignKeywords = [ '#colorLiteral', '#column', @@ -307,7 +307,7 @@ export const keywordAttributes = [ 'usableFromInline' ]; -// Contextual keywords used in @available and #available. +// Contextual keywords used in @available and #(un)available. export const availabilityKeywords = [ 'iOS', 'iOSApplicationExtension', diff --git a/src/languages/livescript.js b/src/languages/livescript.js index 21efa6f576..f55e004731 100644 --- a/src/languages/livescript.js +++ b/src/languages/livescript.js @@ -176,6 +176,30 @@ export default function(hljs) { begin: '(#=>|=>|\\|>>|-?->|!->)' }; + const CLASS_DEFINITION = { + variants: [ + { + match: [ + /class\s+/, + JS_IDENT_RE, + /\s+extends\s+/, + JS_IDENT_RE + ] + }, + { + match: [ + /class\s+/, + JS_IDENT_RE + ] + } + ], + scope: { + 2: "title.class", + 4: "title.class.inherited" + }, + keywords: KEYWORDS + }; + return { name: 'LiveScript', aliases: ['ls'], @@ -207,21 +231,7 @@ export default function(hljs) { } ] }, - { - className: 'class', - beginKeywords: 'class', - end: '$', - illegal: /[:="\[\]]/, - contains: [ - { - beginKeywords: 'extends', - endsWithParent: true, - illegal: /[:="\[\]]/, - contains: [TITLE] - }, - TITLE - ] - }, + CLASS_DEFINITION, { begin: JS_IDENT_RE + ':', end: ':', diff --git a/src/languages/matlab.js b/src/languages/matlab.js index 06f99fe23e..684b0c5188 100644 --- a/src/languages/matlab.js +++ b/src/languages/matlab.js @@ -80,7 +80,6 @@ export default function(hljs) { className: 'string', begin: '\'', end: '\'', contains: [ - hljs.BACKSLASH_ESCAPE, {begin: '\'\''}] }, { @@ -92,7 +91,6 @@ export default function(hljs) { className: 'string', begin: '"', end: '"', contains: [ - hljs.BACKSLASH_ESCAPE, {begin: '""'} ], starts: TRANSPOSE diff --git a/src/languages/monkey.js b/src/languages/monkey.js index 915fa20c98..2d64a442af 100644 --- a/src/languages/monkey.js +++ b/src/languages/monkey.js @@ -16,20 +16,137 @@ export default function(hljs) { hljs.NUMBER_MODE ] }; + const FUNC_DEFINITION = { + variants: [ + { + match: [ + /(function|method)/, + /\s+/, + hljs.UNDERSCORE_IDENT_RE, + ] + }, + ], + scope: { + 1: "keyword", + 3: "title.function" + } + }; + const CLASS_DEFINITION = { + variants: [ + { + match: [ + /(class|interface|extends|implements)/, + /\s+/, + hljs.UNDERSCORE_IDENT_RE, + ] + }, + ], + scope: { + 1: "keyword", + 3: "title.class" + } + }; + const BUILT_INS = [ + "DebugLog", + "DebugStop", + "Error", + "Print", + "ACos", + "ACosr", + "ASin", + "ASinr", + "ATan", + "ATan2", + "ATan2r", + "ATanr", + "Abs", + "Abs", + "Ceil", + "Clamp", + "Clamp", + "Cos", + "Cosr", + "Exp", + "Floor", + "Log", + "Max", + "Max", + "Min", + "Min", + "Pow", + "Sgn", + "Sgn", + "Sin", + "Sinr", + "Sqrt", + "Tan", + "Tanr", + "Seed", + "PI", + "HALFPI", + "TWOPI" + ]; + const LITERALS = [ + "true", + "false", + "null" + ]; + const KEYWORDS = [ + "public", + "private", + "property", + "continue", + "exit", + "extern", + "new", + "try", + "catch", + "eachin", + "not", + "abstract", + "final", + "select", + "case", + "default", + "const", + "local", + "global", + "field", + "end", + "if", + "then", + "else", + "elseif", + "endif", + "while", + "wend", + "repeat", + "until", + "forever", + "for", + "to", + "step", + "next", + "return", + "module", + "inline", + "throw", + "import", + // not positive, but these are not literals + "and", + "or", + "shl", + "shr", + "mod" + ]; return { name: 'Monkey', case_insensitive: true, keywords: { - keyword: 'public private property continue exit extern new try catch ' + - 'eachin not abstract final select case default const local global field ' + - 'end if then else elseif endif while wend repeat until forever for ' + - 'to step next return module inline throw import', - - built_in: 'DebugLog DebugStop Error Print ACos ACosr ASin ASinr ATan ATan2 ATan2r ATanr Abs Abs Ceil ' + - 'Clamp Clamp Cos Cosr Exp Floor Log Max Max Min Min Pow Sgn Sgn Sin Sinr Sqrt Tan Tanr Seed PI HALFPI TWOPI', - - literal: 'true false null and or shl shr mod' + keyword: KEYWORDS, + built_in: BUILT_INS, + literal: LITERALS }, illegal: /\/\*/, contains: [ @@ -41,39 +158,26 @@ export default function(hljs) { relevance: 0 } ), + FUNC_DEFINITION, + CLASS_DEFINITION, { - className: 'function', - beginKeywords: 'function method', - end: '[(=:]|$', - illegal: /\n/, - contains: [ hljs.UNDERSCORE_TITLE_MODE ] - }, - { - className: 'class', - beginKeywords: 'class interface', - end: '$', - contains: [ - { - beginKeywords: 'extends implements' - }, - hljs.UNDERSCORE_TITLE_MODE - ] - }, - { - className: 'built_in', - begin: '\\b(self|super)\\b' + className: 'variable.language', + begin: /\b(self|super)\b/ }, { className: 'meta', - begin: '\\s*#', + begin: /\s*#/, end: '$', keywords: { keyword: 'if else elseif endif end then' } }, { - className: 'meta', - begin: '^\\s*strict\\b' + match: [ + /^\s*/, + /strict\b/ + ], + scope: { 2: "meta" } }, { beginKeywords: 'alias', diff --git a/src/languages/nsis.js b/src/languages/nsis.js index fa3b2e547f..17438c682d 100644 --- a/src/languages/nsis.js +++ b/src/languages/nsis.js @@ -8,6 +8,7 @@ Website: https://nsis.sourceforge.io/Main_Page import * as regex from '../lib/regex.js'; export default function(hljs) { + const regex = hljs.regex; const LANGUAGE_CONSTANTS = [ "ADMINTOOLS", "APPDATA", @@ -153,20 +154,20 @@ export default function(hljs) { const DEFINES = { // ${defines} className: 'variable', - begin: /\$+\{[\w.:-]+\}/ + begin: /\$+\{[\!\w.:-]+\}/ }; const VARIABLES = { // $variables className: 'variable', - begin: /\$+\w+/, + begin: /\$+\w[\w\.]*/, illegal: /\(\)\{\}/ }; const LANGUAGES = { // $(language_strings) className: 'variable', - begin: /\$+\([\w^.:-]+\)/ + begin: /\$+\([\w^.:!-]+\)/ }; const PARAMETERS = { @@ -184,9 +185,9 @@ export default function(hljs) { ) }; - const METACHARS = { + const ESCAPE_CHARS = { // $\n, $\r, $\t, $$ - className: 'meta', + className: 'char.escape', begin: /\$(\\[nrt]|\$)/ }; @@ -214,7 +215,7 @@ export default function(hljs) { ], illegal: /\n/, contains: [ - METACHARS, + ESCAPE_CHARS, CONSTANTS, DEFINES, VARIABLES, @@ -493,7 +494,7 @@ export default function(hljs) { "zlib" ]; - const FUNCTION_DEF = { + const FUNCTION_DEFINITION = { match: [ /Function/, /\s+/, @@ -505,6 +506,23 @@ export default function(hljs) { } }; + // Var Custom.Variable.Name.Item + // Var /GLOBAL Custom.Variable.Name.Item + const VARIABLE_NAME_RE = /[A-Za-z][\w.]*/; + const VARIABLE_DEFINITION = { + match: [ + /Var/, + /\s+/, + /(?:\/GLOBAL\s+)?/, + VARIABLE_NAME_RE + ], + scope: { + 1: "keyword", + 3: "params", + 4: "variable" + } + }; + return { name: 'NSIS', case_insensitive: true, @@ -522,7 +540,8 @@ export default function(hljs) { relevance: 0 } ), - FUNCTION_DEF, + VARIABLE_DEFINITION, + FUNCTION_DEFINITION, { beginKeywords: 'Function PageEx Section SectionGroup FunctionEnd SectionEnd', }, diff --git a/src/languages/oxygene.js b/src/languages/oxygene.js index 6eaef0d295..77c919e585 100644 --- a/src/languages/oxygene.js +++ b/src/languages/oxygene.js @@ -47,12 +47,11 @@ export default function(hljs) { begin: '(#\\d+)+' }; const FUNCTION = { - className: 'function', beginKeywords: 'function constructor destructor procedure method', end: '[:;]', keywords: 'function constructor|10 destructor|10 procedure|10 method|10', contains: [ - hljs.TITLE_MODE, + hljs.inherit(hljs.TITLE_MODE, {scope: "title.function" }), { className: 'params', begin: '\\(', @@ -67,6 +66,13 @@ export default function(hljs) { PAREN_COMMENT ] }; + + const SEMICOLON = { + scope: "punctuation", + match: /;/, + relevance: 0 + }; + return { name: 'Oxygene', case_insensitive: true, @@ -80,20 +86,7 @@ export default function(hljs) { CHAR_STRING, hljs.NUMBER_MODE, FUNCTION, - { - className: 'class', - begin: '=\\bclass\\b', - end: 'end;', - keywords: OXYGENE_KEYWORDS, - contains: [ - STRING, - CHAR_STRING, - CURLY_COMMENT, - PAREN_COMMENT, - hljs.C_LINE_COMMENT_MODE, - FUNCTION - ] - } + SEMICOLON ] }; } diff --git a/src/languages/php.js b/src/languages/php.js index ce0af400a8..7f0be203ae 100644 --- a/src/languages/php.js +++ b/src/languages/php.js @@ -11,15 +11,20 @@ Category: common * @returns {LanguageDetail} * */ export default function(hljs) { + const regex = hljs.regex; + const IDENT_RE_CORE = '[a-zA-Z0-9_\x7f-\xff]*' + + // negative look-ahead tries to avoid matching patterns that are not + // Perl at all like $ident$, @ident@, etc. + '(?![A-Za-z0-9])(?![$]))'; + const IDENT_RE = regex.concat("([a-zA-Z_\\x7f-\\xff]", IDENT_RE_CORE); + // Will not detect camelCase classes + const PASCAL_CASE_CLASS_NAME_RE = regex.concat("([A-Z]", IDENT_RE_CORE); const VARIABLE = { - className: 'variable', - begin: '\\$+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*' + - // negative look-ahead tries to avoid matching patterns that are not - // Perl at all like $ident$, @ident@, etc. - `(?![A-Za-z0-9])(?![$])` + scope: 'variable', + match: '\\$+' + IDENT_RE, }; const PREPROCESSOR = { - className: 'meta', + scope: 'meta', variants: [ { begin: /<\?php/, relevance: 10 }, // boost for obvious PHP { begin: /<\?[=]?/ }, @@ -27,7 +32,7 @@ export default function(hljs) { ] }; const SUBST = { - className: 'subst', + scope: 'subst', variants: [ { begin: /\$\w+/ }, { begin: /\{\$/, end: /\}/ } @@ -45,100 +50,406 @@ export default function(hljs) { end: /[ \t]*(\w+)\b/, contains: hljs.QUOTE_STRING_MODE.contains.concat(SUBST), }); + // list of valid whitespaces because non-breaking space might be part of a IDENT_RE + const WHITESPACE = '[ \t\n]'; const STRING = { - className: 'string', - contains: [hljs.BACKSLASH_ESCAPE, PREPROCESSOR], + scope: 'string', variants: [ - hljs.inherit(SINGLE_QUOTED, { - begin: "b'", end: "'", - }), - hljs.inherit(DOUBLE_QUOTED, { - begin: 'b"', end: '"', - }), DOUBLE_QUOTED, SINGLE_QUOTED, HEREDOC ] }; const NUMBER = { - className: 'number', + scope: 'number', variants: [ - { begin: `\\b0b[01]+(?:_[01]+)*\\b` }, // Binary w/ underscore support - { begin: `\\b0o[0-7]+(?:_[0-7]+)*\\b` }, // Octals w/ underscore support - { begin: `\\b0x[\\da-f]+(?:_[\\da-f]+)*\\b` }, // Hex w/ underscore support + { begin: `\\b0[bB][01]+(?:_[01]+)*\\b` }, // Binary w/ underscore support + { begin: `\\b0[oO][0-7]+(?:_[0-7]+)*\\b` }, // Octals w/ underscore support + { begin: `\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b` }, // Hex w/ underscore support // Decimals w/ underscore support, with optional fragments and scientific exponent (e) suffix. - { begin: `(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:e[+-]?\\d+)?` } + { begin: `(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?` } ], relevance: 0 }; - const KEYWORDS = { - keyword: + const LITERALS = [ + "false", + "null", + "true" + ]; + const KWS = [ // Magic constants: // - '__CLASS__ __DIR__ __FILE__ __FUNCTION__ __LINE__ __METHOD__ __NAMESPACE__ __TRAIT__ ' + + "__CLASS__", + "__DIR__", + "__FILE__", + "__FUNCTION__", + "__COMPILER_HALT_OFFSET__", + "__LINE__", + "__METHOD__", + "__NAMESPACE__", + "__TRAIT__", // Function that look like language construct or language construct that look like function: // List of keywords that may not require parenthesis - 'die echo exit include include_once print require require_once ' + + "die", + "echo", + "exit", + "include", + "include_once", + "print", + "require", + "require_once", // These are not language construct (function) but operate on the currently-executing function and can access the current symbol table // 'compact extract func_get_arg func_get_args func_num_args get_called_class get_parent_class ' + // Other keywords: // // - 'array abstract and as binary bool boolean break callable case catch class clone const continue declare ' + - 'default do double else elseif empty enddeclare endfor endforeach endif endswitch endwhile enum eval extends ' + - 'final finally float for foreach from global goto if implements instanceof insteadof int integer interface ' + - 'isset iterable list match|0 mixed new object or private protected public real return string switch throw trait ' + - 'try unset use var void while xor yield', - literal: 'false null true', - built_in: + "array", + "abstract", + "and", + "as", + "binary", + "bool", + "boolean", + "break", + "callable", + "case", + "catch", + "class", + "clone", + "const", + "continue", + "declare", + "default", + "do", + "double", + "else", + "elseif", + "empty", + "enddeclare", + "endfor", + "endforeach", + "endif", + "endswitch", + "endwhile", + "enum", + "eval", + "extends", + "final", + "finally", + "float", + "for", + "foreach", + "from", + "global", + "goto", + "if", + "implements", + "instanceof", + "insteadof", + "int", + "integer", + "interface", + "isset", + "iterable", + "list", + "match|0", + "mixed", + "new", + "never", + "object", + "or", + "private", + "protected", + "public", + "readonly", + "real", + "return", + "string", + "switch", + "throw", + "trait", + "try", + "unset", + "use", + "var", + "void", + "while", + "xor", + "yield" + ]; + + const BUILT_INS = [ // Standard PHP library: // - 'Error|0 ' + // error is too common a name esp since PHP is case in-sensitive - 'AppendIterator ArgumentCountError ArithmeticError ArrayIterator ArrayObject AssertionError BadFunctionCallException BadMethodCallException CachingIterator CallbackFilterIterator CompileError Countable DirectoryIterator DivisionByZeroError DomainException EmptyIterator ErrorException Exception FilesystemIterator FilterIterator GlobIterator InfiniteIterator InvalidArgumentException IteratorIterator LengthException LimitIterator LogicException MultipleIterator NoRewindIterator OutOfBoundsException OutOfRangeException OuterIterator OverflowException ParentIterator ParseError RangeException RecursiveArrayIterator RecursiveCachingIterator RecursiveCallbackFilterIterator RecursiveDirectoryIterator RecursiveFilterIterator RecursiveIterator RecursiveIteratorIterator RecursiveRegexIterator RecursiveTreeIterator RegexIterator RuntimeException SeekableIterator SplDoublyLinkedList SplFileInfo SplFileObject SplFixedArray SplHeap SplMaxHeap SplMinHeap SplObjectStorage SplObserver SplObserver SplPriorityQueue SplQueue SplStack SplSubject SplSubject SplTempFileObject TypeError UnderflowException UnexpectedValueException UnhandledMatchError ' + + "Error|0", + "AppendIterator", + "ArgumentCountError", + "ArithmeticError", + "ArrayIterator", + "ArrayObject", + "AssertionError", + "BadFunctionCallException", + "BadMethodCallException", + "CachingIterator", + "CallbackFilterIterator", + "CompileError", + "Countable", + "DirectoryIterator", + "DivisionByZeroError", + "DomainException", + "EmptyIterator", + "ErrorException", + "Exception", + "FilesystemIterator", + "FilterIterator", + "GlobIterator", + "InfiniteIterator", + "InvalidArgumentException", + "IteratorIterator", + "LengthException", + "LimitIterator", + "LogicException", + "MultipleIterator", + "NoRewindIterator", + "OutOfBoundsException", + "OutOfRangeException", + "OuterIterator", + "OverflowException", + "ParentIterator", + "ParseError", + "RangeException", + "RecursiveArrayIterator", + "RecursiveCachingIterator", + "RecursiveCallbackFilterIterator", + "RecursiveDirectoryIterator", + "RecursiveFilterIterator", + "RecursiveIterator", + "RecursiveIteratorIterator", + "RecursiveRegexIterator", + "RecursiveTreeIterator", + "RegexIterator", + "RuntimeException", + "SeekableIterator", + "SplDoublyLinkedList", + "SplFileInfo", + "SplFileObject", + "SplFixedArray", + "SplHeap", + "SplMaxHeap", + "SplMinHeap", + "SplObjectStorage", + "SplObserver", + "SplPriorityQueue", + "SplQueue", + "SplStack", + "SplSubject", + "SplTempFileObject", + "TypeError", + "UnderflowException", + "UnexpectedValueException", + "UnhandledMatchError", // Reserved interfaces: // - 'ArrayAccess Closure Generator Iterator IteratorAggregate Serializable Stringable Throwable Traversable WeakReference WeakMap ' + + "ArrayAccess", + "BackedEnum", + "Closure", + "Fiber", + "Generator", + "Iterator", + "IteratorAggregate", + "Serializable", + "Stringable", + "Throwable", + "Traversable", + "UnitEnum", + "WeakReference", + "WeakMap", // Reserved classes: // - 'Directory __PHP_Incomplete_Class parent php_user_filter self static stdClass' + "Directory", + "__PHP_Incomplete_Class", + "parent", + "php_user_filter", + "self", + "static", + "stdClass" + ]; + + /** Dual-case keywords + * + * ["then","FILE"] => + * ["then", "THEN", "FILE", "file"] + * + * @param {string[]} items */ + const dualCase = (items) => { + /** @type string[] */ + const result = []; + items.forEach(item => { + result.push(item); + if (item.toLowerCase() === item) { + result.push(item.toUpperCase()); + } else { + result.push(item.toLowerCase()); + } + }); + return result; + }; + + const KEYWORDS = { + keyword: KWS, + literal: dualCase(LITERALS), + built_in: BUILT_INS, + }; + + /** + * @param {string[]} items */ + const normalizeKeywords = (items) => { + return items.map(item => { + return item.replace(/\|\d+$/, ""); + }); + }; + + const CONSTRUCTOR_CALL = { + variants: [ + { + match: [ + /new/, + regex.concat(WHITESPACE, "+"), + // to prevent built ins from being confused as the class constructor call + regex.concat("(?!", normalizeKeywords(BUILT_INS).join("\\b|"), "\\b)"), + regex.concat(/\\?/, IDENT_RE), + regex.concat(WHITESPACE, "*", /\(/), + ], + scope: { + 1: "keyword", + 4: "title.class", + }, + } + ] + }; + + const FUNCTION_INVOKE = { + relevance: 0, + match: [ + /\b/, + // to prevent keywords from being confused as the function title + regex.concat("(?!fn\\b|function\\b|", normalizeKeywords(KWS).join("\\b|"), "|", normalizeKeywords(BUILT_INS).join("\\b|"), "\\b)"), + IDENT_RE, + regex.concat(WHITESPACE, "*"), + regex.lookahead(/(?=\()/) + ], + scope: { + 3: "title.function.invoke", + } }; + + const CONSTANT_REFERENCE = regex.concat(IDENT_RE, "\\b(?!\\()"); + + const LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON = { + variants: [ + { + match: [ + regex.concat( + /::/, + regex.lookahead(/(?!class\b)/) + ), + CONSTANT_REFERENCE, + ], + scope: { + 2: "variable.constant", + }, + }, + { + match: [ + /::/, + /class/, + ], + scope: { + 2: "variable.language", + }, + }, + { + match: [ + PASCAL_CASE_CLASS_NAME_RE, + regex.concat( + "::", + regex.lookahead(/(?!class\b)/) + ), + ], + scope: { + 1: "title.class", + }, + }, + { + match: [ + PASCAL_CASE_CLASS_NAME_RE, + /::/, + /class/, + ], + scope: { + 1: "title.class", + 3: "variable.language", + }, + } + ] + }; + return { - case_insensitive: true, + case_insensitive: false, keywords: KEYWORDS, contains: [ hljs.HASH_COMMENT_MODE, - hljs.COMMENT('//', '$', {contains: [PREPROCESSOR]}), + hljs.COMMENT('//', '$'), hljs.COMMENT( '/\\*', '\\*/', { contains: [ { - className: 'doctag', - begin: '@[A-Za-z]+' + scope: 'doctag', + match: '@[A-Za-z]+' } ] } ), - hljs.COMMENT( - '__halt_compiler.+?;', - false, - { - endsWithParent: true, - keywords: '__halt_compiler' + { + match: /__halt_compiler\(\);/, + keywords: '__halt_compiler', + starts: { + scope: "comment", + end: hljs.MATCH_NOTHING_RE, + contains: [ + { + match: /\?>/, + scope: "meta", + endsParent: true + } + ] } - ), + }, PREPROCESSOR, { - className: 'keyword', begin: /\$this\b/ + scope: 'variable.language', + match: /\$this\b/ }, VARIABLE, + FUNCTION_INVOKE, + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, { - // swallow composed identifiers to avoid parsing them as keywords - begin: /(::|->)+[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/ + match: [ + /const/, + /\s/, + IDENT_RE, + /\s*=/, + ], + scope: { + 1: "keyword", + 3: "variable.constant", + }, }, + CONSTRUCTOR_CALL, { - className: 'function', + scope: 'function', relevance: 0, beginKeywords: 'fn function', end: /[;{]/, excludeEnd: true, illegal: '[$%\\[]', @@ -152,7 +463,7 @@ export default function(hljs) { endsParent: true }, { - className: 'params', + scope: 'params', begin: '\\(', end: '\\)', excludeBegin: true, excludeEnd: true, @@ -160,6 +471,7 @@ export default function(hljs) { contains: [ 'self', VARIABLE, + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, hljs.C_BLOCK_COMMENT_MODE, STRING, NUMBER @@ -168,7 +480,7 @@ export default function(hljs) { ] }, { - className: 'class', + scope: 'class', variants: [ { beginKeywords: "enum", illegal: /[($"]/ }, { beginKeywords: "class interface trait", illegal: /[:($"]/ } @@ -181,18 +493,31 @@ export default function(hljs) { hljs.UNDERSCORE_TITLE_MODE ] }, + // both use and namespace still use "old style" rules (vs multi-match) + // because the namespace name can include `\` and we still want each + // element to be treated as its own *individual* title { beginKeywords: 'namespace', relevance: 0, end: ';', illegal: /[.']/, - contains: [hljs.UNDERSCORE_TITLE_MODE] + contains: [ + hljs.inherit(hljs.UNDERSCORE_TITLE_MODE, { scope: "title.class" }) + ] }, { beginKeywords: 'use', relevance: 0, end: ';', - contains: [hljs.UNDERSCORE_TITLE_MODE] + contains: [ + // TODO: title.function vs title.class + { + match: /\b(as|const|function)\b/, + scope: "keyword" + }, + // TODO: could be title.class or title.function + hljs.UNDERSCORE_TITLE_MODE + ] }, STRING, NUMBER diff --git a/src/languages/protobuf.js b/src/languages/protobuf.js index 13c88426ee..7cae0a4a24 100644 --- a/src/languages/protobuf.js +++ b/src/languages/protobuf.js @@ -7,29 +7,57 @@ Category: protocols */ export default function(hljs) { + const KEYWORDS = [ + "package", + "import", + "option", + "optional", + "required", + "repeated", + "group", + "oneof" + ]; + const TYPES = [ + "double", + "float", + "int32", + "int64", + "uint32", + "uint64", + "sint32", + "sint64", + "fixed32", + "fixed64", + "sfixed32", + "sfixed64", + "bool", + "string", + "bytes" + ]; + const CLASS_DEFINITION = { + match: [ + /(message|enum|service)\s+/, + hljs.IDENT_RE + ], + scope: { + 1: "keyword", + 2: "title.class" + } + }; + return { name: 'Protocol Buffers', keywords: { - keyword: 'package import option optional required repeated group oneof', - built_in: 'double float int32 int64 uint32 uint64 sint32 sint64 ' + - 'fixed32 fixed64 sfixed32 sfixed64 bool string bytes', - literal: 'true false' + keyword: KEYWORDS, + type: TYPES, + literal: ['true', 'false'] }, contains: [ hljs.QUOTE_STRING_MODE, hljs.NUMBER_MODE, hljs.C_LINE_COMMENT_MODE, hljs.C_BLOCK_COMMENT_MODE, - { - className: 'class', - beginKeywords: 'message enum service', end: /\{/, - illegal: /\n/, - contains: [ - hljs.inherit(hljs.TITLE_MODE, { - starts: {endsWithParent: true, excludeEnd: true} // hack: eating everything after the first title - }) - ] - }, + CLASS_DEFINITION, { className: 'function', beginKeywords: 'rpc', diff --git a/src/languages/python.js b/src/languages/python.js index ce603a86d4..cb152d1b6c 100644 --- a/src/languages/python.js +++ b/src/languages/python.js @@ -255,6 +255,12 @@ export default function(hljs) { // https://docs.python.org/3.9/reference/lexical_analysis.html#numeric-literals const digitpart = '[0-9](_?[0-9])*'; const pointfloat = `(\\b(${digitpart}))?\\.(${digitpart})|\\b(${digitpart})\\.`; + // Whitespace after a number (or any lexical token) is needed only if its absence + // would change the tokenization + // https://docs.python.org/3.9/reference/lexical_analysis.html#whitespace-between-tokens + // We deviate slightly, requiring a word boundary or a keyword + // to avoid accidentally recognizing *prefixes* (e.g., `0` in `0x41` or `08` or `0__1`) + const lookahead = `\\b|${RESERVED_WORDS.join('|')}`; const NUMBER = { className: 'number', relevance: 0, @@ -270,7 +276,7 @@ export default function(hljs) { // because both MUST contain a decimal point and so cannot be confused with // the interior part of an identifier { - begin: `(\\b(${digitpart})|(${pointfloat}))[eE][+-]?(${digitpart})[jJ]?\\b` + begin: `(\\b(${digitpart})|(${pointfloat}))[eE][+-]?(${digitpart})[jJ]?(?=${lookahead})` }, { begin: `(${pointfloat})[jJ]?` @@ -283,22 +289,22 @@ export default function(hljs) { // decinteger is optionally imaginary // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals { - begin: '\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?\\b' + begin: `\\b([1-9](_?[0-9])*|0+(_?0)*)[lLjJ]?(?=${lookahead})` }, { - begin: '\\b0[bB](_?[01])+[lL]?\\b' + begin: `\\b0[bB](_?[01])+[lL]?(?=${lookahead})` }, { - begin: '\\b0[oO](_?[0-7])+[lL]?\\b' + begin: `\\b0[oO](_?[0-7])+[lL]?(?=${lookahead})` }, { - begin: '\\b0[xX](_?[0-9a-fA-F])+[lL]?\\b' + begin: `\\b0[xX](_?[0-9a-fA-F])+[lL]?(?=${lookahead})` }, // imagnumber (digitpart-based) // https://docs.python.org/3.9/reference/lexical_analysis.html#imaginary-literals { - begin: `\\b(${digitpart})[jJ]\\b` + begin: `\\b(${digitpart})[jJ](?=${lookahead})` } ] }; @@ -378,7 +384,7 @@ export default function(hljs) { hljs.HASH_COMMENT_MODE, { match: [ - /def/, /\s+/, + /\bdef/, /\s+/, IDENT_RE, ], scope: { @@ -391,14 +397,14 @@ export default function(hljs) { variants: [ { match: [ - /class/, /\s+/, + /\bclass/, /\s+/, IDENT_RE, /\s*/, /\(\s*/, IDENT_RE,/\s*\)/ ], }, { match: [ - /class/, /\s+/, + /\bclass/, /\s+/, IDENT_RE ], } diff --git a/src/languages/rsl.js b/src/languages/rsl.js index d5de88eab1..01cae371ac 100644 --- a/src/languages/rsl.js +++ b/src/languages/rsl.js @@ -7,19 +7,123 @@ Category: graphics */ export default function(hljs) { + const BUILT_INS = [ + "abs", + "acos", + "ambient", + "area", + "asin", + "atan", + "atmosphere", + "attribute", + "calculatenormal", + "ceil", + "cellnoise", + "clamp", + "comp", + "concat", + "cos", + "degrees", + "depth", + "Deriv", + "diffuse", + "distance", + "Du", + "Dv", + "environment", + "exp", + "faceforward", + "filterstep", + "floor", + "format", + "fresnel", + "incident", + "length", + "lightsource", + "log", + "match", + "max", + "min", + "mod", + "noise", + "normalize", + "ntransform", + "opposite", + "option", + "phong", + "pnoise", + "pow", + "printf", + "ptlined", + "radians", + "random", + "reflect", + "refract", + "renderinfo", + "round", + "setcomp", + "setxcomp", + "setycomp", + "setzcomp", + "shadow", + "sign", + "sin", + "smoothstep", + "specular", + "specularbrdf", + "spline", + "sqrt", + "step", + "tan", + "texture", + "textureinfo", + "trace", + "transform", + "vtransform", + "xcomp", + "ycomp", + "zcomp" + ]; + + const TYPES = [ + "matrix", + "float", + "color", + "point", + "normal", + "vector" + ]; + + const KEYWORDS = [ + "while", + "for", + "if", + "do", + "return", + "else", + "break", + "extern", + "continue" + ]; + + const CLASS_DEFINITION = { + match: [ + /(surface|displacement|light|volume|imager)/, + /\s+/, + hljs.IDENT_RE, + ], + scope: { + 1: "keyword", + 3: "title.class", + } + }; + return { name: 'RenderMan RSL', keywords: { - keyword: - 'float color point normal vector matrix while for if do return else break extern continue', - built_in: - 'abs acos ambient area asin atan atmosphere attribute calculatenormal ceil cellnoise ' + - 'clamp comp concat cos degrees depth Deriv diffuse distance Du Dv environment exp ' + - 'faceforward filterstep floor format fresnel incident length lightsource log match ' + - 'max min mod noise normalize ntransform opposite option phong pnoise pow printf ' + - 'ptlined radians random reflect refract renderinfo round setcomp setxcomp setycomp ' + - 'setzcomp shadow sign sin smoothstep specular specularbrdf spline sqrt step tan ' + - 'texture textureinfo trace transform vtransform xcomp ycomp zcomp' + keyword: KEYWORDS, + built_in: BUILT_INS, + type: TYPES }, illegal: ' +Author: Sean Pinkney Website: http://mc-stan.org/ Category: scientific */ export default function(hljs) { + const regex = hljs.regex; // variable names cannot conflict with block identifiers const BLOCKS = [ 'functions', @@ -17,6 +18,7 @@ export default function(hljs) { 'transformed', 'generated' ]; + const STATEMENTS = [ 'for', 'in', @@ -27,16 +29,10 @@ export default function(hljs) { 'continue', 'return' ]; - const SPECIAL_FUNCTIONS = [ - 'print', - 'reject', - 'increment_log_prob|10', - 'integrate_ode|10', - 'integrate_ode_rk45|10', - 'integrate_ode_bdf|10', - 'algebra_solver' - ]; - const VAR_TYPES = [ + + const TYPES = [ + 'array', + 'complex', 'int', 'real', 'vector', @@ -52,13 +48,24 @@ export default function(hljs) { 'cov_matrix|10', 'void' ]; + + // to get the functions list + // clone the [stan-docs repo](https://github.com/stan-dev/docs) + // then cd into it and run this bash script https://gist.github.com/joshgoebel/dcd33f82d4059a907c986049893843cf + // + // the output files are + // distributions_quoted.txt + // functions_quoted.txt + const FUNCTIONS = [ 'Phi', 'Phi_approx', 'abs', 'acos', 'acosh', + 'add_diag', 'algebra_solver', + 'algebra_solver_newton', 'append_array', 'append_col', 'append_row', @@ -67,56 +74,21 @@ export default function(hljs) { 'atan', 'atan2', 'atanh', - 'bernoulli_cdf', - 'bernoulli_lccdf', - 'bernoulli_lcdf', - 'bernoulli_logit_lpmf', - 'bernoulli_logit_rng', - 'bernoulli_lpmf', - 'bernoulli_rng', 'bessel_first_kind', 'bessel_second_kind', - 'beta_binomial_cdf', - 'beta_binomial_lccdf', - 'beta_binomial_lcdf', - 'beta_binomial_lpmf', - 'beta_binomial_rng', - 'beta_cdf', - 'beta_lccdf', - 'beta_lcdf', - 'beta_lpdf', - 'beta_rng', 'binary_log_loss', - 'binomial_cdf', 'binomial_coefficient_log', - 'binomial_lccdf', - 'binomial_lcdf', - 'binomial_logit_lpmf', - 'binomial_lpmf', - 'binomial_rng', 'block', - 'categorical_logit_lpmf', - 'categorical_logit_rng', - 'categorical_lpmf', - 'categorical_rng', - 'cauchy_cdf', - 'cauchy_lccdf', - 'cauchy_lcdf', - 'cauchy_lpdf', - 'cauchy_rng', 'cbrt', 'ceil', - 'chi_square_cdf', - 'chi_square_lccdf', - 'chi_square_lcdf', - 'chi_square_lpdf', - 'chi_square_rng', + 'chol2inv', 'cholesky_decompose', 'choose', 'col', 'cols', 'columns_dot_product', 'columns_dot_self', + 'conj', 'cos', 'cosh', 'cov_exp_quad', @@ -134,34 +106,16 @@ export default function(hljs) { 'diagonal', 'digamma', 'dims', - 'dirichlet_lpdf', - 'dirichlet_rng', 'distance', 'dot_product', 'dot_self', - 'double_exponential_cdf', - 'double_exponential_lccdf', - 'double_exponential_lcdf', - 'double_exponential_lpdf', - 'double_exponential_rng', - 'e', 'eigenvalues_sym', 'eigenvectors_sym', 'erf', 'erfc', 'exp', 'exp2', - 'exp_mod_normal_cdf', - 'exp_mod_normal_lccdf', - 'exp_mod_normal_lcdf', - 'exp_mod_normal_lpdf', - 'exp_mod_normal_rng', 'expm1', - 'exponential_cdf', - 'exponential_lccdf', - 'exponential_lcdf', - 'exponential_lpdf', - 'exponential_rng', 'fabs', 'falling_factorial', 'fdim', @@ -170,94 +124,68 @@ export default function(hljs) { 'fmax', 'fmin', 'fmod', - 'frechet_cdf', - 'frechet_lccdf', - 'frechet_lcdf', - 'frechet_lpdf', - 'frechet_rng', - 'gamma_cdf', - 'gamma_lccdf', - 'gamma_lcdf', - 'gamma_lpdf', 'gamma_p', 'gamma_q', - 'gamma_rng', - 'gaussian_dlm_obs_lpdf', + 'generalized_inverse', + 'get_imag', 'get_lp', - 'gumbel_cdf', - 'gumbel_lccdf', - 'gumbel_lcdf', - 'gumbel_lpdf', - 'gumbel_rng', + 'get_real', 'head', - 'hypergeometric_lpmf', - 'hypergeometric_rng', + 'hmm_hidden_state_prob', + 'hmm_marginal', 'hypot', + 'identity_matrix', 'inc_beta', 'int_step', + 'integrate_1d', 'integrate_ode', + 'integrate_ode_adams', 'integrate_ode_bdf', 'integrate_ode_rk45', 'inv', 'inv_Phi', - 'inv_chi_square_cdf', - 'inv_chi_square_lccdf', - 'inv_chi_square_lcdf', - 'inv_chi_square_lpdf', - 'inv_chi_square_rng', 'inv_cloglog', - 'inv_gamma_cdf', - 'inv_gamma_lccdf', - 'inv_gamma_lcdf', - 'inv_gamma_lpdf', - 'inv_gamma_rng', 'inv_logit', 'inv_sqrt', 'inv_square', - 'inv_wishart_lpdf', - 'inv_wishart_rng', 'inverse', 'inverse_spd', 'is_inf', 'is_nan', + 'lambert_w0', + 'lambert_wm1', 'lbeta', 'lchoose', + 'ldexp', 'lgamma', - 'lkj_corr_cholesky_lpdf', - 'lkj_corr_cholesky_rng', - 'lkj_corr_lpdf', - 'lkj_corr_rng', + 'linspaced_array', + 'linspaced_int_array', + 'linspaced_row_vector', + 'linspaced_vector', 'lmgamma', 'lmultiply', 'log', - 'log10', 'log1m', 'log1m_exp', 'log1m_inv_logit', 'log1p', 'log1p_exp', - 'log2', 'log_determinant', 'log_diff_exp', 'log_falling_factorial', 'log_inv_logit', + 'log_inv_logit_diff', 'log_mix', + 'log_modified_bessel_first_kind', 'log_rising_factorial', 'log_softmax', 'log_sum_exp', - 'logistic_cdf', - 'logistic_lccdf', - 'logistic_lcdf', - 'logistic_lpdf', - 'logistic_rng', 'logit', - 'lognormal_cdf', - 'lognormal_lccdf', - 'lognormal_lcdf', - 'lognormal_lpdf', - 'lognormal_rng', 'machine_precision', + 'map_rect', 'matrix_exp', + 'matrix_exp_multiply', + 'matrix_power', 'max', 'mdivide_left_spd', 'mdivide_left_tri_low', @@ -267,120 +195,80 @@ export default function(hljs) { 'min', 'modified_bessel_first_kind', 'modified_bessel_second_kind', - 'multi_gp_cholesky_lpdf', - 'multi_gp_lpdf', - 'multi_normal_cholesky_lpdf', - 'multi_normal_cholesky_rng', - 'multi_normal_lpdf', - 'multi_normal_prec_lpdf', - 'multi_normal_rng', - 'multi_student_t_lpdf', - 'multi_student_t_rng', - 'multinomial_lpmf', - 'multinomial_rng', 'multiply_log', 'multiply_lower_tri_self_transpose', - 'neg_binomial_2_cdf', - 'neg_binomial_2_lccdf', - 'neg_binomial_2_lcdf', - 'neg_binomial_2_log_lpmf', - 'neg_binomial_2_log_rng', - 'neg_binomial_2_lpmf', - 'neg_binomial_2_rng', - 'neg_binomial_cdf', - 'neg_binomial_lccdf', - 'neg_binomial_lcdf', - 'neg_binomial_lpmf', - 'neg_binomial_rng', 'negative_infinity', - 'normal_cdf', - 'normal_lccdf', - 'normal_lcdf', - 'normal_lpdf', - 'normal_rng', + 'norm', 'not_a_number', 'num_elements', - 'ordered_logistic_lpmf', - 'ordered_logistic_rng', + 'ode_adams', + 'ode_adams_tol', + 'ode_adjoint_tol_ctl', + 'ode_bdf', + 'ode_bdf_tol', + 'ode_ckrk', + 'ode_ckrk_tol', + 'ode_rk45', + 'ode_rk45_tol', + 'one_hot_array', + 'one_hot_int_array', + 'one_hot_row_vector', + 'one_hot_vector', + 'ones_array', + 'ones_int_array', + 'ones_row_vector', + 'ones_vector', 'owens_t', - 'pareto_cdf', - 'pareto_lccdf', - 'pareto_lcdf', - 'pareto_lpdf', - 'pareto_rng', - 'pareto_type_2_cdf', - 'pareto_type_2_lccdf', - 'pareto_type_2_lcdf', - 'pareto_type_2_lpdf', - 'pareto_type_2_rng', - 'pi', - 'poisson_cdf', - 'poisson_lccdf', - 'poisson_lcdf', - 'poisson_log_lpmf', - 'poisson_log_rng', - 'poisson_lpmf', - 'poisson_rng', + 'polar', 'positive_infinity', 'pow', 'print', 'prod', + 'proj', 'qr_Q', 'qr_R', + 'qr_thin_Q', + 'qr_thin_R', 'quad_form', 'quad_form_diag', 'quad_form_sym', + 'quantile', 'rank', - 'rayleigh_cdf', - 'rayleigh_lccdf', - 'rayleigh_lcdf', - 'rayleigh_lpdf', - 'rayleigh_rng', + 'reduce_sum', 'reject', 'rep_array', 'rep_matrix', 'rep_row_vector', 'rep_vector', + 'reverse', 'rising_factorial', 'round', 'row', 'rows', 'rows_dot_product', 'rows_dot_self', - 'scaled_inv_chi_square_cdf', - 'scaled_inv_chi_square_lccdf', - 'scaled_inv_chi_square_lcdf', - 'scaled_inv_chi_square_lpdf', - 'scaled_inv_chi_square_rng', + 'scale_matrix_exp_multiply', 'sd', 'segment', 'sin', 'singular_values', 'sinh', 'size', - 'skew_normal_cdf', - 'skew_normal_lccdf', - 'skew_normal_lcdf', - 'skew_normal_lpdf', - 'skew_normal_rng', 'softmax', 'sort_asc', 'sort_desc', 'sort_indices_asc', 'sort_indices_desc', 'sqrt', - 'sqrt2', 'square', 'squared_distance', 'step', - 'student_t_cdf', - 'student_t_lccdf', - 'student_t_lcdf', - 'student_t_lpdf', - 'student_t_rng', 'sub_col', 'sub_row', 'sum', + 'svd_U', + 'svd_V', + 'symmetrize_from_lower_tri', 'tail', 'tan', 'tanh', @@ -389,6 +277,7 @@ export default function(hljs) { 'tgamma', 'to_array_1d', 'to_array_2d', + 'to_complex', 'to_matrix', 'to_row_vector', 'to_vector', @@ -397,35 +286,29 @@ export default function(hljs) { 'trace_quad_form', 'trigamma', 'trunc', - 'uniform_cdf', - 'uniform_lccdf', - 'uniform_lcdf', - 'uniform_lpdf', - 'uniform_rng', + 'uniform_simplex', 'variance', - 'von_mises_lpdf', - 'von_mises_rng', - 'weibull_cdf', - 'weibull_lccdf', - 'weibull_lcdf', - 'weibull_lpdf', - 'weibull_rng', - 'wiener_lpdf', - 'wishart_lpdf', - 'wishart_rng' + 'zeros_array', + 'zeros_int_array', + 'zeros_row_vector' ]; + const DISTRIBUTIONS = [ 'bernoulli', 'bernoulli_logit', + 'bernoulli_logit_glm', 'beta', 'beta_binomial', + 'beta_proportion', 'binomial', 'binomial_logit', 'categorical', 'categorical_logit', + 'categorical_logit_glm', 'cauchy', 'chi_square', 'dirichlet', + 'discrete_range', 'double_exponential', 'exp_mod_normal', 'exponential', @@ -433,6 +316,7 @@ export default function(hljs) { 'gamma', 'gaussian_dlm_obs', 'gumbel', + 'hmm_latent', 'hypergeometric', 'inv_chi_square', 'inv_gamma', @@ -448,18 +332,26 @@ export default function(hljs) { 'multi_normal_prec', 'multi_student_t', 'multinomial', + 'multinomial_logit', 'neg_binomial', 'neg_binomial_2', 'neg_binomial_2_log', + 'neg_binomial_2_log_glm', 'normal', + 'normal_id_glm', 'ordered_logistic', + 'ordered_logistic_glm', + 'ordered_probit', 'pareto', 'pareto_type_2', 'poisson', 'poisson_log', + 'poisson_log_glm', 'rayleigh', 'scaled_inv_chi_square', + 'skew_double_exponential', 'skew_normal', + 'std_normal', 'student_t', 'uniform', 'von_mises', @@ -475,7 +367,7 @@ export default function(hljs) { relevance: 0, contains: [ { - className: 'doctag', + scope: 'doctag', match: /@(return|param)/ } ] @@ -483,27 +375,33 @@ export default function(hljs) { ); const INCLUDE = { - className: 'meta', - begin: /^#include\b/, + scope: 'meta', + begin: /#include\b/, end: /$/, - relevance: 0, // relevance comes from keywords - keywords: "include", contains: [ { - match: /[a-z][a-z-.]+/, - className: "string" + match: /[a-z][a-z-._]+/, + scope: 'string' }, hljs.C_LINE_COMMENT_MODE ] }; + const RANGE_CONSTRAINTS = [ + "lower", + "upper", + "offset", + "multiplier" + ]; + return { name: 'Stan', aliases: [ 'stanfuncs' ], keywords: { $pattern: hljs.IDENT_RE, title: BLOCKS, - keyword: STATEMENTS.concat(VAR_TYPES).concat(SPECIAL_FUNCTIONS), + type: TYPES, + keyword: STATEMENTS, built_in: FUNCTIONS }, contains: [ @@ -512,41 +410,81 @@ export default function(hljs) { hljs.HASH_COMMENT_MODE, BLOCK_COMMENT, { - // hack: in range constraints, lower must follow "<" - begin: /<\s*lower\s*=/, - keywords: 'lower' + scope: 'built_in', + match: /\s(pi|e|sqrt2|log2|log10)(?=\()/, + relevance: 0 + }, + { + match: regex.concat(/[<,]\s*/, regex.either(...RANGE_CONSTRAINTS), /\s*=/), + keywords: RANGE_CONSTRAINTS }, { - // hack: in range constraints, upper must follow either , or < - // or - begin: /[<,]\s*upper\s*=/, - keywords: 'upper' + scope: 'keyword', + match: /\btarget(?=\s*\+=)/, }, { - className: 'keyword', - begin: /\btarget\s*\+=/ + // highlights the 'T' in T[,] for only Stan language distributrions + match: [ + /~\s*/, + regex.either(...DISTRIBUTIONS), + /(?:\(\))/, + /\s*T(?=\s*\[)/ + ], + scope: { + 2: "built_in", + 4: "keyword" + } }, { - begin: '~\\s*(' + hljs.IDENT_RE + ')\\s*\\(', - keywords: DISTRIBUTIONS + // highlights distributions that end with special endings + scope: 'built_in', + keywords: DISTRIBUTIONS, + begin: regex.concat(/\w*/, regex.either(...DISTRIBUTIONS), /(_lpdf|_lupdf|_lpmf|_cdf|_lcdf|_lccdf|_qf)(?=\s*[\(.*\)])/) }, { - className: 'number', - variants: [ - { - begin: /\b\d+(?:\.\d*)?(?:[eE][+-]?\d+)?/ - }, - { - begin: /\.\d+(?:[eE][+-]?\d+)?\b/ - } + // highlights distributions after ~ + begin: [ + /~/, + /\s*/, + regex.concat(regex.either(...DISTRIBUTIONS), /(?=\s*[\(.*\)])/) ], - relevance: 0 + scope: { 3: "built_in" } + }, + { + // highlights user defined distributions after ~ + begin: [ + /~/, + /\s*\w+(?=\s*[\(.*\)])/, + '(?!.*/\b(' + regex.either(...DISTRIBUTIONS) + ')\b)' + ], + scope: { 2: "title.function" } + }, + { + // highlights user defined distributions with special endings + scope: 'title.function', + begin: /\w*(_lpdf|_lupdf|_lpmf|_cdf|_lcdf|_lccdf|_qf)(?=\s*[\(.*\)])/ }, { - className: 'string', - begin: '"', - end: '"', + scope: 'number', + match: regex.concat( + // Comes from @RunDevelopment accessed 11/29/2021 at + // https://github.com/PrismJS/prism/blob/c53ad2e65b7193ab4f03a1797506a54bbb33d5a2/components/prism-stan.js#L56 + + // start of big noncapture group which + // 1. gets numbers that are by themselves + // 2. numbers that are separated by _ + // 3. numbers that are separted by . + /(?:\b\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\B\.\d+(?:_\d+)*)/, + // grabs scientific notation + // grabs complex numbers with i + /(?:[eE][+-]?\d+(?:_\d+)*)?i?(?!\w)/ + ), relevance: 0 + }, + { + scope: 'string', + begin: /"/, + end: /"/ } ] }; diff --git a/src/languages/swift.js b/src/languages/swift.js index 0adc30d957..15fb39c9e9 100644 --- a/src/languages/swift.js +++ b/src/languages/swift.js @@ -221,7 +221,7 @@ export default function(hljs) { // https://docs.swift.org/swift-book/ReferenceManual/Attributes.html const AVAILABLE_ATTRIBUTE = { - match: /(@|#)available/, + match: /(@|#(un)?)available/, className: "keyword", starts: { contains: [ diff --git a/src/languages/twig.js b/src/languages/twig.js index 4ea7bd041a..3e4a26257d 100644 --- a/src/languages/twig.js +++ b/src/languages/twig.js @@ -8,67 +8,208 @@ Category: template */ export default function(hljs) { - var PARAMS = { - className: 'params', - begin: '\\(', end: '\\)' + const regex = hljs.regex; + const FUNCTION_NAMES = [ + "attribute", + "block", + "constant", + "country_timezones", + "cycle", + "date", + "dump", + "html_classes", + "include", + "max", + "min", + "parent", + "random", + "range", + "source", + "template_from_string" + ]; + + const FILTERS = [ + "abs", + "batch", + "capitalize", + "column", + "convert_encoding", + "country_name", + "currency_name", + "currency_symbol", + "data_uri", + "date", + "date_modify", + "default", + "escape", + "filter", + "first", + "format", + "format_currency", + "format_date", + "format_datetime", + "format_number", + "format_time", + "html_to_markdown", + "inky_to_html", + "inline_css", + "join", + "json_encode", + "keys", + "language_name", + "last", + "length", + "locale_name", + "lower", + "map", + "markdown", + "markdown_to_html", + "merge", + "nl2br", + "number_format", + "raw", + "reduce", + "replace", + "reverse", + "round", + "slice", + "slug", + "sort", + "spaceless", + "split", + "striptags", + "timezone_name", + "title", + "trim", + "u|0", + "upper", + "url_encode" + ]; + + let TAG_NAMES = [ + "apply", + "autoescape", + "block", + "cache", + "deprecated", + "do", + "embed", + "extends", + "filter", + "flush", + "for", + "from", + "if", + "import", + "include", + "macro", + "sandbox", + "set", + "use", + "verbatim", + "with" + ]; + + TAG_NAMES = TAG_NAMES.concat(TAG_NAMES.map(t => `end${t}`)); + + const STRING = { + scope: 'string', + variants: [ + { + begin: /'/, + end: /'/ + }, + { + begin: /"/, + end: /"/ + }, + ] }; - var FUNCTION_NAMES = 'attribute block constant cycle date dump include ' + - 'max min parent random range source template_from_string'; + const NUMBER = { + scope: "number", + match: /\d+/ + }; - var FUNCTIONS = { - beginKeywords: FUNCTION_NAMES, - keywords: {name: FUNCTION_NAMES}, - relevance: 0, + const PARAMS = { + begin: /\(/, + end: /\)/, + excludeBegin: true, + excludeEnd: true, contains: [ - PARAMS + STRING, + NUMBER ] }; - var FILTER = { - begin: /\|[A-Za-z_]+:?/, - keywords: - 'abs batch capitalize column convert_encoding date date_modify default ' + - 'escape filter first format inky_to_html inline_css join json_encode keys last ' + - 'length lower map markdown merge nl2br number_format raw reduce replace ' + - 'reverse round slice sort spaceless split striptags title trim upper url_encode', + + const FUNCTIONS = { + beginKeywords: FUNCTION_NAMES.join(" "), + keywords: { name: FUNCTION_NAMES }, + relevance: 0, + contains: [ PARAMS ] + }; + + const FILTER = { + match: /\|(?=[A-Za-z_]+:?)/, + beginScope: "punctuation", + relevance: 0, contains: [ - FUNCTIONS + { + match: /[A-Za-z_]+:?/, + keywords: FILTERS + }, ] }; - var TAGS = 'apply autoescape block deprecated do embed extends filter flush for from ' + - 'if import include macro sandbox set use verbatim with'; + const tagNamed = (tagnames, {relevance}) => { + return { + beginScope: { + 1: 'template-tag', + 3: 'name' + }, + relevance: relevance || 2, + endScope: 'template-tag', + begin: [ + /\{%/, + /\s*/, + regex.either(...tagnames) + ], + end: /%\}/, + keywords: "in", + contains: [ + FILTER, + FUNCTIONS, + STRING, + NUMBER + ] + }; + }; - TAGS = TAGS + ' ' + TAGS.split(' ').map(function(t){return 'end' + t}).join(' '); + const CUSTOM_TAG_RE = /[a-z_]+/; + const TAG = tagNamed(TAG_NAMES, { relevance: 2 }); + const CUSTOM_TAG = tagNamed([ CUSTOM_TAG_RE ], { relevance: 1 }); return { name: 'Twig', - aliases: ['craftcms'], + aliases: [ 'craftcms' ], case_insensitive: true, subLanguage: 'xml', contains: [ hljs.COMMENT(/\{#/, /#\}/), + TAG, + CUSTOM_TAG, { - className: 'template-tag', - begin: /\{%/, end: /%\}/, + className: 'template-variable', + begin: /\{\{/, + end: /\}\}/, contains: [ - { - className: 'name', - begin: /\w+/, - keywords: TAGS, - starts: { - endsWithParent: true, - contains: [FILTER, FUNCTIONS], - relevance: 0 - } - } + 'self', + FILTER, + FUNCTIONS, + STRING, + NUMBER ] - }, - { - className: 'template-variable', - begin: /\{\{/, end: /\}\}/, - contains: ['self', FILTER, FUNCTIONS] } ] }; diff --git a/src/lib/regex.js b/src/lib/regex.js index b914fb4c5f..da6cc457c8 100644 --- a/src/lib/regex.js +++ b/src/lib/regex.js @@ -65,11 +65,13 @@ function stripOptionsFromArgs(args) { } } +/** @typedef { {capture?: boolean} } RegexEitherOptions */ + /** * Any of the passed expresssions may match * * Creates a huge this | this | that | that match - * @param {(RegExp | string)[] } args + * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args * @returns {string} */ export function either(...args) { diff --git a/src/styles/dark.css b/src/styles/dark.css index 34708897f3..052dbc94f1 100644 --- a/src/styles/dark.css +++ b/src/styles/dark.css @@ -6,7 +6,7 @@ Dark style from softwaremaniacs.org (c) Ivan Sagalaev .hljs { -background: rgb(80,31,122); -background: linear-gradient(166deg, rgba(80,31,122,1) 0%, rgba(40,32,179,1) 80%); +background-color: #652487; +background-image: linear-gradient(160deg, #652487 0%, #443ac3 35%, #0174b7 68%, #04988e 100%); color:#e7e4eb; } diff --git a/src/styles/gradient-light.css b/src/styles/gradient-light.css index 574534cb56..a5c4f5edc2 100644 --- a/src/styles/gradient-light.css +++ b/src/styles/gradient-light.css @@ -6,8 +6,8 @@ Gradient Light (c) Samia Ali .hljs { -background: rgb(255,253,141); -background: linear-gradient(142deg, rgba(255,253,141,1) 0%, rgba(252,183,255,1) 35%, rgba(144,236,255,1) 100%); +background-color: #f9ccff; +background-image: linear-gradient(295deg, #f9ccff 0%, #e6bbf9 11%, #9ec6f9 32%, #55e6ee 60%, #91f5d1 74%, #f9ffbf 98%); color:#250482; } @@ -46,6 +46,7 @@ color:#01958B; .hljs-section, .hljs-meta .hljs-keyword, + .hljs-symbol, .hljs-type @@ -64,7 +65,7 @@ color:#01958B; .hljs-string { - color: #38c0ff; + color: #2681ab; } diff --git a/src/styles/intellij-light.css b/src/styles/intellij-light.css new file mode 100644 index 0000000000..4ab3f230bb --- /dev/null +++ b/src/styles/intellij-light.css @@ -0,0 +1,119 @@ +/* + +Intellij-light style (c) Pegasis + +*/ + +.hljs { + color: #000; + background: #fff; +} + +.hljs-subst, +.hljs-title { + font-weight: normal; + color: #000; +} + +.hljs-title.function_ { + color: #7A7A43; +} + +.hljs-code, +.hljs-comment, +.hljs-quote { + color: #8C8C8C; + font-style: italic; +} + +.hljs-meta { + color: #9E880D; +} + +.hljs-section { + color: #871094; +} + +.hljs-variable.language_, +.hljs-symbol, +.hljs-selector-class, +.hljs-selector-id, +.hljs-selector-tag, +.hljs-template-tag, +.hljs-selector-attr, +.hljs-selector-pseudo, +.hljs-keyword, +.hljs-meta .hljs-keyword, +.hljs-literal, +.hljs-name, +.hljs-built_in, +.hljs-type { + color: #0033B3; +} + +.hljs-property, +.hljs-attr { + color: #871094; +} + +.hljs-attribute { + color: #174AD4; +} + +.hljs-number { + color: #1750EB; +} + +.hljs-regexp { + color: #264EFF; +} + +.hljs-link { + text-decoration: underline; + color: #006DCC; +} + +.hljs-meta .hljs-string, +.hljs-string { + color: #067D17; +} + +.hljs-char.escape_ { + color: #0037A6; +} + +.hljs-doctag { + text-decoration: underline; +} + +.hljs-template-variable { + color: #248F8F; +} + +.hljs-addition { + background: #BEE6BE; +} + +.hljs-deletion { + background: #D6D6D6; +} + +.hljs-emphasis { + font-style: italic; +} + +.hljs-strong { + font-weight: bold; +} + +.hljs-variable, +.hljs-operator, +.hljs-punctuation, +.hljs-title.class_.inherited__, +.hljs-title.class_, +.hljs-params, +.hljs-bullet, +.hljs-formula, +.hljs-tag { + /* purposely ignored */ +} diff --git a/test/detect/cal/default.txt b/test/detect/cal/default.txt index 5eec86caf0..eb65b97364 100644 --- a/test/detect/cal/default.txt +++ b/test/detect/cal/default.txt @@ -1,4 +1,11 @@ -OBJECT Codeunit 11 Gen. Jnl.-Check Line +OBJECT Table 12 something +{ +} +OBJECT XMLport 3000 something.other +{ +} + +OBJECT Codeunit 11 Gen. Jnl.-Chck Line { OBJECT-PROPERTIES { diff --git a/test/detect/php/default.txt b/test/detect/php/default.txt index 70ba114640..54a9edc624 100644 --- a/test/detect/php/default.txt +++ b/test/detect/php/default.txt @@ -56,14 +56,6 @@ enum Foo: string { case Test = 'test'; } -match ($key) { - 1 => 'Integer 1', - '1' => 'String 1', - true => 'Bool true', - [] => 'Empty array', - [1] => 'Array [1]', -}; - echo URI::ME . URI::$st1; __halt_compiler () ; datahere diff --git a/test/detect/stan/default.txt b/test/detect/stan/default.txt index 99e56c45ec..a4b42f332e 100644 --- a/test/detect/stan/default.txt +++ b/test/detect/stan/default.txt @@ -1,39 +1,40 @@ -// Multivariate Regression Example -// Taken from stan-reference-2.8.0.pdf p.66 - +functions { + #include normal_copula.stanfunctions +} data { - int N; // num individuals - int K; // num ind predictors - int J; // num groups - int L; // num group predictors - int jj[N]; // group for individual - matrix[N,K] x; // individual predictors - row_vector[L] u[J]; // group predictors - vector[N] y; // outcomes + int N; + int K; + matrix[N, K] x; } +transformed data { + complex zi = 1+3.14i; + zi = zi * 0i; + complex yi = to_complex(0, 1.1) + to_complex(0.0, 2.2) + to_complex(); + real x = get_real(3i - 40e-3i + 1e10i); +}› parameters { - corr_matrix[K] Omega; // prior correlation - vector[K] tau; // prior scale - matrix[L,K] gamma; // group coeffs - vector[K] beta[J]; // indiv coeffs by group - real sigma; // prediction error scale + array[K - 1] real mu; + array[K + 1] real sigma; + cholesky_factor_corr[K] L; } model { - tau ~ cauchy(0,2.5); - Omega ~ lkj_corr(2); - to_vector(gamma) ~ normal(0, 5); - { - row_vector[K] u_gamma[J]; - for (j in 1:J) - u_gamma[j] <- u[j] * gamma; - beta ~ multi_normal(u_gamma, quad_form_diag(Omega, tau)); - } + target += normal_lpdf(x[ : , 1] | mu[1], sigma[1]); + target += gumbel_lpdf(x[ : , 2] | mu[2], sigma[2]); + target += lognormal_lpdf(x[ : , 3] | mu[3], sigma[3]); + target += weibull_lpdf(x[ : , 4] | sigma[4], sigma[5]); + { - vector[N] x_beta_jj; - for (n in 1:N) - x_beta_jj[n] <- x[n] * beta[jj[n]]; - y ~ normal(x_beta_jj, sigma); + matrix[K, N] y; + for (n in 1 : N) { + y[1, n] = inv_Phi(normal_cdf(x[n, 1] | mu[1], sigma[1])); + y[2, n] = inv_Phi(gumbel_cdf(x[n, 2] | mu[2], sigma[2])); + y[3, n] = inv_Phi(lognormal_cdf(x[n, 3] | mu[3], sigma[3])); + y[4, n] = inv_Phi(weibull_cdf(x[n, 4] | sigma[4], sigma[5])); + } + y ~ multi_normal(L); + } } - -# Note: Octothorpes indicate comments, too! +generated quantities { + matrix[K, K] Sigma = multiply_lower_tri_self_transpose(L); +} \ No newline at end of file diff --git a/test/markup/arcade/profile.expect.txt b/test/markup/arcade/profile.expect.txt index d4a9dce5f2..f30c09e4b6 100644 --- a/test/markup/arcade/profile.expect.txt +++ b/test/markup/arcade/profile.expect.txt @@ -3,7 +3,7 @@ */ function offsetPopulation(offset){ var popDensity = Round( $feature.POPULATION / AreaGeodetic(Geometry($feature), "square-kilometers") ); - var geom = Geometry({ 'x': offset.x, 'y': offset.y, 'spatialReference':{'wkid':102100} }); + var geom = Geometry({ 'x': offset.x, 'y': offset.y, 'spatialReference':{'wkid':102100} }); var myLayer = FeatureSet($map, ["POPULATION", "ELECTION-DATA"]); return popDensity; } diff --git a/test/markup/axapta/default.expect.txt b/test/markup/axapta/default.expect.txt index dc645bb496..4ce35197d3 100644 --- a/test/markup/axapta/default.expect.txt +++ b/test/markup/axapta/default.expect.txt @@ -1,4 +1,4 @@ -class ExchRateLoadBatch extends RunBaseBatch { +class ExchRateLoadBatch extends RunBaseBatch { ExchRateLoad rbc; container currencies; boolean actual; diff --git a/test/markup/cal/default.expect.txt b/test/markup/cal/default.expect.txt index 20f52bece3..6041808c0a 100644 --- a/test/markup/cal/default.expect.txt +++ b/test/markup/cal/default.expect.txt @@ -1,16 +1,16 @@ -OBJECT Codeunit 11 Gen. Jnl.-Check Line +OBJECT Codeunit 11 Gen. Jnl.-Check Line { OBJECT-PROPERTIES { - Date=09-09-14; - Time=12:00:00; - Version List=NAVW18.00; + Date=09-09-14; + Time=12:00:00; + Version List=NAVW18.00; } PROPERTIES { - TableNo=81; - Permissions=TableData 252=rimd; - OnRun=BEGIN + TableNo=81; + Permissions=TableData 252=rimd; + OnRun=BEGIN GLSetup.GET; RunCheck(Rec); END; @@ -22,12 +22,12 @@ Text000@1000 : TextConst 'ENU=can only be a closing date for G/L entries'; Text001@1001 : TextConst 'ENU=is not within your range of allowed posting dates'; - PROCEDURE ErrorIfPositiveAmt@2(GenJnlLine@1000 : Record 81); + PROCEDURE ErrorIfPositiveAmt@2(GenJnlLine@1000 : Record 81); BEGIN IF GenJnlLine.Amount > 0 THEN GenJnlLine.FIELDERROR(Amount,Text008); END; - LOCAL PROCEDURE CheckGenJnlLineDocType@7(GenJnlLine@1001 : Record 81); + LOCAL PROCEDURE CheckGenJnlLineDocType@7(GenJnlLine@1001 : Record 81); } } diff --git a/test/markup/capnproto/default.expect.txt b/test/markup/capnproto/default.expect.txt index b516975696..a62a9928aa 100644 --- a/test/markup/capnproto/default.expect.txt +++ b/test/markup/capnproto/default.expect.txt @@ -1,17 +1,17 @@ @0xdbb9ad1f14bf0b36; # unique file ID, generated by `capnp id` -struct Person { - name @0 :Text; +struct Person { + name @0 :Text; birthdate @3 :Date; - email @1 :Text; - phones @2 :List(PhoneNumber); + email @1 :Text; + phones @2 :List(PhoneNumber); - struct PhoneNumber { - number @0 :Text; + struct PhoneNumber { + number @0 :Text; type @1 :Type; - enum Type { + enum Type { mobile @0; home @1; work @2; @@ -19,37 +19,37 @@ } } -struct Date { - year @0 :Int16; - month @1 :UInt8; - day @2 :UInt8; - flags @3 :List(Bool) = [ true, false, false, true ]; +struct Date { + year @0 :Int16; + month @1 :UInt8; + day @2 :UInt8; + flags @3 :List(Bool) = [ true, false, false, true ]; } -interface Node { - isDirectory @0 () -> (result :Bool); +interface Node { + isDirectory @0 () -> (result :Bool); } -interface Directory extends(Node) { - list @0 () -> (list: List(Entry)); - struct Entry { - name @0 :Text; +interface Directory extends(Node) { + list @0 () -> (list: List(Entry)); + struct Entry { + name @0 :Text; node @1 :Node; } - create @1 (name :Text) -> (file :File); - mkdir @2 (name :Text) -> (directory :Directory) - open @3 (name :Text) -> (node :Node); - delete @4 (name :Text); - link @5 (name :Text, node :Node); + create @1 (name :Text) -> (file :File); + mkdir @2 (name :Text) -> (directory :Directory) + open @3 (name :Text) -> (node :Node); + delete @4 (name :Text); + link @5 (name :Text, node :Node); } -interface File extends(Node) { - size @0 () -> (size: UInt64); - read @1 (startAt :UInt64 = 0, amount :UInt64 = 0xffffffffffffffff) - -> (data: Data); +interface File extends(Node) { + size @0 () -> (size: UInt64); + read @1 (startAt :UInt64 = 0, amount :UInt64 = 0xffffffffffffffff) + -> (data: Data); # Default params = read entire file. - write @2 (startAt :UInt64, data :Data); - truncate @3 (size :UInt64); + write @2 (startAt :UInt64, data :Data); + truncate @3 (size :UInt64); } \ No newline at end of file diff --git a/test/markup/clojure/character.expect.txt b/test/markup/clojure/character.expect.txt new file mode 100644 index 0000000000..1b7cf05082 --- /dev/null +++ b/test/markup/clojure/character.expect.txt @@ -0,0 +1,5 @@ +\A +\a +\formfeed +\u00DF +\o303 \ No newline at end of file diff --git a/test/markup/clojure/character.txt b/test/markup/clojure/character.txt new file mode 100644 index 0000000000..7cf4531ab9 --- /dev/null +++ b/test/markup/clojure/character.txt @@ -0,0 +1,5 @@ +\A +\a +\formfeed +\u00DF +\o303 \ No newline at end of file diff --git a/test/markup/clojure/comment-macro.expect.txt b/test/markup/clojure/comment-macro.expect.txt new file mode 100644 index 0000000000..55260ddbb3 --- /dev/null +++ b/test/markup/clojure/comment-macro.expect.txt @@ -0,0 +1,2 @@ +(comment "comment is a macro that emits no code. It can contain clojure code in itself.") +(comment-and-something "This is a valid function name") \ No newline at end of file diff --git a/test/markup/clojure/comment-macro.txt b/test/markup/clojure/comment-macro.txt new file mode 100644 index 0000000000..8ebcefc043 --- /dev/null +++ b/test/markup/clojure/comment-macro.txt @@ -0,0 +1,2 @@ +(comment "comment is a macro that emits no code. It can contain clojure code in itself.") +(comment-and-something "This is a valid function name") \ No newline at end of file diff --git a/test/markup/clojure/deps_edn.expect.txt b/test/markup/clojure/deps_edn.expect.txt index fdedd183bd..9d36af63ad 100644 --- a/test/markup/clojure/deps_edn.expect.txt +++ b/test/markup/clojure/deps_edn.expect.txt @@ -1,14 +1,14 @@ -{:aliases {:export {:exec-fn stelcodes.dev-blog.generator/export}, - :repl {:extra-deps {cider/cider-nrepl {:mvn/version "0.25.2"}, - nrepl/nrepl {:mvn/version "0.8.3"}}, - :extra-paths ["dev"], +{:aliases {:export {:exec-fn stelcodes.dev-blog.generator/export}, + :repl {:extra-deps {cider/cider-nrepl {:mvn/version "0.25.2"}, + nrepl/nrepl {:mvn/version "0.8.3"}}, + :extra-paths ["dev"], :main-opts ["-m" "nrepl.cmdline" "--middleware" "[cider.nrepl/cider-middleware]" - "--interactive"]}, - :webhook {:exec-fn stelcodes.dev-blog.webhook/listen}}, - :deps {http-kit/http-kit {:mvn/version "2.5.3"}, - org.clojure/clojure {:mvn/version "1.10.1"}, - stasis/stasis {:mvn/version "2.5.1"}}, + "--interactive"]}, + :webhook {:exec-fn stelcodes.dev-blog.webhook/listen}}, + :deps {http-kit/http-kit {:mvn/version "2.5.3"}, + org.clojure/clojure {:mvn/version "1.10.1"}, + stasis/stasis {:mvn/version "2.5.1"}}, :paths ["src" "resources"]} diff --git a/test/markup/clojure/globals_definition.expect.txt b/test/markup/clojure/globals_definition.expect.txt index e387a1b63c..efc8a15c9a 100644 --- a/test/markup/clojure/globals_definition.expect.txt +++ b/test/markup/clojure/globals_definition.expect.txt @@ -5,8 +5,8 @@ ; function (defn clojure-function [args] (let [string "multiline\nstring" - regexp #"regexp" - number 100,000 + regexp #"regexp" + number 100000 booleans [false true] keyword ::the-keyword] ;; this is comment @@ -14,12 +14,23 @@ (->> (list [vector] {:map map} #{'set}))))) +#"\"abc\\" + +"real +multiline +string" + +#:person{:first "Han" + :last "Solo" + :ship #:ship{:name "Millenium Falcon"}} +#::{:a 1, :b 2} + ; global (def some-var) ; another one (def alternative-var "132") ; defonce -(defonce ^:private another-var #"foo") +(defonce ^:private another-var #"foo") ; private function (defn- add [x y] (+ x y)) diff --git a/test/markup/clojure/globals_definition.txt b/test/markup/clojure/globals_definition.txt index 6faeee7942..0858484786 100644 --- a/test/markup/clojure/globals_definition.txt +++ b/test/markup/clojure/globals_definition.txt @@ -6,7 +6,7 @@ (defn clojure-function [args] (let [string "multiline\nstring" regexp #"regexp" - number 100,000 + number 100000 booleans [false true] keyword ::the-keyword] ;; this is comment @@ -14,6 +14,17 @@ (->> (list [vector] {:map map} #{'set}))))) +#"\"abc\\" + +"real +multiline +string" + +#:person{:first "Han" + :last "Solo" + :ship #:ship{:name "Millenium Falcon"}} +#::{:a 1, :b 2} + ; global (def some-var) ; another one diff --git a/test/markup/clojure/hint_col.expect.txt b/test/markup/clojure/hint_col.expect.txt deleted file mode 100644 index cb833d9027..0000000000 --- a/test/markup/clojure/hint_col.expect.txt +++ /dev/null @@ -1,34 +0,0 @@ -(import [java.lang.annotation Retention RetentionPolicy Target ElementType] - [javax.xml.ws WebServiceRef WebServiceRefs]) - -(definterface Foo (foo [])) - -;; annotation on type -(deftype ^{Deprecated true - Retention RetentionPolicy/RUNTIME - javax.annotation.processing.SupportedOptions ["foo" "bar" "baz"] - javax.xml.ws.soap.Addressing {:enabled false :required true} - WebServiceRefs [(WebServiceRef {:name "fred" :type String}) - (WebServiceRef {:name "ethel" :mappedName "lucy"})]} - Bar [^int a - ;; on field - ^{:tag int - Deprecated true - Retention RetentionPolicy/RUNTIME - javax.annotation.processing.SupportedOptions ["foo" "bar" "baz"] - javax.xml.ws.soap.Addressing {:enabled false :required true} - WebServiceRefs [(WebServiceRef {:name "fred" :type String}) - (WebServiceRef {:name "ethel" :mappedName "lucy"})]} - b] - ;; on method - Foo (^{Deprecated true - Retention RetentionPolicy/RUNTIME - javax.annotation.processing.SupportedOptions ["foo" "bar" "baz"] - javax.xml.ws.soap.Addressing {:enabled false :required true} - WebServiceRefs [(WebServiceRef {:name "fred" :type String}) - (WebServiceRef {:name "ethel" :mappedName "lucy"})]} - foo [this] 42)) - -(seq (.getAnnotations Bar)) -(seq (.getAnnotations (.getField Bar "b"))) -(seq (.getAnnotations (.getMethod Bar "foo" nil))) diff --git a/test/markup/clojure/hint_col.txt b/test/markup/clojure/hint_col.txt deleted file mode 100644 index 9584dec9d0..0000000000 --- a/test/markup/clojure/hint_col.txt +++ /dev/null @@ -1,34 +0,0 @@ -(import [java.lang.annotation Retention RetentionPolicy Target ElementType] - [javax.xml.ws WebServiceRef WebServiceRefs]) - -(definterface Foo (foo [])) - -;; annotation on type -(deftype ^{Deprecated true - Retention RetentionPolicy/RUNTIME - javax.annotation.processing.SupportedOptions ["foo" "bar" "baz"] - javax.xml.ws.soap.Addressing {:enabled false :required true} - WebServiceRefs [(WebServiceRef {:name "fred" :type String}) - (WebServiceRef {:name "ethel" :mappedName "lucy"})]} - Bar [^int a - ;; on field - ^{:tag int - Deprecated true - Retention RetentionPolicy/RUNTIME - javax.annotation.processing.SupportedOptions ["foo" "bar" "baz"] - javax.xml.ws.soap.Addressing {:enabled false :required true} - WebServiceRefs [(WebServiceRef {:name "fred" :type String}) - (WebServiceRef {:name "ethel" :mappedName "lucy"})]} - b] - ;; on method - Foo (^{Deprecated true - Retention RetentionPolicy/RUNTIME - javax.annotation.processing.SupportedOptions ["foo" "bar" "baz"] - javax.xml.ws.soap.Addressing {:enabled false :required true} - WebServiceRefs [(WebServiceRef {:name "fred" :type String}) - (WebServiceRef {:name "ethel" :mappedName "lucy"})]} - foo [this] 42)) - -(seq (.getAnnotations Bar)) -(seq (.getAnnotations (.getField Bar "b"))) -(seq (.getAnnotations (.getMethod Bar "foo" nil))) diff --git a/test/markup/clojure/number.expect.txt b/test/markup/clojure/number.expect.txt new file mode 100644 index 0000000000..25bb636d60 --- /dev/null +++ b/test/markup/clojure/number.expect.txt @@ -0,0 +1,69 @@ +; integer +00 +42 ++42 +-42 + +; BigInt +42N +0N ++42N +-42N + +; octal +052 +00N ++052 +-00N + +; hex +0x2a +0x0N ++0x2a +-0x0N + +; radix +2r101010 +8r52 +16r2a +36r16 +-2r101010 ++36r16 + +; radix BigInt +2r101010N +8r52N +16r2aN +36r16N ++8r52N +-16r2aN + +;; ratios +1/2 +-1/2 ++123/224 + +;; floats +42.0 +-42.0 ++42.0 +42. ++42. +-42. + +; BigDecimal +42.0M +-42M +42.M +42M + +; with Exponent +42.0E2 +-42.0E+9 +42E-0 ++42E-0 + +42.0E2M +42E+9M +-42E+9M ++42.0E2M \ No newline at end of file diff --git a/test/markup/clojure/number.txt b/test/markup/clojure/number.txt new file mode 100644 index 0000000000..01a0374c09 --- /dev/null +++ b/test/markup/clojure/number.txt @@ -0,0 +1,69 @@ +; integer +00 +42 ++42 +-42 + +; BigInt +42N +0N ++42N +-42N + +; octal +052 +00N ++052 +-00N + +; hex +0x2a +0x0N ++0x2a +-0x0N + +; radix +2r101010 +8r52 +16r2a +36r16 +-2r101010 ++36r16 + +; radix BigInt +2r101010N +8r52N +16r2aN +36r16N ++8r52N +-16r2aN + +;; ratios +1/2 +-1/2 ++123/224 + +;; floats +42.0 +-42.0 ++42.0 +42. ++42. +-42. + +; BigDecimal +42.0M +-42M +42.M +42M + +; with Exponent +42.0E2 +-42.0E+9 +42E-0 ++42E-0 + +42.0E2M +42E+9M +-42E+9M ++42.0E2M \ No newline at end of file diff --git a/test/markup/clojure/symbols-numbers.expect.txt b/test/markup/clojure/symbols-numbers.expect.txt index 87595d111b..2808223dcc 100644 --- a/test/markup/clojure/symbols-numbers.expect.txt +++ b/test/markup/clojure/symbols-numbers.expect.txt @@ -1 +1,4 @@ (def +x [(a 1) +2 -3.0 y-5]) +(System/getProperty "java.vm.version") +(.getEnclosingClass java.util.Map$Entry) +(java.util.Map$Entry. .getEnclosingClass) \ No newline at end of file diff --git a/test/markup/clojure/symbols-numbers.txt b/test/markup/clojure/symbols-numbers.txt index 01e839b555..97c92bb562 100644 --- a/test/markup/clojure/symbols-numbers.txt +++ b/test/markup/clojure/symbols-numbers.txt @@ -1 +1,4 @@ (def +x [(a 1) +2 -3.0 y-5]) +(System/getProperty "java.vm.version") +(.getEnclosingClass java.util.Map$Entry) +(java.util.Map$Entry. .getEnclosingClass) \ No newline at end of file diff --git a/test/markup/cpp/bugs.expect.txt b/test/markup/cpp/bugs.expect.txt new file mode 100644 index 0000000000..08e8689dfc --- /dev/null +++ b/test/markup/cpp/bugs.expect.txt @@ -0,0 +1,6 @@ +//4. 对角矩阵 +//4.1 构造对角矩阵 +Eigen::VectorXd vector(5); //构建5维向量 +vector<<1,2,3,4,5; //向量赋值 +Eigen::MatrixXd C(vector.asDiagonal()); //使用向量生成对角阵 +std::cout << "\nC= \n" << C << std::endl; diff --git a/test/markup/cpp/bugs.txt b/test/markup/cpp/bugs.txt new file mode 100644 index 0000000000..00c4281821 --- /dev/null +++ b/test/markup/cpp/bugs.txt @@ -0,0 +1,6 @@ +//4. 对角矩阵 +//4.1 构造对角矩阵 +Eigen::VectorXd vector(5); //构建5维向量 +vector<<1,2,3,4,5; //向量赋值 +Eigen::MatrixXd C(vector.asDiagonal()); //使用向量生成对角阵 +std::cout << "\nC= \n" << C << std::endl; diff --git a/test/markup/fsharp/attributes.expect.txt b/test/markup/fsharp/attributes.expect.txt index 8543437864..5fb83bfcf3 100644 --- a/test/markup/fsharp/attributes.expect.txt +++ b/test/markup/fsharp/attributes.expect.txt @@ -1,4 +1,4 @@ // Strings and numbers are highlighted inside the attribute -[<Foo>] -[<Bar("bar"); Foo(1, 2)>] -let x () = () \ No newline at end of file +[<Foo>] +[<Bar("bar"); Foo(1, 2)>] +let x () = () \ No newline at end of file diff --git a/test/markup/fsharp/bang-keywords.expect.txt b/test/markup/fsharp/bang-keywords.expect.txt index 56aa58dc26..f681697fdf 100644 --- a/test/markup/fsharp/bang-keywords.expect.txt +++ b/test/markup/fsharp/bang-keywords.expect.txt @@ -1 +1 @@ -let! (result2 : byte[]) = stream.AsyncRead(bufferSize) +let! (result2 : byte[]) = stream.AsyncRead(bufferSize) diff --git a/test/markup/fsharp/bang-keywords.txt b/test/markup/fsharp/bang-keywords.txt index 5824ca88db..796afd6609 100644 --- a/test/markup/fsharp/bang-keywords.txt +++ b/test/markup/fsharp/bang-keywords.txt @@ -1 +1 @@ -let! (result2 : byte[]) = stream.AsyncRead(bufferSize) +let! (result2 : byte[]) = stream.AsyncRead(bufferSize) diff --git a/test/markup/fsharp/comments.expect.txt b/test/markup/fsharp/comments.expect.txt index bd0f7d6a23..7d71bcbd14 100644 --- a/test/markup/fsharp/comments.expect.txt +++ b/test/markup/fsharp/comments.expect.txt @@ -14,12 +14,12 @@ asdf *) -let index = +let index = len - |> float - |> Operators.(*) 0.1 // (*) here is not comment - |> Operators.(+) 1 // (+) here is not comment - |> Operators.(-) len // (-) here is not comment + |> float + |> Operators.(*) 0.1 // (*) here is not comment + |> Operators.(+) 1 // (+) here is not comment + |> Operators.(-) len // (-) here is not comment // foobar @@ -34,11 +34,11 @@ asdf /// Longer comments can be associated with a type or member through /// the remarks tag. /// </remarks> -let x = () +let x = () // the next one is not a comment -(*) (*) +(*) (*) -/* +/* this one is not a valid comment either -*/ \ No newline at end of file +*/ \ No newline at end of file diff --git a/test/markup/fsharp/computation-expressions.expect.txt b/test/markup/fsharp/computation-expressions.expect.txt index a78a366724..af296f3f2c 100644 --- a/test/markup/fsharp/computation-expressions.expect.txt +++ b/test/markup/fsharp/computation-expressions.expect.txt @@ -3,21 +3,21 @@ open System.Threading.Tasks // Single line, and contains a capital letter -let unitTask = unitTask { return () } +let unitTask = unitTask { return () } -let work = +let work = async { - let delayTask () = + let delayTask () = // Nested computation task { printfn "Delay..." do! Task.Delay 1000 return 42 } - let! result = delayTask () |> Async.AwaitTask + let! result = delayTask () |> Async.AwaitTask printfn "Async F# sleep..." do! Async.Sleep 1000 return result } -let result = work |> Async.RunSynchronously \ No newline at end of file +let result = work |> Async.RunSynchronously diff --git a/test/markup/fsharp/fsi-and-preprocessor.expect.txt b/test/markup/fsharp/fsi-and-preprocessor.expect.txt index 6889c0e9ef..181ff72bfb 100644 --- a/test/markup/fsharp/fsi-and-preprocessor.expect.txt +++ b/test/markup/fsharp/fsi-and-preprocessor.expect.txt @@ -7,7 +7,7 @@ #nowarn #if DEBUG // whitespace is allowed before -let x = 0 #if DEBUG // but the preprocessor directive must be the first non-whitespace +let x = 0 #if DEBUG // but the preprocessor directive must be the first non-whitespace #IF asdf // should not match wrongly cased keywords #iftest // should not match @@ -15,8 +15,8 @@ #r "file.dll";; // Reference (dynamically load) the given DLL #i "package source uri";; // Include package source uri when searching for packages #I "path";; // Add the given search path for referenced DLLs -#load "file.fs" ...;; // Load the given file(s) as if compiled and referenced -#time ["on"|"off"];; // Toggle timing on/off +#load "file.fs" ...;; // Load the given file(s) as if compiled and referenced +#time ["on"|"off"];; // Toggle timing on/off #help;; // Display help #r "nuget:FSharp.Data, 3.1.2";; // Load Nuget Package 'FSharp.Data' version '3.1.2' #r "nuget:FSharp.Data";; // Load Nuget Package 'FSharp.Data' with the highest version diff --git a/test/markup/fsharp/generic-types.expect.txt b/test/markup/fsharp/generic-types.expect.txt deleted file mode 100644 index e1a5aa0414..0000000000 --- a/test/markup/fsharp/generic-types.expect.txt +++ /dev/null @@ -1,43 +0,0 @@ -// Primarily testing for generic parameters highlighting... - -type Ref<'a> = -{ mutable contents: 'a } - -type Bla<'a> = {X: string} -type Blah< - 'a - > = { x: 'a } -type Blah < - 'a - > = { x: 'a } -type Bla <'a> = {X: string} -let inline asdf x: Bla<'a> = {X = ""} - -let inline asdf x: Bla<^a> = {X = ""} -let inline asdf x: Bla< ^a > = {X = ""} - -let genericSumUnits ( x : float<'u>) (y: float<'u>) = x + y - -let inline konst x _ = x - -type CFunctor() = - static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a - static member inline fmap (f: ^a -> ^b, a: ^a option) = - match a with - | None -> None - | Some x -> Some (f x) - - // default implementation of replace - static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) = - ((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f)) - - // call overridden replace if present - static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) = - (^b : (static member replace: ^a * ^b -> ^c) (a, f)) - -let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) = - ((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f)) - -// Note the concrete type 'CFunctor' specified in the signature -let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or ^b): (static member replace: ^a * ^b -> ^a0) = - replace_instance<CFunctor, _, _, _> (a, f) \ No newline at end of file diff --git a/test/markup/fsharp/generic-types.txt b/test/markup/fsharp/generic-types.txt deleted file mode 100644 index a700edc5be..0000000000 --- a/test/markup/fsharp/generic-types.txt +++ /dev/null @@ -1,43 +0,0 @@ -// Primarily testing for generic parameters highlighting... - -type Ref<'a> = -{ mutable contents: 'a } - -type Bla<'a> = {X: string} -type Blah< - 'a - > = { x: 'a } -type Blah < - 'a - > = { x: 'a } -type Bla <'a> = {X: string} -let inline asdf x: Bla<'a> = {X = ""} - -let inline asdf x: Bla<^a> = {X = ""} -let inline asdf x: Bla< ^a > = {X = ""} - -let genericSumUnits ( x : float<'u>) (y: float<'u>) = x + y - -let inline konst x _ = x - -type CFunctor() = - static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a - static member inline fmap (f: ^a -> ^b, a: ^a option) = - match a with - | None -> None - | Some x -> Some (f x) - - // default implementation of replace - static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) = - ((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f)) - - // call overridden replace if present - static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) = - (^b : (static member replace: ^a * ^b -> ^c) (a, f)) - -let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) = - ((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f)) - -// Note the concrete type 'CFunctor' specified in the signature -let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or ^b): (static member replace: ^a * ^b -> ^a0) = - replace_instance (a, f) \ No newline at end of file diff --git a/test/markup/fsharp/numbers.expect.txt b/test/markup/fsharp/numbers.expect.txt index 2fa768f80d..77a1bd63d3 100644 --- a/test/markup/fsharp/numbers.expect.txt +++ b/test/markup/fsharp/numbers.expect.txt @@ -31,10 +31,10 @@ 9999999999999999999999999999I // Distance, meters. -[<Measure>] type m +[<Measure>] type m // Time, seconds. -[<Measure>] type s +[<Measure>] type s -let v1 = 3.1<m/s> -let x1 = 1.2<m> -let t1 = 1.0<s> \ No newline at end of file +let v1 = 3.1<m/s> +let x1 = 1.2<m> +let t1 = 1.0<s> \ No newline at end of file diff --git a/test/markup/fsharp/operators.expect.txt b/test/markup/fsharp/operators.expect.txt index 188baa2275..ac71ba62f3 100644 --- a/test/markup/fsharp/operators.expect.txt +++ b/test/markup/fsharp/operators.expect.txt @@ -1,28 +1,77 @@ - >= <= <> > < = + - * / % - >=? <=? <>? >? <? =? +? -? *? /? %? -?>=? ?<=? ?<>? ?>? ?<? ?=? ?+? ?-? ?*? ?/? ?%? -?>= ?<= ?<> ?> ?< ?= ?+ ?- ?* ?/ ?% - -** - -<- -> -.. -:: -:> :? :?> -<< >> -<<< >>> ~~~ ^^^ &&& ||| -| || -<| <|| <||| -|> ||> |||> -~~ ~- ~+ - -? ^ ! -!= == -& && + >= <= <> > < = + - * / % + >=? <=? <>? >? <? =? +? -? *? /? %? +?>=? ?<=? ?<>? ?>? ?<? ?=? ?+? ?-? ?*? ?/? ?%? +?>= ?<= ?<> ?> ?< ?= ?+ ?- ?* ?/ ?% + +** + +<- -> +.. +:: +:> :? :?> +<< >> +<<< >>> ~~~ ^^^ &&& ||| +| || +<| <|| <||| +|> ||> |||> +~~ ~- ~+ + +? ^ ! +!= == +& && + +let array = [| 0 |] +let anonymousRecord = {| x = 42 |} +let range = [ for i in 0..10 -> i ] + +// Custom operators + +let inline (+?) (x: int) (y: int) = x + 2*y +printf "%d" (10 +? 1) + +let inline (<!>) (f: 'T->'U) (x: '``Functor<'T>``) : '``Functor<'U>`` = Map.Invoke f x + +let inline (<<|) (f: 'T->'U) (x: '``Functor<'T>``) : '``Functor<'U>`` = Map.Invoke f x + +let inline (|>>) (x: '``Functor<'T>``) (f: 'T->'U) : '``Functor<'U>`` = Map.Invoke f x + +let inline (<*>) (f: '``Applicative<'T -> 'U>``) (x: '``Applicative<'T>``) : '``Applicative<'U>`` = Apply.Invoke f x + +let inline ( *>) (x: '``Applicative<'T>``) (y: '``Applicative<'U>``) : '``Applicative<'U>`` = ((fun (_: 'T) (k: 'U) -> k) <!> x : '``Applicative<'U->'U>``) <*> y + +let inline (<* ) (x: '``Applicative<'U>``) (y: '``Applicative<'T>``): '``Applicative<'U>`` = ((fun (k: 'U) (_: 'T) -> k ) <!> x : '``Applicative<'T->'U>``) <*> y + +let inline (<**>) (x: '``Applicative<'T>``) : '``Applicative<'T -> 'U>``->'``Applicative<'U>`` = flip (<*>) x + +let inline (>>=) (x: '``Monad<'T>``) (f: 'T->'``Monad<'U>``) : '``Monad<'U>`` = Bind.Invoke x f + +let inline (=<<) (f: 'T->'``Monad<'U>``) (x: '``Monad<'T>``) : '``Monad<'U>`` = Bind.Invoke x f + +let inline (>=>) (f: 'T->'``Monad<'U>``) (g: 'U->'``Monad<'V>``) : 'T -> '``Monad<'V>`` = fun x -> Bind.Invoke (f x) g + +let inline (<=<) (g: 'b->'``Monad<'V>``) (f: 'T->'``Monad<'U>``) : 'T -> '``Monad<'V>`` = fun x -> Bind.Invoke (f x) g + +let inline (++) (x: 'Monoid) (y: 'Monoid) : 'Monoid = Plus.Invoke x y + +let inline (<|>) (x: '``Functor<'T>``) (y: '``Functor<'T>``) : '``Functor<'T>`` = Append.Invoke x y + +let inline (=>>) (s: '``Comonad<'T>``) (g: '``Comonad<'T>``->'U) : '``Comonad<'U>`` = Extend.Invoke g s + +// Code quotation open Microsoft.FSharp.Quotations // A typed code quotation. -let expr : Expr<int> = <@ 1 + 1 @> +let expr : Expr<int> = <@ 1 + 1 @> // An untyped code quotation. -let expr2 : Expr = <@@ 1 + 1 @@> \ No newline at end of file +let expr2 : Expr = <@@ 1 + 1 @@> + +// Active patterns + +let (|Integer|_|) (str: string) = + let mutable intvalue = 0 + if System.Int32.TryParse(str, &intvalue) then Some(intvalue) + else None + +let (|Even|Odd|) input = if input % 2 = 0 then Even else Odd +// \ No newline at end of file diff --git a/test/markup/fsharp/operators.txt b/test/markup/fsharp/operators.txt index 97272294f8..503eb76295 100644 --- a/test/markup/fsharp/operators.txt +++ b/test/markup/fsharp/operators.txt @@ -21,8 +21,57 @@ != == & && +let array = [| 0 |] +let anonymousRecord = {| x = 42 |} +let range = [ for i in 0..10 -> i ] + +// Custom operators + +let inline (+?) (x: int) (y: int) = x + 2*y +printf "%d" (10 +? 1) + +let inline () (f: 'T->'U) (x: '``Functor<'T>``) : '``Functor<'U>`` = Map.Invoke f x + +let inline (<<|) (f: 'T->'U) (x: '``Functor<'T>``) : '``Functor<'U>`` = Map.Invoke f x + +let inline (|>>) (x: '``Functor<'T>``) (f: 'T->'U) : '``Functor<'U>`` = Map.Invoke f x + +let inline (<*>) (f: '``Applicative<'T -> 'U>``) (x: '``Applicative<'T>``) : '``Applicative<'U>`` = Apply.Invoke f x + +let inline ( *>) (x: '``Applicative<'T>``) (y: '``Applicative<'U>``) : '``Applicative<'U>`` = ((fun (_: 'T) (k: 'U) -> k) x : '``Applicative<'U->'U>``) <*> y + +let inline (<* ) (x: '``Applicative<'U>``) (y: '``Applicative<'T>``): '``Applicative<'U>`` = ((fun (k: 'U) (_: 'T) -> k ) x : '``Applicative<'T->'U>``) <*> y + +let inline (<**>) (x: '``Applicative<'T>``) : '``Applicative<'T -> 'U>``->'``Applicative<'U>`` = flip (<*>) x + +let inline (>>=) (x: '``Monad<'T>``) (f: 'T->'``Monad<'U>``) : '``Monad<'U>`` = Bind.Invoke x f + +let inline (=<<) (f: 'T->'``Monad<'U>``) (x: '``Monad<'T>``) : '``Monad<'U>`` = Bind.Invoke x f + +let inline (>=>) (f: 'T->'``Monad<'U>``) (g: 'U->'``Monad<'V>``) : 'T -> '``Monad<'V>`` = fun x -> Bind.Invoke (f x) g + +let inline (<=<) (g: 'b->'``Monad<'V>``) (f: 'T->'``Monad<'U>``) : 'T -> '``Monad<'V>`` = fun x -> Bind.Invoke (f x) g + +let inline (++) (x: 'Monoid) (y: 'Monoid) : 'Monoid = Plus.Invoke x y + +let inline (<|>) (x: '``Functor<'T>``) (y: '``Functor<'T>``) : '``Functor<'T>`` = Append.Invoke x y + +let inline (=>>) (s: '``Comonad<'T>``) (g: '``Comonad<'T>``->'U) : '``Comonad<'U>`` = Extend.Invoke g s + +// Code quotation + open Microsoft.FSharp.Quotations // A typed code quotation. let expr : Expr = <@ 1 + 1 @> // An untyped code quotation. let expr2 : Expr = <@@ 1 + 1 @@> + +// Active patterns + +let (|Integer|_|) (str: string) = + let mutable intvalue = 0 + if System.Int32.TryParse(str, &intvalue) then Some(intvalue) + else None + +let (|Even|Odd|) input = if input % 2 = 0 then Even else Odd +// \ No newline at end of file diff --git a/test/markup/fsharp/strings.expect.txt b/test/markup/fsharp/strings.expect.txt index fad7761fa2..75e6ceaf31 100644 --- a/test/markup/fsharp/strings.expect.txt +++ b/test/markup/fsharp/strings.expect.txt @@ -26,7 +26,7 @@ bar""" '\u0041' '\U0001F47D' -$"{1+1}" +$"{1+1}" "" // end "fo\"o" // end @@ -53,7 +53,7 @@ bar""" // end '\u0041' // end '\U0001F47D' // end -$"{1+1}" // end +$"{1+1}" // end 0 "string \'" // end @@ -71,15 +71,15 @@ string" // end string""" // end 5 $"interpola\ {{ -ted \' {1 + 1 // can contain comments and " in placeholders +ted \' {1 + 1 // can contain comments and " in placeholders }string" // end 6 $@"interpolated "" \' {{ -verbatim{1 + 1 // can contain comments and " in placeholders +verbatim{1 + 1 // can contain comments and " in placeholders }string" // end 7 @$"interpolated "" \' {{ -verbatim{1 + 1 // can contain comments and " in placeholders +verbatim{1 + 1 // can contain comments and " in placeholders }string" // end 8 $"""interpolated triple quoted " \' {{ { (sprintf "%d%s" 42) @@ -88,15 +88,15 @@ verbatim{1 + 9 $"""test { @"{it's not a placeholder!}" } asdf""" // end 10 -$"""test { $"but this is:{1+1}" } asdf""" // end +$"""test { $"but this is:{1+1}" } asdf""" // end 11 $"interpola\ {{ -ted \' {1 + 1 // can contain comments in placeholders +ted \' {1 + 1 // can contain comments in placeholders // placeholders cannot contain " }string" // end 12 $@"interpolated "" \' {{ -verbatim{1 + 1 // can contain comments in placeholders +verbatim{1 + 1 // can contain comments in placeholders // placeholders cannot contain " }string" // end 13 @@ -104,14 +104,14 @@ verbatim{1 + // and comments... }string""" // end 14 -let list = [1] -$"""test{ list |> List.map (fun x -> x + 1) }test""" // end +let list = [1] +$"""test{ list |> List.map (fun x -> x + 1) }test""" // end 15 $"test{1 (* " Does it break the string? " *) }test" // end 16 $"test\ { - let x = 42 // valid comment contains " quote " ... + let x = 42 // valid comment contains " quote " ... x (* " Does it break the string? " *) }test" // end 17 @@ -119,18 +119,18 @@ verbatim{1 + { #if DEBUG #endif - let asdf = "}" // """ does it break? - let x = $@"test{2+2 (* " what about double nesting? " *) }test" - let lit = 0 - let x = unitTask { return () } + let asdf = "}" // """ does it break? + let x = $@"test{2+2 (* " what about double nesting? " *) }test" + let lit = 0 + let x = unitTask { return () } asdf }test""" 18 -let list = [1] +let list = [1] $"""test { - let asdf = "}" - list |> List.map (fun x -> x + 1) + let asdf = "}" + list |> List.map (fun x -> x + 1) }test""" // end 19 \ No newline at end of file diff --git a/test/markup/fsharp/types.expect.txt b/test/markup/fsharp/types.expect.txt new file mode 100644 index 0000000000..e48881af06 --- /dev/null +++ b/test/markup/fsharp/types.expect.txt @@ -0,0 +1,143 @@ +// Testing type definition and type annotation highlighting: + +let test'test = 15 // compiles +let bla = test'test // compiles +type test'test<'a> = Test<'a> // compiles + +let ``type`` = "hello" // compiles +let ``type` is a keyword but I can use it in my 'd funky \ \\ \n " ^d binding`` = "hello" // compiles + +// Type names (here with char) can be used to redefine bindings: +let char : char = + let char = box (char "a") + let result = unbox<char> char + try () + with | :? ArgumentException -> failwith "..." + result + +// All the following type annotation examples are valid F# +type ``my = type`` = {a:string} +let x : char array = [|'a'|] +let f f' = f' () : 'returnType // the type annotation should end now +and not color this as a type. let's end this with an end pattern: = +let f (a: int, (b: string)) = () +let f (a: int, b: string) = () +let anonymousRecordAnnotation : {| X: string; Y: int array * string |} = ... +let nested : {| X: string; Y: {| Nested: bool |} |} = () +let test (a: {| X: string; (* this is a comment *) Y: {| Nested: bool |} |}) = () +let f (a: (string[])) = a +let f (a: int -> (unit -> string) -> string) (b: ('a -> 'b -> _ -> ``my = type`` -> {| Prop: '``quoted``|}) -> 'a list -> 'b list) = a +let f (a: ('a -> 'b) -> 'a list -> 'b list -> (unit -> string) -> {| X: string |}) : _ * (int -> unit) = a, (fun x -> ()) +let f (a: ('a -> 'b) // multiline! (currently not supported) + -> {| X: (int -> {| Y: (string -> (unit (*this is getting*))(*really nested...*)); A: ``my = type`` |}) |} + -> 'b list -> (unit -> string) -> {| X: string |}) = a +let test : string (* this is a comment *) = ... +let f (a: 'a when 'a : null, b: string) = () +let iterate2 (f : unit -> #seq<int>) = + for e in f() do printfn "%d" e +type record = + { X: int -> ('a -> 'b) -> (unit -> string) -> 'a list -> 'b list // comment + Y: {| Bla: string (*comment*) array -> unit |} } +type record = + { X: string // comment + Y: {| + Bla: string (*comment*) array + -> unit |} } + +type FancyClass(thing:int, var2 : string -> string, ``ddzdz``: string list, extra) as xxx = + + let pf() = xxx.Test() + let mutable myInternalValue = null + + member xxx.Test() = "F#" + + // A read-only property. + member __.MyReadOnlyProperty = myInternalValue + // A write-only property. + member __.MyWriteOnlyProperty with set (value) = myInternalValue <- value + // A read-write property. + member __.MyReadWriteProperty + with get () = myInternalValue + and set (value) = myInternalValue <- value + + member __.ReadAndWriteWithSignature + with get (count : int) : string = string count + and set (value : int) : unit = failwith "" + + member __.MyReadWriteProperty with get () = myInternalValue + member __.MyReadWriteProperty with set (value) = myInternalValue <- value + + abstract Update : int * string * string option * obj -> FancyClass + default this.Update (thing:int, var2 : string, ``name with spaces``: string option, extra) = this + + member val Property1 = thing + member val Property2 = "" with get, set + +// Testing for generic parameters highlighting: + +type Ref<'a> = +{ mutable contents: 'a } + +type Bla<'a> = {X: string} +type Blah< + 'a + > = { x: 'a } +type Blah < + 'a + > = { x: 'a } +type Bla <'a> = {X: string} +let inline asdf x: Bla<'a> = {X = ""} + +let inline asdf x: Bla<^a> = {X = ""} +let inline asdf x: Bla< ^a > = {X = ""} + +let a : '``asdf``_asdf = () // This is not valid and should not be parsed as a single generic type symbol + +type MyType<'T when 'T : null> = ... +type MyType<'T when 'T : unmanaged> = ... +type MyType<'T when 'T : (member Method1 : 'T -> int)> = ... +type MyType<'T when 'T : delegate<obj * System.EventArgs, unit>> = ... + +let genericSumUnits ( x : float<'u>) (y: float<'u>) = x + y + +let inline konst x _ = x + +type CFunctor() = + static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a + static member inline fmap (f: ^a -> ^b, a: ^a option) = + match a with + | None -> None + | Some x -> Some (f x) + + // default implementation of replace + static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) = + ((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f)) + + // call overridden replace if present + static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) = + (^b : (static member replace: ^a * ^b -> ^c) (a, f)) + +let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) = + ((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f)) + +// Note the concrete type 'CFunctor' specified in the signature +let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or ^b): (static member replace: ^a * ^b -> ^a0) = + replace_instance<CFunctor, _, _, _> (a, f) + +type DUType = + | CaseA + | CaseB of int + | CaseC of (int * (string * string) list) + | CaseD of name :string * age:int + | CaseE of client: Client + | CaseF of client: Client (*comment tests*) * (*comment tests*) string * port : int + | CaseG of (obj -> unit) + | CaseH of string * (obj -> unit) + // Check multiple declaration on one line + | CaseI of int | CaseJ of int + | CaseF2 of client: Client // * string * port : int + | FetchDomainsSuccess of Result<int list * ``type with spaces`` * int, ``type * with * spaces``> + | CaseK of ``var with spaces``: string + | CaseL of ``var with spaces``: ``type with spaces`` + | CaseM of v1 : ``type with spaces`` + | CaseN of ``type with spaces`` diff --git a/test/markup/fsharp/types.txt b/test/markup/fsharp/types.txt new file mode 100644 index 0000000000..490afa4e46 --- /dev/null +++ b/test/markup/fsharp/types.txt @@ -0,0 +1,143 @@ +// Testing type definition and type annotation highlighting: + +let test'test = 15 // compiles +let bla = test'test // compiles +type test'test<'a> = Test<'a> // compiles + +let ``type`` = "hello" // compiles +let ``type` is a keyword but I can use it in my 'd funky \ \\ \n " ^d binding`` = "hello" // compiles + +// Type names (here with char) can be used to redefine bindings: +let char : char = + let char = box (char "a") + let result = unbox char + try () + with | :? ArgumentException -> failwith "..." + result + +// All the following type annotation examples are valid F# +type ``my = type`` = {a:string} +let x : char array = [|'a'|] +let f f' = f' () : 'returnType // the type annotation should end now +and not color this as a type. let's end this with an end pattern: = +let f (a: int, (b: string)) = () +let f (a: int, b: string) = () +let anonymousRecordAnnotation : {| X: string; Y: int array * string |} = ... +let nested : {| X: string; Y: {| Nested: bool |} |} = () +let test (a: {| X: string; (* this is a comment *) Y: {| Nested: bool |} |}) = () +let f (a: (string[])) = a +let f (a: int -> (unit -> string) -> string) (b: ('a -> 'b -> _ -> ``my = type`` -> {| Prop: '``quoted``|}) -> 'a list -> 'b list) = a +let f (a: ('a -> 'b) -> 'a list -> 'b list -> (unit -> string) -> {| X: string |}) : _ * (int -> unit) = a, (fun x -> ()) +let f (a: ('a -> 'b) // multiline! (currently not supported) + -> {| X: (int -> {| Y: (string -> (unit (*this is getting*))(*really nested...*)); A: ``my = type`` |}) |} + -> 'b list -> (unit -> string) -> {| X: string |}) = a +let test : string (* this is a comment *) = ... +let f (a: 'a when 'a : null, b: string) = () +let iterate2 (f : unit -> #seq) = + for e in f() do printfn "%d" e +type record = + { X: int -> ('a -> 'b) -> (unit -> string) -> 'a list -> 'b list // comment + Y: {| Bla: string (*comment*) array -> unit |} } +type record = + { X: string // comment + Y: {| + Bla: string (*comment*) array + -> unit |} } + +type FancyClass(thing:int, var2 : string -> string, ``ddzdz``: string list, extra) as xxx = + + let pf() = xxx.Test() + let mutable myInternalValue = null + + member xxx.Test() = "F#" + + // A read-only property. + member __.MyReadOnlyProperty = myInternalValue + // A write-only property. + member __.MyWriteOnlyProperty with set (value) = myInternalValue <- value + // A read-write property. + member __.MyReadWriteProperty + with get () = myInternalValue + and set (value) = myInternalValue <- value + + member __.ReadAndWriteWithSignature + with get (count : int) : string = string count + and set (value : int) : unit = failwith "" + + member __.MyReadWriteProperty with get () = myInternalValue + member __.MyReadWriteProperty with set (value) = myInternalValue <- value + + abstract Update : int * string * string option * obj -> FancyClass + default this.Update (thing:int, var2 : string, ``name with spaces``: string option, extra) = this + + member val Property1 = thing + member val Property2 = "" with get, set + +// Testing for generic parameters highlighting: + +type Ref<'a> = +{ mutable contents: 'a } + +type Bla<'a> = {X: string} +type Blah< + 'a + > = { x: 'a } +type Blah < + 'a + > = { x: 'a } +type Bla <'a> = {X: string} +let inline asdf x: Bla<'a> = {X = ""} + +let inline asdf x: Bla<^a> = {X = ""} +let inline asdf x: Bla< ^a > = {X = ""} + +let a : '``asdf``_asdf = () // This is not valid and should not be parsed as a single generic type symbol + +type MyType<'T when 'T : null> = ... +type MyType<'T when 'T : unmanaged> = ... +type MyType<'T when 'T : (member Method1 : 'T -> int)> = ... +type MyType<'T when 'T : delegate> = ... + +let genericSumUnits ( x : float<'u>) (y: float<'u>) = x + y + +let inline konst x _ = x + +type CFunctor() = + static member inline fmap (f: ^a -> ^b, a: ^a list) = List.map f a + static member inline fmap (f: ^a -> ^b, a: ^a option) = + match a with + | None -> None + | Some x -> Some (f x) + + // default implementation of replace + static member inline replace< ^a, ^b, ^c, ^d, ^e when ^a :> CFunctor and (^a or ^d): (static member fmap: (^b -> ^c) * ^d -> ^e) > (a, f) = + ((^a or ^d) : (static member fmap : (^b -> ^c) * ^d -> ^e) (konst a, f)) + + // call overridden replace if present + static member inline replace< ^a, ^b, ^c when ^b: (static member replace: ^a * ^b -> ^c)>(a: ^a, f: ^b) = + (^b : (static member replace: ^a * ^b -> ^c) (a, f)) + +let inline replace_instance< ^a, ^b, ^c, ^d when (^a or ^c): (static member replace: ^b * ^c -> ^d)> (a: ^b, f: ^c) = + ((^a or ^c): (static member replace: ^b * ^c -> ^d) (a, f)) + +// Note the concrete type 'CFunctor' specified in the signature +let inline replace (a: ^a) (f: ^b): ^a0 when (CFunctor or ^b): (static member replace: ^a * ^b -> ^a0) = + replace_instance (a, f) + +type DUType = + | CaseA + | CaseB of int + | CaseC of (int * (string * string) list) + | CaseD of name :string * age:int + | CaseE of client: Client + | CaseF of client: Client (*comment tests*) * (*comment tests*) string * port : int + | CaseG of (obj -> unit) + | CaseH of string * (obj -> unit) + // Check multiple declaration on one line + | CaseI of int | CaseJ of int + | CaseF2 of client: Client // * string * port : int + | FetchDomainsSuccess of Result + | CaseK of ``var with spaces``: string + | CaseL of ``var with spaces``: ``type with spaces`` + | CaseM of v1 : ``type with spaces`` + | CaseN of ``type with spaces`` diff --git a/test/markup/groovy/default.expect.txt b/test/markup/groovy/default.expect.txt index 5962db4897..acaa4cc323 100644 --- a/test/markup/groovy/default.expect.txt +++ b/test/markup/groovy/default.expect.txt @@ -4,15 +4,15 @@ import groovy.transform.CompileStatic import java.util.List as MyList -trait Distributable { - void distribute(String version) {} +trait Distributable { + void distribute(String version) {} } @CompileStatic -class Distribution implements Distributable { - double number = 1234.234 / 567 +class Distribution implements Distributable { + double number = 1234.234 / 567 def otherNumber = 3 / 4 - boolean archivable = condition ?: true + boolean archivable = condition ?: true def ternary = a ? b : c String name = "Guillaume" Closure description = null @@ -30,9 +30,9 @@ * description method * @param cl the closure */ - void description(Closure cl) { this.description = cl } + void description(Closure cl) { this.description = cl } - void version(String name, Closure versionSpec) { + void version(String name, Closure versionSpec) { def closure = { println "hi" } as Runnable MyList ml = [1, 2, [a: 1, b:2,c :3]] diff --git a/test/markup/java/titles.expect.txt b/test/markup/java/titles.expect.txt index 571bd0fe51..2043511c9a 100644 --- a/test/markup/java/titles.expect.txt +++ b/test/markup/java/titles.expect.txt @@ -8,3 +8,11 @@ } } } + +sealed interface Command permits LoginCommand { + void run(); +} + +non-sealed abstract class UserPluginCommand extends Command { + void runAsUser(); +} diff --git a/test/markup/java/titles.txt b/test/markup/java/titles.txt index c43f696c92..a4d553fbb6 100644 --- a/test/markup/java/titles.txt +++ b/test/markup/java/titles.txt @@ -8,3 +8,11 @@ public class Greet { } } } + +sealed interface Command permits LoginCommand { + void run(); +} + +non-sealed abstract class UserPluginCommand extends Command { + void runAsUser(); +} diff --git a/test/markup/javascript/class.expect.txt b/test/markup/javascript/class.expect.txt index 3ef253c364..7e1dd67c80 100644 --- a/test/markup/javascript/class.expect.txt +++ b/test/markup/javascript/class.expect.txt @@ -33,3 +33,8 @@ CSSParser Float32Array BigInt64Array +FPs +OutT +InT +CSSParserT +IResponseTsS diff --git a/test/markup/javascript/class.txt b/test/markup/javascript/class.txt index bebfe77f90..4badef7377 100644 --- a/test/markup/javascript/class.txt +++ b/test/markup/javascript/class.txt @@ -33,3 +33,8 @@ SelfDrivingTruck CSSParser Float32Array BigInt64Array +FPs +OutT +InT +CSSParserT +IResponseTsS diff --git a/test/markup/livescript/default.expect.txt b/test/markup/livescript/default.expect.txt index 253ee2843f..bbf6630265 100644 --- a/test/markup/livescript/default.expect.txt +++ b/test/markup/livescript/default.expect.txt @@ -40,7 +40,7 @@ last-three [1 tofunction add x, y @result = x + y -class A +class A (num) -> @x = num property: 1 diff --git a/test/markup/matlab/transpose.expect.txt b/test/markup/matlab/transpose.expect.txt index 996c83bdac..c19049c508 100644 --- a/test/markup/matlab/transpose.expect.txt +++ b/test/markup/matlab/transpose.expect.txt @@ -31,9 +31,9 @@ c2 = {'a',& s = ['a','bc']'; % you can transpose vectors of strings (they are really 'char' arrays) s = s'; % and transpose back % (s')' is a double transpose of a string -x = [(s')', ' xyz ', 'a single quote in a string'', escape \', two quotes in a string''''']; +x = [(s')', ' xyz ', 'a single quote in a string'', two quotes in a string''''']; -s2 = "abc\"def""ghi"; % newer versions of MATLAB support double quoted strings +s2 = "abcdef""ghi"; % newer versions of MATLAB support double quoted strings s3 = (["abc", "defg"]')'; % transpose a vectors of quoted string twice s4 = "abc"!; % transpose a quoted string diff --git a/test/markup/matlab/transpose.txt b/test/markup/matlab/transpose.txt index d1da28e3df..9f69a0cc9f 100644 --- a/test/markup/matlab/transpose.txt +++ b/test/markup/matlab/transpose.txt @@ -31,9 +31,9 @@ c2 = {'a','bc'}'; % transpose of a cell of strings s = ['a','bc']'; % you can transpose vectors of strings (they are really 'char' arrays) s = s'; % and transpose back % (s')' is a double transpose of a string -x = [(s')', ' xyz ', 'a single quote in a string'', escape \', two quotes in a string''''']; +x = [(s')', ' xyz ', 'a single quote in a string'', two quotes in a string''''']; -s2 = "abc\"def""ghi"; % newer versions of MATLAB support double quoted strings +s2 = "abcdef""ghi"; % newer versions of MATLAB support double quoted strings s3 = (["abc", "defg"]')'; % transpose a vectors of quoted string twice s4 = "abc"!; % transpose a quoted string diff --git a/test/markup/monkey/default.expect.txt b/test/markup/monkey/default.expect.txt index 8dfd03e961..5228c24cc4 100644 --- a/test/markup/monkey/default.expect.txt +++ b/test/markup/monkey/default.expect.txt @@ -6,18 +6,18 @@ Import mojo ' The main class which expends Mojo's 'App' class: -Class GameApp Extends App +Class GameApp Extends App Field player:Player - Method OnCreate:Int() + Method OnCreate:Int() Local img:Image = LoadImage("player.png") - Self.player = New Player() + Self.player = New Player() SetUpdateRate(60) Return 0 End - Method OnUpdate:Int() + Method OnUpdate:Int() player.x += HALFPI If (player.x > 100) Then @@ -27,7 +27,7 @@ Return 0 End - Method OnRender:Int() + Method OnRender:Int() Cls(32, 64, 128) player.Draw() diff --git a/test/markup/nsis/default.expect.txt b/test/markup/nsis/default.expect.txt index 9574047d8f..24c8e434a1 100644 --- a/test/markup/nsis/default.expect.txt +++ b/test/markup/nsis/default.expect.txt @@ -32,6 +32,6 @@ ; Functions Function .onInit DetailPrint "The install button reads $(^InstallBtn)" - DetailPrint 'Here comes a$\n$\rline-break!' - DetailPrint `Escape the dollar-sign: $$` + DetailPrint 'Here comes a$\n$\rline-break!' + DetailPrint `Escape the dollar-sign: $$` FunctionEnd diff --git a/test/markup/nsis/variables.expect.txt b/test/markup/nsis/variables.expect.txt new file mode 100644 index 0000000000..7798d8b3d6 --- /dev/null +++ b/test/markup/nsis/variables.expect.txt @@ -0,0 +1,7 @@ +Var CustomVariable +StrCpy $CustomVariable "Hello World" +MessageBox MB_OK "$$CustomVariable is: $CustomVariable" + +Var Variable.With.Dots +StrCpy $Variable.With.Dots "Hello World" +MessageBox MB_OK "$$Variable.With.Dots is: $Variable.With.Dots" diff --git a/test/markup/nsis/variables.txt b/test/markup/nsis/variables.txt new file mode 100644 index 0000000000..a97f06c5ce --- /dev/null +++ b/test/markup/nsis/variables.txt @@ -0,0 +1,7 @@ +Var CustomVariable +StrCpy $CustomVariable "Hello World" +MessageBox MB_OK "$$CustomVariable is: $CustomVariable" + +Var Variable.With.Dots +StrCpy $Variable.With.Dots "Hello World" +MessageBox MB_OK "$$Variable.With.Dots is: $Variable.With.Dots" diff --git a/test/markup/oxygene/default.expect.txt b/test/markup/oxygene/default.expect.txt index ed31804143..187d068e41 100644 --- a/test/markup/oxygene/default.expect.txt +++ b/test/markup/oxygene/default.expect.txt @@ -1,56 +1,56 @@ -namespace LinkedList; +namespace LinkedList; interface uses - System.Text; + System.Text; type List<T> = public class - where T is Object; + where T is Object; private - method AppendToString(aBuilder: StringBuilder); + method AppendToString(aBuilder: StringBuilder); public - constructor(aData: T); - constructor(aData: T; aNext: List<T>); - property Next: List<T>; - property Data: T; + constructor(aData: T); + constructor(aData: T; aNext: List<T>); + property Next: List<T>; + property Data: T; - method ToString: string; override; - end; + method ToString: string; override; + end; implementation -constructor List<T>(aData: T); +constructor List<T>(aData: T); begin - Data := aData; -end; + Data := aData; +end; -constructor List<T>(aData: T; aNext: List<T>); +constructor List<T>(aData: T; aNext: List<T>); begin - constructor(aData); - Next := aNext; -end; + constructor(aData); + Next := aNext; +end; -method List<T>.ToString: string; +method List<T>.ToString: string; begin with lBuilder := new StringBuilder do begin - AppendToString(lBuilder); - result := lBuilder.ToString(); - end; -end; + AppendToString(lBuilder); + result := lBuilder.ToString(); + end; +end; -method List<T>.AppendToString(aBuilder: StringBuilder); +method List<T>.AppendToString(aBuilder: StringBuilder); begin if assigned(Data) then aBuilder.Append(Data.ToString) else - aBuilder.Append('nil'); + aBuilder.Append('nil'); if assigned(Next) then begin - aBuilder.Append(', '); - Next.AppendToString(aBuilder); - end; -end; + aBuilder.Append(', '); + Next.AppendToString(aBuilder); + end; +end; end. diff --git a/test/markup/php/case.expect.txt b/test/markup/php/case.expect.txt new file mode 100644 index 0000000000..e75606fd72 --- /dev/null +++ b/test/markup/php/case.expect.txt @@ -0,0 +1,8 @@ +$test = true +$test = TRUE + +$a = false +$a = FALSE + +$b = null +$b = NULL diff --git a/test/markup/php/case.txt b/test/markup/php/case.txt new file mode 100644 index 0000000000..079112129e --- /dev/null +++ b/test/markup/php/case.txt @@ -0,0 +1,8 @@ +$test = true +$test = TRUE + +$a = false +$a = FALSE + +$b = null +$b = NULL diff --git a/test/markup/php/functions.expect.txt b/test/markup/php/functions.expect.txt index d161e753f4..88c5d94ebe 100644 --- a/test/markup/php/functions.expect.txt +++ b/test/markup/php/functions.expect.txt @@ -6,3 +6,38 @@ $fn2 = function ($x) use ($y) { return $x + $y; }; + +/** + * Function invoke + */ +$date = new DateTimeImmutable (); +$date->format('Y-m-d'); + +DateTimeImmutable::createFromMutable(new \DateTime('now')); + +str_contains (\strtoupper(substr('abcdef', -2), 'f')); + +/** + * Function declaration + */ +function testMe(string|int $name): int +{ + if (empty($name)) { + return 0; + } elseif ($name === 1) { + return (int) $name; + } + + switch($name) { + case '2': + return 2; + default: + throw new \Exception('error'); + } +} + +/** + * First-class Callable Syntax + */ +$fun = mb_strlen(); +$fun(); diff --git a/test/markup/php/functions.txt b/test/markup/php/functions.txt index 2eec171beb..86f7fd48a4 100644 --- a/test/markup/php/functions.txt +++ b/test/markup/php/functions.txt @@ -6,3 +6,38 @@ $fn1 = fn($x) => $x + $y; $fn2 = function ($x) use ($y) { return $x + $y; }; + +/** + * Function invoke + */ +$date = new DateTimeImmutable (); +$date->format('Y-m-d'); + +DateTimeImmutable::createFromMutable(new \DateTime('now')); + +str_contains (\strtoupper(substr('abcdef', -2), 'f')); + +/** + * Function declaration + */ +function testMe(string|int $name): int +{ + if (empty($name)) { + return 0; + } elseif ($name === 1) { + return (int) $name; + } + + switch($name) { + case '2': + return 2; + default: + throw new \Exception('error'); + } +} + +/** + * First-class Callable Syntax + */ +$fun = mb_strlen(); +$fun(); diff --git a/test/markup/php/namespace.expect.txt b/test/markup/php/namespace.expect.txt new file mode 100644 index 0000000000..338c6d38a8 --- /dev/null +++ b/test/markup/php/namespace.expect.txt @@ -0,0 +1,9 @@ +namespace Location\Web; +namespace foo; +use My\Full\Classname as Another; +use My\Full\NSname; +use ArrayObject; +use function My\Full\functionName; +use function My\Full\functionName as func; +use const My\Full\CONSTANT; +use Example\{ClassA, ClassB, ClassC as C}; diff --git a/test/markup/php/namespace.txt b/test/markup/php/namespace.txt new file mode 100644 index 0000000000..c2f16b7f01 --- /dev/null +++ b/test/markup/php/namespace.txt @@ -0,0 +1,9 @@ +namespace Location\Web; +namespace foo; +use My\Full\Classname as Another; +use My\Full\NSname; +use ArrayObject; +use function My\Full\functionName; +use function My\Full\functionName as func; +use const My\Full\CONSTANT; +use Example\{ClassA, ClassB, ClassC as C}; diff --git a/test/markup/php/strings.expect.txt b/test/markup/php/strings.expect.txt index a547757933..8a9c4dd8f5 100644 --- a/test/markup/php/strings.expect.txt +++ b/test/markup/php/strings.expect.txt @@ -12,12 +12,12 @@ MSG); // heredoc syntax -var_dump(<<<SQL +var_dump(<<<SQL SELECT * FROM table SQL); -var_dump(<<<SQL +var_dump(<<<SQL SELECT * FROM table SQL); diff --git a/test/markup/php/titles.expect.txt b/test/markup/php/titles.expect.txt new file mode 100644 index 0000000000..05763d78a2 --- /dev/null +++ b/test/markup/php/titles.expect.txt @@ -0,0 +1,26 @@ +final class Example extends Foo { + const FOO='foo'; + + public function __construct( + public readonly string $name = self::FOO + ) {} + + public function getClass(): string { + return DateTimeImmutable::class; + } + + public function getClassFromSelf(): string { + return self::class; + } + + public static function getClassFromStatic(): string { + return static::class; + } + + public static function getParentClass(): string { + return parent::class; + } +} + +$date = DateTimeImmutable::createFromMutable(new \DateTime()); +echo $date::class; diff --git a/test/markup/php/titles.txt b/test/markup/php/titles.txt new file mode 100644 index 0000000000..6ff19f2fc6 --- /dev/null +++ b/test/markup/php/titles.txt @@ -0,0 +1,26 @@ +final class Example extends Foo { + const FOO='foo'; + + public function __construct( + public readonly string $name = self::FOO + ) {} + + public function getClass(): string { + return DateTimeImmutable::class; + } + + public function getClassFromSelf(): string { + return self::class; + } + + public static function getClassFromStatic(): string { + return static::class; + } + + public static function getParentClass(): string { + return parent::class; + } +} + +$date = DateTimeImmutable::createFromMutable(new \DateTime()); +echo $date::class; diff --git a/test/markup/protobuf/message-message.expect.txt b/test/markup/protobuf/message-message.expect.txt index 0243879d38..fcf7712b80 100644 --- a/test/markup/protobuf/message-message.expect.txt +++ b/test/markup/protobuf/message-message.expect.txt @@ -1,10 +1,10 @@ // A Container message -message Container { - message Message { - required int64 id = 1; +message Container { + message Message { + required int64 id = 1; } repeated Message messages = 1; - optional int32 number = 2; + optional int32 number = 2; } /* diff --git a/test/markup/protobuf/rpc.expect.txt b/test/markup/protobuf/rpc.expect.txt index a09ce497c0..6fdb5e5c47 100644 --- a/test/markup/protobuf/rpc.expect.txt +++ b/test/markup/protobuf/rpc.expect.txt @@ -1,4 +1,4 @@ -service Greeter { +service Greeter { // Sends a greeting rpc SayHello (HelloRequest) returns (HelloReply) {} } diff --git a/test/markup/python/false_positives.expect.txt b/test/markup/python/false_positives.expect.txt new file mode 100644 index 0000000000..cce88e6df8 --- /dev/null +++ b/test/markup/python/false_positives.expect.txt @@ -0,0 +1,5 @@ +foo = _undef +bar + +booger = _unclass +burger diff --git a/test/markup/python/false_positives.txt b/test/markup/python/false_positives.txt new file mode 100644 index 0000000000..cce88e6df8 --- /dev/null +++ b/test/markup/python/false_positives.txt @@ -0,0 +1,5 @@ +foo = _undef +bar + +booger = _unclass +burger diff --git a/test/markup/python/keywords.expect.txt b/test/markup/python/keywords.expect.txt index 501f670464..f2227af2f5 100644 --- a/test/markup/python/keywords.expect.txt +++ b/test/markup/python/keywords.expect.txt @@ -13,5 +13,4 @@ x = Shorty() exec(123) -# note, numbers still aren't highlighted fully -print(1if 0==0else"b") +print(1if 0==0else"b") diff --git a/test/markup/python/keywords.txt b/test/markup/python/keywords.txt index 0b7835526d..30e3d0a180 100644 --- a/test/markup/python/keywords.txt +++ b/test/markup/python/keywords.txt @@ -13,5 +13,4 @@ for _ in sys.path: exec(123) -# note, numbers still aren't highlighted fully print(1if 0==0else"b") diff --git a/test/markup/python/numbers.expect.txt b/test/markup/python/numbers.expect.txt index 004a36eb08..725eb354f7 100644 --- a/test/markup/python/numbers.expect.txt +++ b/test/markup/python/numbers.expect.txt @@ -24,12 +24,30 @@ .0e10J, .00e+10j, .9e-10J, 4.2E10j, 40.0E+08J, 0.E-10j, 00.e100J, 0010e+10j .0e1_0J, .0_0e+10j, .9e-1_0J, 4.2E1_0j, 4_0.0E+0_8J, 0.E-1_0j, 0_0.e1_0_0J, 00_10e+10j -0j, 00J, 000j, 1234J -0j, 0_0J, 0_0_0j, 12_3_4J +0j, 00J, 000j, 009J, 1234j +0j, 0_0J, 0_0_0j, 0_0_9J, 12_3_4j # expressions containing numeric literals 0..__str__, 1e1.__str__, fn(.5) +0is 0, 0lis 0 +0_0_0is 0, 0_0_0lis 0 +0b0is 0, 0b0lis 0 +0b_0_0is 0, 0b_0_0lis 0 +0o0is 0, 0o0lis 0 +0o_0_0is 0, 0o_0_0lis 0 +0x0ais 0, 0x0elis 0 +0x_0_0is 0, 0x_0_0lis 0 +.0is 0, 0.is 0 +.0_0_0is 0, 0_0_0.is 0 +.0e+0is 0, 0.e-0is 0 +.0_0_0e-0_0_0is 0, 0_0_0.e+0_0_0is 0 +.0jis 0, 0.jis 0 +.0_0_0jis 0, 0_0_0.jis 0 +.0e+0jis 0, 0.e-0jis 0 +.0_0_0e-0_0_0jis 0, 0_0_0.e+0_0_0jis 0 +0jis 0, 009jis 0 +0_0_0jis 0, 0_0_9jis 0 # expressions not containing numeric literals x0.j diff --git a/test/markup/python/numbers.txt b/test/markup/python/numbers.txt index a0aeb7dc50..0511ce4337 100644 --- a/test/markup/python/numbers.txt +++ b/test/markup/python/numbers.txt @@ -24,12 +24,30 @@ .0e10J, .00e+10j, .9e-10J, 4.2E10j, 40.0E+08J, 0.E-10j, 00.e100J, 0010e+10j .0e1_0J, .0_0e+10j, .9e-1_0J, 4.2E1_0j, 4_0.0E+0_8J, 0.E-1_0j, 0_0.e1_0_0J, 00_10e+10j -0j, 00J, 000j, 1234J -0j, 0_0J, 0_0_0j, 12_3_4J +0j, 00J, 000j, 009J, 1234j +0j, 0_0J, 0_0_0j, 0_0_9J, 12_3_4j # expressions containing numeric literals 0..__str__, 1e1.__str__, fn(.5) +0is 0, 0lis 0 +0_0_0is 0, 0_0_0lis 0 +0b0is 0, 0b0lis 0 +0b_0_0is 0, 0b_0_0lis 0 +0o0is 0, 0o0lis 0 +0o_0_0is 0, 0o_0_0lis 0 +0x0ais 0, 0x0elis 0 +0x_0_0is 0, 0x_0_0lis 0 +.0is 0, 0.is 0 +.0_0_0is 0, 0_0_0.is 0 +.0e+0is 0, 0.e-0is 0 +.0_0_0e-0_0_0is 0, 0_0_0.e+0_0_0is 0 +.0jis 0, 0.jis 0 +.0_0_0jis 0, 0_0_0.jis 0 +.0e+0jis 0, 0.e-0jis 0 +.0_0_0e-0_0_0jis 0, 0_0_0.e+0_0_0jis 0 +0jis 0, 009jis 0 +0_0_0jis 0, 0_0_9jis 0 # expressions not containing numeric literals x0.j diff --git a/test/markup/rsl/default.expect.txt b/test/markup/rsl/default.expect.txt index c6eb9d4e8c..c67bc9d9cd 100644 --- a/test/markup/rsl/default.expect.txt +++ b/test/markup/rsl/default.expect.txt @@ -5,9 +5,9 @@ * (c) Copyright 1999-2003 Okan Arikan. All rights reserved. */ -surface plastic (float Ka = 1, Kd = 0.5, Ks = 0.5, roughness = 0.1; - color specularcolor = 1;) { - normal Nf = faceforward (normalize(N),I); +surface plastic (float Ka = 1, Kd = 0.5, Ks = 0.5, roughness = 0.1; + color specularcolor = 1;) { + normal Nf = faceforward (normalize(N),I); Ci = Cs * (Ka*ambient() + Kd*diffuse(Nf)) + specularcolor * Ks * specular(Nf,-normalize(I),roughness); Oi = Os; diff --git a/test/markup/stan/default.expect.txt b/test/markup/stan/default.expect.txt index 6a32c43433..aeb9552aa5 100644 --- a/test/markup/stan/default.expect.txt +++ b/test/markup/stan/default.expect.txt @@ -1,39 +1,40 @@ -// Multivariate Regression Example -// Taken from stan-reference-2.8.0.pdf p.66 - +functions { + #include normal_copula.stanfunctions +} data { - int<lower=0> N; // num individuals - int<lower=1> K; // num ind predictors - int<lower=1> J; // num groups - int<lower=1> L; // num group predictors - int<lower=1,upper=J> jj[N]; // group for individual - matrix[N,K] x; // individual predictors - row_vector[L] u[J]; // group predictors - vector[N] y; // outcomes + int<lower=0> N; + int K; + matrix[N, K] x; } +transformed data { + complex zi = 1+3.14i; + zi = zi * 0i; + complex yi = to_complex(0, 1.1) + to_complex(0.0, 2.2) + to_complex(); + real x = get_real(3i - 40e-3i + 1e10i); +}› parameters { - corr_matrix[K] Omega; // prior correlation - vector<lower=0>[K] tau; // prior scale - matrix[L,K] gamma; // group coeffs - vector[K] beta[J]; // indiv coeffs by group - real<lower=0> sigma; // prediction error scale + array[K - 1] real mu; + array[K + 1] real<lower=0> sigma; + cholesky_factor_corr[K] L; } model { - tau ~ cauchy(0,2.5); - Omega ~ lkj_corr(2); - to_vector(gamma) ~ normal(0, 5); - { - row_vector[K] u_gamma[J]; - for (j in 1:J) - u_gamma[j] <- u[j] * gamma; - beta ~ multi_normal(u_gamma, quad_form_diag(Omega, tau)); - } + target += normal_lpdf(x[ : , 1] | mu[1], sigma[1]); + target += gumbel_lpdf(x[ : , 2] | mu[2], sigma[2]); + target += lognormal_lpdf(x[ : , 3] | mu[3], sigma[3]); + target += weibull_lpdf(x[ : , 4] | sigma[4], sigma[5]); + { - vector[N] x_beta_jj; - for (n in 1:N) - x_beta_jj[n] <- x[n] * beta[jj[n]]; - y ~ normal(x_beta_jj, sigma); + matrix[K, N] y; + for (n in 1 : N) { + y[1, n] = inv_Phi(normal_cdf(x[n, 1] | mu[1], sigma[1])); + y[2, n] = inv_Phi(gumbel_cdf(x[n, 2] | mu[2], sigma[2])); + y[3, n] = inv_Phi(lognormal_cdf(x[n, 3] | mu[3], sigma[3])); + y[4, n] = inv_Phi(weibull_cdf(x[n, 4] | sigma[4], sigma[5])); + } + y ~ multi_normal(L); + } } - -# Note: Octothorpes indicate comments, too! +generated quantities { + matrix[K, K] Sigma = multiply_lower_tri_self_transpose(L); +} \ No newline at end of file diff --git a/test/markup/stan/default.txt b/test/markup/stan/default.txt index 99e56c45ec..a4b42f332e 100644 --- a/test/markup/stan/default.txt +++ b/test/markup/stan/default.txt @@ -1,39 +1,40 @@ -// Multivariate Regression Example -// Taken from stan-reference-2.8.0.pdf p.66 - +functions { + #include normal_copula.stanfunctions +} data { - int N; // num individuals - int K; // num ind predictors - int J; // num groups - int L; // num group predictors - int jj[N]; // group for individual - matrix[N,K] x; // individual predictors - row_vector[L] u[J]; // group predictors - vector[N] y; // outcomes + int N; + int K; + matrix[N, K] x; } +transformed data { + complex zi = 1+3.14i; + zi = zi * 0i; + complex yi = to_complex(0, 1.1) + to_complex(0.0, 2.2) + to_complex(); + real x = get_real(3i - 40e-3i + 1e10i); +}› parameters { - corr_matrix[K] Omega; // prior correlation - vector[K] tau; // prior scale - matrix[L,K] gamma; // group coeffs - vector[K] beta[J]; // indiv coeffs by group - real sigma; // prediction error scale + array[K - 1] real mu; + array[K + 1] real sigma; + cholesky_factor_corr[K] L; } model { - tau ~ cauchy(0,2.5); - Omega ~ lkj_corr(2); - to_vector(gamma) ~ normal(0, 5); - { - row_vector[K] u_gamma[J]; - for (j in 1:J) - u_gamma[j] <- u[j] * gamma; - beta ~ multi_normal(u_gamma, quad_form_diag(Omega, tau)); - } + target += normal_lpdf(x[ : , 1] | mu[1], sigma[1]); + target += gumbel_lpdf(x[ : , 2] | mu[2], sigma[2]); + target += lognormal_lpdf(x[ : , 3] | mu[3], sigma[3]); + target += weibull_lpdf(x[ : , 4] | sigma[4], sigma[5]); + { - vector[N] x_beta_jj; - for (n in 1:N) - x_beta_jj[n] <- x[n] * beta[jj[n]]; - y ~ normal(x_beta_jj, sigma); + matrix[K, N] y; + for (n in 1 : N) { + y[1, n] = inv_Phi(normal_cdf(x[n, 1] | mu[1], sigma[1])); + y[2, n] = inv_Phi(gumbel_cdf(x[n, 2] | mu[2], sigma[2])); + y[3, n] = inv_Phi(lognormal_cdf(x[n, 3] | mu[3], sigma[3])); + y[4, n] = inv_Phi(weibull_cdf(x[n, 4] | sigma[4], sigma[5])); + } + y ~ multi_normal(L); + } } - -# Note: Octothorpes indicate comments, too! +generated quantities { + matrix[K, K] Sigma = multiply_lower_tri_self_transpose(L); +} \ No newline at end of file diff --git a/test/markup/swift/attributes.expect.txt b/test/markup/swift/attributes.expect.txt index 885e678a6b..22d4e60978 100644 --- a/test/markup/swift/attributes.expect.txt +++ b/test/markup/swift/attributes.expect.txt @@ -1,4 +1,3 @@ -@available(iOS 14, deprecated: "reason", *) @convention(swift) @objc @objc(name) diff --git a/test/markup/swift/attributes.txt b/test/markup/swift/attributes.txt index 24fe9a41bf..8628043613 100644 --- a/test/markup/swift/attributes.txt +++ b/test/markup/swift/attributes.txt @@ -1,4 +1,3 @@ -@available(iOS 14, deprecated: "reason", *) @convention(swift) @objc @objc(name) diff --git a/test/markup/swift/availability.expect.txt b/test/markup/swift/availability.expect.txt new file mode 100644 index 0000000000..7435c86838 --- /dev/null +++ b/test/markup/swift/availability.expect.txt @@ -0,0 +1,11 @@ +#available() +#available(iOS 15.0, *) +@available() +@available(iOS 15.0, *) +@available(iOS 14, deprecated: "reason", *) + +#unavailable() +#unavailable(iOS 15.0, *) +// not a keyword +@unavailable() +@unavailable(iOS 15.0, *) diff --git a/test/markup/swift/availability.txt b/test/markup/swift/availability.txt new file mode 100644 index 0000000000..87cd134e35 --- /dev/null +++ b/test/markup/swift/availability.txt @@ -0,0 +1,11 @@ +#available() +#available(iOS 15.0, *) +@available() +@available(iOS 15.0, *) +@available(iOS 14, deprecated: "reason", *) + +#unavailable() +#unavailable(iOS 15.0, *) +// not a keyword +@unavailable() +@unavailable(iOS 15.0, *) diff --git a/test/markup/twig/filter_with_underscore.expect.txt b/test/markup/twig/filter_with_underscore.expect.txt index 72c93fd877..9d2928531a 100644 --- a/test/markup/twig/filter_with_underscore.expect.txt +++ b/test/markup/twig/filter_with_underscore.expect.txt @@ -1 +1 @@ -{{ "string with spaces"|url_encode }} \ No newline at end of file +{{ "string with spaces"|url_encode }} \ No newline at end of file diff --git a/test/markup/twig/template_tags.expect.txt b/test/markup/twig/template_tags.expect.txt index 410fb24347..0127a33510 100644 --- a/test/markup/twig/template_tags.expect.txt +++ b/test/markup/twig/template_tags.expect.txt @@ -1,12 +1,12 @@ -{% if posts|length %} - {% for article in articles %} +{% if posts|length %} + {% for article in articles %} &lt;div&gt; - {{ article.title|upper() }} + {{ article.title|upper() }} {# outputs 'WELCOME' #} &lt;/div&gt; - {% endfor %} -{% endif %} + {% endfor %} +{% endif %} -{% set user = json_encode(user) %} +{% set user = json_encode(user) %} \ No newline at end of file diff --git a/tools/build.js b/tools/build.js index 0bf5082685..903976d5c2 100755 --- a/tools/build.js +++ b/tools/build.js @@ -62,7 +62,7 @@ const commander = require('commander'); const path = require('path'); -const { clean } = require("./lib/makestuff"); +const { clean } = require("./lib/makestuff.js"); const log = (...args) => console.log(...args); const TARGETS = ["cdn", "browser", "node"]; @@ -73,8 +73,8 @@ commander .option('-n, --no-minify', 'Disable minification') .option('-ne, --no-esm', 'Disable building ESM') .option('-t, --target ', - 'Build for target ' + - '[all, browser, cdn, node]', + 'Build for target ' + + '[all, browser, cdn, node]', 'browser') .parse(process.argv); diff --git a/tools/build_browser.js b/tools/build_browser.js index 48c0f465b6..24ad4fbed8 100644 --- a/tools/build_browser.js +++ b/tools/build_browser.js @@ -6,10 +6,10 @@ const path = require("path"); const zlib = require('zlib'); const Terser = require("terser"); const child_process = require('child_process'); -const { getLanguages } = require("./lib/language"); -const { filter } = require("./lib/dependencies"); -const config = require("./build_config"); -const { install, installCleanCSS, mkdir, renderTemplate } = require("./lib/makestuff"); +const { getLanguages } = require("./lib/language.js"); +const { filter } = require("./lib/dependencies.js"); +const config = require("./build_config.js"); +const { install, installCleanCSS, mkdir, renderTemplate } = require("./lib/makestuff.js"); const log = (...args) => console.log(...args); const { rollupCode } = require("./lib/bundling.js"); const bundling = require('./lib/bundling.js'); @@ -17,16 +17,16 @@ const Table = require('cli-table'); const getDefaultHeader = () => ({ ...require('../package.json'), - git_sha : child_process + git_sha: child_process .execSync("git rev-parse --short=10 HEAD") - .toString().trim(), + .toString().trim() }); function buildHeader(args = getDefaultHeader()) { - return "/*!\n" + - ` Highlight.js v${args.version} (git: ${args.git_sha})\n` + - ` (c) ${config.copyrightYears} ${args.author.name} and other contributors\n` + - ` License: ${args.license}\n` + - ` */`; + return "/*!\n" + + ` Highlight.js v${args.version} (git: ${args.git_sha})\n` + + ` (c) ${config.copyrightYears} ${args.author.name} and other contributors\n` + + ` License: ${args.license}\n` + + ` */`; } function sortByKey(array, key) { @@ -41,9 +41,9 @@ function detailedGrammarSizes(languages) { if (languages.length > 180) return; const resultTable = new Table({ - head: ['lang','minified'], + head: ['lang', 'minified'], // colWidths: [20,20,10,20,10,20], - chars: {'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''}, + chars: { mid: '', 'left-mid': '', 'mid-mid': '', 'right-mid': '' }, style: { head: ['grey'] } @@ -230,19 +230,19 @@ async function buildCore(name, languages, options) { const sizeInfo = { shas: [] }; const writePromises = []; if (options.minify) { - const { code } = await Terser.minify(index, {...config.terser, module: (options.format === "es") }); + const { code } = await Terser.minify(index, { ...config.terser, module: (options.format === "es") }); const src = `${header}\n${code}`; writePromises.push(fs.writeFile(output.file.replace(/js$/, "min.js"), src)); sizeInfo.minified = src.length; sizeInfo.minifiedSrc = src; - sizeInfo.shas[`${relativePath}${name}.min.js`] = bundling.sha384(src) + sizeInfo.shas[`${relativePath}${name}.min.js`] = bundling.sha384(src); } { const src = `${header}\n${index}`; writePromises.push(fs.writeFile(output.file, src)); sizeInfo.fullSize = src.length; sizeInfo.fullSrc = src; - sizeInfo.shas[`${relativePath}${name}.js`] = bundling.sha384(src) + sizeInfo.shas[`${relativePath}${name}.js`] = bundling.sha384(src); } await Promise.all(writePromises); return sizeInfo; diff --git a/tools/build_cdn.js b/tools/build_cdn.js index 9cc3463ea2..5ca6dc927b 100644 --- a/tools/build_cdn.js +++ b/tools/build_cdn.js @@ -57,7 +57,7 @@ async function buildCDN(options) { if (options.esm) { mkdir("es"); await fs.writeFile(`${process.env.BUILD_DIR}/es/package.json`, `{ "type": "module" }`); - esmCoreSize = await buildCore("core", [], {minify: options.minify, format: "es"}); + esmCoreSize = await buildCore("core", [], { minify: options.minify, format: "es" }); esmCommonSize = await buildCore("highlight", embedLanguages, { minify: options.minify, format: "es" }); } shas = { @@ -157,7 +157,7 @@ async function buildDistributable(language, options) { await fs.mkdir(distDir, { recursive: true }); await fs.writeFile(path.join(language.moduleDir, "dist", filename), language.minified); if (options.esm) { - await fs.writeFile(path.join(language.moduleDir, "dist", filename.replace(".min.js",".es.min.js")), language.minifiedESM); + await fs.writeFile(path.join(language.moduleDir, "dist", filename.replace(".min.js", ".es.min.js")), language.minifiedESM); } } diff --git a/tools/build_node.js b/tools/build_node.js index 9dcc8579b5..d22c2b4e05 100644 --- a/tools/build_node.js +++ b/tools/build_node.js @@ -1,29 +1,29 @@ const fs = require("fs").promises; const fss = require("fs"); -const config = require("./build_config"); +const config = require("./build_config.js"); const glob = require("glob-promise"); -const { getLanguages } = require("./lib/language"); -const { install, mkdir, installCleanCSS } = require("./lib/makestuff"); -const { filter } = require("./lib/dependencies"); +const { getLanguages } = require("./lib/language.js"); +const { install, mkdir, installCleanCSS } = require("./lib/makestuff.js"); +const { filter } = require("./lib/dependencies.js"); const { rollupWrite } = require("./lib/bundling.js"); const log = (...args) => console.log(...args); // https://nodejs.org/api/packages.html#packages_writing_dual_packages_while_avoiding_or_minimizing_hazards async function buildESMStub(name) { const code = - `// https://nodejs.org/api/packages.html#packages_writing_dual_packages_while_avoiding_or_minimizing_hazards\n` + - `import HighlightJS from '../lib/${name}.js';\n` + - `export { HighlightJS };\n` + - `export default HighlightJS;\n`; + `// https://nodejs.org/api/packages.html#packages_writing_dual_packages_while_avoiding_or_minimizing_hazards\n` + + `import HighlightJS from '../lib/${name}.js';\n` + + `export { HighlightJS };\n` + + `export default HighlightJS;\n`; await fs.writeFile(`${process.env.BUILD_DIR}/es/${name}.js`, code); } async function buildCJSIndex(name, languages) { const header = "var hljs = require('./core');"; const footer = - `hljs.HighlightJS = hljs\n` + - `hljs.default = hljs\n` + - `module.exports = hljs;`; + `hljs.HighlightJS = hljs\n` + + `hljs.default = hljs\n` + + `module.exports = hljs;`; const registration = languages.map((lang) => { const require = `require('./languages/${lang.name}')`; @@ -57,7 +57,8 @@ async function buildNodeLanguage(language, options) { if (options.esm) { await fs.writeFile(`${process.env.BUILD_DIR}/es/languages/${language.name}.js.js`, ES_STUB.replace(/%%%%/g, language.name)); - await rollupWrite(input, {...output, + await rollupWrite(input, { + ...output, format: "es", file: output.file.replace("/lib/", "/es/") }); @@ -108,7 +109,7 @@ const generatePackageExports = () => ({ "./lib/languages/*": dual("./lib/languages/*.js"), "./scss/*": "./scss/*", "./styles/*": "./styles/*", - "./types/*": "./types/*", + "./types/*": "./types/*" }); function buildPackageJSON(options) { const packageJson = require("../package.json"); diff --git a/tools/checkAutoDetect.js b/tools/checkAutoDetect.js index 5b101672fb..0da66c8dfd 100755 --- a/tools/checkAutoDetect.js +++ b/tools/checkAutoDetect.js @@ -1,16 +1,16 @@ #!/usr/bin/env node 'use strict'; -let fs = require('fs') -let hljs = require('../build'); -let path = require('path'); -let utility = require('../test/utility'); -let Table = require('cli-table'); -let colors = require('colors/safe'); +const fs = require('fs'); +const hljs = require('../build/lib/index.js'); +const path = require('path'); +const utility = require('../test/utility.js'); +const Table = require('cli-table'); +const colors = require('colors/safe.js'); -let resultTable = new Table({ - head: ['expected', 'actual', 'score', '2nd best', 'score','info'], - colWidths: [20,20,10,20,10,20], +const resultTable = new Table({ + head: ['expected', 'actual', 'score', '2nd best', 'score', 'info'], + colWidths: [20, 20, 10, 20, 10, 20], style: { head: ['grey'] } @@ -24,8 +24,8 @@ function testAutoDetection(language, index, languages) { return fs.readFileSync(filename, 'utf-8'); }) .forEach(function(content) { - const expected = language, - actual = hljs.highlightAuto(content); + const expected = language; + const actual = hljs.highlightAuto(content); if (actual.language !== expected && actual.secondBest.language !== expected) { return resultTable.push([ expected, @@ -45,7 +45,7 @@ function testAutoDetection(language, index, languages) { ]); } // equal relevance is flagged - if (actual.relevance == actual.secondBest.relevance) { + if (actual.relevance === actual.secondBest.relevance) { return resultTable.push([ expected, actual.language, @@ -68,18 +68,16 @@ if (process.env.ONLY_LANGUAGES) { console.log('Checking auto-highlighting for ' + colors.grey(languages.length) + ' languages...'); languages.forEach((lang, index) => { if (index % 60 === 0) { console.log(""); } - testAutoDetection(lang) + testAutoDetection(lang); process.stdout.write("."); }); -console.log("\n") +console.log("\n"); if (resultTable.length === 0) { - console.log(colors.green('SUCCESS') + ' - ' + colors.green(languages.length) + ' of ' + colors.gray(languages.length) + ' languages passed auto-highlight check!') + console.log(colors.green('SUCCESS') + ' - ' + colors.green(languages.length) + ' of ' + colors.gray(languages.length) + ' languages passed auto-highlight check!'); } else { console.log( - colors.red('ISSUES') + ' - ' + colors.red(resultTable.length) + ' of ' + colors.gray(languages.length) + ' languages have potential issues.' + - '\n' + - resultTable.toString()); + colors.red('ISSUES') + ' - ' + colors.red(resultTable.length) + ' of ' + colors.gray(languages.length) + ' languages have potential issues.' + + '\n' + + resultTable.toString()); } - - diff --git a/tools/checkTheme.js b/tools/checkTheme.js index 09f72f2245..45ae7d9157 100755 --- a/tools/checkTheme.js +++ b/tools/checkTheme.js @@ -2,7 +2,9 @@ const fs = require("fs"); const css = require("css"); -const { match } = require("assert"); +const wcagContrast = require("wcag-contrast"); +const Table = require('cli-table'); +const csscolors = require('css-color-names'); require("colors"); const CODE = { @@ -166,25 +168,101 @@ function check_group(group, rules) { }); - let doesNotSupport = has_rules.map(x => x[1]).includes(false); - let skipped = has_rules.find(x => x[2]); + const doesNotSupport = has_rules.map(x => x[1]).includes(false); + const skipped = has_rules.find(x => x[2]); if (doesNotSupport || skipped) { console.log(group.name.yellow); if (doesNotSupport) { console.log(`- Theme does not fully support.`.brightMagenta); } - has_rules.filter(x => !x[1]).forEach(([scope,_]) => { + has_rules.filter(x => !x[1]).forEach(([scope, _]) => { const selector = scopeToSelector(scope); console.log(`- scope ${scope.cyan} is not highlighted\n (css: ${selector.green})`); }); - has_rules.filter(x => x[2]).forEach(([scope,_]) => { + has_rules.filter(x => x[2]).forEach(([scope, _]) => { console.log(` - scope ${scope.cyan} [purposely] un-highlighted.`.cyan); }); console.log(); } } +const round2 = (x) => Math.round(x*100)/100; + +class CSSRule { + constructor(rule, body) { + this.rule = rule; + if (rule.declarations) { + this.bg = rule.declarations.find(x => x.property == "background-color")?.value; + if (!this.bg) { + this.bg = rule.declarations.find(x => x.property == "background")?.value; + } + this.fg = rule.declarations.find(x => x.property =="color")?.value; + + if (this.bg) { + this.bg = csscolors[this.bg] || this.bg; + } + if (this.fg) { + this.fg = csscolors[this.fg] || this.fg; + } + + // inherit from body if we're missing fg or bg + if (this.hasColor) { + if (!this.bg) this.bg = body.background; + if (!this.fg) this.fg = body.foreground; + } + } + } + get background() { + return this.bg + } + + get foreground() { + return this.fg + } + get hasColor() { + if (!this.rule.declarations) return false; + return this.fg || this.bg; + } + toString() { + return ` ${this.foreground} on ${this.background}` + } + + contrastRatio() { + if (!this.foreground) return "unknown (no fg)" + if (!this.background) return "unknown (no bg)" + return round2(wcagContrast.hex(this.foreground, this.background)); + } +} + +function contrast_report(rules) { + console.log("Accessibility Report".yellow); + + var hljs = rules.find (x => x.selectors && x.selectors.includes(".hljs")); + var body = new CSSRule(hljs); + const table = new Table({ + chars: {'mid': '', 'left-mid': '', 'mid-mid': '', 'right-mid': ''}, + head: ['ratio', 'selector', 'fg', 'bg'], + colWidths: [7, 40, 10, 10], + style: { + head: ['grey'] + } + }); + + rules.forEach(rule => { + var color = new CSSRule(rule, body); + if (!color.hasColor) return; + table.push([ + color.contrastRatio(), + rule.selectors, + color.foreground, + color.background + ]) + // console.log(r.selectors[0], color.contrastRatio(), color.toString()); + }) + console.log(table.toString()) +} + function validate(data) { const rules = data.stylesheet.rules; @@ -196,6 +274,8 @@ function validate(data) { check_group(CODE, rules); check_group(OTHER, rules); check_group(HIGH_FIDELITY, rules); + + contrast_report(rules); } process.argv.shift(); diff --git a/tools/developer.html b/tools/developer.html index 0690702bfa..5707b0600b 100644 --- a/tools/developer.html +++ b/tools/developer.html @@ -107,6 +107,7 @@

Code

+ diff --git a/tools/lib/bundling.js b/tools/lib/bundling.js index 1ca11a71c6..55360c6ee9 100644 --- a/tools/lib/bundling.js +++ b/tools/lib/bundling.js @@ -1,8 +1,8 @@ -const rollup = require('rollup') +const rollup = require('rollup'); const crypto = require("crypto"); async function rollupCode(inputOptions, outputOptions) { - const output = await generate(inputOptions, outputOptions) + const output = await generate(inputOptions, outputOptions); return output[0].code; } diff --git a/tools/lib/dependencies.js b/tools/lib/dependencies.js index edc621adf7..c2201d3396 100644 --- a/tools/lib/dependencies.js +++ b/tools/lib/dependencies.js @@ -6,20 +6,19 @@ const DependencyResolver = require('dependency-resolver'); * * @param {array} languages list of languages to be reordered * @returns {array} ordered list of languages -*/ - + */ const reorderDependencies = (languages) => { - let resolver = new DependencyResolver(); - for (let lang of languages) { + const resolver = new DependencyResolver(); + for (const lang of languages) { resolver.add(lang.name); - for (let required of lang.requires) { + for (const required of lang.requires) { resolver.setDependency(lang.name, required); } } return resolver.sort().map((name) => - languages.find((l) => l.name == name) + languages.find((l) => l.name === name) ); -} +}; /** * Filters languages by group (common, etc) @@ -28,14 +27,13 @@ const reorderDependencies = (languages) => { * * @param {array} languages full list of languages * @returns {array} filtered list -*/ - + */ const languagesByGroup = (languages, groupIdentifier) => { - let groupName = groupIdentifier.replace(":",""); + const groupName = groupIdentifier.replace(":", ""); return languages.filter((el) => el.categories.includes(groupName)); -} +}; // :common is a group identifier, "common" is the group name -const isGroup = (id) => id[0] == ":" +const isGroup = (id) => id[0] === ":"; /** @@ -48,39 +46,36 @@ const isGroup = (id) => id[0] == ":" * @param {array} includes - which languages or groups to include * example: ":common elixir ruby" * @returns {array} filtered list if languages -*/ + */ const filter = (allLanguages, includes) => { - if (includes==undefined || includes.length==0) - return reorderDependencies(allLanguages); + if (!includes || includes.length === 0) { return reorderDependencies(allLanguages); } let languages = []; - for (let item of includes) { + for (const item of includes) { if (isGroup(item)) { - languages = languages.concat(languagesByGroup(allLanguages, item)) + languages = languages.concat(languagesByGroup(allLanguages, item)); } else { - let languageName = item; - let found = allLanguages.find((el) => el.name == languageName ) - if (found) - languages.push(found) - else { - console.error(`[ERROR] Language '${languageName}' could not be found.`) - process.exit(1) + const languageName = item; + const found = allLanguages.find((el) => el.name === languageName); + if (found) { languages.push(found); } else { + console.error(`[ERROR] Language '${languageName}' could not be found.`); + process.exit(1); } } } // resolve requires - for (let lang of languages) { + for (const lang of languages) { lang.requires.forEach(needed => { - if (!languages.find((el) => el.name == needed)) { - console.info(`[INFO] Adding ${needed}... ${lang.name} requires ${needed}.`) - languages.push(allLanguages.find((el) => el.name == needed)) + if (!languages.find((el) => el.name === needed)) { + console.info(`[INFO] Adding ${needed}... ${lang.name} requires ${needed}.`); + languages.push(allLanguages.find((el) => el.name === needed)); } }); } // make sure our dependencies are in the correct order return reorderDependencies(languages); -} +}; -module.exports = { reorderDependencies, filter } +module.exports = { reorderDependencies, filter }; diff --git a/tools/lib/language.js b/tools/lib/language.js index 3a1c20c978..8da727e101 100644 --- a/tools/lib/language.js +++ b/tools/lib/language.js @@ -1,37 +1,35 @@ -const fs = require("fs") -const fsProm = require("fs").promises +const fs = require("fs"); const Terser = require("terser"); -const glob = require("glob") -const path = require("path") -const build_config = require("../build_config") +const glob = require("glob"); +const path = require("path"); +const build_config = require("../build_config.js"); -const packageJSON = require("../../package.json") -const REQUIRES_REGEX = /\/\*.*?Requires: (.*?)\r?\n/s -const CATEGORY_REGEX = /\/\*.*?Category: (.*?)\r?\n/s -const LANGUAGE_REGEX = /\/\*.*?Language: (.*?)\r?\n/s -const {rollupCode} = require("./bundling.js") -const { getThirdPartyPackages } = require("./external_language") +const packageJSON = require("../../package.json"); +const REQUIRES_REGEX = /\/\*.*?Requires: (.*?)\r?\n/s; +const CATEGORY_REGEX = /\/\*.*?Category: (.*?)\r?\n/s; +const LANGUAGE_REGEX = /\/\*.*?Language: (.*?)\r?\n/s; +const { rollupCode } = require("./bundling.js"); +const { getThirdPartyPackages } = require("./external_language.js"); class Language { - constructor(name, path) { - this.name = name - this.prettyName = name - this.requires = [] - this.categories = [] - this.third_party = false + this.name = name; + this.prettyName = name; + this.requires = []; + this.categories = []; + this.third_party = false; // compiled code - this.module = "" - this.minified = "" + this.module = ""; + this.minified = ""; - this.path = path - this.data = fs.readFileSync(path, {encoding: "utf8"}) - this.loadMetadata() + this.path = path; + this.data = fs.readFileSync(path, { encoding: "utf8" }); + this.loadMetadata(); } async compile(options) { - await compileLanguage(this,options); + await compileLanguage(this, options); return this; } @@ -39,8 +37,7 @@ class Language { if (this._sample) return this._sample; this._sample = ""; - if (fs.existsSync(this.samplePath)) - this._sample = fs.readFileSync(this.samplePath, {encoding: "utf8"}); + if (fs.existsSync(this.samplePath)) { this._sample = fs.readFileSync(this.samplePath, { encoding: "utf8" }); } return this._sample; } @@ -48,38 +45,34 @@ class Language { if (this.moduleDir) { // this is the 'extras' case. return `${this.moduleDir}/test/detect/${this.name}/default.txt`; - } - else { + } else { // this is the common/built-in case. return `./test/detect/${this.name}/default.txt`; } } loadMetadata() { - var requiresMatch = REQUIRES_REGEX.exec(this.data) - var categoryMatch = CATEGORY_REGEX.exec(this.data) - var languageMatch = LANGUAGE_REGEX.exec(this.data) + const requiresMatch = REQUIRES_REGEX.exec(this.data); + const categoryMatch = CATEGORY_REGEX.exec(this.data); + const languageMatch = LANGUAGE_REGEX.exec(this.data); - if (requiresMatch) - this.requires = requiresMatch[1].split(", ").map((n) => n.replace(".js","")) + if (requiresMatch) { this.requires = requiresMatch[1].split(", ").map((n) => n.replace(".js", "")); } - if (categoryMatch) - this.categories = categoryMatch[1].split(/,\s?/) + if (categoryMatch) { this.categories = categoryMatch[1].split(/,\s?/); } - if (languageMatch) - this.prettyName = languageMatch[1] + if (languageMatch) { this.prettyName = languageMatch[1]; } } static fromFile(filename) { return new Language( - path.basename(filename).replace(".js",""), + path.basename(filename).replace(".js", ""), filename ); } } -async function compileLanguage (language, options) { +async function compileLanguage(language, options) { const HEADER = `/*! \`${language.name}\` grammar compiled for Highlight.js ${packageJSON.version} */`; // TODO: cant we use the source we already have? @@ -105,14 +98,14 @@ async function compileLanguage (language, options) { } async function getLanguages() { - let languages = []; + const languages = []; glob.sync("./src/languages/*.js").forEach((file) => { languages.push(Language.fromFile(file)); }); - let extraPackages = await getThirdPartyPackages(); - for (let ext of extraPackages) { - for (let file of ext.files) { - let l = Language.fromFile(file); + const extraPackages = await getThirdPartyPackages(); + for (const ext of extraPackages) { + for (const file of ext.files) { + const l = Language.fromFile(file); l.loader = ext.loader; l.third_party = true; l.moduleDir = ext.dir; diff --git a/tools/lib/makestuff.js b/tools/lib/makestuff.js index 44e0035c25..9f3f7da707 100644 --- a/tools/lib/makestuff.js +++ b/tools/lib/makestuff.js @@ -2,8 +2,8 @@ const fs = require("fs"); const CleanCSS = require('clean-css'); const path = require('path'); const _ = require('lodash'); -const config = require("../build_config"); const del = require('del'); +const config = require("../build_config.js"); async function clean(directory) { del.sync([directory]); diff --git a/tools/perf.js b/tools/perf.js index 0c31b59b44..3c37ead0a1 100755 --- a/tools/perf.js +++ b/tools/perf.js @@ -20,7 +20,7 @@ const timeTest = (name, func) => { func(); const t1 = performance.now(); console.log(` done! [${((t1 - t0) / 1000).toFixed(2)}s elapsed]`); -} +}; const oneLanguageMarkupTests = (lang) => { for (let i = 0; i < 50; i++) { @@ -52,10 +52,10 @@ const globalCheckAutoDetect = () => { }; const highlightFile = (lang) => { - const source = fs.readFileSync(`./tools/sample_files/${lang}.txt`, { encoding:'utf8' }); - const hljs = require('../build'); + const source = fs.readFileSync(`./tools/sample_files/${lang}.txt`, { encoding: 'utf8' }); + const hljs = require('../build.js'); for (let i = 0; i < 2000; i++) { - hljs.highlight(source, {language: lang}); + hljs.highlight(source, { language: lang }); } }; diff --git a/types/index.d.ts b/types/index.d.ts index dae5dff32e..c1ff73b12d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -23,6 +23,11 @@ declare module 'highlight.js' { install: (vue: any) => void } + // perhaps make this an interface? + type RegexEitherOptions = { + capture?: boolean + } + interface PublicApi { highlight: (codeOrLanguageName: string, optionsOrCode: string | HighlightOptions, ignoreIllegals?: boolean) => HighlightResult highlightAuto: (code: string, languageSubset?: string[]) => AutoHighlightResult @@ -44,6 +49,13 @@ declare module 'highlight.js' { safeMode: () => void versionString: string vuePlugin: () => VuePlugin + regex: { + concat: (...args: (RegExp | string)[]) => string, + lookahead: (re: RegExp | string) => string, + either: (...args: (RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]) => string, + optional: (re: RegExp | string) => string, + anyNumberOfTimes: (re: RegExp | string) => string + } } interface ModesAPI {