├── .nvmrc ├── .gitignore ├── images └── icon.png ├── Docs ├── settings.png ├── error-report.png ├── highlighting.png ├── notebook-output.png ├── themes │ ├── dark-theme.png │ └── light-theme.png ├── feature │ ├── hover-support.gif │ ├── open-config.png │ └── completion-support.gif ├── install │ └── install-extension.png ├── visualization │ ├── invert-theme.png │ └── graphics-scaling.png ├── compatibility.md ├── themes.md └── configuration-details.md ├── scripts ├── build ├── build.bat └── re_build.xml ├── src ├── media │ ├── wlsupplements.woff │ ├── reset.css │ └── render.css ├── test │ ├── tsconfig.json │ ├── suite │ │ ├── extension.test.ts │ │ ├── extension.test.js.map │ │ ├── extension.test.js │ │ ├── index.ts │ │ ├── index.js.map │ │ └── index.js │ ├── runTest.js.map │ ├── runTest.ts │ └── runTest.js ├── extension │ ├── tsconfig.json │ ├── notebook-config.ts │ ├── notebook-kernel.ts │ ├── serializer.ts │ ├── ui-items.ts │ ├── find-kernel.ts │ ├── extension.ts │ └── controller.ts ├── client │ ├── tsconfig.json │ ├── types.d.ts │ └── index.ts └── tsconfig-base.json ├── .vscodeignore ├── tsconfig.json ├── HowToBuild.md ├── wolfram.language-configuration.json ├── CONTRIBUTING.md ├── CHANGELOG.md ├── README.md ├── webpack.config.js ├── resources ├── render-html.wl └── init.wl ├── package.json ├── LICENSE └── themes ├── wolfram-Default.json ├── wolfram-dark-rainbow.json └── wolfram-dark.json /.nvmrc: -------------------------------------------------------------------------------- 1 | 22.11.0 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | 3 | dist 4 | 5 | .DS_Store 6 | 7 | node_modules 8 | -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/images/icon.png -------------------------------------------------------------------------------- /Docs/settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/settings.png -------------------------------------------------------------------------------- /scripts/build: -------------------------------------------------------------------------------- 1 | cd .. 2 | npm install -g vsce 3 | npm audit fix --force 4 | npm install 5 | vsce package -------------------------------------------------------------------------------- /Docs/error-report.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/error-report.png -------------------------------------------------------------------------------- /Docs/highlighting.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/highlighting.png -------------------------------------------------------------------------------- /Docs/notebook-output.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/notebook-output.png -------------------------------------------------------------------------------- /Docs/themes/dark-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/themes/dark-theme.png -------------------------------------------------------------------------------- /Docs/themes/light-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/themes/light-theme.png -------------------------------------------------------------------------------- /Docs/feature/hover-support.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/feature/hover-support.gif -------------------------------------------------------------------------------- /Docs/feature/open-config.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/feature/open-config.png -------------------------------------------------------------------------------- /src/media/wlsupplements.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/src/media/wlsupplements.woff -------------------------------------------------------------------------------- /Docs/feature/completion-support.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/feature/completion-support.gif -------------------------------------------------------------------------------- /Docs/install/install-extension.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/install/install-extension.png -------------------------------------------------------------------------------- /Docs/visualization/invert-theme.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/visualization/invert-theme.png -------------------------------------------------------------------------------- /Docs/visualization/graphics-scaling.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WolframResearch/vscode-wolfram/master/Docs/visualization/graphics-scaling.png -------------------------------------------------------------------------------- /scripts/build.bat: -------------------------------------------------------------------------------- 1 | cd .. 2 | 3 | call %RE_NODE_HOME%\npm install -g @vscode/vsce 4 | 5 | call %RE_NODE_HOME%\npm install 6 | 7 | call %RE_NODE_HOME%\vsce package 8 | -------------------------------------------------------------------------------- /Docs/compatibility.md: -------------------------------------------------------------------------------- 1 | 2 | # Compatibility 3 | 4 | 5 | ## WolframLanguageSyntax Compatibility 6 | 7 | Only the latest released version of Wolfram System is supported. 8 | -------------------------------------------------------------------------------- /src/test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | "rootDir": ".", 5 | "outDir": "../../out/test", 6 | }, 7 | "references": [] 8 | } 9 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | out/test/** 4 | src/** 5 | .gitignore 6 | .yarnrc 7 | .nvmrc 8 | vsc-extension-quickstart.md 9 | **/tsconfig.json 10 | **/.eslintrc.json 11 | **/*.map 12 | **/*.ts 13 | build/** 14 | scripts/** 15 | .vsix 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es2020", 5 | "lib": [ 6 | "es2020","dom" 7 | ], 8 | "outDir": "out", 9 | "sourceMap": true, 10 | "strict": true, 11 | }, 12 | "exclude": [ 13 | "node_modules", 14 | ".vscode-test" 15 | ] 16 | } -------------------------------------------------------------------------------- /src/extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | 2 | 3 | { 4 | "compilerOptions": { 5 | "module": "commonjs", 6 | "target": "es2020", 7 | "lib": [ 8 | "es2020" 9 | ], 10 | "outDir": "out", 11 | "sourceMap": true, 12 | "strict": true 13 | }, 14 | "exclude": [ 15 | "node_modules", 16 | ".vscode-test" 17 | ] 18 | } -------------------------------------------------------------------------------- /src/client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig-base.json", 3 | "compilerOptions": { 4 | // noEmit prevents the default tsc from building this--we use webpack instead 5 | "noEmit": true, 6 | "rootDir": ".", 7 | "module": "esnext", 8 | "lib": ["ES2019", "dom"], 9 | "types": ["webpack-env", "vscode-notebook-renderer"], 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.ts: -------------------------------------------------------------------------------- 1 | import * as assert from 'assert'; 2 | 3 | // You can import and use all API from the 'vscode' module 4 | // as well as import your extension to test it 5 | import * as vscode from 'vscode'; 6 | // import * as myExtension from '../extension'; 7 | 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | 11 | test('Sample test', () => { 12 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 13 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /src/test/runTest.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"runTest.js","sourceRoot":"","sources":["runTest.ts"],"names":[],"mappings":";;AAAA,6BAA6B;AAE7B,yDAAiD;AAEjD,KAAK,UAAU,IAAI;IACjB,IAAI;QACF,4DAA4D;QAC5D,yCAAyC;QACzC,MAAM,wBAAwB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;QAEnE,0BAA0B;QAC1B,iCAAiC;QACjC,MAAM,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;QAEpE,0DAA0D;QAC1D,MAAM,IAAA,wBAAQ,EAAC,EAAE,wBAAwB,EAAE,kBAAkB,EAAE,CAAC,CAAC;KAClE;IAAC,OAAO,GAAG,EAAE;QACZ,OAAO,CAAC,KAAK,CAAC,qBAAqB,EAAE,GAAG,CAAC,CAAC;QAC1C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACjB;AACH,CAAC;AAED,IAAI,EAAE,CAAC"} -------------------------------------------------------------------------------- /src/test/suite/extension.test.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"extension.test.js","sourceRoot":"","sources":["extension.test.ts"],"names":[],"mappings":";;AAAA,iCAAiC;AAEjC,0DAA0D;AAC1D,8CAA8C;AAC9C,iCAAiC;AACjC,+CAA+C;AAE/C,KAAK,CAAC,sBAAsB,EAAE,GAAG,EAAE;IACjC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAAC,kBAAkB,CAAC,CAAC;IAEzD,IAAI,CAAC,aAAa,EAAE,GAAG,EAAE;QACvB,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"} -------------------------------------------------------------------------------- /HowToBuild.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | npm must be installed on your system. Get npm from here: 4 | [Get npm](https://www.npmjs.com/get-npm) 5 | 6 | Make sure that you have installed the required tools: 7 | ``` 8 | npm install -g vsce 9 | ``` 10 | 11 | 12 | ## Building 13 | 14 | Here is an example transcript using the default npm and vsce to build VSCode-Wolfram: 15 | 16 | ``` 17 | npm install 18 | vsce package 19 | ``` 20 | 21 | The result is a `.vsix` file in the project directory. 22 | 23 | ## Installing 24 | 25 | You can install the built extension from command-line terminal in VsCode: 26 | ``` 27 | code --install-extension vsixFilePath 28 | ``` 29 | -------------------------------------------------------------------------------- /src/tsconfig-base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2020", 5 | "lib": [ 6 | "ES2020","dom" 7 | ], 8 | "types": ["node"], 9 | "moduleResolution": "node", 10 | "sourceMap": true, 11 | "strict": true /* enable all strict type-checking options */ 12 | /* Additional Checks */ 13 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 14 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 15 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/test/suite/extension.test.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const assert = require("assert"); 4 | // You can import and use all API from the 'vscode' module 5 | // as well as import your extension to test it 6 | const vscode = require("vscode"); 7 | // import * as myExtension from '../extension'; 8 | suite('Extension Test Suite', () => { 9 | vscode.window.showInformationMessage('Start all tests.'); 10 | test('Sample test', () => { 11 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 12 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 13 | }); 14 | }); 15 | //# sourceMappingURL=extension.test.js.map -------------------------------------------------------------------------------- /Docs/themes.md: -------------------------------------------------------------------------------- 1 | 2 | https://github.com/microsoft/vscode/wiki/Semantic-Highlighting-Overview 3 | 4 | 5 | Themes don't support background styling 6 | https://github.com/microsoft/vscode/issues/3429 7 | 8 | ## BrentonWL 9 | 10 | // { 11 | // // 12 | // // default color of Slot should be an error 13 | // // 14 | // "scope": ["keyword.other.Slot", "keyword.other.SlotSequence"], 15 | // "settings": { 16 | // "foreground": "#ff0000" 17 | // } 18 | // }, 19 | 20 | 21 | { 22 | "name": "Undocumented", 23 | "scope": "support.function.undocumented", 24 | "settings": { 25 | // 26 | // the idea is to make it almost the same as unrecognized 27 | // 28 | "foreground": "#eeeeee" 29 | } 30 | }, 31 | -------------------------------------------------------------------------------- /src/client/types.d.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Tianhuan Lu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | declare module "*.css" { 16 | const content: string; 17 | export default content; 18 | } 19 | -------------------------------------------------------------------------------- /src/test/runTest.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import { runTests } from '@vscode/test-electron'; 4 | 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | 11 | // The path to test runner 12 | // Passed to --extensionTestsPath 13 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 14 | 15 | // Download VS Code, unzip it and run the integration test 16 | await runTests({ extensionDevelopmentPath, extensionTestsPath }); 17 | } catch (err) { 18 | console.error('Failed to run tests', err); 19 | process.exit(1); 20 | } 21 | } 22 | 23 | main(); 24 | -------------------------------------------------------------------------------- /src/test/runTest.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | const path = require("path"); 4 | const test_electron_1 = require("@vscode/test-electron"); 5 | async function main() { 6 | try { 7 | // The folder containing the Extension Manifest package.json 8 | // Passed to `--extensionDevelopmentPath` 9 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 10 | // The path to test runner 11 | // Passed to --extensionTestsPath 12 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 13 | // Download VS Code, unzip it and run the integration test 14 | await (0, test_electron_1.runTests)({ extensionDevelopmentPath, extensionTestsPath }); 15 | } 16 | catch (err) { 17 | console.error('Failed to run tests', err); 18 | process.exit(1); 19 | } 20 | } 21 | main(); 22 | //# sourceMappingURL=runTest.js.map -------------------------------------------------------------------------------- /src/test/suite/index.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | import * as Mocha from 'mocha'; 3 | import * as glob from 'glob'; 4 | 5 | export function run(): Promise { 6 | // Create the mocha test 7 | const mocha = new Mocha({ 8 | ui: 'tdd', 9 | }); 10 | 11 | const testsRoot = path.resolve(__dirname, '..'); 12 | 13 | return new Promise((c, e) => { 14 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 15 | if (err) { 16 | return e(err); 17 | } 18 | 19 | // Add files to the test suite 20 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 21 | 22 | try { 23 | // Run the mocha test 24 | mocha.run(failures => { 25 | if (failures > 0) { 26 | e(new Error(`${failures} tests failed.`)); 27 | } else { 28 | c(); 29 | } 30 | }); 31 | } catch (err) { 32 | console.error(err); 33 | e(err); 34 | } 35 | }); 36 | }); 37 | } 38 | -------------------------------------------------------------------------------- /src/test/suite/index.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"file":"index.js","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":";;;AAAA,6BAA6B;AAC7B,+BAA+B;AAC/B,6BAA6B;AAE7B,SAAgB,GAAG;IACjB,wBAAwB;IACxB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC;QACtB,EAAE,EAAE,KAAK;KACV,CAAC,CAAC;IAEH,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEhD,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC1B,IAAI,CAAC,eAAe,EAAE,EAAE,GAAG,EAAE,SAAS,EAAE,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;YACvD,IAAI,GAAG,EAAE;gBACP,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC;aACf;YAED,8BAA8B;YAC9B,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YAE9D,IAAI;gBACF,qBAAqB;gBACrB,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE;oBACnB,IAAI,QAAQ,GAAG,CAAC,EAAE;wBAChB,CAAC,CAAC,IAAI,KAAK,CAAC,GAAG,QAAQ,gBAAgB,CAAC,CAAC,CAAC;qBAC3C;yBAAM;wBACL,CAAC,EAAE,CAAC;qBACL;gBACH,CAAC,CAAC,CAAC;aACJ;YAAC,OAAO,GAAG,EAAE;gBACZ,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBACnB,CAAC,CAAC,GAAG,CAAC,CAAC;aACR;QACH,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC;AAhCD,kBAgCC"} -------------------------------------------------------------------------------- /wolfram.language-configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | // symbol used for single line comment. Remove this entry if your language does not support line comments 4 | //"lineComment": "//", 5 | // symbols used for start and end a block comment. Remove this entry if your language does not support block comments 6 | "blockComment": [ "(*", "*)" ] 7 | }, 8 | // symbols used as brackets 9 | "brackets": [ 10 | ["{", "}"], 11 | ["[", "]"], 12 | ["(", ")"], 13 | ["<|", "|>"], 14 | ["(*", "*)"], 15 | ], 16 | // symbols that are auto closed when typing 17 | "autoClosingPairs": [ 18 | ["{", "}"], 19 | ["[", "]"], 20 | ["(", ")"], 21 | ["\"", "\""], 22 | ["<|", "|>"], 23 | ["(*", "*)"], 24 | ], 25 | // symbols that that can be used to surround a selection 26 | "surroundingPairs": [ 27 | ["{", "}"], 28 | ["[", "]"], 29 | ["(", ")"], 30 | ["\"", "\""], 31 | ["<|", "|>"], 32 | ["(*", "*)"], 33 | ] 34 | } -------------------------------------------------------------------------------- /src/media/reset.css: -------------------------------------------------------------------------------- 1 | html, body, div, span, applet, object, iframe, 2 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 3 | a, abbr, acronym, address, big, cite, code, 4 | del, dfn, em, img, ins, kbd, q, s, samp, 5 | small, strike, strong, sub, sup, tt, var, 6 | b, u, i, center, 7 | dl, dt, dd, ol, ul, li, 8 | fieldset, form, label, legend, 9 | table, caption, tbody, tfoot, thead, tr, th, td, 10 | article, aside, canvas, details, embed, 11 | figure, figcaption, footer, header, hgroup, 12 | menu, nav, output, ruby, section, summary, 13 | time, mark, audio, video { 14 | margin: 0; 15 | padding: 0; 16 | border: 0; 17 | vertical-align: baseline; 18 | } 19 | /* HTML5 display-role reset for older browsers */ 20 | article, aside, details, figcaption, figure, 21 | footer, header, hgroup, menu, nav, section { 22 | display: block; 23 | } 24 | body { 25 | line-height: 1; 26 | } 27 | ol, ul { 28 | list-style: none; 29 | } 30 | blockquote, q { 31 | quotes: none; 32 | } 33 | blockquote:before, blockquote:after, 34 | q:before, q:after { 35 | content: ''; 36 | content: none; 37 | } 38 | table { 39 | border-collapse: collapse; 40 | border-spacing: 0; 41 | } -------------------------------------------------------------------------------- /scripts/re_build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /src/test/suite/index.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | Object.defineProperty(exports, "__esModule", { value: true }); 3 | exports.run = void 0; 4 | const path = require("path"); 5 | const Mocha = require("mocha"); 6 | const glob = require("glob"); 7 | function run() { 8 | // Create the mocha test 9 | const mocha = new Mocha({ 10 | ui: 'tdd', 11 | }); 12 | const testsRoot = path.resolve(__dirname, '..'); 13 | return new Promise((c, e) => { 14 | glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { 15 | if (err) { 16 | return e(err); 17 | } 18 | // Add files to the test suite 19 | files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); 20 | try { 21 | // Run the mocha test 22 | mocha.run(failures => { 23 | if (failures > 0) { 24 | e(new Error(`${failures} tests failed.`)); 25 | } 26 | else { 27 | c(); 28 | } 29 | }); 30 | } 31 | catch (err) { 32 | console.error(err); 33 | e(err); 34 | } 35 | }); 36 | }); 37 | } 38 | exports.run = run; 39 | //# sourceMappingURL=index.js.map -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Wolfram® 2 | 3 | Thank you for taking the time to contribute to the [Wolfram Research](https://github.com/wolframresearch) repos on GitHub. 4 | 5 | ## Licensing of Contributions 6 | 7 | By contributing to Wolfram, you agree and affirm that: 8 | 9 | > Wolfram may release your contribution under the terms of the [MIT license](https://opensource.org/licenses/MIT); and 10 | 11 | > You have read and agreed to the [Developer Certificate of Origin](http://developercertificate.org/), version 1.1 or later. 12 | 13 | Please see [LICENSE](LICENSE) for licensing conditions pertaining 14 | to individual repositories. 15 | 16 | 17 | ## Bug reports 18 | 19 | ### Security Bugs 20 | 21 | Please **DO NOT** file a public issue regarding a security issue. 22 | Rather, send your report privately to security@wolfram.com. Security 23 | reports are appreciated and we will credit you for it. We do not offer 24 | a security bounty, but the forecast in your neighborhood will be cloudy 25 | with a chance of Wolfram schwag! 26 | 27 | ### General Bugs 28 | 29 | Please use the repository issues page to submit general bug issues. 30 | 31 | Please do not duplicate issues. 32 | 33 | Please do send a complete and well-written report to us. Note: **the 34 | thoroughness of your report will positively correlate to our willingness 35 | and ability to address it**. 36 | 37 | When reporting issues, always include: 38 | 39 | * Your version of *Mathematica*® or the Wolfram Language. 40 | * Your operating system. 41 | -------------------------------------------------------------------------------- /src/client/index.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Tianhuan Lu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | import errorOverlay from "vscode-notebook-error-overlay"; 17 | import type { ActivationFunction } from "vscode-notebook-renderer"; 18 | import "../media/reset.css"; 19 | import "../media/render.css"; 20 | 21 | // Fix the public path so that any async import()'s work as expected. 22 | declare const __webpack_relative_entrypoint_to_root__: string; 23 | declare const scriptUrl: string; 24 | 25 | __webpack_public_path__ = new URL(scriptUrl.replace(/[^/]+$/, '') + __webpack_relative_entrypoint_to_root__).toString(); 26 | 27 | export const activate: ActivationFunction = context => { 28 | 29 | let mutationObservers: { [key: string]: MutationObserver | undefined } = {}; 30 | 31 | return { 32 | renderOutputItem(data, element) { 33 | 34 | element.innerHTML=data.text(); 35 | 36 | 37 | }, 38 | disposeOutputItem(outputId) { 39 | if (typeof outputId === "string") { 40 | let observer = mutationObservers[outputId]; 41 | observer?.disconnect(); 42 | delete mutationObservers[outputId]; 43 | } else { 44 | Object.values(mutationObservers).forEach((observer) => 45 | observer?.disconnect() 46 | ); 47 | mutationObservers = {}; 48 | } 49 | }, 50 | }; 51 | }; 52 | 53 | 54 | -------------------------------------------------------------------------------- /src/extension/notebook-config.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Tianhuan Lu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import * as vscode from "vscode"; 16 | 17 | export class NotebookConfig { 18 | // private config: vscode.WorkspaceConfiguration; 19 | private disposables: any[] = []; 20 | 21 | 22 | constructor() { 23 | // this.config = vscode.workspace.getConfiguration(("wolfram", null)); 24 | } 25 | 26 | dispose() { 27 | this.disposables.forEach(item => { 28 | item.dispose(); 29 | }); 30 | } 31 | 32 | onDidChange(callback: (config: NotebookConfig) => unknown) { 33 | this.disposables.push(vscode.workspace.onDidChangeConfiguration(e => { 34 | if (e.affectsConfiguration("wolfram")) { 35 | callback(this); 36 | } 37 | })); 38 | } 39 | 40 | get(configName: string) { 41 | return vscode.workspace.getConfiguration("wolfram").get(configName); 42 | } 43 | 44 | async update(configName: string, value: any, configurationTarget: any) { 45 | return await vscode.workspace.getConfiguration("wolfram").update( 46 | configName, value, configurationTarget); 47 | } 48 | 49 | getKernelRelatedConfigs() { 50 | const configNames = [ 51 | "notebook.rendering.invertBrightnessInDarkThemes", 52 | "notebook.rendering.imageScalingFactor" 53 | ]; 54 | const renderingConfig = vscode.workspace.getConfiguration("wolfram"); 55 | let config: { [key: string]: any } = {}; 56 | configNames.forEach(name => { 57 | config[name.split('.').pop() as string] = renderingConfig.get(name); 58 | }); 59 | return config; 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/extension/notebook-kernel.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Tianhuan Lu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import * as vscode from "vscode"; 16 | import * as uuid from "uuid"; 17 | 18 | interface ExecutionItem { 19 | id: string, 20 | execution: vscode.NotebookCellExecution, 21 | started?: boolean, 22 | hasOutput?: boolean 23 | } 24 | 25 | export class ExecutionQueue { 26 | private queue: ExecutionItem[] = []; 27 | 28 | constructor() { 29 | } 30 | 31 | empty(): boolean { 32 | return this.queue.length === 0; 33 | } 34 | 35 | clear(): void { 36 | this.queue.forEach(item => { 37 | this.end(item.id, false); 38 | }); 39 | this.queue = []; 40 | } 41 | 42 | push(execution: vscode.NotebookCellExecution): string { 43 | const id = uuid.v4(); 44 | this.queue.push({ id, execution }); 45 | return id; 46 | } 47 | 48 | private findIndex(id: string): number { 49 | return this.queue.findIndex(item => (item.id === id)); 50 | } 51 | 52 | at(index: number): ExecutionItem | null { 53 | return this.queue[index] || null; 54 | } 55 | 56 | find(id: string): ExecutionItem | null { 57 | return this.at(this.findIndex(id)); 58 | } 59 | 60 | remove(id: string): void { 61 | const index = this.findIndex(id); 62 | if (index >= 0) { 63 | this.queue.splice(index, 1); 64 | } 65 | } 66 | 67 | start(id: string): void { 68 | const execution = this.find(id); 69 | if (execution) { 70 | execution.execution.start(Date.now()); 71 | execution.started = true; 72 | } 73 | } 74 | 75 | end(id: string, succeed: boolean): void { 76 | const execution = this.find(id); 77 | if (execution) { 78 | if (!(execution?.started)) { 79 | execution.execution.start(Date.now()); 80 | } 81 | execution.execution.end(succeed, Date.now()); 82 | this.remove(id); 83 | } 84 | } 85 | 86 | getNextPendingExecution(): ExecutionItem | null { 87 | if (this.queue.length > 0 && !(this.queue[0]?.started)) { 88 | return this.queue[0]; 89 | } else { 90 | return null; 91 | } 92 | } 93 | } 94 | 95 | -------------------------------------------------------------------------------- /src/extension/serializer.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Tianhuan Lu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | import * as vscode from 'vscode'; 17 | const util = require("util"); 18 | 19 | 20 | 21 | interface WLNotebookData { 22 | cells: { 23 | kind: vscode.NotebookCellKind; 24 | languageId: string; 25 | value: string; 26 | outputs?: { 27 | items: { 28 | mime: string, 29 | data: string | Uint8Array 30 | }[]; 31 | metadata?: { [key: string]: any }; 32 | }[]; 33 | executionSummary?: vscode.NotebookCellExecutionSummary; 34 | metadata?: { [key: string]: any }; 35 | }[]; 36 | metadata?: { [key: string]: any }; 37 | } 38 | 39 | export class VSNBContentSerializer implements vscode.NotebookSerializer { 40 | // TODO: better label 41 | public readonly label: string = 'Wolfram Language Content Serializer'; 42 | 43 | public async deserializeNotebook(data: Uint8Array, token: vscode.CancellationToken): Promise { 44 | 45 | 46 | 47 | const decoder = new util.TextDecoder(); 48 | const encoder = new util.TextEncoder(); 49 | let notebook: WLNotebookData; 50 | try { 51 | notebook = JSON.parse(decoder.decode(data)) as WLNotebookData; 52 | for (let cell of notebook.cells) { 53 | if (cell.executionSummary) { 54 | // execution summary is session-specific 55 | delete cell.executionSummary; 56 | } 57 | if (cell.outputs) { 58 | for (const output of cell.outputs) { 59 | for (const item of output.items) { 60 | item.data = encoder.encode(item.data); 61 | } 62 | } 63 | } 64 | } 65 | } catch (e) { 66 | notebook = { cells: [] }; 67 | } 68 | return notebook as vscode.NotebookData; 69 | 70 | } 71 | 72 | public async serializeNotebook(data: vscode.NotebookData, token: vscode.CancellationToken): Promise { 73 | 74 | const decoder = new util.TextDecoder(); 75 | const encoder = new util.TextEncoder(); 76 | 77 | let notebook = data as WLNotebookData; 78 | try { 79 | for (const cell of notebook.cells) { 80 | if (cell.outputs) { 81 | for (const output of cell.outputs) { 82 | for (const item of output.items) { 83 | item.data = decoder.decode(item.data); 84 | } 85 | } 86 | } 87 | } 88 | } catch (e) { 89 | notebook = { cells: [] }; 90 | } 91 | 92 | 93 | return encoder.encode(JSON.stringify(notebook, null, 1)); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | 2 | ## v2.0.0 - XX Nov, 2024 3 | 4 | Add themes. 5 | 6 | Add VsCode notebook support. 7 | 8 | Add auto-completion support. 9 | 10 | Add `Start Wolfram in terminal` command. 11 | 12 | 13 | ## v1.8.0 - 10 Oct, 2022 14 | 15 | Add `_` to wordSeparators suggestion. 16 | 17 | Add links to free Wolfram Engine. 18 | 19 | 20 | ## v1.7.0 - 4 July, 2022 21 | 22 | Add light theme 23 | 24 | 13.1 syntax updates 25 | 26 | 27 | ## v1.6.0 - 12 May, 2022 28 | 29 | Update dependencies 30 | 31 | Add "Download Wolfram Engine" links to command palette 32 | 33 | support new 13.1 syntax `"PackedArray"::["Real64"]` 34 | 35 | 36 | ## v1.5.0 - 7 Mar, 2022 37 | 38 | Ensure an empty directory to use as working directory 39 | 40 | Properly push subscription from client.start() 41 | 42 | Increase timeout to 15 seconds and add timeout_warning_enabled setting 43 | 44 | Syntax error for invalid `\|XXXXXX` character syntax 45 | 46 | Remove "Open Notebook" from command palette 47 | 48 | Rename "Open in Notebook Editor" -> "Open in System Editor" 49 | 50 | Various "open" commands are run on different systems, and nothing guarantees opening with the FE 51 | 52 | Minimize user confusion by not mentioning "Notebook Editor" 53 | 54 | 13.0.1 syntax updates 55 | 56 | Merge pull request #9 from LumaKernel/patch-1 57 | Add "Wolfram Language" as language alias for Jupyter Notebook VSCode Integration 58 | 59 | 60 | ### Fixes 61 | 62 | Fix leftover "Example configuration" from early days 63 | 64 | https://github.com/WolframResearch/vscode-wolfram/issues/5 65 | 66 | Fix logic for resolving kernel paths 67 | 68 | Should try new versions as well as older versions 69 | 70 | 71 | ## v1.4.0 - 25 Oct, 2021 72 | 73 | Remove unused WolframLanguageSyntax files 74 | 75 | 76 | ### Fixes 77 | 78 | Fix 415574: unrecognized symbol followed by `[` should have scope `variable.function` 79 | 80 | Also recognize `f @ x` syntax for function call, but do NOT recognize `a ~f~ b` or `a // f` 81 | 82 | 83 | ## v1.3.3 - 11 Oct, 2021 84 | 85 | If a kernel cannot be started, then do not also show the timeout dialog after 10 seconds, that is just extra noise. 86 | 87 | `lsp_server_enabled` setting: Allow selectively disabling Wolfram Language LSP 88 | 89 | 90 | ## v1.3.2 - 27 Sep, 2021 91 | 92 | ### Fixes 93 | - Fixed problem with dialog saying "Language Server kernel did not initialize properly after 10 seconds." 94 | 95 | The kernel actually did start correctly, but the timeout for the dialog was not being handled properly. 96 | 97 | 98 | ## v1.3.1 - 22 Sep, 2021 99 | 100 | First release from official Wolfram Research GitHub repo 101 | 102 | https://github.com/WolframResearch/vscode-wolfram 103 | 104 | 105 | ## 1.3 - 30 Aug, 2021 106 | 107 | Rename publisher to WolframResearch 108 | 109 | A change in CMake \~3.20 introduced compiler_depend.ts file in the CMakeFiles directory 110 | So exclude compiler_depend.ts files 111 | 112 | 113 | ## 0.15 - 15 Jan, 2020 114 | 115 | Add `(\* \*)` as a kind of bracket 116 | 117 | 118 | ## 0.14 - 28 Oct, 2019 119 | 120 | Add ConfidenceLevel setting 121 | 122 | 123 | ## 0.12 - 5 Aug, 2019 124 | 125 | Unify the various command settings into a single wolfram.command setting 126 | -------------------------------------------------------------------------------- /Docs/configuration-details.md: -------------------------------------------------------------------------------- 1 | # Configuration Details 2 | 3 | ## Kernel management 4 | 5 | If you have the Wolfram System (either Wolfram, Mathematica, or Wolfram Engine) installed in the default location on your system, you may not have to change any kernel settings. 6 | 7 | By default, the extension tries to find the most recent version of the Wolfram system in standard locations, but if it cannot be found or you want to specify a kernel to use, edit the `Wolfram: System Kernel` setting to give the full path to the WolframKernel executable. 8 | 9 | LSP functionality runs in its own kernel, separate from evaluations done in notebooks or in the terminal window. 10 | 11 | ## Supported features 12 | 13 | * Syntax Highlighting 14 | * Diagnostics and suggestions for fixes 15 | * Formatting files and selections 16 | * Semantic highlighting 17 | * Expand and shrink selection 18 | * Outline 19 | * Color swatches 20 | * Symbol references 21 | * Function definition and documentation on hover 22 | * Completion support 23 | * VSCode Notebook support 24 | * Running Wolfram Language code in Wolfram terminal 25 | * New menu items (Open in System Editor) 26 | 27 | ## Settings 28 | 29 | You can change many settings for custom kernel management and user experience. 30 | 31 | ### Changing settings 32 | Open the Command Palette 33 | 34 | Choose the command: 35 | `Wolfram Language: Open Configurations` 36 | 37 | ![open-config](../Docs/feature/open-config.png) 38 | 39 | A settings window will open: 40 | 41 | ### Visualization settings 42 | Visualization or rendering related settings can be modified from VSCode settings 43 | 44 | #### Graphics scaling 45 | 46 | Rendered image size in the notebook can be rescaled using `Wolfram › Rendering: Image Scaling Factor`: 47 | 48 | ![graphics-scaling](../Docs/visualization/graphics-scaling.png) 49 | 50 | #### Invert output in dark themes 51 | Rendered image background color can be inverted using `Wolfram › Rendering: Invert Brightness In Dark Themes`: 52 | 53 | ![invert-theme](../Docs/visualization/invert-theme.png) 54 | 55 | ### Other Settings 56 | 57 | It is convenient to remove `$` as a word separator, because it is a letterlike character in Wolfram Language. 58 | 59 | It is also convenient to add `_` as a word separator, because it is NOT a letterlike character in Wolfram Language. 60 | ``` 61 | "editor.wordSeparators": "`~!@#%^&*()-=+[{]}\\|;:'\",.<>/?_" 62 | ``` 63 | 64 | 65 | 66 | ### Extension quick test 67 | 68 | #### LSP functionality 69 | 70 | Many features of this extension use Microsoft's Language Server Protocol (LSP). LSP functionality requires version 12.1 or later of the Wolfram system. 71 | 72 | If properly set up, syntax highlighting and linting of Wolfram Language `.wl` files should be visible. 73 | 74 | Test this by typing this into a new `.wl` file and saving it: 75 | ``` 76 | Which[a, b, a, b] 77 | ``` 78 | 79 | Warnings about duplicate clauses should be seen. 80 | 81 | 82 | #### Notebook functionality 83 | 84 | Create a new file with the `.vsnb` extension. Open the file and notebook input cells should be visible. 85 | 86 | Any valid Wolfram Language expression can be evaluated in this notebook. 87 | 88 | ##### Notebook kernel usage 89 | 90 | 91 | * All notebooks in a single VSCode instance use the same Wolfram kernel. 92 | * Each instance of VSCode uses a different Wolfram kernel. 93 | 94 | 95 | ## Troubleshooting 96 | 97 | If the kernel cannot start, then check the Output view and open the Wolfram Language Error Report output channel for more information. 98 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Wolfram Language extension for Visual Studio Code 2 | 3 | This extension provides support for the [Wolfram Language](https://www.wolfram.com/language) in Visual Studio Code. 4 | 5 | ## Introduction 6 | 7 | The [Wolfram Language](https://www.wolfram.com/language) is a symbolic language, designed with the breadth and unity needed to develop powerful programs quickly. The philosophy of Wolfram Language is to build as much knowledge—about algorithms and the world—into the language as possible. Wolfram Language represents everything—data, formulas, code, graphics, documents, interfaces, etc.—as symbolic expressions, making possible a new level of programming flexibility and power. 8 | 9 | The primary way to work in the Wolfram Language is through [Wolfram Notebooks](https://www.wolfram.com/notebooks/), which provide a rich environment for creating and sharing documents that combine code, text, graphics, and interactive interfaces. These notebooks can be created and edited in the [Wolfram Desktop](https://www.wolfram.com/wolfram-one/) and the [Wolfram Cloud](https://www.wolfram.com/cloud/). 10 | 11 | For developers who prefer to work in a text editor, this extension provides support for the Wolfram Language in Visual Studio Code. This extension provides syntax highlighting, diagnostics, formatting, and other features to help you write Wolfram Language code in Visual Studio Code. It also provides support for running Wolfram Language code in a terminal and for creating more basic Visual Studio Code style notebooks. 12 | 13 | # Installing and configuring the extension 14 | 15 | To install this extension, click on the install button at the top of this page. In most cases, the extension will automatically find the Wolfram Language kernel if the kernel is installed in the default location. 16 | 17 | If the kernel is not found, you can specify the path to the kernel in the extension settings. You can open the extension settings by clicking the gear icon at the top of this page and selecting `Extension Settings` from the dropdown menu. In the Settings window that opens, search for `Wolfram: System Kernel` and enter the path to the Wolfram Language kernel executable. 18 | 19 | For more information on configuring the extension, see the [Configuration Details](Docs/configuration-details.md) page. 20 | 21 | ## Extension features overview 22 | 23 | ### Notebook features 24 | 25 | This extension provides support for creating the more basic Visual Studio style notebooks that can run Wolfram Language inputs. These notebooks are created with the `.vsnb` extension. These notebooks support basic output like text, static graphics, warnings, and messages. 26 | 27 | For full [Wolfram Language notebook](https://wwww.wolfram.com/notebooks) support, use the [Wolfram Desktop](https://www.wolfram.com/one) or [Wolfram Cloud](https://www.wolfram.com/cloud). 28 | 29 | ![notebook](Docs/notebook-output.png) 30 | 31 | ### Syntax Highlighting 32 | 33 | Syntax highlighting makes your Wolfram Language code easier to read and understand: 34 | 35 | ![highlighting](Docs/highlighting.png) 36 | 37 | ### Themes 38 | 39 | This extension provides several themes, including syntax highlighting for the Wolfram Language. The themes provided are: 40 | 41 | * Wolfram (Default) -- Provides a light theme with default Wolfram notebook syntax colors. 42 | * Wolfram (Light) -- Provides a light theme with muted colors 43 | * Wolfram (Dark) -- Provides a dark theme. 44 | * Wolfram (Dark Rainbow) -- Provdes a more colorful dark theme. 45 | 46 | ### Hover support 47 | 48 | When you hover over a Wolfram system function, you can see a brief description of the function: 49 | 50 | ![hover](Docs/feature/hover-support.gif) 51 | 52 | ### Completion support 53 | 54 | When you start typing a Wolfram system function, you can see a list of possible completions: 55 | 56 | ![completion](Docs/feature/completion-support.gif) 57 | 58 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); 2 | const { DefinePlugin } = require('webpack'); 3 | const path = require('path'); 4 | 5 | const makeConfig = (argv, { entry, out, target, library = 'commonjs' }) => ({ 6 | mode: argv.mode, 7 | devtool: argv.mode === 'production' ? false : 'inline-source-map', 8 | entry, 9 | target, 10 | output: { 11 | path: path.join(__dirname, path.dirname(out)), 12 | filename: path.basename(out), 13 | publicPath: '', 14 | libraryTarget: library, 15 | chunkFormat: library, 16 | }, 17 | resolve: { 18 | extensions: ['.ts', '.tsx', '.js', '.jsx', '.css'] 19 | }, 20 | experiments: { 21 | outputModule: true, 22 | }, 23 | externals: { 24 | "vscode": "commonjs vscode", 25 | "vscode-test": "commonjs vscode-test", 26 | "assert": "commonjs assert", 27 | "mocha": "commonjs mocha", 28 | "glob": "commonjs glob", 29 | "util": "commonjs util", 30 | "zeromq": "commonjs zeromq", 31 | "child_process": "commonjs child_process", 32 | "fs": "commonjs fs", 33 | "uuid": "commonjs uuid", 34 | "markdown-it": "commonjs markdown-it", 35 | "path": "commonjs path", 36 | "mathjax": "commonjs mathjax" 37 | }, 38 | module: { 39 | rules: [ 40 | // Allow importing ts(x) files: 41 | { 42 | test: /\.tsx?$/, 43 | loader: 'ts-loader', 44 | options: { 45 | configFile: path.join(path.dirname(entry), 'tsconfig.json'), 46 | // transpileOnly enables hot-module-replacement 47 | transpileOnly: true, 48 | compilerOptions: { 49 | // Overwrite the noEmit from the client's tsconfig 50 | noEmit: false, 51 | }, 52 | }, 53 | }, 54 | // Allow importing CSS modules: 55 | // { 56 | // test: /\.css$/, 57 | // use: [ 58 | // 'style-loader', 59 | // { 60 | // loader: 'css-loader', 61 | // options: { 62 | // importLoaders: 1, 63 | // modules: true, 64 | // }, 65 | // }, 66 | // ], 67 | // }, 68 | 69 | { 70 | test: /\.css$/, 71 | use: ["style-loader", 'css-loader'], 72 | }, 73 | { 74 | test: /\.(png|woff|woff2|eot|ttf|svg)$/, 75 | use: 'file-loader' 76 | } 77 | ], 78 | }, 79 | plugins: [ 80 | new ForkTsCheckerWebpackPlugin({ 81 | typescript: { 82 | configFile: path.join(path.dirname(entry), 'tsconfig.json'), 83 | }, 84 | }), 85 | new DefinePlugin({ 86 | // Path from the output filename to the output directory 87 | __webpack_relative_entrypoint_to_root__: JSON.stringify( 88 | path.posix.relative(path.posix.dirname(`/index.js`), '/'), 89 | ), 90 | scriptUrl: 'import.meta.url', 91 | }), 92 | ], 93 | infrastructureLogging: { 94 | level: "log", // enables logging required for problem matchers 95 | }, 96 | }); 97 | 98 | module.exports = (_env, argv) => [ 99 | 100 | makeConfig(argv, { entry: './src/client/index.ts', out: './out/client/index.js', target: 'web', library: 'module' }), 101 | makeConfig(argv, { entry: './src/test/runTest.ts', out: './out/test/runTest.js', target: 'node' }), 102 | 103 | ]; 104 | -------------------------------------------------------------------------------- /src/extension/ui-items.ts: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Tianhuan Lu 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | import * as vscode from "vscode"; 16 | 17 | export class KernelStatusBarItem { 18 | private item: vscode.StatusBarItem; 19 | private readonly baseText = " Wolfram Kernel"; 20 | private kernelIsActive = false; 21 | private editorIsActive = true; 22 | private disposables: any[] = []; 23 | 24 | constructor(supportedLanguages: string[]) { 25 | this.item = vscode.window.createStatusBarItem( 26 | "wolfram-language-notebook-kernel-status", vscode.StatusBarAlignment.Right, 100 27 | ); 28 | this.disposables.push(this.item); 29 | this.item.name = "Wolfram Kernel"; 30 | this.item.command = "wolframLanguageNotebook.manageKernels"; 31 | this.setDisconnected(); 32 | this.updateVisibility(); 33 | 34 | this.disposables.push(vscode.window.onDidChangeActiveTextEditor(e => { 35 | this.editorIsActive = Boolean(e?.document && supportedLanguages.includes(e.document.languageId)); 36 | this.updateVisibility(); 37 | })); 38 | } 39 | 40 | dispose() { 41 | this.disposables.forEach(item => { 42 | item.dispose(); 43 | }); 44 | } 45 | 46 | private updateVisibility() { 47 | if (this.kernelIsActive || this.editorIsActive) { 48 | this.item.show(); 49 | } else { 50 | this.item.hide(); 51 | } 52 | } 53 | 54 | private setState(active: boolean, icon: string, tooltip: string) { 55 | this.kernelIsActive = active; 56 | this.item.text = icon + this.baseText; 57 | this.item.tooltip = tooltip; 58 | this.updateVisibility(); 59 | } 60 | 61 | setDisconnected() { 62 | this.setState(false, "$(close)", "Currently not connected to a kernel"); 63 | } 64 | 65 | setConnecting() { 66 | this.setState(true, "$(loading~spin)", "Connecting to the kernel"); 67 | } 68 | 69 | setConnected(tooltip: string = "", isRemote: boolean = false) { 70 | this.setState(true, (isRemote ? "$(remote)" : "$(check)"), tooltip || "Kernel connected"); 71 | } 72 | } 73 | 74 | export class ExportNotebookStatusBarItem { 75 | private item: vscode.StatusBarItem; 76 | 77 | constructor() { 78 | this.item = vscode.window.createStatusBarItem( 79 | "wolfram-language-export-notebook-status", vscode.StatusBarAlignment.Right, 101 80 | ); 81 | this.item.name = "Export Notebook"; 82 | this.item.text = "$(loading~spin) Generating Notebook"; 83 | this.item.command = "wolframLanguageNotebook.manageKernels"; 84 | this.item.hide(); 85 | } 86 | 87 | show() { 88 | this.item.show(); 89 | } 90 | 91 | hide() { 92 | this.item.hide(); 93 | } 94 | } 95 | 96 | export class NotebookOutputPanel { 97 | private outputChannel: vscode.OutputChannel; 98 | 99 | constructor(name: string) { 100 | this.outputChannel = vscode.window.createOutputChannel(name); 101 | } 102 | 103 | print(str: string) { 104 | this.outputChannel.appendLine("[" + new Date().toUTCString() + "] " + str); 105 | } 106 | 107 | show() { 108 | this.outputChannel.show(); 109 | } 110 | 111 | hide() { 112 | this.outputChannel.hide(); 113 | } 114 | 115 | clear() { 116 | this.outputChannel.clear(); 117 | } 118 | 119 | dispose() { 120 | this.outputChannel.dispose(); 121 | } 122 | }; 123 | -------------------------------------------------------------------------------- /resources/render-html.wl: -------------------------------------------------------------------------------- 1 | (* ::Package:: *) 2 | 3 | (* 4 | 5 | // Copyright 2021 Tianhuan Lu 6 | // 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // 11 | // http://www.apache.org/licenses/LICENSE-2.0 12 | // 13 | // Unless required by applicable law or agreed to in writing, software 14 | // distributed under the License is distributed on an "AS IS" BASIS, 15 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | // See the License for the specific language governing permissions and 17 | // limitations under the License. 18 | 19 | *) 20 | 21 | 22 | $IterationLimit=400000; 23 | $RecursionLimit=100000; 24 | 25 | 26 | ClearAll[renderWrapper,renderHTML]; 27 | 28 | 29 | $statestack=<||>; 30 | $inheritedStyle=<||>; 31 | $localStyle=<||>; 32 | 33 | localStyleNames=<| 34 | RowBox->{}, 35 | SqrtBox->{SurdForm}, 36 | RadicalBox->{SurdForm}, 37 | FrameBox->{Background,FrameMargins,ImageMargins,RoundingRadius}, 38 | StyleBox->{TextAlignment,FontFamily,FontSize,FontWeight,FontSlant,FontTracking,FontVariations,FontColor,FontOpacity,Background}, 39 | PaneBox->{ImageSize}, 40 | GridBox->{GridBoxFrame} 41 | |>; 42 | inheritedStyleNames=<| 43 | RowBox->{}, 44 | StyleBox->{ShowStringCharacters,SingleLetterItalics}, 45 | PaneBox->{} 46 | |>; 47 | handleStyles[head_,styles_]:=Module[{keys}, 48 | keys=Keys[styles]; 49 | $localStyle=KeyTake[styles,Intersection[keys,Lookup[localStyleNames,head,{}]]]; 50 | {KeyTake[styles,#],AssociationThread[#->Lookup[$inheritedStyle,#,Missing[]]]}&@Intersection[keys,Lookup[inheritedStyleNames,head,{}]] 51 | ]; 52 | 53 | SetAttributes[renderWrapper,HoldAll]; 54 | renderWrapper[state_Association,styles_,expr_]:=Module[{return,stateModifier,pop}, 55 | stackPush[$statestack,Join[<|"head"->Null,"mutable"->False,"bracket"->False|>,<|"head"->state["head"]|>]]; 56 | If[Length[styles]==0,$localStyle=<||>;, 57 | stateModifier=handleStyles[state["head"],styles]; 58 | AssociateTo[$inheritedStyle,stateModifier[[1]]]; 59 | ]; 60 | 61 | return=expr; 62 | If[Length[styles]==0,$localStyle=<||>;, 63 | AssociateTo[$inheritedStyle,Select[stateModifier[[2]],Not@*MissingQ]]; 64 | KeyDropFrom[$inheritedStyle,Keys@Select[stateModifier[[2]],MissingQ]]; 65 | ]; 66 | pop=stackPop[$statestack]; 67 | If[pop["mutable"]===True&&Length[$statestack]>0,Null(*$statestack[[-1,"mutable"]]=True*)]; 68 | return 69 | ]; 70 | renderWrapper[head_Symbol,styles_,expr_]:=renderWrapper[<|"head"->head|>,styles,expr]; 71 | 72 | (* rasterizeAsImage[boxes_]:= Rasterize[RawBoxes[boxes], Background -> If[TrueQ@$getKernelConfig["imageWithTransparency"], None, Automatic]]; *) 73 | 74 | rasterizeAsImage[boxes_]:=Module[{expr=RawBoxes[boxes],black,white,alpha,image}, 75 | If[!TrueQ@$getKernelConfig["imageWithTransparency"], 76 | Rasterize[expr], 77 | black=ImageData@Rasterize[expr,Background->Black]; 78 | white=ImageData@Rasterize[expr,Background->White]; 79 | alpha=Clip[1.-(1./3)(Total[white,{3}]-Total[black,{3}]),{0.,1.}]; 80 | image=0.5*(1.0-(1.0-white)/#)+0.5*(black/#)&[Transpose[ConstantArray[Clip[alpha,{0.001,1.0}],3],{3,1,2}]]; 81 | SetAlphaChannel[Image[Clip[image,{0.,1.}]],Image[alpha]] 82 | ] 83 | ] 84 | 85 | renderHTMLimage[x_,resizable_:True]:=Module[{img=rasterizeAsImage[x] ,dim, final,imageInBase64}, 86 | 87 | Export[FileNameJoin[{$TemporaryDirectory,"img.jpg"}], img]; 88 | ba = ExportByteArray[img, "PNG"]; 89 | imageInBase64 = BaseEncode[ba]; 90 | dim=ImageDimensions[img]; 91 | disableInvert=!TrueQ@$getKernelConfig["invertBrightnessInDarkThemes"]; 92 | StringJoin["" 99 | ] 100 | 101 | ]; 102 | 103 | renderImage[expr_]:=renderWrapper[Expression,<||>, 104 | StringJoin["
",renderHTMLimage[expr],"
"]] -------------------------------------------------------------------------------- /src/extension/find-kernel.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * vscode-wolfram 3 | * 4 | * Created by IDE support team on 10/01/24. 5 | * Copyright (c) 2024 Wolfram Research. All rights reserved. 6 | * 7 | */ 8 | 9 | import * as vscode from "vscode"; 10 | const fs = require('fs'); 11 | 12 | export class FindKernel { 13 | 14 | private readonly linuxKernelPath = [ 15 | 16 | // ToDo: Add Wolfram app paths 17 | 18 | "/usr/local/Wolfram/Wolfram/14.2/Executables/WolframKernel", 19 | "/usr/local/Wolfram/WolframEngine/14.2/Executables/WolframKernel", 20 | 21 | "/usr/local/Wolfram/Wolfram/14.1/Executables/WolframKernel", 22 | "/usr/local/Wolfram/WolframEngine/14.1/Executables/WolframKernel", 23 | 24 | "/usr/local/Wolfram/Mathematica/14.0/Executables/WolframKernel", 25 | "/usr/local/Wolfram/WolframEngine/14.0/Executables/WolframKernel", 26 | 27 | "/usr/local/Wolfram/Mathematica/13.3/Executables/WolframKernel", 28 | "/usr/local/Wolfram/WolframEngine/13.3/Executables/WolframKernel", 29 | 30 | "/usr/local/Wolfram/Mathematica/13.2/Executables/WolframKernel", 31 | "/usr/local/Wolfram/WolframEngine/13.2/Executables/WolframKernel", 32 | 33 | "/usr/local/Wolfram/Mathematica/13.1/Executables/WolframKernel", 34 | "/usr/local/Wolfram/WolframEngine/13.1/Executables/WolframKernel", 35 | 36 | "/usr/local/Wolfram/Mathematica/13.0/Executables/WolframKernel", 37 | "/usr/local/Wolfram/WolframEngine/13.0/Executables/WolframKernel", 38 | 39 | "/usr/local/Wolfram/Mathematica/12.3/Executables/WolframKernel", 40 | "/usr/local/Wolfram/WolframEngine/12.3/Executables/WolframKernel", 41 | 42 | "/usr/local/Wolfram/Mathematica/12.2/Executables/WolframKernel", 43 | "/usr/local/Wolfram/WolframEngine/12.2/Executables/WolframKernel", 44 | 45 | "/usr/local/Wolfram/Mathematica/12.1/Executables/WolframKernel", 46 | "/usr/local/Wolfram/WolframEngine/12.1/Executables/WolframKernel" 47 | 48 | ]; 49 | 50 | private readonly macKernelPath = [ 51 | 52 | "/Applications/Wolfram.app/Contents/MacOS/WolframKernel", 53 | "/Applications/Mathematica.app/Contents/MacOS/WolframKernel", 54 | "/Applications/Wolfram Engine.app/Contents/MacOS/WolframKernel" 55 | 56 | ]; 57 | 58 | private readonly winKernelPath = [ 59 | 60 | "C:\\Program Files\\Wolfram Research\\Wolfram\\14.2\\WolframKernel.exe", 61 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\14.2\\WolframKernel.exe", 62 | 63 | "C:\\Program Files\\Wolfram Research\\Wolfram\\14.1\\WolframKernel.exe", 64 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\14.1\\WolframKernel.exe", 65 | 66 | "C:\\Program Files\\Wolfram Research\\Mathematica\\14.0\\WolframKernel.exe", 67 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\14.0\\WolframKernel.exe", 68 | 69 | "C:\\Program Files\\Wolfram Research\\Mathematica\\13.3\\WolframKernel.exe", 70 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\13.3\\WolframKernel.exe", 71 | 72 | "C:\\Program Files\\Wolfram Research\\Mathematica\\13.2\\WolframKernel.exe", 73 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\13.2\\WolframKernel.exe", 74 | 75 | "C:\\Program Files\\Wolfram Research\\Mathematica\\13.1\\WolframKernel.exe", 76 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\13.1\\WolframKernel.exe", 77 | 78 | "C:\\Program Files\\Wolfram Research\\Mathematica\\13.0\\WolframKernel.exe", 79 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\13.0\\WolframKernel.exe", 80 | 81 | "C:\\Program Files\\Wolfram Research\\Mathematica\\12.3\\WolframKernel.exe", 82 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\12.3\\WolframKernel.exe", 83 | 84 | "C:\\Program Files\\Wolfram Research\\Mathematica\\12.2\\WolframKernel.exe", 85 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\12.2\\WolframKernel.exe", 86 | 87 | "C:\\Program Files\\Wolfram Research\\Mathematica\\12.1\\WolframKernel.exe", 88 | "C:\\Program Files\\Wolfram Research\\Wolfram Engine\\12.1\\WolframKernel.exe" 89 | 90 | ]; 91 | 92 | constructor() { 93 | 94 | } 95 | 96 | public resolveKernel():string { 97 | 98 | const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("wolfram", null); 99 | 100 | let kernel = config.get("systemKernel", "Automatic",); 101 | 102 | // kernel is the default value, so resolve to an actual path 103 | if (kernel == "Automatic") { 104 | 105 | kernel = this.getOSKernelPath(); 106 | } 107 | 108 | return kernel 109 | } 110 | 111 | 112 | private getOSKernelPath():string { 113 | 114 | let possibleKernelPaths: string[]; 115 | 116 | switch (process.platform) { 117 | 118 | case "linux": 119 | // 120 | // generally recommend newer versions over older versions 121 | // and recommend pre-13.0 Wolfram Engine last, because usage messages did not work before 13.0 122 | // 123 | possibleKernelPaths = this.linuxKernelPath; 124 | break; 125 | case "darwin": 126 | possibleKernelPaths = this.macKernelPath; 127 | break; 128 | case "win32": 129 | // 130 | // generally recommend newer versions over older versions 131 | // and recommend pre-13.0 Wolfram Engine last, because usage messages did not work before 13.0 132 | // 133 | possibleKernelPaths = this.winKernelPath; 134 | break; 135 | default: 136 | possibleKernelPaths = []; 137 | break; 138 | } 139 | 140 | let res = possibleKernelPaths.find(k => fs.existsSync(k)); 141 | 142 | if (res === undefined) { 143 | res = "kernel-not-found" 144 | } 145 | 146 | return res; 147 | } 148 | 149 | 150 | }; 151 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wolfram", 3 | "displayName": "Wolfram Language", 4 | "description": "Official Visual Studio Code extension for Wolfram Language", 5 | "publisher": "WolframResearch", 6 | "version": "2.0.1", 7 | "engines": { 8 | "vscode": "^1.95.0" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/WolframResearch/vscode-wolfram.git" 13 | }, 14 | "keywords": [ 15 | "notebookRenderer" 16 | ], 17 | "categories": [ 18 | "Other" 19 | ], 20 | "activationEvents": [ 21 | "onLanguage:wolfram", 22 | "onCommand:wolfram.OpenNotebook", 23 | "onCommand:wolfram.DownloadWolframEngine", 24 | "onCommand:createWolframScriptTerminal", 25 | "onCommand:wolfram.openConfigurations", 26 | "onCommand:wolfram.launchKernel" 27 | ], 28 | "main": "./out/extension/extension.js", 29 | "icon": "images/icon.png", 30 | "contributes": { 31 | "languages": [ 32 | { 33 | "id": "wolfram", 34 | "aliases": [ 35 | "Wolfram", 36 | "wolfram", 37 | "Wolfram Language" 38 | ], 39 | "extensions": [ 40 | ".wl", 41 | ".m", 42 | ".wls", 43 | ".wlt", 44 | ".mt", 45 | ".vsnb" 46 | ], 47 | "configuration": "./wolfram.language-configuration.json" 48 | } 49 | ], 50 | "grammars": [ 51 | { 52 | "language": "wolfram", 53 | "scopeName": "source.wolfram", 54 | "path": "./syntaxes/wolfram.tmLanguage.json" 55 | } 56 | ], 57 | "configuration": { 58 | "type": "object", 59 | "title": "Wolfram", 60 | "properties": { 61 | "wolfram.lsp.serverEnabled": { 62 | "scope": "resource", 63 | "type": "boolean", 64 | "default": true, 65 | "description": "Enables the Wolfram LSP server", 66 | "order": 1 67 | }, 68 | "wolfram.notebook.kernelEnabled": { 69 | "scope": "resource", 70 | "type": "boolean", 71 | "default": false, 72 | "description": "Enables Notebook Evaluation", 73 | "order": 1 74 | }, 75 | "wolfram.timeout_warning_enabled": { 76 | "scope": "resource", 77 | "type": "boolean", 78 | "default": true, 79 | "description": "Enables the timeout warning if the kernel does not start after 15 seconds", 80 | "order": 2 81 | }, 82 | "wolfram.systemKernel": { 83 | "scope": "user", 84 | "type": "string", 85 | "default": "Automatic", 86 | "description": "Path to Wolfram System kernel", 87 | "order": 0 88 | }, 89 | "wolfram.advanced.lsp.ServerLogDirectory": { 90 | "scope": "user", 91 | "type": "string", 92 | "default": "Off", 93 | "description": "Directory for the Wolfram LSP server log", 94 | "order": 5 95 | }, 96 | "wolfram.advanced.notebook.logDirectory": { 97 | "scope": "user", 98 | "type": "string", 99 | "default": "Off", 100 | "description": "Directory for the notebook log", 101 | "order": 5 102 | }, 103 | "wolfram.advanced.lsp.command": { 104 | "scope": "user", 105 | "type": "array", 106 | "default": [ 107 | "lspKernel" 108 | ], 109 | "description": "Command to start the Wolfram LSP server", 110 | "order": 5 111 | }, 112 | "wolfram.lsp.implicitTokens": { 113 | "scope": "user", 114 | "type": "array", 115 | "default": [], 116 | "description": "Experimental option for the Wolfram LSP server", 117 | "order": 3 118 | }, 119 | "wolfram.lsp.semanticTokens": { 120 | "scope": "user", 121 | "type": "boolean", 122 | "default": false, 123 | "description": "Experimental option for the Wolfram LSP server", 124 | "order": 3 125 | }, 126 | "wolfram.notebook.rendering.invertBrightnessInDarkThemes": { 127 | "type": "boolean", 128 | "default": true, 129 | "description": "When an expression is evaluated, this option specifies whether the brightness of the images in the output should be inverted in dark and high contrast themes. ", 130 | "order": 4 131 | }, 132 | "wolfram.notebook.rendering.imageScalingFactor": { 133 | "type": "number", 134 | "default": 0.8, 135 | "description": "Controls image output size", 136 | "order": 4 137 | } 138 | } 139 | }, 140 | "semanticTokenTypes": [], 141 | "semanticTokenModifiers": [ 142 | { 143 | "id": "Module", 144 | "description": "Annotates a variable that is Module scoped" 145 | }, 146 | { 147 | "id": "Block", 148 | "description": "Annotates a variable that is Block scoped" 149 | }, 150 | { 151 | "id": "With", 152 | "description": "Annotates a constant that is With scoped" 153 | }, 154 | { 155 | "id": "shadowed", 156 | "description": "Annotates a variable, parameter, or constant that is shadowed" 157 | }, 158 | { 159 | "id": "unused", 160 | "description": "Annotates a variable, parameter, or constant that is unused" 161 | }, 162 | { 163 | "id": "error", 164 | "description": "Annotates a scoping error" 165 | } 166 | ], 167 | "themes": [ 168 | { 169 | "label": "Wolfram (Dark)", 170 | "uiTheme": "vs-dark", 171 | "path": "./themes/wolfram-dark.json" 172 | }, 173 | { 174 | "label": "Wolfram (Default)", 175 | "uiTheme": "vs", 176 | "path": "./themes/wolfram-Default.json" 177 | }, 178 | { 179 | "label": "Wolfram (Dark Rainbow)", 180 | "uiTheme": "vs-dark", 181 | "path": "./themes/wolfram-dark-rainbow.json" 182 | }, 183 | { 184 | "label": "Wolfram (Light)", 185 | "uiTheme": "vs", 186 | "path": "./themes/Wolfram-light.json" 187 | } 188 | ], 189 | "commands": [ 190 | { 191 | "command": "wolfram.OpenNotebook", 192 | "title": "Open in System Editor" 193 | }, 194 | { 195 | "command": "wolfram.DownloadWolframEngine", 196 | "title": "Wolfram Language: Download Wolfram Engine" 197 | }, 198 | { 199 | "command": "createWolframScriptTerminal", 200 | "title": "Wolfram Language: Start Wolfram in Terminal" 201 | }, 202 | { 203 | "command": "wolfram.launchKernel", 204 | "title": "Wolfram Language: Launch Default Kernel" 205 | }, 206 | { 207 | "command": "wolfram.openConfigurations", 208 | "title": "Wolfram Language: Open Configurations" 209 | } 210 | ], 211 | "menus": { 212 | "explorer/context": [ 213 | { 214 | "when": "resourceExtname == .nb || resourceExtname == .m || resourceExtname == .wl || resourceExtname == .wls || resourceExtname == .cdf", 215 | "command": "wolfram.OpenNotebook", 216 | "group": "navigation" 217 | } 218 | ], 219 | "editor/context": [ 220 | { 221 | "when": "resourceExtname == .nb || resourceExtname == .m || resourceExtname == .wl || resourceExtname == .wls || resourceExtname == .cdf", 222 | "command": "wolfram.OpenNotebook", 223 | "group": "navigation" 224 | }, 225 | { 226 | "when": "resourceExtname == .nb || resourceExtname == .m || resourceExtname == .wl || resourceExtname == .wls || resourceExtname == .cdf", 227 | "command": "workbench.action.terminal.runSelectedText", 228 | "group": "navigation" 229 | }, 230 | { 231 | "when": "resourceExtname == .nb || resourceExtname == .m || resourceExtname == .wl || resourceExtname == .wls || resourceExtname == .cdf", 232 | "command": "workbench.action.terminal.runActiveFile", 233 | "group": "navigation" 234 | } 235 | ], 236 | "commandPalette": [ 237 | { 238 | "command": "wolfram.OpenNotebook", 239 | "when": "false" 240 | }, 241 | { 242 | "command": "wolfram.DownloadWolframEngine" 243 | } 244 | ] 245 | }, 246 | "keybindings": [ 247 | { 248 | "command": "workbench.action.terminal.runSelectedText", 249 | "key": "Shift+Enter", 250 | "when": "resourceExtname == .nb || resourceExtname == .m || resourceExtname == .wl || resourceExtname == .wls || resourceExtname == .cdf" 251 | } 252 | ], 253 | "notebooks": [ 254 | { 255 | "type": "wolfram-notebook", 256 | "displayName": "Wolfram Notebook", 257 | "selector": [ 258 | { 259 | "filenamePattern": "*.vsnb" 260 | } 261 | ] 262 | } 263 | ], 264 | "notebookRenderer": [ 265 | { 266 | "id": "wolfram-notebook-renderer", 267 | "entrypoint": "./out/client/index.js", 268 | "displayName": "wolfram-notebook-renderer", 269 | "mimeTypes": [ 270 | "x-application/wolfram-language-html" 271 | ], 272 | "dependencies": [], 273 | "requiresMessaging": "optional" 274 | } 275 | ] 276 | }, 277 | "scripts": { 278 | "vscode:prepublish": "npm run compile", 279 | "clean": "rm -rf out && rm -rf node_modules", 280 | "compile": "tsc -b && webpack --mode production", 281 | "lint": "eslint src --ext ts", 282 | "watch": "concurrently \"tsc -b --watch\" \"webpack --mode development --watch\"", 283 | "pretest": "webpack --mode development && npm run lint", 284 | "test": "node ./out/test/runTest.js" 285 | }, 286 | "devDependencies": { 287 | "@types/glob": "^8.1.0", 288 | "@types/mocha": "^8.2.3", 289 | "@types/node": "18.11.9", 290 | "@types/uuid": "^9.0.8", 291 | "@types/vscode": "^1.95.0", 292 | "@types/vscode-notebook-renderer": "^1.72.3", 293 | "@types/webpack-env": "^1.18.5", 294 | "@typescript-eslint/eslint-plugin": "^4.33.0", 295 | "@typescript-eslint/parser": "^4.33.0", 296 | "@vscode/test-electron": "^2.4.1", 297 | "concurrently": "^8.2.2", 298 | "css-loader": "^6.11.0", 299 | "eslint": "^7.32.0", 300 | "fork-ts-checker-webpack-plugin": "^6.5.3", 301 | "lodash": "^4.17.21", 302 | "marked": "^4.3.0", 303 | "mocha": "^10.8.2", 304 | "string-argv": "^0.3.2", 305 | "style-loader": "^3.3.4", 306 | "ts-loader": "9.4.1", 307 | "typescript": "^4.9.5", 308 | "vscode-notebook-error-overlay": "^1.0.1", 309 | "web3": "^4.15.0", 310 | "webpack": "^5.96.1", 311 | "webpack-cli": "^4.10.0" 312 | }, 313 | "dependencies": { 314 | "domutils": "^2.8.0", 315 | "open": "8.4.0", 316 | "path": "^0.12.7", 317 | "uuid": "^8.3.2", 318 | "vscode-languageclient": "8.0.2", 319 | "zeromq": "^6.1.2" 320 | } 321 | } 322 | -------------------------------------------------------------------------------- /src/extension/extension.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * vscode-wolfram 3 | * 4 | * Created by IDE support team on 10/01/24. 5 | * Copyright (c) 2024 Wolfram Research. All rights reserved. 6 | * 7 | */ 8 | 9 | const open = require('open'); 10 | const path = require('path'); 11 | const os = require('os'); 12 | const fs = require('fs'); 13 | import { FindKernel } from "./find-kernel"; 14 | 15 | 16 | import * as vscode from 'vscode'; 17 | import { WolframNotebookKernel } from './controller'; 18 | import { VSNBContentSerializer } from './serializer'; 19 | 20 | 21 | import { 22 | commands, 23 | window, 24 | DecorationOptions, 25 | Position, 26 | Range, 27 | Uri 28 | } from 'vscode'; 29 | 30 | import { 31 | LanguageClient, 32 | LanguageClientOptions, 33 | ServerOptions, 34 | TransportKind, 35 | ExecutableOptions 36 | } from 'vscode-languageclient/node'; 37 | 38 | const NOTEBOOK_TYPE = 'wolfram-notebook'; 39 | 40 | interface ImplicitTokenI { 41 | line: number; 42 | column: number; 43 | character: string 44 | } 45 | 46 | interface ImplicitTokensI { 47 | uri: string; 48 | tokens: ImplicitTokenI[] 49 | } 50 | 51 | let extensionKernel = new FindKernel(); 52 | 53 | let client: LanguageClient; 54 | 55 | let wolframTmpDir: string 56 | 57 | let kernel_initialized = false; 58 | 59 | 60 | let implicitTokensDecorationType = vscode.window.createTextEditorDecorationType({}); 61 | 62 | 63 | 64 | export function activate(context: vscode.ExtensionContext) { 65 | 66 | const config: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("wolfram", null); 67 | 68 | // Setup the menu 69 | 70 | context.subscriptions.push(commands.registerCommand('wolfram.OpenNotebook', (name: Uri) => { if (name) { open(name.fsPath) } })); 71 | context.subscriptions.push(commands.registerCommand('wolfram.DownloadWolframEngine', onDownloadWolframEngine)); 72 | 73 | context.subscriptions.push( 74 | vscode.commands.registerCommand( 75 | "wolfram.openConfigurations", 76 | async () => { 77 | await vscode.commands.executeCommand( 78 | "workbench.action.openSettings", 79 | "@ext:WolframResearch.wolfram" 80 | ) 81 | } 82 | ) 83 | ); 84 | 85 | 86 | let mainKernel = extensionKernel.resolveKernel(); 87 | 88 | const download_WEngine_MDString = new vscode.MarkdownString(`[Download Wolfram Engine for kernel support.](https://www.wolfram.com/engine/)`); 89 | 90 | download_WEngine_MDString.supportHtml = true; 91 | download_WEngine_MDString.isTrusted = true; 92 | 93 | /* 94 | kernel setting is Automatic and kernel could not be found. As LSP and Notebook kernels 95 | are same as mainKernel, these kernels will also be missing. So no point of going further. 96 | Show error message here. 97 | */ 98 | 99 | if(mainKernel === "kernel-not-found"){ 100 | vscode.window.showErrorMessage("Kernel is not found in the default location. Either change \"System Kernel\" in the configuration or " + download_WEngine_MDString.value) 101 | return 102 | }; 103 | 104 | if (!fs.existsSync(mainKernel)) { 105 | vscode.window.showErrorMessage("Kernel executable path does not exist: " + mainKernel + ". Either change \"System Kernel\" in the configuration or " + download_WEngine_MDString.value) 106 | return 107 | } 108 | 109 | // Add Terminal 110 | 111 | let terminalKernel = mainKernel; 112 | 113 | 114 | 115 | if(process.platform === "win32"){ 116 | terminalKernel = terminalKernel.replace("WolframKernel.exe", "wolfram.exe") 117 | }; 118 | 119 | context.subscriptions.push( 120 | commands.registerCommand( 121 | 'createWolframScriptTerminal', () => { 122 | 123 | // Reads systemKernel configuration value, and resolve the kernel 124 | // For defaulkt value, it will resolve to the actual path 125 | // For any kernel path is given in the configuration, it will be used 126 | 127 | const wolframscriptTerminal = window.createTerminal(`WolframKernel`, terminalKernel); 128 | wolframscriptTerminal.show() 129 | 130 | } 131 | ) 132 | ); 133 | 134 | 135 | 136 | 137 | // Setup Notebook client 138 | 139 | let nbKernelenabled = config.get("notebook.kernelEnabled", true); 140 | 141 | 142 | let controller = new WolframNotebookKernel(); 143 | 144 | if(nbKernelenabled){controller.launchKernel()}; 145 | 146 | 147 | context.subscriptions.push( 148 | commands.registerCommand( 149 | "wolfram.launchKernel", () => { 150 | 151 | if(nbKernelenabled){ 152 | client.outputChannel.appendLine("Launching Wolfram Kernel"); 153 | controller.launchKernel() 154 | } 155 | 156 | } 157 | ) 158 | ); 159 | 160 | 161 | context.subscriptions.push( 162 | vscode.workspace.registerNotebookSerializer( 163 | NOTEBOOK_TYPE, new VSNBContentSerializer() 164 | ), 165 | controller 166 | ); 167 | 168 | 169 | 170 | 171 | // Setup LSP client 172 | 173 | 174 | 175 | let enabled = config.get("lsp.serverEnabled", true); 176 | 177 | if (!enabled) { 178 | return 179 | } 180 | 181 | 182 | 183 | let lspcommand = config.get("advanced.lsp.command", ["lspKernel"]); 184 | let lspLog = config.get("advanced.lsp.ServerLogDirectory", "Off"); 185 | 186 | // Set lspcommand to use standalone LSP app. 187 | 188 | 189 | 190 | 191 | 192 | 193 | // Use the default option to launch LSPServer 194 | if (lspcommand[0] == "lspKernel") { 195 | 196 | // No log directory is to be used 197 | if (lspLog == "Off") { 198 | 199 | lspcommand = [ 200 | mainKernel, 201 | "-noinit", 202 | "-noprompt", 203 | "-nopaclet", 204 | "-noicon", 205 | "-nostartuppaclets", 206 | "-run", 207 | "Needs[\"LSPServer`\"];LSPServer`StartServer[]" 208 | ]; 209 | 210 | } 211 | 212 | // log directory is a folder location, use that as the log folder 213 | else{ 214 | 215 | lspcommand = [ 216 | mainKernel, 217 | "-noinit", 218 | "-noprompt", 219 | "-nopaclet", 220 | "-noicon", 221 | "-nostartuppaclets", 222 | "-run", 223 | "Needs[\"LSPServer`\"]; LSPServer`$LogLevel = 1; LSPServer`StartServer[\"" + lspLog + "\"]" 224 | ]; 225 | 226 | 227 | } 228 | 229 | }; 230 | 231 | 232 | let implicitTokens = config.get("lsp.implicitTokens", []); 233 | 234 | let semanticTokens = config.get("lsp.semanticTokens", false); 235 | 236 | wolframTmpDir = path.join(os.tmpdir(), "Wolfram") 237 | 238 | // 239 | // recursive option suppresses any directory-already-exists error 240 | // 241 | fs.mkdirSync(wolframTmpDir, { recursive: true }) 242 | 243 | 244 | let opts: ExecutableOptions = { 245 | cwd: wolframTmpDir 246 | }; 247 | 248 | 249 | let serverOptions: ServerOptions = { 250 | run: { 251 | transport: TransportKind.stdio, 252 | command: lspcommand[0], 253 | args: lspcommand.slice(1), 254 | options: opts 255 | }, 256 | debug: { 257 | transport: TransportKind.stdio, 258 | command: lspcommand[0], 259 | args: lspcommand.slice(1), 260 | options: opts 261 | } 262 | }; 263 | 264 | let clientOptions: LanguageClientOptions = { 265 | documentSelector: [{ scheme: 'file', language: 'wolfram' }], 266 | initializationOptions: { 267 | implicitTokens: implicitTokens, 268 | // bracketMatcher: bracketMatcher, 269 | // debugBracketMatcher: debugBracketMatcher 270 | semanticTokens: semanticTokens 271 | } 272 | }; 273 | 274 | 275 | 276 | client = new LanguageClient( 277 | 'wolfram', 278 | 'Wolfram-LSP', 279 | serverOptions, 280 | clientOptions 281 | ); 282 | 283 | // client.outputChannel.dispose(); 284 | 285 | let timeoutWarningEnabled = config.get("timeout_warning_enabled", true); 286 | 287 | if (timeoutWarningEnabled) { 288 | setTimeout(kernel_initialization_check_function, 15000, lspcommand); 289 | } 290 | 291 | client.start().then(() => { 292 | 293 | // 294 | // client.onStart() is called after initialize response, so it is appropriate to set kernel_initialized here 295 | // 296 | kernel_initialized = true; 297 | 298 | client.onNotification("textDocument/publishImplicitTokens", (params: ImplicitTokensI) => { 299 | 300 | let activeEditor = window.activeTextEditor; 301 | 302 | if (!activeEditor) { 303 | return; 304 | } 305 | 306 | let opts: DecorationOptions[] = []; 307 | 308 | params.tokens.forEach( (t) => { 309 | if (!activeEditor) { 310 | return; 311 | } 312 | 313 | const opt: DecorationOptions = { 314 | range: new Range(new Position(t.line - 1, t.column - 1), new Position(t.line - 1, t.column - 1)), 315 | renderOptions: { 316 | before: { 317 | contentText: implicitTokenCharToText(t.character), 318 | color: 'gray' 319 | } 320 | } 321 | }; 322 | 323 | opts.push(opt); 324 | }) 325 | 326 | 327 | activeEditor.setDecorations(implicitTokensDecorationType, opts); 328 | }); 329 | 330 | 331 | }); 332 | 333 | 334 | 335 | } 336 | 337 | 338 | 339 | function kernel_initialization_check_function(command: string[]) { 340 | 341 | 342 | if (kernel_initialized) { 343 | return 344 | } 345 | 346 | let kernel = command[0] 347 | 348 | // 349 | // User knows that the kernel did not start properly, so do not also display timeout error 350 | // 351 | if (!fs.existsSync(kernel)) { 352 | vscode.window.showErrorMessage("Kernel executable not found: " + kernel) 353 | return 354 | } 355 | 356 | // TODO: kill kernel, if possible 357 | 358 | let report = window.createOutputChannel("Wolfram Language Error Report"); 359 | 360 | report.appendLine("Language server kernel did not respond after 15 seconds.") 361 | report.appendLine("") 362 | report.appendLine("If the language kernel server did eventually start after this warning, then you can disable this warning with the timeout_warning_enabled setting.") 363 | report.appendLine("") 364 | report.appendLine("The most likely cause is that required paclets are not installed.") 365 | report.appendLine("") 366 | report.appendLine("The language server kernel process is hanging and may need to be killed manually.") 367 | report.appendLine("") 368 | report.appendLine("This is the command that was used:") 369 | report.appendLine(command.toString()) 370 | report.appendLine("") 371 | report.appendLine("To ensure that required paclets are installed and up-to-date, run this in a notebook:") 372 | report.appendLine("") 373 | report.appendLine("PacletInstall[\"CodeParser\"]") 374 | report.appendLine("PacletInstall[\"CodeInspector\"]") 375 | report.appendLine("PacletInstall[\"CodeFormatter\"]") 376 | report.appendLine("PacletInstall[\"LSPServer\"]") 377 | report.appendLine("") 378 | report.appendLine("To help diagnose the problem, run this in a notebook:") 379 | report.appendLine("") 380 | report.appendLine("Needs[\"LSPServer`\"]") 381 | report.append("LSPServer`RunServerDiagnostic[{") 382 | command.slice(0, -1).forEach( (a) => { 383 | // 384 | // important to replace \ -> \\ before replacing " -> \" 385 | // 386 | report.append("\"" + a.replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + "\"") 387 | report.append(", ") 388 | }) 389 | report.append("\"" + command[command.length - 1].replace(/\\/g, "\\\\").replace(/"/g, "\\\"") + "\"") 390 | report.append("}, ProcessDirectory -> \"") 391 | report.append(wolframTmpDir.replace(/\\/g, "\\\\")) 392 | report.append("\"]") 393 | report.appendLine("") 394 | report.appendLine("") 395 | report.appendLine("Fix any problems then restart and try again.") 396 | 397 | // 398 | // FIXME: it would be great to just include the above text in the error message. 399 | // But VSCode does not currently allow newlines in error messages 400 | // 401 | // Related issues: https://github.com/microsoft/vscode/issues/5454 402 | // 403 | window.showErrorMessage("Cannot start Wolfram language server. Check Output view and open the Wolfram Language Error Report output channel for more information. ") 404 | } 405 | 406 | 407 | function implicitTokenCharToText(c: string) { 408 | switch (c) { 409 | case "x": return "\xd7"; 410 | case "z": return " \xd7"; 411 | // add a space before Null because it looks nicer 412 | case "N": return " Null"; 413 | case "1": return "1"; 414 | case "A": return "All"; 415 | // add spaces before and after \u25a1 because it looks nicer 416 | case "e": return " \u25a1 "; 417 | case "f": return "\u25a1\xd7"; 418 | case "y": return "\xd71"; 419 | case "B": return "All\xd7"; 420 | case "C": return "All\xd71"; 421 | case "D": return "All1"; 422 | default: return " "; 423 | } 424 | } 425 | 426 | function onDownloadWolframEngine(): void { 427 | const uri: Uri = Uri.parse(`https://www.wolfram.com/engine/`); 428 | commands.executeCommand('vscode.open', uri); 429 | } 430 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2021 Wolfram Research Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software is furnished to do so, 8 | subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 15 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 17 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 18 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 19 | 20 | 21 | This project includes work covered by the following copyright and permission notices: 22 | 23 | Apache License 24 | Version 2.0, January 2004 25 | http://www.apache.org/licenses/ 26 | 27 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 28 | 29 | 1. Definitions. 30 | 31 | "License" shall mean the terms and conditions for use, reproduction, 32 | and distribution as defined by Sections 1 through 9 of this document. 33 | 34 | "Licensor" shall mean the copyright owner or entity authorized by 35 | the copyright owner that is granting the License. 36 | 37 | "Legal Entity" shall mean the union of the acting entity and all 38 | other entities that control, are controlled by, or are under common 39 | control with that entity. For the purposes of this definition, 40 | "control" means (i) the power, direct or indirect, to cause the 41 | direction or management of such entity, whether by contract or 42 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 43 | outstanding shares, or (iii) beneficial ownership of such entity. 44 | 45 | "You" (or "Your") shall mean an individual or Legal Entity 46 | exercising permissions granted by this License. 47 | 48 | "Source" form shall mean the preferred form for making modifications, 49 | including but not limited to software source code, documentation 50 | source, and configuration files. 51 | 52 | "Object" form shall mean any form resulting from mechanical 53 | transformation or translation of a Source form, including but 54 | not limited to compiled object code, generated documentation, 55 | and conversions to other media types. 56 | 57 | "Work" shall mean the work of authorship, whether in Source or 58 | Object form, made available under the License, as indicated by a 59 | copyright notice that is included in or attached to the work 60 | (an example is provided in the Appendix below). 61 | 62 | "Derivative Works" shall mean any work, whether in Source or Object 63 | form, that is based on (or derived from) the Work and for which the 64 | editorial revisions, annotations, elaborations, or other modifications 65 | represent, as a whole, an original work of authorship. For the purposes 66 | of this License, Derivative Works shall not include works that remain 67 | separable from, or merely link (or bind by name) to the interfaces of, 68 | the Work and Derivative Works thereof. 69 | 70 | "Contribution" shall mean any work of authorship, including 71 | the original version of the Work and any modifications or additions 72 | to that Work or Derivative Works thereof, that is intentionally 73 | submitted to Licensor for inclusion in the Work by the copyright owner 74 | or by an individual or Legal Entity authorized to submit on behalf of 75 | the copyright owner. For the purposes of this definition, "submitted" 76 | means any form of electronic, verbal, or written communication sent 77 | to the Licensor or its representatives, including but not limited to 78 | communication on electronic mailing lists, source code control systems, 79 | and issue tracking systems that are managed by, or on behalf of, the 80 | Licensor for the purpose of discussing and improving the Work, but 81 | excluding communication that is conspicuously marked or otherwise 82 | designated in writing by the copyright owner as "Not a Contribution." 83 | 84 | "Contributor" shall mean Licensor and any individual or Legal Entity 85 | on behalf of whom a Contribution has been received by Licensor and 86 | subsequently incorporated within the Work. 87 | 88 | 2. Grant of Copyright License. Subject to the terms and conditions of 89 | this License, each Contributor hereby grants to You a perpetual, 90 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 91 | copyright license to reproduce, prepare Derivative Works of, 92 | publicly display, publicly perform, sublicense, and distribute the 93 | Work and such Derivative Works in Source or Object form. 94 | 95 | 3. Grant of Patent License. Subject to the terms and conditions of 96 | this License, each Contributor hereby grants to You a perpetual, 97 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 98 | (except as stated in this section) patent license to make, have made, 99 | use, offer to sell, sell, import, and otherwise transfer the Work, 100 | where such license applies only to those patent claims licensable 101 | by such Contributor that are necessarily infringed by their 102 | Contribution(s) alone or by combination of their Contribution(s) 103 | with the Work to which such Contribution(s) was submitted. If You 104 | institute patent litigation against any entity (including a 105 | cross-claim or counterclaim in a lawsuit) alleging that the Work 106 | or a Contribution incorporated within the Work constitutes direct 107 | or contributory patent infringement, then any patent licenses 108 | granted to You under this License for that Work shall terminate 109 | as of the date such litigation is filed. 110 | 111 | 4. Redistribution. You may reproduce and distribute copies of the 112 | Work or Derivative Works thereof in any medium, with or without 113 | modifications, and in Source or Object form, provided that You 114 | meet the following conditions: 115 | 116 | (a) You must give any other recipients of the Work or 117 | Derivative Works a copy of this License; and 118 | 119 | (b) You must cause any modified files to carry prominent notices 120 | stating that You changed the files; and 121 | 122 | (c) You must retain, in the Source form of any Derivative Works 123 | that You distribute, all copyright, patent, trademark, and 124 | attribution notices from the Source form of the Work, 125 | excluding those notices that do not pertain to any part of 126 | the Derivative Works; and 127 | 128 | (d) If the Work includes a "NOTICE" text file as part of its 129 | distribution, then any Derivative Works that You distribute must 130 | include a readable copy of the attribution notices contained 131 | within such NOTICE file, excluding those notices that do not 132 | pertain to any part of the Derivative Works, in at least one 133 | of the following places: within a NOTICE text file distributed 134 | as part of the Derivative Works; within the Source form or 135 | documentation, if provided along with the Derivative Works; or, 136 | within a display generated by the Derivative Works, if and 137 | wherever such third-party notices normally appear. The contents 138 | of the NOTICE file are for informational purposes only and 139 | do not modify the License. You may add Your own attribution 140 | notices within Derivative Works that You distribute, alongside 141 | or as an addendum to the NOTICE text from the Work, provided 142 | that such additional attribution notices cannot be construed 143 | as modifying the License. 144 | 145 | You may add Your own copyright statement to Your modifications and 146 | may provide additional or different license terms and conditions 147 | for use, reproduction, or distribution of Your modifications, or 148 | for any such Derivative Works as a whole, provided Your use, 149 | reproduction, and distribution of the Work otherwise complies with 150 | the conditions stated in this License. 151 | 152 | 5. Submission of Contributions. Unless You explicitly state otherwise, 153 | any Contribution intentionally submitted for inclusion in the Work 154 | by You to the Licensor shall be under the terms and conditions of 155 | this License, without any additional terms or conditions. 156 | Notwithstanding the above, nothing herein shall supersede or modify 157 | the terms of any separate license agreement you may have executed 158 | with Licensor regarding such Contributions. 159 | 160 | 6. Trademarks. This License does not grant permission to use the trade 161 | names, trademarks, service marks, or product names of the Licensor, 162 | except as required for reasonable and customary use in describing the 163 | origin of the Work and reproducing the content of the NOTICE file. 164 | 165 | 7. Disclaimer of Warranty. Unless required by applicable law or 166 | agreed to in writing, Licensor provides the Work (and each 167 | Contributor provides its Contributions) on an "AS IS" BASIS, 168 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 169 | implied, including, without limitation, any warranties or conditions 170 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 171 | PARTICULAR PURPOSE. You are solely responsible for determining the 172 | appropriateness of using or redistributing the Work and assume any 173 | risks associated with Your exercise of permissions under this License. 174 | 175 | 8. Limitation of Liability. In no event and under no legal theory, 176 | whether in tort (including negligence), contract, or otherwise, 177 | unless required by applicable law (such as deliberate and grossly 178 | negligent acts) or agreed to in writing, shall any Contributor be 179 | liable to You for damages, including any direct, indirect, special, 180 | incidental, or consequential damages of any character arising as a 181 | result of this License or out of the use or inability to use the 182 | Work (including but not limited to damages for loss of goodwill, 183 | work stoppage, computer failure or malfunction, or any and all 184 | other commercial damages or losses), even if such Contributor 185 | has been advised of the possibility of such damages. 186 | 187 | 9. Accepting Warranty or Additional Liability. While redistributing 188 | the Work or Derivative Works thereof, You may choose to offer, 189 | and charge a fee for, acceptance of support, warranty, indemnity, 190 | or other liability obligations and/or rights consistent with this 191 | License. However, in accepting such obligations, You may act only 192 | on Your own behalf and on Your sole responsibility, not on behalf 193 | of any other Contributor, and only if You agree to indemnify, 194 | defend, and hold each Contributor harmless for any liability 195 | incurred by, or claims asserted against, such Contributor by reason 196 | of your accepting any such warranty or additional liability. 197 | 198 | END OF TERMS AND CONDITIONS 199 | 200 | APPENDIX: How to apply the Apache License to your work. 201 | 202 | To apply the Apache License to your work, attach the following 203 | boilerplate notice, with the fields enclosed by brackets "[]" 204 | replaced with your own identifying information. (Don't include 205 | the brackets!) The text should be enclosed in the appropriate 206 | comment syntax for the file format. We also recommend that a 207 | file or class name and description of purpose be included on the 208 | same "printed page" as the copyright notice for easier 209 | identification within third-party archives. 210 | 211 | Copyright [yyyy] [name of copyright owner] 212 | 213 | Licensed under the Apache License, Version 2.0 (the "License"); 214 | you may not use this file except in compliance with the License. 215 | You may obtain a copy of the License at 216 | 217 | http://www.apache.org/licenses/LICENSE-2.0 218 | 219 | Unless required by applicable law or agreed to in writing, software 220 | distributed under the License is distributed on an "AS IS" BASIS, 221 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 222 | See the License for the specific language governing permissions and 223 | limitations under the License. 224 | -------------------------------------------------------------------------------- /themes/wolfram-Default.json: -------------------------------------------------------------------------------- 1 | 2 | // Theme created following Wolfram frontend 3 | // modified from source: solarized-light 4 | // https://github.com/microsoft/vscode/blob/main/extensions/theme-solarized-light/themes/solarized-light-color-theme.json 5 | { 6 | "name": "Wolfram (Default)", 7 | "$schema": "vscode://schemas/color-theme", 8 | "type": "light", 9 | "semanticHighlighting": true, 10 | "semanticTokenColors": { 11 | // Module, With and Block variables 12 | "variable.Module": "#448959", 13 | "variable.Block": "#448959", 14 | "constant.With": "#04751b", 15 | "variable.shadowed": "#f2430e", 16 | "variable.error": "#ff0000", 17 | "variable.unused": "#888888", 18 | "parameter": "#448959", 19 | "parameter.shadowed": "#f2430e", 20 | "parameter.error": "#ff0000", 21 | "parameter.unused": "#888888", 22 | "constant.shadowed": "#448959", 23 | "constant.error": "#ff0000", 24 | "constant.unused": "#888888" 25 | }, 26 | "tokenColors": [ 27 | { 28 | "settings": { 29 | "foreground": "#0530c4" 30 | } 31 | }, 32 | { 33 | "name": "Built-in constant", 34 | "scope": [ 35 | "constant.language", 36 | "meta.preprocessor" 37 | ], 38 | "settings": { 39 | // "foreground": "#B58900" 40 | "fontStyle": "bold", 41 | "foreground": "#0b0b0b" 42 | } 43 | }, 44 | { 45 | "scope": [ 46 | "meta.embedded", 47 | "source.groovy.embedded", 48 | "string meta.image.inline.markdown", 49 | "variable.legacy.builtin.python" 50 | ], 51 | "settings": { 52 | "foreground": "#657B83" 53 | } 54 | }, 55 | { 56 | "name": "Comment", 57 | "scope": "comment", 58 | "settings": { 59 | "fontStyle": "italic", 60 | "foreground": "#4595ae" 61 | } 62 | }, 63 | { 64 | "name": "String", 65 | "scope": "string", 66 | "settings": { 67 | "foreground": "#191919" 68 | } 69 | }, 70 | { 71 | "name": "Regexp", 72 | "scope": "string.regexp", 73 | "settings": { 74 | "foreground": "#DC322F" 75 | } 76 | }, 77 | { 78 | "name": "Number", 79 | "scope": "constant.numeric", 80 | "settings": { 81 | // "foreground": "#D33682" 82 | "fontStyle": "bold", 83 | "foreground": "#0b0b0b" 84 | } 85 | }, 86 | { 87 | "name": "Variable", 88 | "scope": [ 89 | "variable.language", 90 | "variable.other" 91 | ], 92 | "settings": { 93 | // "foreground": "#268BD2" 94 | "foreground": "#130a87" 95 | } 96 | }, 97 | { 98 | "name": "Keyword", 99 | "scope": "keyword", 100 | "settings": { 101 | "foreground": "#000000" 102 | } 103 | }, 104 | { 105 | "name": "Storage", 106 | "scope": "storage", 107 | "settings": { 108 | "fontStyle": "bold", 109 | "foreground": "#586E75" 110 | } 111 | }, 112 | { 113 | "name": "Class name", 114 | "scope": [ 115 | "entity.name.class", 116 | "entity.name.type", 117 | "entity.name.namespace", 118 | "entity.name.scope-resolution" 119 | ], 120 | "settings": { 121 | "fontStyle": "", 122 | "foreground": "#CB4B16" 123 | } 124 | }, 125 | { 126 | "name": "Variable start", 127 | "scope": "punctuation.definition.variable", 128 | "settings": { 129 | "foreground": "#859900" 130 | } 131 | }, 132 | { 133 | "name": "Embedded code markers", 134 | "scope": [ 135 | "punctuation.section.embedded.begin", 136 | "punctuation.section.embedded.end" 137 | ], 138 | "settings": { 139 | "foreground": "#DC322F" 140 | } 141 | }, 142 | 143 | { 144 | "name": "Support.construct", 145 | "scope": [ 146 | "support.function.construct", 147 | "keyword.other.new" 148 | ], 149 | "settings": { 150 | "foreground": "#CB4B16" 151 | } 152 | }, 153 | { 154 | "name": "User-defined constant", 155 | "scope": [ 156 | "constant.character", 157 | "constant.other" 158 | ], 159 | "settings": { 160 | "foreground": "#CB4B16" 161 | } 162 | }, 163 | { 164 | "name": "Inherited class", 165 | "scope": "entity.other.inherited-class", 166 | "settings": { 167 | "foreground": "#6C71C4" 168 | } 169 | }, 170 | { 171 | "name": "Function argument", 172 | "scope": "variable.parameter", 173 | "settings": { 174 | } 175 | }, 176 | { 177 | "name": "Tag name", 178 | "scope": "entity.name.tag", 179 | "settings": { 180 | "foreground": "#268BD2" 181 | } 182 | }, 183 | { 184 | "name": "Tag start/end", 185 | "scope": "punctuation.definition.tag", 186 | "settings": { 187 | "foreground": "#93A1A1" 188 | } 189 | }, 190 | { 191 | "name": "Tag attribute", 192 | "scope": "entity.other.attribute-name", 193 | "settings": { 194 | "foreground": "#93A1A1" 195 | } 196 | }, 197 | { 198 | "name": "Library function", 199 | "scope": "support.function", 200 | "settings": { 201 | // "foreground": "#268BD2" 202 | // built-in functions 203 | "fontStyle": "bold", 204 | "foreground": "#0b0b0b" 205 | } 206 | }, 207 | { 208 | "name": "Function name", 209 | "scope": "entity.name.function", 210 | "settings": { 211 | // "foreground": "#268BD2" 212 | "foreground": "#2347cc" 213 | } 214 | }, 215 | { 216 | "name": "User function", 217 | "scope": "symbol.unrecognized", 218 | "settings": { 219 | // "foreground": "#268BD2" 220 | // built-in functions 221 | "fontStyle": "bold", 222 | "foreground": "#0530c4" 223 | } 224 | }, 225 | { 226 | "name": "Library function", 227 | "scope": "variable.function.", 228 | "settings": { 229 | // "foreground": "#268BD2" 230 | // built-in functions 231 | "fontStyle": "bold", 232 | "foreground": "#0530c4" 233 | } 234 | }, 235 | { 236 | "name": "Continuation", 237 | "scope": "punctuation.separator.continuation", 238 | "settings": { 239 | "foreground": "#DC322F" 240 | } 241 | }, 242 | { 243 | "name": "Library constant", 244 | "scope": [ 245 | "support.constant", 246 | "support.variable" 247 | ], 248 | "settings": {} 249 | }, 250 | { 251 | "name": "Library class/type", 252 | "scope": [ 253 | "support.type", 254 | "support.class" 255 | ], 256 | "settings": { 257 | "foreground": "#859900" 258 | } 259 | }, 260 | { 261 | "name": "Library Exception", 262 | "scope": "support.type.exception", 263 | "settings": { 264 | "foreground": "#CB4B16" 265 | } 266 | }, 267 | { 268 | "name": "Library variable", 269 | "scope": "support.other.variable", 270 | "settings": {} 271 | }, 272 | { 273 | "name": "Invalid", 274 | "scope": "invalid", 275 | "settings": { 276 | "foreground": "#DC322F" 277 | } 278 | }, 279 | { 280 | "name": "diff: header", 281 | "scope": [ 282 | "meta.diff", 283 | "meta.diff.header" 284 | ], 285 | "settings": { 286 | "fontStyle": "italic", 287 | "foreground": "#268BD2" 288 | } 289 | }, 290 | { 291 | "name": "diff: deleted", 292 | "scope": "markup.deleted", 293 | "settings": { 294 | "fontStyle": "", 295 | "foreground": "#DC322F" 296 | } 297 | }, 298 | { 299 | "name": "diff: changed", 300 | "scope": "markup.changed", 301 | "settings": { 302 | "fontStyle": "", 303 | "foreground": "#CB4B16" 304 | } 305 | }, 306 | { 307 | "name": "diff: inserted", 308 | "scope": "markup.inserted", 309 | "settings": { 310 | "foreground": "#859900" 311 | } 312 | }, 313 | { 314 | "name": "Markup Quote", 315 | "scope": "markup.quote", 316 | "settings": { 317 | "foreground": "#859900" 318 | } 319 | }, 320 | { 321 | "name": "Markup Lists", 322 | "scope": "markup.list", 323 | "settings": { 324 | "foreground": "#B58900" 325 | } 326 | }, 327 | { 328 | "name": "Markup Styling", 329 | "scope": [ 330 | "markup.bold", 331 | "markup.italic" 332 | ], 333 | "settings": { 334 | "foreground": "#D33682" 335 | } 336 | }, 337 | { 338 | "name": "Markup: Strong", 339 | "scope": "markup.bold", 340 | "settings": { 341 | "fontStyle": "bold" 342 | } 343 | }, 344 | { 345 | "name": "Markup: Emphasis", 346 | "scope": "markup.italic", 347 | "settings": { 348 | "fontStyle": "italic" 349 | } 350 | }, 351 | { 352 | "scope": "markup.strikethrough", 353 | "settings": { 354 | "fontStyle": "strikethrough" 355 | } 356 | }, 357 | { 358 | "name": "Markup Inline", 359 | "scope": "markup.inline.raw", 360 | "settings": { 361 | "fontStyle": "", 362 | "foreground": "#2AA198" 363 | } 364 | }, 365 | { 366 | "name": "Markup Headings", 367 | "scope": "markup.heading", 368 | "settings": { 369 | "fontStyle": "bold", 370 | "foreground": "#268BD2" 371 | } 372 | }, 373 | { 374 | "name": "Markup Setext Header", 375 | "scope": "markup.heading.setext", 376 | "settings": { 377 | "fontStyle": "", 378 | "foreground": "#268BD2" 379 | } 380 | } 381 | ], 382 | "colors": { 383 | // Base 384 | // "foreground": "", 385 | "focusBorder": "#b49471", 386 | // "contrastActiveBorder": "", 387 | // "contrastBorder": "", 388 | // "widget.shadow": "", 389 | "input.background": "#DDD6C1", 390 | // "input.border": "", 391 | "input.foreground": "#586E75", 392 | "input.placeholderForeground": "#586E75AA", 393 | "inputOption.activeBorder": "#D3AF86", 394 | 395 | "badge.background": "#B58900AA", 396 | "progressBar.background": "#B58900", 397 | // "dropdown.background": "#EEE8D5", 398 | // "dropdown.background": "#e72222", 399 | // "dropdown.foreground": "", 400 | 401 | // output dropdown window 402 | "dropdown.border": "#D3AF86", 403 | 404 | "button.background": "#AC9D57", 405 | // "button.foreground": "", 406 | "selection.background": "#94a1eb", 407 | "list.activeSelectionBackground": "#DFCA88", 408 | "list.activeSelectionForeground": "#6C6C6C", 409 | "quickInputList.focusBackground": "#DFCA8866", 410 | // "list.hoverBackground": "#DFCA8844", 411 | "list.hoverBackground": "#dc88df44", 412 | "list.inactiveSelectionBackground": "#D1CBB8", 413 | "list.highlightForeground": "#B58900", 414 | // "scrollbar.shadow": "", 415 | 416 | // "scrollbarSlider.activeBackground": "", 417 | "scrollbarSlider.background": "#EEE8D5", 418 | "scrollbarSlider.hoverBackground": "#EEE8D5", 419 | "scrollbarSlider.activeBackground": "#B58900", 420 | 421 | // Editor 422 | 423 | "editor.background": "#ffffff", 424 | "notebook.cellEditorBackground": "#FFFFFF", 425 | "editorWidget.background": "#EEE8D5", 426 | "editorCursor.foreground": "#657B83", 427 | "editorWhitespace.foreground": "#586E7580", 428 | 429 | "editorIndentGuide.activeBackground1": "#081E2580", 430 | "editorHoverWidget.background": "#eae4e3", 431 | "editorLineNumber.activeForeground": "#000000", 432 | // The word over which the mouse is hovering 433 | "editor.hoverHighlightBackground": "#eae4e3CC", 434 | // Line where the cursor is: No line here 435 | "editor.lineHighlightBorder": "#FFFFFF", 436 | 437 | 438 | // Workbench: Title 439 | 440 | // Wolfram: titlebar settings 441 | "titleBar.activeBackground": "#f7f3e8", 442 | "titleBar.activeForeground": "#584c27", 443 | 444 | "titleBar.inactiveBackground": "#EEE8D5", 445 | "titleBar.inactiveForeground": "#586E75", 446 | 447 | 448 | 449 | // Workbench: Editors 450 | // "editorGroupHeader.noTabsBackground": "", 451 | "editorGroup.border": "#DDD6C1", 452 | "editorGroup.dropBackground": "#DDD6C1AA", 453 | "editorGroupHeader.tabsBackground": "#D9D2C2", 454 | // Workbench: Tabs 455 | "tab.border": "#DDD6C1", 456 | "tab.activeBackground": "#FDF6E3", 457 | "tab.inactiveBackground": "#D3CBB7", 458 | 459 | "tab.inactiveForeground": "#586E75", 460 | "tab.activeModifiedBorder": "#cb4b16", 461 | 462 | // "tab.activeBackground": "", 463 | // "tab.activeForeground": "", 464 | // "tab.inactiveForeground": "", 465 | "tab.lastPinnedBorder": "#FDF6E3", 466 | // Workbench: Activity Bar 467 | "activityBar.background": "#DDD6C1", 468 | "activityBar.foreground": "#584c27", 469 | "activityBarBadge.background": "#B58900", 470 | // "activityBarBadge.foreground": "", 471 | // Workbench: Panel 472 | // "panel.background": "", 473 | "panel.border": "#DDD6C1", 474 | // "panelTitle.activeBorder": "#ff0000", 475 | 476 | // Text on the terminal bar 477 | // "panelTitle.activeForeground": "#ff0000", 478 | // "panelTitle.inactiveForeground": "", 479 | 480 | // Workbench: Status Bar 481 | "statusBar.foreground": "#586E75", 482 | "statusBar.background": "#EEE8D5", 483 | 484 | "statusBar.debuggingBackground": "#EEE8D5", 485 | "statusBar.noFolderBackground": "#EEE8D5", 486 | "statusBarItem.remoteBackground": "#AC9D57", 487 | "ports.iconRunningProcessForeground": "#2AA19899", 488 | "statusBarItem.prominentBackground": "#DDD6C1", 489 | "statusBarItem.prominentHoverBackground": "#d413b499", 490 | 491 | // "statusBarItem.activeBackground": "", 492 | // "statusBarItem.hoverBackground": "", 493 | // Workbench: Debug 494 | "debugToolBar.background": "#DDD6C1", 495 | "debugExceptionWidget.background": "#DDD6C1", 496 | "debugExceptionWidget.border": "#AB395B", 497 | // Workbench: Quick Open 498 | // "pickerGroup.border": "#2AA19899", 499 | // "pickerGroup.foreground": "#2AA19899", 500 | // Extensions 501 | "extensionButton.prominentBackground": "#b58900", 502 | "extensionButton.prominentHoverBackground": "#584c27aa", 503 | // Workbench: Terminal 504 | // Colors sourced from the official palette http://ethanschoonover.com/solarized 505 | "terminal.ansiBlack": "#073642", 506 | "terminal.ansiRed": "#dc322f", 507 | "terminal.ansiGreen": "#859900", 508 | "terminal.ansiYellow": "#b58900", 509 | "terminal.ansiBlue": "#268bd2", 510 | "terminal.ansiMagenta": "#d33682", 511 | "terminal.ansiCyan": "#2aa198", 512 | "terminal.ansiWhite": "#eee8d5", 513 | "terminal.ansiBrightBlack": "#002b36", 514 | "terminal.ansiBrightRed": "#cb4b16", 515 | "terminal.ansiBrightGreen": "#586e75", 516 | "terminal.ansiBrightYellow": "#657b83", 517 | "terminal.ansiBrightBlue": "#839496", 518 | "terminal.ansiBrightMagenta": "#6c71c4", 519 | "terminal.ansiBrightCyan": "#93a1a1", 520 | "terminal.ansiBrightWhite": "#fdf6e3", 521 | // Set terminal background explicitly, otherwise selection becomes invisible when the 522 | // terminal is in the side bar 523 | // "terminal.background": "#FDF6E3", 524 | "terminal.background": "#FFFFFF", 525 | // Interactive Playground 526 | "walkThrough.embeddedEditorBackground": "#00000014" 527 | } 528 | } 529 | 530 | -------------------------------------------------------------------------------- /themes/wolfram-dark-rainbow.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "vscode://schemas/color-theme", 3 | "type": "dark", 4 | "semanticHighlighting": true, 5 | "semanticTokenColors": { 6 | "variable.Module": "#d8a265", 7 | "variable.Block": "#d8b64f", 8 | "variable.shadowed": "#f2430e", 9 | "variable.error": "#ff0000", 10 | "variable.unused": "#888888", 11 | "parameter": "#e4861b", 12 | "parameter.shadowed": "#f2430e", 13 | "parameter.error": "#ff0000", 14 | "parameter.unused": "#888888", 15 | "constant.With": "#ae81ff", 16 | "constant.shadowed": "#f2430e", 17 | "constant.error": "#ff0000", 18 | "constant.unused": "#888888" 19 | }, 20 | "tokenColors": [ 21 | { 22 | "scope": [ 23 | "symbol.unrecognized" 24 | ], 25 | "settings": { 26 | "foreground": "#F8F8F2" 27 | } 28 | }, 29 | { 30 | "scope": [ 31 | "keyword.operator.Function", 32 | "keyword.operator.BlankNullSequence", 33 | "keyword.operator.BlankSequence", 34 | "keyword.operator.Optional", 35 | "keyword.operator.Blank", 36 | "keyword.other.Slot", 37 | "keyword.other.SlotSequence" 38 | ], 39 | "settings": { 40 | "foreground": "#e4861b" 41 | } 42 | }, 43 | { 44 | "scope": "keyword.operator", 45 | "settings": { 46 | "foreground": "#99cc99" 47 | } 48 | }, 49 | { 50 | "scope": "punctuation.section", 51 | "settings": { 52 | "foreground": "#cccccc" 53 | } 54 | }, 55 | 56 | { 57 | "name": "Comment", 58 | "scope": "comment", 59 | "settings": { 60 | "foreground": "#75715E" 61 | } 62 | }, 63 | { 64 | "name": "Number", 65 | "scope": "constant.numeric", 66 | "settings": { 67 | "foreground": "#AE81FF" 68 | } 69 | }, 70 | { 71 | "name": "Built-in constant", 72 | "scope": "constant.language", 73 | "settings": { 74 | "foreground": "#AE81FF" 75 | } 76 | }, 77 | { 78 | "name": "User-defined constant", 79 | "scope": [ 80 | "constant.character", 81 | "constant.other" 82 | ], 83 | "settings": { 84 | "foreground": "#AE81FF" 85 | } 86 | }, 87 | { 88 | "name": "Variable", 89 | "scope": "variable", 90 | "settings": { 91 | "fontStyle": "" 92 | } 93 | }, 94 | { 95 | "name": "Keyword", 96 | "scope": "keyword", 97 | "settings": { 98 | "foreground": "#F92672" 99 | } 100 | }, 101 | { 102 | "name": "Storage", 103 | "scope": "storage", 104 | "settings": { 105 | "fontStyle": "", 106 | "foreground": "#F92672" 107 | } 108 | }, 109 | { 110 | "name": "Storage type", 111 | "scope": "storage.type", 112 | "settings": { 113 | "fontStyle": "italic", 114 | "foreground": "#66D9EF" 115 | } 116 | }, 117 | { 118 | "name": "Class name", 119 | "scope": "entity.name.class", 120 | "settings": { 121 | "fontStyle": "underline", 122 | "foreground": "#A6E22E" 123 | } 124 | }, 125 | { 126 | "name": "Inherited class", 127 | "scope": "entity.other.inherited-class", 128 | "settings": { 129 | "fontStyle": "italic underline", 130 | "foreground": "#A6E22E" 131 | } 132 | }, 133 | { 134 | "name": "Function name", 135 | "scope": "entity.name.function", 136 | "settings": { 137 | "fontStyle": "", 138 | "foreground": "#A6E22E" 139 | } 140 | }, 141 | { 142 | "name": "User function", 143 | "scope": "variable.function", 144 | "settings": { 145 | "fontStyle": "", 146 | "foreground": "#BBEEF8" 147 | } 148 | }, 149 | { 150 | "name": "Function argument", 151 | "scope": "variable.parameter", 152 | "settings": { 153 | "fontStyle": "italic", 154 | "foreground": "#FD971F" 155 | } 156 | }, 157 | { 158 | "name": "Tag name", 159 | "scope": "entity.name.tag", 160 | "settings": { 161 | "fontStyle": "", 162 | "foreground": "#F92672" 163 | } 164 | }, 165 | { 166 | "name": "Tag attribute", 167 | "scope": "entity.other.attribute-name", 168 | "settings": { 169 | "fontStyle": "", 170 | "foreground": "#A6E22E" 171 | } 172 | }, 173 | 174 | { 175 | "name": "Library function", 176 | "scope": "support.function", 177 | "settings": { 178 | "fontStyle": "", 179 | "foreground": "#66D9EF" 180 | } 181 | }, 182 | { 183 | "name": "Undocumented", 184 | "scope": "support.function.undocumented", 185 | "settings": { 186 | "foreground": "#eeeeee" 187 | } 188 | }, 189 | { 190 | "name": "Library constant", 191 | "scope": "support.constant", 192 | "settings": { 193 | "fontStyle": "", 194 | "foreground": "#66D9EF" 195 | } 196 | }, 197 | { 198 | "name": "Library class/type", 199 | "scope": [ 200 | "support.type", 201 | "support.class" 202 | ], 203 | "settings": { 204 | "fontStyle": "italic", 205 | "foreground": "#66D9EF" 206 | } 207 | }, 208 | { 209 | "name": "Library variable", 210 | "scope": "support.other.variable", 211 | "settings": { 212 | "fontStyle": "" 213 | } 214 | }, 215 | { 216 | "name": "Invalid", 217 | "scope": "invalid", 218 | "settings": { 219 | "foreground": "#FF0000" 220 | } 221 | }, 222 | { 223 | "scope": [ 224 | "meta.embedded", 225 | "source.groovy.embedded" 226 | ], 227 | "settings": { 228 | "foreground": "#F8F8F2" 229 | } 230 | }, 231 | { 232 | "scope": "comment", 233 | "settings": { 234 | "foreground": "#88846F" 235 | } 236 | }, 237 | { 238 | "scope": "punctuation.definition.string.begin", 239 | "settings": { 240 | "foreground": "#99924d" 241 | } 242 | }, 243 | { 244 | "scope": "punctuation.definition.string.end", 245 | "settings": { 246 | "foreground": "#99924d" 247 | } 248 | }, 249 | { 250 | "scope": "string", 251 | "settings": { 252 | "foreground": "#E6DB74" 253 | } 254 | }, 255 | { 256 | "scope": [ 257 | "punctuation.definition.template-expression", 258 | "punctuation.section.embedded" 259 | ], 260 | "settings": { 261 | "foreground": "#F92672" 262 | } 263 | }, 264 | { 265 | "scope": [ 266 | "meta.template.expression" 267 | ], 268 | "settings": { 269 | "foreground": "#F8F8F2" 270 | } 271 | }, 272 | { 273 | "scope": "constant.numeric", 274 | "settings": { 275 | "foreground": "#AE81FF" 276 | } 277 | }, 278 | { 279 | "scope": "constant.language", 280 | "settings": { 281 | "foreground": "#AE81FF" 282 | } 283 | }, 284 | { 285 | "scope": "constant.character, constant.other", 286 | "settings": { 287 | "foreground": "#AE81FF" 288 | } 289 | }, 290 | { 291 | "scope": "variable", 292 | "settings": { 293 | "foreground": "#F8F8F2", 294 | "fontStyle": "" 295 | } 296 | }, 297 | { 298 | "scope": "keyword", 299 | "settings": { 300 | "foreground": "#F92672" 301 | } 302 | }, 303 | { 304 | "scope": "storage", 305 | "settings": { 306 | "foreground": "#F92672", 307 | "fontStyle": "" 308 | } 309 | }, 310 | { 311 | "scope": "storage.type", 312 | "settings": { 313 | "foreground": "#66D9EF", 314 | "fontStyle": "italic" 315 | } 316 | }, 317 | { 318 | "scope": "entity.name.type, entity.name.class, entity.name.namespace, entity.name.scope-resolution", 319 | "settings": { 320 | "foreground": "#A6E22E", 321 | "fontStyle": "underline" 322 | } 323 | }, 324 | { 325 | "scope": "entity.other.inherited-class", 326 | "settings": { 327 | "foreground": "#A6E22E", 328 | "fontStyle": "italic underline" 329 | } 330 | }, 331 | { 332 | "scope": "entity.name.function", 333 | "settings": { 334 | "foreground": "#A6E22E", 335 | "fontStyle": "" 336 | } 337 | }, 338 | { 339 | "scope": "variable.parameter", 340 | "settings": { 341 | "foreground": "#FD971F", 342 | "fontStyle": "italic" 343 | } 344 | }, 345 | { 346 | "scope": "entity.name.tag", 347 | "settings": { 348 | "foreground": "#F92672", 349 | "fontStyle": "" 350 | } 351 | }, 352 | { 353 | "scope": "entity.other.attribute-name", 354 | "settings": { 355 | "foreground": "#A6E22E", 356 | "fontStyle": "" 357 | } 358 | }, 359 | { 360 | "scope": "support.constant", 361 | "settings": { 362 | "foreground": "#66D9EF", 363 | "fontStyle": "" 364 | } 365 | }, 366 | { 367 | "scope": "support.type, support.class", 368 | "settings": { 369 | "foreground": "#66D9EF", 370 | "fontStyle": "italic" 371 | } 372 | }, 373 | { 374 | "scope": "support.other.variable", 375 | "settings": { 376 | "fontStyle": "" 377 | } 378 | }, 379 | { 380 | "scope": "meta.structure.dictionary.json string.quoted.double.json", 381 | "settings": { 382 | "foreground": "#CFCFC2" 383 | } 384 | }, 385 | { 386 | "scope": "meta.diff, meta.diff.header", 387 | "settings": { 388 | "foreground": "#75715E" 389 | } 390 | }, 391 | { 392 | "scope": "markup.deleted", 393 | "settings": { 394 | "foreground": "#F92672" 395 | } 396 | }, 397 | { 398 | "scope": "markup.inserted", 399 | "settings": { 400 | "foreground": "#A6E22E" 401 | } 402 | }, 403 | { 404 | "scope": "markup.changed", 405 | "settings": { 406 | "foreground": "#E6DB74" 407 | } 408 | }, 409 | { 410 | "scope": "constant.numeric.line-number.find-in-files - match", 411 | "settings": { 412 | "foreground": "#AE81FFA0" 413 | } 414 | }, 415 | { 416 | "scope": "entity.name.filename.find-in-files", 417 | "settings": { 418 | "foreground": "#E6DB74" 419 | } 420 | }, 421 | { 422 | "scope": "markup.quote", 423 | "settings": { 424 | "foreground": "#F92672" 425 | } 426 | }, 427 | { 428 | "scope": "markup.list", 429 | "settings": { 430 | "foreground": "#E6DB74" 431 | } 432 | }, 433 | { 434 | "scope": "markup.bold, markup.italic", 435 | "settings": { 436 | "foreground": "#66D9EF" 437 | } 438 | }, 439 | { 440 | "scope": "markup.inline.raw", 441 | "settings": { 442 | "foreground": "#FD971F", 443 | "fontStyle": "" 444 | } 445 | }, 446 | { 447 | "scope": "markup.heading", 448 | "settings": { 449 | "foreground": "#A6E22E" 450 | } 451 | }, 452 | { 453 | "scope": "markup.heading.setext", 454 | "settings": { 455 | "foreground": "#A6E22E", 456 | "fontStyle": "bold" 457 | } 458 | }, 459 | { 460 | "scope": "markup.heading.markdown", 461 | "settings": { 462 | "fontStyle": "bold" 463 | } 464 | }, 465 | { 466 | "scope": "markup.quote.markdown", 467 | "settings": { 468 | "foreground": "#75715E", 469 | "fontStyle": "italic" 470 | } 471 | }, 472 | { 473 | "scope": "markup.bold.markdown", 474 | "settings": { 475 | "fontStyle": "bold" 476 | } 477 | }, 478 | { 479 | "scope": "string.other.link.title.markdown,string.other.link.description.markdown", 480 | "settings": { 481 | "foreground": "#AE81FF" 482 | } 483 | }, 484 | { 485 | "scope": "markup.underline.link.markdown,markup.underline.link.image.markdown", 486 | "settings": { 487 | "foreground": "#E6DB74" 488 | } 489 | }, 490 | { 491 | "scope": "markup.italic.markdown", 492 | "settings": { 493 | "fontStyle": "italic" 494 | } 495 | }, 496 | { 497 | "scope": "markup.list.unnumbered.markdown, markup.list.numbered.markdown", 498 | "settings": { 499 | "foreground": "#F8F8F2" 500 | } 501 | }, 502 | { 503 | "scope": [ 504 | "punctuation.definition.list.begin.markdown" 505 | ], 506 | "settings": { 507 | "foreground": "#A6E22E" 508 | } 509 | }, 510 | { 511 | "scope": "token.info-token", 512 | "settings": { 513 | "foreground": "#6796E6" 514 | } 515 | }, 516 | { 517 | "scope": "token.warn-token", 518 | "settings": { 519 | "foreground": "#CD9731" 520 | } 521 | }, 522 | { 523 | "scope": "token.error-token", 524 | "settings": { 525 | "foreground": "#F44747" 526 | } 527 | }, 528 | { 529 | "scope": "token.debug-token", 530 | "settings": { 531 | "foreground": "#B267E6" 532 | } 533 | }, 534 | { 535 | "scope": "variable.language", 536 | "settings": { 537 | "foreground": "#FD971F" 538 | } 539 | } 540 | ], 541 | "colors": { 542 | "editor.background": "#1E1E1E", 543 | "editorCursor.foreground": "#F8F8F0", 544 | "editor.foreground": "#F8F8F2", 545 | "editorWhitespace.foreground": "#3B3A32", 546 | "editor.lineHighlightBackground": "#3E3D32", 547 | "editor.selectionBackground": "#49483E", 548 | "activityBar.background": "#272822", 549 | "activityBar.foreground": "#f8f8f2", 550 | "badge.background": "#75715e", 551 | "badge.foreground": "#f8f8f2", 552 | "button.background": "#75715e", 553 | "debugToolBar.background": "#1e1f1c", 554 | "diffEditor.insertedTextBackground": "#4b661680", 555 | "diffEditor.removedTextBackground": "#90274a70", 556 | "dropdown.background": "#414339", 557 | "dropdown.listBackground": "#1e1f1c", 558 | "editor.selectionHighlightBackground": "#575b6180", 559 | "editor.wordHighlightBackground": "#4a4a7680", 560 | "editor.wordHighlightStrongBackground": "#6a6a9680", 561 | "editorGroup.border": "#34352f", 562 | "editorGroup.dropBackground": "#41433980", 563 | "editorGroupHeader.tabsBackground": "#1e1f1c", 564 | "editorHoverWidget.background": "#414339", 565 | "editorHoverWidget.border": "#75715e", 566 | "editorIndentGuide.activeBackground": "#767771", 567 | "editorIndentGuide.background": "#464741", 568 | "editorLineNumber.activeForeground": "#c2c2bf", 569 | "editorLineNumber.foreground": "#90908a", 570 | "editorSuggestWidget.background": "#272822", 571 | "editorSuggestWidget.border": "#75715e", 572 | "editorWidget.background": "#1e1f1c", 573 | "focusBorder": "#75715e", 574 | "input.background": "#414339", 575 | "inputOption.activeBorder": "#75715e", 576 | "inputValidation.errorBackground": "#90274a", 577 | "inputValidation.errorBorder": "#f92672", 578 | "inputValidation.infoBackground": "#546190", 579 | "inputValidation.infoBorder": "#819aff", 580 | "inputValidation.warningBackground": "#848528", 581 | "inputValidation.warningBorder": "#e2e22e", 582 | "list.activeSelectionBackground": "#75715e", 583 | "list.dropBackground": "#414339", 584 | "list.focusBackground": "#414339", 585 | "list.highlightForeground": "#f8f8f2", 586 | "list.hoverBackground": "#3e3d32", 587 | "list.inactiveSelectionBackground": "#414339", 588 | "menu.background": "#1e1f1c", 589 | "menu.foreground": "#cccccc", 590 | "minimap.selectionHighlight": "#878b9180", 591 | "panel.border": "#414339", 592 | "panelTitle.activeBorder": "#75715e", 593 | "panelTitle.activeForeground": "#f8f8f2", 594 | "panelTitle.inactiveForeground": "#75715e", 595 | "peekView.border": "#75715e", 596 | "peekViewEditor.background": "#272822", 597 | "peekViewEditor.matchHighlightBackground": "#75715e", 598 | "peekViewResult.background": "#1e1f1c", 599 | "peekViewResult.matchHighlightBackground": "#75715e", 600 | "peekViewResult.selectionBackground": "#414339", 601 | "peekViewTitle.background": "#1e1f1c", 602 | "pickerGroup.foreground": "#75715e", 603 | "progressBar.background": "#75715e", 604 | "selection.background": "#ccccc7", 605 | "settings.focusedRowBackground": "#4143395a", 606 | "sideBar.background": "#1e1f1c", 607 | "sideBarSectionHeader.background": "#272822", 608 | "statusBar.background": "#414339", 609 | "statusBar.debuggingBackground": "#75715e", 610 | "statusBar.noFolderBackground": "#414339", 611 | "statusBarItem.remoteBackground": "#ac6218", 612 | "tab.border": "#1e1f1c", 613 | "tab.inactiveBackground": "#34352f", 614 | "tab.inactiveForeground": "#ccccc7", 615 | "tab.lastPinnedBorder": "#414339", 616 | "terminal.ansiBlack": "#333333", 617 | "terminal.ansiBlue": "#6a7ec8", 618 | "terminal.ansiBrightBlack": "#666666", 619 | "terminal.ansiBrightBlue": "#819aff", 620 | "terminal.ansiBrightCyan": "#66d9ef", 621 | "terminal.ansiBrightGreen": "#a6e22e", 622 | "terminal.ansiBrightMagenta": "#ae81ff", 623 | "terminal.ansiBrightRed": "#f92672", 624 | "terminal.ansiBrightWhite": "#f8f8f2", 625 | "terminal.ansiBrightYellow": "#e2e22e", 626 | "terminal.ansiCyan": "#56adbc", 627 | "terminal.ansiGreen": "#86b42b", 628 | "terminal.ansiMagenta": "#8c6bc8", 629 | "terminal.ansiRed": "#c4265e", 630 | "terminal.ansiWhite": "#e3e3dd", 631 | "terminal.ansiYellow": "#b3b42b", 632 | "titleBar.activeBackground": "#1e1f1c", 633 | "widget.shadow": "#00000098" 634 | }, 635 | "name": "Wolfram (Dark Rainbow).json" 636 | } 637 | -------------------------------------------------------------------------------- /src/extension/controller.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * vscode-wolfram 3 | * 4 | * Created by IDE support team on 10/01/24. 5 | * Copyright (c) 2024 Wolfram Research. All rights reserved. 6 | * 7 | */ 8 | 9 | 10 | 11 | // Copyright 2021 Tianhuan Lu 12 | // 13 | // Licensed under the Apache License, Version 2.0 (the "License"); 14 | // you may not use this file except in compliance with the License. 15 | // You may obtain a copy of the License at 16 | // 17 | // http://www.apache.org/licenses/LICENSE-2.0 18 | // 19 | // Unless required by applicable law or agreed to in writing, software 20 | // distributed under the License is distributed on an "AS IS" BASIS, 21 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 | // See the License for the specific language governing permissions and 23 | // limitations under the License. 24 | 25 | 26 | 27 | 28 | 29 | 30 | import * as vscode from 'vscode'; 31 | const path = require("path"); 32 | const os = require('os'); 33 | const fs = require('fs'); 34 | 35 | const zmq = require("zeromq"); 36 | 37 | import { readFileSync, writeFile, appendFile } from "fs"; 38 | import * as child_process from "child_process"; 39 | import { ExportNotebookStatusBarItem, NotebookOutputPanel } from "./ui-items"; 40 | import { NotebookConfig } from "./notebook-config"; 41 | import { ExecutionQueue } from "./notebook-kernel"; 42 | import { FindKernel } from "./find-kernel"; 43 | 44 | export class WolframNotebookKernel { 45 | private readonly notebookConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration("wolfram", null); 46 | private readonly _id = 'wolfram-notebook-kernel'; 47 | private readonly _label = 'Wolfram Kernel'; 48 | private readonly _supportedLanguages = ['wolfram']; 49 | private findKernel = new FindKernel(); 50 | private kernelStatusString: string = "unrevoled"; 51 | 52 | 53 | private extensionPath: string = ""; 54 | 55 | private logFile: string; 56 | 57 | private outputPanel = new NotebookOutputPanel("Wolfram Language Notebook"); 58 | private config = new NotebookConfig(); 59 | 60 | private readonly _controller: vscode.NotebookController; 61 | private thisExtension: vscode.Extension | undefined; 62 | 63 | private kernel: any; 64 | private socket: any; 65 | 66 | private executionQueue = new ExecutionQueue(); 67 | private selectedNotebooks: Set = new Set(); 68 | 69 | constructor() { 70 | this.thisExtension = vscode.extensions.getExtension("WolframResearch.wolfram"); 71 | 72 | this.logFile = this.notebookConfig.get("advanced.notebook.logDirectory", "Off"); 73 | 74 | if (this.logFile !== "Off") { 75 | this.logFile = this.logFile + "/" + "Notebook-Log-" + new Date().toUTCString() + ".txt"; 76 | // replace ',', '(', ")" and ':' with '-' 77 | this.logFile = this.logFile.replace(/\,|\(|\)|:/g, '-'); 78 | this.outputPanel.print(`Log file = ${this.logFile}`); 79 | }; 80 | 81 | this._controller = vscode.notebooks.createNotebookController(this._id, 82 | 'wolfram-notebook', 83 | this._label); 84 | 85 | this._controller.supportedLanguages = this._supportedLanguages; 86 | this._controller.supportsExecutionOrder = true; 87 | this._controller.executeHandler = this.execute.bind(this); 88 | 89 | 90 | this.extensionPath = this.thisExtension?.extensionPath || ""; 91 | 92 | // when notebook config changes, send a message to the kernel 93 | this.config.onDidChange((config: NotebookConfig) => { 94 | this.postMessageToKernel({ type: "set-config", config: config.getKernelRelatedConfigs() }); 95 | }); 96 | 97 | this._controller.onDidChangeSelectedNotebooks(({ notebook, selected }) => { 98 | if (selected) { 99 | this.selectedNotebooks.add(notebook); 100 | this.outputPanel.print(`The controller is selected for a notebook ${notebook.uri.fsPath}`); 101 | 102 | } else { 103 | this.selectedNotebooks.delete(notebook); 104 | this.outputPanel.print(`The controller is unselected for a notebook ${notebook.uri.fsPath}`); 105 | } 106 | this.outputPanel.print(`There are ${this.selectedNotebooks.size} notebook(s) for which the controller is selected.`); 107 | if (this.selectedNotebooks.size === 0 108 | // && this.config.get("kernel.quitAutomatically") 109 | ) { 110 | // when the last notebook was closed, and the user choose to quit kernel automatically 111 | this.quitKernel(); 112 | } 113 | }); 114 | 115 | } 116 | 117 | dispose(): void { 118 | this.outputPanel.print(`Killing kernel process, pid = ${this.kernel.pid}`); 119 | this.quitKernel(); 120 | this._controller.dispose(); 121 | } 122 | 123 | private execute( 124 | cells: vscode.NotebookCell[], 125 | _notebook: vscode.NotebookDocument, 126 | _controller: vscode.NotebookController 127 | ): void { 128 | if(this.kernelStatusString === "resolved") 129 | { 130 | for (let cell of cells) { 131 | this.outputPanel.print("===========Exec start=====================."); 132 | const execution = this._controller.createNotebookCellExecution(cell); 133 | console.log(`execute kernelStatusString: , ${this.kernelStatusString}`); 134 | if(this.kernelStatusString === "resolved"){this.executionQueue.push(execution)}; 135 | 136 | execution.token.onCancellationRequested(() => { 137 | this.outputPanel.print("Abort evaluation"); 138 | // process.kill(this.kernel.pid); 139 | // this.kernel.kill("SIGKILL"); 140 | this.kernel.kill(this.kernel.pid, "SIGINT"); 141 | this.outputPanel.print("Abort evaluation"); 142 | } 143 | ); 144 | } 145 | this.outputPanel.print("Execution command sent from NB."); 146 | this.checkoutExecutionQueue() 147 | } 148 | } 149 | 150 | 151 | private async checkoutExecutionQueue() { 152 | const currentExecution = this.executionQueue.getNextPendingExecution(); 153 | 154 | if (currentExecution) { 155 | const inputFromCell = currentExecution.execution.cell.document.getText(); 156 | this.outputPanel.print("\n============================================================\n"); 157 | this.outputPanel.print("Input from cell"); 158 | if (this.logFile !== "Off") { 159 | this.appendFileWrite(this.logFile, this.logString("\n============================================================\n")); 160 | this.appendFileWrite(this.logFile, this.logString("Input from cell: " + inputFromCell)); 161 | } 162 | this.outputPanel.print(inputFromCell); 163 | 164 | if (inputFromCell) { 165 | this.postMessageToKernel({ 166 | type: "evaluate-cell", 167 | uuid: currentExecution.id, 168 | text: inputFromCell 169 | }); 170 | 171 | this.executionQueue.start(currentExecution.id); 172 | } else { 173 | this.executionQueue.start(currentExecution.id); 174 | this.executionQueue.end(currentExecution.id, false); 175 | } 176 | 177 | } 178 | } 179 | 180 | 181 | 182 | private writeFileChecked(path: string, text: string | Uint8Array) { 183 | writeFile(path, text, err => { 184 | if (err) { 185 | vscode.window.showErrorMessage(`Unable to write file ${path} \n${err.message}`, 186 | "Retry", "Save As...", "Dismiss").then(value => { 187 | if (value === "Retry") { 188 | this.writeFileChecked(path, text); 189 | } else if (value === "Save As...") { 190 | vscode.window.showSaveDialog({ 191 | defaultUri: vscode.Uri.file(path), 192 | filters: { 193 | "All Files": ["*"] 194 | } 195 | }).then(value => { 196 | if (value) { 197 | this.writeFileChecked(value.fsPath, text); 198 | } 199 | }); 200 | } 201 | }); 202 | return; 203 | } 204 | }); 205 | 206 | } 207 | 208 | private appendFileWrite(path: string, text: string | Uint8Array) { 209 | appendFile(path, text, err => { 210 | if (err) { 211 | vscode.window.showErrorMessage(`Unable to write file ${path} \n${err.message}`); 212 | return; 213 | } 214 | }); 215 | 216 | } 217 | 218 | public async launchKernel() { 219 | 220 | this.outputPanel.print("************ Entering launchKernel ***************"); 221 | 222 | this.outputPanel.print((`TS log file = ${this.logFile}`)); 223 | 224 | let kernelInitPath = path.join(this.extensionPath, 'resources', 'init.wl'); 225 | 226 | if(process.platform === "win32"){ 227 | kernelInitPath = kernelInitPath.replace(/\\/g, "/"); 228 | }; 229 | 230 | const kernelRenderInitPath = path.join(this.extensionPath, 'resources', 'render-html.wl'); 231 | 232 | let kernelRenderInitString = ""; 233 | const kernelPort = this.getRandomPort("49152-65535"); 234 | 235 | 236 | let launchCommand = ""; 237 | let launchArguments = [""]; 238 | 239 | try { 240 | kernelRenderInitString = readFileSync(kernelRenderInitPath).toString(); 241 | } catch (error) { 242 | vscode.window.showErrorMessage("Failed to read kernel initialization files."); 243 | return; 244 | } 245 | 246 | const kernelInitCommands = `ToExpression["VsCodeWolfram\`Private\`zmqPort=${kernelPort}; Get[\\"${kernelInitPath}\\"]"]`; 247 | 248 | 249 | if (this.logFile !== "Off") { 250 | this.appendFileWrite(this.logFile, this.logString(kernelInitCommands)); 251 | } 252 | 253 | 254 | launchCommand = this.findKernel.resolveKernel(); 255 | 256 | if(process.platform === "win32"){ 257 | launchCommand = launchCommand.replace("WolframKernel.exe", "wolfram.exe") 258 | }; 259 | launchArguments = ["-run", kernelInitCommands]; 260 | 261 | 262 | this.outputPanel.print("Launching kernel"); 263 | this.outputPanel.print(`NotebookKernel = ${launchCommand}`); 264 | 265 | this.kernel = child_process.spawn(launchCommand, launchArguments, { stdio: "pipe" }); 266 | 267 | if (this.kernel) { 268 | this.outputPanel.print(`kernel process pid = ${this.kernel.pid}`) 269 | if (this.logFile !== "Off") { this.appendFileWrite(this.logFile, this.logString(`kernel process pid = ${this.kernel.pid}`)) }; 270 | 271 | } 272 | 273 | const launchPromise = new Promise((resolve, reject) => { 274 | const connectionTimeout = setTimeout(() => { 275 | reject(new Error("Kernel initialization took too long")); 276 | }, 15000); 277 | 278 | this.kernel.stdout.on("data", async (data: Buffer) => { 279 | 280 | this.outputPanel.print(`kernel process async pid = ${this.kernel.pid}`) 281 | 282 | const message = data.toString(); 283 | 284 | if (message.startsWith(" ")) { 285 | // a fatal error 286 | vscode.window.showErrorMessage("The kernel has stopped due to the following error: " + message.slice(8)); 287 | return; 288 | } 289 | 290 | this.outputPanel.print("LaunchKernel: Received the following data from kernel:"); 291 | this.outputPanel.print(`${data.toString()}`); 292 | 293 | // TODO: Config first meassage from kernel (not wolframscript) 294 | 295 | 296 | const match = message.match(/\[address tcp:\/\/(127.0.0.1:[0-9]+)\]/); 297 | if (match) { 298 | this.socket = new zmq.Pair({ linger: 0 }); 299 | this.socket.connect("tcp://" + match[1]); 300 | 301 | const rand = Math.floor(Math.random() * 1e9).toString(); 302 | try { 303 | 304 | this.evaluateFrontEnd(kernelRenderInitString, false); 305 | 306 | this.postMessageToKernel({ type: "test", text: rand }); 307 | 308 | let timer: any; 309 | 310 | const [received] = await Promise.race([ 311 | this.socket.receive(), 312 | new Promise(res => timer = setTimeout(() => res([new Error("timeout")]), 10000// milliseconds 313 | )) 314 | ]).finally(() => clearTimeout(timer)); 315 | if (received instanceof Error) { 316 | throw received; 317 | } 318 | this.outputPanel.print("launchKernel :> Received the following test message from kernel:"); 319 | this.outputPanel.print(`${received.toString()}`); 320 | 321 | // this.firstResponse = await this.handleMessageFromKernel(); 322 | this.handleMessageFromKernel(); 323 | 324 | if (this.logFile !== "Off") { 325 | this.appendFileWrite(this.logFile, this.logString("================ Kernel launched with kernel message handler =======================\n\n")); 326 | } 327 | 328 | console.log("================ Kernel launched with kernel message handler ======================="); 329 | 330 | vscode.window.showInformationMessage("Notebook kernel launched, ready for notebook evaluation."); 331 | 332 | resolve("hello from stdout"); 333 | clearTimeout(connectionTimeout); 334 | this.kernelStatusString = "resolved"; 335 | 336 | 337 | 338 | } catch (error) { 339 | 340 | this.outputPanel.print("The kernel took too long to respond through the ZeroMQ link."); 341 | } 342 | } 343 | }); 344 | 345 | this.kernel.stderr.on("data", async (data: Buffer) => { 346 | this.outputPanel.print(`stderr output = ${data.toString()}`); 347 | }); 348 | 349 | 350 | }); 351 | 352 | let returnPromise = await launchPromise; 353 | return returnPromise; 354 | 355 | 356 | } 357 | 358 | // End of launchKernel 359 | 360 | 361 | 362 | 363 | 364 | 365 | private logString (str: string) { 366 | return "[" + new Date().toUTCString() + "] " + str + "\n" 367 | } 368 | 369 | 370 | private getRandomPort(portRanges: string) { 371 | let ranges = [...portRanges.matchAll(/\s*(\d+)\s*(?:[-‐‑‒–]\s*(\d+)\s*)?/g)] 372 | .map(match => [parseInt(match[1]), parseInt(match[match[2] === undefined ? 1 : 2])]) 373 | .map(pair => [Math.max(Math.min(pair[0], pair[1]), 1), Math.min(Math.max(pair[0], pair[1]) + 1, 65536)]) 374 | .filter(pair => pair[0] < pair[1]); 375 | if (ranges.length === 0) { 376 | ranges = [[49152, 65536]]; 377 | } 378 | let cmf: number[] = []; 379 | ranges.reduce((acc, pair, i) => { 380 | cmf[i] = acc + (pair[1] - pair[0]); 381 | return cmf[i]; 382 | }, 0); 383 | 384 | const rand = Math.random() * cmf[cmf.length - 1]; 385 | for (let i = 0; i < cmf.length; ++i) { 386 | if (rand <= cmf[i]) { 387 | const [lower, upper] = ranges[i]; 388 | return Math.min(Math.floor(Math.random() * (upper - lower)) + lower, upper - 1); 389 | } 390 | } 391 | } 392 | 393 | private postMessageToKernel(message: any) { 394 | if (this.socket !== undefined) { 395 | if (this.logFile !== "Off") { 396 | this.appendFileWrite(this.logFile, this.logString( 397 | ("TS -> WL: " + JSON.stringify(message)).substring(0, 400) 398 | )); 399 | } 400 | this.socket.send(typeof message === 'string' ? message : JSON.stringify(message)); 401 | } else { 402 | this.outputPanel.print("The socket is not available; cannot post the message."); 403 | } 404 | } 405 | 406 | 407 | evaluateFrontEnd(text: string, asynchronous: boolean = false) { 408 | this.postMessageToKernel({ 409 | type: "evaluate-front-end", 410 | async: asynchronous, 411 | text: text 412 | }); 413 | } 414 | 415 | private quitKernel() { 416 | this.outputPanel.print(`Killing kernel process, pid = ${this.kernel.pid}`); 417 | 418 | this.kernel.kill("SIGKILL"); 419 | this.kernel = undefined; 420 | this.socket.close(); 421 | this.socket = undefined; 422 | }; 423 | 424 | 425 | private async handleMessageFromKernel() { 426 | 427 | while (true) { 428 | let [message] = await this.socket.receive().catch(() => { 429 | 430 | return [new Error("receive-message")]; 431 | }); 432 | 433 | if (message instanceof Error) { 434 | return; 435 | } 436 | 437 | message = Buffer.from(message).toString("utf-8"); 438 | 439 | this.outputPanel.print("handleMessageFromKernel Message Print :> "); 440 | this.outputPanel.print(JSON.stringify(message)); 441 | 442 | 443 | if (this.logFile !== "Off") { this.appendFileWrite(this.logFile, this.logString("WL -> TS :> " + JSON.stringify(message))); } 444 | 445 | try { 446 | message = JSON.parse(message); 447 | } catch (error) { 448 | this.outputPanel.print("Failed to parse the following message:"); 449 | this.outputPanel.print(message); 450 | continue; 451 | } 452 | 453 | const messageId = message?.uuid || ""; 454 | this.outputPanel.print(`messageId = ${messageId}`) 455 | const currentExecution = this.executionQueue.find(messageId); 456 | 457 | switch (message.type) { 458 | 459 | 460 | 461 | case "show-input-name": 462 | this.outputPanel.print("show-input-name:"); 463 | if (currentExecution) { 464 | const match = message.name.match(/In\[(\d+)\]/); 465 | if (match) { 466 | currentExecution.execution.executionOrder = parseInt(match[1]); 467 | } 468 | } 469 | break; 470 | 471 | case "show-output": 472 | case "show-message": 473 | case "show-text": 474 | this.outputPanel.print("show-output:"); 475 | if (currentExecution) { 476 | const outputItems: vscode.NotebookCellOutputItem[] = []; 477 | 478 | 479 | if (message.text !== "None") { 480 | this.outputPanel.print(`text message = ${message.text}`) 481 | outputItems.push(vscode.NotebookCellOutputItem.text(message.text, "text/html")); 482 | } else { 483 | outputItems.push(vscode.NotebookCellOutputItem.text(message.html, "x-application/wolfram-language-html")); 484 | }; 485 | 486 | const output = new vscode.NotebookCellOutput(outputItems); 487 | 488 | this.outputPanel.print(`Output = ${output.items.toString}`) 489 | 490 | 491 | if (currentExecution?.hasOutput) { 492 | this.outputPanel.print("Output replace:"); 493 | currentExecution.execution.appendOutput(output); 494 | } else { 495 | currentExecution.execution.replaceOutput(output); 496 | currentExecution.hasOutput = true; 497 | } 498 | } 499 | break; 500 | case "evaluation-done": 501 | this.outputPanel.print("evaluation-done:"); 502 | this.executionQueue.end(messageId, true); 503 | this.checkoutExecutionQueue(); 504 | break; 505 | 506 | default: 507 | this.outputPanel.print("The following message has an unexpect type:"); 508 | this.outputPanel.print(JSON.stringify(message)); 509 | } 510 | 511 | } 512 | } 513 | 514 | 515 | 516 | 517 | 518 | 519 | } 520 | -------------------------------------------------------------------------------- /resources/init.wl: -------------------------------------------------------------------------------- 1 | (* ::Package:: *) 2 | (* 3 | 4 | /* 5 | * vscode-wolfram 6 | * 7 | * Created by IDE support team on 10/01/24. 8 | * Copyright (c) 2024 Wolfram Research. All rights reserved. 9 | * 10 | */ 11 | 12 | 13 | 14 | // Copyright 2021 Tianhuan Lu 15 | // 16 | // Licensed under the Apache License, Version 2.0 (the "License"); 17 | // you may not use this file except in compliance with the License. 18 | // You may obtain a copy of the License at 19 | // 20 | // http://www.apache.org/licenses/LICENSE-2.0 21 | // 22 | // Unless required by applicable law or agreed to in writing, software 23 | // distributed under the License is distributed on an "AS IS" BASIS, 24 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | // See the License for the specific language governing permissions and 26 | // limitations under the License. 27 | 28 | *) 29 | 30 | (* ::Section:: *) 31 | (*Import*) 32 | BeginPackage["VsCodeWolfram`"] 33 | 34 | (* ::Section:: *) 35 | (*Initialization*) 36 | 37 | Begin["`Private`"] 38 | 39 | 40 | 41 | timeString[] := DateString[{"Hour24", "-", "Minute", "-", "Second", " "}] 42 | 43 | SetAttributes[logWrite,HoldAllComplete]; 44 | logWrite[message_]:=WriteString[Streams["stdout"],message]; 45 | 46 | logWriteFile[message_] := WriteString[$file, timeString[] //OutputForm, message]; 47 | logError[message_]:=(WriteString[Streams["stdout"]," "<>message];Exit[];) 48 | $lineNumber = 0; 49 | 50 | (* TODO: better WL server side logging when user chooses *) 51 | 52 | $file = FileNameJoin[{$TemporaryDirectory, "Wolfram", "Log", "WL-NB-server-Log-" <> timeString[] <> ".txt"}]; 53 | 54 | If[FileExistsQ[$file], DeleteFile[$file]]; 55 | $file = CreateFile[$file]; 56 | 57 | logWrite["< INITIALIZATION STARTS >"]; 58 | logWrite[TemplateApply["Available kernel processes = ``", ToExpression["$MaxLicenseProcesses - $LicenseProcesses"]]]; 59 | logWriteFile[ "< INITIALIZATION STARTS >\n"]; 60 | logWriteFile[ "< Test STARTS > " <> timeString[] <> " - \n"]; 61 | 62 | 63 | displayMessage[Hold[Message[m : MessageName[p_, t_], args___], True]] := Block[{msgs, $messagefile}, 64 | UpdateOutputQueue[MessageHeader @@ {ToString[Unevaluated[p]], t}]; handleOutput[]; 65 | 66 | msgs = ToString[StringForm[ToString[Unevaluated[p]] <> "::" <> t <> ": " <> If[StringQ[m], m, ReplacePart[m, 1 -> General]], args]]; 67 | 68 | UpdateOutputQueue[TextHeader[msgs]]; handleOutput[]; 69 | 70 | ]; 71 | 72 | messageHandler = If[Last[#], displayMessage[#]]&; 73 | Internal`AddHandler["Message", messageHandler]; 74 | 75 | $hasZeroMQ = (Quiet@Needs["ZeroMQLink`"]=!=$Failed); 76 | $hasCodeParser = (Quiet@Needs["CodeParser`"]=!=$Failed); 77 | 78 | 79 | If[$VersionNumber<12.0, 80 | logError["Version 12.0 or higher is required."];Exit[]; 81 | ]; 82 | 83 | 84 | If[!$hasZeroMQ, 85 | logError["Failed to load ZeroMQLink` package."];Exit[]; 86 | ]; 87 | 88 | 89 | (* ::Section:: *) 90 | (* Config *) 91 | 92 | 93 | If[Head[zmqPort]===Integer&&0 <|"value"-> 0.6,"requires"->((Head[#]=== Real|| Head[#] === Integer) && #>0&)|>, (* Value determined by trial and error or what looks good in screen *) 98 | "storeOutputExpressions"-> <|"value"->True,"requires"->(#===True||#===False&)|>, 99 | "outputSizeLimit"-> <|"value"->5000(*KB*),"requires"->(Head[#]===Integer&&#>0&)|>, 100 | "boxesTimeLimit"-><|"value"->5000(*ms*),"requires"->(Head[#]===Integer&&#>0&)|>, 101 | "htmlTimeLimit"-><|"value"->10000(*ms*),"requires"->(Head[#]===Integer&&#>0&)|>, 102 | "htmlMemoryLimit"-><|"value"->200(*MB*),"requires"->(Head[#]===Integer&&#>0&)|>, 103 | "imageWithTransparency"-><|"value"-> False,"requires"->(#===True||#===False&)|>, 104 | "renderAsImages"-><|"value"->True,"requires"->(#===True||#===False&)|>, 105 | "invertBrightnessInDarkThemes"-><|"value"->True,"requires"->(#===True||#===False&)|> 106 | |>; 107 | 108 | 109 | $setKernelConfig[name_,value_]:=Module[{entry=$config[name]}, 110 | If[MissingQ[entry], 111 | logWrite[ToString[name]<>" is not a valid config name to be set."];, 112 | If[!TrueQ[entry["requires"][value]], 113 | logWrite[ToString[value]<>" is not a valid value of "<>ToString[name]<>"."];Return[];, 114 | $config[name]["value"]=value; 115 | ]; 116 | ]; 117 | ]; 118 | 119 | 120 | $getKernelConfig[name_]:=If[MissingQ[$config[name]], 121 | logWrite[ToString[name]<>" is not a valid config name to be read"];0, 122 | $config[name]["value"] 123 | ]; 124 | 125 | 126 | (* ::Section:: *) 127 | (* Message handling functions *) 128 | 129 | $evaluating=Null; 130 | 131 | $evaluationQueue=<||>; 132 | $outputQueue=<||>; 133 | 134 | $currentOutputMessage=""; 135 | $previousOutputMessage=""; 136 | 137 | $inputName="Null"; 138 | $outputName="Null"; 139 | 140 | $messagedebug=Null; 141 | 142 | 143 | 144 | 145 | ClearAll[queuePush,queuePop,stackPush,stackPop,stackClear]; 146 | SetAttributes[{queuePush, queuePop,stackPush,stackPop,stackClear}, HoldFirst]; 147 | queuePush[q_, value_]:=Module[{},AssociateTo[q, $ModuleNumber->value]]; 148 | queuePop[q_]:=If[Length[q]>0,With[{first=Take[q,1]},KeyDropFrom[q, Keys@first];first[[1]]],Null]; 149 | stackPush[q_, value_]:=Module[{},AssociateTo[q, $ModuleNumber->value]]; 150 | stackPop[q_]:=If[Length[q]>0,With[{last=Take[q,-1]},KeyDropFrom[q, Keys@last];last[[1]]],Null]; 151 | stackClear[q_]:=Module[{},q=<||>]; 152 | 153 | 154 | ClearAll[sendMessage,readMessage]; 155 | sendMessage[message_ByteArray]:=ZeroMQLink`ZMQSocketWriteMessage[$zmqserver,message]; 156 | sendMessage[message_Association]:=sendMessage[StringToByteArray@Developer`WriteRawJSONString[message,"Compact"->True]]; 157 | sendMessage[message_]:=sendMessage[StringToByteArray[ToString[message],"UTF-8"]]; 158 | readMessage[timeout_:1.0]:=Module[{ready=SocketReadyQ[$zmqserver,timeout]},If[ready,ByteArrayToString[SocketReadMessage[$zmqserver],"UTF-8"],$Failed]]; 159 | 160 | 161 | 162 | 163 | 164 | (* ::Section:: *) 165 | (* Output Handler *) 166 | 167 | 168 | (* check if a string contains any private use area characters *) 169 | containsPUAQ[str_] := 170 | AnyTrue[ 171 | ToCharacterCode[str, "Unicode"], 172 | (57344 <= #1 <= 63743 || 983040 <= #1 <= 1048575 || 1048576 <= #1 <= 1114111) & 173 | ]; 174 | 175 | (************************************ 176 | utility for determining if a 177 | result should be displayed 178 | as text or an image 179 | *************************************) 180 | 181 | (* determine if a result does not depend on any Wolfram Language frontend functionality, 182 | such that it should be displayed as text *) 183 | textQ[ExpressionHeader[expr_]] := Module[ 184 | { 185 | (* the head of expr *) 186 | exprHead, 187 | 188 | (* pattern objects *) 189 | pObjects 190 | }, 191 | 192 | (* if we cannot use the frontend, use text *) 193 | If[ 194 | !$canUseFrontEnd, 195 | Return[True]; 196 | ]; 197 | 198 | (* save the head of the expression *) 199 | exprHead = Head[expr]; 200 | 201 | (* if the expression is wrapped with InputForm or OutputForm, 202 | automatically format as text *) 203 | If[exprHead === InputForm || exprHead === OutputForm, 204 | Return[True] 205 | ]; 206 | 207 | (* if the FormatType of $Output is set to TeXForm, or if the expression is wrapped with TeXForm, 208 | and the expression has an acceptable textual form, format as text *) 209 | If[(exprHead == TeXForm) && !containsPUAQ[ToString[expr]], 210 | Return[True]; 211 | ]; 212 | 213 | (* if the FormatType of $Output is set to TraditionalForm, 214 | or if the expression is wrapped with TraditionalForm, 215 | do not use text *) 216 | If[exprHead === TraditionalForm, 217 | Return[False] 218 | ]; 219 | 220 | (* breakdown expr into atomic objects organized by their Head *) 221 | pObjects = 222 | GroupBy[ 223 | Complement[ 224 | Quiet[Cases[ 225 | expr, 226 | elem_ /; (Depth[Unevaluated[elem]] == 1) :> Hold[elem], 227 | {0, Infinity}, 228 | Heads -> True 229 | ]], 230 | (* these symbols are fine *) 231 | {Hold[List], Hold[Association]} 232 | ], 233 | ( 234 | Replace[ 235 | #1, 236 | Hold[elem_] :> Head[Unevaluated[elem]] 237 | ] 238 | ) & 239 | ]; 240 | 241 | (* if expr just contains atomic objects of the types listed above, return True *) 242 | If[ 243 | ContainsOnly[Keys[pObjects], {Integer, Real}], 244 | Return[True]; 245 | ]; 246 | 247 | (* if expr just contains atomic objects of the types listed above, along with some symbols, 248 | return True only if the symbols have no attached rules *) 249 | If[ 250 | ContainsOnly[Keys[pObjects], {Integer, Real, String, Symbol}], 251 | Return[ 252 | AllTrue[ 253 | Lookup[pObjects, String, {}], 254 | (!containsPUAQ[ReleaseHold[#1]]) & 255 | ] && 256 | AllTrue[ 257 | Lookup[pObjects, Symbol, {}], 258 | ( 259 | Replace[ 260 | #1, 261 | Hold[elem_] :> ToString[Definition[elem]] 262 | ] === "Null" 263 | ) & 264 | ] 265 | ]; 266 | ]; 267 | 268 | (* otherwise, no, the result should not be displayed as text *) 269 | Return[False]; 270 | ]; 271 | 272 | 273 | UpdateOutputQueue[outExpr_] := 274 | Switch[Head[outExpr], 275 | 276 | InputHeader, 277 | If[ 278 | $evaluating["progress"]==="complete", 279 | queuePush[$outputQueue,<| 280 | "uuid" -> $evaluating["uuid"], 281 | "type" -> InputHeader 282 | |>]; 283 | ]; 284 | $inputName = outExpr[[1]]; 285 | 286 | If[$evaluating["progress"]==="complete", 287 | sendMessage[<| 288 | "type" -> "show-input-name", 289 | "uuid" -> $evaluating["uuid"], 290 | "name" -> $inputName 291 | |>]; 292 | $inputName="Null"; 293 | ]; 294 | $evaluating = Null;, 295 | 296 | OutputHeader, 297 | $outputName = outExpr[[1]];, 298 | 299 | ExpressionHeader, 300 | queuePush[$outputQueue,<| 301 | "uuid" -> $evaluating["uuid"], 302 | "name" -> $outputName, 303 | "type" -> Head[outExpr], 304 | "outputExpr" -> outExpr 305 | |>]; 306 | $outputName="Null";, 307 | 308 | TextHeader|MessageHeader, 309 | queuePush[$outputQueue,<| 310 | "uuid" -> $evaluating["uuid"], 311 | "type" -> Head[outExpr], 312 | "outputExpr" -> outExpr 313 | |>];, 314 | _, 315 | logWrite["Unexpected output; output = "<>ToString[outExpr]]; 316 | ]; 317 | 318 | 319 | handleOutput[]:= 320 | Module[ 321 | { 322 | output = queuePop[$outputQueue], boxes, exceedsExprSize, 323 | isTraditionalForm=False, isTeXForm=False, shouldStoreText=True, text, html 324 | }, 325 | 326 | $previousOutputMessage = $currentOutputMessage; 327 | $currentOutputMessage = ""; 328 | Switch[output["type"], 329 | 330 | InputHeader, 331 | sendMessage[<| 332 | "type" -> "evaluation-done", 333 | "uuid" -> output["uuid"] 334 | |>];, 335 | 336 | ExpressionHeader, 337 | TimeConstrained[ 338 | exceedsExprSize=!TrueQ[ByteCount[output["outputExpr"]]<=$getKernelConfig["outputSizeLimit"]*2^10]; 339 | If[exceedsExprSize, 340 | output["outputExpr"]=Replace[output["outputExpr"],ExpressionHeader[expr_]:>ExpressionHeader[Short[expr,5]]] 341 | ]; 342 | boxes=If[(isTraditionalForm=MatchQ[#,ExpressionHeader[BoxData[_,TraditionalForm]]]), 343 | FormBox[#[[1,1]],TraditionalForm], 344 | MakeBoxes@@# 345 | ]&[output["outputExpr"]]; 346 | shouldStoreText=(isTeXForm=StringMatchQ[output["name"],RegularExpression["^Out\\[.+\\]//TeXForm=.*"]]) 347 | ||(!exceedsExprSize&&TrueQ@$getKernelConfig["storeOutputExpressions"]); 348 | text=If[shouldStoreText,Replace[output["outputExpr"],ExpressionHeader[expr_]:>ToString[Unevaluated[expr],InputForm]],""]; 349 | If[isTeXForm,text=ExportString[text,"RawJSON"];]; 350 | , 351 | $getKernelConfig["boxesTimeLimit"]/1000.0, 352 | boxes=renderingFailed["The conversion to the box representation took too much time."]; 353 | text="$Failed"; 354 | ]; 355 | 356 | text = 357 | If[ 358 | textQ[output["outputExpr"]], 359 | Replace[output["outputExpr"],ExpressionHeader[expr_]:>ToString[Unevaluated[expr], OutputForm]], 360 | (* else *) 361 | "None" 362 | ]; 363 | 364 | html=TimeConstrained[ 365 | MemoryConstrained[ 366 | If[$getKernelConfig["renderAsImages"],renderImage,renderHTML][boxes], 367 | $getKernelConfig["htmlMemoryLimit"]*2^20, 368 | renderHTML@renderingFailed["Rendering to HTML took much memory."] 369 | ], 370 | $getKernelConfig["htmlTimeLimit"]/1000.0, 371 | renderHTML@renderingFailed["Rendering to HTML took much time."] 372 | ]; 373 | logWriteFile["Expression html: " <> html <> "\n"]; 374 | sendMessage[<| 375 | "type"->"show-output", 376 | "uuid"->output["uuid"], 377 | "name"->output["name"], 378 | (* "text"->If[shouldStoreText,text,Null], *) 379 | "text"-> text, 380 | "isBoxData"->(TrueQ[isTraditionalForm]&&shouldStoreText), 381 | "html"->html 382 | |>];, 383 | MessageHeader, 384 | $currentOutputMessage=TemplateApply["``::``", List@@output["outputExpr"]];, 385 | logWriteFile[logWriteFile[ "handleOutput-- MessageHeader :> " <> ToString[InputForm[output]] <> "\n"]]; 386 | TextHeader, 387 | logWriteFile[logWriteFile[ "handleOutput-- TextHeader :> " <> ToString[InputForm[output]] <> "\n"]]; 388 | If[StringContainsQ[$previousOutputMessage,"::"]&&StringContainsQ[output["outputExpr"][[1]],$previousOutputMessage], 389 | sendMessage[<| 390 | "type"->"show-message", 391 | "uuid"->output["uuid"], 392 | "text"->"None", 393 | "html"->StringJoin["
",StringReplace[
394 |               output["outputExpr"][[1]],
395 |               $previousOutputMessage->(""<>$previousOutputMessage<>"")
396 |             ],"
"] 397 | 398 | |>]; 399 | , 400 | sendMessage[<| 401 | "type"->"show-text", 402 | "uuid"->output["uuid"], 403 | "text"-> "None", 404 | "html"->StringJoin["
",ToString[output["outputExpr"][[1]]],"
"] 405 | |>]; 406 | ], 407 | _, 408 | logWrite["Unknown output type; output="<>ToString[output]]; 409 | ]; 410 | ]; 411 | 412 | (* ::Section:: *) 413 | (* Message Handler*) 414 | 415 | handleMessage[] := Module[ {}, 416 | 417 | $message = Quiet @ Developer`ReadRawJSONString[$messagetext]; 418 | 419 | If[$message===$Failed, 420 | logError["Error occured in parsing the previous message.\n$messagetext = "<>ToString[$messagetext]]; 421 | Return[]; 422 | ]; 423 | 424 | Module[{uuid,match,syntaxErrors}, 425 | Switch[$message["type"], 426 | 427 | "test", 428 | sendMessage[<|"type"->"test","text"->$message["text"],"version"->$Version|>];, 429 | 430 | "evaluate-cell", 431 | If[SyntaxQ[$message["text"]], 432 | 433 | logWriteFile[ "handleMessage-- $message (evaluate-cell) :> " <> ToString[InputForm[$message]] <> "\n"]; 434 | 435 | ,(* else *) 436 | 437 | If[$hasCodeParser, 438 | syntaxErrors=Cases[CodeParser`CodeParse[$message["text"]],(ErrorNode|AbstractSyntaxErrorNode|UnterminatedGroupNode|UnterminatedCallNode)[___],Infinity]; 439 | logWriteFile["The expression has the following syntax errors: "<>ToString[syntaxErrors]]; 440 | , 441 | syntaxErrors={}; 442 | logWriteFile["The expression has syntax errors (CodeParser` is unavailable)"]; 443 | ]; 444 | 445 | queuePush[$outputQueue,<| 446 | "uuid" -> $message["uuid"], 447 | "type" -> TextHeader, 448 | "outputExpr" -> TextHeader[#] 449 | |> &@ StringRiffle[ 450 | If[Length[syntaxErrors]==0,{"Syntax error at character "<>ToString@SyntaxLength[$message["text"]]}, 451 | TemplateApply["Syntax error `` at line `` column ``",{ToString[#1],Sequence@@#3[CodeParser`Source][[1]]}]&@@@syntaxErrors 452 | ],"\n" 453 | ]]; 454 | 455 | queuePush[$outputQueue,<| 456 | "uuid"->$message["uuid"], 457 | "type"->InputHeader 458 | |>]; 459 | 460 | ]; 461 | 462 | queuePush[$evaluationQueue,<| 463 | "uuid" -> $message["uuid"], 464 | "text" -> $message["text"], 465 | "type" -> "evaluate-cell", 466 | "progress"-> "complete" 467 | |>]; 468 | 469 | logWriteFile[ "handleMessage-- $evaluationQueue :> " <> ToString[InputForm[$evaluationQueue]] <> "\n"]; 470 | , 471 | "set-config", 472 | KeyValueMap[$setKernelConfig,$message["config"]];, 473 | 474 | "evaluate-front-end", 475 | If[SyntaxQ@$message["text"], 476 | Quiet@If[$message["aync"]===True, 477 | With[{expr=$message["text"]},LocalSubmit[ToExpression[expr]];];, 478 | ToExpression[$message["text"]] 479 | ]; 480 | ,(* else *) 481 | 482 | logWrite["Syntax error in the previous front end evaluation: " <> $message["text"]]; 483 | ], 484 | _, 485 | logWrite["Unknown message type; message="<>ToString[$message]]; 486 | ]; 487 | ]; 488 | ]; 489 | 490 | 491 | 492 | 493 | (* ::Section:: *) 494 | (* Evaluation Handler*) 495 | 496 | Unprotect[Print]; 497 | 498 | Print[args___] := Block[{$inPatch = True, printStrm, printfile}, 499 | printStrm = OpenWrite[FileNameJoin[{$TemporaryDirectory, "testfile.txt"}], FormatType -> OutputForm]; 500 | AppendTo[$Output, printStrm]; 501 | Print[args]; 502 | $Output = DeleteCases[$Output, printStrm]; 503 | printfile = Close[printStrm]; 504 | UpdateOutputQueue[TextHeader[Read[printfile, Record, RecordSeparators -> {}]]]; 505 | Close[printfile]; 506 | 507 | DeleteFile[printfile]; 508 | handleOutput[]; 509 | 510 | ]/;Not[TrueQ[$inPatch]]; 511 | 512 | Protect[Print]; 513 | 514 | 515 | 516 | handleEvaluation[]:=Module[{eval, res, strm, input, inputString, fullEval, printfile}, 517 | 518 | (* 519 | Message for evaluation: 520 | <|3358 -> <|"uuid" -> "...", "text" -> "2+2\n2+3\n2+4\n", "type" -> "evaluate-cell", "progress" -> "complete"|>|> 521 | *) 522 | 523 | logWriteFile[ "handleEvaluation: Entry $evaluationQueue :> " <> ToString[InputForm[$evaluationQueue]] <> "\n"]; 524 | 525 | $evaluating = queuePop[$evaluationQueue]; 526 | 527 | (* 528 | <|"uuid" -> "...", "text" -> "2+2\n2+3\n2+4\n", "type" -> "evaluate-cell", "progress" -> "complete"|> 529 | *) 530 | 531 | If[$evaluating["type"] === "evaluate-cell", 532 | strm = StringToStream[$evaluating["text"]]; 533 | evalRes = 0; 534 | fullEval = {}; 535 | 536 | While[evalRes =!= EndOfFile, 537 | 538 | input = Read[strm, Hold[Expression]]; 539 | 540 | logWriteFile[ "handleEvaluation: input :> \n" <> ToString[InputForm[input]] <> "\n"]; 541 | 542 | evalRes = ReleaseHold[input]; 543 | 544 | 545 | If[evalRes =!= EndOfFile, 546 | 547 | $lineNumber = $lineNumber + 1; 548 | 549 | Unprotect[In, Out, $Line]; 550 | $Line = $lineNumber + 1; 551 | With[{in = input}, In[$lineNumber] := ReleaseHold[in]]; 552 | Out[$lineNumber] = evalRes; 553 | Protect[In, Out, $Line]; 554 | 555 | inputString = "In[" <> ToString[$lineNumber] <> "]:= "; 556 | 557 | UpdateOutputQueue[OutputHeader["Out[" <> ToString[$lineNumber] <> "]= "]]; 558 | If[evalRes =!= Null, UpdateOutputQueue[ExpressionHeader[evalRes]]]; 559 | 560 | handleOutput[] 561 | ]; 562 | 563 | ]; 564 | ]; 565 | 566 | UpdateOutputQueue[InputHeader[inputString]]; 567 | handleOutput[]; 568 | 569 | ]; 570 | 571 | 572 | (* ::Section:: *) 573 | (* Communication settings *) 574 | 575 | $zmqserver=SocketOpen[{"127.0.0.1",zmqPort},"ZMQ"]; 576 | If[Head[$zmqserver]=!=SocketObject,logError["Failed to create a ZeroMQ local server on port "<>ToString[zmqPort]<>"."];Exit[];]; 577 | logWrite[TemplateApply["[address tcp://127.0.0.1:``]\n",$zmqserver["DestinationPort"]]]; 578 | 579 | 580 | logWrite[""]; 581 | logWriteFile[ "\n"]; 582 | 583 | 584 | (* ::Section:: *) 585 | (* Main message loop *) 586 | 587 | While[True, 588 | 589 | $messagetext=readMessage[0.03]; 590 | 591 | If[Not[FailureQ[$messagetext]], 592 | 593 | logWriteFile[ "================================ Message cycle starts ========================================\n"]; 594 | logWriteFile[ "MesageLoop:> $messagetext :> " <> StringTake[ToString[InputForm[$messagetext]], UpTo[100]] <> "\n"]; 595 | ]; 596 | 597 | If[Head[$messagetext]===String, 598 | handleMessage[]; 599 | ]; 600 | 601 | If[Length[$evaluationQueue] > 0, 602 | logWriteFile[ "MesageLoop:> $evaluationQueue :> " <> ToString[InputForm[$evaluationQueue]] <> "\n"]; 603 | handleEvaluation[]; 604 | ]; 605 | 606 | If[Length[$outputQueue] > 0, 607 | logWriteFile[ "MesageLoop:> $outputQueue :> " <> ToString[InputForm[$outputQueue]] <> "\n"]; 608 | handleOutput[]; 609 | ]; 610 | 611 | ]; 612 | 613 | 614 | End[] 615 | 616 | EndPackage[] 617 | 618 | (* ::Section:: *) 619 | (*End*) 620 | -------------------------------------------------------------------------------- /src/media/render.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --fraction-line-width: max(0.08em, 1px); 3 | --script-font-size: max(71%, 8pt); /* getScriptStyle */ 4 | --line-height: 1.1; 5 | } 6 | 7 | :host { 8 | --fraction-line-width: max(0.08em, 1px); 9 | --script-font-size: max(71%, 8pt); /* getScriptStyle */ 10 | --line-height: 1.1; 11 | } 12 | 13 | @font-face { 14 | font-family: "wlsupplements"; 15 | src: url(data:application/font-woff;base64,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) format('woff'); 16 | } 17 | 18 | pre { 19 | font-family: Consolas, Courier, monospace 20 | } 21 | 22 | pre > .wl-message { 23 | color: var(--vscode-editorError-foreground) 24 | } 25 | 26 | .font-measure-canvas { 27 | display: block; 28 | width: max-content; 29 | position: fixed; 30 | top: 0px; 31 | left: 0px; 32 | z-index: -1; 33 | opacity: 0; 34 | } 35 | .font-measure-canvas > * { 36 | display: inline-block; 37 | } 38 | 39 | .wexpr { 40 | font-family: Consolas, Courier, monospace; 41 | line-height: var(--line-height); 42 | } 43 | 44 | .wexpr.traditional-form { 45 | font-family: 'Times New Roman', Times, serif 46 | } 47 | 48 | w, wb, 49 | wrow, wsub, wsup, wsubsup, wover, wunder, wunderover, 50 | wfrac, wsqrt, wgraph, wgrid, wframe, wpane, 51 | wunknown, wfailed { 52 | margin: 0; 53 | padding: 0; 54 | border: 0; 55 | font-size: 100%; 56 | font: inherit; 57 | vertical-align: baseline; 58 | display: inline-block; 59 | white-space: nowrap; 60 | line-height: var(--line-height); 61 | } 62 | .wexpr > wrow, .wexpr > w, 63 | wframe > wrow, wframe > w, 64 | wpane > wrow, wpane > w { 65 | display: inline; 66 | white-space: normal; 67 | word-break: normal; 68 | overflow-wrap: anywhere; 69 | } 70 | wrow > wrow, wrow > w { 71 | white-space: inherit; 72 | word-break: inherit; 73 | overflow-wrap: inherit; 74 | } 75 | w.italic { 76 | font-style: italic; 77 | } 78 | wrow > wrow { 79 | display: inherit; 80 | } 81 | w, wrow { 82 | text-decoration: inherit; 83 | } 84 | wgraph { 85 | vertical-align: middle; 86 | position: relative; 87 | } 88 | 89 | wunknown, wfailed { 90 | color: var(--vscode-editorError-foreground); 91 | border: dashed 1px var(--vscode-editorError-foreground); 92 | cursor: help; 93 | } 94 | wunknown:after { 95 | content: "[…]" 96 | } 97 | 98 | w.symbol { 99 | font-family: 'wlsupplements'; 100 | } 101 | 102 | w.large-symbol { 103 | font-family: 'wlsupplements'; 104 | line-height: calc(var(--line-height) + 0.5); 105 | } 106 | 107 | w.small-symbol { 108 | font-family: 'wlsupplements'; 109 | line-height: calc(var(--line-height) - 0.5); 110 | } 111 | 112 | 113 | /* baseline indicator element */ 114 | wrow > w:first-child:before, 115 | wsub > w:first-child:before, 116 | wsup > w:first-child:before, 117 | wsubsup > w:first-child:before, 118 | wfrac > :last-child > w:first-child:before, 119 | wsqrt > w:nth-child(3):before { 120 | display: inline-block; 121 | content: ""; 122 | } 123 | 124 | /* margins */ 125 | wrow > w:not(:first-child) { 126 | margin: 0 0.1ch; 127 | } 128 | wsub, wsup, wsubsup, wover, wunder, wunderover { 129 | margin: 0 0.1ch; 130 | } 131 | wfrac { 132 | margin: 0 0.2ch; 133 | padding: 0 0.2ch; 134 | } 135 | wsqrt { 136 | margin: 0 0.1ch; 137 | } 138 | 139 | 140 | wfrac { 141 | text-align: center; 142 | } 143 | wfrac > :first-child { 144 | display: block; 145 | } 146 | wfrac > :last-child { 147 | display: grid; 148 | } 149 | wfrac > :last-child > :first-child { 150 | height: calc(1em * var(--line-height)); 151 | margin-top: calc(-0.45em * var(--line-height)); 152 | margin-bottom: calc(-0.4em * var(--line-height)); 153 | margin-left: -0.2ch; 154 | margin-right: -0.2ch; 155 | transform: translateY(calc(0.6em * var(--line-height))); 156 | } 157 | wfrac > :last-child > :last-child { 158 | display: block; 159 | z-index: 1; 160 | } 161 | wfrac.script > :last-child > :last-child, 162 | wfrac.script > :first-child { 163 | font-size: var(--script-font-size); 164 | } 165 | wfrac > :last-child > :first-child { 166 | border-top: solid var(--fraction-line-width); 167 | } 168 | wfrac.script > :last-child > :first-child { 169 | border-top: solid calc(0.71 * var(--fraction-line-width)); 170 | } 171 | 172 | wsup > :last-child { 173 | font-size: var(--script-font-size); 174 | vertical-align: 1.3ex; 175 | } 176 | wsub > :last-child { 177 | font-size: var(--script-font-size); 178 | vertical-align: -0.7ex; 179 | } 180 | 181 | wsubsup > :last-child { 182 | font-size: var(--script-font-size); 183 | vertical-align: middle; 184 | } 185 | wsubsup > :last-child > :nth-child(2) { 186 | display: block; 187 | height: 0px; 188 | } 189 | wsubsup > :last-child:after { 190 | content: "."; 191 | font-size: 0pt; 192 | display: block; 193 | } 194 | 195 | wunder { 196 | display: inline-grid; 197 | text-align: center; 198 | } 199 | wunder > :last-child { 200 | display: block; 201 | font-size: var(--script-font-size); 202 | } 203 | wover { 204 | display: inline-block; 205 | text-align: center; 206 | } 207 | wover > :first-child { 208 | display: block; 209 | font-size: var(--script-font-size); 210 | } 211 | 212 | wunderover { 213 | text-align: center; 214 | } 215 | wunderover > :first-child { 216 | display: block; 217 | font-size: var(--script-font-size); 218 | } 219 | wunderover > :last-child { 220 | display: grid; 221 | } 222 | wunderover > :last-child > :last-child { 223 | display: block; 224 | font-size: var(--script-font-size); 225 | } 226 | 227 | wgraph { 228 | vertical-align: middle; 229 | margin: calc(1px + 0.1em); 230 | } 231 | wgraph:focus { 232 | outline: 1px solid orange; 233 | } 234 | wgraph > img { 235 | width: 100%; 236 | height: 100%; 237 | position: absolute; 238 | top: 0; 239 | left: 0; 240 | image-rendering: auto; 241 | } 242 | body.vscode-dark wgraph > img, 243 | body.vscode-high-contrast wgraph > img { 244 | filter: invert(1) hue-rotate(180deg); 245 | } 246 | wgraph > .resize-widget { 247 | display: none; 248 | position: absolute; 249 | top: calc(100% - 5px); 250 | left: calc(100% - 5px); 251 | width: 5px; 252 | height: 5px; 253 | background-color: var(--vscode-editorLightBulb-foreground); 254 | cursor: se-resize; 255 | } 256 | wgraph:focus > .resize-widget { 257 | display: block; 258 | } 259 | 260 | wframe { 261 | padding: var(--fraction-line-width); 262 | border: solid max(0.05em, 1px); 263 | vertical-align: middle; 264 | } 265 | 266 | wpane { 267 | vertical-align: middle; 268 | overflow: hidden; 269 | } 270 | 271 | wgrid { 272 | display: inline-grid; 273 | vertical-align: middle; 274 | margin: 0.1em; 275 | justify-items: stretch; 276 | align-items: baseline; 277 | border-top: solid 0px; 278 | border-left: solid 0px; 279 | } 280 | wgrid > w { 281 | display: block; 282 | text-align: center; 283 | padding: 0.1em 0.3em; 284 | } 285 | wgrid > w[style*="grid-row-start"] { 286 | align-self: stretch 287 | } 288 | wgrid.outer-frame { 289 | border: solid max(0.05em, 1px); 290 | } 291 | wgrid.all-frame { 292 | border-left: solid max(0.05em, 1px); 293 | border-top: solid max(0.05em, 1px); 294 | } 295 | wgrid.all-frame > w { 296 | border-right: solid max(0.05em, 1px); 297 | border-bottom: solid max(0.05em, 1px); 298 | } 299 | 300 | wsqrt { 301 | display: inline-flex; 302 | align-items: baseline; 303 | } 304 | 305 | wsqrt > :nth-child(1) { 306 | display: inline-flex; 307 | flex-direction: column-reverse; 308 | height: 1em; 309 | align-self: flex-end; 310 | align-items: flex-end; 311 | } 312 | wsqrt > :nth-child(1) > :nth-child(1), 313 | wsqrt > :nth-child(2) { 314 | display: inline-flex; 315 | align-items: flex-end; 316 | font-family: "wlsupplements"; 317 | overflow: hidden; 318 | line-height: 1.0; 319 | } 320 | wsqrt > :nth-child(1) > :nth-child(1) { 321 | margin-top: 0.2em; 322 | overflow: visible; 323 | } 324 | wsqrt > :nth-child(1) > :nth-child(1) > *, 325 | wsqrt > :nth-child(2) > * { 326 | transform-origin: 50% 100%; 327 | } 328 | wsqrt > :nth-child(1) > :nth-child(2) { 329 | font-size: var(--script-font-size); 330 | } 331 | 332 | wsqrt > :nth-child(2) { 333 | align-self: stretch; 334 | } 335 | wsqrt > :nth-child(2):empty { 336 | border-right: var(--fraction-line-width) solid; 337 | } 338 | 339 | wsqrt > :nth-child(3) { 340 | border-top: solid var(--fraction-line-width); 341 | padding: 0 0.15ch 0 0.15ch 342 | } 343 | 344 | wsqrt > :nth-child(4) { 345 | align-self: flex-start; 346 | line-height: 1.0; 347 | font-family: "wlsupplements"; 348 | overflow: hidden; 349 | } 350 | wsqrt > :nth-child(4):before { 351 | content: "\e08a"; 352 | } 353 | 354 | /* 355 | brackets 356 | */ 357 | 358 | wb { 359 | height: 0px; 360 | width: fit-content; 361 | vertical-align: middle; 362 | } 363 | 364 | wb:not([ch]) { 365 | transform: translateY(calc(-0.6 * 1.15em)); 366 | } 367 | 368 | wb[ch] { 369 | display: inline-flex; 370 | align-items: center; 371 | font-family: "wlsupplements"; 372 | line-height: 1em; 373 | } 374 | 375 | wb[ch] * { 376 | line-height: 1em; 377 | } 378 | 379 | wb[ch] > w > w:nth-child(odd) { 380 | display: block; 381 | } 382 | 383 | wb[ch] > w > w:nth-child(even) { 384 | display: grid; 385 | justify-items: center; 386 | align-items: center; 387 | overflow: hidden; 388 | } 389 | 390 | #context-menu { 391 | border: 1px solid var(--vscode-editorWidget-border); 392 | background-color: var(--vscode-editor-background); 393 | box-shadow: 2px 2px 10px 2px var(--vscode-widget-shadow); 394 | border-radius: 3px; 395 | position: absolute; 396 | display: none; 397 | opacity: 0.0; 398 | transition: opacity 0.15s; 399 | } 400 | 401 | #context-menu:focus { 402 | display: block; 403 | opacity: 1.0; 404 | } 405 | 406 | #context-menu > .menu-options { 407 | list-style: none; 408 | padding: 3px 0; 409 | } 410 | 411 | #context-menu > .menu-options > .menu-option { 412 | font-size: 90%; 413 | padding: 4px 15px 4px 10px; 414 | cursor: default; 415 | } 416 | 417 | #context-menu > .menu-options > .menu-option:hover { 418 | background: var(--vscode-toolbar-hoverBackground); 419 | } 420 | -------------------------------------------------------------------------------- /themes/wolfram-dark.json: -------------------------------------------------------------------------------- 1 | { 2 | // Theme created following Wolfram Alpha dark theme 3 | // modified from source: vscode-intellij-darcula-theme 4 | // https://github.com/xr0master/vscode-intellij-darcula-theme/blob/master/themes/darcula-color-theme.json 5 | 6 | "$schema": "vscode://schemas/color-theme", 7 | "name": "Wolfram (Dark)", 8 | "type": "dark", 9 | "semanticHighlighting": true, 10 | "semanticTokenColors": { 11 | // Module, With and Block variables 12 | "variable.Module": "#79a185", 13 | "variable.Block": "#79a185", 14 | "variable.With": "#79a185", 15 | "constant.With": "#79a185", 16 | "variable.shadowed": "#f2430e", 17 | "variable.error": "#ff0000", 18 | "variable.unused": "#D4D4D4", 19 | "parameter": "#D4D4D4", 20 | "parameter.shadowed": "#f2430e", 21 | "parameter.error": "#ff0000", 22 | "parameter.unused": "#D4D4D4", 23 | "constant.shadowed": "#448959", 24 | "constant.error": "#ff0000", 25 | "constant.unused": "#D4D4D4" 26 | }, 27 | "colors": { 28 | "activityBar.background": "#3c3f41", 29 | "activityBar.border": "#4b4b4b", 30 | "activityBar.foreground": "#ffffff", 31 | "activityBarBadge.background": "#cc7832", 32 | "dropdown.background": "#3c3f41", 33 | "dropdown.border": "#4b4b4b", 34 | "dropdown.foreground": "#bababa", 35 | "editor.background": "#333333", 36 | "editor.foreground": "#a9b7c6", 37 | "editor.inactiveSelectionBackground": "#3a3d41", 38 | "editor.lineHighlightBackground": "#323232", 39 | "editor.selectionHighlightBackground": "#415a41", 40 | "editorIndentGuide.activeBackground1": "#606060", 41 | "editorIndentGuide.background1": "#4b4b4b", 42 | "editorLineNumber.activeForeground": "#999999", 43 | "editorLineNumber.foreground": "#606366", 44 | "input.background": "#3c3f41", 45 | "input.border": "#4b4b4b", 46 | "input.foreground": "#bababa", 47 | "input.placeholderForeground": "#a6a6a6", 48 | "list.dropBackground": "#373a3c", 49 | "menu.background": "#3c3f41", 50 | "menu.foreground": "#bababa", 51 | "panel.background": "#3c3f41", 52 | "panel.border": "#4b4b4b", 53 | "panelTitle.activeBorder": "#bababa", 54 | "panelTitle.activeForeground": "#bababa", 55 | "panelTitle.inactiveForeground": "#888888", 56 | "scrollbarSlider.activeBackground": "#707070", 57 | "scrollbarSlider.background": "#505050", 58 | "scrollbarSlider.hoverBackground": "#676767", 59 | "settings.numberInputBackground": "#292929", 60 | "settings.textInputBackground": "#292929", 61 | "sideBar.background": "#3c3f41", 62 | "sideBar.border": "#4b4b4b", 63 | "sideBar.foreground": "#bababa", 64 | "sideBarSectionHeader.foreground": "#bababa", 65 | "sideBarTitle.foreground": "#bababa", 66 | "statusBar.background": "#3c3f41", 67 | "statusBar.border": "#4b4b4b", 68 | "statusBar.foreground": "#bababa", 69 | "tab.activeBackground": "#515658", 70 | "tab.activeBorder": "#bababa", 71 | "tab.activeForeground": "#bababa", 72 | "tab.border": "#4b4b4b", 73 | "tab.inactiveBackground": "#3c3e3f", 74 | "tab.inactiveForeground": "#a1a1a1", 75 | "terminal.ansiBlack": "#ffffff", 76 | "terminal.ansiBlue": "#5394ec", 77 | "terminal.ansiBrightBlue": "#7eaef1", 78 | "terminal.ansiBrightCyan": "#6cdada", 79 | "terminal.ansiBrightGreen": "#a8c023", 80 | "terminal.ansiBrightMagenta": "#ff99ff", 81 | "terminal.ansiBrightRed": "#ff8785", 82 | "terminal.ansiBrightYellow": "#ffff00", 83 | "terminal.ansiCyan": "#299999", 84 | "terminal.ansiGreen": "#a8c023", 85 | "terminal.ansiMagenta": "#ae8abe", 86 | "terminal.ansiRed": "#ff6b68", 87 | "terminal.ansiWhite": "#1f1f1f", 88 | "terminal.ansiYellow": "#d6bf55", 89 | "terminal.background": "#2b2b2b", 90 | "terminal.border": "#4b4b4b", 91 | "widget.shadow": "#1a1a1aaa" 92 | }, 93 | "tokenColors": [ 94 | { 95 | "scope": [ 96 | "meta.embedded", 97 | "source.groovy.embedded" 98 | ], 99 | "settings": { 100 | "foreground": "#D4D4D4" 101 | } 102 | }, 103 | { 104 | "scope": "emphasis", 105 | "settings": { 106 | "fontStyle": "italic" 107 | } 108 | }, 109 | { 110 | "scope": "strong", 111 | "settings": { 112 | "fontStyle": "bold" 113 | } 114 | }, 115 | { 116 | "scope": "header", 117 | "settings": { 118 | "foreground": "#000080" 119 | } 120 | }, 121 | { 122 | "scope": "comment", 123 | "settings": { 124 | "foreground": "#6A9955" 125 | } 126 | }, 127 | { 128 | "scope": "constant.language", 129 | "settings": { 130 | "foreground": "#569cd6" 131 | } 132 | }, 133 | { 134 | "scope": [ 135 | "constant.numeric" 136 | ], 137 | "settings": { 138 | "foreground": "#b5cea8" 139 | } 140 | }, 141 | { 142 | "scope": "constant.regexp", 143 | "settings": { 144 | "foreground": "#646695" 145 | } 146 | }, 147 | { 148 | "scope": "entity.name.tag", 149 | "settings": { 150 | "foreground": "#569cd6" 151 | } 152 | }, 153 | { 154 | "scope": "entity.name.tag.css", 155 | "settings": { 156 | "foreground": "#d7ba7d" 157 | } 158 | }, 159 | { 160 | "scope": "entity.other.attribute-name", 161 | "settings": { 162 | "foreground": "#9cdcfe" 163 | } 164 | }, 165 | { 166 | "scope": [ 167 | "entity.other.attribute-name.class.css", 168 | "entity.other.attribute-name.class.mixin.css", 169 | "entity.other.attribute-name.id.css", 170 | "entity.other.attribute-name.parent-selector.css", 171 | "entity.other.attribute-name.pseudo-class.css", 172 | "entity.other.attribute-name.pseudo-element.css", 173 | "source.css.less entity.other.attribute-name.id", 174 | "entity.other.attribute-name.attribute.scss", 175 | "entity.other.attribute-name.scss" 176 | ], 177 | "settings": { 178 | "foreground": "#d7ba7d" 179 | } 180 | }, 181 | { 182 | "scope": "invalid", 183 | "settings": { 184 | "foreground": "#f44747" 185 | } 186 | }, 187 | { 188 | "scope": "markup.underline", 189 | "settings": { 190 | "fontStyle": "underline" 191 | } 192 | }, 193 | { 194 | "scope": "markup.bold", 195 | "settings": { 196 | "fontStyle": "bold", 197 | "foreground": "#569cd6" 198 | } 199 | }, 200 | { 201 | "scope": "markup.heading", 202 | "settings": { 203 | "fontStyle": "bold", 204 | "foreground": "#569cd6" 205 | } 206 | }, 207 | { 208 | "scope": "markup.italic", 209 | "settings": { 210 | "fontStyle": "italic" 211 | } 212 | }, 213 | { 214 | "scope": "markup.inserted", 215 | "settings": { 216 | "foreground": "#b5cea8" 217 | } 218 | }, 219 | { 220 | "scope": "markup.deleted", 221 | "settings": { 222 | "foreground": "#ce9178" 223 | } 224 | }, 225 | { 226 | "scope": "markup.changed", 227 | "settings": { 228 | "foreground": "#569cd6" 229 | } 230 | }, 231 | { 232 | "scope": "punctuation.definition.quote.begin.markdown", 233 | "settings": { 234 | "foreground": "#6A9955" 235 | } 236 | }, 237 | { 238 | "scope": "punctuation.definition.list.begin.markdown", 239 | "settings": { 240 | "foreground": "#6796e6" 241 | } 242 | }, 243 | { 244 | "scope": "markup.inline.raw", 245 | "settings": { 246 | "foreground": "#ce9178" 247 | } 248 | }, 249 | { 250 | "name": "brackets of XML/HTML tags", 251 | "scope": "punctuation.definition.tag", 252 | "settings": { 253 | "foreground": "#808080" 254 | } 255 | }, 256 | { 257 | "scope": "meta.preprocessor", 258 | "settings": { 259 | "foreground": "#569cd6" 260 | } 261 | }, 262 | { 263 | "scope": "meta.preprocessor.string", 264 | "settings": { 265 | "foreground": "#ce9178" 266 | } 267 | }, 268 | { 269 | "scope": "meta.preprocessor.numeric", 270 | "settings": { 271 | "foreground": "#b5cea8" 272 | } 273 | }, 274 | { 275 | "scope": "meta.structure.dictionary.key.python", 276 | "settings": { 277 | "foreground": "#9cdcfe" 278 | } 279 | }, 280 | { 281 | "scope": "meta.diff.header", 282 | "settings": { 283 | "foreground": "#569cd6" 284 | } 285 | }, 286 | { 287 | "scope": "storage", 288 | "settings": { 289 | "foreground": "#569cd6" 290 | } 291 | }, 292 | { 293 | "scope": "storage.type", 294 | "settings": { 295 | "foreground": "#569cd6" 296 | } 297 | }, 298 | { 299 | "scope": "storage.modifier", 300 | "settings": { 301 | "foreground": "#569cd6" 302 | } 303 | }, 304 | { 305 | "scope": "string", 306 | "settings": { 307 | "foreground": "#ce9178" 308 | } 309 | }, 310 | { 311 | "scope": "string.tag", 312 | "settings": { 313 | "foreground": "#ce9178" 314 | } 315 | }, 316 | { 317 | "scope": "string.value", 318 | "settings": { 319 | "foreground": "#ce9178" 320 | } 321 | }, 322 | { 323 | "scope": "string.regexp", 324 | "settings": { 325 | "foreground": "#d16969" 326 | } 327 | }, 328 | { 329 | "name": "String interpolation", 330 | "scope": [ 331 | "punctuation.definition.template-expression.begin", 332 | "punctuation.definition.template-expression.end", 333 | "punctuation.section.embedded" 334 | ], 335 | "settings": { 336 | "foreground": "#569cd6" 337 | } 338 | }, 339 | { 340 | "name": "Reset JavaScript string interpolation expression", 341 | "scope": [ 342 | "meta.template.expression" 343 | ], 344 | "settings": { 345 | "foreground": "#d4d4d4" 346 | } 347 | }, 348 | { 349 | "scope": [ 350 | "support.type.vendored.property-name", 351 | "support.type.property-name", 352 | "variable.css", 353 | "variable.scss", 354 | "variable.other.less", 355 | "source.coffee.embedded" 356 | ], 357 | "settings": { 358 | "foreground": "#9cdcfe" 359 | } 360 | }, 361 | { 362 | "scope": "keyword", 363 | "settings": { 364 | "foreground": "#569cd6" 365 | } 366 | }, 367 | { 368 | "scope": "keyword.control", 369 | "settings": { 370 | "foreground": "#569cd6" 371 | } 372 | }, 373 | { 374 | "scope": "keyword.operator", 375 | "settings": { 376 | "foreground": "#d4d4d4" 377 | } 378 | }, 379 | { 380 | "scope": [ 381 | "keyword.operator.new", 382 | "keyword.operator.expression", 383 | "keyword.operator.cast", 384 | "keyword.operator.sizeof", 385 | "keyword.operator.instanceof", 386 | "keyword.operator.logical.python" 387 | ], 388 | "settings": { 389 | "foreground": "#569cd6" 390 | } 391 | }, 392 | { 393 | "scope": "keyword.other.unit", 394 | "settings": { 395 | "foreground": "#b5cea8" 396 | } 397 | }, 398 | { 399 | "scope": [ 400 | "punctuation.section.embedded.begin.php", 401 | "punctuation.section.embedded.end.php" 402 | ], 403 | "settings": { 404 | "foreground": "#569cd6" 405 | } 406 | }, 407 | { 408 | "scope": "support.function.git-rebase", 409 | "settings": { 410 | "foreground": "#9cdcfe" 411 | } 412 | }, 413 | { 414 | "scope": "constant.sha.git-rebase", 415 | "settings": { 416 | "foreground": "#b5cea8" 417 | } 418 | }, 419 | { 420 | "name": "coloring of the Java import and package identifiers", 421 | "scope": [ 422 | "storage.modifier.import.java", 423 | "variable.language.wildcard.java", 424 | "storage.modifier.package.java" 425 | ], 426 | "settings": { 427 | "foreground": "#d4d4d4" 428 | } 429 | }, 430 | { 431 | "name": "this.self", 432 | "scope": "variable.language", 433 | "settings": { 434 | "foreground": "#569cd6" 435 | } 436 | }, 437 | { 438 | "name": "Function declarations", 439 | "scope": [ 440 | "entity.name.function", 441 | "support.function", 442 | "support.constant.handlebars" 443 | ], 444 | "settings": { 445 | "foreground": "#DCDCAA" 446 | } 447 | }, 448 | { 449 | "name": "Types declaration and references", 450 | "scope": [ 451 | "meta.return-type", 452 | "support.class", 453 | "support.type", 454 | "entity.name.type", 455 | "entity.name.class", 456 | "storage.type.numeric.go", 457 | "storage.type.byte.go", 458 | "storage.type.boolean.go", 459 | "storage.type.string.go", 460 | "storage.type.uintptr.go", 461 | "storage.type.error.go", 462 | "storage.type.rune.go", 463 | "storage.type.cs", 464 | "storage.type.generic.cs", 465 | "storage.type.modifier.cs", 466 | "storage.type.variable.cs", 467 | "storage.type.annotation.java", 468 | "storage.type.generic.java", 469 | "storage.type.java", 470 | "storage.type.object.array.java", 471 | "storage.type.primitive.array.java", 472 | "storage.type.primitive.java", 473 | "storage.type.token.java", 474 | "storage.type.groovy", 475 | "storage.type.annotation.groovy", 476 | "storage.type.parameters.groovy", 477 | "storage.type.generic.groovy", 478 | "storage.type.object.array.groovy", 479 | "storage.type.primitive.array.groovy", 480 | "storage.type.primitive.groovy" 481 | ], 482 | "settings": { 483 | "foreground": "#4EC9B0" 484 | } 485 | }, 486 | { 487 | "name": "Types declaration and references, TS grammar specific", 488 | "scope": [ 489 | "meta.type.cast.expr", 490 | "meta.type.new.expr", 491 | "support.constant.math", 492 | "support.constant.dom", 493 | "support.constant.json", 494 | "entity.other.inherited-class" 495 | ], 496 | "settings": { 497 | "foreground": "#4EC9B0" 498 | } 499 | }, 500 | { 501 | "name": "Control flow keywords", 502 | "scope": "keyword.control", 503 | "settings": { 504 | "foreground": "#C586C0" 505 | } 506 | }, 507 | { 508 | "name": "Variable and parameter name", 509 | "scope": [ 510 | "variable", 511 | "meta.definition.variable.name", 512 | "support.variable", 513 | "entity.name.variable" 514 | ], 515 | "settings": { 516 | "foreground": "#9CDCFE" 517 | } 518 | }, 519 | { 520 | "name": "Object keys, TS grammar specific", 521 | "scope": [ 522 | "meta.object-literal.key" 523 | ], 524 | "settings": { 525 | "foreground": "#9CDCFE" 526 | } 527 | }, 528 | { 529 | "name": "CSS property value", 530 | "scope": [ 531 | "support.constant.property-value", 532 | "support.constant.font-name", 533 | "support.constant.media-type", 534 | "support.constant.media", 535 | "constant.other.color.rgb-value", 536 | "constant.other.rgb-value", 537 | "support.constant.color" 538 | ], 539 | "settings": { 540 | "foreground": "#CE9178" 541 | } 542 | }, 543 | { 544 | "name": "Regular expression groups", 545 | "scope": [ 546 | "punctuation.definition.group.regexp", 547 | "punctuation.definition.group.assertion.regexp", 548 | "punctuation.definition.character-class.regexp", 549 | "punctuation.character.set.begin.regexp", 550 | "punctuation.character.set.end.regexp", 551 | "keyword.operator.negation.regexp", 552 | "support.other.parenthesis.regexp" 553 | ], 554 | "settings": { 555 | "foreground": "#CE9178" 556 | } 557 | }, 558 | { 559 | "scope": [ 560 | "constant.character.character-class.regexp", 561 | "constant.other.character-class.set.regexp", 562 | "constant.other.character-class.regexp", 563 | "constant.character.set.regexp" 564 | ], 565 | "settings": { 566 | "foreground": "#d16969" 567 | } 568 | }, 569 | { 570 | "scope": [ 571 | "keyword.operator.or.regexp", 572 | "keyword.control.anchor.regexp" 573 | ], 574 | "settings": { 575 | "foreground": "#DCDCAA" 576 | } 577 | }, 578 | { 579 | "scope": "keyword.operator.quantifier.regexp", 580 | "settings": { 581 | "foreground": "#d7ba7d" 582 | } 583 | }, 584 | { 585 | "scope": "constant.character", 586 | "settings": { 587 | "foreground": "#569cd6" 588 | } 589 | }, 590 | { 591 | "scope": "constant.character.escape", 592 | "settings": { 593 | "foreground": "#d7ba7d" 594 | } 595 | }, 596 | { 597 | "scope": "token.info-token", 598 | "settings": { 599 | "foreground": "#6796e6" 600 | } 601 | }, 602 | { 603 | "scope": "token.warn-token", 604 | "settings": { 605 | "foreground": "#cd9731" 606 | } 607 | }, 608 | { 609 | "scope": "token.error-token", 610 | "settings": { 611 | "foreground": "#f44747" 612 | } 613 | }, 614 | { 615 | "scope": "token.debug-token", 616 | "settings": { 617 | "foreground": "#b267e6" 618 | } 619 | }, 620 | { 621 | "scope": "string", 622 | "settings": { 623 | "foreground": "#6A8759", 624 | "fontStyle": "bold" 625 | } 626 | }, 627 | { 628 | "scope": "keyword - keyword.operator", 629 | "settings": { 630 | "foreground": "#CC7832" 631 | } 632 | }, 633 | { 634 | "scope": "keyword.control", 635 | "settings": { 636 | "foreground": "#CC7832" 637 | } 638 | }, 639 | { 640 | "scope": "storage", 641 | "settings": { 642 | "foreground": "#CC7832" 643 | } 644 | }, 645 | { 646 | "scope": "storage.type", 647 | "settings": { 648 | "foreground": "#CC7832" 649 | } 650 | }, 651 | { 652 | "scope": "constant.numeric", 653 | "settings": { 654 | "foreground": "#01adb8" 655 | } 656 | }, 657 | { 658 | "scope": "entity.name.type", 659 | "settings": { 660 | "foreground": "#CC7832" 661 | } 662 | }, 663 | { 664 | "scope": "entity.name.class", 665 | "settings": { 666 | "foreground": "#CC7832" 667 | } 668 | }, 669 | { 670 | "scope": "support.type", 671 | "settings": { 672 | "foreground": "#CC7832" 673 | } 674 | }, 675 | { 676 | "scope": "support.class", 677 | "settings": { 678 | "foreground": "#CC7832" 679 | } 680 | }, 681 | { 682 | "scope": "entity.name.function", 683 | "settings": { 684 | // "foreground": "#FFC66D" 685 | "foreground": "#d68c2d" 686 | } 687 | }, 688 | { 689 | "scope": "support.function", 690 | "settings": { 691 | "foreground": "#FFC66D" 692 | } 693 | }, 694 | { 695 | "scope": "variable", 696 | "settings": { 697 | "foreground": "#d4d4d4" 698 | } 699 | }, 700 | { 701 | "scope": "entity.name.variable", 702 | "settings": { 703 | "foreground": "#9876AA" 704 | } 705 | }, 706 | { 707 | "name": "Comments", 708 | "scope": [ 709 | "comment", 710 | "comment.block", 711 | "comment.line" 712 | ], 713 | "settings": { 714 | "foreground": "#808080", 715 | "fontStyle": "italic" 716 | } 717 | }, 718 | { 719 | "scope": [ 720 | "punctuation.terminator.statement", 721 | "punctuation.separator.comma", 722 | "punctuation.separator.parameter", 723 | "punctuation.separator.dictionary.key-value.json", 724 | "punctuation.separator.dictionary.key-value.json.comments", 725 | "punctuation.separator.dictionary.pair.json", 726 | "punctuation.separator.dictionary.pair.json.comments", 727 | "punctuation.separator.array.json", 728 | "punctuation.separator.array.json.comments", 729 | "constant.character.escape", 730 | "keyword.control.anchor.regexp" 731 | ], 732 | "settings": { 733 | "foreground": "#CC7832" 734 | } 735 | }, 736 | { 737 | "name": "Global keywords", 738 | "scope": [ 739 | "constant.language", 740 | "keyword.control", 741 | "keyword.operator.expression", 742 | "keyword.operator.new", 743 | "keyword.other.debugger", 744 | "support.type", 745 | "storage.type", 746 | "storage.modifier", 747 | "variable.language.super", 748 | "variable.language.this" 749 | ], 750 | "settings": { 751 | // "foreground": "#cb9e55", 752 | "foreground": "#FFC66D", 753 | // "fontStyle": "italic" 754 | } 755 | }, 756 | { 757 | "name": "String", 758 | "scope": [ 759 | "punctuation.definition.string", 760 | "string.regexp", 761 | "constant.other.character-class" 762 | ], 763 | "settings": { 764 | "foreground": "#6A8759" 765 | } 766 | }, 767 | { 768 | "name": "Comment Documentation", 769 | "scope": [ 770 | "comment.block.documentation", 771 | "entity.name.type.instance.jsdoc", 772 | "variable.other.jsdoc" 773 | ], 774 | "settings": { 775 | "foreground": "#6A8759" 776 | } 777 | }, 778 | { 779 | "name": "JsDocs", 780 | "scope": "storage.type.class.jsdoc", 781 | "settings": { 782 | "foreground": "#6A8759", 783 | "fontStyle": "italic bold underline" 784 | } 785 | }, 786 | { 787 | "name": "Main Text Color", 788 | "scope": [ 789 | "punctuation.accessor", 790 | "punctuation.separator.key-value", 791 | "punctuation.definition.block", 792 | "variable.other.readwrite", 793 | "variable.other.constant", 794 | "variable.parameter", 795 | "variable.other.object", 796 | "variable.language.arguments", 797 | "support.variable", 798 | "support.variable.object", 799 | "support.class", 800 | "keyword", 801 | "keyword.operator.logical", 802 | "keyword.operator.optional", 803 | "keyword.operator.type.annotation", 804 | "entity.name.type", 805 | "entity.other.inherited-class", 806 | "constant.language.import-export-all", 807 | "storage.type.function.arrow", 808 | "meta.function.expression", 809 | "meta.object.member", 810 | "meta.brace.round", 811 | "meta.brace.square" 812 | ], 813 | "settings": { 814 | "foreground": "#A9B7C6" 815 | } 816 | }, 817 | { 818 | "name": "Veriables", 819 | "scope": [ 820 | "meta.function-call", 821 | "meta.object.member", 822 | "variable.other.property", 823 | "variable.other.object.property", 824 | "meta.object-literal.key", 825 | "support.variable.property" 826 | ], 827 | "settings": { 828 | "foreground": "#d4d4d4" 829 | } 830 | }, 831 | { 832 | "name": "Constants", 833 | "scope": [ 834 | "variable.other.constant.property", 835 | "variable.other.constant.object.property" 836 | ], 837 | "settings": { 838 | "foreground": "#d4d4d4", 839 | "fontStyle": "italic" 840 | } 841 | }, 842 | { 843 | "name": "JSON", 844 | "scope": [ 845 | "support.type.property-name", 846 | "support.type.property-name.json.comments", 847 | "punctuation.support.type.property-name.end.json.comments", 848 | "punctuation.support.type.property-name.begin.json.comments" 849 | ], 850 | "settings": { 851 | "foreground": "#9876AA", 852 | "fontStyle": "" 853 | } 854 | }, 855 | { 856 | "name": "Regexp Blocks", 857 | "scope": [ 858 | "punctuation.definition.group.regexp", 859 | "punctuation.definition.character-class.regexp", 860 | "punctuation.definition.group.no-capture.regexp", 861 | "punctuation.definition.group.assertion.regexp", 862 | "constant.other.character-class.regexp" 863 | ], 864 | "settings": { 865 | "foreground": "#FFC66D" 866 | } 867 | }, 868 | { 869 | "name": "Regex set and etc", 870 | "scope": [ 871 | "constant.regexp", 872 | "keyword.operator.quantifier.regexp" 873 | ], 874 | "settings": { 875 | "foreground": "#6897BB" 876 | } 877 | }, 878 | { 879 | "name": "XML/HTML tags", 880 | "scope": [ 881 | "keyword.other.doctype.xml", 882 | "entity.name.tag", 883 | "support.class", 884 | "punctuation.definition.tag" 885 | ], 886 | "settings": { 887 | "foreground": "#E8BF6A" 888 | } 889 | }, 890 | { 891 | "name": "XML/HTML attribute name", 892 | "scope": [ 893 | "variable.language.documentroot.xml", 894 | "entity.other.attribute-name", 895 | "support.variable.dom.js" 896 | ], 897 | "settings": { 898 | "foreground": "#BABABA" 899 | } 900 | }, 901 | { 902 | "name": "XML/HTML embedded section", 903 | "scope": [ 904 | "punctuation.section.embedded" 905 | ], 906 | "settings": { 907 | "foreground": "#a9b7c6" 908 | } 909 | }, 910 | { 911 | "name": "HTML attribute value", 912 | "scope": "text.html.basic string", 913 | "settings": { 914 | "foreground": "#A5C261" 915 | } 916 | }, 917 | { 918 | "name": "Constant characters", 919 | "scope": "constant.character.entity", 920 | "settings": { 921 | "foreground": "#6D9CBE" 922 | } 923 | }, 924 | { 925 | "name": "YAML comments", 926 | "scope": "comment.line.number-sign.yaml", 927 | "settings": { 928 | "foreground": "#629755", 929 | "fontStyle": "italic" 930 | } 931 | }, 932 | { 933 | "name": "YAML key", 934 | "scope": "entity.name.tag.yaml", 935 | "settings": { 936 | "foreground": "#CC7832" 937 | } 938 | }, 939 | { 940 | "name": "YAML block/text", 941 | "scope": [ 942 | "source.yaml keyword.control", 943 | "source.yaml constant.language", 944 | "source.yaml storage.modifier.chomping-indicator", 945 | "string.unquoted.plain.out.yaml", 946 | "constant.numeric.integer.yaml" 947 | ], 948 | "settings": { 949 | "foreground": "#A9B7C6", 950 | "fontStyle": "" 951 | } 952 | }, 953 | { 954 | "name": "YAML Anchor/Alias", 955 | "scope": [ 956 | "entity.name.type.anchor.yaml", 957 | "variable.other.alias.yaml" 958 | ], 959 | "settings": { 960 | "foreground": "#E8BF6A" 961 | } 962 | }, 963 | { 964 | "name": "CSS/SCSS global key", 965 | "scope": [ 966 | "keyword.other.important", 967 | "keyword.other.default" 968 | ], 969 | "settings": { 970 | "foreground": "#CC7832", 971 | "fontStyle": "" 972 | } 973 | }, 974 | { 975 | "name": "CSS atribute/selector", 976 | "scope": [ 977 | "entity.other.attribute-name.css", 978 | "entity.other.attribute-name.id.css", 979 | "entity.other.attribute-name.class.css", 980 | "entity.other.attribute-name.pseudo-element.css", 981 | "entity.other.attribute-name.pseudo-class.css", 982 | "entity.other.attribute-name.class.mixin.css", 983 | "support.function.url.css", 984 | "constant.other.unicode-range.css", 985 | "support.constant.language-range.css", 986 | "punctuation.definition.entity.css" 987 | ], 988 | "settings": { 989 | "foreground": "#E8BF6A" 990 | } 991 | }, 992 | { 993 | "name": "CSS URL", 994 | "scope": "variable.parameter.url.css", 995 | "settings": { 996 | "foreground": "#287BDE" 997 | } 998 | }, 999 | { 1000 | "name": "CSS property name", 1001 | "scope": [ 1002 | "support.type.property-name.css", 1003 | "support.type.vendored.property-name" 1004 | ], 1005 | "settings": { 1006 | "foreground": "#BABABA", 1007 | "fontStyle": "" 1008 | } 1009 | }, 1010 | { 1011 | "name": "CSS tag name", 1012 | "scope": [ 1013 | "entity.name.tag.css" 1014 | ], 1015 | "settings": { 1016 | "foreground": "#CC7832" 1017 | } 1018 | }, 1019 | { 1020 | "name": "CSS terminator", 1021 | "scope": [ 1022 | "punctuation.terminator.rule.css" 1023 | ], 1024 | "settings": { 1025 | "foreground": "#CC7832" 1026 | } 1027 | }, 1028 | { 1029 | "name": "CSS colon/braces and etc", 1030 | "scope": [ 1031 | "keyword.other.unit.percentage.css", 1032 | "punctuation.section.function.end.bracket.round.css", 1033 | "punctuation.section.function.begin.bracket.round.css", 1034 | "punctuation.section.property-list.begin.bracket.curly.css", 1035 | "punctuation.section.property-list.end.bracket.curly.css", 1036 | "punctuation.definition.entity.begin.bracket.square.css", 1037 | "punctuation.definition.entity.end.bracket.square.css" 1038 | ], 1039 | "settings": { 1040 | "foreground": "#A9B7C6" 1041 | } 1042 | }, 1043 | { 1044 | "name": "CSS property value", 1045 | "scope": [ 1046 | "support.constant.font-name.css", 1047 | "support.constant.color.w3c-standard-color-name.css", 1048 | "support.constant.property-value.css", 1049 | "keyword.other.unit.px.css", 1050 | "keyword.other.unit.em.css" 1051 | ], 1052 | "settings": { 1053 | "foreground": "#A5C261" 1054 | } 1055 | }, 1056 | { 1057 | "name": "CSS hex color", 1058 | "scope": "constant.other.color.rgb-value.hex.css", 1059 | "settings": { 1060 | "foreground": "#6897BB" 1061 | } 1062 | }, 1063 | { 1064 | "name": "CSS comma", 1065 | "scope": "punctuation.separator.list.comma.css", 1066 | "settings": { 1067 | "foreground": "#CC7832" 1068 | } 1069 | }, 1070 | { 1071 | "name": "Sass/SCSS variable", 1072 | "scope": "variable.scss", 1073 | "settings": { 1074 | "foreground": "#6D9CBE" 1075 | } 1076 | }, 1077 | { 1078 | "name": "Markdown", 1079 | "scope": [ 1080 | "entity.name.section.markdown", 1081 | "punctuation.definition.heading" 1082 | ], 1083 | "settings": { 1084 | "foreground": "#CC7832", 1085 | "fontStyle": "bold" 1086 | } 1087 | }, 1088 | { 1089 | "name": "Markdown link", 1090 | "scope": "markup.underline.link", 1091 | "settings": { 1092 | "foreground": "#6D9CBE", 1093 | "fontStyle": "italic" 1094 | } 1095 | } 1096 | ] 1097 | } --------------------------------------------------------------------------------