├── .editorconfig ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── CI.yml │ └── publish.yml ├── .gitignore ├── .prettierignore ├── .prettierrc.yml ├── .vscode └── settings.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── __tests__ ├── index.js └── package.json ├── data └── documentation-data.yml ├── images ├── icon.png ├── play-arrow-with-logo.svg ├── play-arrow.svg └── processing.png ├── jest.config.js ├── legacy └── pde.tmLanguage.json ├── media ├── error.png ├── hover-1.png └── hover-2.png ├── package.json ├── pde.configuration.json ├── rollup.config.js ├── rollup └── plugins │ ├── package.json │ ├── src │ ├── index.ts │ ├── json-and-yaml.ts │ └── types.ts │ └── tsconfig.json ├── scripts ├── checkDocs.mjs ├── helpers │ └── fetchDocs.mjs └── writeDocs.mjs ├── snippets └── snippets.json ├── src ├── commands │ ├── index.ts │ ├── run.ts │ └── search.ts ├── config.ts ├── diagnostics.ts ├── documentation-data.yml ├── documentation.ts ├── env.d.ts ├── index.ts ├── types.d.ts ├── utils │ ├── escapePath.ts │ ├── index.ts │ └── search.ts └── validateCommand.ts ├── syntaxes └── pde.tmLanguage.json ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.{json,html,yml,yaml,css,scss}] 13 | indent_style = space 14 | indent_size = 2 15 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | */node_modules/ 2 | /src/serviceWorker.ts 3 | lint 4 | start 5 | lib 6 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | function* range(min, max) { 2 | for (let num = min; num < max; num++) { 3 | yield num 4 | } 5 | } 6 | 7 | module.exports = { 8 | env: { 9 | es2021: true, 10 | node: true, 11 | }, 12 | extends: ["eslint:recommended", "plugin:@typescript-eslint/eslint-recommended"], 13 | parser: "@typescript-eslint/parser", 14 | globals: { 15 | Atomics: "readonly", 16 | SharedArrayBuffer: "readonly", 17 | }, 18 | parserOptions: { 19 | ecmaVersion: 2021, 20 | sourceType: "module", 21 | project: ["./tsconfig.json"], 22 | }, 23 | plugins: ["@typescript-eslint", "prefer-arrow"], 24 | rules: { 25 | // General ESLint rules 26 | "arrow-body-style": ["warn", "as-needed"], 27 | "default-case-last": "warn", 28 | "dot-location": ["warn", "property"], 29 | eqeqeq: "error", 30 | "id-length": ["error", {exceptions: ["_", "$"]}], 31 | "max-len": "off", 32 | "max-lines": ["warn", 500], 33 | "max-statements": ["warn", {max: 25}], 34 | "no-else-return": "warn", 35 | "no-empty": ["warn", {allowEmptyCatch: true}], 36 | "no-extra-semi": "off", 37 | "no-negated-condition": "warn", 38 | "no-nested-ternary": "warn", 39 | "no-unused-vars": "off", 40 | "no-var": "warn", 41 | "object-shorthand": "warn", 42 | "one-var": ["warn", "never"], 43 | "padding-line-between-statements": [ 44 | "warn", 45 | {blankLine: "always", prev: "*", next: "return"}, 46 | {blankLine: "always", prev: ["const", "let", "var"], next: "*"}, 47 | {blankLine: "any", prev: ["const", "let", "var"], next: ["const", "let", "var"]}, 48 | {blankLine: "always", prev: "function", next: "*"}, 49 | ], 50 | "prefer-const": "warn", 51 | "prefer-destructuring": [ 52 | "error", 53 | { 54 | array: false, 55 | object: true, 56 | }, 57 | ], 58 | "prefer-exponentiation-operator": "warn", 59 | "prefer-object-spread": "warn", 60 | "prefer-template": "warn", 61 | "require-await": "warn", 62 | "require-unicode-regexp": "warn", 63 | "sort-imports": ["warn"], 64 | 65 | // Typescript Rules 66 | "@typescript-eslint/array-type": "warn", 67 | "@typescript-eslint/consistent-indexed-object-style": ["warn", "index-signature"], 68 | "@typescript-eslint/consistent-type-assertions": ["warn", {assertionStyle: "as"}], 69 | "@typescript-eslint/member-ordering": "warn", 70 | "@typescript-eslint/naming-convention": [ 71 | "error", 72 | { 73 | selector: "default", 74 | format: ["camelCase"], 75 | }, 76 | { 77 | selector: "variableLike", 78 | format: ["camelCase"], 79 | leadingUnderscore: "allow", 80 | }, 81 | { 82 | selector: "memberLike", 83 | modifiers: ["private"], 84 | format: ["camelCase"], 85 | leadingUnderscore: "require", 86 | }, 87 | { 88 | selector: "property", 89 | modifiers: ["private"], 90 | format: ["camelCase"], 91 | leadingUnderscore: "require", 92 | }, 93 | { 94 | selector: "typeLike", 95 | format: ["PascalCase"], 96 | }, 97 | { 98 | selector: "variable", 99 | types: ["boolean"], 100 | format: ["PascalCase"], 101 | prefix: ["is", "should", "has", "can", "did", "will"], 102 | }, 103 | { 104 | selector: "parameter", 105 | format: ["camelCase"], 106 | leadingUnderscore: "allow", 107 | }, 108 | { 109 | selector: "property", 110 | format: ["camelCase", "PascalCase", "snake_case", "UPPER_CASE"], 111 | }, 112 | { 113 | selector: "enumMember", 114 | format: ["camelCase", "PascalCase", "snake_case", "UPPER_CASE"], 115 | }, 116 | ], 117 | "@typescript-eslint/no-magic-numbers": [ 118 | "warn", 119 | { 120 | ignoreEnums: true, 121 | ignoreNumericLiteralTypes: true, 122 | ignoreReadonlyClassProperties: true, 123 | ignoreArrayIndexes: true, 124 | ignore: [...Array.from(range(-10, 11)), 16, 32, 64, 128, 256, 512], 125 | }, 126 | ], 127 | "@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn", 128 | "@typescript-eslint/prefer-for-of": "warn", 129 | "@typescript-eslint/prefer-function-type": "warn", 130 | "@typescript-eslint/prefer-optional-chain": "warn", 131 | 132 | // Typescript extension rules 133 | "@typescript-eslint/default-param-last": "warn", 134 | "@typescript-eslint/dot-notation": "warn", 135 | "@typescript-eslint/lines-between-class-members": ["warn", "always"], 136 | "@typescript-eslint/no-dupe-class-members": "warn", 137 | "@typescript-eslint/no-duplicate-imports": "warn", 138 | "@typescript-eslint/no-extra-semi": "off", 139 | "@typescript-eslint/no-shadow": "warn", 140 | "@typescript-eslint/no-unused-expressions": "warn", 141 | "@typescript-eslint/no-unused-vars": "off", 142 | "@typescript-eslint/no-unused-vars-experimental": "warn", 143 | "@typescript-eslint/no-use-before-define": "warn", 144 | 145 | // Preter arrow rules 146 | "prefer-arrow-callback": "warn", 147 | "prefer-arrow/prefer-arrow-functions": [ 148 | "warn", 149 | { 150 | disallowPrototype: true, 151 | singleReturnOnly: false, 152 | classPropertiesAllowed: true, 153 | allowStandaloneDeclarations: false, 154 | }, 155 | ], 156 | }, 157 | } 158 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Enforce Unix newlines 2 | * text=auto eol=lf 3 | 4 | # Don't diff or textually merge documentation data 5 | data/documentation-data.yml binary 6 | 7 | .eslintrc.js linguist-detectable=false 8 | rollup.config.js linguist-detectable=false 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG] " 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **VSCode (please complete the following information):** 27 | 28 | - OS: [e.g. iOS8.1] 29 | - Version [e.g. 22] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[FEATURE] " 5 | labels: "" 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | name: build 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - uses: actions/setup-node@v1 13 | with: 14 | node-version: "14.x" 15 | registry-url: "https://registry.npmjs.org" 16 | 17 | - name: install deps 18 | run: yarn install --frozen-lockfile 19 | 20 | - name: build 21 | run: yarn workspaces run tsc 22 | 23 | - name: lint 24 | run: yarn lint 25 | 26 | - name: check with prettier 27 | run: yarn prettier . --check 28 | 29 | - name: test 30 | run: yarn test 31 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish to release 2 | on: 3 | release: 4 | types: [published] 5 | 6 | jobs: 7 | publish: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: actions/setup-node@v1 12 | with: 13 | node-version: "14.x" 14 | registry-url: "https://registry.npmjs.org" 15 | 16 | - name: install deps 17 | run: yarn install --frozen-lockfile 18 | 19 | - name: build plugins 20 | run: yarn workspace rollup-plugins run build 21 | 22 | - name: build 23 | run: yarn vsce package 24 | 25 | - name: Release 26 | uses: softprops/action-gh-release@v1 27 | with: 28 | files: ./processing-vscode-*.vsix 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | 32 | - name: Publish to marketplace 33 | uses: lannonbr/vsce-action@master 34 | with: 35 | args: "publish -p $PUBLISH_TOKEN" 36 | env: 37 | PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | out 2 | node_modules 3 | *.log 4 | .idea 5 | *.vsix 6 | lib 7 | processing-vscode.js 8 | .eslintcache 9 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | data/* 2 | src/*.yml 3 | */node_modules/ 4 | build 5 | .serverless 6 | .vscode 7 | lib/ 8 | tsconfig*.json 9 | legacy 10 | processing-vscode.js 11 | pnpm-lock.yaml 12 | -------------------------------------------------------------------------------- /.prettierrc.yml: -------------------------------------------------------------------------------- 1 | # Normal Options 2 | arrowParens: "always" 3 | bracketSpacing: false 4 | embeddedLanguageFormatting: "auto" 5 | endOfLine: "lf" 6 | htmlWhitespaceSensitivity: "strict" 7 | jsxBracketSameLine: false 8 | jsxSingleQuote: false 9 | printWidth: 99 10 | quoteProps: "as-needed" 11 | semi: false 12 | singleQuote: false 13 | tabWidth: 4 14 | trailingComma: "all" 15 | useTabs: false 16 | 17 | # JSDoc plugin 18 | jsdocSpaces: 1 19 | jsdocDescriptionWithDot: false 20 | jsdocDescriptionTag: false 21 | jsdocVerticalAlignment: false 22 | jsdocKeepUnParseAbleExampleIndent: false 23 | jsdocSingleLineComment: false 24 | tsdoc: true 25 | 26 | plugins: 27 | - ./node_modules/prettier-plugin-jsdoc 28 | - ./node_modules/prettier-plugin-package 29 | 30 | overrides: 31 | - files: 32 | - "*.html" 33 | - "*.yml" 34 | - "*.yaml" 35 | - "*.json" 36 | - "*.css" 37 | - "*.scss" 38 | options: 39 | tabWidth: 2 40 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "out": false // set this to true to hide the "out" folder with the compiled JS files 4 | }, 5 | "search.exclude": { 6 | "out": true // set this to false to include "out" folder in search results 7 | }, 8 | // Turn off tsc task auto detection since we have the necessary tasks as npm scripts 9 | "[typescript]": { 10 | "editor.defaultFormatter": "esbenp.prettier-vscode", 11 | "editor.formatOnSave": true, 12 | }, 13 | "[json]": { 14 | "editor.defaultFormatter": "esbenp.prettier-vscode" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | *.log 2 | 3 | .github 4 | .vscode/ 5 | data/ 6 | legacy/ 7 | media/ 8 | node_modules/** 9 | rollup/ 10 | scripts/ 11 | src/ 12 | .editorconfig 13 | .eslintcache 14 | .eslintignore 15 | .eslintrc.js 16 | .gitattributes 17 | .gitignore 18 | .prettierignore 19 | .prettierrc.yml 20 | .vscodeignore 21 | pnpm-lock.yaml 22 | pnpm-workspace.yaml 23 | rollup.config.js 24 | tsconfig.json 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [2.4.1] - 2021-12-17 9 | 10 | ### Added 11 | 12 | - feat: accomidate for legacy `processing.path` conig option 13 | 14 | ### Fixed 15 | 16 | - fix: escape spaces in executable path 17 | 18 | ## [2.4.0] - 2021-07-10 19 | 20 | ### Added 21 | 22 | - feat(snippets): add snippets for circle() and square() 23 | 24 | ## [2.3.0] - 2021-05-27 25 | 26 | ### Added 27 | 28 | - feat(py): add config option processing.py.isEnabled 29 | - feat(search): directly search processing reference if possible 30 | - feat(search): add py.processing.org search 31 | 32 | ### Changed 33 | 34 | - fix: add extra restrictions to commands 35 | 36 | ## [2.2.0] - 2021-05-21 37 | 38 | ### Added 39 | 40 | - feat: add python run button 41 | 42 | ### Changed 43 | 44 | - fix(docs): trim documentation hover data 45 | - fix: don't show hover docs on single line comments 46 | 47 | ## [2.1.0] - 2021-05-02 48 | 49 | ### Added 50 | 51 | - feat: add `runPathQuote` option 52 | 53 | ### Changed 54 | 55 | - ! diagnostics are opt-out by default 56 | 57 | ### Fixed 58 | 59 | - fix: quote windows path names 60 | 61 | ## [2.0.6] - 2021-03-19 62 | 63 | ### Fixed 64 | 65 | - Make valid project names case insensitive 66 | 67 | ## [2.0.5] - 2020-03-19 68 | 69 | ### Fixed 70 | 71 | - Handle paths with spaces better 72 | 73 | ## [2.0.4] - 2020-03-18 74 | 75 | ### Fixed 76 | 77 | - Added quotes around run command to allow for whitespaced paths [#1](https://github.com/Luke-zhang-04/processing-vscode/pull/1) 78 | 79 | ## [2.0.3] - 2021-03-01 80 | 81 | Even more changes to README 82 | 83 | ## [2.0.2] - 2021-03-01 84 | 85 | More changes to README 86 | 87 | ## [2.0.1] - 2021-03-01 88 | 89 | Only some changes to README and CI 90 | 91 | ### Changed 92 | 93 | - made the run button a lighter green 94 | 95 | ## [2.0.0] - 2021-03-01 96 | 97 | ### Added 98 | 99 | - feat: add documentation on hover for Processing Buildtins 100 | - feat: add diagnostics from the `processing-java` CLI 101 | - feat: add a run button to the editor menu 102 | - feat: add quotes to `autoClosingPairs` and `surroundingPairs` 103 | 104 | ### Changed 105 | 106 | - changed configuration `processing.path` to `processing.processingPath` 107 | - changed language configuration 108 | - changed the langauge grammar to Red Hat's [Java Grammar](https://github.com/redhat-developer/vscode-java/blob/master/syntaxes/java.tmLanguage.json) 109 | 110 | ### Removed 111 | 112 | - removed the task file feature in favour of a run button 113 | 114 | ## [1.4.6] - 2020-09-03 115 | 116 | ### Fixed 117 | 118 | - Updated markdown files 119 | 120 | ## [1.4.5] - 2020-09-03 121 | 122 | ### Fixed 123 | 124 | - Updated packages 125 | 126 | ### Changed 127 | 128 | - Using GitHub Actions instead of Travis 129 | 130 | ## [1.4.4] - 2020-08-25 131 | 132 | ### Added 133 | 134 | Can now use DuckDuckGo or Google to search. Thanks to [@atnbueno](https://github.com/atnbueno) 135 | 136 | ## [1.4.3] - 2020-08-25 137 | 138 | ### Fixed 139 | 140 | Merged in bugfix PRs from [@hysysk](https://github.com/hysysk) and [@atnbueno](https://github.com/atnbueno) 141 | 142 | Updated dependencies 143 | 144 | ## [1.4.1] - 2019-12-23 145 | 146 | ### Fixed 147 | 148 | Improved snippets.json thanks to work from [@jerrylususu](https://github.com/jerrylususu) 149 | 150 | Fixed Windows on Bash path issue thanks to [@micuat](https://github.com/micuat) 151 | 152 | ## [1.4.0] - 2019-08-30 153 | 154 | ### Fixed 155 | 156 | Updated tests from latest template to fix automatic builds. 157 | 158 | ### Added 159 | 160 | Users can now choose between processing.org's documentation and p5js 161 | 162 | Thanks to [@brianmcfadden](https://github.com/brianmcfadden) 163 | 164 | ## [1.3.1] - 2019-06-05 165 | 166 | ### Fixed 167 | 168 | - Updated NPM packages 169 | 170 | ## [1.3] - 2019-02-06 171 | 172 | ### Removed 173 | 174 | - Removed the opn requirement, using new internal open external API 175 | 176 | ### Fixed 177 | 178 | - Updated package.json requirements 179 | 180 | ## [1.2.2] - 2018-07-25 181 | 182 | ### Added 183 | 184 | - Added path setting 185 | 186 | ## [1.1.0] - 2018-05-09 187 | 188 | ### Added 189 | 190 | - Added documentation search 191 | 192 | ### Fixed 193 | 194 | - Changed extension namespace to processing (from "extension") 195 | 196 | ## [1.0.0] - 2018-05-09 197 | 198 | ### Added 199 | 200 | - Added Changelog 201 | - Support for multi root workplaces 202 | 203 | ### Fixed 204 | 205 | - Updated dependencies and deploy scripts 206 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 - 2020 Tobiah Zarlez, 2021 Luke Zhang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | icon 2 | 3 | # Processing for Visual Studio Code 4 | 5 | [![Marketplace Version](https://vsmarketplacebadge.apphb.com/version/Luke-zhang-04.processing-vscode.svg?style=for-the-badge&logo=visual-studio-code&logoColor=007ACC&color=007ACC&labelColor=083254)](https://marketplace.visualstudio.com/items?itemName=Luke-zhang-04.processing-vscode) 6 | 7 | [![Installs](https://vsmarketplacebadge.apphb.com/installs-short/Luke-zhang-04.processing-vscode.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=Luke-zhang-04.processing-vscode) 8 | [![Rating](https://vsmarketplacebadge.apphb.com/rating-star/Luke-zhang-04.processing-vscode.svg?style=flat-square)](https://marketplace.visualstudio.com/items?itemName=Luke-zhang-04.processing-vscode) 9 | [![.github/workflows/CI.yml](https://img.shields.io/github/workflow/status/Luke-zhang-04/processing-vscode/Node.js%20CI?label=CI&logo=github&style=flat-square)](https://github.com/Luke-zhang-04/processing-vscode/actions) 10 | [![License](https://img.shields.io/github/license/Luke-zhang-04/processing-vscode?style=flat-square)](./LICENSE) 11 | ![Maintained?](https://img.shields.io/maintenance/yes/2021?style=flat-square) 12 | [![Vulnerabilities](https://snyk.io/test/github/Luke-zhang-04/processing-vscode/badge.svg?style=flat-square)](https://snyk.io/test/github/Luke-zhang-04/processing-vscode) 13 | 14 | Note on Processing 4: I'm not sure how this extension will handle Processing 4. I will wait for it to be out of beta and fix the extension if needed. 15 | 16 | ## Contents 17 | 18 | - [What this extension is](#what-this-extension-is) 19 | - [What this extension isn't](#what-this-extension-isnt) 20 | - [Why the fork?](#why-the-fork) 21 | - [Screenshots](#screenshots) 22 | - [Feature list](#feature-list) 23 | - [Syntax Highlighting](#syntax-highlighting) 24 | - [Snippets](#snippets) 25 | - [Documentation on Hover](#documentation-on-hover) 26 | - [Commands](#commands) 27 | - [Using task files](#using-task-files) 28 | - [Processing Python](#processing-python) 29 | - [Credits](#credits) 30 | 31 | ## What this extension is 32 | 33 | This is a [fork of a Visual Studio Code extension created by Tobiah Zarlez](https://github.com/TobiahZ/processing-vscode) to add [Processing](https://processing.org/) language support, with added documentation on hover, diagnostics, and more. 34 | 35 | ## What this extension isn't 36 | 37 | - This extension does not allow you to debug Java or Processing projects. 38 | - This is **NOT a language server**, and hence cannot provide the features a language server can. There simply is not enough demand for a Processing language server, and that type of thing is definitely out of the scope of my abilities. Language servers take entire teams from big companies such as Microsoft to make. 39 | - This extension cannot provide IntelliSense, for example 40 | 41 | ## Why the fork? 42 | 43 | The [original extension](https://github.com/TobiahZ/processing-vscode) was missing some features that I wanted and it seemed as if the repo was no longer being maintained. So, forked the extension and changed some things. 44 | 45 | - Better syntax highlighting (from [Red Hat Java](https://github.com/redhat-developer/vscode-java/blob/master/syntaxes/java.tmLanguage.json)) 46 | - Documentation on hover (via Regex) 47 | - A run button (both Processing Java and Processing Python) 48 | - Simple diagnostics (via the processing-java CLI, which can be extremely slow, and is disabled by default) 49 | - Strings are auto closing and surrounding (didn't work in the old extension) 50 | 51 | See the [CHANGELOG](https://github.com/Luke-zhang-04/processing-vscode/blob/main/CHANGELOG.md) for all changes 52 | 53 | ## Screenshots 54 | 55 | ![Hover](https://raw.githubusercontent.com/Luke-zhang-04/processing-vscode/main/media/hover-1.png) 56 | 57 |
58 | More Screenshots 59 | 60 | ![Hover](https://raw.githubusercontent.com/Luke-zhang-04/processing-vscode/main/media/hover-2.png) 61 | ![Error](https://raw.githubusercontent.com/Luke-zhang-04/processing-vscode/main/media/error.png) 62 | 63 |
64 | 65 | ## Feature list 66 | 67 | ### Syntax highlighting 68 | 69 | Open any .pde file, or choose "Processing" from the drop down menu in the bottom right corner. Syntax highlighting is from [Red Hat's Java extension](https://github.com/redhat-developer/vscode-java/blob/master/syntaxes/java.tmLanguage.json). 70 | 71 | ### Snippets 72 | 73 | Once the language has been set, you will see code snippets pop up automatically as you type! 74 | 75 | ### Documentation on hover 76 | 77 | When you hover over a function such as `square`, documentation for this function will appear! Documentation is scraped directly from the [Processing reference page](https://processing.org/reference/), so anything missing from there will be missing here too. 78 | 79 | ### Commands 80 | 81 | Installing this extension will add the following commands to your command pallette (`CTRL+SHIFT+P`, or opened by `View -> Command Pallette`). These commands can be selected and run from there, to complete the corresponding tasks. 82 | 83 | - Open Extension Documentation 84 | - Opens this documentation. 85 | - Open Documentation for Selection 86 | - Use the pallet command "Processing: Open Documentation for Selection" to open the processing documentation for the current selection. 87 | - By default uses processing.org's documentation. Can change to p5js's if preferred using the `processing.docs` setting. 88 | - Run 89 | - Runs the current Processing project (from current working directory). Will automatically detect if the project is Processing Java or Python. 90 | - If the setting `processing.shouldSendSigint` is set to `true`, run will interrupt the current running processing program before running the new one. 91 | - RunJava 92 | - Runs the current Processing Java project (from CWD) 93 | - RunPy 94 | - Runs the current Processing Python project (from CWD) 95 | - Search Processing Website 96 | - Use the pallet command "Processing: Search Processing Website" to quickly search whatever you want on the processing website. 97 | - By default uses Google for search. Can change to DuckDuckGo if preferred using the `processing.search` setting. 98 | 99 | ## Using Task Files 100 | 101 | The [original extension](https://github.com/TobiahZ/processing-vscode) made use of a [tasks.json](https://github.com/TobiahZ/processing-vscode/blob/b98d44b095b303f7f66017c632b17e47fa00dfcd/ProcessingTasks.json) file to run processing projects. This has been replaced with the run command and run button (processing.Run). You can bind this command to a keybinding. 102 | 103 | Alternatively, if you prefer the `tasks.json` file, you can continue to use it, but the `command` field should be changed to `"${config:processing.path}"`. 104 | 105 | ## Processing Python 106 | 107 | This extension attempts to make Processing with Python easier to use. Follow these steps: 108 | 109 | 1. Download the [processing-python library](https://py.processing.org/tutorials/command-line/#requirements) for your operating system 110 | - Take note of the location of this file. For example, I might store mine in `~/processing.py-linux64/processing.py-3056-linux64/processing-py.jar` 111 | 2. Download the proper [Java version](https://py.processing.org/tutorials/command-line/#requirements) for your operating system 112 | - Follow the steps in the [Processing docs](https://py.processing.org/tutorials/command-line/#requirements) 113 | 3. Configure the extension 114 | - Change the following configuration options 115 | - `processing.py.jarPath`: the path to your `processing-py.jar` file. Preferably, this is an absolute path. In this example, it will be `~/processing.py-linux64/processing.py-3056-linux64/processing-py.jar` 116 | - `processing.py.javaPath`: the path to your `java` executable. For example, `/usr/bin/java` 117 | - Make sure `processing.py.isEnabled` is set to `true` (true by default) 118 | 4. Downloads stub definitions (optional) 119 | - Definitions can be found [here](https://github.com/Abdulla060/Processing.py-intellisense/blob/master/lib/Processing3.pyi) 120 | - After than, follow the imports in [this example](https://github.com/Abdulla060/Processing.py-intellisense/blob/master/Example.py) 121 | 122 | ## Credits 123 | 124 | - Snippets are based on the [Processing Sublime Text plugin](https://github.com/b-g/processing-sublime). 125 | - Syntax highlighting is based on the [VSCode Java grammar](https://github.com/microsoft/vscode/blob/main/extensions/java/syntaxes/java.tmLanguage.json) 126 | - Thanks to [Tobiah Zarlez](https://github.com/TobiahZ) for making the [original extension](https://github.com/TobiahZ/processing-vscode) 127 | 128 | ## Development 129 | 130 | - Run `yarn vsce package` 131 | - Run `code --install-extension processing-vscode-.vsix` 132 | -------------------------------------------------------------------------------- /__tests__/index.js: -------------------------------------------------------------------------------- 1 | import {escapeExecutablePath} from "../src/utils/escapePath" 2 | 3 | describe("test path escape", () => { 4 | it("should escape Windows path with space", () => { 5 | const originalPath = "C:\\Program Files\\processing\\processing-java" 6 | 7 | expect(escapeExecutablePath(originalPath)).toBe( 8 | "C:\\Program` Files\\processing\\processing-java", 9 | ) 10 | }) 11 | 12 | it("should escape Unix path with space", () => { 13 | const originalPath = "/usr/bin/something else/processing-java" 14 | 15 | expect(escapeExecutablePath(originalPath)).toBe( 16 | "/usr/bin/something\\ else/processing-java", 17 | ) 18 | }) 19 | 20 | it("should leave Windows path without spaces as is", () => { 21 | const originalPath = ".\\processing\\processing-java" 22 | 23 | expect(escapeExecutablePath(originalPath)).toBe(".\\processing\\processing-java") 24 | }) 25 | 26 | it("should leave Unix path without spaces as is", () => { 27 | const originalPath = "/usr/bin/processing-java" 28 | 29 | expect(escapeExecutablePath(originalPath)).toBe("/usr/bin/processing-java") 30 | }) 31 | 32 | it("should not escape already escaped spaces on Windows", () => { 33 | const originalPath = "C:\\Program` Files\\processing\\processing java" 34 | 35 | expect(escapeExecutablePath(originalPath)).toBe( 36 | "C:\\Program` Files\\processing\\processing` java", 37 | ) 38 | }) 39 | 40 | it("should not escape already escaped spaces on Unix", () => { 41 | const originalPath = "/usr/bin/something else/processing\\ java" 42 | 43 | expect(escapeExecutablePath(originalPath)).toBe( 44 | "/usr/bin/something\\ else/processing\\ java", 45 | ) 46 | }) 47 | 48 | it("should detect platform if no path seperators available", () => { 49 | const originalPath = "processing java" 50 | 51 | if (process.platform === "win32") { 52 | expect(escapeExecutablePath(originalPath)).toBe("processing` java") 53 | } else { 54 | expect(escapeExecutablePath(originalPath)).toBe("processing\\ java") 55 | } 56 | }) 57 | 58 | it("should leave single path as is", () => { 59 | const originalPath = "processing-java" 60 | 61 | expect(escapeExecutablePath(originalPath)).toBe("processing-java") 62 | }) 63 | }) 64 | -------------------------------------------------------------------------------- /__tests__/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "module" 3 | } 4 | -------------------------------------------------------------------------------- /images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Luke-zhang-04/processing-vscode/c116f535868f409d0f40fd16440201c597dbbaa0/images/icon.png -------------------------------------------------------------------------------- /images/play-arrow-with-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /images/play-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /images/processing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Luke-zhang-04/processing-vscode/c116f535868f409d0f40fd16440201c597dbbaa0/images/processing.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import("ts-jest/dist/types").InitialOptionsTsJest} 3 | */ 4 | module.exports = { 5 | preset: "ts-jest", 6 | testEnvironment: "node", 7 | } 8 | -------------------------------------------------------------------------------- /legacy/pde.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "fileTypes": [ 3 | "pde", 4 | "java" 5 | ], 6 | "foldingStartMarker": "(\\{\\s*(//.*)?$|^\\s*// \\{\\{\\{)", 7 | "foldingStopMarker": "^\\s*(\\}|// \\}\\}\\}$)", 8 | "name": "Processing", 9 | "patterns": [ 10 | { 11 | "captures": { 12 | "1": { 13 | "name": "keyword.other.package.java" 14 | }, 15 | "2": { 16 | "name": "storage.modifier.package.java" 17 | }, 18 | "3": { 19 | "name": "punctuation.terminator.java" 20 | } 21 | }, 22 | "match": "^\\s*(package)\\b(?:\\s*([^ ;$]+)\\s*(;)?)?", 23 | "name": "meta.package.java" 24 | }, 25 | { 26 | "captures": { 27 | "1": { 28 | "name": "keyword.other.import.processing" 29 | }, 30 | "2": { 31 | "name": "storage.modifier.import.processing" 32 | }, 33 | "3": { 34 | "name": "punctuation.terminator.processing" 35 | } 36 | }, 37 | "match": "^\\s*(import)\\b(?:\\s*([^ ;$]+)\\s*(;)?)?", 38 | "name": "meta.import.processing" 39 | }, 40 | { 41 | "include": "#class-body" 42 | } 43 | ], 44 | "repository": { 45 | "all-types": { 46 | "patterns": [ 47 | { 48 | "include": "#simple-arrays" 49 | }, 50 | { 51 | "include": "#simple-types" 52 | }, 53 | { 54 | "include": "#object-types" 55 | } 56 | ] 57 | }, 58 | "annotations": { 59 | "patterns": [ 60 | { 61 | "begin": "(@[^ (]+)(\\()", 62 | "beginCaptures": { 63 | "1": { 64 | "name": "storage.type.annotation.processing" 65 | }, 66 | "2": { 67 | "name": "punctuation.definition.annotation-arguments.begin.processing" 68 | } 69 | }, 70 | "end": "(\\))", 71 | "endCaptures": { 72 | "1": { 73 | "name": "punctuation.definition.annotation-arguments.end.processing" 74 | } 75 | }, 76 | "name": "meta.declaration.annotation.processing", 77 | "patterns": [ 78 | { 79 | "captures": { 80 | "1": { 81 | "name": "constant.other.key.processing" 82 | }, 83 | "2": { 84 | "name": "keyword.operator.assignment.processing" 85 | } 86 | }, 87 | "match": "(\\w*)\\s*(=)" 88 | }, 89 | { 90 | "include": "#code" 91 | }, 92 | { 93 | "match": ",", 94 | "name": "punctuation.seperator.property.processing" 95 | } 96 | ] 97 | }, 98 | { 99 | "match": "@\\w*", 100 | "name": "storage.type.annotation.processing" 101 | } 102 | ] 103 | }, 104 | "anonymous-classes-and-new": { 105 | "begin": "\\bnew\\b", 106 | "beginCaptures": { 107 | "0": { 108 | "name": "keyword.control.new.processing" 109 | } 110 | }, 111 | "end": "(?<=\\)|\\])(?!\\s*{)|(?<=})|(?=;)", 112 | "patterns": [ 113 | { 114 | "begin": "(\\w+)\\s*(?=\\[)", 115 | "beginCaptures": { 116 | "1": { 117 | "name": "storage.type.processing" 118 | } 119 | }, 120 | "end": "}|(?=;|\\))", 121 | "patterns": [ 122 | { 123 | "begin": "\\[", 124 | "end": "\\]", 125 | "patterns": [ 126 | { 127 | "include": "#inner-code" 128 | } 129 | ] 130 | }, 131 | { 132 | "begin": "{", 133 | "end": "(?=})", 134 | "patterns": [ 135 | { 136 | "include": "#code" 137 | } 138 | ] 139 | } 140 | ] 141 | }, 142 | { 143 | "begin": "(?=\\w.*\\()", 144 | "end": "(?<=\\))", 145 | "patterns": [ 146 | { 147 | "include": "#object-types" 148 | }, 149 | { 150 | "begin": "\\(", 151 | "beginCaptures": { 152 | "1": { 153 | "name": "storage.type.processing" 154 | } 155 | }, 156 | "end": "\\)", 157 | "patterns": [ 158 | { 159 | "include": "#inner-code" 160 | } 161 | ] 162 | } 163 | ] 164 | }, 165 | { 166 | "begin": "{", 167 | "end": "}", 168 | "name": "meta.inner-class.processing", 169 | "patterns": [ 170 | { 171 | "include": "#class-body" 172 | } 173 | ] 174 | } 175 | ] 176 | }, 177 | "assertions": { 178 | "patterns": [ 179 | { 180 | "begin": "\\b(assert)\\s", 181 | "beginCaptures": { 182 | "1": { 183 | "name": "keyword.control.assert.processing" 184 | } 185 | }, 186 | "end": "$", 187 | "name": "meta.declaration.assertion.processing", 188 | "patterns": [ 189 | { 190 | "match": ":", 191 | "name": "keyword.operator.assert.expression-seperator.processing" 192 | }, 193 | { 194 | "include": "#code" 195 | } 196 | ] 197 | } 198 | ] 199 | }, 200 | "class": { 201 | "begin": "(?=\\w?[\\w\\s]*(?:class|(?:@)?interface)\\s+\\w+)", 202 | "end": "}", 203 | "endCaptures": { 204 | "0": { 205 | "name": "punctuation.section.class.end.processing" 206 | } 207 | }, 208 | "name": "meta.class.processing", 209 | "patterns": [ 210 | { 211 | "include": "#storage-modifiers" 212 | }, 213 | { 214 | "include": "#comments" 215 | }, 216 | { 217 | "captures": { 218 | "1": { 219 | "name": "storage.modifier.processing" 220 | }, 221 | "2": { 222 | "name": "entity.name.type.class.processing" 223 | } 224 | }, 225 | "match": "(class|(?:@)?interface)\\s+(\\w+)", 226 | "name": "meta.class.identifier.processing" 227 | }, 228 | { 229 | "begin": "extends", 230 | "beginCaptures": { 231 | "0": { 232 | "name": "storage.modifier.extends.processing" 233 | } 234 | }, 235 | "end": "(?={|implements)", 236 | "name": "meta.definition.class.inherited.classes.processing", 237 | "patterns": [ 238 | { 239 | "include": "#object-types-inherited" 240 | }, 241 | { 242 | "include": "#comments" 243 | } 244 | ] 245 | }, 246 | { 247 | "begin": "(implements)\\s", 248 | "beginCaptures": { 249 | "1": { 250 | "name": "storage.modifier.implements.processing" 251 | } 252 | }, 253 | "end": "(?=\\s*extends|\\{)", 254 | "name": "meta.definition.class.implemented.interfaces.processing", 255 | "patterns": [ 256 | { 257 | "include": "#object-types-inherited" 258 | }, 259 | { 260 | "include": "#comments" 261 | } 262 | ] 263 | }, 264 | { 265 | "begin": "{", 266 | "end": "(?=})", 267 | "name": "meta.class.body.processing", 268 | "patterns": [ 269 | { 270 | "include": "#class-body" 271 | } 272 | ] 273 | } 274 | ] 275 | }, 276 | "enum": { 277 | "begin": "(?=\\w?[\\w\\s]*(?:enum)\\s+\\w+)", 278 | "end": "}", 279 | "endCaptures": { 280 | "0": { 281 | "name": "punctuation.section.class.end.processing" 282 | } 283 | }, 284 | "name": "meta.class.processing", 285 | "patterns": [ 286 | { 287 | "include": "#storage-modifiers" 288 | }, 289 | { 290 | "include": "#comments" 291 | }, 292 | { 293 | "captures": { 294 | "1": { 295 | "name": "storage.modifier.processing" 296 | }, 297 | "2": { 298 | "name": "entity.name.type.class.processing" 299 | } 300 | }, 301 | "match": "(enum)\\s+(\\w+)", 302 | "name": "meta.class.identifier.processing" 303 | }, 304 | { 305 | "begin": "extends", 306 | "beginCaptures": { 307 | "0": { 308 | "name": "storage.modifier.extends.processing" 309 | } 310 | }, 311 | "end": "(?={|implements)", 312 | "name": "meta.definition.class.inherited.classes.processing", 313 | "patterns": [ 314 | { 315 | "include": "#object-types-inherited" 316 | }, 317 | { 318 | "include": "#comments" 319 | } 320 | ] 321 | }, 322 | { 323 | "begin": "(implements)\\s", 324 | "beginCaptures": { 325 | "1": { 326 | "name": "storage.modifier.implements.processing" 327 | } 328 | }, 329 | "end": "(?=\\s*extends|\\{)", 330 | "name": "meta.definition.class.implemented.interfaces.processing", 331 | "patterns": [ 332 | { 333 | "include": "#object-types-inherited" 334 | }, 335 | { 336 | "include": "#comments" 337 | } 338 | ] 339 | }, 340 | { 341 | "begin": "{", 342 | "end": "(?=})", 343 | "name": "meta.class.body.processing", 344 | "patterns": [ 345 | { 346 | "include": "#enum-body" 347 | } 348 | ] 349 | } 350 | ] 351 | }, 352 | "class-body": { 353 | "patterns": [ 354 | { 355 | "include": "#comments" 356 | }, 357 | { 358 | "include": "#class" 359 | }, 360 | { 361 | "include": "#enum" 362 | }, 363 | { 364 | "include": "#methods" 365 | }, 366 | { 367 | "include": "#annotations" 368 | }, 369 | { 370 | "include": "#storage-modifiers" 371 | }, 372 | { 373 | "include": "#code" 374 | } 375 | ] 376 | }, 377 | "enum-body": { 378 | "patterns": [ 379 | { 380 | "include": "#comments" 381 | }, 382 | { 383 | "include": "#class" 384 | }, 385 | { 386 | "include": "#enum" 387 | }, 388 | { 389 | "include": "#enums" 390 | }, 391 | { 392 | "include": "#methods" 393 | }, 394 | { 395 | "include": "#annotations" 396 | }, 397 | { 398 | "include": "#storage-modifiers" 399 | }, 400 | { 401 | "include": "#code" 402 | } 403 | ] 404 | }, 405 | "code": { 406 | "patterns": [ 407 | { 408 | "include": "#comments" 409 | }, 410 | { 411 | "include": "#class" 412 | }, 413 | { 414 | "include": "#enum" 415 | }, 416 | { 417 | "begin": "{", 418 | "end": "}", 419 | "patterns": [ 420 | { 421 | "include": "#code" 422 | } 423 | ] 424 | }, 425 | { 426 | "include": "#assertions" 427 | }, 428 | { 429 | "include": "#parens" 430 | }, 431 | { 432 | "include": "#constants-and-special-vars" 433 | }, 434 | { 435 | "include": "#anonymous-classes-and-new" 436 | }, 437 | { 438 | "include": "#keywords" 439 | }, 440 | { 441 | "include": "#operators" 442 | }, 443 | { 444 | "include": "#storage-modifiers" 445 | }, 446 | { 447 | "include": "#strings" 448 | }, 449 | { 450 | "include": "#all-types" 451 | }, 452 | { 453 | "include": "#function-calls" 454 | } 455 | ] 456 | }, 457 | "inner-code": { 458 | "patterns": [ 459 | { 460 | "include": "#comments" 461 | }, 462 | { 463 | "include": "#assertions" 464 | }, 465 | { 466 | "include": "#parens" 467 | }, 468 | { 469 | "include": "#constants-and-special-vars" 470 | }, 471 | { 472 | "include": "#anonymous-classes-and-new" 473 | }, 474 | { 475 | "include": "#keywords" 476 | }, 477 | { 478 | "include": "#inner-operators" 479 | }, 480 | { 481 | "include": "#storage-modifiers" 482 | }, 483 | { 484 | "include": "#strings" 485 | }, 486 | { 487 | "include": "#all-types" 488 | }, 489 | { 490 | "include": "#function-calls" 491 | } 492 | ] 493 | }, 494 | "comments": { 495 | "patterns": [ 496 | { 497 | "captures": { 498 | "0": { 499 | "name": "punctuation.definition.comment.processing" 500 | } 501 | }, 502 | "match": "/\\*\\*/", 503 | "name": "comment.block.empty.processing" 504 | }, 505 | { 506 | "include": "text.html.javadoc" 507 | }, 508 | { 509 | "include": "#comments-inline" 510 | } 511 | ] 512 | }, 513 | "comments-inline": { 514 | "patterns": [ 515 | { 516 | "begin": "/\\*", 517 | "captures": { 518 | "0": { 519 | "name": "punctuation.definition.comment.processing" 520 | } 521 | }, 522 | "end": "\\*/", 523 | "name": "comment.block.processing" 524 | }, 525 | { 526 | "captures": { 527 | "1": { 528 | "name": "comment.line.double-slash.processing" 529 | }, 530 | "2": { 531 | "name": "punctuation.definition.comment.processing" 532 | } 533 | }, 534 | "match": "\\s*((//).*$\\n?)" 535 | } 536 | ] 537 | }, 538 | "constants-and-special-vars": { 539 | "patterns": [ 540 | { 541 | "match": "\\b(true|false|null)\\b", 542 | "name": "constant.language.processing" 543 | }, 544 | { 545 | "match": "\\b(this|super)\\b", 546 | "name": "variable.language.processing" 547 | }, 548 | { 549 | "match": "\\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\\.?[0-9]*)|(\\.[0-9]+))((e|E)(\\+|-)?[0-9]+)?)([LlFfUuDd]|UL|ul)?\\b", 550 | "name": "constant.numeric.processing" 551 | }, 552 | { 553 | "match": "(#[0-9a-fA-F]+)\\b", 554 | "name": "constant.numeric.processing" 555 | }, 556 | { 557 | "captures": { 558 | "1": { 559 | "name": "keyword.operator.dereference.processing" 560 | } 561 | }, 562 | "match": "(\\.)?\\b([A-Z][A-Z0-9_]+)(?!<|\\.class|\\s*\\w+\\s*=)\\b", 563 | "name": "constant.other.processing" 564 | } 565 | ] 566 | }, 567 | "enums": { 568 | "begin": "^(?=\\s*[A-Z0-9_]+\\s*({|\\(|,))", 569 | "end": "(?=;|})", 570 | "patterns": [ 571 | { 572 | "begin": "\\w+", 573 | "beginCaptures": { 574 | "0": { 575 | "name": "constant.other.enum.java" 576 | } 577 | }, 578 | "end": "(?=,|;|})", 579 | "name": "meta.enum.java", 580 | "patterns": [ 581 | { 582 | "include": "#parens" 583 | }, 584 | { 585 | "begin": "{", 586 | "end": "}", 587 | "patterns": [ 588 | { 589 | "include": "#class-body" 590 | } 591 | ] 592 | } 593 | ] 594 | } 595 | ] 596 | }, 597 | "keywords": { 598 | "patterns": [ 599 | { 600 | "match": "\\b(try|catch|finally|throw)\\b", 601 | "name": "keyword.control.catch-exception.processing" 602 | }, 603 | { 604 | "match": "\\b(return|break|case|continue|default|do|while|for|switch|if|else)\\b", 605 | "name": "keyword.control.processing" 606 | }, 607 | { 608 | "match": "\\b(displayHeight|displayWidth|focused|frameCount|frameRate|height|key|keyCode|keyPressed|mouseButton|mousePressed|mouseX|mouseY|online|pixelHeight|pixelWidth|pixels|pmouseX|pmouseY|screen|width)\\b", 609 | "name": "constant.other.processing" 610 | }, 611 | { 612 | "match": "\\b(ADD|ALIGN_CENTER|ALIGN_LEFT|ALIGN_RIGHT|ALPHA|ALPHA_MASK|ALT|AMBIENT|ARGB|ARROW|BACKSPACE|BEVEL|BLEND|BLUE_MASK|BLUR|CENTER|CENTER_RADIUS|CHATTER|CODED|COMPLAINT|COMPONENT|COMPOSITE|CONCAVE_POLYGON|CONTROL|CONVEX_POLYGON|CORNER|CORNERS|CROSS|CUSTOM|DARKEST|DEGREES|DEG_TO_RAD|DELETE|DIFFERENCE|DIFFUSE|DISABLED|DISABLE_TEXT_SMOOTH|DOWN|ENTER|EPSILON|ESC|FX2D|GIF|GREEN_MASK|GREY|HALF|HALF_PI|HAND|HARD_LIGHT|HSB|IMAGE|INVERT|JAVA2D|JPEG|LEFT|LIGHTEST|LINES|LINE_LOOP|LINE_STRIP|MAX_FLOAT|MITER|MODEL|MOVE|MULTIPLY|NORMALIZED|NO_DEPTH_TEST|NTSC|ONE|OPAQUE|OPENGL|ORTHOGRAPHIC|OVERLAY|P2D|P3D|PAL|PDF|PERSPECTIVE|PI|PIXEL_CENTER|POINTS|POLYGON|POSTERIZE|PROBLEM|PROJECT|QUADS|QUAD_STRIP|QUARTER_PI|RADIANS|RAD_TO_DEG|RED_MASK|REPLACE|RETURN|RGB|RIGHT|ROUND|SCREEN|SECAM|SHIFT|SOFT_LIGHT|SPAN|SPECULAR|SQUARE|SUBTRACT|SVIDEO|TAB|TARGA|TEXT|TFF|THIRD_PI|THRESHOLD|TIFF|TRIANGLES|TRIANGLE_FAN|TRIANGLE_STRIP|TUNER|TAU|TWO|TWO_PI|UP|WAIT|WHITESPACE)\\b", 613 | "name": "support.constant.processing" 614 | }, 615 | { 616 | "match": "\\b(Array|Character|FloatDict|FloatList|IntDict|IntList|Integer|JSONArray|JSONObject|Math|Object|PFont|PGraphics|PImage|PShader|PShape|PSound|PVector|StringBuffer|StringDict|StringList|Table|TableRow|Thread|XML)\\b", 617 | "name": "support.class.processing" 618 | }, 619 | { 620 | "match": "\\b(instanceof)\\b", 621 | "name": "keyword.operator.processing" 622 | } 623 | ] 624 | }, 625 | "operators": { 626 | "patterns": [ 627 | { 628 | "include": "#common-operators" 629 | }, 630 | { 631 | "begin": "=", 632 | "beginCaptures": { 633 | "0": { 634 | "name": "keyword.operator.assignment.processing" 635 | } 636 | }, 637 | "end": ";", 638 | "patterns": [ 639 | { 640 | "include": "#inner-code" 641 | } 642 | ] 643 | }, 644 | { 645 | "match": ";", 646 | "name": "punctuation.terminator.processing" 647 | } 648 | ] 649 | }, 650 | "inner-operators": { 651 | "patterns": [ 652 | { 653 | "include": "#common-operators" 654 | }, 655 | { 656 | "match": "(=)", 657 | "name": "keyword.operator.assignment.processing" 658 | } 659 | ] 660 | }, 661 | "common-operators": { 662 | "patterns": [ 663 | { 664 | "match": "(==|!=|<=|>=|<>|<|>)", 665 | "name": "keyword.operator.comparison.processing" 666 | }, 667 | { 668 | "match": "(\\-\\-|\\+\\+)", 669 | "name": "keyword.operator.increment-decrement.processing" 670 | }, 671 | { 672 | "match": "(\\+\\=|\\-\\=|\\*\\=|\\/\\=)", 673 | "name": "keyword.operator.arithmetic-assignment.processing" 674 | }, 675 | { 676 | "match": "(\\-|\\+|\\*|\\/|%)", 677 | "name": "keyword.operator.arithmetic.processing" 678 | }, 679 | { 680 | "match": "(!|&&|\\|\\|)", 681 | "name": "keyword.operator.logical.processing" 682 | }, 683 | { 684 | "match": "(?<=\\S)\\.(?=\\S)", 685 | "name": "keyword.operator.dereference.processing" 686 | }, 687 | { 688 | "match": "(\\?|\\:)", 689 | "name": "keyword.operator.ternary.processing" 690 | } 691 | ] 692 | }, 693 | "function-calls": { 694 | "patterns": [ 695 | { 696 | "captures": { 697 | "1": { 698 | "name": "support.function.any-method.processing" 699 | } 700 | }, 701 | "match": "(?x)\n \t\t\t\t(\n \t\t\t\t\t(?!while|for|do|if|else|switch|catch|enumerate|return|r?iterate)(?: \\b[A-Za-z_][A-Za-z0-9_]*+\\b | :: )*+ # actual name\n \t\t\t\t)\n \t\t\t\t \\s*(?:\\()", 702 | "name": "meta.function-call.processing" 703 | } 704 | ] 705 | }, 706 | "methods": { 707 | "begin": "(?!new)(?=\\w.*\\s+)(?=[^=]+\\()", 708 | "end": "}|(?=;)", 709 | "name": "meta.method.processing", 710 | "patterns": [ 711 | { 712 | "include": "#storage-modifiers" 713 | }, 714 | { 715 | "begin": "(\\w+)\\s*\\(", 716 | "beginCaptures": { 717 | "1": { 718 | "name": "entity.name.function.processing" 719 | } 720 | }, 721 | "end": "\\)", 722 | "name": "meta.method.identifier.processing", 723 | "patterns": [ 724 | { 725 | "include": "#parameters" 726 | } 727 | ] 728 | }, 729 | { 730 | "begin": "(?=\\w.*\\s+\\w+\\s*\\()", 731 | "end": "(?=\\w+\\s*\\()", 732 | "name": "meta.method.return-type.processing", 733 | "patterns": [ 734 | { 735 | "include": "#all-types" 736 | } 737 | ] 738 | }, 739 | { 740 | "include": "#throws" 741 | }, 742 | { 743 | "begin": "{", 744 | "end": "(?=})", 745 | "name": "meta.method.body.processing", 746 | "patterns": [ 747 | { 748 | "include": "#code" 749 | } 750 | ] 751 | } 752 | ] 753 | }, 754 | "object-types": { 755 | "patterns": [ 756 | { 757 | "begin": "\\b((?:[a-z]\\w*\\.)*[A-Z]+\\w*)<", 758 | "end": ">|[^\\w\\s,\\?<\\[\\]]", 759 | "name": "storage.type.generic.processing", 760 | "patterns": [ 761 | { 762 | "include": "#object-types" 763 | }, 764 | { 765 | "begin": "<", 766 | "comment": "This is to support <>'s with no actual type prefix", 767 | "end": ">|[^\\w\\s,\\[\\]<]", 768 | "name": "storage.type.generic.processing" 769 | } 770 | ] 771 | }, 772 | { 773 | "begin": "\\b((?:[a-z]\\w*\\.)*[A-Z]+\\w*)(?=\\[)", 774 | "end": "(?=[^\\]\\s])", 775 | "name": "storage.type.object.array.processing", 776 | "patterns": [ 777 | { 778 | "begin": "\\[", 779 | "end": "\\]", 780 | "patterns": [ 781 | { 782 | "include": "#inner-code" 783 | } 784 | ] 785 | } 786 | ] 787 | }, 788 | { 789 | "captures": { 790 | "1": { 791 | "name": "keyword.operator.dereference.processing" 792 | } 793 | }, 794 | "match": "\\b(?:[a-z]\\w*(\\.))*[A-Z]+\\w*\\b", 795 | "name": "storage.type.processing" 796 | } 797 | ] 798 | }, 799 | "object-types-inherited": { 800 | "patterns": [ 801 | { 802 | "begin": "\\b((?:[a-z]\\w*\\.)*[A-Z]+\\w*)<", 803 | "end": ">|[^\\w\\s,<]", 804 | "name": "entity.other.inherited-class.processing", 805 | "patterns": [ 806 | { 807 | "include": "#object-types" 808 | }, 809 | { 810 | "begin": "<", 811 | "comment": "This is to support <>'s with no actual type prefix", 812 | "end": ">|[^\\w\\s,<]", 813 | "name": "storage.type.generic.processing" 814 | } 815 | ] 816 | }, 817 | { 818 | "captures": { 819 | "1": { 820 | "name": "keyword.operator.dereference.processing" 821 | } 822 | }, 823 | "match": "\\b(?:[a-z]\\w*(\\.))*[A-Z]+\\w*", 824 | "name": "entity.other.inherited-class.processing" 825 | } 826 | ] 827 | }, 828 | "parameters": { 829 | "patterns": [ 830 | { 831 | "match": "final", 832 | "name": "storage.modifier.processing" 833 | }, 834 | { 835 | "include": "#simple-arrays" 836 | }, 837 | { 838 | "include": "#simple-types" 839 | }, 840 | { 841 | "include": "#object-types" 842 | }, 843 | { 844 | "match": "\\w+", 845 | "name": "variable.parameter.processing" 846 | } 847 | ] 848 | }, 849 | "parens": { 850 | "begin": "\\(", 851 | "end": "\\)", 852 | "patterns": [ 853 | { 854 | "include": "#inner-code" 855 | } 856 | ] 857 | }, 858 | "simple-arrays": { 859 | "patterns": [ 860 | { 861 | "match": "\\b(?:void|boolean|byte|char|short|int|float|long|double|color)(\\[\\])*\\b", 862 | "name": "storage.type.simple.array.processing" 863 | } 864 | ] 865 | }, 866 | "simple-types": { 867 | "patterns": [ 868 | { 869 | "match": "\\b(?:void|boolean|byte|char|short|int|float|long|double|color)\\b", 870 | "name": "storage.type.simple.processing" 871 | } 872 | ] 873 | }, 874 | "storage-modifiers": { 875 | "captures": { 876 | "1": { 877 | "name": "storage.modifier.processing" 878 | } 879 | }, 880 | "match": "\\b(public|private|protected|static|final|native|synchronized|abstract|threadsafe|transient)\\b" 881 | }, 882 | "strings": { 883 | "patterns": [ 884 | { 885 | "begin": "\"", 886 | "beginCaptures": { 887 | "0": { 888 | "name": "punctuation.definition.string.begin.processing" 889 | } 890 | }, 891 | "end": "\"", 892 | "endCaptures": { 893 | "0": { 894 | "name": "punctuation.definition.string.end.processing" 895 | } 896 | }, 897 | "name": "string.quoted.double.processing", 898 | "patterns": [ 899 | { 900 | "match": "\\\\.", 901 | "name": "constant.character.escape.processing" 902 | } 903 | ] 904 | }, 905 | { 906 | "begin": "'", 907 | "beginCaptures": { 908 | "0": { 909 | "name": "punctuation.definition.string.begin.processing" 910 | } 911 | }, 912 | "end": "'", 913 | "endCaptures": { 914 | "0": { 915 | "name": "punctuation.definition.string.end.processing" 916 | } 917 | }, 918 | "name": "string.quoted.single.processing", 919 | "patterns": [ 920 | { 921 | "match": "\\\\.", 922 | "name": "constant.character.escape.processing" 923 | } 924 | ] 925 | } 926 | ] 927 | }, 928 | "throws": { 929 | "begin": "throws", 930 | "beginCaptures": { 931 | "0": { 932 | "name": "storage.modifier.processing" 933 | } 934 | }, 935 | "end": "(?={|;)", 936 | "name": "meta.throwables.processing", 937 | "patterns": [ 938 | { 939 | "include": "#object-types" 940 | } 941 | ] 942 | }, 943 | "values": { 944 | "patterns": [ 945 | { 946 | "include": "#strings" 947 | }, 948 | { 949 | "include": "#object-types" 950 | }, 951 | { 952 | "include": "#constants-and-special-vars" 953 | } 954 | ] 955 | } 956 | }, 957 | "scopeName": "source.pde", 958 | "uuid": "D3D6351E-1416-4AE7-8060-665C6108D2C5" 959 | } 960 | -------------------------------------------------------------------------------- /media/error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Luke-zhang-04/processing-vscode/c116f535868f409d0f40fd16440201c597dbbaa0/media/error.png -------------------------------------------------------------------------------- /media/hover-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Luke-zhang-04/processing-vscode/c116f535868f409d0f40fd16440201c597dbbaa0/media/hover-1.png -------------------------------------------------------------------------------- /media/hover-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Luke-zhang-04/processing-vscode/c116f535868f409d0f40fd16440201c597dbbaa0/media/hover-2.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "processing-vscode", 3 | "version": "2.4.1", 4 | "private": true, 5 | "description": "Processing Language Support for VSCode", 6 | "license": "MIT", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/Luke-zhang-04/processing-vscode.git" 10 | }, 11 | "homepage": "https://github.com/Luke-zhang-04/processing-vscode", 12 | "bugs": "https://github.com/Luke-zhang-04/processing-vscode/issues", 13 | "main": "./processing-vscode.js", 14 | "engines": { 15 | "vscode": "^1.48.0" 16 | }, 17 | "scripts": { 18 | "build": "rollup -c rollup.config.js", 19 | "deploy": "vsce publish", 20 | "format": "prettier . --write && eslint --ext ts --fix --cache", 21 | "lint": "eslint --ext ts src --max-warnings 0 --cache", 22 | "test": "node --experimental-vm-modules --experimental-specifier-resolution=node node_modules/.bin/jest", 23 | "vscode:prepublish": "rollup -c rollup.config.js" 24 | }, 25 | "keywords": [ 26 | "processing", 27 | "pde", 28 | "processing.py", 29 | "processing-python", 30 | "language", 31 | "snippets", 32 | "diagnostics", 33 | "runner" 34 | ], 35 | "devDependencies": { 36 | "@rollup/plugin-node-resolve": "^13.0.0", 37 | "@rollup/plugin-typescript": "^8.2.1", 38 | "@types/glob": "^7.1.4", 39 | "@types/jest": "^27.0.3", 40 | "@types/jsdom": "^16.2.13", 41 | "@types/node": "^16.3.1", 42 | "@types/node-fetch": "^2.5.11", 43 | "@types/vscode": "^1.48.0", 44 | "@typescript-eslint/eslint-plugin": "^4.28.2", 45 | "@typescript-eslint/parser": "^4.28.2", 46 | "eslint": "^7.30.0", 47 | "eslint-plugin-prefer-arrow": "^1.2.3", 48 | "glob": "^7.1.7", 49 | "jest": "^27.4.5", 50 | "jsdom": "^16.6.0", 51 | "node-fetch": "^2.6.1", 52 | "prettier": "^2.3.2", 53 | "prettier-plugin-jsdoc": "^0.3.23", 54 | "prettier-plugin-package": "^1.3.0", 55 | "rollup": "^2.53.0", 56 | "rollup-plugin-progress": "^1.1.2", 57 | "rollup-plugin-terser": "^7.0.2", 58 | "ts-jest": "^27.1.2", 59 | "tslib": "^2.3.0", 60 | "typescript": "~4.3.5", 61 | "vsce": "^1.95.1", 62 | "yaml": "^1.10.2" 63 | }, 64 | "activationEvents": [ 65 | "onCommand:processing.OpenExtensionDocumentation", 66 | "onCommand:processing.OpenDocs", 67 | "onCommand:processing.SearchWebsite", 68 | "onCommand:processing.Run", 69 | "onCommand:processing.RunJava", 70 | "onCommand:processing.RunPy", 71 | "onLanguage:pde", 72 | "onLanguage:python" 73 | ], 74 | "categories": [ 75 | "Programming Languages", 76 | "Snippets" 77 | ], 78 | "contributes": { 79 | "commands": [ 80 | { 81 | "command": "processing.Run", 82 | "title": "Processing: Run Open Processing Project", 83 | "enablement": "resourceLangId == python || resourceLangId == pde" 84 | }, 85 | { 86 | "command": "processing.RunPy", 87 | "title": "Processing: Run Open Processing Python Project", 88 | "icon": "./images/play-arrow-with-logo.svg", 89 | "enablement": "resourceLangId == python && config.processing.py.isEnabled" 90 | }, 91 | { 92 | "command": "processing.RunJava", 93 | "title": "Processing: Run Open Processing Java Project", 94 | "icon": "./images/play-arrow.svg", 95 | "enablement": "resourceLangId == pde" 96 | }, 97 | { 98 | "command": "processing.OpenExtensionDocumentation", 99 | "title": "Processing: Open Extension Documentation", 100 | "enablement": "resourceLangId == pde" 101 | }, 102 | { 103 | "command": "processing.OpenDocs", 104 | "title": "Processing: Open Documentation for Selection", 105 | "enablement": "resourceLangId == pde || resourceLangId == python && config.processing.py.isEnabled" 106 | }, 107 | { 108 | "command": "processing.SearchWebsite", 109 | "title": "Processing: Search Processing Website", 110 | "enablement": "resourceLangId == pde || resourceLangId == python && config.processing.py.isEnabled" 111 | } 112 | ], 113 | "languages": [ 114 | { 115 | "id": "pde", 116 | "aliases": [ 117 | "Processing", 118 | "pde" 119 | ], 120 | "extensions": [ 121 | ".pde" 122 | ], 123 | "configuration": "./pde.configuration.json" 124 | } 125 | ], 126 | "grammars": [ 127 | { 128 | "language": "pde", 129 | "scopeName": "source.pde", 130 | "path": "./syntaxes/pde.tmLanguage.json" 131 | } 132 | ], 133 | "snippets": [ 134 | { 135 | "language": "pde", 136 | "path": "./snippets/snippets.json" 137 | } 138 | ], 139 | "menus": { 140 | "editor/context": [ 141 | { 142 | "when": "editorHasSelection && editorLangId == 'pde'", 143 | "command": "processing.OpenDocs", 144 | "group": "navigation@1" 145 | }, 146 | { 147 | "when": "resourceLangId == pde", 148 | "command": "processing.RunJava", 149 | "group": "navigation" 150 | }, 151 | { 152 | "when": "resourceLangId == python && config.processing.py.isEnabled", 153 | "command": "processing.RunPy", 154 | "group": "navigation" 155 | } 156 | ], 157 | "editor/title": [ 158 | { 159 | "when": "resourceLangId == pde", 160 | "command": "processing.RunJava", 161 | "group": "navigation" 162 | }, 163 | { 164 | "when": "resourceLangId == python && config.processing.py.isEnabled", 165 | "command": "processing.RunPy", 166 | "group": "navigation" 167 | } 168 | ] 169 | }, 170 | "configuration": { 171 | "type": "object", 172 | "title": "Processing", 173 | "properties": { 174 | "processing.processingPath": { 175 | "type": "string", 176 | "default": "processing-java", 177 | "description": "Path to Processing. Leave default if you've added processing to your path, otherwise enter the path to `processing-java` here. Example: `/usr/bin/processing-java` for Unix, or `C:\\Program Files\\processing-3.0.1\\processing-java` for Windows." 178 | }, 179 | "processing.path": { 180 | "type": "string", 181 | "default": "processing-java", 182 | "description": "Legacy path to Processing. Use processing.processingPath instead. If processing.processingPath is available, it will be used", 183 | "deprecationMessage": "Legacy path to Processing. Use processing.processingPath instead. If processing.processingPath is available, it will be used" 184 | }, 185 | "processing.docs": { 186 | "type": "string", 187 | "default": "auto", 188 | "enum": [ 189 | "processing.org", 190 | "p5js.org", 191 | "py.processing.org", 192 | "auto" 193 | ], 194 | "enumDescriptions": [ 195 | "Use processing.org for documentation", 196 | "Use p5js for documentation", 197 | "Use py.processing.org for documentation", 198 | "Automatically determine either processing.org or py.processing.org (never p5js) depending on the current file" 199 | ], 200 | "description": "Which documentation this extension should use" 201 | }, 202 | "processing.search": { 203 | "type": "string", 204 | "default": "Google", 205 | "enum": [ 206 | "Google", 207 | "DuckDuckGo" 208 | ], 209 | "enumDescriptions": [ 210 | "Use Google to search documentation", 211 | "Use DuckDuckGo to search documentation" 212 | ], 213 | "description": "Which search engine should this extension use?" 214 | }, 215 | "processing.shouldGiveDiagnostics": { 216 | "type": "boolean", 217 | "default": false, 218 | "description": "If the extension should provide diagnostics (via processing-java). Note that this feature is quite slow." 219 | }, 220 | "processing.shouldSendSigint": { 221 | "type": "boolean", 222 | "default": false, 223 | "description": "If the extension should send sigint to the terminal stop the current running processing program before running the new one by sending \"\\x03\" (^C). If true, it essentially presses ctrl+c for you." 224 | }, 225 | "processing.runPathQuotes": { 226 | "type": "string", 227 | "enum": [ 228 | "auto", 229 | "always" 230 | ], 231 | "default": "auto", 232 | "description": "When the run path should be quoted. If always, the run path will always be quoted. If auto, the extension will attempt to figure out when to quote the path." 233 | }, 234 | "processing.py.jarPath": { 235 | "type": "string", 236 | "default": "processing-py.jar", 237 | "description": "The location of your processing-py.jar file. You can download it from https://py.processing.org/tutorials/command-line/#requirements." 238 | }, 239 | "processing.py.javaPath": { 240 | "type": "string", 241 | "default": "java", 242 | "description": "Path to Java. Leave default if you've added java to your path, otherwise enter the path to `java` here. Example: `/usr/bin/java` for Unix, or potentially `C:\\Program Files\\Java\\jdk1.8.0_202\\bin\\javac.exe` for Windows." 243 | }, 244 | "processing.py.isEnabled": { 245 | "type": "boolean", 246 | "default": true, 247 | "description": "If processing.py features should be enabled or not." 248 | } 249 | } 250 | } 251 | }, 252 | "displayName": "Processing VSCode", 253 | "icon": "images/processing.png", 254 | "publisher": "Luke-zhang-04", 255 | "workspaces": [ 256 | ".", 257 | "./rollup/plugins" 258 | ] 259 | } 260 | -------------------------------------------------------------------------------- /pde.configuration.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "lineComment": "//", 4 | "blockComment": ["/*", "*/"] 5 | }, 6 | "brackets": [ 7 | ["{", "}"], 8 | ["[", "]"], 9 | ["(", ")"] 10 | ], 11 | "autoClosingPairs": [ 12 | { 13 | "open": "{", 14 | "close": "}" 15 | }, 16 | { 17 | "open": "[", 18 | "close": "]" 19 | }, 20 | { 21 | "open": "(", 22 | "close": ")" 23 | }, 24 | { 25 | "open": "'", 26 | "close": "'", 27 | "notIn": ["string", "comment"] 28 | }, 29 | { 30 | "open": "\"", 31 | "close": "\"", 32 | "notIn": ["string"] 33 | }, 34 | { 35 | "open": "`", 36 | "close": "`", 37 | "notIn": ["string", "comment"] 38 | }, 39 | { 40 | "open": "/**", 41 | "close": " */", 42 | "notIn": ["string"] 43 | } 44 | ], 45 | "surroundingPairs": [ 46 | ["{", "}"], 47 | ["[", "]"], 48 | ["(", ")"], 49 | ["'", "'"], 50 | ["\"", "\""], 51 | ["<", ">"] 52 | ], 53 | "autoCloseBefore": ";:.,=}])>` \n\t", 54 | "folding": { 55 | "markers": { 56 | "start": "^\\s*//\\s*#?region\\b", 57 | "end": "^\\s*//\\s*#?endregion\\b" 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /rollup.config.js: -------------------------------------------------------------------------------- 1 | import {yaml} from "./rollup/plugins/lib/index.js" 2 | import progress from "rollup-plugin-progress" 3 | import resolve from "@rollup/plugin-node-resolve" 4 | import {terser} from "rollup-plugin-terser" 5 | import typescript from "@rollup/plugin-typescript" 6 | 7 | const banner = `/** 8 | * Processing-vscode - Processing Language Support for VSCode 9 | * https://github.com/Luke-zhang-04/processing-vscode 10 | * 11 | * @license MIT 12 | * @version 2.4.1 13 | * @preserve 14 | * @copyright (C) 2016 - 2020 Tobiah Zarlez, 2021 Luke Zhang 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | ` 25 | 26 | /** 27 | * @type {import("rollup").RollupOptions} 28 | */ 29 | const config = { 30 | input: "src/index.ts", 31 | output: { 32 | file: "./processing-vscode.js", 33 | format: "cjs", 34 | banner, 35 | inlineDynamicImports: true, 36 | sourcemap: process.env.NODE_ENV === "dev" ? "inline" : false, 37 | }, 38 | plugins: [ 39 | progress(), 40 | typescript(), 41 | yaml(), 42 | resolve({ 43 | resolveOnly: [/^(?!vscode)$/], 44 | }), 45 | process.env.NODE_ENV === "dev" 46 | ? undefined 47 | : terser({ 48 | format: { 49 | comments: (_, {value}) => 50 | (/@preserve/.test(value) || !/processing-vscode/iu.test(value)) && 51 | /@preserve|li[cs]ense|copyright/iu.test(value), 52 | }, 53 | }), 54 | ], 55 | } 56 | 57 | export default config 58 | -------------------------------------------------------------------------------- /rollup/plugins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rollup-plugins", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "build": "tsc" 8 | }, 9 | "dependencies": { 10 | "@rollup/pluginutils": "^4.1.0", 11 | "js-yaml": "^4.1.0" 12 | }, 13 | "devDependencies": { 14 | "@types/js-yaml": "^4.0.1", 15 | "rollup": "^2.53.0", 16 | "typescript": "^4.3.2" 17 | }, 18 | "types": "./lib/index.d.ts" 19 | } 20 | -------------------------------------------------------------------------------- /rollup/plugins/src/index.ts: -------------------------------------------------------------------------------- 1 | export {default as yaml} from "./json-and-yaml" 2 | -------------------------------------------------------------------------------- /rollup/plugins/src/json-and-yaml.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * @license MIT 3 | * @file improved Version of @rollup/plugin-json and @rollup/plugin-yaml that combines the two and 4 | * provides the option for JSON.stringify() 5 | * @copyright (c) 2019 RollupJS Plugin Contributors 6 | * (https://github.com/rollup/plugins/graphs/contributors), 2021 Luke Zhang 7 | * @see {@link https://github.com/rollup/plugins/tree/master/packages/json} 8 | * @see {@link https://github.com/rollup/plugins/tree/master/packages/yaml} 9 | */ 10 | 11 | import {FilterPattern, createFilter, dataToEsm} from "@rollup/pluginutils" 12 | import yaml from "js-yaml" 13 | import type {PluginFunc} from "./types" 14 | 15 | type ValidYamlType = 16 | | number 17 | | string 18 | | boolean 19 | | null 20 | | undefined 21 | | {[key: string]: ValidYamlType} 22 | | ValidYamlType[] 23 | 24 | type RollupJsonOptions = { 25 | /** 26 | * All JSON and YAML files will be parsed by default, but you can also specifically include files 27 | * 28 | * @default ["**‍/*.json", "**‍/*.y(a)?ml"] 29 | */ 30 | include?: FilterPattern 31 | /** 32 | * All JSON and YAML files will be parsed by default, but you can also specifically exclude files 33 | * 34 | * @default 35 | */ 36 | exclude?: FilterPattern 37 | /** 38 | * For tree-shaking, properties will be declared as variables, using either `var` or `const`. 39 | * 40 | * @default true 41 | */ 42 | preferConst?: boolean 43 | /** 44 | * Specify indentation for the generated default export 45 | * 46 | * @default 47 | */ 48 | indent?: string 49 | /** 50 | * Ignores indent and generates the smallest code 51 | * 52 | * @default false 53 | */ 54 | compact?: boolean 55 | /** 56 | * Generate a named export for every property of the JSON object 57 | * 58 | * @default true 59 | */ 60 | namedExports?: boolean 61 | /** 62 | * Character for when json should be stringified and then parsed at runtime 63 | * 64 | * @default 14 * 1024 (14kb) 65 | * @see {@link https://v8.dev/blog/cost-of-javascript-2019#json} 66 | */ 67 | stringifyLimit?: number 68 | /** 69 | * A function which can optionally mutate parsed YAML. The function should return the mutated 70 | * `object`, or `undefined` which will make no changes to the parsed YAML. 71 | * 72 | * @default undefined 73 | */ 74 | transform?: (data: ValidYamlType, filePath: string) => ValidYamlType | undefined 75 | /** 76 | * - If `single`, specifies that the target YAML documents contain only one document in the target file(s). 77 | * - If more than one [document stream](https://yaml.org/spec/1.2/spec.html#id2801681) exists in 78 | * the target YAML file(s), set `documentMode: 'multi'`. 79 | * 80 | * @default 'single' 81 | */ 82 | documentMode?: "single" | "multi" 83 | } 84 | 85 | const json: PluginFunc = ({ 86 | include = ["**/*.y(a)?ml", "**/*.json"], 87 | exclude, 88 | preferConst = true, 89 | indent = " ", 90 | compact = false, 91 | namedExports = true, 92 | stringifyLimit = 14 * 1024, 93 | transform, 94 | documentMode = "single", 95 | } = {}) => { 96 | const filter = createFilter(include, exclude) 97 | 98 | let loadMethod = (documentMode === "multi" ? yaml.loadAll : yaml.load) as ( 99 | str: string, 100 | iterator?: (doc: any) => void, 101 | opts?: yaml.LoadOptions, 102 | ) => ValidYamlType 103 | 104 | const plugin: ReturnType> = { 105 | name: "json/yaml", 106 | transform(code, id) { 107 | if (!filter(id)) { 108 | return null 109 | } 110 | 111 | try { 112 | const parsed = transform?.(loadMethod(code), id) ?? loadMethod(code) 113 | const stringified = JSON.stringify(parsed, null, 0) 114 | 115 | return { 116 | code: 117 | stringified.length > stringifyLimit 118 | ? `export default JSON.parse(${JSON.stringify(stringified)})` 119 | : dataToEsm(parsed, { 120 | preferConst, 121 | compact, 122 | namedExports, 123 | indent, 124 | }), 125 | map: {mappings: ""}, 126 | } 127 | } catch (err) { 128 | const message = `Could not parse JSON file: ${ 129 | err instanceof Error ? err.toString() : JSON.stringify(err) 130 | }` 131 | 132 | this.error({message, id}) 133 | } 134 | }, 135 | } 136 | 137 | return plugin 138 | } 139 | 140 | export default json 141 | -------------------------------------------------------------------------------- /rollup/plugins/src/types.ts: -------------------------------------------------------------------------------- 1 | export type PluginFunc = (options: T) => import("rollup").Plugin | undefined 2 | -------------------------------------------------------------------------------- /rollup/plugins/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "ES2020", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', 'ES2021', or 'ESNEXT'. */ 8 | "module": "ES2020", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', 'react', 'react-jsx' or 'react-jsxdev'. */ 13 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "./lib", /* Redirect output structure to the directory. */ 18 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | "strictNullChecks": true, /* Enable strict null checks. */ 31 | "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | "noUncheckedIndexedAccess": true, /* Include 'undefined' in index signature results */ 43 | "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an 'override' modifier. */ 44 | "noPropertyAccessFromIndexSignature": false, /* Require undeclared properties from index signatures to use element accesses. */ 45 | 46 | /* Module Resolution Options */ 47 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 48 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 49 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 50 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 51 | // "typeRoots": [], /* List of folders to include type definitions from. */ 52 | // "types": [], /* Type declaration files to be included in compilation. */ 53 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 54 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 55 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 56 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 57 | 58 | /* Source Map Options */ 59 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 60 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 61 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 62 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 63 | 64 | /* Experimental Options */ 65 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 66 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 67 | 68 | /* Advanced Options */ 69 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 70 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 71 | }, 72 | "include": ["./src"] 73 | } 74 | -------------------------------------------------------------------------------- /scripts/checkDocs.mjs: -------------------------------------------------------------------------------- 1 | #!/bin/node 2 | 3 | /** 4 | * @file Checks If documentation data is up to date 5 | */ 6 | 7 | import crypto from "crypto" 8 | import {dirname} from "path" 9 | import {fileURLToPath} from "url" 10 | import {promises as fs} from "fs" 11 | import yaml from "yaml" 12 | import getDocs from "./helpers/fetchDocs.mjs" 13 | 14 | export const hash = (algo, contents, format = "hex") => 15 | crypto.createHash(algo).update(contents).digest(format) 16 | 17 | const __dirname = dirname(fileURLToPath(import.meta.url)) 18 | 19 | const newDocs = await getDocs() 20 | const newDocsString = `# THIS IS AN AUTOGENERATED FILE; DO NOT EDIT DIRECTLY\n\n${yaml.stringify( 21 | newDocs, 22 | { 23 | sortMapEntries: true, 24 | }, 25 | )}`.trim() 26 | 27 | const oldDocsString = ( 28 | await fs.readFile(`${__dirname}/../data/documentation-data.yml`, "utf-8") 29 | ).trim() 30 | 31 | if (hash("sha256", newDocsString) === hash("sha256", oldDocsString)) { 32 | console.log("Documentation data is up to date") 33 | } else { 34 | throw new Error("Documentation is out of date") 35 | } 36 | -------------------------------------------------------------------------------- /scripts/helpers/fetchDocs.mjs: -------------------------------------------------------------------------------- 1 | #!/bin/node 2 | 3 | import {JSDOM} from "jsdom" 4 | import fetch from "node-fetch" 5 | 6 | const docsUrl = "https://processing.org/reference" 7 | 8 | // Processing global variables 9 | const variables = [ 10 | "focused", 11 | "frameCount", 12 | "height", 13 | "width", 14 | "pixelHeight", 15 | "pixelWidth", 16 | "mouseButton", 17 | "mouseX", 18 | "mouseY", 19 | "pmouseX", 20 | "pmouseY", 21 | "key", 22 | "keyCode", 23 | "keyPressed", 24 | "HALF_PI", 25 | "PI", 26 | "QUARTER_PI", 27 | "TAU", 28 | "TWO_PI", 29 | ] 30 | 31 | const constants = ["HALF_PI.html", "PI.html", "QUARTER_PI.html", "TAU.html", "TWO_PI.html"] 32 | 33 | // Processing classes 34 | const classes = [ 35 | "Array", 36 | "ArrayList", 37 | "FloatDict", 38 | "FloatList", 39 | "HashMap", 40 | "IntDict", 41 | "IntList", 42 | "JSONArray", 43 | "JSONObject", 44 | "Object", 45 | "String", 46 | "StringDict", 47 | "StringList", 48 | "Table", 49 | "TableRow", 50 | "XML", 51 | "PShape", 52 | "PImage", 53 | "PGraphics", 54 | "PShader", 55 | "PFont", 56 | "PVector", 57 | ] 58 | 59 | /** 60 | * Gets all the links to Processing builtins 61 | */ 62 | const getDocLinks = async () => { 63 | const response = await fetch(docsUrl) 64 | 65 | if (response.status !== 200) { 66 | console.log(`Response for all links returned status ${response.status}.`) 67 | console.log(response) 68 | 69 | return 70 | } 71 | 72 | const {window} = new JSDOM(await response.text()) // Fetch docs and parse as document 73 | const {document} = window 74 | const references = Array.from(document.querySelectorAll("div.category a")) // All reference items 75 | 76 | return { 77 | functionLinks: references // Function doc links 78 | .filter(({innerHTML}) => /[A-z]\(\)/u.test(innerHTML)) 79 | .map((item) => item.getAttribute("href").trim()), 80 | variableLinks: references // Variable doc links 81 | .filter(({innerHTML}) => variables.includes(innerHTML)) 82 | .map((item) => item.getAttribute("href").trim()), 83 | classLinks: references // Class doc links 84 | .filter(({innerHTML}) => classes.includes(innerHTML)) 85 | .map((item) => item.getAttribute("href").trim()), 86 | } 87 | } 88 | 89 | /** 90 | * Escapes some html 91 | * 92 | * @param {string} html - Html to escape 93 | * @returns {string} Escaped html 94 | */ 95 | const escapeHTML = (html) => 96 | html 97 | .replace(/<(\/)?(b|pre)>/gu, "`") 98 | .replace(//gu, "") 99 | .replace(/<[^>]*>/gu, "") 100 | .replace(/</gu, "<") 101 | .replace(/>/gu, ">") 102 | .trim() 103 | 104 | /** 105 | * Gets the documentation for a single link 106 | * 107 | * @param {string} link - Link to get doc from 108 | * @returns {Promise} 109 | */ 110 | const documentVariable = async (link) => { 111 | const documentation = { 112 | docUrl: `${docsUrl}/${link}`, 113 | type: constants.includes(link) ? "const" : "var", 114 | } 115 | 116 | const response = await fetch(`${docsUrl}/${link}`) 117 | 118 | if (!response.ok) { 119 | console.log(`Response for ${link} returned status ${response.status}.`) 120 | console.log(response) 121 | 122 | return 123 | } 124 | 125 | const {window} = new JSDOM(await response.text()) // Parse webpage 126 | const {document} = window 127 | 128 | for (const item of Array.from(document.querySelectorAll(".content table tr"))) { 129 | const header = item.querySelector("th") 130 | 131 | if (!header) { 132 | continue 133 | } 134 | 135 | const {innerHTML} = header // Get the header for each table item 136 | 137 | const property = (() => { 138 | if (["Description", "Examples", "Name"].includes(innerHTML)) { 139 | return innerHTML.toLowerCase() 140 | } 141 | })() 142 | 143 | if (property) { 144 | if (property === "description") { 145 | const description = escapeHTML(item.querySelector("td").innerHTML).replace( 146 | /\\n/gu, 147 | "\n\n", 148 | ) 149 | 150 | documentation.description = 151 | description.length > 1000 ? description.slice(0, 1000) + ". . ." : description 152 | } else if (property === "examples") { 153 | documentation[property] = escapeHTML(item.querySelector("td").innerHTML).replace( 154 | /`/giu, 155 | "", 156 | ) 157 | } else { 158 | documentation[property] = escapeHTML(item.querySelector("td").innerHTML) 159 | } 160 | } 161 | } 162 | 163 | return documentation 164 | } 165 | 166 | /** 167 | * Gets the documentation for a single link 168 | * 169 | * @param {string} link - Link to get doc from 170 | * @returns {Promise} 171 | */ 172 | const documentFunction = async (link) => { 173 | const documentation = { 174 | docUrl: `${docsUrl}/${link}`, 175 | parameters: {}, 176 | type: "function", 177 | } 178 | 179 | const response = await fetch(`${docsUrl}/${link}`) 180 | 181 | if (!response.ok) { 182 | console.log(`Response for ${link} returned status ${response.status}.`) 183 | console.log(response) 184 | 185 | return 186 | } 187 | 188 | const {window} = new JSDOM(await response.text()) 189 | const {document} = window 190 | 191 | for (const item of Array.from(document.querySelectorAll(".content table tr"))) { 192 | const header = item.querySelector("th") 193 | 194 | if (!header) { 195 | continue 196 | } 197 | 198 | const {innerHTML} = header 199 | 200 | const property = (() => { 201 | if (["Description", "Syntax", "Returns", "Parameters", "Name"].includes(innerHTML)) { 202 | return innerHTML.toLowerCase() 203 | } 204 | })() 205 | 206 | if (property) { 207 | if (property === "parameters") { 208 | Array.from(item.querySelectorAll("td table tr")).forEach((item) => { 209 | documentation.parameters[item.querySelector("th").innerHTML] = escapeHTML( 210 | item.querySelector("td").innerHTML, 211 | ) 212 | }) 213 | } else if (property === "syntax") { 214 | documentation.syntax = escapeHTML(item.querySelector("td").innerHTML).replace( 215 | /`/gu, 216 | "", 217 | ) 218 | } else if (property === "description") { 219 | const description = escapeHTML(item.querySelector("td").innerHTML).replace( 220 | /\\n/gu, 221 | "\n\n", 222 | ) 223 | 224 | documentation.description = 225 | description.length > 1000 ? description.slice(0, 1000) + ". . ." : description 226 | } else { 227 | documentation[property] = escapeHTML(item.querySelector("td").innerHTML) 228 | } 229 | } 230 | } 231 | 232 | return documentation 233 | } 234 | 235 | /** 236 | * Gets the documentation for a single link 237 | * 238 | * @param {string} link - Link to get doc from 239 | * @returns {Promise} 240 | */ 241 | const documentClass = async (link) => { 242 | const documentation = { 243 | docUrl: `${docsUrl}/${link}`, 244 | parameters: {}, 245 | methods: {}, 246 | fields: {}, 247 | type: "class", 248 | } 249 | 250 | const response = await fetch(`${docsUrl}/${link}`) 251 | 252 | if (!response.ok) { 253 | // If response wasn't ok, return 254 | console.log(`Response for ${link} returned status ${response.status}.`) 255 | console.log(response) 256 | 257 | return 258 | } 259 | 260 | const {window} = new JSDOM(await response.text()) // Parse the page 261 | const {document} = window 262 | 263 | for (const item of Array.from(document.querySelectorAll(".content table tr"))) { 264 | const header = item.querySelector("th") 265 | 266 | if (!header) { 267 | continue 268 | } 269 | 270 | const {innerHTML} = header 271 | 272 | const property = (() => { 273 | if (["Description", "Constructor", "Parameters", "Name"].includes(innerHTML)) { 274 | return innerHTML.toLowerCase() 275 | } 276 | })() 277 | 278 | if (property) { 279 | if (property === "parameters") { 280 | Array.from(item.querySelectorAll("td table tr")).forEach((item) => { 281 | documentation.parameters[item.querySelector("th").innerHTML] = escapeHTML( 282 | item.querySelector("td").innerHTML, 283 | ) 284 | }) 285 | } else if (property === "constructor") { 286 | documentation.syntax = escapeHTML(item.querySelector("td").innerHTML).replace( 287 | /`/gu, 288 | "", 289 | ) 290 | } else if (property === "description") { 291 | const description = escapeHTML(item.querySelector("td").innerHTML).replace( 292 | /\\n/gu, 293 | "\n\n", 294 | ) 295 | 296 | documentation.description = 297 | description.length > 1000 ? description.slice(0, 1000) + ". . ." : description 298 | } else { 299 | documentation[property] = escapeHTML(item.querySelector("td").innerHTML) 300 | } 301 | } 302 | } 303 | 304 | return documentation 305 | } 306 | 307 | /** 308 | * Gets the documentation for the links in `links` 309 | * 310 | * @param {{ 311 | * functionLinks: string[] 312 | * variableLinks: string[] 313 | * classLinks: string[] 314 | * }} links 315 | * - Links go get documenttion from 316 | */ 317 | const documentLinks = async ({classLinks, functionLinks, variableLinks}) => { 318 | /** 319 | * All documentation (final object dumped to JSON) 320 | * 321 | * @type {import("../../src/types").Documentation} 322 | */ 323 | const documentation = {} 324 | 325 | const fetchPromises = [] // Get documentation asynchronously 326 | 327 | console.log(` Getting documentation for ${functionLinks.length} functions`) 328 | for (const link of functionLinks) { 329 | // Document functions 330 | const job = (async () => { 331 | const doc = await documentFunction(link) 332 | 333 | if (doc) { 334 | documentation[doc.name.replace(/\(\)/gu, "")] = { 335 | ...doc, 336 | name: undefined, 337 | } 338 | } 339 | })() 340 | 341 | fetchPromises.push(job) 342 | } 343 | 344 | console.log(` Getting documentation for ${classLinks.length} classes`) 345 | for (const link of classLinks) { 346 | // Document classes 347 | const job = (async () => { 348 | const doc = await documentClass(link) 349 | 350 | if (doc) { 351 | documentation[doc.name.replace(/\(\)/gu, "")] = { 352 | ...doc, 353 | name: undefined, 354 | } 355 | } 356 | })() 357 | 358 | fetchPromises.push(job) 359 | } 360 | 361 | console.log(` Getting documentation for ${variableLinks.length} variables`) 362 | for (const link of variableLinks) { 363 | // Document variables 364 | const job = (async () => { 365 | const doc = await documentVariable(link) 366 | 367 | if (doc) { 368 | documentation[doc.name.replace(/\(\)/gu, "")] = { 369 | ...doc, 370 | name: undefined, 371 | } 372 | } 373 | })() 374 | 375 | fetchPromises.push(job) 376 | } 377 | 378 | await Promise.all(fetchPromises) 379 | 380 | return documentation 381 | } 382 | 383 | /** 384 | * @returns Documentation from https://processing.org/reference 385 | */ 386 | export const getDocs = async () => { 387 | const links = await getDocLinks() 388 | 389 | if (!links) { 390 | return 391 | } 392 | 393 | console.log( 394 | `Got doc links for ${ 395 | links.functionLinks.length + links.classLinks.length + links.variableLinks.length 396 | } items`, 397 | ) 398 | 399 | const docs = await documentLinks(links) 400 | 401 | return docs 402 | } 403 | 404 | export default getDocs 405 | -------------------------------------------------------------------------------- /scripts/writeDocs.mjs: -------------------------------------------------------------------------------- 1 | #!/bin/node 2 | 3 | /** 4 | * @file gets Documentation from https://processing.org/reference and dumps it into 5 | * `src/documentation-data.json` with some bootleg webscraping 6 | */ 7 | 8 | import {dirname} from "path" 9 | import {fileURLToPath} from "url" 10 | import {promises as fs} from "fs" 11 | import yaml from "yaml" 12 | import getDocs from "./helpers/fetchDocs.mjs" 13 | 14 | const __dirname = dirname(fileURLToPath(import.meta.url)) 15 | 16 | const docs = await getDocs() 17 | 18 | await fs.writeFile( 19 | `${__dirname}/../data/documentation-data.yml`, 20 | `# THIS IS AN AUTOGENERATED FILE; DO NOT EDIT DIRECTLY\n\n${yaml.stringify(docs, { 21 | sortMapEntries: true, 22 | })}`, 23 | "utf8", 24 | ) 25 | -------------------------------------------------------------------------------- /src/commands/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @copyright (C) 2021 Luke Zhang 5 | */ 6 | 7 | import {openDocumentation, openProcessingDocs, searchUnityDocs} from "./search" 8 | import {run as runProject} from "./run" 9 | import {shouldEnablePython} from "../config" 10 | import vscode from "vscode" 11 | 12 | export const subscribeCommands = (context: vscode.ExtensionContext): void => { 13 | context.subscriptions.push(vscode.commands.registerCommand("processing.Run", runProject)) 14 | 15 | if (shouldEnablePython) { 16 | context.subscriptions.push( 17 | vscode.commands.registerCommand("processing.RunPy", () => runProject("py")), 18 | ) 19 | } 20 | 21 | context.subscriptions.push( 22 | vscode.commands.registerCommand("processing.RunJava", () => runProject("java")), 23 | ) 24 | 25 | context.subscriptions.push( 26 | vscode.commands.registerCommand( 27 | "processing.OpenExtensionDocumentation", 28 | openDocumentation, 29 | ), 30 | ) 31 | 32 | // Open Processing Documentation, when you already have something you want to search selected 33 | context.subscriptions.push( 34 | vscode.commands.registerTextEditorCommand("processing.OpenDocs", openProcessingDocs), 35 | ) 36 | 37 | context.subscriptions.push( 38 | vscode.commands.registerCommand("processing.SearchWebsite", searchUnityDocs), 39 | ) 40 | } 41 | 42 | export default subscribeCommands 43 | -------------------------------------------------------------------------------- /src/commands/run.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @copyright (C) 2021 Luke Zhang 5 | */ 6 | 7 | import { 8 | jarPath, 9 | javaCommand, 10 | processingCommand, 11 | shouldAlwaysQuotePath, 12 | shouldSendSigint, 13 | } from "../config" 14 | import path, {dirname} from "path" 15 | import {isValidProcessingProject} from "../utils" 16 | import vscode from "vscode" 17 | 18 | const pythonUtils = { 19 | getProjectFilename: ({fileName}: vscode.TextDocument): string => 20 | shouldAlwaysQuotePath || / |\\/u.test(fileName) ? `"${fileName}"` : fileName, 21 | 22 | getJarFilename: (): string => 23 | shouldAlwaysQuotePath || / |\\/u.test(jarPath) ? `"${jarPath}"` : jarPath, 24 | } 25 | 26 | class RunManager { 27 | private _terminal?: vscode.Terminal = undefined 28 | 29 | private _pythonTerminal?: vscode.Terminal = undefined 30 | 31 | public run = (mode?: "py" | "java"): void => { 32 | const {activeTextEditor: editor} = vscode.window 33 | 34 | if (!editor) { 35 | vscode.window.showErrorMessage("No active text editor found") 36 | 37 | return 38 | } 39 | 40 | const processingMode = (() => { 41 | if (mode) { 42 | return mode 43 | } 44 | 45 | if (/\.pde$/u.test(editor.document.fileName)) { 46 | return "java" 47 | } else if (editor.document.languageId === "python") { 48 | return "py" 49 | } 50 | 51 | return 52 | })() 53 | 54 | if (processingMode === "java") { 55 | this._runJavaMode(editor) 56 | } else if (processingMode === "py") { 57 | this._runPythonMode(editor) 58 | } else { 59 | vscode.window.showErrorMessage("Could not determine processing mode.") 60 | } 61 | } 62 | 63 | /** 64 | * This monstrosity searches for an existing terminal if it exists or creates a new one and returns it. 65 | * 66 | * @param terminalName - Key of terminal in class 67 | * @param terminalDisplayName - Display name of terminal 68 | * @returns Vscode terminal 69 | */ 70 | private _getTerminal = ( 71 | terminalName: "_terminal" | "_pythonTerminal", 72 | terminalDisplayName: string, 73 | ): vscode.Terminal => 74 | (this[terminalName] !== undefined && this[terminalName]?.exitStatus === undefined // Terminal exists 75 | ? vscode.window.terminals.find((terminal) => terminal.name === terminalDisplayName) // Find existing terminal 76 | : (this[terminalName] = vscode.window.createTerminal(terminalDisplayName))) ?? // Terminal doesn't exist; create a new terminal 77 | (this[terminalName] = vscode.window.createTerminal(terminalDisplayName)) // Somehow couldn't find an existing terminal 78 | 79 | /** 80 | * Runs the current project in Java mode 81 | * 82 | * @param editor - Vscode text editor 83 | */ 84 | private _runJavaMode = (editor: vscode.TextEditor): void => { 85 | const terminalName = "_terminal" 86 | const hasTerminal = 87 | this[terminalName] !== undefined && this[terminalName]?.exitStatus === undefined 88 | const currentTerminal = this._getTerminal(terminalName, "Processing") 89 | 90 | let sketchName = dirname(editor.document.fileName) 91 | const isValidProjectName = isValidProcessingProject(sketchName.split(path.sep).pop()) 92 | const shouldQuotePath = shouldAlwaysQuotePath || / |\\/u.test(sketchName) 93 | 94 | if (shouldQuotePath) { 95 | sketchName = `"${sketchName}"` 96 | } 97 | 98 | currentTerminal.show() 99 | 100 | if (!isValidProjectName) { 101 | vscode.window.showWarningMessage( 102 | "Warning: Processing project names must be valid Java variable names. Your program may fail to run properly.", 103 | ) 104 | } 105 | 106 | // If file is a processing project file 107 | const cmd = `${ 108 | hasTerminal && shouldSendSigint ? "\x03" : "" 109 | }${processingCommand} --sketch=${sketchName} --run` 110 | 111 | currentTerminal.sendText(cmd) 112 | } 113 | 114 | /** 115 | * Runs the current project in Python mode 116 | * 117 | * @param editor - Vscode text editor 118 | */ 119 | private _runPythonMode = (editor: vscode.TextEditor): void => { 120 | const terminalName = "_terminal" 121 | const hasTerminal = 122 | this[terminalName] !== undefined && this[terminalName]?.exitStatus === undefined 123 | const currentTerminal = this._getTerminal(terminalName, "Processing-py") 124 | 125 | currentTerminal.show() 126 | 127 | // If file is a processing project file 128 | const cmd = `${ 129 | hasTerminal && shouldSendSigint ? "\x03" : "" 130 | }${javaCommand} -jar ${pythonUtils.getJarFilename()} ${pythonUtils.getProjectFilename( 131 | editor.document, 132 | )}` 133 | 134 | currentTerminal.sendText(cmd) 135 | } 136 | } 137 | 138 | const runManager = new RunManager() 139 | 140 | /** 141 | * Runs the current processing project 142 | * 143 | * @param editor - Vscode text editor 144 | * @param log - Vscode output log 145 | */ 146 | export const {run} = runManager 147 | -------------------------------------------------------------------------------- /src/commands/search.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @copyright (C) 2016 - 2020 Tobiah Zarlez, 2021 Luke Zhang 5 | */ 6 | 7 | import {search} from "../utils" 8 | import vscode from "vscode" 9 | 10 | const openDocErrorMessage = async (str: string) => { 11 | const item = await vscode.window.showErrorMessage(`Error: ${str}`, "Open Docs") 12 | 13 | if (item === "Open Docs") { 14 | search.openURL("docs") 15 | } 16 | } 17 | 18 | export const openDocumentation = () => { 19 | search.openURL( 20 | "https://github.com/Luke-zhang-04/processing-vscode#processing-for-visual-studio-code", 21 | ) 22 | } 23 | 24 | export const openProcessingDocs = (textEditor: vscode.TextEditor) => { 25 | // selection[0] is the start, and selection[1] is the end 26 | const {selection} = textEditor 27 | 28 | if (!selection.isSingleLine) { 29 | openDocErrorMessage("Multiple lines selected, please select a class or function.") 30 | 31 | return 32 | } 33 | 34 | let range = undefined 35 | 36 | if (selection.isEmpty) { 37 | // selection is empty, get any word at cursor 38 | range = textEditor.document.getWordRangeAtPosition(selection.active) 39 | } else { 40 | // selection is not empty, get text from it 41 | range = new vscode.Range(selection.start, selection.end) 42 | } 43 | 44 | if (range === undefined) { 45 | openDocErrorMessage( 46 | 'Nothing is selected. Please select a class, or use "Search Documentation" instead!', 47 | ) 48 | 49 | return 50 | } 51 | 52 | search.openProcessingDocs( 53 | textEditor.document.lineAt(range.start.line).text, 54 | range.start.character, 55 | range.end.character, 56 | ) 57 | } 58 | 59 | export const searchUnityDocs = () => { 60 | vscode.window 61 | .showInputBox({ 62 | prompt: "Search Processing Website:", 63 | }) 64 | .then((result: string | undefined) => { 65 | if (result !== undefined) { 66 | // Use the node module "open" to open a web browser 67 | search.openURL("docs", result) 68 | } 69 | }) 70 | } 71 | -------------------------------------------------------------------------------- /src/config.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @copyright (C) 2021 Luke Zhang 5 | */ 6 | 7 | import {escapeExecutablePath} from "./utils" 8 | import vscode from "vscode" 9 | 10 | const getProcessingCommand = (): string => { 11 | // Look for processing.processingPath, then processing.path, then default to processing-java 12 | const config = vscode.workspace 13 | .getConfiguration() 14 | .get( 15 | "processing.processingPath", 16 | vscode.workspace.getConfiguration().get("processing.path", "processing-java"), 17 | ) 18 | 19 | if (typeof config !== "string") { 20 | const msg = "Config option processing.processingPath must be of type string" 21 | 22 | vscode.window.showErrorMessage(msg) 23 | 24 | return "processing-java" 25 | } 26 | 27 | return escapeExecutablePath(config) 28 | } 29 | 30 | const getJavaCommand = (): string => { 31 | const config = vscode.workspace 32 | .getConfiguration() 33 | .get("processing.py.javaPath", "java") 34 | 35 | if (typeof config !== "string") { 36 | const msg = "Config option processing.py.javaPath must be of type string" 37 | 38 | vscode.window.showErrorMessage(msg) 39 | 40 | return "java" 41 | } 42 | 43 | return config 44 | } 45 | 46 | const getJarPath = (): string => { 47 | const config = vscode.workspace 48 | .getConfiguration() 49 | .get("processing.py.jarPath", "processing-py.jar") 50 | 51 | if (typeof config !== "string") { 52 | const msg = "Config option processing.py.jarPath must be of type string" 53 | 54 | vscode.window.showErrorMessage(msg) 55 | 56 | return "processing-py.jar" 57 | } 58 | 59 | return config 60 | } 61 | 62 | const getShouldEnablePython = (): boolean => { 63 | const isEnabled = vscode.workspace 64 | .getConfiguration() 65 | .get("processing.py.isEnabled", true) 66 | 67 | if (typeof isEnabled !== "boolean") { 68 | const msg = "Config option processing.py.isEnabled should be a boolean" 69 | 70 | vscode.window.showErrorMessage(msg) 71 | 72 | return true 73 | } 74 | 75 | return isEnabled 76 | } 77 | 78 | type SearchEngines = "Google" | "DuckDuckGo" 79 | type DocOptions = "processing.org" | "p5js.org" | "py.processing.org" | "auto" 80 | 81 | const getSearchConfig = (): {searchEngine: SearchEngines; processingDocs: DocOptions} => { 82 | const config = vscode.workspace.getConfiguration("processing") 83 | const processingDocs = config.get("docs", "auto") 84 | const searchEngine = config.get("search", "Google") 85 | 86 | if (!["processing.org", "p5js.org", "py.processing.org", "auto"].includes(processingDocs)) { 87 | const msg = 88 | 'Config option processing.docs must be "processing.org" | "p5js.org" | "py.processing.org" | "auto"' 89 | 90 | vscode.window.showErrorMessage(msg) 91 | 92 | return {searchEngine: "Google", processingDocs: "auto"} 93 | } else if (!["Google", "DuckDuckGo"].includes(searchEngine)) { 94 | const msg = 'Config option processing.search must be "Google" | "DuckDuckGo"' 95 | 96 | vscode.window.showErrorMessage(msg) 97 | 98 | return {searchEngine: "Google", processingDocs: "auto"} 99 | } 100 | 101 | return { 102 | searchEngine, 103 | processingDocs, 104 | } 105 | } 106 | 107 | const getshouldEnableDiagnostics = (): boolean => { 108 | const shouldGiveDiagnostics = vscode.workspace 109 | .getConfiguration() 110 | .get("processing.shouldGiveDiagnostics", true) 111 | 112 | if (typeof shouldGiveDiagnostics !== "boolean") { 113 | const msg = "Config option processing.shouldGiveDiagnostics must be of type boolean" 114 | 115 | vscode.window.showErrorMessage(msg) 116 | 117 | return true 118 | } 119 | 120 | return shouldGiveDiagnostics 121 | } 122 | 123 | const getQuoteEnablement = (): boolean => { 124 | const shouldQuotePath = vscode.workspace 125 | .getConfiguration() 126 | .get<"always" | "auto">("processing.runPathQuotes", "auto") 127 | 128 | if (shouldQuotePath !== "always" && shouldQuotePath !== "auto") { 129 | const msg = 'Config option processing.runPathQuotes should be "auto" or "always"' 130 | 131 | vscode.window.showErrorMessage(msg) 132 | 133 | return false 134 | } 135 | 136 | return shouldQuotePath === "always" 137 | } 138 | 139 | const getShouldSendSigint = (): boolean => { 140 | const isEnabled = vscode.workspace 141 | .getConfiguration() 142 | .get("processing.shouldSendSigint", false) 143 | 144 | if (typeof isEnabled !== "boolean") { 145 | const msg = "Config option processing.shouldSendSigint must be of type boolean" 146 | 147 | vscode.window.showErrorMessage(msg) 148 | 149 | throw new Error(msg) 150 | } 151 | 152 | return isEnabled 153 | } 154 | 155 | export let processingCommand = getProcessingCommand() 156 | export let javaCommand = getJavaCommand() 157 | export let jarPath = getJarPath() 158 | export let shouldEnablePython = getShouldEnablePython() 159 | export let searchConfig = getSearchConfig() 160 | export let shouldEnableDiagnostics = getshouldEnableDiagnostics() 161 | export let shouldAlwaysQuotePath = getQuoteEnablement() 162 | export let shouldSendSigint = getShouldSendSigint() 163 | 164 | vscode.workspace.onDidChangeConfiguration(() => { 165 | processingCommand = getProcessingCommand() 166 | javaCommand = getJavaCommand() 167 | jarPath = getJarPath() 168 | shouldEnablePython = getShouldEnablePython() 169 | searchConfig = getSearchConfig() 170 | shouldEnableDiagnostics = getshouldEnableDiagnostics() 171 | shouldAlwaysQuotePath = getQuoteEnablement() 172 | shouldSendSigint = getShouldSendSigint() 173 | }) 174 | -------------------------------------------------------------------------------- /src/diagnostics.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @copyright (C) 2021 Luke Zhang 5 | */ 6 | 7 | import path, {dirname} from "path" 8 | import childProcess from "child_process" 9 | import crypto from "crypto" 10 | import {isValidProcessingProject} from "./utils" 11 | import {processingCommand} from "./config" 12 | import vscode from "vscode" 13 | 14 | let oldHash = "" 15 | 16 | const hash = (content: {toString: () => string}) => 17 | crypto.createHash("sha384").update(content.toString()).digest("hex") 18 | 19 | const createDiagnostic = ( 20 | lineOfText: vscode.TextLine, 21 | lineIndex: number, 22 | charIndex: number, 23 | message: string, 24 | ): vscode.Diagnostic => { 25 | const range = new vscode.Range(lineIndex, charIndex, lineIndex, lineOfText.text.length) 26 | 27 | const diagnostic = new vscode.Diagnostic(range, message, vscode.DiagnosticSeverity.Error) 28 | 29 | diagnostic.code = "processing-java" 30 | 31 | return diagnostic 32 | } 33 | 34 | const refreshDiagnostics = async ( 35 | diagnostics: vscode.DiagnosticCollection, 36 | doc: vscode.TextDocument, 37 | log: vscode.OutputChannel, 38 | ): Promise => { 39 | try { 40 | const foundDiagnostics: vscode.Diagnostic[] = [] 41 | let sketchName = doc.fileName.includes(".pde") ? dirname(doc.fileName) : undefined 42 | 43 | if ( 44 | sketchName && 45 | doc.getText() && 46 | isValidProcessingProject(sketchName.split(path.sep).pop()) 47 | ) { 48 | const shouldQuotePath = sketchName.includes(" ") 49 | 50 | if (shouldQuotePath) { 51 | sketchName = `"${sketchName}"` 52 | } 53 | 54 | console.log({sketchName}) 55 | const diagnostic = await new Promise((resolve) => { 56 | const processingProcess = childProcess.spawn(processingCommand, [ 57 | `--sketch=${sketchName}`, 58 | "--build", 59 | ]) 60 | 61 | const problems: string[] = [] 62 | 63 | const handleOutput = (data: Buffer): void => { 64 | for (const line of data.toString().split("\n")) { 65 | if (/(:[0-9]+){4}:/gu.test(line)) { 66 | problems.push(line) 67 | } 68 | } 69 | } 70 | 71 | processingProcess.stderr.on("data", handleOutput) 72 | processingProcess.stdout.on("data", handleOutput) 73 | 74 | processingProcess.on("exit", () => { 75 | resolve(problems) 76 | }) 77 | }).catch(() => undefined) 78 | 79 | if (!diagnostic) { 80 | return 81 | } 82 | 83 | if (diagnostic.length > 0) { 84 | log.appendLine(diagnostic.toString()) 85 | } 86 | 87 | for (const result of diagnostic) { 88 | const splitResult = result.split(":") 89 | const lineIndex = Number(splitResult[1]) - 1 90 | const charIndex = Number(splitResult[2]) - 2 91 | 92 | foundDiagnostics.push( 93 | createDiagnostic( 94 | doc.lineAt(lineIndex), 95 | lineIndex > 0 ? lineIndex : 0, 96 | charIndex > 0 ? charIndex : 0, 97 | splitResult.slice(5).join("").trim(), 98 | ), 99 | ) 100 | } 101 | 102 | diagnostics.set(doc.uri, foundDiagnostics) 103 | } 104 | } catch (_) {} 105 | } 106 | 107 | export const subscribeDiagnostics = ( 108 | diagnostics: vscode.DiagnosticCollection, 109 | context: vscode.ExtensionContext, 110 | log: vscode.OutputChannel, 111 | ): void => { 112 | let isRunning = false 113 | let shouldRunAgain = false 114 | 115 | const runDiagnostics = async ( 116 | editor: vscode.TextEditor | vscode.TextDocumentChangeEvent, 117 | ): Promise => { 118 | if (isRunning) { 119 | shouldRunAgain = true 120 | } else { 121 | isRunning = true 122 | 123 | oldHash = `${editor.document.fileName} = ${hash(editor.document.getText())}` 124 | 125 | await refreshDiagnostics(diagnostics, editor.document, log) 126 | 127 | let newHash = `${editor.document.fileName} = ${hash(editor.document.getText())}` 128 | 129 | while (shouldRunAgain || oldHash !== newHash) { 130 | shouldRunAgain = false 131 | oldHash = newHash 132 | 133 | await refreshDiagnostics(diagnostics, editor.document, log) 134 | 135 | newHash = `${editor.document.fileName} = ${hash(editor.document.getText())}` 136 | 137 | if (!shouldRunAgain || oldHash === newHash) { 138 | break 139 | } 140 | } 141 | 142 | await refreshDiagnostics(diagnostics, editor.document, log) 143 | 144 | isRunning = false 145 | } 146 | } 147 | 148 | if (vscode.window.activeTextEditor) { 149 | const editor = vscode.window.activeTextEditor 150 | 151 | runDiagnostics(editor) 152 | } 153 | 154 | context.subscriptions.push( 155 | vscode.window.onDidChangeActiveTextEditor((editor) => { 156 | if (editor && /\.pde/u.test(editor.document.fileName)) { 157 | runDiagnostics(editor) 158 | } 159 | }), 160 | ) 161 | 162 | context.subscriptions.push( 163 | vscode.workspace.onDidChangeTextDocument((editor) => { 164 | if (/\.pde/u.test(editor.document.fileName)) { 165 | if (editor.contentChanges.length > 0) { 166 | runDiagnostics(editor) 167 | } 168 | } 169 | }), 170 | ) 171 | 172 | context.subscriptions.push( 173 | vscode.workspace.onDidCloseTextDocument((doc) => diagnostics.delete(doc.uri)), 174 | ) 175 | } 176 | 177 | export default subscribeDiagnostics 178 | -------------------------------------------------------------------------------- /src/documentation-data.yml: -------------------------------------------------------------------------------- 1 | ../data/documentation-data.yml -------------------------------------------------------------------------------- /src/documentation.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @copyright (C) 2021 Luke Zhang 5 | */ 6 | 7 | import type { 8 | Documentation, 9 | DocumentationClass, 10 | DocumentationFunction, 11 | DocumentationVariable, 12 | } from "./types" 13 | import documentation from "./documentation-data.yml" 14 | import vscode from "vscode" 15 | 16 | /** 17 | * Gets the hovered "thing" and returns it 18 | * 19 | * @param line - Contents of line 20 | * @param position - Position of hover 21 | */ 22 | const getHoveredItem = (line: string, position: number): string | undefined => { 23 | if (/\/\//u.test(line.slice(0, position))) { 24 | return 25 | } 26 | 27 | const itemStart = (() => { 28 | let index = position 29 | 30 | for (; index >= 0 && index < line.length; index--) { 31 | if (!/[a-z]|[0-9]|_/iu.test(line[index]!)) { 32 | break 33 | } 34 | } 35 | 36 | return index + 1 37 | })() 38 | 39 | const itemEnd = (() => { 40 | let index = position 41 | 42 | for (; index >= 0 && index < line.length; index++) { 43 | if (!/[a-z]|[0-9]|_/iu.test(line[index]!)) { 44 | break 45 | } 46 | } 47 | 48 | return index 49 | })() 50 | 51 | return line.slice(itemStart, itemEnd) 52 | } 53 | 54 | const documentVariable = ( 55 | info: DocumentationVariable, 56 | item: keyof typeof documentation, 57 | ): vscode.Hover => 58 | new vscode.Hover([ 59 | info.examples 60 | ? `\`\`\`js 61 | ${info.type} ${item} 62 | \`\`\` 63 | \`\`\`java 64 | // Examples 65 | ${info.examples} 66 | \`\`\`` 67 | : `\`\`\`js 68 | ${info.type} ${item} 69 | \`\`\``, 70 | `${info.examples ? "" : `${item}\n\n`}${info.description} 71 | 72 | *@see* — [${info.docUrl}](${info.docUrl}) 73 | `, 74 | ]) 75 | 76 | const documentFuntion = ( 77 | info: DocumentationFunction, 78 | item: keyof typeof documentation, 79 | ): vscode.Hover => { 80 | const params = Object.entries(info.parameters).map(([name, desc]) => { 81 | const typeDefs = desc.indexOf(":") 82 | 83 | if (typeDefs === -1) { 84 | return `*@param* \`${name}\` — ${desc}` 85 | } 86 | 87 | const formattedDesc = `\`${desc.slice(0, typeDefs)}\`${desc.slice(typeDefs)}` 88 | 89 | return `*@param* \`${name}\` — ${formattedDesc}` 90 | }) 91 | const {returns} = info 92 | 93 | // Prepare yourself 94 | return new vscode.Hover([ 95 | ...(info.syntax 96 | ? [ 97 | `\`\`\`js 98 | ${info.type} ${item} 99 | \`\`\` 100 | \`\`\`java 101 | ${info.syntax} 102 | \`\`\``, 103 | ] 104 | : []), 105 | `${info.syntax ? "" : `${item}\n\n`}${info.description} 106 | 107 | *@see* — [${info.docUrl}](${info.docUrl}) 108 | 109 | ${params.join("\n\n")} 110 | 111 | ${returns ? `*@returns* \`${returns}\`` : ""} 112 | `, 113 | ]) 114 | } 115 | 116 | const documentClass = ( 117 | info: DocumentationClass, 118 | item: keyof typeof documentation, 119 | ): vscode.Hover => { 120 | const params = Object.entries(info.parameters).map(([name, desc]) => { 121 | const typeDefs = desc.indexOf(":") 122 | 123 | if (typeDefs === -1) { 124 | return `*@param* \`${name}\` — ${desc}` 125 | } 126 | 127 | const formattedDesc = `\`${desc.slice(0, typeDefs)}\`${desc.slice(typeDefs)}` 128 | 129 | return `*@param* \`${name}\` — ${formattedDesc}` 130 | }) 131 | 132 | // Prepare yourself 133 | return new vscode.Hover([ 134 | ...(info.syntax 135 | ? [ 136 | `\`\`\`js 137 | ${info.type} ${item} 138 | \`\`\` 139 | \`\`\`java 140 | ${info.syntax} 141 | \`\`\``, 142 | ] 143 | : []), 144 | `${info.syntax ? "" : `${item}\n\n`}${info.description} 145 | 146 | *@see* — [${info.docUrl}](${info.docUrl}) 147 | 148 | ${params.join("\n\n")} 149 | `, 150 | ]) 151 | } 152 | 153 | vscode.languages.registerHoverProvider( 154 | {scheme: "file", language: "pde"}, 155 | { 156 | provideHover: (document, position) => { 157 | const line = document.lineAt(position.line) 158 | const item = getHoveredItem(line.text, position.character) as 159 | | keyof typeof documentation 160 | | undefined 161 | 162 | if (item === undefined) { 163 | return 164 | } 165 | 166 | const info = (documentation as Documentation)[item] 167 | 168 | if (!info) { 169 | return 170 | } else if (info.type === "function") { 171 | return documentFuntion(info, item) 172 | } else if (info.type === "class") { 173 | return documentClass(info, item) 174 | } 175 | 176 | // Not a function or class, therefore a variable 177 | return documentVariable(info, item) 178 | }, 179 | }, 180 | ) 181 | -------------------------------------------------------------------------------- /src/env.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.yml" { 2 | const content: {[key: string]: unknown} 3 | 4 | export default content 5 | } 6 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @version 2.4.1 5 | * @copyright (C) 2016 - 2020 Tobiah Zarlez, 2021 Luke Zhang 6 | */ 7 | 8 | import {processingCommand, shouldEnableDiagnostics} from "./config" 9 | import isValidProcessingCommand from "./validateCommand" 10 | import subscribeCommands from "./commands" 11 | import subscribeDiagnostics from "./diagnostics" 12 | import vscode from "vscode" 13 | 14 | export const activate = async (context: vscode.ExtensionContext) => { 15 | const log = vscode.window.createOutputChannel("Processing") 16 | 17 | log.appendLine("Activating Processing language extension...") 18 | 19 | subscribeCommands(context) 20 | 21 | if (shouldEnableDiagnostics) { 22 | if (await isValidProcessingCommand(processingCommand)) { 23 | const pdeDiagnostics = vscode.languages.createDiagnosticCollection("processing") 24 | 25 | context.subscriptions.push(pdeDiagnostics) 26 | subscribeDiagnostics(pdeDiagnostics, context, log) 27 | } else { 28 | log.appendLine( 29 | `ERROR! The configured processing command ${processingCommand} could not be executed.`, 30 | ) 31 | log.show() 32 | } 33 | } 34 | 35 | await import("./documentation") 36 | 37 | log.appendLine("Processing language extension is now active!") 38 | } 39 | 40 | // this method is called when your extension is deactivated 41 | export const deactivate = () => {} 42 | -------------------------------------------------------------------------------- /src/types.d.ts: -------------------------------------------------------------------------------- 1 | export interface DocumentationClass { 2 | description: string 3 | syntax: string 4 | parameters: {[key: string]: string} 5 | docUrl: string 6 | type: "class" 7 | } 8 | 9 | export interface DocumentationFunction { 10 | description: string 11 | syntax: string 12 | parameters: {[key: string]: string} 13 | returns: string 14 | docUrl: string 15 | type: "function" 16 | } 17 | 18 | export interface DocumentationVariable { 19 | description: string 20 | examples?: string 21 | docUrl: string 22 | type: "var" | "const" 23 | } 24 | 25 | export type Documentation = { 26 | [key: string]: DocumentationFunction | DocumentationVariable | DocumentationClass 27 | } 28 | -------------------------------------------------------------------------------- /src/utils/escapePath.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @copyright (C) 2021 Luke Zhang 5 | */ 6 | 7 | export const escapeExecutablePath = (pathName: string): string => { 8 | if (!/ /gu.test(pathName)) { 9 | return pathName 10 | } 11 | 12 | let isWindowsPath = /[a-zA-Z]:[\\/](?:[a-zA-Z0-9]+[\\/])*([a-zA-Z0-9]+)/gu.test(pathName) 13 | 14 | if (!/[\\/]/gu.test(pathName)) { 15 | isWindowsPath = process.platform === "win32" 16 | } 17 | 18 | if (isWindowsPath) { 19 | // Windows path 20 | return pathName.replace(/(? 11 | path !== undefined && /^[/_$a-z][/\w$]*$/iu.test(path) 12 | -------------------------------------------------------------------------------- /src/utils/search.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @copyright (C) 2016 - 2020 Tobiah Zarlez, 2021 Luke Zhang 5 | */ 6 | 7 | import type {Documentation} from "../types" 8 | import documentation from "../documentation-data.yml" 9 | import {searchConfig} from "../config" 10 | import vscode from "vscode" 11 | 12 | const enum Urls { 13 | ProcessingorgDocs = "https://processing.org/reference/", 14 | ProcessingorgSearchGoogle = "https://www.google.com/search?as_sitesearch=processing.org&as_q=", 15 | ProcessingorgSearchDuckDuckGo = "https://duckduckgo.com/?q=!processing+%5C", 16 | P5jsDocs = "https://p5js.org/reference/", 17 | P5jsSearchGoogle = "https://www.google.com/search?as_sitesearch=p5js.org&as_q=", 18 | P5jsSearchDuckDuckGo = "https://duckduckgo.com/?q=!p5+", 19 | PyDocs = "https://py.processing.org/reference/", 20 | PySearchGoogle = "https://www.google.com/search?as_sitesearch=py.processing.org&as_q=", 21 | PySearchDuckDuckGo = "https://duckduckgo.com/?q=%5Csite%3Apy.processing.org+", 22 | } 23 | 24 | export const openURL = async (searchBase?: string, url?: string): Promise => { 25 | if (searchBase === "open") { 26 | await vscode.env.openExternal(vscode.Uri.parse(url as string)) 27 | } else { 28 | const {processingDocs, searchEngine} = searchConfig 29 | const searchUrl = ((): string => { 30 | let directDocUrl: string | undefined 31 | 32 | if (searchBase === "docs") { 33 | const { 34 | window: {activeTextEditor}, 35 | } = vscode 36 | const languageId = activeTextEditor?.document.languageId 37 | 38 | if (!url) { 39 | if (processingDocs === "p5js.org") { 40 | return Urls.P5jsDocs 41 | } else if ( 42 | (processingDocs === "auto" && languageId === "pyton") || 43 | processingDocs === "py.processing.org" 44 | ) { 45 | return Urls.PyDocs 46 | } 47 | 48 | // (processingDocs === "auto" && languageId === "pde") 49 | // || processingDocs === "processing.org" 50 | return Urls.ProcessingorgDocs 51 | } else if ( 52 | // Look for entry directly in documentation data 53 | (processingDocs === "auto" || processingDocs === "processing.org") && 54 | languageId === "pde" && 55 | (directDocUrl = (documentation as Documentation)[url]?.docUrl) !== undefined 56 | ) { 57 | return directDocUrl 58 | } else if (searchEngine === "DuckDuckGo") { 59 | // Search Engine == "google" 60 | if (processingDocs === "p5js.org") { 61 | return `${Urls.P5jsSearchDuckDuckGo}${url}` 62 | } else if ( 63 | (processingDocs === "auto" && languageId === "pyton") || 64 | processingDocs === "py.processing.org" 65 | ) { 66 | return `${Urls.PySearchDuckDuckGo}${url}` 67 | } 68 | 69 | // (processingDocs === "auto" && languageId === "pde") 70 | // || processingDocs === "processing.org" 71 | return `${Urls.ProcessingorgSearchDuckDuckGo}${url}` 72 | } 73 | 74 | // Search Engine == "google" 75 | if (processingDocs === "p5js.org") { 76 | return `${Urls.P5jsSearchGoogle}${url}` 77 | } else if ( 78 | (processingDocs === "auto" && languageId === "pyton") || 79 | processingDocs === "py.processing.org" 80 | ) { 81 | return `${Urls.PySearchGoogle}${url}` 82 | } 83 | 84 | // (processingDocs === "auto" && languageId === "pde") 85 | // || processingDocs === "processing.org" 86 | return `${Urls.ProcessingorgSearchGoogle}${url}` 87 | } 88 | 89 | return searchBase ?? "" 90 | })() 91 | 92 | await vscode.env.openExternal(vscode.Uri.parse(searchUrl)) 93 | } 94 | 95 | return 96 | } 97 | 98 | // Slice and Trim 99 | export const prepareInput = (input: string, start: number, end: number) => { 100 | // input is the whole line, part of which is selected by the user (defined by star/end) 101 | 102 | if (start >= end) { 103 | return "" 104 | } 105 | 106 | // Everything looks good by this point, so time to open a web browser! 107 | return input.slice(start, end).trim() 108 | } 109 | 110 | export const openProcessingDocs = (input: string, start: number, end: number) => { 111 | // Use the node module "opn" to open a web browser 112 | openURL("docs", prepareInput(input, start, end)) 113 | } 114 | -------------------------------------------------------------------------------- /src/validateCommand.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Processing-vscode - Processing Language Support for VSCode 3 | * 4 | * @copyright (C) 2021 Luke Zhang 5 | */ 6 | import childProcess from "child_process" 7 | 8 | export const isValidProcessingCommand = async (cmd: string): Promise => { 9 | const result = await new Promise((resolve) => { 10 | const processingProcess = childProcess.spawn(cmd, ["--help"]) 11 | 12 | let output = "" 13 | 14 | processingProcess.stderr.on("data", (data) => (output += data.toString())) 15 | processingProcess.stdout.on("data", (data) => (output += data.toString())) 16 | 17 | processingProcess.on("exit", () => { 18 | resolve(output.trim()) 19 | }) 20 | 21 | processingProcess.on("error", () => resolve(false)) 22 | }) 23 | 24 | return typeof result === "boolean" 25 | ? result 26 | : /Command line edition for Processing/u.test(result) 27 | } 28 | 29 | export default isValidProcessingCommand 30 | -------------------------------------------------------------------------------- /syntaxes/pde.tmLanguage.json: -------------------------------------------------------------------------------- 1 | { 2 | "information_for_contributors": [ 3 | "This file has is based off https://github.com/microsoft/vscode/blob/main/extensions/java/syntaxes/java.tmLanguage.json" 4 | ], 5 | "scopeName": "source.pde", 6 | "uuid": "fa3cf963-f9b4-4e28-949d-af2b8d279f97", 7 | "name": "Processing", 8 | "fileTypes": ["pde", "bsh"], 9 | "patterns": [ 10 | { 11 | "begin": "\\b(package)\\b\\s*", 12 | "beginCaptures": { 13 | "1": { 14 | "name": "keyword.other.package.processing" 15 | } 16 | }, 17 | "end": "\\s*(;)", 18 | "endCaptures": { 19 | "1": { 20 | "name": "punctuation.terminator.processing" 21 | } 22 | }, 23 | "name": "meta.package.processing", 24 | "contentName": "storage.modifier.package.processing", 25 | "patterns": [ 26 | { 27 | "include": "#comments" 28 | }, 29 | { 30 | "match": "(?<=\\.)\\s*\\.|\\.(?=\\s*;)", 31 | "name": "invalid.illegal.character_not_allowed_here.processing" 32 | }, 33 | { 34 | "match": "(?", 859 | "endCaptures": { 860 | "0": { 861 | "name": "punctuation.bracket.angle.processing" 862 | } 863 | }, 864 | "patterns": [ 865 | { 866 | "match": "\\b(extends|super)\\b", 867 | "name": "storage.modifier.$1.processing" 868 | }, 869 | { 870 | "match": "(?>>?|~|\\^)", 931 | "name": "keyword.operator.bitwise.processing" 932 | }, 933 | { 934 | "match": "((&|\\^|\\||<<|>>>?)=)", 935 | "name": "keyword.operator.assignment.bitwise.processing" 936 | }, 937 | { 938 | "match": "(===?|!=|<=|>=|<>|<|>)", 939 | "name": "keyword.operator.comparison.processing" 940 | }, 941 | { 942 | "match": "([+*/%-]=)", 943 | "name": "keyword.operator.assignment.arithmetic.processing" 944 | }, 945 | { 946 | "match": "(=)", 947 | "name": "keyword.operator.assignment.processing" 948 | }, 949 | { 950 | "match": "(\\-\\-|\\+\\+)", 951 | "name": "keyword.operator.increment-decrement.processing" 952 | }, 953 | { 954 | "match": "(\\-|\\+|\\*|\\/|%)", 955 | "name": "keyword.operator.arithmetic.processing" 956 | }, 957 | { 958 | "match": "(!|&&|\\|\\|)", 959 | "name": "keyword.operator.logical.processing" 960 | }, 961 | { 962 | "match": "(\\||&)", 963 | "name": "keyword.operator.bitwise.processing" 964 | }, 965 | { 966 | "match": "\\b(const|goto)\\b", 967 | "name": "keyword.reserved.processing" 968 | }, 969 | { 970 | "match": "\\b(Array|Character|FloatDict|FloatList|IntDict|IntList|Integer|JSONArray|JSONObject|Math|Object|PFont|PGraphics|PImage|PShader|PShape|PSound|PVector|String|StringBuffer|StringDict|StringList|Table|TableRow|Thread|XML|Byte|Short|Long|Float|Double|Boolean|System)\\b", 971 | "name": "support.class.processing" 972 | }, 973 | { 974 | "match": "\\b(ADD|ALIGN_CENTER|ALIGN_LEFT|ALIGN_RIGHT|ALPHA|ALPHA_MASK|ALT|AMBIENT|ARGB|ARROW|BACKSPACE|BEVEL|BLEND|BLUE_MASK|BLUR|CENTER|CENTER_RADIUS|CHATTER|CODED|COMPLAINT|COMPONENT|COMPOSITE|CONCAVE_POLYGON|CONTROL|CONVEX_POLYGON|CORNER|CORNERS|CROSS|CUSTOM|DARKEST|DEGREES|DEG_TO_RAD|DELETE|DIFFERENCE|DIFFUSE|DISABLED|DISABLE_TEXT_SMOOTH|DOWN|ENTER|EPSILON|ESC|FX2D|GIF|GREEN_MASK|GREY|HALF|HALF_PI|HAND|HARD_LIGHT|HSB|IMAGE|INVERT|JAVA2D|JPEG|LEFT|LIGHTEST|LINES|LINE_LOOP|LINE_STRIP|MAX_FLOAT|MITER|MODEL|MOVE|MULTIPLY|NORMALIZED|NO_DEPTH_TEST|NTSC|ONE|OPAQUE|OPENGL|ORTHOGRAPHIC|OVERLAY|P2D|P3D|PAL|PDF|PERSPECTIVE|PI|PIXEL_CENTER|POINTS|POLYGON|POSTERIZE|PROBLEM|PROJECT|QUADS|QUAD_STRIP|QUARTER_PI|RADIANS|RAD_TO_DEG|RED_MASK|REPLACE|RETURN|RGB|RIGHT|ROUND|SCREEN|SECAM|SHIFT|SOFT_LIGHT|SPAN|SPECULAR|SQUARE|SUBTRACT|SVIDEO|TAB|TARGA|TEXT|TFF|THIRD_PI|THRESHOLD|TIFF|TRIANGLES|TRIANGLE_FAN|TRIANGLE_STRIP|TUNER|TAU|TWO|TWO_PI|UP|WAIT|WHITESPACE)\\b", 975 | "name": "constant.language.processing" 976 | } 977 | ] 978 | }, 979 | "lambda-expression": { 980 | "patterns": [ 981 | { 982 | "match": "->", 983 | "name": "storage.type.function.arrow.processing" 984 | } 985 | ] 986 | }, 987 | "member-variables": { 988 | "begin": "(?=private|protected|public|native|synchronized|abstract|threadsafe|transient|static|final)", 989 | "end": "(?=\\=|;)", 990 | "patterns": [ 991 | { 992 | "include": "#storage-modifiers" 993 | }, 994 | { 995 | "include": "#variables" 996 | }, 997 | { 998 | "include": "#primitive-arrays" 999 | }, 1000 | { 1001 | "include": "#object-types" 1002 | } 1003 | ] 1004 | }, 1005 | "method-call": { 1006 | "begin": "(\\.)\\s*([A-Za-z_$][\\w$]*)\\s*(\\()", 1007 | "beginCaptures": { 1008 | "1": { 1009 | "name": "punctuation.separator.period.processing" 1010 | }, 1011 | "2": { 1012 | "name": "entity.name.function.processing" 1013 | }, 1014 | "3": { 1015 | "name": "punctuation.definition.parameters.begin.bracket.round.processing" 1016 | } 1017 | }, 1018 | "end": "\\)", 1019 | "endCaptures": { 1020 | "0": { 1021 | "name": "punctuation.definition.parameters.end.bracket.round.processing" 1022 | } 1023 | }, 1024 | "name": "meta.method-call.processing", 1025 | "patterns": [ 1026 | { 1027 | "include": "#code" 1028 | } 1029 | ] 1030 | }, 1031 | "methods": { 1032 | "begin": "(?!new)(?=[\\w<].*\\s+)(?=([^=/]|/(?!/))+\\()", 1033 | "end": "(})|(?=;)", 1034 | "endCaptures": { 1035 | "1": { 1036 | "name": "punctuation.section.method.end.bracket.curly.processing" 1037 | } 1038 | }, 1039 | "name": "meta.method.processing", 1040 | "patterns": [ 1041 | { 1042 | "include": "#storage-modifiers" 1043 | }, 1044 | { 1045 | "begin": "(\\w+)\\s*(\\()", 1046 | "beginCaptures": { 1047 | "1": { 1048 | "name": "entity.name.function.processing" 1049 | }, 1050 | "2": { 1051 | "name": "punctuation.definition.parameters.begin.bracket.round.processing" 1052 | } 1053 | }, 1054 | "end": "\\)", 1055 | "endCaptures": { 1056 | "0": { 1057 | "name": "punctuation.definition.parameters.end.bracket.round.processing" 1058 | } 1059 | }, 1060 | "name": "meta.method.identifier.processing", 1061 | "patterns": [ 1062 | { 1063 | "include": "#parameters" 1064 | }, 1065 | { 1066 | "include": "#parens" 1067 | }, 1068 | { 1069 | "include": "#comments" 1070 | } 1071 | ] 1072 | }, 1073 | { 1074 | "include": "#generics" 1075 | }, 1076 | { 1077 | "begin": "(?=\\w.*\\s+\\w+\\s*\\()", 1078 | "end": "(?=\\s+\\w+\\s*\\()", 1079 | "name": "meta.method.return-type.processing", 1080 | "patterns": [ 1081 | { 1082 | "include": "#all-types" 1083 | }, 1084 | { 1085 | "include": "#parens" 1086 | }, 1087 | { 1088 | "include": "#comments" 1089 | } 1090 | ] 1091 | }, 1092 | { 1093 | "include": "#throws" 1094 | }, 1095 | { 1096 | "begin": "{", 1097 | "beginCaptures": { 1098 | "0": { 1099 | "name": "punctuation.section.method.begin.bracket.curly.processing" 1100 | } 1101 | }, 1102 | "end": "(?=})", 1103 | "contentName": "meta.method.body.processing", 1104 | "patterns": [ 1105 | { 1106 | "include": "#code" 1107 | } 1108 | ] 1109 | }, 1110 | { 1111 | "include": "#comments" 1112 | } 1113 | ] 1114 | }, 1115 | "module": { 1116 | "begin": "((open)\\s)?(module)\\s+(\\w+)", 1117 | "end": "}", 1118 | "beginCaptures": { 1119 | "1": { 1120 | "name": "storage.modifier.processing" 1121 | }, 1122 | "3": { 1123 | "name": "storage.modifier.processing" 1124 | }, 1125 | "4": { 1126 | "name": "entity.name.type.module.processing" 1127 | } 1128 | }, 1129 | "endCaptures": { 1130 | "0": { 1131 | "name": "punctuation.section.module.end.bracket.curly.processing" 1132 | } 1133 | }, 1134 | "name": "meta.module.processing", 1135 | "patterns": [ 1136 | { 1137 | "begin": "{", 1138 | "beginCaptures": { 1139 | "0": { 1140 | "name": "punctuation.section.module.begin.bracket.curly.processing" 1141 | } 1142 | }, 1143 | "end": "(?=})", 1144 | "contentName": "meta.module.body.processing", 1145 | "patterns": [ 1146 | { 1147 | "match": "\\b(requires|transitive|exports|opens|to|uses|provides|with)\\b", 1148 | "name": "keyword.module.processing" 1149 | } 1150 | ] 1151 | } 1152 | ] 1153 | }, 1154 | "numbers": { 1155 | "patterns": [ 1156 | { 1157 | "match": "(?x)\n\\b(?)?(\\()", 1444 | "beginCaptures": { 1445 | "1": { 1446 | "name": "storage.modifier.processing" 1447 | }, 1448 | "2": { 1449 | "name": "entity.name.type.record.processing" 1450 | }, 1451 | "3": { 1452 | "patterns": [ 1453 | { 1454 | "include": "#generics" 1455 | } 1456 | ] 1457 | }, 1458 | "4": { 1459 | "name": "punctuation.definition.parameters.begin.bracket.round.processing" 1460 | } 1461 | }, 1462 | "end": "\\)", 1463 | "endCaptures": { 1464 | "0": { 1465 | "name": "punctuation.definition.parameters.end.bracket.round.processing" 1466 | } 1467 | }, 1468 | "name": "meta.record.identifier.processing", 1469 | "patterns": [ 1470 | { 1471 | "include": "#code" 1472 | } 1473 | ] 1474 | }, 1475 | { 1476 | "begin": "(implements)\\s", 1477 | "beginCaptures": { 1478 | "1": { 1479 | "name": "storage.modifier.implements.processing" 1480 | } 1481 | }, 1482 | "end": "(?=\\s*\\{)", 1483 | "name": "meta.definition.class.implemented.interfaces.processing", 1484 | "patterns": [ 1485 | { 1486 | "include": "#object-types-inherited" 1487 | }, 1488 | { 1489 | "include": "#comments" 1490 | } 1491 | ] 1492 | }, 1493 | { 1494 | "include": "#record-body" 1495 | } 1496 | ] 1497 | }, 1498 | "record-body": { 1499 | "begin": "{", 1500 | "beginCaptures": { 1501 | "0": { 1502 | "name": "punctuation.section.class.begin.bracket.curly.processing" 1503 | } 1504 | }, 1505 | "end": "(?=})", 1506 | "name": "meta.record.body.processing", 1507 | "patterns": [ 1508 | { 1509 | "include": "#record-constructor" 1510 | }, 1511 | { 1512 | "include": "#class-body" 1513 | } 1514 | ] 1515 | }, 1516 | "record-constructor": { 1517 | "begin": "(?!new)(?=[\\w<].*\\s+)(?=([^\\(=/]|/(?!/))+(?={))", 1518 | "end": "(})|(?=;)", 1519 | "endCaptures": { 1520 | "1": { 1521 | "name": "punctuation.section.method.end.bracket.curly.processing" 1522 | } 1523 | }, 1524 | "name": "meta.method.processing", 1525 | "patterns": [ 1526 | { 1527 | "include": "#storage-modifiers" 1528 | }, 1529 | { 1530 | "begin": "(\\w+)", 1531 | "beginCaptures": { 1532 | "1": { 1533 | "name": "entity.name.function.processing" 1534 | } 1535 | }, 1536 | "end": "(?=\\s*{)", 1537 | "name": "meta.method.identifier.processing", 1538 | "patterns": [ 1539 | { 1540 | "include": "#comments" 1541 | } 1542 | ] 1543 | }, 1544 | { 1545 | "include": "#comments" 1546 | }, 1547 | { 1548 | "begin": "{", 1549 | "beginCaptures": { 1550 | "0": { 1551 | "name": "punctuation.section.method.begin.bracket.curly.processing" 1552 | } 1553 | }, 1554 | "end": "(?=})", 1555 | "contentName": "meta.method.body.processing", 1556 | "patterns": [ 1557 | { 1558 | "include": "#code" 1559 | } 1560 | ] 1561 | } 1562 | ] 1563 | }, 1564 | "static-initializer": { 1565 | "patterns": [ 1566 | { 1567 | "include": "#anonymous-block-and-instance-initializer" 1568 | }, 1569 | { 1570 | "match": "static", 1571 | "name": "storage.modifier.processing" 1572 | } 1573 | ] 1574 | }, 1575 | "storage-modifiers": { 1576 | "match": "\\b(public|private|protected|static|final|native|synchronized|abstract|threadsafe|transient|volatile|default|strictfp|sealed|non-sealed)\\b", 1577 | "name": "storage.modifier.processing" 1578 | }, 1579 | "strings": { 1580 | "patterns": [ 1581 | { 1582 | "begin": "\"", 1583 | "beginCaptures": { 1584 | "0": { 1585 | "name": "punctuation.definition.string.begin.processing" 1586 | } 1587 | }, 1588 | "end": "\"", 1589 | "endCaptures": { 1590 | "0": { 1591 | "name": "punctuation.definition.string.end.processing" 1592 | } 1593 | }, 1594 | "name": "string.quoted.double.processing", 1595 | "patterns": [ 1596 | { 1597 | "match": "\\\\.", 1598 | "name": "constant.character.escape.processing" 1599 | } 1600 | ] 1601 | }, 1602 | { 1603 | "begin": "'", 1604 | "beginCaptures": { 1605 | "0": { 1606 | "name": "punctuation.definition.string.begin.processing" 1607 | } 1608 | }, 1609 | "end": "'", 1610 | "endCaptures": { 1611 | "0": { 1612 | "name": "punctuation.definition.string.end.processing" 1613 | } 1614 | }, 1615 | "name": "string.quoted.single.processing", 1616 | "patterns": [ 1617 | { 1618 | "match": "\\\\.", 1619 | "name": "constant.character.escape.processing" 1620 | } 1621 | ] 1622 | } 1623 | ] 1624 | }, 1625 | "throws": { 1626 | "begin": "throws", 1627 | "beginCaptures": { 1628 | "0": { 1629 | "name": "storage.modifier.processing" 1630 | } 1631 | }, 1632 | "end": "(?={|;)", 1633 | "name": "meta.throwables.processing", 1634 | "patterns": [ 1635 | { 1636 | "match": ",", 1637 | "name": "punctuation.separator.delimiter.processing" 1638 | }, 1639 | { 1640 | "match": "[a-zA-Z$_][\\.a-zA-Z0-9$_]*", 1641 | "name": "storage.type.processing" 1642 | } 1643 | ] 1644 | }, 1645 | "try-catch-finally": { 1646 | "patterns": [ 1647 | { 1648 | "begin": "\\btry\\b", 1649 | "beginCaptures": { 1650 | "0": { 1651 | "name": "keyword.control.try.processing" 1652 | } 1653 | }, 1654 | "end": "}", 1655 | "endCaptures": { 1656 | "0": { 1657 | "name": "punctuation.section.try.end.bracket.curly.processing" 1658 | } 1659 | }, 1660 | "name": "meta.try.processing", 1661 | "patterns": [ 1662 | { 1663 | "begin": "\\(", 1664 | "beginCaptures": { 1665 | "0": { 1666 | "name": "punctuation.section.try.resources.begin.bracket.round.processing" 1667 | } 1668 | }, 1669 | "end": "\\)", 1670 | "endCaptures": { 1671 | "0": { 1672 | "name": "punctuation.section.try.resources.end.bracket.round.processing" 1673 | } 1674 | }, 1675 | "name": "meta.try.resources.processing", 1676 | "patterns": [ 1677 | { 1678 | "include": "#code" 1679 | } 1680 | ] 1681 | }, 1682 | { 1683 | "begin": "{", 1684 | "beginCaptures": { 1685 | "0": { 1686 | "name": "punctuation.section.try.begin.bracket.curly.processing" 1687 | } 1688 | }, 1689 | "end": "(?=})", 1690 | "contentName": "meta.try.body.processing", 1691 | "patterns": [ 1692 | { 1693 | "include": "#code" 1694 | } 1695 | ] 1696 | } 1697 | ] 1698 | }, 1699 | { 1700 | "begin": "\\b(catch)\\b", 1701 | "beginCaptures": { 1702 | "1": { 1703 | "name": "keyword.control.catch.processing" 1704 | } 1705 | }, 1706 | "end": "}", 1707 | "endCaptures": { 1708 | "0": { 1709 | "name": "punctuation.section.catch.end.bracket.curly.processing" 1710 | } 1711 | }, 1712 | "name": "meta.catch.processing", 1713 | "patterns": [ 1714 | { 1715 | "include": "#comments" 1716 | }, 1717 | { 1718 | "begin": "\\(", 1719 | "beginCaptures": { 1720 | "0": { 1721 | "name": "punctuation.definition.parameters.begin.bracket.round.processing" 1722 | } 1723 | }, 1724 | "end": "\\)", 1725 | "endCaptures": { 1726 | "0": { 1727 | "name": "punctuation.definition.parameters.end.bracket.round.processing" 1728 | } 1729 | }, 1730 | "contentName": "meta.catch.parameters.processing", 1731 | "patterns": [ 1732 | { 1733 | "include": "#comments" 1734 | }, 1735 | { 1736 | "include": "#storage-modifiers" 1737 | }, 1738 | { 1739 | "begin": "[a-zA-Z$_][\\.a-zA-Z0-9$_]*", 1740 | "beginCaptures": { 1741 | "0": { 1742 | "name": "storage.type.processing" 1743 | } 1744 | }, 1745 | "end": "(\\|)|(?=\\))", 1746 | "endCaptures": { 1747 | "1": { 1748 | "name": "punctuation.catch.separator.processing" 1749 | } 1750 | }, 1751 | "patterns": [ 1752 | { 1753 | "include": "#comments" 1754 | }, 1755 | { 1756 | "match": "\\w+", 1757 | "captures": { 1758 | "0": { 1759 | "name": "variable.parameter.processing" 1760 | } 1761 | } 1762 | } 1763 | ] 1764 | } 1765 | ] 1766 | }, 1767 | { 1768 | "begin": "{", 1769 | "beginCaptures": { 1770 | "0": { 1771 | "name": "punctuation.section.catch.begin.bracket.curly.processing" 1772 | } 1773 | }, 1774 | "end": "(?=})", 1775 | "contentName": "meta.catch.body.processing", 1776 | "patterns": [ 1777 | { 1778 | "include": "#code" 1779 | } 1780 | ] 1781 | } 1782 | ] 1783 | }, 1784 | { 1785 | "begin": "\\bfinally\\b", 1786 | "beginCaptures": { 1787 | "0": { 1788 | "name": "keyword.control.finally.processing" 1789 | } 1790 | }, 1791 | "end": "}", 1792 | "endCaptures": { 1793 | "0": { 1794 | "name": "punctuation.section.finally.end.bracket.curly.processing" 1795 | } 1796 | }, 1797 | "name": "meta.finally.processing", 1798 | "patterns": [ 1799 | { 1800 | "begin": "{", 1801 | "beginCaptures": { 1802 | "0": { 1803 | "name": "punctuation.section.finally.begin.bracket.curly.processing" 1804 | } 1805 | }, 1806 | "end": "(?=})", 1807 | "contentName": "meta.finally.body.processing", 1808 | "patterns": [ 1809 | { 1810 | "include": "#code" 1811 | } 1812 | ] 1813 | } 1814 | ] 1815 | } 1816 | ] 1817 | }, 1818 | "simple-types": { 1819 | "patterns": [ 1820 | { 1821 | "match": "\\b(?:void|boolean|byte|char|short|int|float|long|double|color|String|PVector)\\b", 1822 | "name": "storage.type.simple.processing" 1823 | } 1824 | ] 1825 | }, 1826 | "variables-local": { 1827 | "begin": "(?=\\b(var)\\b\\s+[A-Za-z_$][\\w$]*\\s*(=|:|;))", 1828 | "end": "(?=\\=|:|;)", 1829 | "name": "meta.definition.variable.local.processing", 1830 | "patterns": [ 1831 | { 1832 | "match": "\\bvar\\b", 1833 | "name": "storage.type.local.processing" 1834 | }, 1835 | { 1836 | "match": "([A-Za-z$_][\\w$]*)(?=\\s*(\\[\\])*\\s*(=|:|;))", 1837 | "captures": { 1838 | "1": { 1839 | "name": "variable.other.definition.processing" 1840 | } 1841 | } 1842 | }, 1843 | { 1844 | "include": "#code" 1845 | } 1846 | ] 1847 | } 1848 | } 1849 | } 1850 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "ES2019", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "ESNext", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | "allowJs": true, /* Allow javascript files to be compiled. */ 11 | "checkJs": false, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | "declaration": false, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | // "outDir": "./lib", /* Redirect output structure to the directory. */ 18 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./tsbuildinfo", /* Specify file to store incremental compilation information */ 21 | "removeComments": false, /* Do not emit comments to output. */ 22 | "noEmit": true, /* Do not emit outputs. */ 23 | "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | "strictNullChecks": true, /* Enable strict null checks. */ 31 | "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | 43 | /* Module Resolution Options */ 44 | "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | // "typeRoots": [], /* List of folders to include type definitions from. */ 49 | // "types": [], /* Type declaration files to be included in compilation. */ 50 | "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 51 | // "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 52 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 53 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 54 | 55 | /* Source Map Options */ 56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 60 | 61 | /* Experimental Options */ 62 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 63 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 64 | 65 | /* Advanced Options */ 66 | "skipLibCheck": false, /* Skip type checking of declaration files. */ 67 | "skipDefaultLibCheck": true, 68 | "forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */ 69 | "resolveJsonModule": true, 70 | "noUncheckedIndexedAccess": true, 71 | }, 72 | "include": [ 73 | "src" 74 | ] 75 | } 76 | --------------------------------------------------------------------------------