├── .gitattributes ├── .github └── workflows │ ├── ci.yml │ └── rich-navigation.yml.off ├── .gitignore ├── .lsifrc.json ├── .npmignore ├── .vscode ├── launch.json └── settings.json ├── LICENSE.md ├── README.md ├── SECURITY.md ├── ThirdPartyNotices.txt ├── api-extractor.json ├── benchmark ├── JavaScript.tmLanguage.json ├── JavaScript.tmLanguage.json.txt ├── benchmark.js ├── bootstrap.css.txt ├── bootstrap.min.css.txt ├── large.js.txt ├── large.min.js.txt ├── main.08642f99.css.txt ├── minified.js.txt └── vscode.d.ts.txt ├── build └── pipeline.yml ├── package-lock.json ├── package.json ├── scripts └── tmconvert.js ├── src ├── debug.ts ├── diffStateStacks.ts ├── encodedTokenAttributes.ts ├── grammar │ ├── basicScopesAttributeProvider.ts │ ├── grammar.ts │ ├── grammarDependencies.ts │ ├── index.ts │ └── tokenizeString.ts ├── json.ts ├── main.ts ├── matcher.ts ├── onigLib.ts ├── parseRawGrammar.ts ├── plist.ts ├── rawGrammar.ts ├── registry.ts ├── rule.ts ├── tests │ ├── all.test.ts │ ├── grammar.test.ts │ ├── inspect.ts │ ├── json.test.ts │ ├── matcher.test.ts │ ├── onigLibs.ts │ ├── resolver.ts │ ├── themeTest.ts │ ├── themedTokenizer.ts │ ├── themes.test.ts │ └── tokenization.test.ts ├── theme.ts ├── typings │ └── lib.ie11_safe_es6.d.ts └── utils.ts ├── test-cases ├── first-mate │ ├── README.md │ ├── fixtures │ │ ├── apply-end-pattern-last.json │ │ ├── c-plus-plus.json │ │ ├── c.json │ │ ├── coffee-script.json │ │ ├── content-name.json │ │ ├── css.json │ │ ├── forever.json │ │ ├── git-commit.json │ │ ├── hello.json │ │ ├── html-erb.json │ │ ├── html-rails.json │ │ ├── html.json │ │ ├── hyperlink.json │ │ ├── imaginary.json │ │ ├── include-external-repository-rule.json │ │ ├── infinite-loop.json │ │ ├── java.json │ │ ├── javascript-regex.json │ │ ├── javascript.json │ │ ├── json.json │ │ ├── latex.json │ │ ├── loops.json │ │ ├── makefile.json │ │ ├── multiline.json │ │ ├── nested-captures.json │ │ ├── objective-c-plus-plus.json │ │ ├── objective-c.json │ │ ├── php.json │ │ ├── python-regex.json │ │ ├── python.json │ │ ├── ruby-on-rails.json │ │ ├── ruby.json │ │ ├── scss.json │ │ ├── sql.json │ │ ├── text.json │ │ ├── thrift.json │ │ └── todo.json │ └── tests.json ├── suite1 │ ├── fixtures │ │ ├── 105.grammarA.json │ │ ├── 105.grammarB.json │ │ ├── 147.grammar.json │ │ ├── 66.plist │ │ ├── Jade.json │ │ ├── Jade.tmLanguage │ │ ├── Jade22.json │ │ ├── Makefile.plist │ │ ├── Markdown.tmLanguage │ │ ├── Perl.plist │ │ ├── Pug.tmLanguage │ │ ├── Ruby.plist │ │ ├── YAML.tmLanguage │ │ ├── aspvbnet.plist │ │ ├── groovy.json │ │ ├── html.json │ │ ├── html2.json │ │ ├── infinite-loop.json │ │ ├── javascript.json │ │ ├── markdown.plist │ │ ├── php.plist │ │ ├── testlang12.plist │ │ └── whileLang.plist │ ├── tests.json │ └── whileTests.json └── themes │ ├── .gitignore │ ├── Abyss.tmTheme │ ├── Kimbie_dark.tmTheme │ ├── Monokai.tmTheme │ ├── QuietLight.tmTheme │ ├── Solarized-dark.tmTheme │ ├── Solarized-light.tmTheme │ ├── Tomorrow-Night-Blue.tmTheme │ ├── dark_plus.json │ ├── dark_vs.json │ ├── dimmed-monokai.tmTheme │ ├── go │ ├── colorize-fixtures │ │ ├── test-13777.go │ │ └── test.go │ ├── colorize-results │ │ ├── test-13777_go.json │ │ └── test_go.json │ └── go.json │ ├── grammars.json │ ├── hc_black.json │ ├── languages.json │ ├── light_plus.json │ ├── light_vs.json │ ├── red.tmTheme │ ├── syntaxes │ ├── ASPVBnet.plist │ ├── Batch File.tmLanguage │ ├── Clojure.tmLanguage │ ├── Dockerfile.tmLanguage │ ├── Groovy.tmLanguage │ ├── Handlebars.json │ ├── JSON.tmLanguage │ ├── Jade.json │ ├── JavaScript.tmLanguage.json │ ├── MagicPython.tmLanguage.json │ ├── MagicRegExp.tmLanguage.json │ ├── Makefile.json │ ├── Objective-C.tmLanguage │ ├── Perl 6.tmLanguage │ ├── Perl.plist │ ├── Platform.tmLanguage │ ├── PowershellSyntax.tmLanguage │ ├── R.plist │ ├── Regular Expressions (JavaScript).tmLanguage │ ├── Ruby.plist │ ├── SQL.plist │ ├── Shell-Unix-Bash.tmLanguage.json │ ├── TypeScript.tmLanguage.json │ ├── TypeScriptReact.tmLanguage.json │ ├── c++.json │ ├── c.json │ ├── coffeescript.json │ ├── cshtml.json │ ├── css.plist │ ├── diff.tmLanguage │ ├── fsharp.json │ ├── git-commit.tmLanguage │ ├── git-rebase.tmLanguage │ ├── go.json │ ├── html.json │ ├── java.json │ ├── less.tmLanguage.json │ ├── lua.json │ ├── markdown.tmLanguage │ ├── php.json │ ├── properties.plist │ ├── rust.json │ ├── scss.json │ ├── shaderlab.json │ ├── swift.json │ ├── xml.json │ ├── xsl.json │ └── yaml.json │ ├── tests │ ├── 12750.html │ ├── 12750.html.result │ ├── 13448.html │ ├── 13448.html.result │ ├── 14119.less │ ├── 14119.less.result │ ├── COMMIT_EDITMSG │ ├── COMMIT_EDITMSG.result │ ├── Dockerfile │ ├── Dockerfile.result │ ├── basic.java │ ├── basic.java.result │ ├── git-rebase-todo │ ├── git-rebase-todo.result │ ├── issue-1550.yaml │ ├── issue-1550.yaml.result │ ├── issue-4008.yaml │ ├── issue-4008.yaml.result │ ├── issue-6303.yaml │ ├── issue-6303.yaml.result │ ├── makefile │ ├── makefile.result │ ├── test-13777.go │ ├── test-13777.go.result │ ├── test-4287.jade │ ├── test-4287.jade.result │ ├── test-6611.rs │ ├── test-6611.rs.result │ ├── test-7115.xml │ ├── test-7115.xml.result │ ├── test-brackets.tsx │ ├── test-brackets.tsx.result │ ├── test-cssvariables.less │ ├── test-cssvariables.less.result │ ├── test-cssvariables.scss │ ├── test-cssvariables.scss.result │ ├── test-function-inv.ts │ ├── test-function-inv.ts.result │ ├── test-issue11.ts │ ├── test-issue11.ts.result │ ├── test-issue5431.ts │ ├── test-issue5431.ts.result │ ├── test-issue5465.ts │ ├── test-issue5465.ts.result │ ├── test-issue5566.ts │ ├── test-issue5566.ts.result │ ├── test-keywords.ts │ ├── test-keywords.ts.result │ ├── test-members.ts │ ├── test-members.ts.result │ ├── test-object-literals.ts │ ├── test-object-literals.ts.result │ ├── test-regex.coffee │ ├── test-regex.coffee.result │ ├── test-strings.ts │ ├── test-strings.ts.result │ ├── test-this.ts │ ├── test-this.ts.result │ ├── test-variables.css │ ├── test-variables.css.result │ ├── test.bat │ ├── test.bat.result │ ├── test.c │ ├── test.c.result │ ├── test.cc │ ├── test.cc.result │ ├── test.clj │ ├── test.clj.result │ ├── test.coffee │ ├── test.coffee.result │ ├── test.cpp │ ├── test.cpp.result │ ├── test.cshtml │ ├── test.cshtml.result │ ├── test.css │ ├── test.css.result │ ├── test.diff │ ├── test.diff.result │ ├── test.fs │ ├── test.fs.result │ ├── test.go │ ├── test.go.result │ ├── test.groovy │ ├── test.groovy.result │ ├── test.handlebars │ ├── test.handlebars.result │ ├── test.hbs │ ├── test.hbs.result │ ├── test.html │ ├── test.html.result │ ├── test.ini │ ├── test.ini.result │ ├── test.js │ ├── test.js.result │ ├── test.json │ ├── test.json.result │ ├── test.jsx │ ├── test.jsx.result │ ├── test.less │ ├── test.less.result │ ├── test.lua │ ├── test.lua.result │ ├── test.m │ ├── test.m.result │ ├── test.md │ ├── test.md.result │ ├── test.php │ ├── test.php.result │ ├── test.pl │ ├── test.pl.result │ ├── test.ps1 │ ├── test.ps1.result │ ├── test.py │ ├── test.py.result │ ├── test.r │ ├── test.r.result │ ├── test.rb │ ├── test.rb.result │ ├── test.rs │ ├── test.rs.result │ ├── test.scss │ ├── test.scss.result │ ├── test.sh │ ├── test.sh.result │ ├── test.shader │ ├── test.shader.result │ ├── test.sql │ ├── test.sql.result │ ├── test.swift │ ├── test.swift.result │ ├── test.ts │ ├── test.ts.result │ ├── test.vb │ ├── test.vb.result │ ├── test.xml │ ├── test.xml.result │ ├── test.yaml │ ├── test.yaml.result │ ├── test2.pl │ ├── test2.pl.result │ ├── test6916.js │ ├── test6916.js.result │ ├── tsconfig.json │ └── tsconfig.json.result │ └── tsconfig.json ├── tsconfig.json └── webpack.config.js /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [pull_request] 4 | 5 | jobs: 6 | build: 7 | name: CI 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-node@v2 12 | with: 13 | node-version: 14 14 | - run: npm ci 15 | - run: npm run compile 16 | - run: npm test 17 | -------------------------------------------------------------------------------- /.github/workflows/rich-navigation.yml.off: -------------------------------------------------------------------------------- 1 | name: "Rich Navigation Indexing" 2 | on: 3 | workflow_dispatch: 4 | pull_request: 5 | push: 6 | branches: 7 | - main 8 | tags: 9 | - 'v[0-9]+.[0-9]+.[0-9]+' 10 | 11 | jobs: 12 | richnav: 13 | runs-on: windows-latest 14 | steps: 15 | - uses: actions/checkout@v2 16 | 17 | - uses: actions/setup-node@v2 18 | with: 19 | node-version: 14 20 | 21 | - name: Install dependencies 22 | run: npm install 23 | 24 | - uses: microsoft/RichCodeNavIndexer@v0.1 25 | with: 26 | languages: typescript 27 | repo-token: ${{ secrets.GITHUB_TOKEN }} 28 | typescriptVersion: 0.6.0-next.19 29 | configFiles: .lsifrc.json 30 | continue-on-error: true 31 | 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /coverage/ 2 | /node_modules/ 3 | /out/ 4 | /release/ 5 | *.lsif 6 | /temp/ 7 | /types/ 8 | etc/ -------------------------------------------------------------------------------- /.lsifrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "project": "./tsconfig.json", 3 | "out": "vscode-textmate.lsif", 4 | "source": "./package.json", 5 | "package": "./package.json" 6 | } -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /.vscode/ 2 | /benchmark/ 3 | /build/ 4 | /coverage/ 5 | /out/ 6 | /scripts/ 7 | /src/ 8 | /test-cases/ 9 | /typings/ 10 | /.npmignore 11 | /azure-pipelines.yml 12 | /build-template.yml 13 | /npm-debug.log 14 | /ThirdPartyNotices.txt 15 | /tsconfig.json 16 | /tslint.json 17 | /webpack.config.js 18 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "configurations": [ 4 | 5 | { 6 | "name": "Launch tests", 7 | "type": "node", 8 | "request": "launch", 9 | "program": "${workspaceRoot}/node_modules/mocha/bin/mocha", 10 | "stopOnEntry": false, 11 | "args": [ "--ui=tdd", "./out/tests/all.test.js"], 12 | "cwd": "${workspaceRoot}", 13 | "runtimeExecutable": null, 14 | "runtimeArgs": ["--nolazy"], 15 | "env": { 16 | "NODE_ENV": "development" 17 | }, 18 | "console": "internalConsole", 19 | "sourceMaps": true, 20 | "outFiles": [ "out/**" ] 21 | }, 22 | { 23 | "type": "node", 24 | "request": "launch", 25 | "name": "Launch benchmark", 26 | "program": "${workspaceFolder}/benchmark/benchmark.js" 27 | } 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | // Place your settings in this file to overwrite default and user settings. 2 | { 3 | "files.trimTrailingWhitespace": true, 4 | "editor.insertSpaces": false, 5 | "editor.tabSize": 4, 6 | "search.exclude": { 7 | "**/node_modules": true, 8 | "**/bower_components": true, 9 | "out/**": true, 10 | "release/**": true, 11 | "coverage/**": true 12 | }, 13 | "git.branchProtection": [ 14 | "main", 15 | "release/*" 16 | ], 17 | "git.branchProtectionPrompt": "alwaysCommitToNewBranch", 18 | "git.branchRandomName.enable": true, 19 | "lcov.sourceMaps": true, 20 | "typescript.tsdk": "./node_modules/typescript/lib", 21 | "tslint.enable": true, 22 | "mochaExplorer.ui": "tdd", 23 | "testExplorer.useNativeTesting": true, 24 | "mochaExplorer.files": "out/tests/all.test.js", 25 | "sarif-viewer.connectToGithubCodeScanning": "off", 26 | "files.associations": { 27 | "api-extractor.json": "jsonc", 28 | "tsdoc-metadata.json": "jsonc" 29 | } 30 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Microsoft Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # VSCode TextMate [![Build Status](https://dev.azure.com/ms/vscode-textmate/_apis/build/status/microsoft.vscode-textmate?branchName=master)](https://dev.azure.com/ms/vscode-textmate/_build/latest?definitionId=172&branchName=master) 2 | 3 | An interpreter for grammar files as defined by TextMate. TextMate grammars use the oniguruma dialect (https://github.com/kkos/oniguruma). Supports loading grammar files from JSON or PLIST format. This library is used in VS Code. Cross - grammar injections are currently not supported. 4 | 5 | ## Installing 6 | 7 | ```sh 8 | npm install vscode-textmate 9 | ``` 10 | 11 | ## Using 12 | 13 | ```javascript 14 | const fs = require('fs'); 15 | const path = require('path'); 16 | const vsctm = require('vscode-textmate'); 17 | const oniguruma = require('vscode-oniguruma'); 18 | 19 | /** 20 | * Utility to read a file as a promise 21 | */ 22 | function readFile(path) { 23 | return new Promise((resolve, reject) => { 24 | fs.readFile(path, (error, data) => error ? reject(error) : resolve(data)); 25 | }) 26 | } 27 | 28 | const wasmBin = fs.readFileSync(path.join(__dirname, './node_modules/vscode-oniguruma/release/onig.wasm')).buffer; 29 | const vscodeOnigurumaLib = oniguruma.loadWASM(wasmBin).then(() => { 30 | return { 31 | createOnigScanner(patterns) { return new oniguruma.OnigScanner(patterns); }, 32 | createOnigString(s) { return new oniguruma.OnigString(s); } 33 | }; 34 | }); 35 | 36 | // Create a registry that can create a grammar from a scope name. 37 | const registry = new vsctm.Registry({ 38 | onigLib: vscodeOnigurumaLib, 39 | loadGrammar: (scopeName) => { 40 | if (scopeName === 'source.js') { 41 | // https://github.com/textmate/javascript.tmbundle/blob/master/Syntaxes/JavaScript.plist 42 | return readFile('./JavaScript.plist').then(data => vsctm.parseRawGrammar(data.toString())) 43 | } 44 | console.log(`Unknown scope name: ${scopeName}`); 45 | return null; 46 | } 47 | }); 48 | 49 | // Load the JavaScript grammar and any other grammars included by it async. 50 | registry.loadGrammar('source.js').then(grammar => { 51 | const text = [ 52 | `function sayHello(name) {`, 53 | `\treturn "Hello, " + name;`, 54 | `}` 55 | ]; 56 | let ruleStack = vsctm.INITIAL; 57 | for (let i = 0; i < text.length; i++) { 58 | const line = text[i]; 59 | const lineTokens = grammar.tokenizeLine(line, ruleStack); 60 | console.log(`\nTokenizing line: ${line}`); 61 | for (let j = 0; j < lineTokens.tokens.length; j++) { 62 | const token = lineTokens.tokens[j]; 63 | console.log(` - token from ${token.startIndex} to ${token.endIndex} ` + 64 | `(${line.substring(token.startIndex, token.endIndex)}) ` + 65 | `with scopes ${token.scopes.join(', ')}` 66 | ); 67 | } 68 | ruleStack = lineTokens.ruleStack; 69 | } 70 | }); 71 | 72 | /* OUTPUT: 73 | 74 | Unknown scope name: source.js.regexp 75 | 76 | Tokenizing line: function sayHello(name) { 77 | - token from 0 to 8 (function) with scopes source.js, meta.function.js, storage.type.function.js 78 | - token from 8 to 9 ( ) with scopes source.js, meta.function.js 79 | - token from 9 to 17 (sayHello) with scopes source.js, meta.function.js, entity.name.function.js 80 | - token from 17 to 18 (() with scopes source.js, meta.function.js, punctuation.definition.parameters.begin.js 81 | - token from 18 to 22 (name) with scopes source.js, meta.function.js, variable.parameter.function.js 82 | - token from 22 to 23 ()) with scopes source.js, meta.function.js, punctuation.definition.parameters.end.js 83 | - token from 23 to 24 ( ) with scopes source.js 84 | - token from 24 to 25 ({) with scopes source.js, punctuation.section.scope.begin.js 85 | 86 | Tokenizing line: return "Hello, " + name; 87 | - token from 0 to 1 ( ) with scopes source.js 88 | - token from 1 to 7 (return) with scopes source.js, keyword.control.js 89 | - token from 7 to 8 ( ) with scopes source.js 90 | - token from 8 to 9 (") with scopes source.js, string.quoted.double.js, punctuation.definition.string.begin.js 91 | - token from 9 to 16 (Hello, ) with scopes source.js, string.quoted.double.js 92 | - token from 16 to 17 (") with scopes source.js, string.quoted.double.js, punctuation.definition.string.end.js 93 | - token from 17 to 18 ( ) with scopes source.js 94 | - token from 18 to 19 (+) with scopes source.js, keyword.operator.arithmetic.js 95 | - token from 19 to 20 ( ) with scopes source.js 96 | - token from 20 to 24 (name) with scopes source.js, support.constant.dom.js 97 | - token from 24 to 25 (;) with scopes source.js, punctuation.terminator.statement.js 98 | 99 | Tokenizing line: } 100 | - token from 0 to 1 (}) with scopes source.js, punctuation.section.scope.end.js 101 | 102 | */ 103 | 104 | ``` 105 | 106 | ## For grammar authors 107 | 108 | See [vscode-tmgrammar-test](https://github.com/PanAeon/vscode-tmgrammar-test) that can help you write unit tests against your grammar. 109 | 110 | ## API doc 111 | 112 | See [the main.ts file](./src/main.ts) 113 | 114 | ## Developing 115 | 116 | * Clone the repository 117 | * Run `npm install` 118 | * Compile in the background with `npm run watch` 119 | * Run tests with `npm test` 120 | * Run benchmark with `npm run benchmark` 121 | * Troubleshoot a grammar with `npm run inspect -- PATH_TO_GRAMMAR PATH_TO_FILE` 122 | 123 | ## Code of Conduct 124 | 125 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 126 | 127 | 128 | ## License 129 | [MIT](https://github.com/Microsoft/vscode-textmate/blob/master/LICENSE.md) 130 | 131 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). 6 | 7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/en-us/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/en-us/msrc/pgp-key-msrc). 16 | 17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 18 | 19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/en-us/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /ThirdPartyNotices.txt: -------------------------------------------------------------------------------- 1 | THIRD-PARTY SOFTWARE NOTICES AND INFORMATION 2 | Do Not Translate or Localize 3 | 4 | This project incorporates material from the project(s) listed below (collectively, “Third Party Code”). 5 | Microsoft is not the original author of the Third Party Code. The original copyright notice and license 6 | under which Microsoft received such Third Party Code are set out below. This Third Party Code is licensed 7 | to you under their original license terms set forth below. Microsoft reserves all other rights not 8 | expressly granted, whether by implication, estoppel or otherwise. 9 | 10 | The following files/folders contain third party software used for development-time testing: 11 | 12 | ========================================================================================================= 13 | benchmark/bootstrap.css, benchmark/bootstrap.min.css 14 | --------------------------------------------------------------------------------------------------------- 15 | The MIT License (MIT) 16 | 17 | Copyright (c) 2011-2015 Twitter, Inc 18 | 19 | Permission is hereby granted, free of charge, to any person obtaining a copy 20 | of this software and associated documentation files (the "Software"), to deal 21 | in the Software without restriction, including without limitation the rights 22 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 23 | copies of the Software, and to permit persons to whom the Software is 24 | furnished to do so, subject to the following conditions: 25 | 26 | The above copyright notice and this permission notice shall be included in 27 | all copies or substantial portions of the Software. 28 | 29 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 32 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 33 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 34 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 35 | THE SOFTWARE. 36 | ========================================================================================================= 37 | 38 | 39 | 40 | ========================================================================================================= 41 | benchmark/large.js, benchmark/large.min.js 42 | --------------------------------------------------------------------------------------------------------- 43 | The MIT License (MIT) 44 | 45 | Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors 46 | 47 | Permission is hereby granted, free of charge, to any person obtaining a copy 48 | of this software and associated documentation files (the "Software"), to deal 49 | in the Software without restriction, including without limitation the rights 50 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 51 | copies of the Software, and to permit persons to whom the Software is 52 | furnished to do so, subject to the following conditions: 53 | 54 | The above copyright notice and this permission notice shall be included in 55 | all copies or substantial portions of the Software. 56 | 57 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 58 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 59 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 60 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 61 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 62 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 63 | THE SOFTWARE. 64 | ========================================================================================================= 65 | 66 | 67 | 68 | ========================================================================================================= 69 | test-cases/first-mate/** 70 | --------------------------------------------------------------------------------------------------------- 71 | The MIT License (MIT) 72 | 73 | Copyright (c) 2013 GitHub Inc. 74 | 75 | Permission is hereby granted, free of charge, to any person obtaining a copy 76 | of this software and associated documentation files (the "Software"), to deal 77 | in the Software without restriction, including without limitation the rights 78 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 79 | copies of the Software, and to permit persons to whom the Software is 80 | furnished to do so, subject to the following conditions: 81 | 82 | The above copyright notice and this permission notice shall be included in 83 | all copies or substantial portions of the Software. 84 | 85 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 86 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 87 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 88 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 89 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 90 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 91 | THE SOFTWARE. 92 | ========================================================================================================= 93 | 94 | 95 | 96 | ========================================================================================================= 97 | test-cases/suite1/** 98 | --------------------------------------------------------------------------------------------------------- 99 | Copyright (c) TextMate project authors 100 | 101 | If not otherwise specified (see below), files in this repository fall under the following license: 102 | 103 | Permission to copy, use, modify, sell and distribute this 104 | software is granted. This software is provided "as is" without 105 | express or implied warranty, and with no claim as to its 106 | suitability for any purpose. 107 | 108 | An exception is made for files in readable text which contain their own license information, 109 | or files where an accompanying file exists (in the same directory) with a "-license" suffix added 110 | to the base-name name of the original file, and an extension of txt, html, or similar. For example 111 | "tidy" is accompanied by "tidy-license.txt". 112 | ========================================================================================================= -------------------------------------------------------------------------------- /benchmark/benchmark.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const fs = require('fs'); 3 | const main = require('../release/main'); 4 | const onigLibs = require('../out/tests/onigLibs'); 5 | 6 | const Registry = main.Registry; 7 | 8 | const onigurumaRegistry = new Registry({ loadGrammar, onigLib: onigLibs.getOniguruma()}); 9 | 10 | function tokenize(grammar, content) { 11 | const start = Date.now(); 12 | let ruleStack = null; 13 | for (let i = 0; i < content.length; i++) { 14 | const r = grammar.tokenizeLine(content[i], ruleStack); 15 | ruleStack = r.ruleStack; 16 | } 17 | return Date.now() - start; 18 | } 19 | 20 | async function tokenizeFile(filePath, scope, message) { 21 | const content = fs.readFileSync(filePath, 'utf8') 22 | const lines = content.split(/\r\n|\r|\n/); 23 | 24 | let onigurumaGrammar = await onigurumaRegistry.loadGrammar(scope); 25 | let onigurumaTime = tokenize(onigurumaGrammar, lines); 26 | 27 | console.log(); 28 | console.log(message); 29 | console.log('TOKENIZING ' + content.length + ' lines using grammar ' + scope); 30 | console.log(`Oniguruma: ${onigurumaTime} ms.`); 31 | } 32 | 33 | function loadGrammar(scopeName) { 34 | let grammarPath = null; 35 | if (scopeName === 'source.js') { 36 | grammarPath = path.resolve(__dirname, 'JavaScript.tmLanguage.json'); 37 | } else if (scopeName === 'source.ts') { 38 | grammarPath = path.resolve(__dirname, '..', 'test-cases/themes/syntaxes/TypeScript.tmLanguage.json'); 39 | } else if (scopeName === 'source.css') { 40 | grammarPath = path.resolve(__dirname, '..', 'test-cases/first-mate/fixtures/css.json'); 41 | } else if (scopeName === 'source.json') { 42 | grammarPath = path.resolve(__dirname, '..', 'test-cases/themes/syntaxes/JSON.json'); 43 | } else { 44 | return null; 45 | } 46 | return Promise.resolve(main.parseRawGrammar(fs.readFileSync(grammarPath).toString(), grammarPath)); 47 | } 48 | 49 | async function test() { 50 | await tokenizeFile(path.join(__dirname, 'large.js.txt'), 'source.js', 'jQuery v2.0.3'); 51 | await tokenizeFile(path.join(__dirname, 'bootstrap.css.txt'), 'source.css', 'Bootstrap CSS v3.1.1'), 52 | await tokenizeFile(path.join(__dirname, 'vscode.d.ts.txt'), 'source.ts', 'vscode.d.ts'); 53 | await tokenizeFile(path.join(__dirname, 'JavaScript.tmLanguage.json.txt'), 'source.ts', 'JSON'); 54 | await tokenizeFile(path.join(__dirname, 'bootstrap.min.css.txt'), 'source.css', 'Bootstrap CSS v3.1.1 minified') 55 | await tokenizeFile(path.join(__dirname, 'large.min.js.txt'), 'source.js', 'jQuery v2.0.3 minified'); 56 | await tokenizeFile(path.join(__dirname, 'main.08642f99.css.txt'), 'source.css', 'Bootstrap with multi-byte minified') 57 | await tokenizeFile(path.join(__dirname, 'minified.js.txt'), 'source.js', 'Simple minified file'); 58 | }; 59 | test(); 60 | 61 | 62 | -------------------------------------------------------------------------------- /build/pipeline.yml: -------------------------------------------------------------------------------- 1 | name: $(Date:yyyyMMdd)$(Rev:.r) 2 | 3 | trigger: 4 | batch: true 5 | branches: 6 | include: 7 | - main 8 | pr: none 9 | 10 | resources: 11 | repositories: 12 | - repository: templates 13 | type: github 14 | name: microsoft/vscode-engineering 15 | ref: main 16 | endpoint: Monaco 17 | 18 | parameters: 19 | - name: publishPackage 20 | displayName: 🚀 Publish vscode-textmate 21 | type: boolean 22 | default: false 23 | 24 | extends: 25 | template: azure-pipelines/npm-package/pipeline.yml@templates 26 | parameters: 27 | npmPackages: 28 | - name: vscode-textmate 29 | 30 | buildSteps: 31 | - script: npm ci 32 | displayName: Install dependencies 33 | 34 | - script: npm run compile 35 | displayName: Compile 36 | 37 | - script: npm run bundle 38 | displayName: Bundle 39 | 40 | testPlatforms: 41 | - name: Linux 42 | nodeVersions: 43 | - 16.x 44 | 45 | testSteps: 46 | - script: npm ci 47 | displayName: Install dependencies 48 | 49 | - script: npm run compile 50 | displayName: Compile 51 | 52 | - script: npm test 53 | displayName: Test 54 | 55 | publishPackage: ${{ parameters.publishPackage }} 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vscode-textmate", 3 | "version": "9.2.0", 4 | "description": "VSCode TextMate grammar helpers", 5 | "author": { 6 | "name": "Microsoft Corporation" 7 | }, 8 | "main": "./release/main.js", 9 | "typings": "./types/vscode-textmate.d.ts", 10 | "files": [ 11 | "release/**/*.js", 12 | "!release/tests/**/*.js", 13 | "types/vscode-textmate.d.ts" 14 | ], 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/microsoft/vscode-textmate" 18 | }, 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/microsoft/vscode-textmate/issues" 22 | }, 23 | "scripts": { 24 | "watch": "tsc --watch", 25 | "compile": "tsc", 26 | "test": "mocha --ui=tdd ./out/tests/all.test.js", 27 | "benchmark": "node benchmark/benchmark.js", 28 | "inspect": "node out/tests/inspect.js", 29 | "tmconvert": "node scripts/tmconvert.js", 30 | "version": "npm run compile && npm run test", 31 | "postversion": "git push && git push --tags", 32 | "prepublishOnly": "tsc && webpack --progress && npm run api-extractor", 33 | "bundle": "webpack && npm run api-extractor", 34 | "api-extractor": "mkdirp etc && npx api-extractor run --local" 35 | }, 36 | "devDependencies": { 37 | "@microsoft/api-extractor": "^7.48.0", 38 | "@types/mocha": "^9.1.0", 39 | "@types/node": "^16.6.1", 40 | "copy-webpack-plugin": "^9.1.0", 41 | "mkdirp": "^3.0.1", 42 | "mocha": "^11.1.0", 43 | "typescript": "^4.3.5", 44 | "vscode-oniguruma": "^1.5.1", 45 | "webpack": "^5.50.0", 46 | "webpack-cli": "^4.8.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /scripts/tmconvert.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | 3 | 4 | if (process.argv.length < 3) { 5 | console.log('usage: node index.js '); 6 | process.exit(0); 7 | } 8 | 9 | const GRAMMAR_PATH = process.argv[process.argv.length - 1]; 10 | let contents = JSON.parse(fs.readFileSync(GRAMMAR_PATH).toString()); 11 | delete contents['information_for_contributors']; 12 | delete contents['version']; 13 | delete contents['name']; 14 | delete contents['scopeName']; 15 | let strContents = JSON.stringify(contents, null, ' '); 16 | 17 | strContents = strContents.replace(/"([\w-]+)": /g, '$1 = ') 18 | strContents = strContents.replace(/ = "(.*)",/g, ' = "$1";') 19 | strContents = strContents.replace(/"(\s*)\}/mg, '";$1}') 20 | strContents = strContents.replace(/\[\n/mg, '(\n') 21 | strContents = strContents.replace(/\],\n/mg, ');\n') 22 | strContents = strContents.replace(/\]\n/mg, ');\n') 23 | strContents = strContents.replace(/\},\n(\s*)([^{ ])/mg, '};\n$1$2') 24 | strContents = strContents.replace(/\}\n(\s*)([^) ])/mg, '};\n$1$2') 25 | strContents = strContents.replace(/\}\n(\s*)([^) ])/mg, '};\n$1$2') 26 | 27 | console.log(strContents); 28 | 29 | -------------------------------------------------------------------------------- /src/debug.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | export const DebugFlags = { 6 | InDebugMode: (typeof process !== 'undefined' && !!process.env['VSCODE_TEXTMATE_DEBUG']) 7 | }; 8 | 9 | export const UseOnigurumaFindOptions = false; 10 | -------------------------------------------------------------------------------- /src/diffStateStacks.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { StateStackImpl, StateStackFrame } from "./grammar"; 6 | import { StateStack } from "./main"; 7 | 8 | export function diffStateStacksRefEq(first: StateStack, second: StateStack): StackDiff { 9 | let pops = 0; 10 | const newFrames: StateStackFrame[] = []; 11 | 12 | let curFirst: StateStackImpl | null = first as StateStackImpl; 13 | let curSecond: StateStackImpl | null = second as StateStackImpl; 14 | 15 | while (curFirst !== curSecond) { 16 | if (curFirst && (!curSecond || curFirst.depth >= curSecond.depth)) { 17 | // curFirst is certainly not contained in curSecond 18 | pops++; 19 | curFirst = curFirst.parent; 20 | } else { 21 | // curSecond is certainly not contained in curFirst. 22 | // Also, curSecond must be defined, as otherwise a previous case would match 23 | newFrames.push(curSecond!.toStateStackFrame()); 24 | curSecond = curSecond!.parent; 25 | } 26 | } 27 | return { 28 | pops, 29 | newFrames: newFrames.reverse(), 30 | }; 31 | } 32 | 33 | export function applyStateStackDiff(stack: StateStack | null, diff: StackDiff): StateStackImpl | null { 34 | let curStack = stack as StateStackImpl | null; 35 | for (let i = 0; i < diff.pops; i++) { 36 | curStack = curStack!.parent; 37 | } 38 | for (const frame of diff.newFrames) { 39 | curStack = StateStackImpl.pushFrame(curStack, frame); 40 | } 41 | return curStack; 42 | } 43 | 44 | export interface StackDiff { 45 | readonly pops: number; 46 | readonly newFrames: StateStackFrame[]; 47 | } 48 | -------------------------------------------------------------------------------- /src/grammar/basicScopesAttributeProvider.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { OptionalStandardTokenType } from "../encodedTokenAttributes"; 6 | import { IEmbeddedLanguagesMap } from "../main"; 7 | import { ScopeName } from "../theme"; 8 | import { CachedFn, escapeRegExpCharacters } from "../utils"; 9 | 10 | export class BasicScopeAttributes { 11 | constructor( 12 | public readonly languageId: number, 13 | public readonly tokenType: OptionalStandardTokenType 14 | ) { 15 | } 16 | } 17 | 18 | export class BasicScopeAttributesProvider { 19 | private readonly _defaultAttributes: BasicScopeAttributes; 20 | private readonly _embeddedLanguagesMatcher: ScopeMatcher; 21 | 22 | constructor(initialLanguageId: number, embeddedLanguages: IEmbeddedLanguagesMap | null) { 23 | this._defaultAttributes = new BasicScopeAttributes(initialLanguageId, OptionalStandardTokenType.NotSet); 24 | this._embeddedLanguagesMatcher = new ScopeMatcher(Object.entries(embeddedLanguages || {})); 25 | } 26 | 27 | public getDefaultAttributes(): BasicScopeAttributes { 28 | return this._defaultAttributes; 29 | } 30 | 31 | public getBasicScopeAttributes(scopeName: ScopeName | null): BasicScopeAttributes { 32 | if (scopeName === null) { 33 | return BasicScopeAttributesProvider._NULL_SCOPE_METADATA; 34 | } 35 | return this._getBasicScopeAttributes.get(scopeName); 36 | } 37 | 38 | private static readonly _NULL_SCOPE_METADATA = new BasicScopeAttributes(0, 0); 39 | 40 | private readonly _getBasicScopeAttributes = new CachedFn((scopeName) => { 41 | const languageId = this._scopeToLanguage(scopeName); 42 | const standardTokenType = this._toStandardTokenType(scopeName); 43 | return new BasicScopeAttributes(languageId, standardTokenType); 44 | }); 45 | 46 | /** 47 | * Given a produced TM scope, return the language that token describes or null if unknown. 48 | * e.g. source.html => html, source.css.embedded.html => css, punctuation.definition.tag.html => null 49 | */ 50 | private _scopeToLanguage(scope: ScopeName): number { 51 | return this._embeddedLanguagesMatcher.match(scope) || 0; 52 | } 53 | 54 | private _toStandardTokenType(scopeName: ScopeName): OptionalStandardTokenType { 55 | const m = scopeName.match(BasicScopeAttributesProvider.STANDARD_TOKEN_TYPE_REGEXP); 56 | if (!m) { 57 | return OptionalStandardTokenType.NotSet; 58 | } 59 | switch (m[1]) { 60 | case "comment": 61 | return OptionalStandardTokenType.Comment; 62 | case "string": 63 | return OptionalStandardTokenType.String; 64 | case "regex": 65 | return OptionalStandardTokenType.RegEx; 66 | case "meta.embedded": 67 | return OptionalStandardTokenType.Other; 68 | } 69 | throw new Error("Unexpected match for standard token type!"); 70 | } 71 | 72 | private static STANDARD_TOKEN_TYPE_REGEXP = /\b(comment|string|regex|meta\.embedded)\b/; 73 | } 74 | 75 | class ScopeMatcher { 76 | private readonly values: ReadonlyMap | null; 77 | private readonly scopesRegExp: RegExp | null; 78 | 79 | constructor(values: [ScopeName, TValue][]) { 80 | if (values.length === 0) { 81 | this.values = null; 82 | this.scopesRegExp = null; 83 | } else { 84 | this.values = new Map(values); 85 | 86 | // create the regex 87 | const escapedScopes = values.map( 88 | ([scopeName, value]) => escapeRegExpCharacters(scopeName) 89 | ); 90 | 91 | escapedScopes.sort(); 92 | escapedScopes.reverse(); // Longest scope first 93 | this.scopesRegExp = new RegExp( 94 | `^((${escapedScopes.join(")|(")}))($|\\.)`, 95 | "" 96 | ); 97 | } 98 | } 99 | 100 | public match(scope: ScopeName): TValue | undefined { 101 | if (!this.scopesRegExp) { 102 | return undefined; 103 | } 104 | const m = scope.match(this.scopesRegExp); 105 | if (!m) { 106 | // no scopes matched 107 | return undefined; 108 | } 109 | return this.values!.get(m[1])!; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/grammar/index.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | export * from './grammar'; -------------------------------------------------------------------------------- /src/matcher.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | export interface MatcherWithPriority { 6 | matcher: Matcher; 7 | priority: -1 | 0 | 1; 8 | } 9 | 10 | export interface Matcher { 11 | (matcherInput: T): boolean; 12 | } 13 | 14 | export function createMatchers(selector: string, matchesName: (names: string[], matcherInput: T) => boolean): MatcherWithPriority[] { 15 | const results = []>[]; 16 | const tokenizer = newTokenizer(selector); 17 | let token = tokenizer.next(); 18 | while (token !== null) { 19 | let priority: -1 | 0 | 1 = 0; 20 | if (token.length === 2 && token.charAt(1) === ':') { 21 | switch (token.charAt(0)) { 22 | case 'R': priority = 1; break; 23 | case 'L': priority = -1; break; 24 | default: 25 | console.log(`Unknown priority ${token} in scope selector`); 26 | } 27 | token = tokenizer.next(); 28 | } 29 | let matcher = parseConjunction(); 30 | results.push({ matcher, priority }); 31 | if (token !== ',') { 32 | break; 33 | } 34 | token = tokenizer.next(); 35 | } 36 | return results; 37 | 38 | function parseOperand(): Matcher | null { 39 | if (token === '-') { 40 | token = tokenizer.next(); 41 | const expressionToNegate = parseOperand(); 42 | return matcherInput => !!expressionToNegate && !expressionToNegate(matcherInput); 43 | } 44 | if (token === '(') { 45 | token = tokenizer.next(); 46 | const expressionInParents = parseInnerExpression(); 47 | if (token === ')') { 48 | token = tokenizer.next(); 49 | } 50 | return expressionInParents; 51 | } 52 | if (isIdentifier(token)) { 53 | const identifiers: string[] = []; 54 | do { 55 | identifiers.push(token); 56 | token = tokenizer.next(); 57 | } while (isIdentifier(token)); 58 | return matcherInput => matchesName(identifiers, matcherInput); 59 | } 60 | return null; 61 | } 62 | function parseConjunction(): Matcher { 63 | const matchers: Matcher[] = []; 64 | let matcher = parseOperand(); 65 | while (matcher) { 66 | matchers.push(matcher); 67 | matcher = parseOperand(); 68 | } 69 | return matcherInput => matchers.every(matcher => matcher(matcherInput)); // and 70 | } 71 | function parseInnerExpression(): Matcher { 72 | const matchers: Matcher[] = []; 73 | let matcher = parseConjunction(); 74 | while (matcher) { 75 | matchers.push(matcher); 76 | if (token === '|' || token === ',') { 77 | do { 78 | token = tokenizer.next(); 79 | } while (token === '|' || token === ','); // ignore subsequent commas 80 | } else { 81 | break; 82 | } 83 | matcher = parseConjunction(); 84 | } 85 | return matcherInput => matchers.some(matcher => matcher(matcherInput)); // or 86 | } 87 | } 88 | 89 | function isIdentifier(token: string | null): token is string { 90 | return !!token && !!token.match(/[\w\.:]+/); 91 | } 92 | 93 | function newTokenizer(input: string): { next: () => string | null } { 94 | let regex = /([LR]:|[\w\.:][\w\.:\-]*|[\,\|\-\(\)])/g; 95 | let match = regex.exec(input); 96 | return { 97 | next: () => { 98 | if (!match) { 99 | return null; 100 | } 101 | const res = match[0]; 102 | match = regex.exec(input); 103 | return res; 104 | } 105 | }; 106 | } 107 | -------------------------------------------------------------------------------- /src/onigLib.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { OrMask } from "./utils"; 6 | 7 | export interface IOnigLib { 8 | createOnigScanner(sources: string[]): OnigScanner; 9 | createOnigString(str: string): OnigString; 10 | } 11 | 12 | export interface IOnigCaptureIndex { 13 | start: number; 14 | end: number; 15 | length: number; 16 | } 17 | 18 | export interface IOnigMatch { 19 | index: number; 20 | captureIndices: IOnigCaptureIndex[]; 21 | } 22 | 23 | export const enum FindOption { 24 | None = 0, 25 | /** 26 | * equivalent of ONIG_OPTION_NOT_BEGIN_STRING: (str) isn't considered as begin of string (* fail \A) 27 | */ 28 | NotBeginString = 1, 29 | /** 30 | * equivalent of ONIG_OPTION_NOT_END_STRING: (end) isn't considered as end of string (* fail \z, \Z) 31 | */ 32 | NotEndString = 2, 33 | /** 34 | * equivalent of ONIG_OPTION_NOT_BEGIN_POSITION: (start) isn't considered as start position of search (* fail \G) 35 | */ 36 | NotBeginPosition = 4, 37 | /** 38 | * used for debugging purposes. 39 | */ 40 | DebugCall = 8, 41 | } 42 | 43 | export interface OnigScanner { 44 | findNextMatchSync(string: string | OnigString, startPosition: number, options: OrMask): IOnigMatch | null; 45 | dispose?(): void; 46 | } 47 | 48 | export interface OnigString { 49 | readonly content: string; 50 | dispose?(): void; 51 | } 52 | 53 | export function disposeOnigString(str: OnigString) { 54 | if (typeof str.dispose === 'function') { 55 | str.dispose(); 56 | } 57 | } -------------------------------------------------------------------------------- /src/parseRawGrammar.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { IRawGrammar } from './rawGrammar'; 6 | import * as plist from './plist'; 7 | import { DebugFlags } from './debug'; 8 | import { parseJSON } from './json'; 9 | 10 | export function parseRawGrammar(content: string, filePath: string | null = null): IRawGrammar { 11 | if (filePath !== null && /\.json$/.test(filePath)) { 12 | return parseJSONGrammar(content, filePath); 13 | } 14 | return parsePLISTGrammar(content, filePath); 15 | } 16 | 17 | function parseJSONGrammar(contents: string, filename: string | null): IRawGrammar { 18 | if (DebugFlags.InDebugMode) { 19 | return parseJSON(contents, filename, true); 20 | } 21 | return JSON.parse(contents); 22 | } 23 | 24 | function parsePLISTGrammar(contents: string, filename: string | null): IRawGrammar { 25 | if (DebugFlags.InDebugMode) { 26 | return plist.parseWithLocation(contents, filename, '$vscodeTextmateLocation'); 27 | } 28 | return plist.parsePLIST(contents); 29 | } 30 | -------------------------------------------------------------------------------- /src/rawGrammar.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { RuleId } from "./rule"; 6 | import { ScopeName } from "./theme"; 7 | 8 | export interface IRawGrammar extends ILocatable { 9 | repository: IRawRepository; 10 | readonly scopeName: ScopeName; 11 | readonly patterns: IRawRule[]; 12 | readonly injections?: { [expression: string]: IRawRule }; 13 | readonly injectionSelector?: string; 14 | 15 | readonly fileTypes?: string[]; 16 | readonly name?: string; 17 | readonly firstLineMatch?: string; 18 | } 19 | 20 | /** 21 | * Allowed values: 22 | * * Scope Name, e.g. `source.ts` 23 | * * Top level scope reference, e.g. `source.ts#entity.name.class` 24 | * * Relative scope reference, e.g. `#entity.name.class` 25 | * * self, e.g. `$self` 26 | * * base, e.g. `$base` 27 | */ 28 | export type IncludeString = string; 29 | export type RegExpString = string; 30 | 31 | export interface IRawRepositoryMap { 32 | [name: string]: IRawRule; 33 | $self: IRawRule; 34 | $base: IRawRule; 35 | } 36 | 37 | export type IRawRepository = IRawRepositoryMap & ILocatable; 38 | 39 | export interface IRawRule extends ILocatable { 40 | id?: RuleId; // This is not part of the spec only used internally 41 | 42 | readonly include?: IncludeString; 43 | 44 | readonly name?: ScopeName; 45 | readonly contentName?: ScopeName; 46 | 47 | readonly match?: RegExpString; 48 | readonly captures?: IRawCaptures; 49 | readonly begin?: RegExpString; 50 | readonly beginCaptures?: IRawCaptures; 51 | readonly end?: RegExpString; 52 | readonly endCaptures?: IRawCaptures; 53 | readonly while?: RegExpString; 54 | readonly whileCaptures?: IRawCaptures; 55 | readonly patterns?: IRawRule[]; 56 | 57 | readonly repository?: IRawRepository; 58 | 59 | readonly applyEndPatternLast?: boolean; 60 | } 61 | 62 | export type IRawCaptures = IRawCapturesMap & ILocatable; 63 | 64 | export interface IRawCapturesMap { 65 | [captureId: string]: IRawRule; 66 | } 67 | 68 | export interface ILocation { 69 | readonly filename: string; 70 | readonly line: number; 71 | readonly char: number; 72 | } 73 | 74 | export interface ILocatable { 75 | readonly $vscodeTextmateLocation?: ILocation; 76 | } 77 | -------------------------------------------------------------------------------- /src/registry.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { BalancedBracketSelectors, createGrammar, Grammar, IGrammarRepository, IThemeProvider, AttributedScopeStack } from './grammar'; 6 | import { IRawGrammar } from './rawGrammar'; 7 | import { IGrammar, IEmbeddedLanguagesMap, ITokenTypeMap } from './main'; 8 | import { ScopeStack, Theme, StyleAttributes, ThemeTrieElementRule, ScopeName } from './theme'; 9 | import { IOnigLib } from './onigLib'; 10 | 11 | export class SyncRegistry implements IGrammarRepository, IThemeProvider { 12 | private readonly _grammars = new Map(); 13 | private readonly _rawGrammars = new Map(); 14 | private readonly _injectionGrammars = new Map(); 15 | private _theme: Theme; 16 | 17 | constructor(theme: Theme, private readonly _onigLibPromise: Promise) { 18 | this._theme = theme; 19 | } 20 | 21 | public dispose(): void { 22 | for (const grammar of this._grammars.values()) { 23 | grammar.dispose(); 24 | } 25 | } 26 | 27 | public setTheme(theme: Theme): void { 28 | this._theme = theme; 29 | } 30 | 31 | public getColorMap(): string[] { 32 | return this._theme.getColorMap(); 33 | } 34 | 35 | /** 36 | * Add `grammar` to registry and return a list of referenced scope names 37 | */ 38 | public addGrammar(grammar: IRawGrammar, injectionScopeNames?: ScopeName[]): void { 39 | this._rawGrammars.set(grammar.scopeName, grammar); 40 | 41 | if (injectionScopeNames) { 42 | this._injectionGrammars.set(grammar.scopeName, injectionScopeNames); 43 | } 44 | } 45 | 46 | /** 47 | * Lookup a raw grammar. 48 | */ 49 | public lookup(scopeName: ScopeName): IRawGrammar | undefined { 50 | return this._rawGrammars.get(scopeName)!; 51 | } 52 | 53 | /** 54 | * Returns the injections for the given grammar 55 | */ 56 | public injections(targetScope: ScopeName): ScopeName[] { 57 | return this._injectionGrammars.get(targetScope)!; 58 | } 59 | 60 | /** 61 | * Get the default theme settings 62 | */ 63 | public getDefaults(): StyleAttributes { 64 | return this._theme.getDefaults(); 65 | } 66 | 67 | /** 68 | * Match a scope in the theme. 69 | */ 70 | public themeMatch(scopePath: ScopeStack): StyleAttributes | null { 71 | return this._theme.match(scopePath); 72 | } 73 | 74 | /** 75 | * Lookup a grammar. 76 | */ 77 | public async grammarForScopeName( 78 | scopeName: ScopeName, 79 | initialLanguage: number, 80 | embeddedLanguages: IEmbeddedLanguagesMap | null, 81 | tokenTypes: ITokenTypeMap | null, 82 | balancedBracketSelectors: BalancedBracketSelectors | null 83 | ): Promise { 84 | if (!this._grammars.has(scopeName)) { 85 | let rawGrammar = this._rawGrammars.get(scopeName)!; 86 | if (!rawGrammar) { 87 | return null; 88 | } 89 | this._grammars.set(scopeName, createGrammar( 90 | scopeName, 91 | rawGrammar, 92 | initialLanguage, 93 | embeddedLanguages, 94 | tokenTypes, 95 | balancedBracketSelectors, 96 | this, 97 | await this._onigLibPromise 98 | )); 99 | } 100 | return this._grammars.get(scopeName)!; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/tests/all.test.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import './grammar.test'; 6 | import './json.test'; 7 | import './matcher.test'; 8 | import './themes.test'; 9 | import './tokenization.test'; 10 | -------------------------------------------------------------------------------- /src/tests/inspect.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import * as fs from 'fs'; 6 | import { Registry, IGrammar, parseRawGrammar } from '../main'; 7 | import { StateStackImpl as StackElementImpl, Grammar as GrammarImpl } from '../grammar'; 8 | import * as debug from '../debug'; 9 | import { getOniguruma } from './onigLibs'; 10 | 11 | class ExtendedStackElement extends StackElementImpl { 12 | _instanceId?: number; 13 | } 14 | 15 | debug.DebugFlags.InDebugMode = true; 16 | 17 | if (process.argv.length < 4) { 18 | console.log('usage: node index.js [ ...] '); 19 | process.exit(0); 20 | } 21 | 22 | const GRAMMAR_PATHS = process.argv.slice(2, process.argv.length - 1); 23 | const FILE_PATH = process.argv[process.argv.length - 1]; 24 | 25 | const registry = new Registry({ 26 | onigLib: getOniguruma(), 27 | loadGrammar: () => Promise.resolve(null) 28 | }); 29 | let grammarPromises: Promise[] = []; 30 | for (let path of GRAMMAR_PATHS) { 31 | console.log('LOADING GRAMMAR: ' + path); 32 | const content = fs.readFileSync(path).toString(); 33 | const rawGrammar = parseRawGrammar(content, path); 34 | grammarPromises.push(registry.addGrammar(rawGrammar)); 35 | } 36 | 37 | Promise.all(grammarPromises).then(_grammars => { 38 | const grammar = _grammars[0]; 39 | const fileContents = fs.readFileSync(FILE_PATH).toString(); 40 | const lines = fileContents.split(/\r\n|\r|\n/); 41 | let ruleStack = null; 42 | let lastElementId = 0; 43 | for (let i = 0; i < lines.length; i++) { 44 | const line = lines[i]; 45 | 46 | console.log(''); 47 | console.log(''); 48 | console.log('==========================================='); 49 | console.log('TOKENIZING LINE ' + (i + 1) + ': |' + line + '|'); 50 | 51 | const r = grammar.tokenizeLine(line, ruleStack); 52 | 53 | console.log(''); 54 | 55 | let stackElement: ExtendedStackElement | null = r.ruleStack; 56 | let cnt = 0; 57 | while (stackElement) { 58 | cnt++; 59 | stackElement = stackElement.parent; 60 | } 61 | 62 | console.log('@@LINE END RULE STACK CONTAINS ' + cnt + ' RULES:'); 63 | stackElement = r.ruleStack; 64 | let list: string[] = []; 65 | while (stackElement) { 66 | if (!stackElement._instanceId) { 67 | stackElement._instanceId = (++lastElementId); 68 | } 69 | let ruleDesc = stackElement.getRule(grammar as GrammarImpl); 70 | if (!ruleDesc) { 71 | list.push(' * no rule description found'); 72 | } else { 73 | list.push(' * ' + ruleDesc.debugName + ' -- [' + ruleDesc.id + ',' + stackElement._instanceId + '] "' + stackElement.nameScopesList!.getScopeNames() + '", "' + stackElement.contentNameScopesList!.getScopeNames() + '"'); 74 | } 75 | stackElement = stackElement.parent; 76 | } 77 | list.reverse(); 78 | console.log(list.join('\n')); 79 | 80 | ruleStack = r.ruleStack; 81 | } 82 | }); 83 | -------------------------------------------------------------------------------- /src/tests/json.test.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import * as assert from 'assert'; 6 | import { parseJSON } from '../json'; 7 | 8 | function isValid(json: string): void { 9 | let expected = JSON.parse(json); 10 | let actual = parseJSON(json, null, false); 11 | assert.deepStrictEqual(actual, expected); 12 | 13 | // let actual2 = JSONparse(json, true); 14 | // assert.deepEqual(actual2, expected); 15 | } 16 | 17 | function isInvalid(json: string): void { 18 | let hadErr = false; 19 | try { 20 | parseJSON(json, null, false); 21 | } catch (err) { 22 | hadErr = true; 23 | } 24 | assert.strictEqual(hadErr, true, 'expected invalid: ' + json); 25 | } 26 | 27 | test('JSON Invalid body', function () { 28 | isInvalid('{}[]'); 29 | isInvalid('*'); 30 | }); 31 | 32 | test('JSON Trailing Whitespace', function () { 33 | isValid('{}\n\n'); 34 | }); 35 | 36 | test('JSON Objects', function () { 37 | isValid('{}'); 38 | isValid('{"key": "value"}'); 39 | isValid('{"key1": true, "key2": 3, "key3": [null], "key4": { "nested": {}}}'); 40 | isValid('{"constructor": true }'); 41 | 42 | isInvalid('{'); 43 | isInvalid('{3:3}'); 44 | isInvalid('{\'key\': 3}'); 45 | isInvalid('{"key" 3}'); 46 | isInvalid('{"key":3 "key2": 4}'); 47 | isInvalid('{"key":42, }'); 48 | isInvalid('{"key:42'); 49 | }); 50 | 51 | test('JSON Arrays', function () { 52 | isValid('[]'); 53 | isValid('[1, 2]'); 54 | isValid('[1, "string", false, {}, [null]]'); 55 | 56 | isInvalid('['); 57 | isInvalid('[,]'); 58 | isInvalid('[1 2]'); 59 | isInvalid('[true false]'); 60 | isInvalid('[1, ]'); 61 | isInvalid('[[]'); 62 | isInvalid('["something"'); 63 | isInvalid('[magic]'); 64 | }); 65 | 66 | test('JSON Strings', function () { 67 | isValid('["string"]'); 68 | isValid('["\\"\\\\\\/\\b\\f\\n\\r\\t\\u1234\\u12AB"]'); 69 | isValid('["\\\\"]'); 70 | 71 | isInvalid('["'); 72 | isInvalid('["]'); 73 | isInvalid('["\\z"]'); 74 | isInvalid('["\\u"]'); 75 | isInvalid('["\\u123"]'); 76 | isInvalid('["\\u123Z"]'); 77 | isInvalid('[\'string\']'); 78 | }); 79 | 80 | test('Numbers', function () { 81 | isValid('[0, -1, 186.1, 0.123, -1.583e+4, 1.583E-4, 5e8]'); 82 | 83 | // isInvalid('[+1]'); 84 | // isInvalid('[01]'); 85 | // isInvalid('[1.]'); 86 | // isInvalid('[1.1+3]'); 87 | // isInvalid('[1.4e]'); 88 | // isInvalid('[-A]'); 89 | }); 90 | 91 | test('JSON misc', function () { 92 | isValid('{}'); 93 | isValid('[null]'); 94 | isValid('{"a":true}'); 95 | isValid('{\n\t"key" : {\n\t"key2": 42\n\t}\n}'); 96 | isValid('{"key":[{"key2":42}]}'); 97 | isValid('{\n\t\n}'); 98 | isValid('{\n"first":true\n\n}'); 99 | isValid('{\n"key":32,\n\n"key2":45}'); 100 | isValid('{"a": 1,\n\n"d": 2}'); 101 | isValid('{"a": 1, "a": 2}'); 102 | isValid('{"a": { "a": 2, "a": 3}}'); 103 | isValid('[{ "a": 2, "a": 3}]'); 104 | isValid('{"key1":"first string", "key2":["second string"]}'); 105 | 106 | isInvalid('{\n"key":32,\nerror\n}'); 107 | }); 108 | -------------------------------------------------------------------------------- /src/tests/matcher.test.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import * as assert from 'assert'; 6 | import { createMatchers } from '../matcher'; 7 | 8 | let tests = [ 9 | { "expression": "foo", "input": ["foo"], "result": true }, 10 | { "expression": "foo", "input": ["bar"], "result": false }, 11 | { "expression": "- foo", "input": ["foo"], "result": false }, 12 | { "expression": "- foo", "input": ["bar"], "result": true }, 13 | { "expression": "- - foo", "input": ["bar"], "result": false }, 14 | { "expression": "bar foo", "input": ["foo"], "result": false }, 15 | { "expression": "bar foo", "input": ["bar"], "result": false }, 16 | { "expression": "bar foo", "input": ["bar", "foo"], "result": true }, 17 | { "expression": "bar - foo", "input": ["bar"], "result": true }, 18 | { "expression": "bar - foo", "input": ["foo", "bar"], "result": false }, 19 | { "expression": "bar - foo", "input": ["foo"], "result": false }, 20 | { "expression": "bar, foo", "input": ["foo"], "result": true }, 21 | { "expression": "bar, foo", "input": ["bar"], "result": true }, 22 | { "expression": "bar, foo", "input": ["bar", "foo"], "result": true }, 23 | { "expression": "bar, -foo", "input": ["bar", "foo"], "result": true }, 24 | { "expression": "bar, -foo", "input": ["yo"], "result": true }, 25 | { "expression": "bar, -foo", "input": ["foo"], "result": false }, 26 | { "expression": "(foo)", "input": ["foo"], "result": true }, 27 | { "expression": "(foo - bar)", "input": ["foo"], "result": true }, 28 | { "expression": "(foo - bar)", "input": ["foo", "bar"], "result": false }, 29 | { "expression": "foo bar - (yo man)", "input": ["foo", "bar"], "result": true }, 30 | { "expression": "foo bar - (yo man)", "input": ["foo", "bar", "yo"], "result": true }, 31 | { "expression": "foo bar - (yo man)", "input": ["foo", "bar", "yo", "man"], "result": false }, 32 | { "expression": "foo bar - (yo | man)", "input": ["foo", "bar", "yo", "man"], "result": false }, 33 | { "expression": "foo bar - (yo | man)", "input": ["foo", "bar", "yo"], "result": false }, 34 | { "expression": "R:text.html - (comment.block, text.html source)", "input": ["text.html", "bar", "source"], "result": false }, 35 | { "expression": "text.html.php - (meta.embedded | meta.tag), L:text.html.php meta.tag, L:source.js.embedded.html", "input": ["text.html.php", "bar", "source.js"], "result": true } 36 | ]; 37 | 38 | let nameMatcher = (identifers: string[], stackElements: string[]) => { 39 | let lastIndex = 0; 40 | return identifers.every(identifier => { 41 | for (let i = lastIndex; i < stackElements.length; i++) { 42 | if (stackElements[i] === identifier) { 43 | lastIndex = i + 1; 44 | return true; 45 | } 46 | } 47 | return false; 48 | }); 49 | }; 50 | 51 | tests.forEach((tst, index) => { 52 | test('Matcher Test #' + index, () => { 53 | let matchers = createMatchers(tst.expression, nameMatcher); 54 | let result = matchers.some(m => m.matcher(tst.input)); 55 | assert.strictEqual(result, tst.result); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /src/tests/onigLibs.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { IOnigLib } from '../onigLib'; 6 | 7 | let onigurumaLib: Promise | null = null; 8 | 9 | export function getOniguruma(): Promise { 10 | if (!onigurumaLib) { 11 | let vscodeOnigurumaModule = require('vscode-oniguruma'); 12 | let fs = require('fs'); 13 | let path = require('path'); 14 | const wasmBin = fs.readFileSync(path.join(__dirname, '../../node_modules/vscode-oniguruma/release/onig.wasm')).buffer; 15 | onigurumaLib = (>vscodeOnigurumaModule.loadWASM(wasmBin)).then((_: any) => { 16 | return { 17 | createOnigScanner(patterns: string[]) { return new vscodeOnigurumaModule.OnigScanner(patterns); }, 18 | createOnigString(s: string) { return new vscodeOnigurumaModule.OnigString(s); } 19 | }; 20 | }); 21 | } 22 | return onigurumaLib; 23 | } 24 | -------------------------------------------------------------------------------- /src/tests/resolver.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { IOnigLib } from '../onigLib'; 6 | import { parseRawGrammar } from '../parseRawGrammar'; 7 | import { RegistryOptions } from '../main'; 8 | 9 | import * as path from 'path'; 10 | import * as fs from 'fs'; 11 | import { IRawGrammar } from '../rawGrammar'; 12 | 13 | export interface ILanguageRegistration { 14 | id: string; 15 | extensions: string[]; 16 | filenames: string[]; 17 | } 18 | 19 | export interface IGrammarRegistration { 20 | language: string; 21 | scopeName: string; 22 | path: string; 23 | embeddedLanguages: { [scopeName: string]: string; }; 24 | grammar?: Promise; 25 | } 26 | 27 | export class Resolver implements RegistryOptions { 28 | public readonly language2id: { [languages: string]: number; }; 29 | private _lastLanguageId: number; 30 | private _id2language: string[]; 31 | private readonly _grammars: IGrammarRegistration[]; 32 | private readonly _languages: ILanguageRegistration[]; 33 | public readonly onigLib: Promise; 34 | 35 | constructor(grammars: IGrammarRegistration[], languages: ILanguageRegistration[], onigLibPromise: Promise) { 36 | this._grammars = grammars; 37 | this._languages = languages; 38 | this.onigLib = onigLibPromise; 39 | 40 | this.language2id = Object.create(null); 41 | this._lastLanguageId = 0; 42 | this._id2language = []; 43 | 44 | for (let i = 0; i < this._languages.length; i++) { 45 | let languageId = ++this._lastLanguageId; 46 | this.language2id[this._languages[i].id] = languageId; 47 | this._id2language[languageId] = this._languages[i].id; 48 | } 49 | } 50 | 51 | public findLanguageByExtension(fileExtension: string): string | null { 52 | for (let i = 0; i < this._languages.length; i++) { 53 | let language = this._languages[i]; 54 | 55 | if (!language.extensions) { 56 | continue; 57 | } 58 | 59 | for (let j = 0; j < language.extensions.length; j++) { 60 | let extension = language.extensions[j]; 61 | 62 | if (extension === fileExtension) { 63 | return language.id; 64 | } 65 | } 66 | } 67 | 68 | return null; 69 | } 70 | 71 | public findLanguageByFilename(filename: string): string | null { 72 | for (let i = 0; i < this._languages.length; i++) { 73 | let language = this._languages[i]; 74 | 75 | if (!language.filenames) { 76 | continue; 77 | } 78 | 79 | for (let j = 0; j < language.filenames.length; j++) { 80 | let lFilename = language.filenames[j]; 81 | 82 | if (filename === lFilename) { 83 | return language.id; 84 | } 85 | } 86 | } 87 | 88 | return null; 89 | } 90 | 91 | public findScopeByFilename(filename: string): string | null { 92 | let language = this.findLanguageByExtension(path.extname(filename)) || this.findLanguageByFilename(filename); 93 | if (language) { 94 | let grammar = this.findGrammarByLanguage(language); 95 | if (grammar) { 96 | return grammar.scopeName; 97 | } 98 | } 99 | return null; 100 | } 101 | 102 | public findGrammarByLanguage(language: string): IGrammarRegistration { 103 | for (let i = 0; i < this._grammars.length; i++) { 104 | let grammar = this._grammars[i]; 105 | 106 | if (grammar.language === language) { 107 | return grammar; 108 | } 109 | } 110 | 111 | throw new Error('Could not findGrammarByLanguage for ' + language); 112 | } 113 | 114 | public async loadGrammar(scopeName: string): Promise { 115 | for (let i = 0; i < this._grammars.length; i++) { 116 | let grammar = this._grammars[i]; 117 | if (grammar.scopeName === scopeName) { 118 | if (!grammar.grammar) { 119 | grammar.grammar = readGrammarFromPath(grammar.path); 120 | } 121 | return grammar.grammar; 122 | } 123 | } 124 | //console.warn('test resolver: missing grammar for ' + scopeName); 125 | return null; 126 | } 127 | } 128 | 129 | function readGrammarFromPath(path: string) : Promise { 130 | return new Promise((c,e) => { 131 | fs.readFile(path, (error, content) => { 132 | if (error) { 133 | e(error); 134 | } else { 135 | c(parseRawGrammar(content.toString(), path)); 136 | } 137 | }); 138 | }); 139 | } 140 | -------------------------------------------------------------------------------- /src/tests/themeTest.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import * as fs from 'fs'; 6 | import * as path from 'path'; 7 | import { IEmbeddedLanguagesMap } from '../main'; 8 | import { tokenizeWithTheme, IThemedToken } from './themedTokenizer'; 9 | import { ThemeData } from './themes.test'; 10 | import { Resolver } from './resolver'; 11 | 12 | interface IThemesTokens { 13 | [theme: string]: IThemedToken[]; 14 | } 15 | 16 | export class ThemeTest { 17 | 18 | private static _readFile(filename: string): string { 19 | return fs.readFileSync(filename).toString('utf8'); 20 | } 21 | 22 | private static _normalizeNewLines(str: string): string { 23 | return str.split(/\r\n|\n/).join('\n'); 24 | } 25 | 26 | private readonly EXPECTED_FILE_PATH: string; 27 | private readonly tests: SingleThemeTest[]; 28 | 29 | public readonly expected: string; 30 | public readonly testName: string; 31 | public actual: string | null; 32 | 33 | constructor(THEMES_TEST_PATH: string, testFile: string, themeDatas: ThemeData[], resolver: Resolver) { 34 | const TEST_FILE_PATH = path.join(THEMES_TEST_PATH, 'tests', testFile); 35 | const testFileContents = ThemeTest._readFile(TEST_FILE_PATH); 36 | 37 | this.EXPECTED_FILE_PATH = path.join(THEMES_TEST_PATH, 'tests', testFile + '.result'); 38 | this.expected = ThemeTest._normalizeNewLines(ThemeTest._readFile(this.EXPECTED_FILE_PATH)); 39 | 40 | // Determine the language 41 | let language = resolver.findLanguageByExtension(path.extname(testFile)) || resolver.findLanguageByFilename(testFile); 42 | if (!language) { 43 | throw new Error('Could not determine language for ' + testFile); 44 | } 45 | let grammar = resolver.findGrammarByLanguage(language); 46 | 47 | let embeddedLanguages: IEmbeddedLanguagesMap = Object.create(null); 48 | if (grammar.embeddedLanguages) { 49 | for (let scopeName in grammar.embeddedLanguages) { 50 | embeddedLanguages[scopeName] = resolver.language2id[grammar.embeddedLanguages[scopeName]]; 51 | } 52 | } 53 | 54 | this.tests = []; 55 | for (let themeData of themeDatas) { 56 | this.tests.push(new SingleThemeTest( 57 | themeData, 58 | testFileContents, 59 | grammar.scopeName, 60 | resolver.language2id[language], 61 | embeddedLanguages 62 | )); 63 | } 64 | 65 | this.testName = testFile; 66 | this.actual = null; 67 | } 68 | 69 | public async evaluate(): Promise { 70 | await Promise.all(this.tests.map(t => t.evaluate())); 71 | 72 | let actual: IThemesTokens = {}; 73 | for (let i = 0; i < this.tests.length; i++) { 74 | actual[this.tests[i].themeData.themeName] = this.tests[i].actual!; 75 | } 76 | 77 | this.actual = ThemeTest._normalizeNewLines(JSON.stringify(actual, null, '\t')); 78 | } 79 | 80 | public writeExpected(): void { 81 | fs.writeFileSync(this.EXPECTED_FILE_PATH, this.actual!); 82 | } 83 | } 84 | 85 | class SingleThemeTest { 86 | 87 | public readonly themeData: ThemeData; 88 | private readonly contents: string; 89 | private readonly initialScopeName: string; 90 | private readonly initialLanguage: number; 91 | private readonly embeddedLanguages: IEmbeddedLanguagesMap; 92 | 93 | public actual: IThemedToken[] | null; 94 | 95 | constructor( 96 | themeData: ThemeData, 97 | contents: string, 98 | initialScopeName: string, 99 | initialLanguage: number, 100 | embeddedLanguages: IEmbeddedLanguagesMap, 101 | ) { 102 | this.themeData = themeData; 103 | this.contents = contents; 104 | this.initialScopeName = initialScopeName; 105 | this.initialLanguage = initialLanguage; 106 | this.embeddedLanguages = embeddedLanguages; 107 | 108 | this.actual = null; 109 | } 110 | 111 | public async evaluate(): Promise { 112 | this.actual = await this._tokenizeWithThemeAsync(); 113 | } 114 | 115 | private async _tokenizeWithThemeAsync(): Promise { 116 | const grammar = await this.themeData.registry.loadGrammarWithEmbeddedLanguages(this.initialScopeName, this.initialLanguage, this.embeddedLanguages); 117 | if (!grammar) { 118 | throw new Error(`Cannot load grammar for ${this.initialScopeName}`); 119 | } 120 | return tokenizeWithTheme(this.themeData.registry.getColorMap(), this.contents, grammar); 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/tests/themedTokenizer.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { IGrammar, StateStack } from '../main'; 6 | import { EncodedTokenAttributes } from '../encodedTokenAttributes'; 7 | import { applyStateStackDiff, diffStateStacksRefEq } from '../diffStateStacks'; 8 | 9 | export interface IThemedToken { 10 | content: string; 11 | color: string; 12 | } 13 | 14 | export function tokenizeWithTheme(colorMap: string[], fileContents: string, grammar: IGrammar): IThemedToken[] { 15 | 16 | const lines = fileContents.split(/\r\n|\r|\n/); 17 | 18 | let ruleStack: StateStack | null = null; 19 | let actual: IThemedToken[] = [], actualLen = 0; 20 | 21 | for (let i = 0, len = lines.length; i < len; i++) { 22 | const line = lines[i]; 23 | const result = grammar.tokenizeLine2(line, ruleStack); 24 | const tokensLength = result.tokens.length / 2; 25 | for (let j = 0; j < tokensLength; j++) { 26 | const startIndex = result.tokens[2 * j]; 27 | const nextStartIndex = j + 1 < tokensLength ? result.tokens[2 * j + 2] : line.length; 28 | const tokenText = line.substring(startIndex, nextStartIndex); 29 | if (tokenText === '') { 30 | continue; 31 | } 32 | const metadata = result.tokens[2 * j + 1]; 33 | const foreground = EncodedTokenAttributes.getForeground(metadata); 34 | const foregroundColor = colorMap[foreground]; 35 | 36 | actual[actualLen++] = { 37 | content: tokenText, 38 | color: foregroundColor 39 | }; 40 | } 41 | 42 | if (ruleStack) { 43 | const diff = diffStateStacksRefEq(ruleStack, result.ruleStack); 44 | ruleStack = applyStateStackDiff(ruleStack, diff); 45 | } else { 46 | ruleStack = result.ruleStack; 47 | } 48 | } 49 | 50 | return actual; 51 | } 52 | -------------------------------------------------------------------------------- /src/tests/tokenization.test.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import * as fs from 'fs'; 6 | import * as path from 'path'; 7 | import * as assert from 'assert'; 8 | import { Registry, IGrammar, RegistryOptions, StateStack, parseRawGrammar } from '../main'; 9 | import { IOnigLib } from '../onigLib'; 10 | import { getOniguruma } from './onigLibs'; 11 | import { IRawGrammar } from '../rawGrammar'; 12 | import { applyStateStackDiff, diffStateStacksRefEq } from '../diffStateStacks'; 13 | 14 | const REPO_ROOT = path.join(__dirname, '../../'); 15 | 16 | function assertTokenizationSuite(testLocation: string): void { 17 | 18 | interface IRawTest { 19 | desc: string; 20 | grammars: string[]; 21 | grammarPath?: string; 22 | grammarScopeName?: string; 23 | grammarInjections?: string[]; 24 | lines: IRawTestLine[]; 25 | } 26 | interface IRawTestLine { 27 | line: string; 28 | tokens: IRawToken[]; 29 | } 30 | interface IRawToken { 31 | value: string; 32 | scopes: string[]; 33 | } 34 | 35 | let tests: IRawTest[] = JSON.parse(fs.readFileSync(testLocation).toString()); 36 | 37 | 38 | tests.forEach((tst) => { 39 | 40 | test(tst.desc, async () => { 41 | await performTest(tst, getOniguruma()); 42 | }); 43 | }); 44 | 45 | async function performTest(test: IRawTest, onigLib: Promise): Promise { 46 | 47 | let grammarScopeName = test.grammarScopeName; 48 | let grammarByScope : { [scope:string]:IRawGrammar } = {}; 49 | for (let grammarPath of test.grammars) { 50 | let content = fs.readFileSync(path.join(path.dirname(testLocation), grammarPath)).toString(); 51 | let rawGrammar = parseRawGrammar(content, grammarPath); 52 | grammarByScope[rawGrammar.scopeName] = rawGrammar; 53 | if (!grammarScopeName && grammarPath === test.grammarPath) { 54 | grammarScopeName = rawGrammar.scopeName; 55 | } 56 | } 57 | if (!grammarScopeName) { 58 | throw new Error('I HAVE NO GRAMMAR FOR TEST'); 59 | } 60 | 61 | let options: RegistryOptions = { 62 | onigLib: onigLib, 63 | loadGrammar: (scopeName: string) => Promise.resolve(grammarByScope[scopeName]), 64 | getInjections: (scopeName: string) => { 65 | if (scopeName === grammarScopeName) { 66 | return test.grammarInjections; 67 | } 68 | } 69 | }; 70 | let registry = new Registry(options); 71 | let grammar: IGrammar | null = await registry.loadGrammar(grammarScopeName); 72 | if (!grammar) { 73 | throw new Error('I HAVE NO GRAMMAR FOR TEST'); 74 | } 75 | let prevState: StateStack | null = null; 76 | for (let i = 0; i < test.lines.length; i++) { 77 | prevState = assertLineTokenization(grammar, test.lines[i], prevState); 78 | } 79 | } 80 | 81 | function assertLineTokenization(grammar: IGrammar, testCase: IRawTestLine, prevState: StateStack | null): StateStack { 82 | let actual = grammar.tokenizeLine(testCase.line, prevState); 83 | 84 | let actualTokens: IRawToken[] = actual.tokens.map((token) => { 85 | return { 86 | value: testCase.line.substring(token.startIndex, token.endIndex), 87 | scopes: token.scopes 88 | }; 89 | }); 90 | 91 | // TODO@Alex: fix tests instead of working around 92 | if (testCase.line.length > 0) { 93 | // Remove empty tokens... 94 | testCase.tokens = testCase.tokens.filter((token) => { 95 | return (token.value.length > 0); 96 | }); 97 | } 98 | 99 | assert.deepStrictEqual(actualTokens, testCase.tokens, 'Tokenizing line ' + testCase.line); 100 | 101 | if (prevState) { 102 | const diff = diffStateStacksRefEq(prevState, actual.ruleStack); 103 | actual = { ...actual, ruleStack: applyStateStackDiff(prevState, diff)! } 104 | } 105 | 106 | return actual.ruleStack; 107 | } 108 | } 109 | 110 | assertTokenizationSuite(path.join(REPO_ROOT, 'test-cases/first-mate/tests.json')); 111 | assertTokenizationSuite(path.join(REPO_ROOT, 'test-cases/suite1/tests.json')); 112 | assertTokenizationSuite(path.join(REPO_ROOT, 'test-cases/suite1/whileTests.json')); 113 | -------------------------------------------------------------------------------- /src/typings/lib.ie11_safe_es6.d.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | // Defined a subset of ES6 built ins that run in IE11 7 | // CHECK WITH http://kangax.github.io/compat-table/es6/#ie11 8 | 9 | interface Map { 10 | clear(): void; 11 | delete(key: K): boolean; 12 | forEach(callbackfn: (value: V, index: K, map: Map) => void, thisArg?: any): void; 13 | get(key: K): V | undefined; 14 | has(key: K): boolean; 15 | set(key: K, value?: V): Map; 16 | readonly size: number; 17 | 18 | // not supported on IE11: 19 | // entries(): IterableIterator<[K, V]>; 20 | // keys(): IterableIterator; 21 | // values(): IterableIterator; 22 | // [Symbol.iterator]():IterableIterator<[K,V]>; 23 | // [Symbol.toStringTag]: string; 24 | } 25 | 26 | interface MapConstructor { 27 | new (): Map; 28 | 29 | // not supported on IE11: 30 | // new (iterable: Iterable<[K, V]>): Map; 31 | } 32 | declare var Map: MapConstructor; 33 | 34 | 35 | interface Set { 36 | add(value: T): Set; 37 | clear(): void; 38 | delete(value: T): boolean; 39 | forEach(callbackfn: (value: T, index: T, set: Set) => void, thisArg?: any): void; 40 | has(value: T): boolean; 41 | readonly size: number; 42 | 43 | // not supported on IE11: 44 | // entries(): IterableIterator<[T, T]>; 45 | // keys(): IterableIterator; 46 | // values(): IterableIterator; 47 | // [Symbol.iterator]():IterableIterator; 48 | // [Symbol.toStringTag]: string; 49 | } 50 | 51 | interface SetConstructor { 52 | new (): Set; 53 | 54 | // not supported on IE11: 55 | // new (iterable: Iterable): Set; 56 | } 57 | declare var Set: SetConstructor; 58 | 59 | 60 | interface WeakMap { 61 | delete(key: K): boolean; 62 | get(key: K): V | undefined; 63 | has(key: K): boolean; 64 | // IE11 doesn't return this 65 | // set(key: K, value?: V): this; 66 | set(key: K, value?: V): undefined; 67 | } 68 | 69 | interface WeakMapConstructor { 70 | new(): WeakMap; 71 | new (): WeakMap; 72 | // new (entries?: [K, V][]): WeakMap; 73 | readonly prototype: WeakMap; 74 | } 75 | declare var WeakMap: WeakMapConstructor; 76 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------- 2 | * Copyright (C) Microsoft Corporation. All rights reserved. 3 | *--------------------------------------------------------*/ 4 | 5 | import { IOnigCaptureIndex } from './onigLib'; 6 | 7 | export function clone(something: T): T { 8 | return doClone(something); 9 | } 10 | 11 | function doClone(something: any): any { 12 | if (Array.isArray(something)) { 13 | return cloneArray(something); 14 | } 15 | if (typeof something === 'object') { 16 | return cloneObj(something); 17 | } 18 | return something; 19 | } 20 | 21 | function cloneArray(arr: any[]): any[] { 22 | let r: any[] = []; 23 | for (let i = 0, len = arr.length; i < len; i++) { 24 | r[i] = doClone(arr[i]); 25 | } 26 | return r; 27 | } 28 | 29 | function cloneObj(obj: any): any { 30 | let r: any = {}; 31 | for (let key in obj) { 32 | r[key] = doClone(obj[key]); 33 | } 34 | return r; 35 | } 36 | 37 | export function mergeObjects(target: any, ...sources: any[]): any { 38 | sources.forEach(source => { 39 | for (let key in source) { 40 | target[key] = source[key]; 41 | } 42 | }); 43 | return target; 44 | } 45 | 46 | export function basename(path: string): string { 47 | const idx = ~path.lastIndexOf('/') || ~path.lastIndexOf('\\'); 48 | if (idx === 0) { 49 | return path; 50 | } else if (~idx === path.length - 1) { 51 | return basename(path.substring(0, path.length - 1)); 52 | } else { 53 | return path.substr(~idx + 1); 54 | } 55 | } 56 | 57 | let CAPTURING_REGEX_SOURCE = /\$(\d+)|\${(\d+):\/(downcase|upcase)}/g; 58 | 59 | export class RegexSource { 60 | 61 | public static hasCaptures(regexSource: string | null): boolean { 62 | if (regexSource === null) { 63 | return false; 64 | } 65 | CAPTURING_REGEX_SOURCE.lastIndex = 0; 66 | return CAPTURING_REGEX_SOURCE.test(regexSource); 67 | } 68 | 69 | public static replaceCaptures(regexSource: string, captureSource: string, captureIndices: IOnigCaptureIndex[]): string { 70 | return regexSource.replace(CAPTURING_REGEX_SOURCE, (match: string, index: string, commandIndex: string, command: string) => { 71 | let capture = captureIndices[parseInt(index || commandIndex, 10)]; 72 | if (capture) { 73 | let result = captureSource.substring(capture.start, capture.end); 74 | // Remove leading dots that would make the selector invalid 75 | while (result[0] === '.') { 76 | result = result.substring(1); 77 | } 78 | switch (command) { 79 | case 'downcase': 80 | return result.toLowerCase(); 81 | case 'upcase': 82 | return result.toUpperCase(); 83 | default: 84 | return result; 85 | } 86 | } else { 87 | return match; 88 | } 89 | }); 90 | } 91 | } 92 | 93 | /** 94 | * A union of given const enum values. 95 | */ 96 | export type OrMask = number; 97 | 98 | export function strcmp(a: string, b: string): number { 99 | if (a < b) { 100 | return -1; 101 | } 102 | if (a > b) { 103 | return 1; 104 | } 105 | return 0; 106 | } 107 | 108 | export function strArrCmp(a: readonly string[] | null, b: readonly string[] | null): number { 109 | if (a === null && b === null) { 110 | return 0; 111 | } 112 | if (!a) { 113 | return -1; 114 | } 115 | if (!b) { 116 | return 1; 117 | } 118 | let len1 = a.length; 119 | let len2 = b.length; 120 | if (len1 === len2) { 121 | for (let i = 0; i < len1; i++) { 122 | let res = strcmp(a[i], b[i]); 123 | if (res !== 0) { 124 | return res; 125 | } 126 | } 127 | return 0; 128 | } 129 | return len1 - len2; 130 | } 131 | 132 | export function isValidHexColor(hex: string): boolean { 133 | if (/^#[0-9a-f]{6}$/i.test(hex)) { 134 | // #rrggbb 135 | return true; 136 | } 137 | 138 | if (/^#[0-9a-f]{8}$/i.test(hex)) { 139 | // #rrggbbaa 140 | return true; 141 | } 142 | 143 | if (/^#[0-9a-f]{3}$/i.test(hex)) { 144 | // #rgb 145 | return true; 146 | } 147 | 148 | if (/^#[0-9a-f]{4}$/i.test(hex)) { 149 | // #rgba 150 | return true; 151 | } 152 | 153 | return false; 154 | } 155 | 156 | /** 157 | * Escapes regular expression characters in a given string 158 | */ 159 | export function escapeRegExpCharacters(value: string): string { 160 | return value.replace(/[\-\\\{\}\*\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&'); 161 | } 162 | 163 | export class CachedFn { 164 | private readonly cache = new Map(); 165 | constructor(private readonly fn: (key: TKey) => TValue) { 166 | } 167 | 168 | public get(key: TKey): TValue { 169 | if (this.cache.has(key)) { 170 | return this.cache.get(key)!; 171 | } 172 | const value = this.fn(key); 173 | this.cache.set(key, value); 174 | return value; 175 | } 176 | } 177 | 178 | declare let performance: { now: () => number } | undefined; 179 | export const performanceNow = 180 | typeof performance === "undefined" 181 | // performance.now() is not available in this environment, so use Date.now() 182 | ? function () { 183 | return Date.now(); 184 | } 185 | : function () { 186 | return performance!.now(); 187 | }; -------------------------------------------------------------------------------- /test-cases/first-mate/README.md: -------------------------------------------------------------------------------- 1 | These testcases have been generated from the test cases of first-mate at https://github.com/atom/first-mate -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/apply-end-pattern-last.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "applyEndPatternLast", 3 | "scopeName": "source.apply-end-pattern-last", 4 | "patterns": [ 5 | { 6 | "name": "end-pattern-last-env", 7 | "begin": "last", 8 | "end": "^$", 9 | "patterns": [ 10 | { 11 | "name": "scope", 12 | "begin": "\\{", 13 | "end": "\\}", 14 | "applyEndPatternLast": true, 15 | "patterns": [ 16 | { 17 | "match": "\\}excentricSyntax", 18 | "name": "excentric" 19 | } 20 | ] 21 | } 22 | ] 23 | }, 24 | { 25 | "name": "normal-env", 26 | "begin": "first", 27 | "end": "^$", 28 | "patterns": [ 29 | { 30 | "name": "scope", 31 | "begin": "\\{", 32 | "end": "\\}", 33 | "patterns": [ 34 | { 35 | "match": "\\}excentricSyntax", 36 | "name": "excentric" 37 | } 38 | ] 39 | } 40 | ] 41 | } 42 | ] 43 | } -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/content-name.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.test", 3 | "patterns": [ 4 | { 5 | "begin": "#if", 6 | "end": "#endif", 7 | "name": "pre", 8 | "contentName": "nested" 9 | }, 10 | { 11 | "begin": "\\s*", 12 | "end": "fin", 13 | "name": "all", 14 | "contentName": "middle" 15 | } 16 | ] 17 | } -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/forever.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "forever", 3 | "scopeName": "source.forever", 4 | "patterns": [ 5 | { 6 | "name": "text", 7 | "begin": "(?=forever)", 8 | "end": "whatevs", 9 | "patterns": [ 10 | { 11 | "include": "$self" 12 | } 13 | ] 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/git-commit.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": [ 3 | "COMMIT_EDITMSG", 4 | "MERGE_MSG" 5 | ], 6 | "foldingStartMarker": "^\\+\\+\\+", 7 | "foldingStopMarker": "^---", 8 | "name": "Git Commit Message", 9 | "patterns": [ 10 | { 11 | "begin": "\\A(?!#)", 12 | "end": "(?=# Please enter the commit message)", 13 | "name": "meta.scope.message.git-commit", 14 | "patterns": [ 15 | { 16 | "begin": "\\G", 17 | "end": "^(?!\\G)", 18 | "patterns": [ 19 | { 20 | "captures": { 21 | "1": { 22 | "name": "keyword.other.$2.git-commit" 23 | } 24 | }, 25 | "match": "\\G((fixup|squash)!)\\s*" 26 | }, 27 | { 28 | "match": ".{66,}$", 29 | "name": "invalid.illegal.line-too-long.git-commit" 30 | }, 31 | { 32 | "match": ".{51,}$", 33 | "name": "invalid.deprecated.line-too-long.git-commit" 34 | } 35 | ] 36 | } 37 | ] 38 | }, 39 | { 40 | "begin": "(?=# Please enter the commit message)", 41 | "end": "\\z", 42 | "name": "meta.scope.metadata.git-commit", 43 | "patterns": [ 44 | { 45 | "include": "#metadata" 46 | } 47 | ] 48 | } 49 | ], 50 | "repository": { 51 | "metadata": { 52 | "patterns": [ 53 | { 54 | "begin": "(?=^# Changes to be committed:)", 55 | "end": "(?!\\G)((?=^# \\w)|(?!^#))", 56 | "patterns": [ 57 | { 58 | "begin": "(^[ \\t]+)?(?=#)", 59 | "beginCaptures": { 60 | "1": { 61 | "name": "punctuation.whitespace.comment.leading.git-commit" 62 | } 63 | }, 64 | "contentName": "comment.line.number-sign.git-commit", 65 | "end": "(?!\\G)^", 66 | "patterns": [ 67 | { 68 | "match": "\\G#", 69 | "name": "punctuation.definition.comment.git-commit" 70 | }, 71 | { 72 | "match": "((modified|renamed):.*)$\\n?", 73 | "name": "markup.changed.git-commit" 74 | }, 75 | { 76 | "match": "(new file:.*)$\\n?", 77 | "name": "markup.inserted.git-commit" 78 | }, 79 | { 80 | "match": "(deleted:.*)$\\n?", 81 | "name": "markup.deleted.git-commit" 82 | } 83 | ] 84 | } 85 | ] 86 | }, 87 | { 88 | "begin": "(^[ \\t]+)?(?=#)", 89 | "beginCaptures": { 90 | "1": { 91 | "name": "punctuation.whitespace.comment.leading.git-commit" 92 | } 93 | }, 94 | "contentName": "comment.line.number-sign.git-commit", 95 | "end": "(?!\\G)^", 96 | "patterns": [ 97 | { 98 | "match": "\\G#", 99 | "name": "punctuation.definition.comment.git-commit" 100 | } 101 | ] 102 | }, 103 | { 104 | "begin": "(?=diff\\ \\-\\-git)", 105 | "comment": "diff presented at the end of the commit message when using commit -v.", 106 | "contentName": "source.diff", 107 | "end": "\\z", 108 | "name": "meta.embedded.diff.git-commit", 109 | "patterns": [ 110 | { 111 | "include": "source.diff" 112 | } 113 | ] 114 | } 115 | ] 116 | } 117 | }, 118 | "scopeName": "text.git-commit" 119 | } -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/hello.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "hello", 3 | "scopeName": "source.hello", 4 | "fileTypes": [ 5 | "world" 6 | ], 7 | "patterns": [ 8 | { 9 | "match": "hello", 10 | "name": "prefix.hello" 11 | }, 12 | { 13 | "match": "world(!?)", 14 | "captures": { 15 | "1": { 16 | "name": "emphasis.hello" 17 | } 18 | }, 19 | "name": "suffix.hello" 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/html-erb.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": [ 3 | "erb", 4 | "rhtml", 5 | "html.erb" 6 | ], 7 | "injections": { 8 | "text.html.erb - (meta.embedded.block.erb | meta.embedded.line.erb | meta.tag | comment), meta.tag string.quoted": { 9 | "patterns": [ 10 | { 11 | "begin": "(^\\s*)(?=<%+#(?![^%]*%>))", 12 | "beginCaptures": { 13 | "0": { 14 | "name": "punctuation.whitespace.comment.leading.erb" 15 | } 16 | }, 17 | "end": "(?!\\G)(\\s*$\\n)?", 18 | "endCaptures": { 19 | "0": { 20 | "name": "punctuation.whitespace.comment.trailing.erb" 21 | } 22 | }, 23 | "patterns": [ 24 | { 25 | "include": "#comment" 26 | } 27 | ] 28 | }, 29 | { 30 | "begin": "(^\\s*)(?=<%(?![^%]*%>))", 31 | "beginCaptures": { 32 | "0": { 33 | "name": "punctuation.whitespace.embedded.leading.erb" 34 | } 35 | }, 36 | "end": "(?!\\G)(\\s*$\\n)?", 37 | "endCaptures": { 38 | "0": { 39 | "name": "punctuation.whitespace.embedded.trailing.erb" 40 | } 41 | }, 42 | "patterns": [ 43 | { 44 | "include": "#tags" 45 | } 46 | ] 47 | }, 48 | { 49 | "include": "#comment" 50 | }, 51 | { 52 | "include": "#tags" 53 | } 54 | ] 55 | } 56 | }, 57 | "keyEquivalent": "^~H", 58 | "name": "HTML (Ruby - ERB)", 59 | "patterns": [ 60 | { 61 | "include": "text.html.basic" 62 | } 63 | ], 64 | "repository": { 65 | "comment": { 66 | "patterns": [ 67 | { 68 | "begin": "<%+#", 69 | "beginCaptures": { 70 | "0": { 71 | "name": "punctuation.definition.comment.begin.erb" 72 | } 73 | }, 74 | "end": "%>", 75 | "endCaptures": { 76 | "0": { 77 | "name": "punctuation.definition.comment.end.erb" 78 | } 79 | }, 80 | "name": "comment.block.erb" 81 | } 82 | ] 83 | }, 84 | "tags": { 85 | "patterns": [ 86 | { 87 | "begin": "<%+(?!>)[-=]?(?![^%]*%>)", 88 | "beginCaptures": { 89 | "0": { 90 | "name": "punctuation.section.embedded.begin.erb" 91 | } 92 | }, 93 | "contentName": "source.ruby", 94 | "end": "(-?%)>", 95 | "endCaptures": { 96 | "0": { 97 | "name": "punctuation.section.embedded.end.erb" 98 | }, 99 | "1": { 100 | "name": "source.ruby" 101 | } 102 | }, 103 | "name": "meta.embedded.block.erb", 104 | "patterns": [ 105 | { 106 | "captures": { 107 | "1": { 108 | "name": "punctuation.definition.comment.erb" 109 | } 110 | }, 111 | "match": "(#).*?(?=-?%>)", 112 | "name": "comment.line.number-sign.erb" 113 | }, 114 | { 115 | "include": "source.ruby" 116 | } 117 | ] 118 | }, 119 | { 120 | "begin": "<%+(?!>)[-=]?", 121 | "beginCaptures": { 122 | "0": { 123 | "name": "punctuation.section.embedded.begin.erb" 124 | } 125 | }, 126 | "contentName": "source.ruby", 127 | "end": "(-?%)>", 128 | "endCaptures": { 129 | "0": { 130 | "name": "punctuation.section.embedded.end.erb" 131 | }, 132 | "1": { 133 | "name": "source.ruby" 134 | } 135 | }, 136 | "name": "meta.embedded.line.erb", 137 | "patterns": [ 138 | { 139 | "captures": { 140 | "1": { 141 | "name": "punctuation.definition.comment.erb" 142 | } 143 | }, 144 | "match": "(#).*?(?=-?%>)", 145 | "name": "comment.line.number-sign.erb" 146 | }, 147 | { 148 | "include": "source.ruby" 149 | } 150 | ] 151 | } 152 | ] 153 | } 154 | }, 155 | "scopeName": "text.html.erb" 156 | } -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/html-rails.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": [ 3 | "rhtml", 4 | "erb", 5 | "html.erb" 6 | ], 7 | "foldingStartMarker": "(?x)\n\t\t(<(?i:head|body|table|thead|tbody|tfoot|tr|div|select|fieldset|style|script|ul|ol|form|dl)\\b.*?>\n\t\t|)\n\t\t|\\{\\s*($|\\?>\\s*$|//|/\\*(.*\\*/\\s*$|(?!.*?\\*/)))\n\t\t)", 8 | "foldingStopMarker": "(?x)\n\t\t(\n\t\t|^\\s*-->\n\t\t|(^|\\s)\\}\n\t\t)", 9 | "keyEquivalent": "^~R", 10 | "name": "HTML (Rails)", 11 | "patterns": [ 12 | { 13 | "begin": "<%+#", 14 | "captures": { 15 | "0": { 16 | "name": "punctuation.definition.comment.erb" 17 | } 18 | }, 19 | "end": "%>", 20 | "name": "comment.block.erb" 21 | }, 22 | { 23 | "begin": "<%+(?!>)[-=]?", 24 | "captures": { 25 | "0": { 26 | "name": "punctuation.section.embedded.ruby" 27 | } 28 | }, 29 | "end": "-?%>", 30 | "name": "source.ruby.rails.embedded.html", 31 | "patterns": [ 32 | { 33 | "captures": { 34 | "1": { 35 | "name": "punctuation.definition.comment.ruby" 36 | } 37 | }, 38 | "match": "(#).*?(?=-?%>)", 39 | "name": "comment.line.number-sign.ruby" 40 | }, 41 | { 42 | "include": "source.ruby.rails" 43 | } 44 | ] 45 | }, 46 | { 47 | "include": "text.html.basic" 48 | } 49 | ], 50 | "scopeName": "text.html.ruby" 51 | } -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/hyperlink.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": [], 3 | "injectionSelector": "text, string, comment", 4 | "name": "Hyperlink", 5 | "patterns": [ 6 | { 7 | "match": "(?x)\n\t\t\t\t( (https?|s?ftp|ftps|file|smb|afp|nfs|(x-)?man(-page)?|gopher|txmt|issue)://|mailto:)\n\t\t\t\t[-:@a-zA-Z0-9_.,~%+/?=&#;]+(?)|(\\?:))?", 103 | "beginCaptures": { 104 | "1": { 105 | "name": "punctuation.definition.group.regexp" 106 | }, 107 | "3": { 108 | "name": "punctuation.definition.group.capture.regexp" 109 | }, 110 | "4": { 111 | "name": "entity.name.section.group.regexp" 112 | }, 113 | "5": { 114 | "name": "punctuation.definition.group.capture.regexp" 115 | }, 116 | "6": { 117 | "name": "punctuation.definition.group.no-capture.regexp" 118 | } 119 | }, 120 | "end": "(\\))", 121 | "endCaptures": { 122 | "1": { 123 | "name": "punctuation.definition.group.regexp" 124 | } 125 | }, 126 | "name": "meta.group.regexp", 127 | "patterns": [ 128 | { 129 | "include": "$self" 130 | } 131 | ] 132 | }, 133 | { 134 | "include": "#character-class" 135 | } 136 | ], 137 | "repository": { 138 | "character-class": { 139 | "patterns": [ 140 | { 141 | "match": "\\\\[wWsSdDhH]|\\.", 142 | "name": "constant.character.character-class.regexp" 143 | }, 144 | { 145 | "match": "\\\\.", 146 | "name": "constant.character.escape.backslash.regexp" 147 | }, 148 | { 149 | "begin": "(\\[)(\\^)?", 150 | "beginCaptures": { 151 | "1": { 152 | "name": "punctuation.definition.character-class.regexp" 153 | }, 154 | "2": { 155 | "name": "keyword.operator.negation.regexp" 156 | } 157 | }, 158 | "end": "(\\])", 159 | "endCaptures": { 160 | "1": { 161 | "name": "punctuation.definition.character-class.regexp" 162 | } 163 | }, 164 | "name": "constant.other.character-class.set.regexp", 165 | "patterns": [ 166 | { 167 | "include": "#character-class" 168 | }, 169 | { 170 | "captures": { 171 | "2": { 172 | "name": "constant.character.escape.backslash.regexp" 173 | }, 174 | "4": { 175 | "name": "constant.character.escape.backslash.regexp" 176 | } 177 | }, 178 | "match": "((\\\\.)|.)\\-((\\\\.)|[^\\]])", 179 | "name": "constant.other.character-class.range.regexp" 180 | } 181 | ] 182 | } 183 | ] 184 | } 185 | }, 186 | "scopeName": "source.regexp.python" 187 | } -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/text.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": [ 3 | "txt" 4 | ], 5 | "keyEquivalent": "^~P", 6 | "name": "Plain Text", 7 | "patterns": [ 8 | { 9 | "captures": { 10 | "1": { 11 | "name": "punctuation.definition.item.text" 12 | } 13 | }, 14 | "match": "^\\s*(•).*$\\n?", 15 | "name": "meta.bullet-point.strong.text" 16 | }, 17 | { 18 | "captures": { 19 | "1": { 20 | "name": "punctuation.definition.item.text" 21 | } 22 | }, 23 | "match": "^\\s*(·).*$\\n?", 24 | "name": "meta.bullet-point.light.text" 25 | }, 26 | { 27 | "captures": { 28 | "1": { 29 | "name": "punctuation.definition.item.text" 30 | } 31 | }, 32 | "match": "^\\s*(\\*).*$\\n?", 33 | "name": "meta.bullet-point.star.text" 34 | }, 35 | { 36 | "begin": "^([ \\t]*)(?=\\S)", 37 | "contentName": "meta.paragraph.text", 38 | "end": "^(?!\\1(?=\\S))" 39 | } 40 | ], 41 | "scopeName": "text.plain" 42 | } -------------------------------------------------------------------------------- /test-cases/first-mate/fixtures/todo.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": [], 3 | "injectionSelector": "comment, text.plain", 4 | "name": "TODO", 5 | "patterns": [ 6 | { 7 | "match": "\\b(TODO|FIXME|CHANGED)\\b", 8 | "name": "storage.type.class.${1:/downcase}" 9 | }, 10 | { 11 | "captures": { 12 | "1": { 13 | "name": "markup.underline.link.radar" 14 | } 15 | }, 16 | "match": "<(ra?dar:/(?:/problem|)/(?:[&0-9]+))>", 17 | "name": "storage.type.class.radar" 18 | } 19 | ], 20 | "scopeName": "text.todo" 21 | } -------------------------------------------------------------------------------- /test-cases/suite1/fixtures/105.grammarA.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.test", 3 | "patterns": [{ "include": "#test" }, { "include": "#embedded" }], 4 | "repository": { 5 | "test": { 6 | "begin": "testStart", 7 | "end": "testEnd", 8 | "patterns": [{ "include": "#test2" }] 9 | }, 10 | "test2": { 11 | "match": "some test pattern", 12 | "name": "test.name" 13 | }, 14 | "embedded": { 15 | "begin": "embedStart", 16 | "end": "embedEnd", 17 | "patterns": [{ "include": "source.test.embedded" }] 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test-cases/suite1/fixtures/105.grammarB.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.test.embedded", 3 | "patterns": [{ "include": "#test" }], 4 | "repository": { 5 | "test": { 6 | "begin": "testStart", 7 | "end": "testEnd", 8 | "patterns": [{ "include": "#test2" }] 9 | }, 10 | "test2": { 11 | "include": "source.test#test2" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test-cases/suite1/fixtures/147.grammar.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.test", 3 | "patterns": [ 4 | { 5 | "match": "\\b(?i:function)\\b", 6 | "name": "storage.type.$0 keyword.declaration.$0" 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /test-cases/suite1/fixtures/66.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | scopeName 6 | text.test 7 | 8 | patterns 9 | 10 | 11 | begin^. 12 | namecomment 13 | 14 | 15 | 16 | begin. 17 | nameinvalid 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test-cases/suite1/fixtures/infinite-loop.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "infinite-loop-grammar", 3 | "scopeName": "source.infinite-loop", 4 | "patterns": [ 5 | { 6 | "name": "start", 7 | "begin": "\\A", 8 | "end": "$", 9 | "patterns": [ 10 | { 11 | "name": "negative-look-ahead", 12 | "match": "(?!a)" 13 | } 14 | ] 15 | }, 16 | { 17 | "include": "#test" 18 | }, 19 | { 20 | "include": "#not_a_problem" 21 | } 22 | ], 23 | "repository": { 24 | "test": { 25 | "name": "test", 26 | "begin": "(?=test)", 27 | "end": "$", 28 | "patterns": [ 29 | { 30 | "include": "#test_this" 31 | } 32 | ] 33 | }, 34 | "test_this": { 35 | "name": "test_this", 36 | "begin": "(?=test this)", 37 | "end": "$", 38 | "patterns": [ 39 | { 40 | "include": "#test_this_line" 41 | } 42 | ] 43 | }, 44 | "test_this_line": { 45 | "name": "test_this_line", 46 | "begin": "(?=test this line)", 47 | "end": "$", 48 | "patterns": [ 49 | { 50 | "include": "#test" 51 | } 52 | ] 53 | }, 54 | "spaces": 55 | { 56 | "name": "spaces", 57 | "begin": "^(?=\\s)", 58 | "end": "(?=\\S)" 59 | }, 60 | "not_a_problem": 61 | { 62 | "name": "not_a_problem", 63 | "begin": "(?=not)", 64 | "end": "\\z", 65 | "patterns": [ 66 | { 67 | "name": "not", 68 | "match": "\\Gnot" 69 | }, 70 | { 71 | "include": "#not_a_problem" 72 | }, 73 | { 74 | "include": "#spaces" 75 | } 76 | ] 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /test-cases/suite1/fixtures/testlang12.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | testlang 8 | 9 | name 10 | testlang 11 | patterns 12 | 13 | 14 | include 15 | #indentedVerbatimOp 16 | 17 | 18 | repository 19 | 20 | indentedVerbatimOp 21 | 22 | begin 23 | ^([ \t]*)(?=(.*?)\|$) 24 | end 25 | ^(?!\1[ \t])(?=[ \t]*\S) 26 | name 27 | string.unquoted.verbatim.youki 28 | 29 | 30 | scopeName 31 | text.testlang 32 | uuid 33 | 159375af-d9b4-448c-a9da-d235eadf3556 34 | 35 | -------------------------------------------------------------------------------- /test-cases/suite1/fixtures/whileLang.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | whileLang 8 | 9 | name 10 | whileLang 11 | patterns 12 | 13 | 14 | include 15 | #alist 16 | 17 | 18 | include 19 | #blist 20 | 21 | 22 | repository 23 | 24 | number 25 | 26 | match 27 | [0-9] 28 | name 29 | number 30 | 31 | letter 32 | 33 | match 34 | x 35 | name 36 | letter 37 | 38 | alist 39 | 40 | begin 41 | A 42 | patterns 43 | 44 | 45 | include 46 | #alist 47 | 48 | 49 | include 50 | #blist 51 | 52 | 53 | include 54 | #letter 55 | 56 | 57 | name 58 | alist 59 | while 60 | a 61 | 62 | blist 63 | 64 | begin 65 | B 66 | patterns 67 | 68 | 69 | include 70 | #alist 71 | 72 | 73 | include 74 | #blist 75 | 76 | 77 | include 78 | #number 79 | 80 | 81 | name 82 | blist 83 | whileCaptures 84 | 85 | 2 86 | 87 | name 88 | bstart 89 | 90 | 91 | while 92 | (^|\G)(b) 93 | 94 | 95 | scopeName 96 | text.whileLang 97 | uuid 98 | 159375af-d9b4-448c-a9da-d235eadf3556 99 | 100 | -------------------------------------------------------------------------------- /test-cases/themes/.gitignore: -------------------------------------------------------------------------------- 1 | /tests/*.diff.html 2 | -------------------------------------------------------------------------------- /test-cases/themes/dark_plus.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Dark+", 3 | "include": "./dark_vs.json", 4 | "settings": [ 5 | { 6 | "name": "Function declarations", 7 | "scope": [ 8 | "entity.name.function", 9 | "support.function" 10 | ], 11 | "settings": { 12 | "foreground": "#DCDCAA" 13 | } 14 | }, 15 | { 16 | "name": "Types declaration and references", 17 | "scope": [ 18 | "meta.return-type", 19 | "support.class", 20 | "support.type", 21 | "entity.name.type", 22 | "entity.name.class", 23 | 24 | "storage.type.cs", 25 | "storage.type.generic.cs", 26 | "storage.type.modifier.cs", 27 | "storage.type.variable.cs", 28 | 29 | "storage.type.annotation.java", 30 | "storage.type.generic.java", 31 | "storage.type.java", 32 | "storage.type.object.array.java", 33 | "storage.type.primitive.array.java", 34 | "storage.type.primitive.java", 35 | "storage.type.token.java", 36 | 37 | "storage.type.groovy", 38 | "storage.type.annotation.groovy", 39 | "storage.type.parameters.groovy", 40 | "storage.type.generic.groovy", 41 | "storage.type.object.array.groovy", 42 | "storage.type.primitive.array.groovy", 43 | "storage.type.primitive.groovy" 44 | ], 45 | "settings": { 46 | "foreground": "#4EC9B0" 47 | } 48 | }, 49 | { 50 | "name": "Types declaration and references, TS grammar specific", 51 | "scope": [ 52 | "meta.return.type", 53 | "meta.type.cast.expr", 54 | "meta.type.new.expr", 55 | "support.constant.math", 56 | "support.constant.dom", 57 | "support.constant.json" 58 | ], 59 | "settings": { 60 | "foreground": "#4EC9B0" 61 | } 62 | }, 63 | { 64 | "name": "Control flow keywords", 65 | "scope": "keyword.control", 66 | "settings": { 67 | "foreground": "#C586C0" 68 | } 69 | }, 70 | { 71 | "name": "Variable and parameter name", 72 | "scope": [ 73 | "variable", 74 | "meta.definition.variable.name", 75 | "support.variable" 76 | ], 77 | "settings": { 78 | "foreground": "#9CDCFE" 79 | } 80 | }, 81 | { 82 | "name": "Object keys, TS grammar specific", 83 | "scope": [ 84 | "meta.object-literal.key", 85 | "meta.object-literal.key entity.name.function" 86 | ], 87 | "settings": { 88 | "foreground": "#9CDCFE" 89 | } 90 | }, 91 | { 92 | "name": "CSS property value", 93 | "scope": [ 94 | "constant.other.color.rgb-value.css", 95 | "constant.other.rgb-value.css", 96 | "meta.property-value.css support.function", 97 | "meta.property-value.css support", 98 | 99 | "constant.numeric.color.rgb-value.scss", 100 | "constant.rgb-value.scss", 101 | "meta.property-value.scss support.function", 102 | "meta.property-value.scss support" 103 | ], 104 | "settings": { 105 | "foreground": "#CE9178" 106 | } 107 | } 108 | ] 109 | } -------------------------------------------------------------------------------- /test-cases/themes/go/colorize-fixtures/test-13777.go: -------------------------------------------------------------------------------- 1 | var e [][]*aType // ( bug in highligher?) -------------------------------------------------------------------------------- /test-cases/themes/go/colorize-fixtures/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | dnsName := "test-vm-from-go" 10 | storageAccount := "mystorageaccount" 11 | 12 | client, err := management.ClientFromPublishSettingsFile("path/to/downloaded.publishsettings", "") 13 | if err != nil { 14 | panic(err) 15 | } 16 | 17 | // create virtual machine 18 | role := vmutils.NewVMConfiguration(dnsName, vmSize) 19 | vmutils.ConfigureDeploymentFromPlatformImage( 20 | &role, 21 | vmImage, 22 | fmt.Sprintf("http://%s.blob.core.windows.net/sdktest/%s.vhd", storageAccount, dnsName), 23 | "") 24 | } -------------------------------------------------------------------------------- /test-cases/themes/go/colorize-results/test-13777_go.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "c": "var", 4 | "t": "go.keyword.var", 5 | "r": { 6 | "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.keyword rgb(86, 156, 214)", 7 | "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.keyword rgb(0, 0, 255)", 8 | "dark_vs": ".vs-dark.vscode-theme-defaults-themes-dark_vs-json .token.keyword rgb(86, 156, 214)", 9 | "light_vs": ".vs.vscode-theme-defaults-themes-light_vs-json .token.keyword rgb(0, 0, 255)", 10 | "hc_black": ".hc-black.vscode-theme-defaults-themes-hc_black-json .token.keyword rgb(86, 156, 214)" 11 | } 12 | }, 13 | { 14 | "c": " e [][]*aType // ( ", 15 | "t": "", 16 | "r": { 17 | "dark_plus": ".vs-dark .token rgb(212, 212, 212)", 18 | "light_plus": ".vs .token rgb(0, 0, 0)", 19 | "dark_vs": ".vs-dark .token rgb(212, 212, 212)", 20 | "light_vs": ".vs .token rgb(0, 0, 0)", 21 | "hc_black": ".hc-black .token rgb(255, 255, 255)" 22 | } 23 | }, 24 | { 25 | "c": "bug", 26 | "t": "declaration.go.other.variable", 27 | "r": { 28 | "dark_plus": ".vs-dark.vscode-theme-defaults-themes-dark_plus-json .token.variable rgb(156, 220, 254)", 29 | "light_plus": ".vs.vscode-theme-defaults-themes-light_plus-json .token.variable rgb(0, 16, 128)", 30 | "dark_vs": ".vs-dark .token rgb(212, 212, 212)", 31 | "light_vs": ".vs .token rgb(0, 0, 0)", 32 | "hc_black": ".hc-black .token rgb(255, 255, 255)" 33 | } 34 | }, 35 | { 36 | "c": " in highligher?", 37 | "t": "", 38 | "r": { 39 | "dark_plus": ".vs-dark .token rgb(212, 212, 212)", 40 | "light_plus": ".vs .token rgb(0, 0, 0)", 41 | "dark_vs": ".vs-dark .token rgb(212, 212, 212)", 42 | "light_vs": ".vs .token rgb(0, 0, 0)", 43 | "hc_black": ".hc-black .token rgb(255, 255, 255)" 44 | } 45 | }, 46 | { 47 | "c": ")", 48 | "t": "bracket.go.other.punctuation.round", 49 | "r": { 50 | "dark_plus": ".vs-dark .token rgb(212, 212, 212)", 51 | "light_plus": ".vs .token rgb(0, 0, 0)", 52 | "dark_vs": ".vs-dark .token rgb(212, 212, 212)", 53 | "light_vs": ".vs .token rgb(0, 0, 0)", 54 | "hc_black": ".hc-black .token rgb(255, 255, 255)" 55 | } 56 | } 57 | ] -------------------------------------------------------------------------------- /test-cases/themes/light_plus.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Light+", 3 | "include": "./light_vs.json", 4 | "settings": [ 5 | { 6 | "name": "Function declarations", 7 | "scope": [ 8 | "entity.name.function", 9 | "support.function" 10 | ], 11 | "settings": { 12 | "foreground": "#795E26" 13 | } 14 | }, 15 | { 16 | "name": "Types declaration and references", 17 | "scope": [ 18 | "meta.return-type", 19 | "support.class", 20 | "support.type", 21 | "entity.name.type", 22 | "entity.name.class", 23 | 24 | "storage.type.cs", 25 | "storage.type.generic.cs", 26 | "storage.type.modifier.cs", 27 | "storage.type.variable.cs", 28 | 29 | "storage.type.annotation.java", 30 | "storage.type.generic.java", 31 | "storage.type.java", 32 | "storage.type.object.array.java", 33 | "storage.type.primitive.array.java", 34 | "storage.type.primitive.java", 35 | "storage.type.token.java", 36 | 37 | "storage.type.groovy", 38 | "storage.type.annotation.groovy", 39 | "storage.type.parameters.groovy", 40 | "storage.type.generic.groovy", 41 | "storage.type.object.array.groovy", 42 | "storage.type.primitive.array.groovy", 43 | "storage.type.primitive.groovy" 44 | ], 45 | "settings": { 46 | "foreground": "#267f99" 47 | } 48 | }, 49 | { 50 | "name": "Types declaration and references, TS grammar specific", 51 | "scope": [ 52 | "meta.return.type", 53 | "meta.type.cast.expr", 54 | "meta.type.new.expr", 55 | "support.constant.math", 56 | "support.constant.dom", 57 | "support.constant.json" 58 | ], 59 | "settings": { 60 | "foreground": "#267f99" 61 | } 62 | }, 63 | { 64 | "name": "Control flow keywords", 65 | "scope": "keyword.control", 66 | "settings": { 67 | "foreground": "#AF00DB" 68 | } 69 | }, 70 | { 71 | "name": "Variable and parameter name", 72 | "scope": [ 73 | "variable", 74 | "meta.definition.variable.name", 75 | "support.variable" 76 | ], 77 | "settings": { 78 | "foreground": "#001080" 79 | } 80 | }, 81 | { 82 | "name": "Object keys, TS grammar specific", 83 | "scope": [ 84 | "meta.object-literal.key", 85 | "meta.object-literal.key entity.name.function" 86 | ], 87 | "settings": { 88 | "foreground": "#001080" 89 | } 90 | }, 91 | { 92 | "name": "CSS property value", 93 | "scope": [ 94 | "constant.other.color.rgb-value.css", 95 | "constant.other.rgb-value.css", 96 | "meta.property-value.css support.function", 97 | "meta.property-value.css support", 98 | 99 | "constant.numeric.color.rgb-value.scss", 100 | "constant.rgb-value.scss", 101 | "meta.property-value.scss support.function", 102 | "meta.property-value.scss support" 103 | ], 104 | "settings": { 105 | "foreground": "#0451a5" 106 | } 107 | } 108 | ] 109 | } -------------------------------------------------------------------------------- /test-cases/themes/syntaxes/Dockerfile.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | Dockerfile 8 | 9 | name 10 | Dockerfile 11 | patterns 12 | 13 | 14 | captures 15 | 16 | 1 17 | 18 | name 19 | keyword.control.dockerfile 20 | 21 | 2 22 | 23 | name 24 | keyword.other.special-method.dockerfile 25 | 26 | 27 | match 28 | ^\s*(?:(ONBUILD)\s+)?(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|USER|WORKDIR|COPY|LABEL|STOPSIGNAL|ARG)\s 29 | 30 | 31 | captures 32 | 33 | 1 34 | 35 | name 36 | keyword.operator.dockerfile 37 | 38 | 2 39 | 40 | name 41 | keyword.other.special-method.dockerfile 42 | 43 | 44 | match 45 | ^\s*(?:(ONBUILD)\s+)?(CMD|ENTRYPOINT)\s 46 | 47 | 48 | begin 49 | " 50 | beginCaptures 51 | 52 | 1 53 | 54 | name 55 | punctuation.definition.string.begin.dockerfile 56 | 57 | 58 | end 59 | " 60 | endCaptures 61 | 62 | 1 63 | 64 | name 65 | punctuation.definition.string.end.dockerfile 66 | 67 | 68 | name 69 | string.quoted.double.dockerfile 70 | patterns 71 | 72 | 73 | match 74 | \\. 75 | name 76 | constant.character.escaped.dockerfile 77 | 78 | 79 | 80 | 81 | begin 82 | ' 83 | beginCaptures 84 | 85 | 1 86 | 87 | name 88 | punctuation.definition.string.begin.dockerfile 89 | 90 | 91 | end 92 | ' 93 | endCaptures 94 | 95 | 1 96 | 97 | name 98 | punctuation.definition.string.end.dockerfile 99 | 100 | 101 | name 102 | string.quoted.single.dockerfile 103 | patterns 104 | 105 | 106 | match 107 | \\. 108 | name 109 | constant.character.escaped.dockerfile 110 | 111 | 112 | 113 | 114 | captures 115 | 116 | 1 117 | 118 | name 119 | punctuation.whitespace.comment.leading.dockerfile 120 | 121 | 2 122 | 123 | name 124 | comment.line.number-sign.dockerfile 125 | 126 | 3 127 | 128 | name 129 | punctuation.definition.comment.dockerfile 130 | 131 | 132 | comment 133 | comment.line 134 | match 135 | ^(\s*)((#).*$\n?) 136 | 137 | 138 | scopeName 139 | source.dockerfile 140 | uuid 141 | a39d8795-59d2-49af-aa00-fe74ee29576e 142 | 143 | -------------------------------------------------------------------------------- /test-cases/themes/syntaxes/cshtml.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ASP.NET Razor", 3 | "scopeName": "text.html.cshtml", 4 | "fileTypes": [ 5 | "cshtml", 6 | "gohtml" 7 | ], 8 | "patterns": [ 9 | { 10 | "name": "section.embedded.source.cshtml", 11 | "begin": "(@?([a-zA-Z0-9]+)?)(\\s[a-zA-Z0-9]+)?(\n|\r)?(\\{)", 12 | "beginCaptures": { 13 | "0": { 14 | "name": "punctuation.section.embedded.begin.cshtml" 15 | }, 16 | "1": { 17 | "name": "keyword.control.cshtml" 18 | } 19 | }, 20 | "patterns": [ 21 | { 22 | "name": "section.embedded.source.cshtml", 23 | "begin": "(@?([a-zA-Z0-9]+)?)(\\s[a-zA-Z0-9]+)?(\n|\r)?(\\{)", 24 | "beginCaptures": { 25 | "0": { 26 | "name": "punctuation.section.embedded.begin.cshtml" 27 | }, 28 | "1": { 29 | "name": "keyword.control.cshtml" 30 | } 31 | }, 32 | "patterns": [ 33 | { 34 | "name": "string.quoted.single.cshtml", 35 | "match": "'" 36 | }, 37 | { 38 | "include": "#embedded-code" 39 | }, 40 | { 41 | "include": "#comments" 42 | }, 43 | { 44 | "include": "source.cs" 45 | }, 46 | { 47 | "include": "text.html.basic" 48 | } 49 | ], 50 | "end": "\\}", 51 | "endCaptures": { 52 | "0": { 53 | "name": "punctuation.section.embedded.begin.cshtml" 54 | } 55 | } 56 | }, 57 | { 58 | "name": "string.quoted.single.cshtml", 59 | "match": "'" 60 | }, 61 | { 62 | "include": "#embedded-code" 63 | }, 64 | { 65 | "include": "#comments" 66 | }, 67 | { 68 | "include": "text.html.basic" 69 | } 70 | ], 71 | "end": "\\}", 72 | "endCaptures": { 73 | "0": { 74 | "name": "punctuation.section.embedded.begin.cshtml" 75 | } 76 | }, 77 | "comments": "Simple multi-line code section" 78 | }, 79 | { 80 | "begin": "(@[a-zA-Z0-9]+)(\\s?)", 81 | "captures": { 82 | "0": { 83 | "name": "section.embedded.begin.cshtml" 84 | }, 85 | "1": { 86 | "name": "keyword.control.cshtml" 87 | } 88 | }, 89 | "patterns": [ 90 | { 91 | "match": "(([a-zA-Z0-9]+)(\\.)?)+?", 92 | "captures": { 93 | "2": { 94 | "name": "entity.name.tag.source.cshtml" 95 | }, 96 | "3": { 97 | "name": "punctuation.separator.namespace.source.cshtml" 98 | } 99 | } 100 | }, 101 | { 102 | "include": "#embedded-code" 103 | }, 104 | { 105 | "include": "#comments" 106 | }, 107 | { 108 | "include": "source.cs" 109 | }, 110 | { 111 | "include": "text.html.basic" 112 | } 113 | ], 114 | "end": "(\\n|\\s)", 115 | "comments": "Covers single line Razor tags" 116 | }, 117 | { 118 | "include": "#comments" 119 | }, 120 | { 121 | "include": "text.html.basic" 122 | } 123 | ], 124 | "repository": { 125 | "embedded-code": { 126 | "match": "(@?[a-zA-Z0-9]+)(\\.([a-zA-Z0-9]+))?", 127 | "captures": { 128 | "1": { 129 | "name": "keyword.control.cshtml" 130 | }, 131 | "3": { 132 | "name": "entity.name.tag.source.cshtml" 133 | } 134 | }, 135 | "patterns": [ 136 | { 137 | "include": "#comments" 138 | } 139 | ] 140 | }, 141 | "comments": { 142 | "begin": "@\\*", 143 | "captures": { 144 | "0": { 145 | "name": "punctuation.definition.comment.source.cshtml" 146 | } 147 | }, 148 | "end": "\\*@", 149 | "name": "comment.block.cshtml" 150 | } 151 | }, 152 | "version": "https://github.com/demyte/language-cshtml/commit/a49735dc7aef56ae772a3bcfd8e42c89895dcff4" 153 | } -------------------------------------------------------------------------------- /test-cases/themes/syntaxes/git-rebase.tmLanguage: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | fileTypes 6 | 7 | git-rebase-todo 8 | 9 | name 10 | Git Rebase Message 11 | patterns 12 | 13 | 14 | captures 15 | 16 | 1 17 | 18 | name 19 | punctuation.definition.comment.git-rebase 20 | 21 | 22 | match 23 | ^\s*(#).*$\n? 24 | name 25 | comment.line.number-sign.git-rebase 26 | 27 | 28 | captures 29 | 30 | 1 31 | 32 | name 33 | support.function.git-rebase 34 | 35 | 2 36 | 37 | name 38 | constant.sha.git-rebase 39 | 40 | 3 41 | 42 | name 43 | meta.commit-message.git-rebase 44 | 45 | 46 | match 47 | ^\s*(pick|p|reword|r|edit|e|squash|s|fixup|f|d|drop|x|exec)\s+([0-9a-f]+)\s+(.*)$ 48 | name 49 | meta.commit-command.git-rebase 50 | 51 | 52 | scopeName 53 | text.git-rebase 54 | uuid 55 | 7F1CC209-5F6D-486A-8180-09FA282381A1 56 | 57 | 58 | -------------------------------------------------------------------------------- /test-cases/themes/syntaxes/lua.json: -------------------------------------------------------------------------------- 1 | { 2 | "comment": "Lua Syntax: version 0.8", 3 | "fileTypes": [ 4 | "lua" 5 | ], 6 | "firstLineMatch": "\\A#!.*?\\blua\\b", 7 | "keyEquivalent": "^~L", 8 | "name": "Lua", 9 | "patterns": [ 10 | { 11 | "captures": { 12 | "1": { 13 | "name": "keyword.control.lua" 14 | }, 15 | "2": { 16 | "name": "entity.name.function.scope.lua" 17 | }, 18 | "3": { 19 | "name": "entity.name.function.lua" 20 | }, 21 | "4": { 22 | "name": "punctuation.definition.parameters.begin.lua" 23 | }, 24 | "5": { 25 | "name": "variable.parameter.function.lua" 26 | }, 27 | "6": { 28 | "name": "punctuation.definition.parameters.end.lua" 29 | } 30 | }, 31 | "match": "\\b(function)(?:\\s+([a-zA-Z_.:]+[.:])?([a-zA-Z_]\\w*)\\s*)?(\\()([^)]*)(\\))", 32 | "name": "meta.function.lua" 33 | }, 34 | { 35 | "match": "(?=?|(? 2 | 3 | 4 | 5 | fileTypes 6 | 7 | ini 8 | conf 9 | 10 | keyEquivalent 11 | ^~I 12 | name 13 | Ini 14 | patterns 15 | 16 | 17 | begin 18 | (^[ \t]+)?(?=#) 19 | beginCaptures 20 | 21 | 1 22 | 23 | name 24 | punctuation.whitespace.comment.leading.ini 25 | 26 | 27 | end 28 | (?!\G) 29 | patterns 30 | 31 | 32 | begin 33 | # 34 | beginCaptures 35 | 36 | 0 37 | 38 | name 39 | punctuation.definition.comment.ini 40 | 41 | 42 | end 43 | \n 44 | name 45 | comment.line.number-sign.ini 46 | 47 | 48 | 49 | 50 | begin 51 | (^[ \t]+)?(?=;) 52 | beginCaptures 53 | 54 | 1 55 | 56 | name 57 | punctuation.whitespace.comment.leading.ini 58 | 59 | 60 | end 61 | (?!\G) 62 | patterns 63 | 64 | 65 | begin 66 | ; 67 | beginCaptures 68 | 69 | 0 70 | 71 | name 72 | punctuation.definition.comment.ini 73 | 74 | 75 | end 76 | \n 77 | name 78 | comment.line.semicolon.ini 79 | 80 | 81 | 82 | 83 | captures 84 | 85 | 1 86 | 87 | name 88 | keyword.other.definition.ini 89 | 90 | 2 91 | 92 | name 93 | punctuation.separator.key-value.ini 94 | 95 | 96 | match 97 | \b([a-zA-Z0-9_.-]+)\b\s*(=) 98 | 99 | 100 | captures 101 | 102 | 1 103 | 104 | name 105 | punctuation.definition.entity.ini 106 | 107 | 3 108 | 109 | name 110 | punctuation.definition.entity.ini 111 | 112 | 113 | match 114 | ^(\[)(.*?)(\]) 115 | name 116 | entity.name.section.group-title.ini 117 | 118 | 119 | begin 120 | ' 121 | beginCaptures 122 | 123 | 0 124 | 125 | name 126 | punctuation.definition.string.begin.ini 127 | 128 | 129 | end 130 | ' 131 | endCaptures 132 | 133 | 0 134 | 135 | name 136 | punctuation.definition.string.end.ini 137 | 138 | 139 | name 140 | string.quoted.single.ini 141 | patterns 142 | 143 | 144 | match 145 | \\. 146 | name 147 | constant.character.escape.ini 148 | 149 | 150 | 151 | 152 | begin 153 | " 154 | beginCaptures 155 | 156 | 0 157 | 158 | name 159 | punctuation.definition.string.begin.ini 160 | 161 | 162 | end 163 | " 164 | endCaptures 165 | 166 | 0 167 | 168 | name 169 | punctuation.definition.string.end.ini 170 | 171 | 172 | name 173 | string.quoted.double.ini 174 | 175 | 176 | scopeName 177 | source.properties 178 | uuid 179 | 77DC23B6-8A90-11D9-BAA4-000A9584EC8C 180 | 181 | -------------------------------------------------------------------------------- /test-cases/themes/syntaxes/shaderlab.json: -------------------------------------------------------------------------------- 1 | { 2 | "scopeName": "source.shaderlab", 3 | "name": "ShaderLab", 4 | "fileTypes": [ 5 | "shader" 6 | ], 7 | "patterns": [ 8 | { 9 | "match": "\\b([0-9]+\\.?[0-9]*)\\b", 10 | "name": "constant.numeric.shaderlab" 11 | }, 12 | { 13 | "match": "\\b(Shader|Properties|Category|SubShader|Tags|Pass)\\b", 14 | "name": "support.class.shaderlab" 15 | }, 16 | { 17 | "match": "\\b(CGPROGRAM|ENDCG)\\b", 18 | "name": "support.class.shaderlab" 19 | }, 20 | { 21 | "match": "\\b(Dependency|Fallback)\\b", 22 | "name": "support.variable.shaderlab" 23 | }, 24 | { 25 | "match": "^\\s*\\[(HideInInspector)\\]", 26 | "name": "keyword.shaderlab" 27 | }, 28 | { 29 | "match": "\\b(_\\w+)\\b", 30 | "name": "support.variable.input.shaderlab" 31 | }, 32 | { 33 | "match": "\\b(uv(2)*_\\w+|viewDir|COLOR|screenPos|worldPos|worldRefl|worldNormal|worldRefl|worldNormal)\\b", 34 | "name": "support.variable.input.shaderlab" 35 | }, 36 | { 37 | "match": "\\b(Albedo|Normal|Emission|Specular|Gloss|Alpha)\\b", 38 | "name": "support.variable.output.shaderlab" 39 | }, 40 | { 41 | "match": "\\b(appdata_(base|tan|full|img)|SurfaceOutput)\\b", 42 | "name": "support.variable.structure.shaderlab" 43 | }, 44 | { 45 | "match": "\\b(UNITY_MATRIX_(MVP|MV|V|P|VP|T_MV|IT_MV|TEXTURE0|TEXTURE1|TEXTURE2|TEXTURE3)|_Object2World|_World2Object|_WorldSpaceCameraPos|unity_Scale)\\b", 46 | "name": "support.variable.transformation.shaderlab" 47 | }, 48 | { 49 | "match": "\\b(_ModelLightColor[0-9]|_SpecularLightColor[0-9]|_ObjectSpaceLightPos|_Light2World|_World2Light|_Object2Light)\\b", 50 | "name": "support.variable.lighting.shaderlab" 51 | }, 52 | { 53 | "match": "\\b(_Time|_SinTime|_CosTime|unity_DeltaTime|_ProjectionParams|_ScreenParams)\\b", 54 | "name": "support.variable.other.shaderlab" 55 | }, 56 | { 57 | "include": "#comments" 58 | }, 59 | { 60 | "include": "#strings" 61 | }, 62 | { 63 | "include": "#functions" 64 | }, 65 | { 66 | "include": "#cg" 67 | } 68 | ], 69 | "repository": { 70 | "comments": { 71 | "patterns": [ 72 | { 73 | "begin": "//", 74 | "end": "$", 75 | "name": "comment.line.double-slash.shaderlab" 76 | }, 77 | { 78 | "begin": "/\\*", 79 | "end": "\\*/", 80 | "name": "comment.line.block.shaderlab" 81 | } 82 | ] 83 | }, 84 | "strings": { 85 | "patterns": [ 86 | { 87 | "begin": "\"", 88 | "end": "\"", 89 | "name": "string.quoted.double.shaderlab" 90 | } 91 | ] 92 | }, 93 | "functions": { 94 | "patterns": [ 95 | { 96 | "match": "(?x) (?: (?= \\s ) (?:(?<=else|new|return) | (?)", 29 | "name": "meta.tag.xml.template", 30 | "patterns": [ 31 | { 32 | "captures": { 33 | "1": { 34 | "name": "entity.other.attribute-name.namespace.xml" 35 | }, 36 | "2": { 37 | "name": "entity.other.attribute-name.xml" 38 | }, 39 | "3": { 40 | "name": "punctuation.separator.namespace.xml" 41 | }, 42 | "4": { 43 | "name": "entity.other.attribute-name.localname.xml" 44 | } 45 | }, 46 | "match": " (?:([-_a-zA-Z0-9]+)((:)))?([a-zA-Z-]+)" 47 | }, 48 | { 49 | "include": "#doublequotedString" 50 | }, 51 | { 52 | "include": "#singlequotedString" 53 | } 54 | ] 55 | }, 56 | { 57 | "include": "text.xml" 58 | } 59 | ], 60 | "repository": { 61 | "doublequotedString": { 62 | "begin": "\"", 63 | "beginCaptures": { 64 | "0": { 65 | "name": "punctuation.definition.string.begin.xml" 66 | } 67 | }, 68 | "end": "\"", 69 | "endCaptures": { 70 | "0": { 71 | "name": "punctuation.definition.string.end.xml" 72 | } 73 | }, 74 | "name": "string.quoted.double.xml" 75 | }, 76 | "singlequotedString": { 77 | "begin": "'", 78 | "beginCaptures": { 79 | "0": { 80 | "name": "punctuation.definition.string.begin.xml" 81 | } 82 | }, 83 | "end": "'", 84 | "endCaptures": { 85 | "0": { 86 | "name": "punctuation.definition.string.end.xml" 87 | } 88 | }, 89 | "name": "string.quoted.single.xml" 90 | } 91 | }, 92 | "version": "https://github.com/atom/language-xml/commit/507de2ee7daca60cf02e9e21fbeb92bbae73e280" 93 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/12750.html: -------------------------------------------------------------------------------- 1 | 4 | -------------------------------------------------------------------------------- /test-cases/themes/tests/13448.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-cases/themes/tests/14119.less: -------------------------------------------------------------------------------- 1 | #f(@hm: "broken highlighting in VS Code") { 2 | content: ""; 3 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/COMMIT_EDITMSG: -------------------------------------------------------------------------------- 1 | This is the summary line. It can't be too long. 2 | After I can write a much more detailed description without quite the same restrictions on length. 3 | 4 | # Please enter the commit message for your changes. Lines starting 5 | # with '#' will be ignored, and an empty message aborts the commit. 6 | # On branch master 7 | # Your branch is up-to-date with 'origin/master'. 8 | # 9 | # Changes to be committed: 10 | # deleted: README.md 11 | # modified: index.less 12 | # new file: spec/COMMIT_EDITMSG 13 | # -------------------------------------------------------------------------------- /test-cases/themes/tests/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu 2 | MAINTAINER Kimbro Staken 3 | 4 | RUN apt-get install -y software-properties-common python 5 | RUN add-apt-repository ppa:chris-lea/node.js 6 | RUN echo "deb http://us.archive.ubuntu.com/ubuntu/ precise universe" >> /etc/apt/sources.list 7 | RUN apt-get update 8 | RUN apt-get install -y nodejs 9 | #RUN apt-get install -y nodejs=0.6.12~dfsg1-1ubuntu1 10 | RUN mkdir /var/www 11 | 12 | ADD app.js /var/www/app.js 13 | 14 | CMD ["/usr/bin/node", "/var/www/app.js"] -------------------------------------------------------------------------------- /test-cases/themes/tests/basic.java: -------------------------------------------------------------------------------- 1 | package foo; 2 | 3 | import org.junit.Test; 4 | import org.junit.runners.*; 5 | 6 | /* 7 | * Multi line comment 8 | */ 9 | public class TestClass { 10 | 11 | private String aString; 12 | 13 | /** 14 | * @param args 15 | */ 16 | public void doSomething(int a) { 17 | double b = 0.0; 18 | double c = 10e3; 19 | long l = 134l; 20 | } 21 | 22 | /* 23 | * multiline comment 24 | */ 25 | @SuppressWarnings(value = "aString") 26 | private long privateMethod(long b){ 27 | for (int i = 0; i < 9; i++) { 28 | System.out.println("Hello" + i); 29 | } 30 | return 10; 31 | } 32 | 33 | //single line comment 34 | @Test 35 | public void someTests() { 36 | int hex = 0x5; 37 | Vector v = new Vector(); 38 | } 39 | 40 | 41 | } 42 | -------------------------------------------------------------------------------- /test-cases/themes/tests/git-rebase-todo: -------------------------------------------------------------------------------- 1 | pick 1fc6c95 Patch A 2 | squash fa39187 Something to add to patch A 3 | pick 7b36971 Something to move before patch B 4 | pick 6b2481b Patch B 5 | fixup c619268 A fix for Patch B 6 | edit dd1475d Something I want to split 7 | reword 4ca2acc i cant' typ goods 8 | 9 | # Commands: 10 | # p, pick = use commit 11 | # r, reword = use commit, but edit the commit message 12 | # e, edit = use commit, but stop for amending 13 | # s, squash = use commit, but meld into previous commit 14 | # f, fixup = like "squash", but discard this commit's log message 15 | # x, exec = run command (the rest of the line) using shell -------------------------------------------------------------------------------- /test-cases/themes/tests/issue-1550.yaml: -------------------------------------------------------------------------------- 1 | test1 : dsd 2 | test2 : abc-def 3 | test-3 : abcdef 4 | test-4 : abc-def -------------------------------------------------------------------------------- /test-cases/themes/tests/issue-4008.yaml: -------------------------------------------------------------------------------- 1 | - blue: a="brown,not_brown" 2 | - not_blue: foo 3 | - blue: foo="}" 4 | - not_blue: 1 -------------------------------------------------------------------------------- /test-cases/themes/tests/issue-6303.yaml: -------------------------------------------------------------------------------- 1 | swagger: '2.0' 2 | info: 3 | description: 'The API Management Service API defines an updated and refined version 4 | of the concepts currently known as Developer, APP, and API Product in Edge. Of 5 | note is the introduction of the API concept, missing previously from Edge 6 | 7 | ' 8 | title: API Management Service API 9 | version: initial -------------------------------------------------------------------------------- /test-cases/themes/tests/makefile: -------------------------------------------------------------------------------- 1 | all: hello 2 | 3 | hello: main.o factorial.o hello.o 4 | g++ main.o factorial.o hello.o -o hello 5 | 6 | main.o: main.cpp 7 | g++ -c main.cpp 8 | 9 | factorial.o: factorial.cpp 10 | g++ -c factorial.cpp 11 | 12 | hello.o: hello.cpp 13 | g++ -c hello.cpp 14 | 15 | clean: 16 | rm *o hello 17 | 18 | define defined 19 | $(info Checkng existance of $(1)) 20 | $(if ifeq "$(flavor $(1))" "undefined",0,1) 21 | endef 22 | 23 | ifeq ($(call defined,TOP_DIR),0) 24 | TOP_DIR must be set before including paths.mk 25 | endif 26 | 27 | include $(TOP_DIR)3rdparty.mk 28 | 29 | ifeq ($(call defined,CODIT_DIR),0) 30 | CODIT_DIR must be set in $(TOP_DIR)3rdparty.mk 31 | endif -------------------------------------------------------------------------------- /test-cases/themes/tests/test-13777.go: -------------------------------------------------------------------------------- 1 | var e [][]*aType // ( bug in highligher?) -------------------------------------------------------------------------------- /test-cases/themes/tests/test-13777.go.result: -------------------------------------------------------------------------------- 1 | { 2 | "abyss": [ 3 | { 4 | "content": "var", 5 | "color": "#225588" 6 | }, 7 | { 8 | "content": " e [][]*aType // ( bug in highligher?)", 9 | "color": "#6688CC" 10 | } 11 | ], 12 | "dark_vs": [ 13 | { 14 | "content": "var", 15 | "color": "#569CD6" 16 | }, 17 | { 18 | "content": " e [][]*aType // ( bug in highligher?)", 19 | "color": "#D4D4D4" 20 | } 21 | ], 22 | "light_vs": [ 23 | { 24 | "content": "var", 25 | "color": "#0000FF" 26 | }, 27 | { 28 | "content": " e [][]*aType // ( bug in highligher?)", 29 | "color": "#000000" 30 | } 31 | ], 32 | "hc_black": [ 33 | { 34 | "content": "var", 35 | "color": "#569CD6" 36 | }, 37 | { 38 | "content": " e [][]*aType // ( bug in highligher?)", 39 | "color": "#FFFFFF" 40 | } 41 | ], 42 | "dark_plus": [ 43 | { 44 | "content": "var", 45 | "color": "#569CD6" 46 | }, 47 | { 48 | "content": " e [][]*aType // ( ", 49 | "color": "#D4D4D4" 50 | }, 51 | { 52 | "content": "bug", 53 | "color": "#9CDCFE" 54 | }, 55 | { 56 | "content": " in highligher?)", 57 | "color": "#D4D4D4" 58 | } 59 | ], 60 | "light_plus": [ 61 | { 62 | "content": "var", 63 | "color": "#0000FF" 64 | }, 65 | { 66 | "content": " e [][]*aType // ( ", 67 | "color": "#000000" 68 | }, 69 | { 70 | "content": "bug", 71 | "color": "#001080" 72 | }, 73 | { 74 | "content": " in highligher?)", 75 | "color": "#000000" 76 | } 77 | ], 78 | "kimbie_dark": [ 79 | { 80 | "content": "var", 81 | "color": "#98676A" 82 | }, 83 | { 84 | "content": " e [][]*aType // ( ", 85 | "color": "#D3AF86" 86 | }, 87 | { 88 | "content": "bug", 89 | "color": "#DC3958" 90 | }, 91 | { 92 | "content": " in highligher?)", 93 | "color": "#D3AF86" 94 | } 95 | ], 96 | "monokai": [ 97 | { 98 | "content": "var", 99 | "color": "#F92672" 100 | }, 101 | { 102 | "content": " e [][]*aType // ( bug in highligher?)", 103 | "color": "#F8F8F2" 104 | } 105 | ], 106 | "monokai_dimmed": [ 107 | { 108 | "content": "var", 109 | "color": "#676867" 110 | }, 111 | { 112 | "content": " e [][]*aType // ( ", 113 | "color": "#C5C8C6" 114 | }, 115 | { 116 | "content": "bug", 117 | "color": "#6089B4" 118 | }, 119 | { 120 | "content": " in highligher?)", 121 | "color": "#C5C8C6" 122 | } 123 | ], 124 | "quietlight": [ 125 | { 126 | "content": "var", 127 | "color": "#4B83CD" 128 | }, 129 | { 130 | "content": " e [][]*aType // ( ", 131 | "color": "#333333" 132 | }, 133 | { 134 | "content": "bug", 135 | "color": "#7A3E9D" 136 | }, 137 | { 138 | "content": " in highligher?", 139 | "color": "#333333" 140 | }, 141 | { 142 | "content": ")", 143 | "color": "#777777" 144 | } 145 | ], 146 | "red": [ 147 | { 148 | "content": "var", 149 | "color": "#F12727FF" 150 | }, 151 | { 152 | "content": " e [][]*aType // ( ", 153 | "color": "#F8F8F8" 154 | }, 155 | { 156 | "content": "bug", 157 | "color": "#FB9A4BFF" 158 | }, 159 | { 160 | "content": " in highligher?)", 161 | "color": "#F8F8F8" 162 | } 163 | ], 164 | "solarized_dark": [ 165 | { 166 | "content": "var", 167 | "color": "#859900" 168 | }, 169 | { 170 | "content": " e [][]*aType // ( ", 171 | "color": "#93A1A1" 172 | }, 173 | { 174 | "content": "bug", 175 | "color": "#268BD2" 176 | }, 177 | { 178 | "content": " in highligher?)", 179 | "color": "#93A1A1" 180 | } 181 | ], 182 | "solarized_light": [ 183 | { 184 | "content": "var", 185 | "color": "#859900" 186 | }, 187 | { 188 | "content": " e [][]*aType // ( ", 189 | "color": "#586E75" 190 | }, 191 | { 192 | "content": "bug", 193 | "color": "#268BD2" 194 | }, 195 | { 196 | "content": " in highligher?)", 197 | "color": "#586E75" 198 | } 199 | ], 200 | "tomorrow_night_blue": [ 201 | { 202 | "content": "var", 203 | "color": "#EBBBFF" 204 | }, 205 | { 206 | "content": " e [][]*aType // ( ", 207 | "color": "#FFFFFF" 208 | }, 209 | { 210 | "content": "bug", 211 | "color": "#FF9DA4" 212 | }, 213 | { 214 | "content": " in highligher?)", 215 | "color": "#FFFFFF" 216 | } 217 | ] 218 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-4287.jade: -------------------------------------------------------------------------------- 1 | .ssdsd 2 | 3 | // asdsdas -------------------------------------------------------------------------------- /test-cases/themes/tests/test-4287.jade.result: -------------------------------------------------------------------------------- 1 | { 2 | "abyss": [ 3 | { 4 | "content": ".ssdsd", 5 | "color": "#F280D0" 6 | }, 7 | { 8 | "content": " // asdsdas", 9 | "color": "#22AA44" 10 | } 11 | ], 12 | "dark_vs": [ 13 | { 14 | "content": ".ssdsd", 15 | "color": "#569CD6" 16 | }, 17 | { 18 | "content": " // asdsdas", 19 | "color": "#CE9178" 20 | } 21 | ], 22 | "light_vs": [ 23 | { 24 | "content": ".ssdsd", 25 | "color": "#0000FF" 26 | }, 27 | { 28 | "content": " // asdsdas", 29 | "color": "#0000FF" 30 | } 31 | ], 32 | "hc_black": [ 33 | { 34 | "content": ".ssdsd", 35 | "color": "#569CD6" 36 | }, 37 | { 38 | "content": " // asdsdas", 39 | "color": "#CE9178" 40 | } 41 | ], 42 | "dark_plus": [ 43 | { 44 | "content": ".ssdsd", 45 | "color": "#569CD6" 46 | }, 47 | { 48 | "content": " // asdsdas", 49 | "color": "#CE9178" 50 | } 51 | ], 52 | "light_plus": [ 53 | { 54 | "content": ".ssdsd", 55 | "color": "#0000FF" 56 | }, 57 | { 58 | "content": " // asdsdas", 59 | "color": "#0000FF" 60 | } 61 | ], 62 | "kimbie_dark": [ 63 | { 64 | "content": ".ssdsd", 65 | "color": "#F79A32" 66 | }, 67 | { 68 | "content": " // asdsdas", 69 | "color": "#889B4A" 70 | } 71 | ], 72 | "monokai": [ 73 | { 74 | "content": ".ssdsd", 75 | "color": "#AE81FF" 76 | }, 77 | { 78 | "content": " // asdsdas", 79 | "color": "#E6DB74" 80 | } 81 | ], 82 | "monokai_dimmed": [ 83 | { 84 | "content": ".ssdsd", 85 | "color": "#FF0080" 86 | }, 87 | { 88 | "content": " // asdsdas", 89 | "color": "#9AA83A" 90 | } 91 | ], 92 | "quietlight": [ 93 | { 94 | "content": ".ssdsd", 95 | "color": "#AB6526" 96 | }, 97 | { 98 | "content": " // asdsdas", 99 | "color": "#448C27" 100 | } 101 | ], 102 | "red": [ 103 | { 104 | "content": ".ssdsd", 105 | "color": "#994646FF" 106 | }, 107 | { 108 | "content": " // asdsdas", 109 | "color": "#CD8D8DFF" 110 | } 111 | ], 112 | "solarized_dark": [ 113 | { 114 | "content": ".ssdsd", 115 | "color": "#B58900" 116 | }, 117 | { 118 | "content": " // asdsdas", 119 | "color": "#2AA198" 120 | } 121 | ], 122 | "solarized_light": [ 123 | { 124 | "content": ".ssdsd", 125 | "color": "#B58900" 126 | }, 127 | { 128 | "content": " // asdsdas", 129 | "color": "#2AA198" 130 | } 131 | ], 132 | "tomorrow_night_blue": [ 133 | { 134 | "content": ".ssdsd", 135 | "color": "#FFC58F" 136 | }, 137 | { 138 | "content": " // asdsdas", 139 | "color": "#D1F1A9" 140 | } 141 | ] 142 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-6611.rs: -------------------------------------------------------------------------------- 1 | impl Foo 2 | where A: B 3 | { } 4 | 5 | impl Foo for C 6 | where A: B 7 | { } 8 | 9 | impl Foo for C 10 | { 11 | fn foo -> C 12 | where A: B 13 | { } 14 | } 15 | 16 | fn foo -> C 17 | where A: B 18 | { } 19 | 20 | struct Foo 21 | where A: B 22 | { } 23 | 24 | trait Foo : C 25 | where A: B 26 | { } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-7115.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test-brackets.tsx: -------------------------------------------------------------------------------- 1 | let a = Array(); // Highlight ok here 2 | 3 | interface egGenericsInArray { 4 | a: Array; 5 | } 6 | let s = "nothing should fail here..."; -------------------------------------------------------------------------------- /test-cases/themes/tests/test-cssvariables.less: -------------------------------------------------------------------------------- 1 | :root { 2 | --spacing-unit: 6px; 3 | --cell-padding: (4 * var(--spacing-unit)); 4 | } 5 | body { 6 | padding-left: calc(4 * var(--spacing-unit, 5px)); 7 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-cssvariables.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --spacing-unit: 6px; 3 | --cell-padding: (4 * var(--spacing-unit)); 4 | } 5 | body { 6 | padding-left: calc(4 * var(--spacing-unit, 5px)); 7 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-function-inv.ts: -------------------------------------------------------------------------------- 1 | rowData.push(callback(new Cell(row, col, false))); -------------------------------------------------------------------------------- /test-cases/themes/tests/test-issue11.ts: -------------------------------------------------------------------------------- 1 | let keyCode = 0; 2 | if(!(keyCode === 8 || (keyCode>=48 && keyCode<=57))) {} 3 | for (let i=0; i<5; i++) {} 4 | for (var i=0; i<5; i++) {} 5 | for (let i=0; i<5; i++) {} 6 | for (; i<5;) {} 7 | for (let i=0; 1+( i<<5 ) < 5;i++) {} 8 | var p = 1?2:(3<4?5:6); 9 | class A { } 10 | class A1 string }> { } 11 | class B { } 12 | class C { } 13 | function foo() { return 1;} 14 | let x1: A<(param?: number) => void, B>; 15 | let x2: A; 16 | const t = 1 < (5 > 10 ? 1 : 2); 17 | var f6 = 1 < foo(); -------------------------------------------------------------------------------- /test-cases/themes/tests/test-issue5431.ts: -------------------------------------------------------------------------------- 1 | function foo(isAll, startTime, endTime) { 2 | const timeRange = isAll ? '所有时间' : `${startTime} - ${endTime}`; 3 | return true; 4 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-issue5465.ts: -------------------------------------------------------------------------------- 1 | function* foo2() { 2 | yield 'bar'; 3 | yield* ['bar']; 4 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-issue5566.ts: -------------------------------------------------------------------------------- 1 | function foo3() { 2 | const foo = (): any => ({ 'bar': 'baz' }) 3 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-keywords.ts: -------------------------------------------------------------------------------- 1 | export var foo = () => new RegExp(''); 2 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test-members.ts: -------------------------------------------------------------------------------- 1 | class A2 { 2 | public count: number = 9; 3 | public resolveNextGeneration(cell : A2) { 4 | } 5 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-object-literals.ts: -------------------------------------------------------------------------------- 1 | let s1 = { 2 | k: { 3 | k1: s, 4 | k2: 1 5 | } 6 | }; -------------------------------------------------------------------------------- /test-cases/themes/tests/test-regex.coffee: -------------------------------------------------------------------------------- 1 | regex = /Hello (\d+) #{user}/g 2 | 2 / 3 3 | 2/3 4 | 5 | a = b/c + d/g 6 | someOtherStuff 7 | 8 | name="hello" 9 | test=/// #{name} 10 | 11 | fancyRegExp = /// 12 | (\d+) # numbers 13 | (\w*) # letters 14 | $ # the end 15 | /// -------------------------------------------------------------------------------- /test-cases/themes/tests/test-strings.ts: -------------------------------------------------------------------------------- 1 | var x = `Hello ${foo}!`; 2 | console.log(`string text line 1 3 | string text line 2`); 4 | x = tag`Hello ${ a + b } world ${ a * b }`; -------------------------------------------------------------------------------- /test-cases/themes/tests/test-this.ts: -------------------------------------------------------------------------------- 1 | { 2 | this.foo = 9; 3 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test-variables.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --spacing-unit: 6px; 3 | --cell-padding: (4 * var(--spacing-unit)); 4 | } 5 | body { 6 | padding-left: calc(4 * var(--spacing-unit, 5px)); 7 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal 3 | 4 | title VSCode Dev 5 | 6 | pushd %~dp0\.. 7 | 8 | :: Node modules 9 | if not exist node_modules call .\scripts\npm.bat install 10 | 11 | :: Get electron 12 | node .\node_modules\gulp\bin\gulp.js electron 13 | 14 | :: Build 15 | if not exist out node .\node_modules\gulp\bin\gulp.js compile 16 | 17 | :: Configuration 18 | set NODE_ENV=development 19 | set VSCODE_DEV=1 20 | set ELECTRON_DEFAULT_ERROR_MODE=1 21 | set ELECTRON_ENABLE_LOGGING=1 22 | set ELECTRON_ENABLE_STACK_DUMPING=1 23 | 24 | :: Launch Code 25 | .\.build\electron\electron.exe . %* 26 | popd 27 | 28 | endlocal -------------------------------------------------------------------------------- /test-cases/themes/tests/test.c: -------------------------------------------------------------------------------- 1 | /* C Program to find roots of a quadratic equation when coefficients are entered by user. */ 2 | /* Library function sqrt() computes the square root. */ 3 | 4 | #include 5 | #include /* This is needed to use sqrt() function.*/ 6 | int main() 7 | { 8 | float a, b, c, determinant, r1,r2, real, imag; 9 | printf("Enter coefficients a, b and c: "); 10 | scanf("%f%f%f",&a,&b,&c); 11 | determinant=b*b-4*a*c; 12 | if (determinant>0) 13 | { 14 | r1= (-b+sqrt(determinant))/(2*a); 15 | r2= (-b-sqrt(determinant))/(2*a); 16 | printf("Roots are: %.2f and %.2f",r1 , r2); 17 | } 18 | else if (determinant==0) 19 | { 20 | r1 = r2 = -b/(2*a); 21 | printf("Roots are: %.2f and %.2f", r1, r2); 22 | } 23 | else 24 | { 25 | real= -b/(2*a); 26 | imag = sqrt(-determinant)/(2*a); 27 | printf("Roots are: %.2f+%.2fi and %.2f-%.2fi", real, imag, real, imag); 28 | } 29 | return 0; 30 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.cc: -------------------------------------------------------------------------------- 1 | #if B4G_DEBUG_CHECK 2 | fprintf(stderr,"num_candidate_ret=%d:", num_candidate); 3 | for(int i=0;i o(new O); 14 | // sadness. 15 | 16 | sprintf(options, "STYLE=Keramik;TITLE=%s;THEME=%s", ...); 17 | } 18 | 19 | 20 | int main2() { 21 | printf(";"); 22 | // the rest of 23 | asm("movw $0x38, %ax; ltr %ax"); 24 | fn("{};"); 25 | 26 | // the rest of 27 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.clj: -------------------------------------------------------------------------------- 1 | ;; from http://clojure-doc.org/articles/tutorials/introduction.html 2 | 3 | (require '[clojure.string :as str]) 4 | (def the-answer 42) 5 | [1 2 3] ; A vector 6 | [1 :two "three"] 7 | {:a 1 :b 2} 8 | #{:a :b :c} 9 | '(1 2 3) 10 | (def my-stuff ["shirt" "coat" "hat"]) ; this is more typical usage. 11 | 12 | (my-func (my-func2 arg1 13 | arg2) 14 | (other-func arg-a 15 | (foo-bar arg-x 16 | arg-y 17 | (+ arg-xx 18 | arg-yy 19 | arg-zz)) 20 | arg-b)) 21 | '(+ 1 2 3) 22 | ;; ⇒ (+ 1 2 3) 23 | (let [width 10 24 | height 20 25 | thickness 2] 26 | (println "hello from inside the `let`.") 27 | (* width 28 | height 29 | thickness)) 30 | 31 | ;; Vectors 32 | (def v [:a :b :c]) 33 | (def li '(:a :b :c)) 34 | (conj v :d) ; ⇒ [:a :b :c :d] 35 | (conj li :d) ; ⇒ (:d :a :b :c) 36 | 37 | v ; ⇒ is still [:a :b :c] 38 | li ; ⇒ is still (:a :b :c) 39 | 40 | ;; Maps 41 | (def m {:a 1 :b 2}) 42 | (assoc m :c 3) ; ⇒ {:a 1 :c 3 :b 2} 43 | (dissoc m :b) ; ⇒ {:a 1} 44 | 45 | (def my-atom (atom {:foo 1})) 46 | ;; ⇒ #'user/my-atom 47 | @my-atom 48 | ;; ⇒ {:foo 1} 49 | (swap! my-atom update-in [:foo] inc) 50 | ;; ⇒ {:foo 2} 51 | @my-atom 52 | ;; ⇒ {:foo 2} -------------------------------------------------------------------------------- /test-cases/themes/tests/test.coffee: -------------------------------------------------------------------------------- 1 | """ 2 | A CoffeeScript sample. 3 | """ 4 | 5 | class Vehicle 6 | constructor: (@name) => 7 | 8 | drive: () => 9 | alert "Drive #{@name}" 10 | 11 | class Car extends Vehicle 12 | drive: () => 13 | alert "Driving #{@name}" 14 | 15 | c = new Car "Volvo" 16 | 17 | while onTheRoad() 18 | c.drive() 19 | 20 | vehicles = (new Car for i in [1..100]) 21 | 22 | startRace = (vehicles) -> [vehicle.drive() for vehicle in vehicles] 23 | 24 | fancyRegExp = /// 25 | (\d+) # numbers 26 | (\w*) # letters 27 | $ # the end 28 | /// 29 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.cpp: -------------------------------------------------------------------------------- 1 | // classes example 2 | #include 3 | using namespace std; 4 | 5 | class Rectangle { 6 | int width, height; 7 | public: 8 | void set_values (int,int); 9 | int area() {return width*height;} 10 | }; 11 | 12 | void Rectangle::set_values (int x, int y) { 13 | width = x; 14 | height = y; 15 | } 16 | 17 | int main () { 18 | Rectangle rect; 19 | rect.set_values (3,4); 20 | cout << "area: " << rect.area(); 21 | return 0; 22 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.cshtml: -------------------------------------------------------------------------------- 1 | @{ 2 | var total = 0; 3 | var totalMessage = ""; 4 | @* a multiline 5 | razor comment embedded in csharp *@ 6 | if (IsPost) { 7 | 8 | // Retrieve the numbers that the user entered. 9 | var num1 = Request["text1"]; 10 | var num2 = Request["text2"]; 11 | 12 | // Convert the entered strings into integers numbers and add. 13 | total = num1.AsInt() + num2.AsInt(); 14 | totalMessage = "Total = " + total; 15 | } 16 | } 17 | 18 | 19 | 20 | 21 | Add Numbers 22 | 23 | 24 | 25 |

Enter two whole numbers and then click Add.

26 |
27 |

28 | 29 |

30 |

31 | 32 |

33 |

34 |
35 | 36 | @* now we call the totalMessage method 37 | (a multi line razor comment outside code) *@ 38 | 39 |

@totalMessage

40 | 41 |

@(totalMessage+"!")

42 | 43 | An email address (with escaped at character): name@@domain.com 44 | 45 | 46 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.css: -------------------------------------------------------------------------------- 1 | /* css Zen Garden default style v1.02 */ 2 | /* css released under Creative Commons License - http://creativecommons.org/licenses/by-nc-sa/1.0/ */ 3 | /* This file based on 'Tranquille' by Dave Shea */ 4 | /* You may use this file as a foundation for any new work, but you may find it easier to start from scratch. */ 5 | /* Not all elements are defined in this file, so you'll most likely want to refer to the xhtml as well. */ 6 | /* Your images should be linked as if the CSS file sits in the same folder as the images. ie. no paths. */ 7 | /* basic elements */ 8 | 9 | @import "mystyle.css"; 10 | @import url("mystyle.css"); 11 | @import url("bluish.css") projection, tv; 12 | 13 | .html { 14 | padding: 0; 15 | font-style: 0; 16 | } 17 | body { 18 | font: 75% georgia, sans-serif; 19 | line-height: 1.88889; 20 | color: #555753; 21 | background: #fff url(blossoms.jpg) no-repeat bottom right; 22 | margin: 0; 23 | padding: 0; 24 | background-image: -webkit-linear-gradient(top, start-color, end-color); 25 | background-image: -webkit-gradient(linear, left top, left bottom, from(start-color), to(end-color)); 26 | background-image: -moz-linear-gradient(top, start-color, end-color); 27 | background-image: linear-gradient(to bottom, start-color, end-color); 28 | } 29 | 30 | p { 31 | margin-top: 0; 32 | text-align: justify; 33 | } 34 | 35 | h3 { 36 | font: italic normal 1.4em georgia, sans-serif; 37 | letter-spacing: 1px; 38 | margin-bottom: 0; 39 | color: #7D775C; 40 | } 41 | 42 | a:link { 43 | font-weight: bold; 44 | text-decoration: none; 45 | color: #B7A5DF; 46 | } 47 | 48 | a:visited { 49 | font-weight: bold; 50 | text-decoration: none; 51 | color: #D4CDDC; 52 | cursor: pointer; 53 | } 54 | 55 | a:hover, 56 | a:focus, 57 | a:active { 58 | text-decoration: underline; 59 | color: #9685BA; 60 | } 61 | 62 | abbr { 63 | border-bottom: none; 64 | } 65 | 66 | 67 | /* specific divs */ 68 | 69 | .page-wrapper { 70 | background: url(zen-bg.jpg) no-repeat top left; 71 | padding: 0 175px 0 110px; 72 | margin: 0; 73 | position: relative; 74 | } 75 | 76 | .intro { 77 | min-width: 470px; 78 | width: 100%; 79 | } 80 | 81 | header h1 { 82 | background: transparent url(h1.gif) no-repeat top left; 83 | margin-top: 10px; 84 | display: block; 85 | width: 219px; 86 | height: 87px; 87 | float: left; 88 | text-indent: 100%; 89 | white-space: nowrap; 90 | overflow: hidden; 91 | } 92 | 93 | header { 94 | padding-top: 20px; 95 | height: 87px; 96 | } 97 | 98 | .summary { 99 | clear: both; 100 | margin: 20px 20px 20px 10px; 101 | width: 160px; 102 | float: left; 103 | } 104 | 105 | .summary p { 106 | font: italic 1.1em/2.2 georgia; 107 | text-align: center; 108 | } 109 | 110 | .preamble { 111 | clear: right; 112 | padding: 0px 10px 0 10px; 113 | } 114 | 115 | .supporting { 116 | padding-left: 10px; 117 | margin-bottom: 40px; 118 | } 119 | 120 | #footer { 121 | text-align: center 122 | } 123 | 124 | footer a:link, 125 | footer a:visited { 126 | margin-right: 20px; 127 | } 128 | 129 | .sidebar { 130 | margin-left: 600px; 131 | position: absolute; 132 | top: 0; 133 | right: 0; 134 | } 135 | 136 | .sidebar .wrapper { 137 | font: 10px verdana, sans-serif; 138 | background: transparent url(paper-bg.jpg) top left repeat-y; 139 | padding: 10px; 140 | margin-top: 150px; 141 | width: 130px; 142 | } 143 | 144 | .sidebar li a:link { 145 | color: #988F5E; 146 | } 147 | 148 | .sidebar li a:visited { 149 | color: '#B3AE94'; 150 | } 151 | 152 | .extra1 { 153 | background: transparent url(cr2.gif) top left no-repeat; 154 | position: absolute; 155 | top: 40px; 156 | right: 0; 157 | width: 148px; 158 | height: 110px; 159 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.diff: -------------------------------------------------------------------------------- 1 | --- lao Sat Jan 26 23:30:39 1991 2 | +++ tzu Sat Jan 26 23:30:50 1991 3 | @@ -1,7 +1,6 @@ 4 | -The Way that can be told of is not the eternal Way; 5 | -The name that can be named is not the eternal name. 6 | The Nameless is the origin of Heaven and Earth; 7 | -The Named is the mother of all things. 8 | +The named is the mother of all things. 9 | + 10 | Therefore let there always be non-being, 11 | so we may see their subtlety, 12 | And let there always be being, 13 | @@ -9,3 +8,6 @@ 14 | The two are the same, 15 | But after they are produced, 16 | they have different names. 17 | +They both may be called deep and profound. 18 | +Deeper and more profound, 19 | +The door of all subtleties! -------------------------------------------------------------------------------- /test-cases/themes/tests/test.fs: -------------------------------------------------------------------------------- 1 | // from https://msdn.microsoft.com/en-us/library/dd233160.aspx 2 | 3 | // The declaration creates a constructor that takes two values, name and age. 4 | type Person(name:string, age:int) = 5 | let mutable internalAge = age 6 | 7 | new(name:string) = Person(name, 0) 8 | 9 | member this.Name = name 10 | // A read/write property. 11 | member this.Age 12 | with get() = internalAge 13 | and set(value) = internalAge <- value 14 | 15 | member this.HasABirthday () = internalAge <- internalAge + 1 16 | member this.IsOfAge targetAge = internalAge >= targetAge 17 | override this.ToString () = 18 | "Name: " + name + "\n" + "Age: " + (string)internalAge -------------------------------------------------------------------------------- /test-cases/themes/tests/test.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/base64" 5 | "fmt" 6 | ) 7 | 8 | func main() { 9 | dnsName := "test-vm-from-go" 10 | storageAccount := "mystorageaccount" 11 | 12 | client, err := management.ClientFromPublishSettingsFile("path/to/downloaded.publishsettings", "") 13 | if err != nil { 14 | panic(err) 15 | } 16 | 17 | // create virtual machine 18 | role := vmutils.NewVMConfiguration(dnsName, vmSize) 19 | vmutils.ConfigureDeploymentFromPlatformImage( 20 | &role, 21 | vmImage, 22 | fmt.Sprintf("http://%s.blob.core.windows.net/sdktest/%s.vhd", storageAccount, dnsName), 23 | "") 24 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.groovy: -------------------------------------------------------------------------------- 1 | 2 | // Hello World 3 | println "Hello world!" 4 | 5 | /* 6 | Variables: 7 | 8 | You can assign values to variables for later use 9 | */ 10 | 11 | def x = 1 12 | println x 13 | 14 | x = new java.util.Date() 15 | println x 16 | 17 | x = -3.1499392 18 | println x 19 | 20 | x = false 21 | println x 22 | 23 | x = "Groovy!" 24 | println x 25 | 26 | /* 27 | Collections and maps 28 | */ 29 | 30 | //Creating an empty list 31 | def technologies = [] 32 | 33 | /*** Adding a elements to the list ***/ 34 | 35 | // As with Java 36 | technologies.add("Grails") 37 | 38 | // Left shift adds, and returns the list 39 | technologies << "Groovy" 40 | 41 | // Add multiple elements 42 | technologies.addAll(["Gradle","Griffon"]) 43 | 44 | /*** Removing elements from the list ***/ 45 | 46 | // As with Java 47 | technologies.remove("Griffon") 48 | 49 | // Subtraction works also 50 | technologies = technologies - 'Grails' 51 | 52 | /*** Iterating Lists ***/ 53 | 54 | // Iterate over elements of a list 55 | technologies.each { println "Technology: $it"} 56 | technologies.eachWithIndex { it, i -> println "$i: $it"} 57 | 58 | /*** Checking List contents ***/ 59 | 60 | //Evaluate if a list contains element(s) (boolean) 61 | contained = technologies.contains( 'Groovy' ) 62 | 63 | // Or 64 | contained = 'Groovy' in technologies 65 | 66 | // To sort without mutating original, you can do: 67 | sortedTechnologies = technologies.sort( false ) 68 | 69 | 70 | //Replace all elements in the list 71 | Collections.replaceAll(technologies, 'Gradle', 'gradle') 72 | 73 | //Shuffle a list 74 | Collections.shuffle(technologies, new Random()) 75 | 76 | //Clear a list 77 | technologies.clear() 78 | 79 | //Creating an empty map 80 | def devMap = [:] 81 | 82 | //Add values 83 | devMap = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy'] 84 | devMap.put('lastName','Perez') 85 | 86 | //Iterate over elements of a map 87 | devMap.each { println "$it.key: $it.value" } 88 | devMap.eachWithIndex { it, i -> println "$i: $it"} 89 | 90 | //Evaluate if a map contains a key 91 | assert devMap.containsKey('name') 92 | 93 | //Get the keys of a map 94 | println devMap.keySet() 95 | 96 | class Foo { 97 | // read only property 98 | final String name = "Roberto" 99 | 100 | // read only property with public getter and protected setter 101 | String language 102 | protected void setLanguage(String language) { this.language = language } 103 | 104 | // dynamically typed property 105 | def lastName 106 | } 107 | 108 | /* 109 | Logical Branching and Looping 110 | */ 111 | 112 | //Groovy supports the usual if - else syntax 113 | def x = 3 114 | 115 | if(x==1) { 116 | println "One" 117 | } else if(x==2) { 118 | println "Two" 119 | } else { 120 | println "X greater than Two" 121 | } 122 | 123 | //Groovy also supports the ternary operator: 124 | def y = 10 125 | def x = (y > 1) ? "worked" : "failed" 126 | assert x == "worked" 127 | 128 | //Groovy supports 'The Elvis Operator' too! 129 | //Instead of using the ternary operator: 130 | 131 | displayName = user.name ? user.name : 'Anonymous' 132 | 133 | //We can write it: 134 | displayName = user.name ?: 'Anonymous' 135 | 136 | //For loop 137 | //Iterate over a range 138 | def x = 0 139 | for (i in 0 .. 30) { 140 | x += i 141 | } 142 | 143 | //Iterate over a list 144 | x = 0 145 | for( i in [5,3,2,1] ) { 146 | x += i 147 | } 148 | 149 | //Iterate over an array 150 | array = (0..20).toArray() 151 | x = 0 152 | for (i in array) { 153 | x += i 154 | } 155 | 156 | //Iterate over a map 157 | def map = ['name':'Roberto', 'framework':'Grails', 'language':'Groovy'] 158 | x = 0 159 | for ( e in map ) { 160 | x += e.value 161 | } 162 | 163 | def technologies = ['Groovy','Grails','Gradle'] 164 | technologies*.toUpperCase() // = to technologies.collect { it?.toUpperCase() } 165 | 166 | def user = User.get(1) 167 | def username = user?.username 168 | 169 | def clos = { println "Hello World!" } 170 | 171 | def sum = { a, b -> println a+b } 172 | sum(2,4) 173 | 174 | def x = 5 175 | def multiplyBy = { num -> num * x } 176 | println multiplyBy(10) 177 | 178 | def clos = { print it } 179 | clos( "hi" ) 180 | 181 | def cl = {a, b -> 182 | sleep(3000) // simulate some time consuming processing 183 | a + b 184 | } 185 | 186 | mem = cl.memoize() 187 | 188 | def callClosure(a, b) { 189 | def start = System.currentTimeMillis() 190 | mem(a, b) 191 | println "Inputs(a = $a, b = $b) - took ${System.currentTimeMillis() - start} msecs." 192 | } 193 | 194 | callClosure(1, 2) 195 | 196 | //Another example: 197 | import groovy.transform.TypeChecked 198 | 199 | @TypeChecked 200 | Integer test() { 201 | Integer num = "1" 202 | 203 | Integer[] numbers = [1,2,3,4] 204 | 205 | Date date = numbers[1] 206 | 207 | return "Test" 208 | 209 | } 210 | 211 | //CompileStatic example: 212 | import groovy.transform.CompileStatic 213 | 214 | @CompileStatic 215 | int sum(int x, int y) { 216 | x + y 217 | } 218 | 219 | assert sum(2,5) == 7 220 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.handlebars: -------------------------------------------------------------------------------- 1 |
2 |

{{title}}

3 | {{#if author}} 4 |

{{author.firstName}} {{author.lastName}}

5 | {{else}} 6 |

Unknown Author

7 | {{/if}} 8 | {{contentBody}} 9 |
10 | 11 | {{#unless license}} 12 |

WARNING: This entry does not have a license!

13 | {{/unless}} 14 | 15 |
16 |
    17 | {{#each footnotes}} 18 |
  • {{this}}
  • 19 | {{/each}} 20 |
21 |
22 | 23 |

Comments

24 | 25 |
26 | {{#each comments}} 27 |

{{title}}

28 |
{{body}}
29 | {{/each}} 30 |
-------------------------------------------------------------------------------- /test-cases/themes/tests/test.hbs: -------------------------------------------------------------------------------- 1 |

Comments

2 | 3 |
4 | {{#each comments}} 5 |

{{title}}

6 |
{{body}}
7 | {{/each}} 8 |

{{./name}} or {{this/name}} or {{this.name}}

9 |
10 |
11 | {{!-- only output author name if an author exists --}} 12 | {{#if author}} 13 |

{{firstName}} {{lastName}}

14 | {{/if}} 15 |
16 |
17 | {{> userMessage tagName="h1" }} 18 | 19 |

Comments

20 | 21 | {{#each comments}} 22 | {{> userMessage tagName="h2" }} 23 | {{/each}} 24 |
-------------------------------------------------------------------------------- /test-cases/themes/tests/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | VSCode Tests 5 | 6 | 7 | 13 | 14 | 15 |
16 | 17 | 19 | 20 | 21 | 22 | 36 | 41 | 42 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.ini: -------------------------------------------------------------------------------- 1 | ; last modified 1 April 2001 by John Doe 2 | [owner] 3 | name=John Doe 4 | organization=Acme Widgets Inc. 5 | 6 | [database] 7 | ; use IP address in case network name resolution is not working 8 | server=192.0.2.62 9 | port=143 10 | file="payroll.dat" -------------------------------------------------------------------------------- /test-cases/themes/tests/test.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | var gulp = require('gulp'); 7 | var tsb = require('gulp-tsb'); 8 | var util = require('./lib/util'); 9 | var watcher = require('./lib/watch'); 10 | var assign = require('object-assign'); 11 | 12 | var compilation = tsb.create(assign({ verbose: true }, require('./tsconfig.json').compilerOptions)); 13 | 14 | gulp.task('compile', function() { 15 | return gulp.src('**/*.ts', { base: '.' }) 16 | .pipe(compilation()) 17 | .pipe(gulp.dest('')); 18 | }); 19 | 20 | gulp.task('watch', function() { 21 | var src = gulp.src('**/*.ts', { base: '.' }); 22 | 23 | return watcher('**/*.ts', { base: '.' }) 24 | .pipe(util.incremental(compilation, src)) 25 | .pipe(gulp.dest('')); 26 | }); 27 | 28 | gulp.task('default', ['compile']); 29 | 30 | function cloneArray(arr) { 31 | _.foo(); 32 | var r = []; 33 | for (var i = 0, len = arr.length; i < len; i++) { 34 | r[i] = doClone(arr[i]); 35 | } 36 | return r; 37 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.json: -------------------------------------------------------------------------------- 1 | { 2 | // a comment 3 | "options": { 4 | "myBool": true, 5 | "myInteger": 1, 6 | "myString": "String\u0056", 7 | "myNumber": 1.24, 8 | "myNull": null, 9 | "myArray": [ 1, "Hello", true, null, [], {}], 10 | "myObject" : { 11 | "foo": "bar" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.jsx: -------------------------------------------------------------------------------- 1 | var ToggleText = React.createClass({ 2 | getInitialState: function () { 3 | return { 4 | showDefault: true 5 | } 6 | }, 7 | 8 | toggle: function (e) { 9 | // Prevent following the link. 10 | e.preventDefault(); 11 | 12 | // Invert the chosen default. 13 | // This will trigger an intelligent re-render of the component. 14 | this.setState({ showDefault: !this.state.showDefault }) 15 | }, 16 | 17 | render: function () { 18 | // Default to the default message. 19 | var message = this.props.default; 20 | 21 | // If toggled, show the alternate message. 22 | if (!this.state.showDefault) { 23 | message = this.props.alt; 24 | } 25 | 26 | return ( 27 |
28 |

Hello {message}!

29 | Toggle 30 |
31 | ); 32 | } 33 | }); 34 | 35 | React.render(, document.body); -------------------------------------------------------------------------------- /test-cases/themes/tests/test.less: -------------------------------------------------------------------------------- 1 | @import "mystyle.css"; 2 | @import url("mystyle.css"); 3 | @import url("bluish.css") projection, tv; 4 | 5 | @base: #f938ab; 6 | 7 | .box-shadow(@style, @c) when (iscolor(@c)) { 8 | border-radius: @style @c; 9 | } 10 | 11 | .box-shadow(@style, @alpha: 50%) when (isnumber(@alpha)) { 12 | .box-shadow(@style, rgba(0, 0, 0, @alpha)); 13 | } 14 | 15 | .box { 16 | color: saturate(@base, 5%); 17 | border-color: lighten(@base, 30%); 18 | 19 | div { 20 | .box-shadow((0 0 5px), 30%); 21 | } 22 | } 23 | 24 | #header { 25 | h1 { 26 | font-size: 26px; 27 | font-weight: bold; 28 | } 29 | 30 | p { font-size: 12px; 31 | a { text-decoration: none; 32 | &:hover { border-width: 1px } 33 | } 34 | } 35 | } 36 | 37 | @the-border: 1px; 38 | @base-color: #111; 39 | @red: #842210; 40 | 41 | #header { 42 | color: (@base-color * 3); 43 | border-left: @the-border; 44 | border-right: (@the-border * 2); 45 | } 46 | 47 | #footer { 48 | color: (@base-color + #003300); 49 | border-color: desaturate(@red, 10%); 50 | } 51 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.lua: -------------------------------------------------------------------------------- 1 | -- defines a factorial function 2 | function fact (n) 3 | if n == 0 then 4 | return 1 5 | else 6 | return n * fact(n-1) 7 | end 8 | end 9 | 10 | print("enter a number:") 11 | a = io.read("*number") -- read a number 12 | print(fact(a)) -------------------------------------------------------------------------------- /test-cases/themes/tests/test.m: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (c) Microsoft Corporation. All rights reserved. 3 | // 4 | 5 | #import "UseQuotes.h" 6 | #import 7 | 8 | /* 9 | Multi 10 | Line 11 | Comments 12 | */ 13 | @implementation Test 14 | 15 | - (void) applicationWillFinishLaunching:(NSNotification *)notification 16 | { 17 | } 18 | 19 | - (IBAction)onSelectInput:(id)sender 20 | { 21 | NSString* defaultDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0]; 22 | 23 | NSOpenPanel* panel = [NSOpenPanel openPanel]; 24 | [panel setAllowedFileTypes:[[NSArray alloc] initWithObjects:@"ipa", @"xcarchive", @"app", nil]]; 25 | 26 | [panel beginWithCompletionHandler:^(NSInteger result) 27 | { 28 | if (result == NSFileHandlingPanelOKButton) 29 | [self.inputTextField setStringValue:[panel.URL path]]; 30 | }]; 31 | return YES; 32 | 33 | int hex = 0xFEF1F0F; 34 | float ing = 3.14; 35 | ing = 3.14e0; 36 | ing = 31.4e-2; 37 | } 38 | 39 | -(id) initWithParams:(id) aHandler withDeviceStateManager:(id) deviceStateManager 40 | { 41 | // add a tap gesture recognizer 42 | UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; 43 | NSMutableArray *gestureRecognizers = [NSMutableArray array]; 44 | [gestureRecognizers addObject:tapGesture]; 45 | [gestureRecognizers addObjectsFromArray:scnView.gestureRecognizers]; 46 | scnView.gestureRecognizers = gestureRecognizers; 47 | 48 | return tapGesture; 49 | return nil; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.md: -------------------------------------------------------------------------------- 1 | # Header 1 # 2 | ## Header 2 ## 3 | ### Header 3 ### (Hashes on right are optional) 4 | ## Markdown plus h2 with a custom ID ## {#id-goes-here} 5 | [Link back to H2](#id-goes-here) 6 | 7 | ### Alternate heading styles: 8 | Alternate Header 1 9 | ================== 10 | Alternate Header 2 11 | ------------------ 12 | 13 | 14 |
15 |
16 | nested div 17 |
18 | 21 | This is a div _with_ underscores 22 | and a & bold element. 23 | 26 |
27 | 28 | * Bullet lists are easy too 29 | - Another one 30 | + Another one 31 | 32 | This is a paragraph, which is text surrounded by 33 | whitespace. Paragraphs can be on one 34 | line (or many), and can drone on for hours. 35 | 36 | Now some inline markup like _italics_, **bold**, 37 | and `code()`. Note that underscores 38 | in_words_are ignored. 39 | 40 | ````application/json 41 | { value: ["or with a mime type"] } 42 | ```` 43 | 44 | > Blockquotes are like quoted text in email replies 45 | >> And, they can be nested 46 | 47 | 1. A numbered list 48 | 2. Which is numbered 49 | 3. With periods and a space 50 | 51 | And now some code: 52 | 53 | // Code is just text indented a bit 54 | which(is_easy) to_remember(); 55 | 56 | And a block 57 | 58 | ~~~ 59 | // Markdown extra adds un-indented code blocks too 60 | 61 | if (this_is_more_code == true && !indented) { 62 | // tild wrapped code blocks, also not indented 63 | } 64 | ~~~ 65 | 66 | Text with 67 | two trailing spaces 68 | (on the right) 69 | can be used 70 | for things like poems 71 | 72 | ### Horizontal rules 73 | 74 | * * * * 75 | **** 76 | -------------------------- 77 | 78 | ![picture alt](/images/photo.jpeg "Title is optional") 79 | 80 | ## Markdown plus tables ## 81 | 82 | | Header | Header | Right | 83 | | ------ | ------ | -----: | 84 | | Cell | Cell | $10 | 85 | | Cell | Cell | $20 | 86 | 87 | * Outer pipes on tables are optional 88 | * Colon used for alignment (right versus left) 89 | 90 | ## Markdown plus definition lists ## 91 | 92 | Bottled water 93 | : $ 1.25 94 | : $ 1.55 (Large) 95 | 96 | Milk 97 | Pop 98 | : $ 1.75 99 | 100 | * Multiple definitions and terms are possible 101 | * Definitions can include multiple paragraphs too 102 | 103 | *[ABBR]: Markdown plus abbreviations (produces an tag) -------------------------------------------------------------------------------- /test-cases/themes/tests/test.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | Example page 4 | 5 | 6 | 7 | 8 | "); 36 | 37 | // display shuffled cards (EXAMPLE ONLY) 38 | for ($index = 0; $index < 52; $index++) { 39 | if ($starting_point == 52) { $starting_point = 0; } 40 | print("Uncut Point: $deck[$index] "); 41 | $starting_point++; 42 | } 43 | ?> 44 | 45 | 46 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.pl: -------------------------------------------------------------------------------- 1 | use strict; 2 | 3 | my $badfound = 0; 4 | sub check_line { 5 | my($fn, $line) = @_; 6 | 7 | # Check for that =. 8 | if($line =~ /^\s*if\s*\(.*[^!<>=]=([^=].*\)|\))/) { 9 | if(!$badfound) { 10 | print("The following suspicious lines were found:\n"); 11 | $badfound = 1; 12 | } 13 | print "$fn:$.: $line\n"; 14 | } 15 | } 16 | 17 | # 18 | # This function opens and reads one file, and calls 19 | # check_line to analyze each line. Call it with the 20 | # file name. 21 | # 22 | sub check_file { 23 | my($fn) = @_; 24 | 25 | if(!open(IN, $fn)) { 26 | print "Cannot read $fn.\n"; 27 | return; 28 | } 29 | 30 | my($line); 31 | while($line = ) 32 | { 33 | chomp $line; 34 | check_line($fn,$line); 35 | } 36 | 37 | close IN; 38 | } 39 | 40 | # 41 | # Go through the argument list and check each file 42 | # 43 | while(my $fn = shift @ARGV) { 44 | check_file($fn); 45 | } 46 | if(!$badfound) { print "No suspicious lines were found.\n"; } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.ps1: -------------------------------------------------------------------------------- 1 | # Copyright Microsoft Corporation 2 | 3 | function Test-IsAdmin() { 4 | try { 5 | $identity = [Security.Principal.WindowsIdentity]::GetCurrent() 6 | $principal = New-Object Security.Principal.WindowsPrincipal -ArgumentList $identity 7 | return $principal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator ) 8 | } catch { 9 | throw "Failed to determine if the current user has elevated privileges. The error was: '{0}'." -f $_ 10 | } 11 | } 12 | 13 | function Invoke-Environment() 14 | { 15 | param 16 | ( 17 | [Parameter(Mandatory=1)][string]$Command 18 | ) 19 | 20 | foreach($_ in cmd /c "$Command 2>&1 & set") { 21 | if ($_ -match '^([^=]+)=(.*)') { 22 | [System.Environment]::SetEnvironmentVariable($matches[1], $matches[2]) 23 | } 24 | } 25 | } 26 | Write-Host -Object 'Initializing Azure PowerShell environment...'; 27 | 28 | # PowerShell commands need elevation for dependencies installation and running tests 29 | if (!(Test-IsAdmin)){ 30 | Write-Host -Object 'Please launch command under administrator account. It is needed for environment setting up and unit test.' -ForegroundColor Red; 31 | } 32 | 33 | $env:AzurePSRoot = Split-Path -Parent -Path $env:AzurePSRoot; 34 | 35 | if (Test-Path -Path "$env:ADXSDKProgramFiles\Microsoft Visual Studio 12.0") { 36 | $vsVersion="12.0" 37 | } else { 38 | $vsVersion="11.0" 39 | } 40 | 41 | $setVSEnv = '"{0}\Microsoft Visual Studio {1}\VC\vcvarsall.bat" x64' -f $env:ADXSDKProgramFiles, $vsVersion; 42 | 43 | Invoke-Environment -Command $setVSEnv; -------------------------------------------------------------------------------- /test-cases/themes/tests/test.py: -------------------------------------------------------------------------------- 1 | from banana import * 2 | 3 | class Monkey: 4 | # Bananas the monkey can eat. 5 | capacity = 10 6 | def eat(self, N): 7 | '''Make the monkey eat N bananas!''' 8 | capacity = capacity - N*banana.size 9 | 10 | def feeding_frenzy(self): 11 | eat(9.25) 12 | return "Yum yum" 13 | 14 | def some_func(a: 15 | lambda x=None: 16 | {key: val 17 | for key, val in 18 | (x if x is not None else []) 19 | }=42): 20 | pass 21 | 22 | if 1900 < year < 2100 and 1 <= month <= 12 \ 23 | and 1 <= day <= 31 and 0 <= hour < 24 \ 24 | and 0 <= minute < 60 and 0 <= second < 60: # Looks like a valid date 25 | return 1 26 | 27 | def firstn(g, n): 28 | for i in range(n): 29 | yield g.next() 30 | 31 | reduce(lambda x,y: x+y, [47,11,42,13]) 32 | woerter = {"house" : "Haus", "cat":"Katze", "black":"schwarz"} 33 | 34 | mydictionary = { 35 | 'foo': 23, #comment 36 | 'bar': "hello" #sqadsad 37 | } 38 | 39 | def steuern(einkommen): 40 | """Berechnung der zu zahlenden Steuern fuer ein zu versteuerndes Einkommen von x""" 41 | if einkommen <= 8004: 42 | steuer = 0 43 | elif einkommen <= 13469: 44 | y = (einkommen -8004.0)/10000.0 45 | steuer = (912.17 * y + 1400)*y 46 | else: 47 | steuer = einkommen * 0.44 - 15694 48 | return steuer 49 | 50 | def beliebig(x, y, *mehr): 51 | print "x=", x, ", x=", y 52 | print "mehr: ", mehr 53 | 54 | class Memoize: 55 | def __init__(self, fn): 56 | self.fn = fn 57 | self.memo = {} 58 | def __call__(self, *args): 59 | if args not in self.memo: 60 | self.memo[args] = self.fn(*args) 61 | return self.memo[args] 62 | 63 | res = re.search(r"([0-9-]*)\s*([A-Za-z]+),\s+(.*)", i) 64 | 65 | while True: 66 | try: 67 | n = raw_input("Number: ") 68 | n = int(n) 69 | break 70 | except ValueError: 71 | print("Not a number") 72 | 73 | async with EXPR as VAR: 74 | BLOCK 75 | 76 | # Comments in dictionary items should be colorized accordingly 77 | my_dictionary = { 78 | 'foo':23, # this should be colorized as comment 79 | 'bar':"foobar" #this should be colorized as comment 80 | } 81 | 82 | # test raw strings 83 | text = r""" 84 | interval ``[1,2)`` leads to 85 | """ 86 | highlight_error = True 87 | 88 | # highlight doctests 89 | r'''Module docstring 90 | 91 | Some text followed by code sample: 92 | >>> for a in foo(2, b=1, 93 | ... c=3): 94 | ... print(a) 95 | 0 96 | 1 97 | ''' 98 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.r: -------------------------------------------------------------------------------- 1 | # © Microsoft. All rights reserved. 2 | 3 | #' Add together two numbers. 4 | #' 5 | #' @param x A number. 6 | #' @param y A number. 7 | #' @return The sum of \code{x} and \code{y}. 8 | #' @examples 9 | #' add(1, 1) 10 | #' add(10, 1) 11 | add <- function(x, y) { 12 | x + y 13 | } 14 | 15 | add(1, -2, 2.0) 16 | add(1.0e10, 2.0e10) 17 | 18 | paste("one", NULL) 19 | paste(NA, 'two') 20 | 21 | paste("multi- 22 | line", 23 | 'multi- 24 | line') 25 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # Code generated by Microsoft (R) AutoRest Code Generator 0.16.0.0 3 | # Changes may cause incorrect behavior and will be lost if the code is 4 | # regenerated. 5 | 6 | module Azure::ARM::Scheduler 7 | # 8 | # A service client - single point of access to the REST API. 9 | # 10 | class SchedulerManagementClient < MsRestAzure::AzureServiceClient 11 | include Azure::ARM::Scheduler::Models 12 | include MsRestAzure 13 | 14 | # @return job_collections 15 | attr_reader :job_collections 16 | 17 | # 18 | # Creates initializes a new instance of the SchedulerManagementClient class. 19 | # @param credentials [MsRest::ServiceClientCredentials] credentials to authorize HTTP requests made by the service client. 20 | # @param base_url [String] the base URI of the service. 21 | # @param options [Array] filters to be applied to the HTTP requests. 22 | # 23 | def initialize(credentials, base_url = nil, options = nil) 24 | super(credentials, options) 25 | @base_url = base_url || 'https://management.azure.com' 26 | 27 | fail ArgumentError, 'credentials is nil' if credentials.nil? 28 | fail ArgumentError, 'invalid type of credentials input parameter' unless credentials.is_a?(MsRest::ServiceClientCredentials) 29 | @credentials = credentials 30 | 31 | @job_collections = JobCollections.new(self) 32 | @jobs = Jobs.new(self) 33 | @api_version = '2016-01-01' 34 | @long_running_operation_retry_timeout = 30 35 | @generate_client_request_id = true 36 | if MacOS.version >= :mavericks 37 | version = `#{MAVERICKS_PKG_PATH}/usr/bin/clang --version` 38 | else 39 | version = `/usr/bin/clang --version` 40 | end 41 | version = version[/clang-(\d+\.\d+\.\d+(\.\d+)?)/, 1] || "0" 42 | version < latest_version 43 | end 44 | 45 | end 46 | end -------------------------------------------------------------------------------- /test-cases/themes/tests/test.rs: -------------------------------------------------------------------------------- 1 | use std::io; 2 | 3 | fn main() { 4 | println!("Guess the number!"); 5 | 6 | println!("Please input your guess."); 7 | 8 | let mut guess = String::new(); 9 | 10 | io::stdin().read_line(&mut guess) 11 | .ok() 12 | .expect("Failed to read line"); 13 | 14 | println!("You guessed: {}", guess); 15 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | if [[ "$OSTYPE" == "darwin"* ]]; then 4 | realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; } 5 | ROOT=$(dirname $(dirname $(realpath "$0"))) 6 | else 7 | ROOT=$(dirname $(dirname $(readlink -f $0))) 8 | fi 9 | 10 | DEVELOPER=$(xcode-select -print-path) 11 | LIPO=$(xcrun -sdk iphoneos -find lipo) 12 | 13 | function code() { 14 | cd $ROOT 15 | 16 | # Node modules 17 | test -d node_modules || ./scripts/npm.sh install 18 | 19 | # Configuration 20 | export NODE_ENV=development 21 | 22 | # Launch Code 23 | if [[ "$OSTYPE" == "darwin"* ]]; then 24 | exec ./.build/electron/Electron.app/Contents/MacOS/Electron . "$@" 25 | else 26 | exec ./.build/electron/electron . "$@" 27 | fi 28 | } 29 | 30 | code "$@" 31 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.shader: -------------------------------------------------------------------------------- 1 | Shader "Example/Diffuse Simple" { 2 | SubShader { 3 | Tags { "RenderType" = "Opaque" } 4 | CGPROGRAM 5 | #pragma surface surf Lambert 6 | struct Input { 7 | float4 color : COLOR; 8 | }; 9 | void surf (Input IN, inout SurfaceOutput o) { 10 | o.Albedo = 1; 11 | } 12 | ENDCG 13 | } 14 | Fallback "Diffuse" 15 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.sql: -------------------------------------------------------------------------------- 1 | CREATE VIEW METRIC_STATS (ID, MONTH, TEMP_C, RAIN_C) AS 2 | SELECT ID, 3 | MONTH, 4 | (TEMP_F - 32) * 5 /9, 5 | RAIN_I * 0.3937 6 | FROM STATS; -------------------------------------------------------------------------------- /test-cases/themes/tests/test.swift: -------------------------------------------------------------------------------- 1 | var teamScore = 0 2 | var greeting = "Hello!" 3 | func hasAnyMatches(list: [Int], condition: (Int) -> Bool) -> Bool { 4 | for item in list { 5 | if condition(item) { 6 | return true 7 | } 8 | } 9 | return false 10 | } -------------------------------------------------------------------------------- /test-cases/themes/tests/test.ts: -------------------------------------------------------------------------------- 1 | /* Game of Life 2 | * Implemented in TypeScript 3 | * To learn more about TypeScript, please visit http://www.typescriptlang.org/ 4 | */ 5 | 6 | module Conway { 7 | 8 | export class Cell { 9 | public row: number; 10 | public col: number; 11 | public live: boolean; 12 | 13 | constructor(row: number, col: number, live: boolean) { 14 | this.row = row; 15 | this.col = col; 16 | this.live = live 17 | } 18 | } 19 | 20 | export class GameOfLife { 21 | private gridSize: number; 22 | private canvasSize: number; 23 | private lineColor: string; 24 | private liveColor: string; 25 | private deadColor: string; 26 | private initialLifeProbability: number; 27 | private animationRate: number; 28 | private cellSize: number; 29 | private world; 30 | 31 | 32 | constructor() { 33 | this.gridSize = 50; 34 | this.canvasSize = 600; 35 | this.lineColor = '#cdcdcd'; 36 | this.liveColor = '#666'; 37 | this.deadColor = '#eee'; 38 | this.initialLifeProbability = 0.5; 39 | this.animationRate = 60; 40 | this.cellSize = 0; 41 | this.world = this.createWorld(); 42 | this.circleOfLife(); 43 | } 44 | 45 | public createWorld() { 46 | return this.travelWorld( (cell : Cell) => { 47 | cell.live = Math.random() < this.initialLifeProbability; 48 | return cell; 49 | }); 50 | } 51 | 52 | public circleOfLife() : void { 53 | this.world = this.travelWorld( (cell: Cell) => { 54 | cell = this.world[cell.row][cell.col]; 55 | this.draw(cell); 56 | return this.resolveNextGeneration(cell); 57 | }); 58 | setTimeout( () => {this.circleOfLife()}, this.animationRate); 59 | } 60 | 61 | public resolveNextGeneration(cell : Cell) { 62 | var count = this.countNeighbors(cell); 63 | var newCell = new Cell(cell.row, cell.col, cell.live); 64 | if(count < 2 || count > 3) newCell.live = false; 65 | else if(count == 3) newCell.live = true; 66 | return newCell; 67 | } 68 | 69 | public countNeighbors(cell : Cell) { 70 | var neighbors = 0; 71 | for(var row = -1; row <=1; row++) { 72 | for(var col = -1; col <= 1; col++) { 73 | if(row == 0 && col == 0) continue; 74 | if(this.isAlive(cell.row + row, cell.col + col)) { 75 | neighbors++; 76 | } 77 | } 78 | } 79 | return neighbors; 80 | } 81 | 82 | public isAlive(row : number, col : number) { 83 | if(row < 0 || col < 0 || row >= this.gridSize || col >= this.gridSize) return false; 84 | return this.world[row][col].live; 85 | } 86 | 87 | public travelWorld(callback) { 88 | var result = []; 89 | for(var row = 0; row < this.gridSize; row++) { 90 | var rowData = []; 91 | for(var col = 0; col < this.gridSize; col++) { 92 | rowData.push(callback(new Cell(row, col, false))); 93 | } 94 | result.push(rowData); 95 | } 96 | return result; 97 | } 98 | 99 | public draw(cell : Cell) { 100 | if(this.cellSize == 0) this.cellSize = this.canvasSize/this.gridSize; 101 | 102 | this.context.strokeStyle = this.lineColor; 103 | this.context.strokeRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize); 104 | this.context.fillStyle = cell.live ? this.liveColor : this.deadColor; 105 | this.context.fillRect(cell.row * this.cellSize, cell.col*this.cellSize, this.cellSize, this.cellSize); 106 | } 107 | 108 | } 109 | } 110 | 111 | var game = new Conway.GameOfLife(); 112 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.vb: -------------------------------------------------------------------------------- 1 | ' Copyright (c) Microsoft Corporation. All rights reserved. 2 | 3 | Public Sub LongTask(ByVal Duration As Single, _ 4 | ByVal MinimumInterval As Single) 5 | Dim Threshold As Single 6 | Dim Start As Single 7 | Dim blnCancel As Boolean 8 | 9 | ' The Timer property of the DateAndTime object returns the seconds 10 | ' and milliseconds that have passed since midnight. 11 | Start = CSng(Timer) 12 | Threshold = MinimumInterval 13 | 14 | Do While CSng(Timer)< (Start + Duration) 15 | ' In a real application, some unit of work would 16 | ' be done here each time through the loop. 17 | If CSng(Timer)> (Start + Threshold) Then 18 | RaiseEvent PercentDone( _ 19 | Threshold / Duration, blnCancel) 20 | ' Check to see if the operation was canceled. 21 | If blnCancel Then Exit Sub 22 | Threshold = Threshold + MinimumInterval 23 | End If 24 | Loop 25 | End Sub -------------------------------------------------------------------------------- /test-cases/themes/tests/test.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | Lucy 13 | 1952-03-03 14 | bossy, crabby and selfish 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test-cases/themes/tests/test.yaml: -------------------------------------------------------------------------------- 1 | # sequencer protocols for Laser eye surgery 2 | --- 3 | - step: &id001 # defines anchor label &id001 4 | instrument: Lasik 2000 5 | pulseEnergy: 5.4 6 | spotSize: 1mm 7 | 8 | - step: *id001 # refers to the first step (with anchor &id001) 9 | - step: *id001 10 | spotSize: 2mm 11 | - step: *id002 12 | - {name: John Smith, age: 33} 13 | - name: Mary Smith 14 | age: 27 15 | men: [John Smith, Bill Jones] 16 | women: 17 | - Mary Smith 18 | - Susan Williams -------------------------------------------------------------------------------- /test-cases/themes/tests/test2.pl: -------------------------------------------------------------------------------- 1 | die("[$sheet->{label}] Unexpected sheet format.") unless ( 2 | $sheet->{"$date_col$row"} =~ /CALL_DATE/i && 3 | $sheet->{"$pixel_cols[4]$row"} =~ /Home_Bind_Count/i 4 | ); 5 | 6 | $row++; 7 | while ($row < $sheet->{maxrow}) { 8 | $row++; 9 | $total_lines++; 10 | 11 | my $date = $sheet->{"$date_col$row"}; 12 | next unless $date; 13 | (warning "Unexpected date format: '$date'"), next unless ($date =~ /^2\d\d\d-\d\d-\d\d$/); 14 | 15 | my $phone = trim($sheet->{"$phone_col$row"}); 16 | (warning "Unexpected phone format: '$phone'."), next unless ($phone =~ /^\d{10}$/); 17 | 18 | info $phone; 19 | next if ($date gt $date_to || $date lt $date_from); 20 | 21 | my @pixels = (0) x 5; 22 | for (1..4) { 23 | $pixels[$_] = trim($sheet->{"$pixel_cols[4]$row"}); 24 | (warning "Pixel $_ is not a number in the row # $row."), next unless looks_like_number($pixels[$_]); 25 | }; 26 | 27 | for (1..4) { 28 | add_phone_activity($date, $phone, "pixel-$_", $pixels[$_]) if $pixels[$_]; 29 | }; 30 | $parsed_lines++; 31 | }; -------------------------------------------------------------------------------- /test-cases/themes/tests/test6916.js: -------------------------------------------------------------------------------- 1 | for(var i=0;i<9;i++){for(var j;j