├── .prettierignore ├── src ├── webviews │ ├── apps │ │ ├── shared │ │ │ ├── partials │ │ │ │ ├── tail.html │ │ │ │ └── head.html │ │ │ ├── scss │ │ │ │ ├── base.scss │ │ │ │ ├── reset.scss │ │ │ │ └── vscode.scss │ │ │ └── gWebviewApp.ts │ │ ├── .eslintrc.json │ │ ├── tsconfig.json │ │ └── calc │ │ │ ├── calc.scss │ │ │ └── calc.types.ts │ ├── webviewMsg.types.ts │ ├── helpers.ts │ ├── gWebview.ts │ └── gWebviewView.ts ├── views │ ├── providers │ │ └── helpers.ts │ ├── nodes │ │ ├── navTreeNode.ts │ │ ├── statsNode.ts │ │ └── nodes.ts │ └── gView.ts ├── util │ ├── quickpicks │ │ ├── buttons.ts │ │ └── lineNumbers.ts │ ├── commands │ │ ├── showSupportGCode.ts │ │ ├── removeLineNumbers.ts │ │ ├── showGCodeSettings.ts │ │ ├── addLineNumbers.ts │ │ ├── removeComment.ts │ │ ├── base.ts │ │ ├── index.ts │ │ └── addComment.ts │ ├── stateControl.ts │ ├── version.ts │ ├── localStorageService.ts │ ├── configuration │ │ ├── config.ts │ │ └── defaults.ts │ ├── machineTypeController.ts │ ├── messages.ts │ ├── constants.ts │ ├── logger.ts │ └── statusBar.ts ├── extension.ts └── hovers │ ├── gcodeHoverProvider.ts │ └── gcodeHoverControl.ts ├── .eslintignore ├── images ├── logo.png ├── screenshot.png ├── hovers-screenshot.png ├── stats-screenshot.png ├── tree-screenshot.png ├── settings-screenshot.png ├── calculator-screenshot.png ├── statusbar-screenshot.png └── context-menu-screenshot.png ├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── FUNDING.yml ├── workflows │ ├── lock.yml │ ├── stale.yml │ ├── greetings.yml │ └── codeql.yml └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .markdownlint.json ├── .vscode ├── extensions.json ├── tasks.json ├── settings.json └── vscode-gcode-syntax.code-snippets ├── tsconfig.tests.json ├── .editorconfig ├── samplenc ├── sample-mill-metric.nc ├── sample-profile.nc ├── sample-circular-pocket.nc └── sample-colors.nc ├── .prettierrc ├── .vscodeignore ├── resources └── icons │ ├── dark │ ├── stop.svg │ ├── boring.svg │ ├── cutting.svg │ ├── ccwcutting.svg │ ├── heart.svg │ ├── refresh.svg │ ├── cwcutting.svg │ ├── settings.svg │ ├── coolantoff.svg │ ├── localsubprog.svg │ ├── subprogreturn.svg │ ├── spindleccw.svg │ ├── extsubprog.svg │ ├── spindlecw.svg │ ├── dwell.svg │ ├── rapid.svg │ ├── toolchange.svg │ ├── workoffset.svg │ ├── drill.svg │ ├── engraving.svg │ ├── coolanton.svg │ ├── drill-dwell.svg │ ├── tapping-lh.svg │ └── tapping-rh.svg │ └── light │ ├── stop.svg │ ├── boring.svg │ ├── cutting.svg │ ├── ccwcutting.svg │ ├── heart.svg │ ├── refresh.svg │ ├── cwcutting.svg │ ├── settings.svg │ ├── coolantoff.svg │ ├── localsubprog.svg │ ├── subprogreturn.svg │ ├── spindleccw.svg │ ├── extsubprog.svg │ ├── spindlecw.svg │ ├── dwell.svg │ ├── rapid.svg │ ├── toolchange.svg │ ├── workoffset.svg │ ├── drill.svg │ ├── engraving.svg │ ├── coolanton.svg │ ├── drill-dwell.svg │ ├── tapping-lh.svg │ └── tapping-rh.svg ├── snippets ├── general-snippets.json ├── mcode-snippets.json └── gcode-snippets.json ├── SECURITY.md ├── .gitattributes ├── tsconfig.json ├── test ├── e2e │ ├── extension.test.ts │ └── index.ts ├── runTests.ts └── unit │ └── stats.test.ts ├── LICENSE ├── language └── gcode-language.json ├── CONTRIBUTING.md └── .eslintrc.json /.prettierignore: -------------------------------------------------------------------------------- 1 | package*.json -------------------------------------------------------------------------------- /src/webviews/apps/shared/partials/tail.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | out/* 2 | dist/* 3 | tsconfig.tsbuildinfo 4 | webpack.config.js -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appliedengdesign/vscode-gcode-syntax/HEAD/images/logo.png -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appliedengdesign/vscode-gcode-syntax/HEAD/images/screenshot.png -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # These owners will be the default owners for everything in the repo. 2 | * @mikecentola 3 | 4 | -------------------------------------------------------------------------------- /images/hovers-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appliedengdesign/vscode-gcode-syntax/HEAD/images/hovers-screenshot.png -------------------------------------------------------------------------------- /images/stats-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appliedengdesign/vscode-gcode-syntax/HEAD/images/stats-screenshot.png -------------------------------------------------------------------------------- /images/tree-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appliedengdesign/vscode-gcode-syntax/HEAD/images/tree-screenshot.png -------------------------------------------------------------------------------- /images/settings-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appliedengdesign/vscode-gcode-syntax/HEAD/images/settings-screenshot.png -------------------------------------------------------------------------------- /images/calculator-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appliedengdesign/vscode-gcode-syntax/HEAD/images/calculator-screenshot.png -------------------------------------------------------------------------------- /images/statusbar-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appliedengdesign/vscode-gcode-syntax/HEAD/images/statusbar-screenshot.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .eslintcache 2 | .vscode-test/** 3 | *.vsix 4 | dist 5 | images/*.ai 6 | node_modules 7 | out 8 | releases 9 | tsconfig.tsbuildinfo -------------------------------------------------------------------------------- /images/context-menu-screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/appliedengdesign/vscode-gcode-syntax/HEAD/images/context-menu-screenshot.png -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "line-length": false, 4 | "no-inline-html": false, 5 | "first-line-heading": false, 6 | "no-duplicate-heading": false 7 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "amodio.tsl-problem-matcher", 4 | "dbaeumer.vscode-eslint", 5 | "esbenp.prettier-vscode" 6 | ] 7 | } -------------------------------------------------------------------------------- /src/webviews/apps/shared/scss/base.scss: -------------------------------------------------------------------------------- 1 | html { 2 | height: 100%; 3 | font-size: 62.5%; 4 | } 5 | 6 | body { 7 | height: 100%; 8 | line-height: 1.4; 9 | font-size: 100% !important; 10 | } 11 | 12 | a { 13 | border: 0; 14 | } -------------------------------------------------------------------------------- /src/webviews/apps/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "../../../.eslintrc.json" 4 | ], 5 | "env": { 6 | "browser": true 7 | }, 8 | "parserOptions": { 9 | "project": "src/webviews/apps/tsconfig.json" 10 | } 11 | } -------------------------------------------------------------------------------- /tsconfig.tests.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "lib": [ 5 | "ES2021" 6 | ], 7 | "module": "CommonJS", 8 | "outDir": "out", 9 | "tsBuildInfoFile": "tsconfig.tests.tsbuildinfo" 10 | } 11 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ## Suggest a Feature you'd like to see 11 | 12 | **Additional context** 13 | Add any other context or screenshots about the feature request here. 14 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | trim_trailing_whitespace = true 7 | charset = utf-8 8 | indent_size = 4 9 | indent_style = space 10 | max_line_length = 120 11 | 12 | [*.{svg,gif,png,jpg,jpeg}] 13 | insert_final_newline = false 14 | 15 | [*.md] 16 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /src/webviews/apps/shared/partials/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {toolkit} 11 | 12 | {title} 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/webviews/apps/shared/scss/reset.scss: -------------------------------------------------------------------------------- 1 | html { 2 | box-sizing: border-box; 3 | font-size: 13px; 4 | } 5 | 6 | *, 7 | *:before, 8 | *:after { 9 | box-sizing: inherit; 10 | } 11 | 12 | body, 13 | h1, 14 | h2, 15 | h3, 16 | h4, 17 | h5, 18 | h6, 19 | p, 20 | ol, 21 | ul { 22 | margin: 0; 23 | padding: 0; 24 | font-weight: normal; 25 | } 26 | 27 | img { 28 | max-width: 100%; 29 | height: auto; 30 | } -------------------------------------------------------------------------------- /samplenc/sample-mill-metric.nc: -------------------------------------------------------------------------------- 1 | O1000 2 | T1 M6 3 | (Linear / Feed - Absolute) 4 | G0 G90 G40 G21 G17 G94 G80 5 | G54 X-75 Y-75 S500 M3 (Position 6) 6 | G43 Z100 H1 7 | Z5 8 | G1 Z-20 F100 9 | X-40 (Position 1) 10 | Y40 M8 (Position 2) 11 | X40 (Position 3) 12 | Y-40 (Position 4) 13 | X-75 (Position 5) 14 | Y-75 (Position 6) 15 | G0 Z100 16 | M30 -------------------------------------------------------------------------------- /src/webviews/apps/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "lib": [ 5 | "dom", 6 | "dom.iterable", 7 | "ES2021" 8 | ], 9 | "outDir": "../../" 10 | }, 11 | "include": [ 12 | "**/*.ts", 13 | "../webviewMsg.types.ts" 14 | ], 15 | "exclude": [ 16 | "node_modules", 17 | "test" 18 | ] 19 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "presentation": { 4 | "echo": false, 5 | "reveal": "always", 6 | "focus": false, 7 | "panel": "dedicated", 8 | "showReuseMessage": false, 9 | "clear": false 10 | }, 11 | "tasks": [ 12 | { 13 | "type": "npm", 14 | "script": "build", 15 | "problemMatcher": [ 16 | "$ts-webpack", 17 | ], 18 | "group": { 19 | "kind": "build", 20 | "isDefault": true 21 | } 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /src/webviews/webviewMsg.types.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | export interface WebviewMsg { 8 | type: string; 9 | payload?: any; 10 | } 11 | -------------------------------------------------------------------------------- /src/views/providers/helpers.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | export function stripComments(line: string): string { 8 | return line.replace(/\s*\(.*\)\s*$|^\s*;.*/g, ''); 9 | } 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "arrowParens": "avoid", 3 | "endOfLine": "lf", 4 | "singleQuote": true, 5 | "trailingComma": "all", 6 | "printWidth": 120, 7 | "tabWidth": 4, 8 | "bracketSpacing": true, 9 | "overrides": [ 10 | { 11 | "files": ".prettierrc", 12 | "options": { 13 | "parser": "json" 14 | } 15 | }, 16 | { 17 | "files": "*.md", 18 | "options": { 19 | "tabWidth": 2 20 | } 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /.vscodeignore: -------------------------------------------------------------------------------- 1 | .eslintcache 2 | .eslintignore 3 | .eslintrc.json 4 | .gitattributes 5 | .github/** 6 | .gitignore 7 | .markdownlint.json 8 | .prettierignore 9 | .prettierrc 10 | .vscode-test/** 11 | .vscode-test-web/** 12 | .vscode/** 13 | **/*.map 14 | CODE_OF_CONDUCT.md 15 | CONTRIBUTING.md 16 | SECURITY.md 17 | CHANGELOG.md 18 | images/**/[^logo]* 19 | out/test/** 20 | package-lock.json 21 | samplenc/** 22 | scripts/** 23 | src/** 24 | test/** 25 | out/** 26 | node_modules/** 27 | tsconfig** 28 | tsconfig.tsbuildinfo 29 | webpack.config*.js 30 | .DS_Store -------------------------------------------------------------------------------- /src/webviews/helpers.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import crypto from 'crypto'; 8 | 9 | export function getNonce(): string { 10 | return crypto.randomBytes(16).toString('base64'); 11 | } 12 | -------------------------------------------------------------------------------- /resources/icons/dark/stop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/stop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /snippets/general-snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "O0000": { 3 | "prefix": "O", 4 | "body": [ 5 | "O${0:NNNN}" 6 | ], 7 | "description": "Add Program Number" 8 | }, 9 | "GOTO": { 10 | "prefix": "GOTO", 11 | "body": [ 12 | "GOTO ${0:NNNN}" 13 | ], 14 | "description": "GOTO Number" 15 | }, 16 | "NXXXX": { 17 | "prefix": "sub", 18 | "body": [ 19 | "N${1:NNNN}", 20 | " $0", 21 | "M99" 22 | ], 23 | "description": "Local Subprogram" 24 | } 25 | } -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Reporting Security Issues 2 | 3 | Our team takes security bugs in our extension very seriously. We appreciate your efforts to responsibly disclose any findings, and will make every efford to acknowledge your contributions. 4 | 5 | We try to keep all of the dependencies updated whenever possible. 6 | 7 | Because this is a plugin to VSCode, to report a security issue or vulnerability, please verify that the issue is with our plugin and if so, submit an [issue](https://github.com/appliedengdesign/vscode-gcode-syntax/issues), otherwise, submit an issue with the [VSCode project](https://github.com/microsoft/vscode). 8 | -------------------------------------------------------------------------------- /resources/icons/dark/boring.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/boring.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/util/quickpicks/buttons.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { QuickInputButton, ThemeIcon, Uri } from 'vscode'; 9 | 10 | export class GButton implements QuickInputButton { 11 | constructor(public iconPath: Uri | { dark: Uri; light: Uri } | ThemeIcon, public tooltip: string | undefined) {} 12 | } 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto eol=lf 5 | 6 | 7 | # Force batch scripts to always use CRLF line endings so that if a repo is accessed 8 | # in Windows via a file share from Linux, the scripts will work. 9 | *.{cmd,[cC][mM][dD]} text eol=crlf 10 | *.{bat,[bB][aA][tT]} text eol=crlf 11 | 12 | 13 | # Force bash scripts to always use lf line endings so that if a repo is accessed 14 | # in Unix via a file share from Windows, the scripts will work. 15 | *.sh text eol=lf 16 | 17 | -------------------------------------------------------------------------------- /samplenc/sample-profile.nc: -------------------------------------------------------------------------------- 1 | % 2 | O0 3 | G40 G49 G80 4 | ( BEGIN TOOL LIST ) 5 | ( TOOL 3 - .25 EM - DESC: 0.2497 DIA, 3 FLUTE, CARBIDE MAT ) 6 | ( ENDOF TOOL LIST ) 7 | (2 1/2 Axis Profiling) 8 | (Tool Diameter = 0.2497 Length = 3.5 ) 9 | G20 T03 M6 10 | M08 11 | S12000 M03 12 | G90 G00 X4.8752 Y0. 13 | G43 Z0.25 H03 14 | G01 Z0. F18. 15 | Y4. F36. 16 | G17 17 | G03 X4. Y4.8752 I-0.8752 J0. 18 | G01 X-4. 19 | G03 X-4.8752 Y4. I0. J-0.8752 20 | G01 Y1. 21 | G03 X-4. Y0.1248 I0.8752 J0. 22 | G01 X-2. 23 | G02 X0.1248 Y-2. I0. J-2.1248 24 | G01 Y-4. 25 | G03 X1. Y-4.8752 I0.8752 J0. 26 | G01 X4. 27 | G03 X4.8752 Y-4. I0. J0.8752 28 | G01 Y0. 29 | G00 Z0.25 30 | M05 31 | M09 32 | G28 G91 Z0.0 33 | M30 34 | % 35 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [appliedengdesign] 4 | #patreon: # Replace with a single Patreon username 5 | #open_collective: # Replace with a single Open Collective username 6 | #ko_fi: # Replace with a single Ko-fi username 7 | #tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | #community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | #liberapay: # Replace with a single Liberapay username 10 | #issuehunt: # Replace with a single IssueHunt username 11 | #otechie: # Replace with a single Otechie username 12 | custom: ['http://appliedengdesign.com', 'https://youtube.com/c/AppliedEngDesignUSA'] 13 | -------------------------------------------------------------------------------- /.github/workflows/lock.yml: -------------------------------------------------------------------------------- 1 | name: 'Lock Closed Issues' 2 | 3 | on: 4 | schedule: 5 | - cron: '30 5 * * *' 6 | 7 | workflow_dispatch: 8 | 9 | permissions: 10 | issues: write 11 | pull-requests: write 12 | 13 | concurrency: 14 | group: lock 15 | 16 | jobs: 17 | action: 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: dessant/lock-threads@v3 21 | with: 22 | github-token: ${{ secrets.GITHUB_TOKEN }} 23 | issue-comment: 'This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related topics.' 24 | issue-inactive-days: 60 25 | add-issue-labels: 'archived' 26 | process-only: 'issues' 27 | -------------------------------------------------------------------------------- /src/util/commands/showSupportGCode.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { GCommand } from './base'; 9 | import { Messages } from '../messages'; 10 | import { GCommands } from '../constants'; 11 | 12 | export class ShowSupportGCode extends GCommand { 13 | constructor() { 14 | super(GCommands.ShowSupportGCode); 15 | } 16 | 17 | execute() { 18 | return Messages.showSupportGCodeMessage(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 16 | 1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Environment / Version:** 28 | 29 | - OS Version: [e.g. Windows 10, OS X, Linux] 30 | - VSCode Version: 31 | - Extension Version: 32 | 33 | **Additional context** 34 | Add any other context about the problem here. 35 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Mark Stale Issues and Pull Requests 2 | 3 | on: 4 | schedule: 5 | - cron: '36 7 * * *' 6 | 7 | jobs: 8 | stale: 9 | 10 | runs-on: ubuntu-latest 11 | permissions: 12 | issues: write 13 | pull-requests: write 14 | 15 | steps: 16 | - uses: actions/stale@v5 17 | with: 18 | repo-token: ${{ secrets.GITHUB_TOKEN }} 19 | 20 | days-before-stale: 60 21 | days-before-close: -1 22 | 23 | stale-issue-message: 'This issue has been automatically marked as stale because it has not had recent activity.' 24 | 25 | stale-pr-message: 'This pull request has been automatically marked as stale because it has not had recent activity.' 26 | 27 | stale-issue-label: 'stale-issue' 28 | stale-pr-label: 'stale-pull-request' 29 | -------------------------------------------------------------------------------- /src/util/commands/removeLineNumbers.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { GCommands } from '../constants'; 9 | import { LineNumberer } from '../lineNumberer'; 10 | import { GCommand } from './base'; 11 | 12 | export class RemoveLineNumbers extends GCommand { 13 | constructor() { 14 | super(GCommands.RemoveLineNumbers); 15 | } 16 | 17 | async execute() { 18 | const ln = new LineNumberer(); 19 | await ln.removeNumbers(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/tsconfig", 3 | "compilerOptions": { 4 | "esModuleInterop": true, 5 | "forceConsistentCasingInFileNames": true, 6 | "incremental": true, 7 | "isolatedModules": true, 8 | "lib": [ 9 | "ES2021" 10 | ], 11 | "module": "CommonJS", 12 | "moduleResolution": "node", 13 | "noFallthroughCasesInSwitch": true, 14 | "noImplicitReturns": true, 15 | "noUnusedLocals": false, 16 | "newLine": "lf", 17 | "outDir": "out", 18 | "resolveJsonModule": true, 19 | "rootDir": ".", 20 | "skipLibCheck": true, 21 | "sourceMap": true, 22 | "strict": true, 23 | "target": "ES2021", 24 | "useDefineForClassFields": true 25 | }, 26 | "include": [ 27 | "src/**/*.ts", 28 | "test/**/*.ts" 29 | ], 30 | "exclude": [ 31 | "node_modules", 32 | "samplenc", 33 | "src/webviews/apps/**/*" 34 | ] 35 | } -------------------------------------------------------------------------------- /src/util/commands/showGCodeSettings.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { commands } from 'vscode'; 9 | import { GCommand } from './base'; 10 | import { constants, GCommands, VSBuiltInCommands } from '../constants'; 11 | 12 | export class ShowGCodeSettings extends GCommand { 13 | constructor() { 14 | super(GCommands.ShowGCodeSettings); 15 | } 16 | 17 | execute() { 18 | void commands.executeCommand(VSBuiltInCommands.OpenSettings, `@ext:${constants.extensionQualifiedId}`); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /resources/icons/dark/cutting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/cutting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: [pull_request_target, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | permissions: 9 | issues: write 10 | pull-requests: write 11 | 12 | steps: 13 | - uses: actions/first-interaction@v1 14 | with: 15 | repo-token: ${{ secrets.GITHUB_TOKEN }} 16 | issue-message: 'Hello and welcome! Thanks for creating your first issue! Someone from our community will get back to you soon!' 17 | pr-message: > 18 | Thanks for opening your first pull reqest in VSCode G-Code Syntax! 19 | 20 | Please make sure you read the [Contributing Guide](https://github.com/appliedengdesign/vscode-gcode-syntax/blob/master/CONTRIBUTING.md) and follow the [Code of Conduct](https://github.com/appliedengdesign/vscode-gcode-syntax/blob/master/CODE_OF_CONDUCT.md). -------------------------------------------------------------------------------- /test/e2e/extension.test.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | import * as assert from 'assert'; 6 | import { after } from 'mocha'; 7 | import * as vscode from 'vscode'; 8 | 9 | suite('Extension Test Suite', () => { 10 | void vscode.window.showInformationMessage('Start all tests.'); 11 | 12 | after(() => { 13 | void vscode.window.showInformationMessage('All Tests Done!'); 14 | }); 15 | 16 | test('Sample test', () => { 17 | assert.strictEqual(-1, [1, 2, 3].indexOf(5)); 18 | assert.strictEqual(-1, [1, 2, 3].indexOf(0)); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/runTests.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | import * as path from 'path'; 6 | 7 | import { runTests } from 'vscode-test'; 8 | 9 | async function main() { 10 | try { 11 | const extensionDevelopmentPath = path.resolve(__dirname, '../../'); 12 | const extensionTestsPath = path.resolve(__dirname, './suite/index'); 13 | 14 | await runTests({ 15 | extensionDevelopmentPath, 16 | extensionTestsPath, 17 | }); 18 | } catch (err) { 19 | console.error(err); 20 | console.error('Failed to run tests'); 21 | process.exit(1); 22 | } 23 | } 24 | 25 | void main(); 26 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | schedule: 9 | - cron: '30 3 * * 0' 10 | 11 | jobs: 12 | analyze: 13 | name: Analyze 14 | runs-on: ubuntu-latest 15 | permissions: 16 | actions: read 17 | contents: read 18 | security-events: write 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | language: [ 'javascript', 'typescript' ] 24 | 25 | steps: 26 | - name: Checkout repository 27 | uses: actions/checkout@v3 28 | 29 | # Initializes the CodeQL tools for scanning. 30 | - name: Initialize CodeQL 31 | uses: github/codeql-action/init@v2 32 | with: 33 | languages: ${{ matrix.language }} 34 | 35 | - name: Autobuild 36 | uses: github/codeql-action/autobuild@v2 37 | 38 | - name: Perform CodeQL Analysis 39 | uses: github/codeql-action/analyze@v2 40 | -------------------------------------------------------------------------------- /resources/icons/dark/ccwcutting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/heart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/ccwcutting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/heart.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/cwcutting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/cwcutting.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/coolantoff.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/coolantoff.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/localsubprog.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/localsubprog.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/subprogreturn.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/subprogreturn.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Applied Engineering & Design 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 | -------------------------------------------------------------------------------- /src/views/nodes/navTreeNode.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { TreeItemCollapsibleState } from 'vscode'; 8 | import { constants } from '../../util/constants'; 9 | import * as path from 'path'; 10 | import { IconType, ViewNode } from './nodes'; 11 | 12 | export class NavTreeNode extends ViewNode { 13 | constructor(public readonly label: string, public readonly collapsibleState: TreeItemCollapsibleState) { 14 | super(label); 15 | } 16 | 17 | setIcon(type: IconType): void { 18 | this.iconPath = { 19 | light: path.join(constants.iconsPath, 'light', `${type}.svg`), 20 | dark: path.join(constants.iconsPath, 'dark', `${type}.svg`), 21 | }; 22 | } 23 | 24 | getTreeItem(): ViewNode | Promise { 25 | return this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /resources/icons/dark/spindleccw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/spindleccw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/util/commands/addLineNumbers.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { configuration } from '../configuration/config'; 9 | import { GCommands } from '../constants'; 10 | import { LineNumberer } from '../lineNumberer'; 11 | import { LineNumbersInput } from '../quickpicks/lineNumbers'; 12 | import { GCommand } from './base'; 13 | 14 | export class AddLineNumbers extends GCommand { 15 | constructor() { 16 | super(GCommands.AddLineNumbers); 17 | } 18 | 19 | async execute() { 20 | const ln = new LineNumberer(); 21 | 22 | if (configuration.getParam('lineNumberer.enableQuickPick')) { 23 | const lnInputs = new LineNumbersInput(); 24 | const state = await lnInputs.collect(); 25 | 26 | await ln.addNumbers(state.start, state.increment); 27 | } else { 28 | await ln.addNumbers(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /resources/icons/dark/extsubprog.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/extsubprog.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/spindlecw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/spindlecw.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/dwell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/dwell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/unit/stats.test.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { expect } from 'chai'; 9 | import { GCodeRuntimeParser } from '../../src/views/providers/gcodeRuntimeParser'; 10 | import fs from 'fs'; 11 | import path from 'path'; 12 | 13 | describe('G-Code Stats', () => { 14 | it('calculates the correct runtime', () => { 15 | const gcr = new GCodeRuntimeParser( 16 | fs.readFileSync(path.resolve(__dirname, '..', '..', 'samplenc', 'sample-profile.nc')).toString(), 17 | ); 18 | gcr.update(); 19 | 20 | expect(gcr.getRuntime()).to.be.equal(59.74464683955828); 21 | }); 22 | 23 | it('calculates the correct runtime', () => { 24 | const gcr = new GCodeRuntimeParser( 25 | fs.readFileSync(path.resolve(__dirname, '..', '..', 'samplenc', 'sample-circular-pocket.nc')).toString(), 26 | ); 27 | gcr.update(); 28 | 29 | expect(gcr.getRuntime()).to.be.equal(430.00882725574473); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /src/util/commands/removeComment.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { Range, window } from 'vscode'; 9 | import { constants, GCommands } from '../constants'; 10 | import { GCommand } from './base'; 11 | 12 | export class RemoveComment extends GCommand { 13 | constructor() { 14 | super(GCommands.RemoveComment); 15 | } 16 | 17 | execute() { 18 | const editor = window.activeTextEditor; 19 | 20 | if (editor && editor.document.uri.scheme === 'file' && editor.document.languageId === constants.langId) { 21 | const select = new Range(editor.selection.start, editor.selection.end); 22 | 23 | let text = editor.document.getText(select); 24 | 25 | // Remove () in the selection 26 | const re1 = /\(|\)/g; 27 | 28 | text = text.replace(re1, ''); 29 | 30 | void editor.edit(editBuilder => { 31 | editBuilder.replace(select, text); 32 | }); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "out": false 4 | }, 5 | "search.exclude": { 6 | "out": true, 7 | "dist": true 8 | }, 9 | "typescript.tsc.autoDetect": "off", 10 | "[typescript]": { 11 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 12 | }, 13 | "[json]": { 14 | "editor.quickSuggestions": { 15 | "strings": true 16 | }, 17 | "editor.suggest.insertMode": "replace", 18 | "gitlens.codeLens.scopes": [ 19 | "document" 20 | ], 21 | "editor.defaultFormatter": "vscode.json-language-features" 22 | }, 23 | "[jsonc]": { 24 | "editor.quickSuggestions": { 25 | "strings": true 26 | }, 27 | "editor.suggest.insertMode": "replace", 28 | "gitlens.codeLens.scopes": [ 29 | "document" 30 | ], 31 | "editor.defaultFormatter": "vscode.json-language-features" 32 | }, 33 | "[javascript]": { 34 | "editor.defaultFormatter": "dbaeumer.vscode-eslint" 35 | }, 36 | "editor.formatOnSave": true, 37 | "editor.formatOnPaste": true, 38 | "eslint.alwaysShowStatus": true, 39 | "eslint.format.enable": true, 40 | "eslint.validate": [ 41 | "typescript", 42 | "javascript" 43 | ], 44 | "prettier.requireConfig": true, 45 | } -------------------------------------------------------------------------------- /src/extension.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | import { ExtensionContext } from 'vscode'; 7 | import { configuration } from './util/configuration/config'; 8 | import { constants } from './util/constants'; 9 | import { Logger } from './util/logger'; 10 | import { Control } from './control'; 11 | 12 | export function activate(context: ExtensionContext) { 13 | const start = process.hrtime(); 14 | 15 | // Initialize Logger 16 | Logger.initialize(context); 17 | Logger.enable(); 18 | 19 | Logger.log('Initializing G-Code...'); 20 | 21 | // Initialize Controller 22 | Control.initialize(context, configuration); 23 | 24 | Logger.log( 25 | `${constants.extension.shortname} v${constants.extension.version} activated in ${Control.getLoadTime( 26 | start, 27 | ).toFixed(3)}ms`, 28 | ); 29 | Logger.log(constants.copyright); 30 | } 31 | 32 | export function deactivate() { 33 | // Clean up 34 | Control.terminate(); 35 | 36 | // Close Logger 37 | Logger.close(); 38 | } 39 | -------------------------------------------------------------------------------- /src/util/commands/base.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { commands, Disposable } from 'vscode'; 9 | import { GCommands } from '../constants'; 10 | 11 | export abstract class GCommand implements Disposable { 12 | private readonly _disposable: Disposable; 13 | 14 | constructor(cmd: GCommands | GCommands[]) { 15 | if (typeof cmd === 'string') { 16 | this._disposable = commands.registerCommand(cmd, (...args: any[]) => this._execute(cmd, ...args), this); 17 | 18 | return; 19 | } 20 | 21 | const subscriptions = cmd.map(cmd => 22 | commands.registerCommand(cmd, (...args: any[]) => this._execute(cmd, ...args), this), 23 | ); 24 | this._disposable = Disposable.from(...subscriptions); 25 | } 26 | 27 | dispose() { 28 | this._disposable && this._disposable.dispose(); 29 | } 30 | 31 | abstract execute(...args: any[]): any; 32 | 33 | protected _execute(cmd: string, ...args: any[]): void { 34 | this.execute(...args); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/util/commands/index.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { Disposable } from 'vscode'; 9 | import { AddComment } from './addComment'; 10 | import { AddLineNumbers } from './addLineNumbers'; 11 | import { RemoveComment } from './removeComment'; 12 | import { RemoveLineNumbers } from './removeLineNumbers'; 13 | import { ShowGCodeSettings } from './showGCodeSettings'; 14 | import { ShowSupportGCode } from './showSupportGCode'; 15 | 16 | export { AddComment } from './addComment'; 17 | export { AddLineNumbers } from './addLineNumbers'; 18 | export { RemoveComment } from './removeComment'; 19 | export { RemoveLineNumbers } from './removeLineNumbers'; 20 | export { ShowGCodeSettings } from './showGCodeSettings'; 21 | export { ShowSupportGCode } from './showSupportGCode'; 22 | 23 | export function registerCommands(): Disposable[] { 24 | return [ 25 | new AddComment(), 26 | new AddLineNumbers(), 27 | new RemoveComment(), 28 | new RemoveLineNumbers(), 29 | new ShowGCodeSettings(), 30 | new ShowSupportGCode(), 31 | ]; 32 | } 33 | -------------------------------------------------------------------------------- /resources/icons/dark/rapid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/rapid.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test/e2e/index.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | import path from 'path'; 6 | import Mocha from 'mocha'; 7 | import glob from 'glob'; 8 | 9 | export const run = (testsRoot: string): Promise => { 10 | // Create the mocha test 11 | const mocha = new Mocha({ 12 | ui: 'tdd', 13 | timeout: 15000, 14 | color: true, 15 | }); 16 | 17 | return new Promise((c, e) => { 18 | glob('**/**.test.js', { cwd: testsRoot }, (error, files) => { 19 | if (error) { 20 | return e(error); 21 | } 22 | 23 | try { 24 | files.forEach((file: string) => mocha.addFile(path.resolve(testsRoot, file))); 25 | // Run the mocha test 26 | mocha.run((failures: number) => { 27 | if (failures > 0) { 28 | e(new Error(`${failures} tests failed.`)); 29 | } else { 30 | c(); 31 | } 32 | }); 33 | } catch (err) { 34 | e(err); 35 | } 36 | }); 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /src/hovers/gcodeHoverProvider.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { 8 | CancellationToken, 9 | Hover, 10 | HoverProvider, 11 | MarkdownString, 12 | Position, 13 | ProviderResult, 14 | TextDocument, 15 | } from 'vscode'; 16 | import { Control } from '../control'; 17 | 18 | export class GCodeHoverProvider implements HoverProvider { 19 | provideHover(document: TextDocument, position: Position, _token: CancellationToken): ProviderResult { 20 | const range = document.getWordRangeAtPosition(position); 21 | const text = document.getText(range); 22 | 23 | const def = this.lookup(text); 24 | if (def === undefined) { 25 | return; 26 | } else { 27 | return new Hover(def, range); 28 | } 29 | } 30 | 31 | private lookup(text: string): MarkdownString | undefined { 32 | const ref = Control.machineTypeController?.gReference; 33 | 34 | const code = ref?.get(text); 35 | 36 | if (code === undefined) { 37 | return; 38 | } 39 | 40 | return new MarkdownString(`**${text}**: `).appendMarkdown(code.shortDesc ?? ''); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.vscode/vscode-gcode-syntax.code-snippets: -------------------------------------------------------------------------------- 1 | { 2 | "Create Snippet": { 3 | "scope": "json", 4 | "prefix": "snip", 5 | "body": [ 6 | "\"$1\": {", 7 | "\t\"scope\": \"gcode\",", 8 | "\t\"prefix\": \"$2\",", 9 | "\t\"body\": [", 10 | "\t\t\"$0\"", 11 | "\t],", 12 | "\t\"description\": \"$3\"", 13 | "}" 14 | ], 15 | "description": "Create Snippet" 16 | }, 17 | "Add File Header": { 18 | "scope": "typescript,javascript", 19 | "prefix": [ 20 | "header", 21 | "copyright" 22 | ], 23 | "body": [ 24 | "/* ---------------------------------------------------------------------------------------------", 25 | " * Copyright (c) Applied Eng & Design All rights reserved.", 26 | " * Licensed under the MIT License. See License.md in the project root for license information.", 27 | " * -------------------------------------------------------------------------------------------- */" 28 | ], 29 | "description": "Adds Copyright Header..." 30 | }, 31 | "Issues Link": { 32 | "scope": "markdown", 33 | "prefix": [ 34 | "issues", 35 | "gh", 36 | "ghissues", 37 | "link" 38 | ], 39 | "body": "https://github.com/appliedengdesign/vscode-gcode-syntax/issues/$1", 40 | "description": "Insert link to GH issue" 41 | }, 42 | "Tag Link": { 43 | "scope": "markdown", 44 | "prefix": [ 45 | "tag", 46 | "ghtag", 47 | "release", 48 | "link" 49 | ], 50 | "body": "(https://github.com/appliedengesign/vscode-gcode-syntax/releases/tag/$1", 51 | "description": "Insert link to release" 52 | } 53 | } -------------------------------------------------------------------------------- /language/gcode-language.json: -------------------------------------------------------------------------------- 1 | { 2 | "comments": { 3 | "blockComment": [ 4 | "(", 5 | ")" 6 | ], 7 | "lineComment": ";" 8 | }, 9 | "brackets": [ 10 | [ 11 | "{", 12 | "}" 13 | ], 14 | [ 15 | "[", 16 | "]" 17 | ], 18 | [ 19 | "(", 20 | ")" 21 | ], 22 | [ 23 | "<", 24 | ">" 25 | ] 26 | ], 27 | "autoClosingPairs": [ 28 | { 29 | "open": "(", 30 | "close": ")" 31 | }, 32 | { 33 | "open": "[", 34 | "close": "]" 35 | }, 36 | { 37 | "open": "<", 38 | "close": ">" 39 | }, 40 | { 41 | "open": "{", 42 | "close": "}" 43 | }, 44 | { 45 | "open": "\"", 46 | "close": "\"" 47 | }, 48 | { 49 | "open": "'", 50 | "close": "'" 51 | } 52 | ], 53 | "surroundingPairs": [ 54 | [ 55 | "(", 56 | ")" 57 | ], 58 | [ 59 | "[", 60 | "]" 61 | ], 62 | [ 63 | "<", 64 | ">" 65 | ], 66 | [ 67 | "{", 68 | "}" 69 | ], 70 | [ 71 | "\"", 72 | "\"" 73 | ], 74 | [ 75 | "'", 76 | "'" 77 | ] 78 | ] 79 | } -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 14 | 15 | # Pull Request 16 | 17 | ## Description 18 | 19 | 22 | 23 | ## Issues 24 | 25 | 30 | 31 | ## Reviewer Notes 32 | 33 | 38 | 39 | ## Checklist 40 | 41 | 42 | 43 | - [] I have followed the guidelines in the [Contributing](https://github.com/appliedengdesign/vscode-gcode-syntax/blob/main/CONTRIBUTING.md) document. 44 | - [] I have followed the [Code of Conduct](https://github.com/appliedengdesign/vscode-gcode-syntax/blob/main/CODE_OF_CONDUCT.md) for this project. 45 | - [] My changes follow the coding style of this project. 46 | - [] My changes have been formatted and linted. 47 | - [] I have made any relevant changes to the documentation as needed (include CHANGELOG.md and/or README.md). 48 | - [] My changes have a descriptive commit message with a short title, including links to issues it addresses. 49 | - [] I had fun. 50 | -------------------------------------------------------------------------------- /snippets/mcode-snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "Spindle": { 3 | "scope": "gcode", 4 | "prefix": "S", 5 | "body": [ 6 | "S${1:[RPM]} M0${2|3,4|}" 7 | ], 8 | "description": "Spindle Speed" 9 | }, 10 | "M03": { 11 | "scope": "gcode", 12 | "prefix": "M03", 13 | "body": [ 14 | "M03 S${0:[RPM]}" 15 | ], 16 | "description": "Spindle CW" 17 | }, 18 | "M04": { 19 | "scope": "gcode", 20 | "prefix": "M04", 21 | "body": [ 22 | "M04 S${0:[RPM]}" 23 | ], 24 | "description": "Spindle CCW" 25 | }, 26 | "M05": { 27 | "scope": "gcode", 28 | "prefix": "M05", 29 | "description": "Spindle Off" 30 | }, 31 | "M06": { 32 | "scope": "gcode", 33 | "prefix": "M06", 34 | "body": [ 35 | "M06 T${0:[Tool Num]}" 36 | ], 37 | "description": "M06 Tool Change" 38 | }, 39 | "M19": { 40 | "scope": "gcode", 41 | "prefix": "M19", 42 | "body": [ 43 | "M19 ${1|P,S|}${0:[Angle]}" 44 | ], 45 | "description": "M19 Spindle Orient" 46 | }, 47 | "M97": { 48 | "scope": "gcode", 49 | "prefix": "M97", 50 | "body": [ 51 | "M97 P${2:0000} L${0:1}" 52 | ], 53 | "description": "M97 Local Subprogram Call" 54 | }, 55 | "M98": { 56 | "scope": "gcode", 57 | "prefix": "M98", 58 | "body": [ 59 | "M98 P${1:0000} L${0:1}" 60 | ], 61 | "description": "M98 Subprogram Call" 62 | } 63 | } -------------------------------------------------------------------------------- /src/webviews/apps/calc/calc.scss: -------------------------------------------------------------------------------- 1 | @import '../shared/scss/reset'; 2 | @import '../shared/scss/vscode'; 3 | @import '../shared/scss/base'; 4 | 5 | .container { 6 | display: flex; 7 | justify-content: center; 8 | min-height: 100%; 9 | margin: 0; 10 | padding: 0; 11 | } 12 | 13 | section { 14 | display: flex; 15 | flex-direction: column; 16 | justify-content: start; 17 | padding: 1em; 18 | } 19 | 20 | section.row { 21 | flex-direction: row; 22 | flex: none; 23 | justify-content: center; 24 | padding: 0; 25 | } 26 | 27 | h3 { 28 | border: none; 29 | font-weight: 600; 30 | margin-top: 0; 31 | white-space: nowrap; 32 | } 33 | 34 | vscode-text-field, 35 | vscode-button { 36 | margin: 0.5rem 0; 37 | } 38 | 39 | vscode-panel-view { 40 | flex-wrap: wrap; 41 | flex-direction: column; 42 | padding: 0; 43 | } 44 | 45 | vscode-text-field.results { 46 | font-style: italic; 47 | } 48 | 49 | span.clear-btn { 50 | margin-top: 1rem; 51 | } 52 | 53 | span.units { 54 | font-weight: 600; 55 | font-size: 0.9em; 56 | } 57 | 58 | label.results { 59 | font-style: italic; 60 | margin-top: 1rem; 61 | margin-bottom: 2px; 62 | } 63 | 64 | span.results { 65 | border: 1px solid var(--vscode-inputValidation-infoBorder); 66 | background: transparent; 67 | width: 90px; 68 | height: 20px; 69 | padding: 5px; 70 | } 71 | 72 | section.calculator > vscode-button { 73 | margin-top: 1rem; 74 | } 75 | 76 | .error { 77 | color: var(--vscode-errorForeground); 78 | } 79 | 80 | .hidden { 81 | visibility: hidden; 82 | } 83 | 84 | #finish .label { 85 | padding-bottom: 3.5px; 86 | } -------------------------------------------------------------------------------- /src/webviews/apps/shared/gWebviewApp.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { WebviewMsg } from '../../webviewMsg.types'; 8 | 9 | declare let __BOOTSTRAP__: WebviewMsg; 10 | 11 | interface VsCodeApi { 12 | postMessage(msg: any): void; 13 | setState(state: any): void; 14 | getState(): any; 15 | } 16 | 17 | declare function acquireVsCodeApi(): VsCodeApi; 18 | 19 | export abstract class GWebviewApp { 20 | private readonly _api: VsCodeApi; 21 | protected bootstrap: WebviewMsg | undefined; 22 | 23 | constructor(protected readonly appName: string) { 24 | // Get Bootstrap if any 25 | if (typeof __BOOTSTRAP__ !== 'undefined') { 26 | this.bootstrap = __BOOTSTRAP__; 27 | } 28 | 29 | this._api = acquireVsCodeApi(); 30 | this._registerEvents(); 31 | } 32 | 33 | private _registerEvents(): void { 34 | window.addEventListener('message', this.onMsgReceived.bind(this)); 35 | } 36 | 37 | protected postMessage(msg: any): void { 38 | this._api.postMessage(msg); 39 | } 40 | 41 | protected getState(): any { 42 | return this._api.getState(); 43 | } 44 | 45 | protected setState(state: any): void { 46 | this._api.setState(state); 47 | } 48 | 49 | protected abstract onMsgReceived(e: MessageEvent): void; 50 | } 51 | -------------------------------------------------------------------------------- /snippets/gcode-snippets.json: -------------------------------------------------------------------------------- 1 | { 2 | "G04": { 3 | "scope": "gcode", 4 | "prefix": "G04", 5 | "body": [ 6 | "G04 P${0:[Dwell]}" 7 | ], 8 | "description": "G04 Dwell" 9 | }, 10 | "G43": { 11 | "scope": "gcode", 12 | "prefix": "G43", 13 | "body": [ 14 | "G43 Z${1:[Z Loc]} H${0:[Tool Num]}" 15 | ], 16 | "description": "" 17 | }, 18 | "G81": { 19 | "prefix": "G81", 20 | "scope": "gcode", 21 | "body": [ 22 | "G81 X${1:[X Loc]} Y${2:[Y Loc]} Z${3:[Depth]} R${4:[Retract Plane]} F${5:[Feed Rate]}", 23 | " $0", 24 | "G80" 25 | ], 26 | "description": "G81 Drill Cycle" 27 | }, 28 | "G82": { 29 | "prefix": "G82", 30 | "scope": "gcode", 31 | "body": [ 32 | "G82 X${1:[X Loc]} Y${2:[Y Loc]} Z${3:[Depth]} R${4:[Retract Plane]} F${5:[Feed Rate]} P${6:[Dwell]}", 33 | " $0", 34 | "G80" 35 | ], 36 | "description": "G82 Drill Cycle w/ Dwell" 37 | }, 38 | "G83": { 39 | "prefix": "G83", 40 | "scope": "gcode", 41 | "body": [ 42 | "G83 X${1:[X Loc]} Y${2:[Y Loc]} Z${3:[Depth]} R${4:[Retract Plane]} Q${5:[Peck Incr]} F${6:[Feed Rate]}", 43 | " $0", 44 | "G80" 45 | ], 46 | "description": "G83 Deep Hole Peck Cycle" 47 | }, 48 | "G84": { 49 | "scope": "gcode", 50 | "prefix": "G84", 51 | "body": [ 52 | "G84 X${1:[X Loc]} Y${2:[Y Loc]} Z${3:[Depth]} R${4:[Retract Plane]} F${5:[Feed Rate]}", 53 | " $0", 54 | "G80" 55 | ], 56 | "description": "G84 Tapping cycle" 57 | } 58 | } -------------------------------------------------------------------------------- /src/util/commands/addComment.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { Range, window } from 'vscode'; 9 | import { constants, GCommands } from '../constants'; 10 | import { Messages } from '../messages'; 11 | import { GCommand } from './base'; 12 | 13 | export class AddComment extends GCommand { 14 | constructor() { 15 | super(GCommands.AddComment); 16 | } 17 | 18 | async execute() { 19 | const editor = window.activeTextEditor; 20 | let replace = ''; 21 | 22 | if (editor && editor.document.uri.scheme === 'file' && editor.document.languageId === constants.langId) { 23 | const select = new Range(editor.selection.start, editor.selection.end); 24 | let text = editor.document.getText(select); 25 | 26 | // Remove any () in the selection 27 | const re1 = /\(|\)/; 28 | 29 | text = text.replace(re1, ''); 30 | 31 | const lines = text.split(/\r?\n|\r/g) || []; 32 | 33 | for (let i = 0; i < lines.length; ++i) { 34 | lines[i] = lines[i].replace(/\r?\n|\r/g, ''); 35 | replace += `(${lines[i]})${i + 1 === lines.length ? '' : '\n'}`; 36 | } 37 | 38 | await editor.edit(editBuilder => { 39 | editBuilder.replace(select, replace); 40 | }); 41 | } else { 42 | await Messages.showErrorMessage('Editor does not contain G-Code'); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /samplenc/sample-circular-pocket.nc: -------------------------------------------------------------------------------- 1 | G0 G49 G40 G17 G80 G50 G90 2 | M6 T0(TOOL DIA.0.75) 3 | G64 4 | G20 (Inch) 5 | M04 S0 6 | G00 G43 H0 Z0.1 7 | X0 Y0 8 | G01 Z-0.25 F1 9 | G2 Y0 X0.15 R0.075 F30 10 | Y0 X-0.15 R0.15 11 | Y0 X0.3 R0.225 12 | Y0 X-0.3 R0.3 13 | Y0 X0.45 R0.375 14 | Y0 X-0.45 R0.45 15 | Y0 X0.6 R0.525 16 | Y0 X-0.6 R0.6 17 | Y0 X0.75 R0.675 18 | Y0 X-0.75 R0.75 19 | Y0 X0.9 R0.825 20 | Y0 X-0.9 R0.9 21 | Y0 X1.05 R0.975 22 | Y0 X-1.05 R1.05 23 | Y0 X1.125 R1.0875 24 | Y0 X-1.125 R1.125 25 | X1.125 Y0 R1.125 26 | Y-0.375 X0.75 R0.375 27 | G00 Z0.1 28 | X0 Y0 29 | G01 Z-0.5 F1 30 | G2 Y0 X0.15 R0.075 F30 31 | Y0 X-0.15 R0.15 32 | Y0 X0.3 R0.225 33 | Y0 X-0.3 R0.3 34 | Y0 X0.45 R0.375 35 | Y0 X-0.45 R0.45 36 | Y0 X0.6 R0.525 37 | Y0 X-0.6 R0.6 38 | Y0 X0.75 R0.675 39 | Y0 X-0.75 R0.75 40 | Y0 X0.9 R0.825 41 | Y0 X-0.9 R0.9 42 | Y0 X1.05 R0.975 43 | Y0 X-1.05 R1.05 44 | Y0 X1.125 R1.0875 45 | Y0 X-1.125 R1.125 46 | X1.125 Y0 R1.125 47 | Y-0.375 X0.75 R0.375 48 | G00 Z0.1 49 | X0 Y0 50 | G01 Z-0.75 F1 51 | G2 Y0 X0.15 R0.075 F30 52 | Y0 X-0.15 R0.15 53 | Y0 X0.3 R0.225 54 | Y0 X-0.3 R0.3 55 | Y0 X0.45 R0.375 56 | Y0 X-0.45 R0.45 57 | Y0 X0.6 R0.525 58 | Y0 X-0.6 R0.6 59 | Y0 X0.75 R0.675 60 | Y0 X-0.75 R0.75 61 | Y0 X0.9 R0.825 62 | Y0 X-0.9 R0.9 63 | Y0 X1.05 R0.975 64 | Y0 X-1.05 R1.05 65 | Y0 X1.125 R1.0875 66 | Y0 X-1.125 R1.125 67 | X1.125 Y0 R1.125 68 | Y-0.375 X0.75 R0.375 69 | G00 Z0.1 70 | X0 Y0 71 | G01 Z-0.9 F1 72 | G2 Y0 X0.15 R0.075 F30 73 | Y0 X-0.15 R0.15 74 | Y0 X0.3 R0.225 75 | Y0 X-0.3 R0.3 76 | Y0 X0.45 R0.375 77 | Y0 X-0.45 R0.45 78 | Y0 X0.6 R0.525 79 | Y0 X-0.6 R0.6 80 | Y0 X0.75 R0.675 81 | Y0 X-0.75 R0.75 82 | Y0 X0.9 R0.825 83 | Y0 X-0.9 R0.9 84 | Y0 X1.05 R0.975 85 | Y0 X-1.05 R1.05 86 | Y0 X1.125 R1.0875 87 | Y0 X-1.125 R1.125 88 | X1.125 Y0 R1.125 89 | Y-0.375 X0.75 R0.375 90 | G00 Z0.1 91 | M5 M9 92 | M30 -------------------------------------------------------------------------------- /resources/icons/dark/toolchange.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/toolchange.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/webviews/apps/calc/calc.types.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | export interface ICalcDom { 8 | rpm?: { 9 | btn: HTMLElement; 10 | speed: HTMLInputElement; 11 | toolDia: HTMLInputElement; 12 | results: HTMLSpanElement; 13 | }; 14 | 15 | speed?: { 16 | btn: HTMLElement; 17 | rpm: HTMLInputElement; 18 | toolDia: HTMLInputElement; 19 | results: HTMLSpanElement; 20 | }; 21 | 22 | feedrate?: { 23 | btn: HTMLElement; 24 | rpm: HTMLInputElement; 25 | numFlutes: HTMLInputElement; 26 | chipLoad: HTMLInputElement; 27 | results: HTMLSpanElement; 28 | }; 29 | 30 | chipLoad?: { 31 | btn: HTMLElement; 32 | feedRate: HTMLInputElement; 33 | rpm: HTMLInputElement; 34 | numFlutes: HTMLInputElement; 35 | results: HTMLSpanElement; 36 | }; 37 | 38 | mrr?: { 39 | btn: HTMLElement; 40 | axialDepth: HTMLInputElement; 41 | radialDepth: HTMLInputElement; 42 | feedRate: HTMLInputElement; 43 | results: HTMLSpanElement; 44 | }; 45 | 46 | finish?: { 47 | btn: HTMLElement; 48 | radius: HTMLInputElement; 49 | feedRate: HTMLInputElement; 50 | results: HTMLSpanElement; 51 | }; 52 | } 53 | 54 | export type TCalcDom = ICalcDom[keyof ICalcDom]; 55 | 56 | export enum MachineTypes { 57 | EDM = 'edm', 58 | Mill = 'mill', 59 | Lathe = 'lathe', 60 | Laser = 'laser', 61 | Printer = 'printer', 62 | Swiss = 'swiss', 63 | } 64 | 65 | export type MachineType = MachineTypes; 66 | 67 | export enum Units { 68 | Inch = 'Inch', 69 | MM = 'Metric', 70 | Default = 'Default (Inch)', 71 | } 72 | 73 | export interface calcBootstrap { 74 | machineType: MachineTypes; 75 | units: Units; 76 | } 77 | -------------------------------------------------------------------------------- /src/views/nodes/statsNode.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { constants } from '../../util/constants'; 8 | import { TreeItemCollapsibleState } from 'vscode'; 9 | import { IconType, ResourceType, ViewNode } from './nodes'; 10 | import * as path from 'path'; 11 | 12 | export const enum StatsType { 13 | Root, 14 | ToolChanges, 15 | RunTime, 16 | Error, 17 | Info, 18 | } 19 | 20 | export class StatsNode extends ViewNode { 21 | private _children: ViewNode[] = []; 22 | 23 | constructor( 24 | private type: StatsType, 25 | private name: string, 26 | private desc?: string, 27 | private cValue?: ResourceType, 28 | private collapsible: TreeItemCollapsibleState = TreeItemCollapsibleState.None, 29 | private tTip?: string, 30 | ) { 31 | super(name, desc, ResourceType.Stats); 32 | 33 | this.setIcon(); 34 | } 35 | 36 | setIcon(): void { 37 | switch (this.type) { 38 | case StatsType.ToolChanges: 39 | this.iconPath = { 40 | light: path.join(constants.iconsPath, 'light', `${IconType.ToolChange}${constants.iconExt}`), 41 | dark: path.join(constants.iconsPath, 'dark', `${IconType.ToolChange}${constants.iconExt}`), 42 | }; 43 | break; 44 | 45 | case StatsType.RunTime: 46 | this.iconPath = { 47 | light: path.join(constants.iconsPath, 'light', `${IconType.Dwell}${constants.iconExt}`), 48 | dark: path.join(constants.iconsPath, 'dark', `${IconType.Dwell}${constants.iconExt}`), 49 | }; 50 | break; 51 | } 52 | } 53 | 54 | getTreeItem(): ViewNode | Promise { 55 | return this; 56 | } 57 | 58 | getChildren(): ViewNode[] { 59 | return this._children; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /samplenc/sample-colors.nc: -------------------------------------------------------------------------------- 1 | % 2 | O01234 3 | G40 G49 G80 4 | ( BEGIN TOOL LIST ) 5 | ( TOOL 17 - 3/8 EM - DESC: 0.3771 DIA, 2 FLUTE, CARBIDE MAT ) 6 | ( ENDOF TOOL LIST ) 7 | 8 | ( WORK ZERO ) 9 | G54 10 | 11 | (POCKET SLOTS) 12 | (Tool Diameter = 0.3771 Length = 1.5 ) 13 | G20 T17 M6 14 | T808 15 | 16 | T0202 17 | 18 | M08 19 | S12000 M03 20 | 21 | T#123 22 | 23 | H#123 24 | 25 | H27.4 26 | 27 | S3200 M04 28 | G90 G0 X-1.9996 Y-6.2902 29 | G43 Z-2.8833 H17 30 | G1 Z-3.1333 F45. 31 | X-2.0486 Y-6.2744 Z-3.1378 F67.5 32 | X-2.1029 Y-6.2565 Z-3.1428 33 | X-2.157 Y-6.238 Z-3.1478 34 | X-2.2109 Y-6.2191 Z-3.1528 35 | X-2.2647 Y-6.1997 Z-3.1578 36 | G02 X5. Y6. R2.0 37 | G03 X5. Y6. R3.5 38 | 39 | G04 P50. 40 | 41 | G154 P25 42 | 43 | G54.1 P35 44 | 45 | G05.1 46 | 47 | G68.2 48 | 49 | G53.1 50 | 51 | G59 P25 52 | 53 | G112 54 | 55 | G15 H10 56 | 57 | X.1234 58 | 59 | X-.1242 60 | 61 | X10.01 62 | 63 | X-25.231 64 | 65 | M04 S5000 66 | 67 | (POCKET SLOTS) 68 | (Tool Diameter = 0.3771 Length = 1.5 ) 69 | M06 T12 70 | M08 71 | S12000 M03 72 | 73 | S5000 M03 74 | M3 S#1243 75 | 76 | M3 S[1234 / #123] 77 | 78 | G41 D02 79 | 80 | #3004=0 81 | #28=0(LOOP CHECKING) 82 | WHILE[ABS[#5+7.]]LT0.1]D02(WAIT FOR OPCODE) 83 | G02X#[#31+10.] 84 | #28=#28+1 85 | IF[#28 LT 5000] GOTO300 86 | #33=78 87 | N300 88 | END2 89 | E.#234 90 | E#234 91 | 92 | F[#123/2] 93 | 94 | X[#234 / 2] 95 | 96 | G04 P1. 97 | G04 P.5 98 | G04 P500 99 | 100 | IF[#898EQ#996]GOTO19999 101 | 102 | IF [123 LE ABS[#452 + 1234]] THEN 103 | (SOMETHING) 104 | ELSE 105 | (SOMETHING ELSE) 106 | ENDIF 107 | 108 | WHILE [#123 LT 7.5] DO 5 109 | (SOMETHING HERE) 110 | END 5 111 | 112 | WHILE [#123 LT 7.5] DO5 113 | (SOMETHING HERE) 114 | END5 115 | 116 | #[#8 + 7.]=0 117 | 118 | G51 P[ #5 * 1000 ] 119 | 120 | #101 = FIX[ #1 MOD 1000 ] 121 | 122 | G65 P5000 A1. B2. C3. 123 | 124 | M09 125 | 126 | (POCKET SLOTS) 127 | (Tool Diameter = 0.3771 Length = 1.5 ) 128 | G20 T1 M06 129 | M08 130 | S12000 M03 131 | 132 | M97 P1000 133 | 134 | T13 M6 135 | 136 | M30 137 | 138 | 139 | N1000 140 | ( LOCAL SUB PROGRAM) 141 | 142 | G00 X0. Y0. 143 | 144 | M6 T25 145 | 146 | M99 147 | 148 | 149 | 150 | 151 | % 152 | -------------------------------------------------------------------------------- /src/util/stateControl.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { ExtensionContext } from 'vscode'; 8 | import { constants } from './constants'; 9 | import { LocalStorageService, StorageLocations } from './localStorageService'; 10 | import { Logger } from './logger'; 11 | import { Version } from './version'; 12 | 13 | export interface IState extends Record { 14 | previousVersion: string; 15 | version: string; 16 | } 17 | 18 | export class StateControl { 19 | private defaults: IState = { 20 | previousVersion: '0.0.0', 21 | version: '0.0.0', 22 | }; 23 | 24 | private _state: IState; 25 | private _storageManager: LocalStorageService; 26 | 27 | constructor(context: ExtensionContext) { 28 | Logger.log('Starting Local Storage Service...'); 29 | this._storageManager = new LocalStorageService(context); 30 | this._state = this.getState(); 31 | } 32 | 33 | private getState(): IState { 34 | return this._storageManager.getValue(constants.configId, StorageLocations.Global) ?? this.defaults; 35 | } 36 | 37 | async deleteState(): Promise { 38 | await this._storageManager.deleteValue(constants.configId, StorageLocations.Global); 39 | } 40 | 41 | private async _writeState(): Promise { 42 | await this._storageManager.setValue(constants.configId, this._state, StorageLocations.Global); 43 | } 44 | 45 | getVersion(): Version { 46 | return new Version(this._state.version); 47 | } 48 | 49 | async updateVer(ver: Version | string): Promise { 50 | let newVer: Version; 51 | if (typeof ver === 'string') { 52 | newVer = new Version(ver); 53 | } else { 54 | newVer = ver; 55 | } 56 | 57 | this._state.previousVersion = this._state.version; 58 | this._state.version = newVer.getVersionAsString(); 59 | 60 | await this._writeState(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/util/version.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | export interface IVersion { 8 | major: number; 9 | minor: number; 10 | patch: number; 11 | } 12 | 13 | export type VersionCheck = -1 | 0 | 1; 14 | 15 | export class Version { 16 | private _version: IVersion; 17 | 18 | constructor(ver: IVersion | string) { 19 | if (typeof ver === 'string') { 20 | this._version = this.parseVer(ver); 21 | } else { 22 | this._version = ver; 23 | } 24 | } 25 | 26 | private parseVer(stringVer: string): IVersion { 27 | const [major, minor, patch] = stringVer.split('.'); 28 | return { 29 | major: parseInt(major, 10), 30 | minor: parseInt(minor, 10), 31 | patch: patch == null ? 0 : parseInt(patch, 10), 32 | }; 33 | } 34 | 35 | getVersion(): IVersion { 36 | return this._version; 37 | } 38 | 39 | getVersionAsString(): string { 40 | return `${this._version.major}.${this._version.minor}.${this._version.patch}`; 41 | } 42 | 43 | compareWith(ver: IVersion | string): VersionCheck { 44 | // Compare Versions 45 | if (typeof ver === 'string') { 46 | ver = this.parseVer(ver); 47 | } 48 | 49 | // Check Major Version 50 | if (this._version.major > ver.major) { 51 | return 1; 52 | } 53 | 54 | if (this._version.major < ver.major) { 55 | return -1; 56 | } 57 | 58 | // Check Minor Version 59 | if (this._version.minor > ver.minor) { 60 | return 1; 61 | } 62 | 63 | if (this._version.minor < ver.minor) { 64 | return -1; 65 | } 66 | 67 | // Check Patch Version 68 | if (this._version.patch > ver.patch) { 69 | return 1; 70 | } 71 | 72 | if (this._version.patch < ver.patch) { 73 | return -1; 74 | } 75 | 76 | // Versions are Equal 77 | return 0; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/webviews/apps/shared/scss/vscode.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --container-paddding: 20px; 3 | --input-padding-vertical: 6px; 4 | --input-padding-horizontal: 4px; 5 | --input-margin-vertical: 4px; 6 | --input-margin-horizontal: 0; 7 | } 8 | 9 | body { 10 | padding: 0 var(--container-paddding); 11 | color: var(--vscode-foreground); 12 | font-size: var(--vscode-font-size); 13 | font-weight: var(--vscode-font-weight); 14 | font-family: var(--vscode-font-family); 15 | background-color: var(--vscode-editor-background); 16 | } 17 | 18 | ol, 19 | ul { 20 | padding-left: var(--container-paddding); 21 | } 22 | 23 | body > *, 24 | form > * { 25 | margin-block-start: var(--input-margin-vertical); 26 | margin-block-end: var(--input-margin-vertical); 27 | } 28 | 29 | *:focus { 30 | outline-color: var(--vscode-focusBorder) !important; 31 | } 32 | 33 | a { 34 | color: var(--vscode-textLink-foreground); 35 | } 36 | 37 | a:hover, 38 | a:active { 39 | color: var(--vscode-textLink-activeForeground); 40 | } 41 | 42 | code { 43 | font-size: var(--vscode-editor-font-size); 44 | font-family: var(--vscode-editor-font-family); 45 | } 46 | 47 | button { 48 | border: none; 49 | padding: var(--input-padding-vertical) var(--input-padding-horizontal); 50 | width: 100%; 51 | text-align: center; 52 | outline: 1px solid transparent; 53 | outline-offset: 2px !important; 54 | color: var(--vscode-button-foreground); 55 | background: var(--vscode-button-background); 56 | } 57 | 58 | button:hover { 59 | cursor: pointer; 60 | background: var(--vscode-button-hoverBackground); 61 | } 62 | 63 | button:focus { 64 | outline-color: var(--vscode-focusBorder); 65 | } 66 | 67 | button.secondary { 68 | color: var(--vscode-button-secondaryForeground); 69 | background: var(--vscode-button-secondaryBackground); 70 | } 71 | 72 | button.secondary:hover { 73 | background: var(--vscode-button-secondaryHoverBackground); 74 | } 75 | 76 | input:not([type='checkbox']), 77 | textarea { 78 | display: block; 79 | width: 100%; 80 | border: none; 81 | font-family: var(--vscode-font-family); 82 | padding: var(--input-padding-vertical) var(--input-padding-horizontal); 83 | color: var(--vscode-input-foreground); 84 | outline-color: var(--vscode-input-border); 85 | background-color: var(--vscode-input-background); 86 | } 87 | 88 | input::placeholder, 89 | textarea::placeholder { 90 | color: var(--vscode-input-placeholderForeground); 91 | } -------------------------------------------------------------------------------- /src/util/localStorageService.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | export const enum StorageLocations { 8 | Global = 'global', 9 | WorkSpace = 'workspace', 10 | } 11 | 12 | export type StorageLocation = StorageLocations; 13 | 14 | import { ExtensionContext, Memento } from 'vscode'; 15 | import { Logger } from './logger'; 16 | 17 | export class LocalStorageService { 18 | private _wsState: Memento; 19 | private _globalState: Memento; 20 | 21 | constructor(private readonly context: ExtensionContext) { 22 | this._wsState = context.workspaceState; 23 | this._globalState = context.globalState; 24 | } 25 | 26 | public getValue(key: string, loc: StorageLocation): T | undefined { 27 | if (loc === StorageLocations.WorkSpace) { 28 | return this._wsState.get(key); 29 | } else { 30 | return this._globalState.get(key); 31 | } 32 | } 33 | 34 | public async setValue(key: string, value: T, loc: StorageLocation): Promise { 35 | if (loc === StorageLocations.WorkSpace) { 36 | try { 37 | await this._wsState.update(key, value); 38 | } catch (reason) { 39 | Logger.error(reason); 40 | } 41 | } else { 42 | try { 43 | await this._globalState.update(key, value); 44 | } catch (reason) { 45 | Logger.error(reason); 46 | } 47 | } 48 | } 49 | 50 | public async deleteValue(key: string, loc: StorageLocation): Promise { 51 | if (loc === StorageLocations.WorkSpace) { 52 | try { 53 | await this._wsState.update(key, undefined); 54 | } catch (reason) { 55 | Logger.error(reason); 56 | } 57 | } else { 58 | try { 59 | await this._globalState.update(key, undefined); 60 | } catch (reason) { 61 | Logger.error(reason); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /resources/icons/dark/workoffset.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/workoffset.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/util/configuration/config.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unsafe-member-access */ 2 | /* eslint-disable @typescript-eslint/no-unsafe-assignment */ 3 | /* --------------------------------------------------------------------------------------------- 4 | * Copyright (c) Applied Eng & Design All rights reserved. 5 | * Licensed under the MIT License. See License.md in the project root for license information. 6 | * -------------------------------------------------------------------------------------------- */ 7 | 'use strict'; 8 | import { ConfigurationChangeEvent, ConfigurationScope, Event, EventEmitter, ExtensionContext, workspace } from 'vscode'; 9 | import { constants } from '../constants'; 10 | import { Logger } from '../logger'; 11 | import { GCodeConfiguration } from './defaults'; 12 | 13 | export class Config { 14 | private static _defaults: GCodeConfiguration; 15 | private _onDidChange = new EventEmitter(); 16 | get onDidChange(): Event { 17 | return this._onDidChange.event; 18 | } 19 | 20 | static initialize(context: ExtensionContext, cfg: Config) { 21 | context.subscriptions.push(workspace.onDidChangeConfiguration(cfg.onConfigurationChanged, cfg)); 22 | } 23 | 24 | private onConfigurationChanged(e: ConfigurationChangeEvent) { 25 | Logger.log('Configuration changed...'); 26 | 27 | this._onDidChange.fire(e); 28 | } 29 | 30 | getParam(param: string, scope?: ConfigurationScope, defaultValue?: T): T | undefined { 31 | return defaultValue === undefined 32 | ? workspace.getConfiguration(constants.configId, scope).get(param) 33 | : workspace.getConfiguration(constants.configId, scope).get(param, defaultValue); 34 | } 35 | 36 | // Set Parameter 37 | async setParam(param: string, value: any, global = true, scope?: ConfigurationScope): Promise { 38 | try { 39 | await workspace.getConfiguration(constants.configId, scope).update(param, value, global); 40 | } catch (err) { 41 | Logger.log('Error updating configuration'); 42 | return false; 43 | } 44 | 45 | return this.getParam(param) === value; 46 | } 47 | 48 | changed(e: ConfigurationChangeEvent, section: string, scope?: ConfigurationScope): boolean { 49 | return e.affectsConfiguration(`${constants.configId}.${section}`, scope) ?? true; 50 | } 51 | } 52 | 53 | export const configuration = new Config(); 54 | -------------------------------------------------------------------------------- /resources/icons/dark/drill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/drill.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/hovers/gcodeHoverControl.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { ConfigurationChangeEvent, Disposable, languages, TextEditor, Uri, window } from 'vscode'; 8 | import { configuration } from '../util/configuration/config'; 9 | import { constants } from '../util/constants'; 10 | import { Logger } from '../util/logger'; 11 | import { GCodeHoverProvider } from './gcodeHoverProvider'; 12 | 13 | export class GCodeHoverControl implements Disposable { 14 | private readonly _disposable: Disposable; 15 | private _hoverProvider: Disposable | undefined; 16 | private _enabled: boolean; 17 | private _uri: Uri | undefined; 18 | 19 | constructor() { 20 | this._disposable = Disposable.from(configuration.onDidChange(this.onConfigurationChanged, this)); 21 | 22 | this._enabled = configuration.getParam('general.hovers.enabled'); 23 | 24 | if (this._enabled) { 25 | Logger.log('Hovers: Enabled'); 26 | this.register(window.activeTextEditor); 27 | } 28 | } 29 | 30 | dispose() { 31 | this.unregister(); 32 | this._disposable && this._disposable.dispose(); 33 | } 34 | 35 | private onConfigurationChanged(e: ConfigurationChangeEvent) { 36 | if (configuration.changed(e, 'general.hovers.enabled')) { 37 | if (this._enabled) { 38 | // Disable and Dispose 39 | Logger.log('Hovers: Disabled'); 40 | this.unregister(); 41 | } else { 42 | // Enable 43 | Logger.log('Hovers: Enabled'); 44 | this.register(window.activeTextEditor); 45 | } 46 | } 47 | } 48 | 49 | private unregister(): void { 50 | if (this._hoverProvider != null) { 51 | this._hoverProvider.dispose(); 52 | this._hoverProvider = undefined; 53 | } 54 | } 55 | 56 | private register(editor: TextEditor | undefined) { 57 | this.unregister(); 58 | 59 | if (editor == null) { 60 | return; 61 | } 62 | 63 | if (this._enabled) { 64 | this._hoverProvider = Disposable.from( 65 | languages.registerHoverProvider({ language: constants.langId }, new GCodeHoverProvider()), 66 | ); 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /resources/icons/light/engraving.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/engraving.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/util/quickpicks/lineNumbers.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { configuration } from '../configuration/config'; 9 | import { defaults } from '../configuration/defaults'; 10 | import { GQuickPick } from './common'; 11 | 12 | interface State { 13 | title: string; 14 | step: number; 15 | totalSteps: number; 16 | start: number; 17 | increment: number; 18 | } 19 | 20 | const title = 'Line Number Options'; 21 | 22 | export class LineNumbersInput extends GQuickPick { 23 | private readonly _state; 24 | 25 | constructor() { 26 | // Multi-Step 27 | super(true); 28 | 29 | this._state = {} as Partial; 30 | } 31 | 32 | async collect() { 33 | await this.run(() => this.enterStart()); 34 | return this._state as State; 35 | } 36 | 37 | private async enterStart() { 38 | this._state.start = +(await this.showMultiInputBox({ 39 | title, 40 | step: 1, 41 | totalSteps: 2, 42 | value: ( 43 | configuration.getParam('lineNumberer.defaultStart') ?? defaults.lineNumberer.defaultStart 44 | ).toString(), 45 | prompt: 'Choose Start Number', 46 | validate: this.validate, 47 | shouldResume: this.shouldResume, 48 | })); 49 | 50 | return () => this.enterIncrement(); 51 | } 52 | 53 | private async enterIncrement() { 54 | this._state.increment = +(await this.showMultiInputBox({ 55 | title, 56 | step: 2, 57 | totalSteps: 2, 58 | value: ( 59 | configuration.getParam('lineNumberer.defaultIncrement') ?? 60 | defaults.lineNumberer.defaultIncrement 61 | ).toString(), 62 | prompt: 'Choose Increment Number', 63 | validate: this.validate, 64 | shouldResume: this.shouldResume, 65 | })); 66 | } 67 | 68 | protected validate(_value: number | string): Promise { 69 | if (typeof _value === 'string') { 70 | _value = +_value; 71 | } 72 | 73 | if (isNaN(_value)) { 74 | return Promise.resolve('Value is not a number'); 75 | } else if (_value < 1) { 76 | return Promise.resolve('Number must be greater than zero.'); 77 | } else { 78 | return Promise.resolve(undefined); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/util/configuration/defaults.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { StatusBarAlignment } from 'vscode'; 9 | import { GCodeUnits } from '../constants'; 10 | import { LineNumbererOptions, LineNumberFrequency } from '../lineNumberer'; 11 | import { MachineType, MachineTypes } from '@appliedengdesign/gcode-reference'; 12 | 13 | export enum TraceLevel { 14 | Silent = 'silent', 15 | Errors = 'errors', 16 | Warnings = 'warnings', 17 | Verbose = 'verbose', 18 | Debug = 'debug', 19 | } 20 | 21 | export interface GCodeConfiguration { 22 | general: { 23 | machineType: MachineType; 24 | 25 | hovers: { 26 | enabled: boolean; 27 | }; 28 | 29 | statusBars: { 30 | enabled: boolean; 31 | alignment: StatusBarAlignment; 32 | }; 33 | 34 | units: GCodeUnits; 35 | 36 | outputLevel: TraceLevel; 37 | }; 38 | 39 | lineNumberer: LineNumbererOptions; 40 | 41 | views: { 42 | maxAutoRefresh: number; 43 | 44 | navTree: { 45 | autoRefresh: boolean; 46 | }; 47 | 48 | stats: { 49 | autoRefresh: boolean; 50 | }; 51 | }; 52 | 53 | webviews: { 54 | calc: { 55 | enabled: boolean; 56 | }; 57 | }; 58 | } 59 | 60 | export const defaults: GCodeConfiguration = { 61 | general: { 62 | machineType: MachineTypes.Mill, 63 | hovers: { 64 | enabled: true, 65 | }, 66 | statusBars: { 67 | enabled: true, 68 | alignment: StatusBarAlignment.Left, 69 | }, 70 | units: GCodeUnits.Auto, 71 | outputLevel: TraceLevel.Verbose, 72 | }, 73 | lineNumberer: { 74 | addSpaceAfter: true, 75 | defaultIncrement: 10, 76 | defaultStart: 10, 77 | enableQuickPick: true, 78 | frequency: LineNumberFrequency.EveryLine, 79 | ignoreBlank: true, 80 | ignoreComments: true, 81 | ignoreExtra: [], 82 | ignoreProgramNumbers: true, 83 | matchLineNumber: false, 84 | showProgress: true, 85 | }, 86 | views: { 87 | maxAutoRefresh: 10000, 88 | navTree: { 89 | autoRefresh: true, 90 | }, 91 | stats: { 92 | autoRefresh: false, 93 | }, 94 | }, 95 | webviews: { 96 | calc: { 97 | enabled: true, 98 | }, 99 | }, 100 | }; 101 | -------------------------------------------------------------------------------- /resources/icons/dark/coolanton.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/coolanton.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/drill-dwell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/drill-dwell.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/util/machineTypeController.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { ConfigurationChangeEvent, Disposable, Event, EventEmitter } from 'vscode'; 8 | import { GReference, MachineType, MachineTypes } from '@appliedengdesign/gcode-reference'; 9 | import { configuration } from './configuration/config'; 10 | import { Logger } from './logger'; 11 | import { StatusBar, StatusBarControl } from './statusBar'; 12 | import { Control } from '../control'; 13 | import { GCommands } from './constants'; 14 | import { defaults } from './configuration/defaults'; 15 | 16 | export class MachineTypeController implements Disposable { 17 | private readonly _dispoables: Disposable[] = []; 18 | private _machineType: MachineType = defaults.general.machineType; 19 | private _statusbar: StatusBarControl; 20 | private readonly mtypeStatusBar: StatusBar = 'machineTypeBar'; 21 | private _gReference: GReference; 22 | 23 | private _onDidChangeMachineType: EventEmitter = new EventEmitter(); 24 | get onDidChangeMachineType(): Event { 25 | return this._onDidChangeMachineType.event; 26 | } 27 | 28 | constructor() { 29 | this._statusbar = Control.statusBarController; 30 | this._gReference = new GReference(); 31 | this._update(); 32 | 33 | this._dispoables.push(configuration.onDidChange(this._onConfigurationChanged, this)); 34 | } 35 | 36 | dispose() { 37 | Disposable.from(...this._dispoables).dispose(); 38 | } 39 | 40 | private _onConfigurationChanged(e: ConfigurationChangeEvent) { 41 | if (configuration.changed(e, 'general.machineType')) { 42 | this._update(); 43 | } else { 44 | return; 45 | } 46 | } 47 | 48 | private _update() { 49 | const cfgMachineType = configuration.getParam('general.machineType') ?? defaults.general.machineType; 50 | Logger.log(`Machine Type: ${cfgMachineType}`); 51 | switch (cfgMachineType) { 52 | case 'Mill': 53 | this._machineType = MachineTypes.Mill; 54 | break; 55 | 56 | case 'Lathe': 57 | this._machineType = MachineTypes.Lathe; 58 | break; 59 | 60 | case '3D Printer': 61 | this._machineType = MachineTypes.Printer; 62 | break; 63 | 64 | case 'Swiss': 65 | this._machineType = MachineTypes.Swiss; 66 | break; 67 | 68 | case 'Laser': 69 | this._machineType = MachineTypes.Laser; 70 | break; 71 | 72 | case 'EDM': 73 | this._machineType = MachineTypes.EDM; 74 | break; 75 | 76 | default: 77 | return; 78 | } 79 | 80 | // Update Status Bar 81 | this._statusbar.updateStatusBar( 82 | cfgMachineType, 83 | this.mtypeStatusBar, 84 | undefined, 85 | undefined, 86 | GCommands.ShowGCodeSettings, 87 | ); 88 | 89 | // Update GReference 90 | this._gReference.setType(this._machineType); 91 | 92 | // Fire Event 93 | this._onDidChangeMachineType.fire(this._machineType); 94 | } 95 | 96 | get gReference() { 97 | return this._gReference; 98 | } 99 | 100 | get machineType() { 101 | return this._machineType; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /src/webviews/gWebview.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable max-len */ 2 | /* eslint-disable @typescript-eslint/restrict-template-expressions */ 3 | /* --------------------------------------------------------------------------------------------- 4 | * Copyright (c) Applied Eng & Design All rights reserved. 5 | * Licensed under the MIT License. See License.md in the project root for license information. 6 | * -------------------------------------------------------------------------------------------- */ 7 | 'use strict'; 8 | 9 | import { 10 | Disposable, 11 | Uri, 12 | ViewColumn, 13 | Webview, 14 | WebviewOptions, 15 | WebviewPanel, 16 | WebviewPanelOnDidChangeViewStateEvent, 17 | window, 18 | } from 'vscode'; 19 | import { constants, WebviewCommands } from '../util/constants'; 20 | import { Control } from '../control'; 21 | 22 | export abstract class GWebview implements Disposable { 23 | protected _disposables: Disposable[] = []; 24 | private _panel: WebviewPanel | undefined; 25 | private _dPanel: Disposable | undefined; 26 | private _title: string; 27 | 28 | constructor( 29 | public readonly id: string, 30 | title: string, 31 | showCommand: WebviewCommands, 32 | private readonly _column?: ViewColumn, 33 | ) { 34 | this._title = title; 35 | this._disposables.push(...this.registerCommands()); 36 | } 37 | 38 | dispose() { 39 | Disposable.from(...this._disposables).dispose(); 40 | this._dPanel?.dispose(); 41 | } 42 | 43 | hide() { 44 | this._panel?.dispose(); 45 | } 46 | 47 | get visible() { 48 | return this._panel?.visible ?? false; 49 | } 50 | 51 | get title(): string { 52 | return this._panel?.title ?? this._title; 53 | } 54 | 55 | setTitle(title: string) { 56 | this._title = title; 57 | if (this._panel) { 58 | this._panel.title = title; 59 | } 60 | } 61 | 62 | private onPanelDisposed() { 63 | this._panel?.dispose(); 64 | this._panel = undefined; 65 | } 66 | 67 | private onViewStateChanged(e: WebviewPanelOnDidChangeViewStateEvent) { 68 | if (e.webviewPanel.active) { 69 | // View State Changed 70 | } 71 | } 72 | 73 | protected onShowCommand(): void { 74 | void this.show(); 75 | } 76 | 77 | async show(column: ViewColumn = ViewColumn.Beside): Promise { 78 | if (!this._panel) { 79 | this._panel = window.createWebviewPanel( 80 | this.id, 81 | this._title, 82 | { viewColumn: column, preserveFocus: false }, 83 | this.getWebviewOptions(), 84 | ); 85 | 86 | this._panel.iconPath = Uri.file(constants.gcodeIcon); 87 | 88 | this._dPanel = Disposable.from( 89 | this._panel, 90 | this._panel.onDidDispose(this.onPanelDisposed, this), 91 | this._panel.onDidChangeViewState(this.onViewStateChanged, this), 92 | ); 93 | 94 | this._panel.webview.html = await this.getHtml(this._panel.webview); 95 | } else { 96 | const html = await this.getHtml(this._panel.webview); 97 | 98 | this._panel.webview.html = ''; 99 | this._panel.webview.html = html; 100 | 101 | this._panel.reveal(this._panel.viewColumn ?? ViewColumn.Active, false); 102 | } 103 | } 104 | 105 | async refresh(): Promise { 106 | if (this._panel) { 107 | this._panel.webview.html = await this.getHtml(this._panel.webview); 108 | } 109 | } 110 | 111 | protected abstract getHtml(webview: Webview): Promise; 112 | protected abstract registerCommands(): Disposable[]; 113 | 114 | private getWebviewOptions(): WebviewOptions { 115 | return { 116 | enableScripts: true, 117 | enableCommandUris: true, 118 | localResourceRoots: [Uri.joinPath(Control.context.extensionUri)], 119 | }; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/util/messages.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | 8 | import { env, MessageItem, Uri, window } from 'vscode'; 9 | import { constants } from './constants'; 10 | import { Version } from './version'; 11 | 12 | enum MessageType { 13 | Info, 14 | Warn, 15 | Error, 16 | } 17 | 18 | export class Messages { 19 | static async showSupportGCodeMessage() { 20 | const actions: MessageItem[] = [ 21 | { title: 'Leave a Review' }, 22 | { title: 'Become a Sponsor' }, 23 | { title: 'Subscribe to our YouTube' }, 24 | ]; 25 | 26 | const result = await Messages._showMessage( 27 | MessageType.Info, 28 | 'G-Code Syntax is offered to everyone for free. If you find it useful, please consider ' + 29 | '[supporting](https://github.com/sponsors/appliedengdesign) it. Thank you! ❤', 30 | ...actions, 31 | ); 32 | 33 | if (result != null) { 34 | if (result === actions[0]) { 35 | await env.openExternal(Uri.parse(constants.urls.vsmpReviews)); 36 | } else if (result === actions[1]) { 37 | await env.openExternal(Uri.parse('https://github.com/sponsors/appliedengdesign')); 38 | } else if (result === actions[2]) { 39 | await env.openExternal(Uri.parse('https://youtube.com/c/AppliedEngDesignUSA')); 40 | } 41 | } 42 | } 43 | 44 | static async showWhatsNewMessage(ver: Version) { 45 | const actions: MessageItem[] = [{ title: "What's New" }, { title: '❤' }]; 46 | 47 | const result = await Messages._showMessage( 48 | MessageType.Info, 49 | `G-Code Syntax has been updated to v${ver.getVersionAsString()} - Check out what's new!`, 50 | ...actions, 51 | ); 52 | 53 | if (result != null) { 54 | if (result === actions[0]) { 55 | await env.openExternal(Uri.parse(constants.urls.changeLog)); 56 | } else if (result === actions[1]) { 57 | await env.openExternal(Uri.parse('https://github.com/sponsors/appliedengdesign')); 58 | } 59 | } 60 | } 61 | 62 | static async showRefreshWarningMessage(): Promise { 63 | // Show Warning message about large file refresh 64 | 65 | const actions: MessageItem[] = [{ title: 'Continue' }, { title: 'Abort' }]; 66 | 67 | const result = await Messages._showMessage( 68 | MessageType.Warn, 69 | 'File size is above 10K lines. Tree / Stats refresh may not work.', 70 | ...actions, 71 | ); 72 | 73 | if (result != null) { 74 | if (result === actions[0]) { 75 | return true; 76 | } else { 77 | return false; 78 | } 79 | } else { 80 | return false; 81 | } 82 | } 83 | 84 | static async showErrorMessage(msg: string) { 85 | await this._showMessage(MessageType.Error, msg); 86 | } 87 | 88 | private static async _showMessage( 89 | type: MessageType, 90 | msg: string, 91 | ...actions: MessageItem[] 92 | ): Promise { 93 | let result: MessageItem | undefined = undefined; 94 | 95 | switch (type) { 96 | case MessageType.Info: 97 | result = await window.showInformationMessage(msg, ...actions); 98 | break; 99 | 100 | case MessageType.Warn: 101 | result = await window.showWarningMessage(msg, ...actions); 102 | break; 103 | 104 | case MessageType.Error: 105 | result = await window.showErrorMessage(msg, ...actions); 106 | } 107 | 108 | return result; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/util/constants.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-unsafe-member-access */ 2 | /* eslint-disable @typescript-eslint/no-unsafe-assignment */ 3 | /* --------------------------------------------------------------------------------------------- 4 | * Copyright (c) Applied Eng & Design All rights reserved. 5 | * Licensed under the MIT License. See License.md in the project root for license information. 6 | * -------------------------------------------------------------------------------------------- */ 7 | 'use strict'; 8 | 9 | import * as path from 'path'; 10 | import { extensions } from 'vscode'; 11 | 12 | const publisher = 'appliedengdesign'; 13 | const extensionId = 'vscode-gcode-syntax'; 14 | const extensionQualifiedId = `${publisher}.${extensionId}`; 15 | 16 | const gcode = extensions.getExtension(extensionQualifiedId)!; 17 | 18 | interface IConstants { 19 | readonly configId: string; 20 | readonly copyright: string; 21 | readonly extension: { 22 | readonly name: string; 23 | readonly version: string; 24 | readonly shortname: string; 25 | }; 26 | readonly extensionOutputChannelName: string; 27 | readonly extensionQualifiedId: string; 28 | readonly gcodeIcon: string; 29 | readonly iconsPath: string; 30 | readonly iconExt: string; 31 | readonly langId: string; 32 | readonly urls: { 33 | readonly changeLog: string; 34 | readonly readme: string; 35 | readonly vsmpReviews: string; 36 | }; 37 | } 38 | 39 | export const constants: IConstants = { 40 | configId: gcode.packageJSON.contributes.languages[0].id, 41 | copyright: gcode.packageJSON.copyright, 42 | extension: { 43 | name: gcode.packageJSON.displayName, 44 | version: gcode.packageJSON.version, 45 | shortname: gcode.packageJSON.shortName, 46 | }, 47 | extensionOutputChannelName: gcode.packageJSON.shortName, 48 | extensionQualifiedId: extensionQualifiedId, 49 | gcodeIcon: path.join(__dirname, '..', 'resources', 'icons', 'gcode.svg'), 50 | iconsPath: path.join(__dirname, '..', 'resources', 'icons'), 51 | iconExt: '.svg', 52 | langId: gcode.packageJSON.contributes.languages[0].id, 53 | urls: { 54 | changeLog: 'https://github.com/appliedengdesign/vscode-gcode-syntax/blob/master/CHANGELOG.md', 55 | readme: 'https://github.com/appliedengdesign/vscode-gcode-syntax/blob/master/README.md', 56 | vsmpReviews: 57 | 'https://marketplace.visualstudio.com/items?' + 58 | 'itemName=appliedengdesign.vscode-gcode-syntax&ssr=false#review-details', 59 | }, 60 | } as const; 61 | 62 | export enum PIcon { 63 | Alert = ' $(alert) ', 64 | Check = ' $(check) ', 65 | Heart = ' $(heart) ', 66 | } 67 | 68 | export enum VSBuiltInCommands { 69 | OpenSettings = 'workbench.action.openSettings', 70 | SetContext = 'setContext', 71 | } 72 | 73 | export enum Contexts { 74 | MachineType = 'gcode:general:machineType', 75 | ViewsNavTreeEnabled = 'gcode:views:navTree:enabled', 76 | ViewsStatsEnabled = 'gcode:views:stats:enabled', 77 | CalcWebviewViewEnabled = 'gcode:webviews:calc:enabled', 78 | } 79 | 80 | export enum GCodeUnits { 81 | Auto = 'Auto', 82 | Inch = 'Inch', 83 | MM = 'Metric', 84 | Default = 'Default (Inch)', 85 | } 86 | 87 | export enum GCommands { 88 | ShowGCodeSettings = 'gcode.showSettings', 89 | ShowSupportGCode = 'gcode.supportGCode', 90 | AddComment = 'gcode.addComment', 91 | RemoveComment = 'gcode.removeComment', 92 | AddLineNumbers = 'gcode.addLineNumbers', 93 | RemoveLineNumbers = 'gcode.removeLineNumbers', 94 | } 95 | 96 | export enum Webviews { 97 | CalcWebviewView = 'gcode.webviews.calc', 98 | } 99 | 100 | export enum WebviewTitles { 101 | CalcWebviewView = 'Machining Calculators', 102 | } 103 | 104 | export enum ViewCommands { 105 | RefreshStats = 'gcode.views.stats.refresh', 106 | RefreshTree = 'gcode.views.navTree.refresh', 107 | TreeSelect = 'gcode.views.navTree.select', 108 | } 109 | 110 | export enum WebviewCommands { 111 | ShowCodesWebview = 'gcode.webviews.codes.show', 112 | ShowCalcWebview = 'gcode.webviews.calc.show', 113 | } 114 | -------------------------------------------------------------------------------- /src/views/nodes/nodes.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { Command, ThemeIcon, TreeItem, TreeItemCollapsibleState, Uri } from 'vscode'; 8 | import { StatsNode } from './statsNode'; 9 | import { NavTreeNode } from './navTreeNode'; 10 | 11 | export const enum ResourceType { 12 | Stats = 'gcode:stats', 13 | Tree = 'gcode:navTree', 14 | } 15 | 16 | export const enum IconType { 17 | Boring = 'boring', 18 | Cutting = 'cutting', 19 | CWCutting = 'cwcutting', 20 | CCWCutting = 'ccwcutting', 21 | CoolantOn = 'coolanton', 22 | CoolantOff = 'coolantoff', 23 | Dwell = 'dwell', 24 | Drill = 'drill', 25 | DrillDwell = 'drill-dwell', 26 | DrillPeck = 'drill-peck', 27 | Engraving = 'engraving', 28 | ExtSubProgram = 'extsubprog', 29 | LocalSub = 'localsubprog', 30 | Rapid = 'rapid', 31 | SubProgramReturn = 'subprogreturn', 32 | SpindleCW = 'spindlecw', 33 | SpindleCCW = 'spindleccw', 34 | Stop = 'stop', 35 | TappingRH = 'tapping-rh', 36 | TappingLH = 'tapping-lh', 37 | ToolChange = 'toolchange', 38 | WorkOffset = 'workoffset', 39 | } 40 | 41 | export interface Node { 42 | setIcon(icon: IconType | undefined): void; 43 | getChildren(): ViewNode[] | Promise; 44 | getTreeItem(): TreeItem | Promise; 45 | getCommand(): Command | undefined; 46 | refresh?(): void | boolean | Promise | Promise; 47 | } 48 | 49 | export type NodeTypes = NavTreeNode | StatsNode; 50 | 51 | export abstract class ViewNode extends TreeItem implements Node { 52 | constructor( 53 | private _name: string, 54 | private _description?: string, 55 | private _contextValue?: ResourceType, 56 | private _collapsible?: TreeItemCollapsibleState, 57 | private _tooltip?: string, 58 | private _iconPath?: 59 | | string 60 | | Uri 61 | | { 62 | light: string | Uri; 63 | dark: string | Uri; 64 | } 65 | | ThemeIcon, 66 | protected readonly parent?: ViewNode, 67 | protected readonly _type?: NType, 68 | ) { 69 | super(_name); 70 | 71 | if (_description !== undefined) { 72 | this.description = _description; 73 | } 74 | 75 | if (_contextValue !== undefined) { 76 | this.contextValue = _contextValue; 77 | } 78 | 79 | if (_collapsible !== undefined) { 80 | this.collapsibleState = _collapsible; 81 | } 82 | 83 | if (_tooltip !== undefined) { 84 | this.tooltip = _tooltip; 85 | } 86 | 87 | if (_iconPath !== undefined) { 88 | this.iconPath = _iconPath; 89 | } 90 | } 91 | 92 | abstract setIcon(icon: IconType | undefined): void; 93 | 94 | getChildren(): ViewNode[] | Promise { 95 | return []; 96 | } 97 | 98 | getParent(): ViewNode | undefined { 99 | return this.parent; 100 | } 101 | 102 | abstract getTreeItem(): ViewNode | Promise; 103 | 104 | getCommand(): Command | undefined { 105 | return undefined; 106 | } 107 | 108 | refresh?(): void | boolean | Promise | Promise; 109 | 110 | update?(changes: { 111 | name?: string; 112 | desc?: string; 113 | tooltip?: string; 114 | iconPath?: 115 | | string 116 | | Uri 117 | | { 118 | light: string | Uri; 119 | dark: string | Uri; 120 | } 121 | | ThemeIcon; 122 | }) { 123 | if (changes.name !== undefined) { 124 | this._name = changes.name; 125 | } 126 | 127 | if (changes.desc !== undefined) { 128 | this._description = changes.desc; 129 | } 130 | 131 | if (changes.tooltip !== undefined) { 132 | this._tooltip = changes.tooltip; 133 | } 134 | 135 | if (changes.iconPath !== undefined) { 136 | this._iconPath = changes.iconPath; 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/views/gView.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { 8 | commands, 9 | ConfigurationChangeEvent, 10 | Disposable, 11 | Event, 12 | EventEmitter, 13 | TextDocumentChangeEvent, 14 | TextEditor, 15 | TreeDataProvider, 16 | TreeItem, 17 | TreeView, 18 | TreeViewVisibilityChangeEvent, 19 | window, 20 | workspace, 21 | } from 'vscode'; 22 | import { configuration } from '../util/configuration/config'; 23 | import { Logger } from '../util/logger'; 24 | import { NodeTypes, ViewNode } from './nodes/nodes'; 25 | 26 | export abstract class GView> implements TreeDataProvider, Disposable { 27 | protected _disposables: Disposable[] = []; 28 | protected _root: TRoot | undefined; 29 | protected _tree: TreeView | undefined; 30 | protected _editor: TextEditor | undefined; 31 | protected _autoRefresh: boolean | undefined; 32 | 33 | protected _onDidChangeTreeData: EventEmitter = new EventEmitter(); 34 | get onDidChangeTreeData(): Event { 35 | return this._onDidChangeTreeData.event; 36 | } 37 | 38 | private _onDidChangeVisibility: EventEmitter = 39 | new EventEmitter(); 40 | get onDidChangeVisibility(): Event { 41 | return this._onDidChangeVisibility.event; 42 | } 43 | 44 | protected abstract getRoot(): ViewNode | undefined; 45 | 46 | constructor(public readonly id: string, public readonly name: string) { 47 | this._disposables.push(...this.registerCommands()); 48 | } 49 | 50 | protected ensureRoot() { 51 | if (this._root === undefined) { 52 | this.getRoot(); 53 | } 54 | 55 | return this._root; 56 | } 57 | 58 | protected initialize(options: { showCollapseAll?: boolean } = {}) { 59 | this._tree = window.createTreeView(this.id, { 60 | ...options, 61 | treeDataProvider: this, 62 | }); 63 | 64 | this._disposables.push( 65 | configuration.onDidChange(this.onConfigurationChanged, this), 66 | window.onDidChangeActiveTextEditor(() => this.onActiveEditorChanged()), 67 | workspace.onDidChangeTextDocument(e => this.onDocumentChanged(e)), 68 | this._tree, 69 | this._tree.onDidChangeVisibility(this.onVisibilityChanged, this), 70 | ); 71 | } 72 | 73 | protected onVisibilityChanged(e: TreeViewVisibilityChangeEvent) { 74 | this._onDidChangeVisibility.fire(e); 75 | } 76 | 77 | get visible(): boolean { 78 | return this._tree?.visible ?? false; 79 | } 80 | 81 | protected async show(options?: { preserveFocus?: boolean }) { 82 | if (!this.visible) { 83 | try { 84 | void (await commands.executeCommand(`${this.id}.focus`, options)); 85 | } catch (err) { 86 | Logger.error(err, 'Error focusing view'); 87 | } 88 | } 89 | } 90 | 91 | dispose() { 92 | Disposable.from(...this._disposables).dispose(); 93 | } 94 | 95 | getTreeItem(element: ViewNode): TreeItem | Promise { 96 | return element; 97 | } 98 | 99 | getChildren(element?: ViewNode): ViewNode[] | Promise | undefined { 100 | if (element) { 101 | return element.getChildren(); 102 | } else { 103 | const root = this.ensureRoot(); 104 | return root?.getChildren(); 105 | } 106 | } 107 | 108 | getParent(element: ViewNode): ViewNode | undefined { 109 | return element.getParent(); 110 | } 111 | 112 | protected abstract registerCommands(): Disposable[]; 113 | 114 | protected abstract refresh(element?: ViewNode): void; 115 | 116 | protected abstract onConfigurationChanged(e: ConfigurationChangeEvent): void; 117 | 118 | protected abstract onActiveEditorChanged(): void; 119 | 120 | protected abstract onDocumentChanged(changeEvent: TextDocumentChangeEvent): void; 121 | } 122 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribute to VSCode GCode Syntax 2 | 3 | Thank you for your interest in contributing to the VSCode GCode Syntax project. Please note the [Code of Conduct](CODE_OF_CONDUCT.md) document and follow it in all of your interactions with this project. 4 | 5 | There are a variety of ways you can contribute to this project. 6 | 7 | - Help answer issues or questions on using the extension 8 | - Find Bugs and Fix them! 9 | - Work on new features! 10 | - Fix Typos! (I make a lot of them) 11 | - Edit Documentation 12 | 13 | Here are a couple guidelines to get you started... 14 | 15 | ## Getting Started 16 | 17 | To contribute to [VSCode GCode Syntax](https://github.com/appliedengdesign/vscode-gcode-syntax), you need to fork this repository and submit a pull request for any changes. 18 | 19 | - [How to fork a repository](https://help.github.com/articles/fork-a-repo) 20 | - [How to make a pull request](https://help.github.com/articles/creating-a-pull-request/) 21 | - [Changing a commit message](https://help.github.com/articles/changing-a-commit-message/) 22 | - [How to squash commits](https://help.github.com/articles/about-pull-request-merges/) 23 | 24 | Search open/closed issues before submitting any code changes because someone may have pushed the same code before. 25 | 26 | Please create an issue _before_ creating your pull request. 27 | 28 | ### Branches 29 | 30 | Create a local working branch that is specific to the scope of the changes that you want to make and then submit a pull request when your changes are ready. Each branch you create should be as specific as possible to streamline work flow and to reduce the possibility of merge conflicts. For instance, consider creating a branch to work on documentation or to fix a typo. 31 | 32 | ### Formatting 33 | 34 | This project contains an [`.editorconfig`](https://github.com/appliedengdesign/vscode-gcode-syntax/blob/main/.editorconfig) file. If your IDE or code editor doesn't natively support it, please install the [EditorConfig](https://editorconfig.org) plugin. 35 | 36 | This project uses [prettier](https://prettier.io/) for code formatting. You can run prettier across the code by calling `npm run pretty` from a terminal. 37 | 38 | To format the code as you make changes you can install the [Prettier - Code formatter](https://marketplace.visualstudio.com/items/esbenp.prettier-vscode) extension. 39 | 40 | Add the following to your User Settings to run prettier: 41 | 42 | `"editor.formatOnSave": true,` 43 | 44 | ### Linting 45 | 46 | This project uses [ESLint](https://eslint.org/) for code linting. You can run ESLint across the code by calling `npm run lint` from a terminal. Warnings from ESLint show up in the `Errors and Warnings` quick box and you can navigate to them from inside VS Code. 47 | 48 | To lint the code as you make changes you can install the [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) extension. 49 | 50 | ### Update the README 51 | 52 | If this is your first contribution to GCode Reference, please give yourself credit by adding yourself to the _Contributors_ section of the [README](README.md) in the following format: 53 | 54 | - `Your Name ([@(https://github.com/` 55 | 56 | ### Signing Your Commits 57 | 58 | This project requires that commits are GPG signed. This ensures that YOU are really the author of your commit, and the code is REALLY what you wrote. 59 | 60 | Check out this article: [How (and why) to sign Git commits](https://withblue.ink/2020/05/17/how-and-why-to-sign-git-commits.html) 61 | 62 | ### Authoring Tools 63 | 64 | [Visual Studio Code](https://code.visualstudio.com) is a preferred tool to work on this project. 65 | 66 | #### Recommended Extensions 67 | 68 | - [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) 69 | - [Prettier](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) 70 | 71 | ### Submitting a Pull Request 72 | 73 | Please follow all instructions in the [PR template](.github/PULL_REQUEST_TEMPLATE.md). 74 | 75 | - Push your changes to your branch in your fork of the repository. 76 | - Submit a pull request to the [master](https://github.com/appliedengdesign/master-syntax/tree/master) of the [vscode-gcode-syntax](https://github.com/appliedengdesign/vscode-gcode-syntax) respository. 77 | - Make sure to explicitly say not to complete pull request if you are still making changes. 78 | 79 | ## Additional Resources 80 | 81 | - [GitHub Docs](http://help.github.com/) 82 | - [GitHub Pull Request Docs](http://help.github.com/send-pull-requests/) 83 | - [Successful Git Branching Model](http://nvie.com/posts/a-successful-git-branching-model/) 84 | -------------------------------------------------------------------------------- /src/util/logger.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 6 | 'use strict'; 7 | import { ConfigurationChangeEvent, ExtensionContext, OutputChannel, window } from 'vscode'; 8 | import { configuration } from './configuration/config'; 9 | import { defaults, TraceLevel } from './configuration/defaults'; 10 | import { constants } from './constants'; 11 | 12 | /* Log Levels 13 | Silent - No Output 14 | Errors - Errors only 15 | Warnings - Warnings + Errors 16 | Verbose - Standard Outputs + Warnings + Errors 17 | Debug - Everything 18 | */ 19 | 20 | const configTraceLevel = 'general.outputLevel'; 21 | 22 | export class Logger { 23 | private static output: OutputChannel | undefined; 24 | private static _level: TraceLevel = TraceLevel.Verbose; 25 | 26 | static initialize(context: ExtensionContext, level?: TraceLevel) { 27 | this.level = level ?? this._level; 28 | this.output = this.output || window.createOutputChannel(constants.extensionOutputChannelName); 29 | 30 | context.subscriptions.push(configuration.onDidChange(this.onConfigurationChanged, this)); 31 | } 32 | 33 | private static onConfigurationChanged(e: ConfigurationChangeEvent) { 34 | if (configuration.changed(e, configTraceLevel)) { 35 | this.level = configuration.getParam(configTraceLevel) ?? defaults.general.outputLevel; 36 | } 37 | } 38 | 39 | static get level() { 40 | return this._level; 41 | } 42 | 43 | static set level(value: TraceLevel) { 44 | this._level = value; 45 | 46 | if (value === TraceLevel.Silent) { 47 | if (this.output != null) { 48 | this.close(); 49 | } 50 | } else { 51 | this.output = this.output ?? window.createOutputChannel(constants.extensionOutputChannelName); 52 | } 53 | } 54 | 55 | static enable() { 56 | if (this.output === undefined) { 57 | return; 58 | } 59 | 60 | this.output.show(); 61 | } 62 | 63 | static debug(message: string): void { 64 | if ( 65 | this.level === TraceLevel.Silent || 66 | this.level === TraceLevel.Errors || 67 | this.level === TraceLevel.Warnings || 68 | this.level === TraceLevel.Verbose 69 | ) { 70 | return; 71 | } 72 | 73 | if (this.output !== undefined) { 74 | this.output.appendLine(message); 75 | } 76 | } 77 | 78 | static log(message: string): void { 79 | if ( 80 | this.level === TraceLevel.Silent || 81 | this.level === TraceLevel.Errors || 82 | this.level === TraceLevel.Warnings 83 | ) { 84 | return; 85 | } 86 | 87 | if (this.output !== undefined) { 88 | this.output.appendLine(`${this.level === TraceLevel.Debug ? this.timestamp : ''} ${message}`); 89 | } 90 | } 91 | 92 | static warn(message: string): void { 93 | if (this.level === TraceLevel.Silent || this.level === TraceLevel.Errors) { 94 | return; 95 | } 96 | 97 | if (this.output !== undefined) { 98 | this.output.appendLine(message); 99 | } 100 | } 101 | 102 | static error(err: Error | unknown, message?: string): void { 103 | if (this.level === TraceLevel.Silent) { 104 | return; 105 | } 106 | 107 | if (message == null) { 108 | const stack = err instanceof Error ? err.stack : undefined; 109 | 110 | if (stack) { 111 | const match = /.*\s*?at\s(.+?)\s/.exec(stack); 112 | if (match != null) { 113 | message = match[1]; 114 | } 115 | } 116 | } 117 | 118 | if (this.output !== undefined) { 119 | this.output.appendLine( 120 | `${this.level === TraceLevel.Debug ? this.timestamp : ''} ${message ?? ''}\n${String(err)}`, 121 | ); 122 | } 123 | } 124 | 125 | static close() { 126 | if (this.output !== undefined) { 127 | this.output.dispose(); 128 | this.output = undefined; 129 | } 130 | } 131 | 132 | private static get timestamp(): string { 133 | const now = new Date(); 134 | return `[${now.toISOString().replace(/T/, ' ').replace(/\..+/, '')}:${`00${now.getUTCMilliseconds()}`.slice( 135 | -3, 136 | )}]`; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /resources/icons/dark/tapping-lh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/tapping-lh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/dark/tapping-rh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/light/tapping-rh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/webviews/gWebviewView.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { 8 | CancellationToken, 9 | commands, 10 | Disposable, 11 | Uri, 12 | Webview, 13 | WebviewOptions, 14 | WebviewView, 15 | WebviewViewProvider, 16 | WebviewViewResolveContext, 17 | window, 18 | } from 'vscode'; 19 | import { Control } from '../control'; 20 | import { Logger } from '../util/logger'; 21 | import { WebviewMsg } from './webviewMsg.types'; 22 | 23 | export abstract class GWebviewView implements WebviewViewProvider, Disposable { 24 | protected readonly _disposables: Disposable[] = []; 25 | protected _enabled: boolean | undefined; 26 | private _view: WebviewView | undefined; 27 | private _disposableView: Disposable | undefined; 28 | private _title: string; 29 | 30 | constructor(public readonly id: string, title: string) { 31 | this._title = title; 32 | 33 | this._disposables.push(window.registerWebviewViewProvider(id, this), ...(this.registerCommands?.() ?? [])); 34 | } 35 | 36 | dispose() { 37 | Disposable.from(...this._disposables).dispose(); 38 | this._disposableView?.dispose(); 39 | } 40 | 41 | isEnabled(): boolean { 42 | return this._enabled ?? false; 43 | } 44 | 45 | disable() { 46 | this._enabled = false; 47 | } 48 | 49 | get visible() { 50 | return this._view?.visible ?? false; 51 | } 52 | 53 | get title(): string { 54 | return this._view?.title ?? this._title; 55 | } 56 | 57 | set title(title: string) { 58 | this._title = title; 59 | if (this._view) { 60 | this._view.title = title; 61 | } 62 | } 63 | 64 | get description(): string | undefined { 65 | return this._view?.description; 66 | } 67 | 68 | set description(desc: string | undefined) { 69 | if (this._view) { 70 | this._view.description = desc; 71 | } 72 | } 73 | 74 | async show(options?: { preserveFocus?: boolean }) { 75 | try { 76 | void (await commands.executeCommand(`${this.id}.focus`), options); 77 | } catch (err) { 78 | Logger.error(err); 79 | } 80 | } 81 | 82 | async resolveWebviewView( 83 | webviewView: WebviewView, 84 | _context: WebviewViewResolveContext, 85 | _token: CancellationToken, 86 | ): Promise { 87 | this._view = webviewView; 88 | 89 | webviewView.webview.options = this.getWebviewOptions(); 90 | webviewView.title = this.title; 91 | 92 | this._disposableView = Disposable.from( 93 | this._view.onDidDispose(this.onViewDisposed, this), 94 | this._view.onDidChangeVisibility(this.onViewVisabilityChanged, this), 95 | this._view.webview.onDidReceiveMessage(this.onMessageReceived, this), 96 | ); 97 | 98 | await this.refresh(); 99 | } 100 | 101 | protected async refresh(): Promise { 102 | if (this._view) { 103 | this._view.webview.html = await this.getHtml(this._view.webview); 104 | } 105 | } 106 | 107 | protected abstract getHtml(webview: Webview): Promise; 108 | protected registerCommands?(): Disposable[]; 109 | protected handleMessage?(msg: WebviewMsg): void; 110 | protected bootstrap?(): WebviewMsg; 111 | 112 | protected getWebviewOptions(): WebviewOptions { 113 | return { 114 | enableScripts: true, 115 | enableCommandUris: true, 116 | localResourceRoots: [Uri.joinPath(Control.context.extensionUri)], 117 | }; 118 | } 119 | 120 | protected onMessageReceived(msg: WebviewMsg): void { 121 | if (msg) { 122 | this.handleMessage?.(msg); 123 | } else { 124 | return; 125 | } 126 | } 127 | 128 | protected async postMessage(msg: WebviewMsg) { 129 | if (this._view) { 130 | return await this._view.webview.postMessage(msg); 131 | } else { 132 | return Promise.resolve(false); 133 | } 134 | } 135 | 136 | private onViewDisposed() { 137 | this._disposableView?.dispose(); 138 | this._disposableView = undefined; 139 | this._view = undefined; 140 | } 141 | 142 | private async onViewVisabilityChanged() { 143 | const visable = this.visible; 144 | 145 | if (visable) { 146 | await this.refresh(); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "es2021": true, 4 | "node": true 5 | }, 6 | "extends": [ 7 | "eslint:recommended", 8 | "plugin:@typescript-eslint/recommended", 9 | "plugin:@typescript-eslint/recommended-requiring-type-checking", 10 | "plugin:import/errors", 11 | "plugin:import/warnings", 12 | "plugin:import/typescript", 13 | "prettier" 14 | ], 15 | "parser": "@typescript-eslint/parser", 16 | "parserOptions": { 17 | "ecmaVersion": 2021, 18 | "sourceType": "module", 19 | "ecmaFeatures": { 20 | "impliedStrict": true 21 | }, 22 | "project": "tsconfig.json" 23 | }, 24 | "plugins": [ 25 | "import", 26 | "@typescript-eslint", 27 | "prettier" 28 | ], 29 | "root": true, 30 | "rules": { 31 | "@typescript-eslint/explicit-module-boundary-types": "off", 32 | "@typescript-eslint/indent": "off", 33 | "@typescript-eslint/no-empty-function": [ 34 | "warn", 35 | { 36 | "allow": [ 37 | "constructors" 38 | ] 39 | } 40 | ], 41 | "@typescript-eslint/no-empty-interface": "error", 42 | "@typescript-eslint/no-explicit-any": "off", 43 | "@typescript-eslint/no-floating-promises": "error", 44 | "@typescript-eslint/no-inferrable-types": [ 45 | "warn", 46 | { 47 | "ignoreParameters": true, 48 | "ignoreProperties": true 49 | } 50 | ], 51 | "@typescript-eslint/no-namespace": "off", 52 | "@typescript-eslint/no-non-null-assertion": "off", 53 | "@typescript-eslint/no-unsafe-argument": "off", 54 | "@typescript-eslint/no-unused-vars": [ 55 | "warn", 56 | { 57 | "args": "after-used", 58 | "argsIgnorePattern": "^_", 59 | "ignoreRestSiblings": true, 60 | "varsIgnorePattern": "^_$" 61 | } 62 | ], 63 | "@typescript-eslint/no-use-before-define": "error", 64 | "@typescript-eslint/semi": "error", 65 | "@typescript-eslint/unbound-method": "off", 66 | "arrow-parens": [ 67 | "error", 68 | "as-needed" 69 | ], 70 | "brace-style": [ 71 | "warn", 72 | "1tbs", 73 | { 74 | "allowSingleLine": true 75 | } 76 | ], 77 | "comma-dangle": [ 78 | "error", 79 | "only-multiline" 80 | ], 81 | "complexity": "off", 82 | "curly": "error", 83 | "dot-notation": "error", 84 | "eqeqeq": [ 85 | "error", 86 | "smart" 87 | ], 88 | "eol-last": "error", 89 | "import/no-dynamic-require": "error", 90 | "import/no-default-export": "error", 91 | "import/no-duplicates": "error", 92 | "import/no-self-import": "error", 93 | "import/no-unresolved": [ 94 | "warn", 95 | { 96 | "ignore": [ 97 | "vscode" 98 | ] 99 | } 100 | ], 101 | "max-classes-per-file": [ 102 | "error", 103 | 1 104 | ], 105 | "max-len": [ 106 | "error", 107 | { 108 | "code": 120 109 | } 110 | ], 111 | "no-bitwise": "error", 112 | "no-console": [ 113 | "error", 114 | { 115 | "allow": [ 116 | "info", 117 | "error" 118 | ] 119 | } 120 | ], 121 | "no-duplicate-imports": "error", 122 | "no-inner-declarations": "off", 123 | "no-invalid-this": "error", 124 | "no-trailing-spaces": "error", 125 | "no-var": "error", 126 | "prefer-arrow-callback": "error", 127 | "prefer-const": "error", 128 | "prefer-numeric-literals": "error", 129 | "prefer-object-spread": "error", 130 | "prefer-rest-params": "error", 131 | "prefer-spread": "error", 132 | "prefer-template": "error", 133 | "prettier/prettier": "error", 134 | "quotes": [ 135 | "error", 136 | "single", 137 | { 138 | "avoidEscape": true 139 | } 140 | ], 141 | "radix": "error", 142 | "semi": [ 143 | "error", 144 | "always" 145 | ], 146 | "semi-style": [ 147 | "error", 148 | "last" 149 | ], 150 | "spaced-comment": [ 151 | "error", 152 | "always" 153 | ], 154 | "space-in-parens": [ 155 | "error", 156 | "never" 157 | ], 158 | "sort-imports": [ 159 | "error", 160 | { 161 | "ignoreCase": true, 162 | "ignoreDeclarationSort": true, 163 | "ignoreMemberSort": false, 164 | "memberSyntaxSortOrder": [ 165 | "none", 166 | "all", 167 | "multiple", 168 | "single" 169 | ] 170 | } 171 | ], 172 | "yoda": "error" 173 | } 174 | } -------------------------------------------------------------------------------- /src/util/statusBar.ts: -------------------------------------------------------------------------------- 1 | /* --------------------------------------------------------------------------------------------- 2 | * Copyright (c) Applied Eng & Design All rights reserved. 3 | * Licensed under the MIT License. See License.md in the project root for license information. 4 | * -------------------------------------------------------------------------------------------- */ 5 | 'use strict'; 6 | 7 | import { ConfigurationChangeEvent, Disposable, StatusBarAlignment, StatusBarItem, ThemeColor, window } from 'vscode'; 8 | import { configuration } from './configuration/config'; 9 | import { defaults } from './configuration/defaults'; 10 | import { GCommands } from './constants'; 11 | import { Logger } from './logger'; 12 | 13 | export interface StatusBars { 14 | treeStatusBar?: StatusBarItem | undefined; 15 | unitsBar?: StatusBarItem | undefined; 16 | machineTypeBar?: StatusBarItem | undefined; 17 | support?: StatusBarItem | undefined; 18 | } 19 | 20 | export type StatusBar = keyof StatusBars; 21 | 22 | const sb = { 23 | enabled: 'general.statusBars.enabled', 24 | aligh: 'general.statusBars.alignment', 25 | }; 26 | 27 | export class StatusBarControl implements Disposable { 28 | private _enabled: boolean; 29 | private _align: StatusBarAlignment; 30 | private readonly _disposable: Disposable | undefined; 31 | 32 | // Status Bars 33 | private _statusBars: StatusBars; 34 | 35 | constructor() { 36 | this._disposable = Disposable.from(configuration.onDidChange(this.onConfigurationChanged, this)); 37 | 38 | this._enabled = configuration.getParam(sb.enabled) ?? defaults.general.statusBars.enabled; 39 | 40 | this._statusBars = { 41 | treeStatusBar: undefined, 42 | unitsBar: undefined, 43 | machineTypeBar: undefined, 44 | support: undefined, 45 | }; 46 | 47 | this._align = configuration.getParam(sb.aligh) ?? defaults.general.statusBars.alignment; 48 | 49 | if (this._enabled) { 50 | Logger.log('Loading Status Bars...'); 51 | 52 | Object.keys(this._statusBars).forEach(key => { 53 | this._statusBars[key as keyof StatusBars] = window.createStatusBarItem( 54 | this._align, 55 | (this._align = StatusBarAlignment.Left ? 1 : 999), 56 | ); 57 | }); 58 | 59 | this.showStatusBars(); 60 | } 61 | } 62 | 63 | dispose() { 64 | Object.keys(this._statusBars).forEach(key => { 65 | this._statusBars[key as keyof StatusBars]?.dispose(); 66 | }); 67 | 68 | this._disposable && this._disposable.dispose(); 69 | } 70 | 71 | private onConfigurationChanged(e: ConfigurationChangeEvent) { 72 | if (configuration.changed(e, sb.enabled)) { 73 | if (this._enabled) { 74 | // Disable & Dispose 75 | Object.keys(this._statusBars).forEach(key => { 76 | this._statusBars[key as keyof StatusBars]?.dispose(); 77 | }); 78 | } else { 79 | // Enable 80 | Object.keys(this._statusBars).forEach(key => { 81 | this._statusBars[key as keyof StatusBars] = window.createStatusBarItem( 82 | this._align, 83 | this._align === StatusBarAlignment.Left ? 1 : 999, 84 | ); 85 | }); 86 | 87 | this.showStatusBars(); 88 | } 89 | 90 | this._enabled = configuration.getParam(sb.enabled) ?? defaults.general.statusBars.enabled; 91 | 92 | this._align = configuration.getParam(sb.aligh) ?? defaults.general.statusBars.alignment; 93 | } else { 94 | return; 95 | } 96 | } 97 | 98 | updateStatusBar( 99 | message: string, 100 | bar: StatusBar, 101 | tooltip?: string, 102 | color?: string | ThemeColor, 103 | cmd?: GCommands | string, 104 | ): boolean { 105 | if (!this._enabled) { 106 | return false; 107 | } else { 108 | if (this._statusBars !== undefined && bar in this._statusBars) { 109 | // Set Text 110 | this._statusBars[bar]!.text = message; 111 | 112 | // Set Tooltip 113 | if (tooltip) { 114 | this._statusBars[bar]!.tooltip = tooltip; 115 | } else { 116 | this._statusBars[bar]!.tooltip = undefined; 117 | } 118 | 119 | // Set Color 120 | if (color) { 121 | this._statusBars[bar]!.color = color; 122 | } else { 123 | this._statusBars[bar]!.color = undefined; 124 | } 125 | 126 | // Set Command 127 | if (cmd) { 128 | this._statusBars[bar]!.command = cmd; 129 | } else { 130 | this._statusBars[bar]!.command = undefined; 131 | } 132 | 133 | // Show Bars 134 | this.showStatusBars(); 135 | 136 | return true; 137 | } else { 138 | return false; 139 | } 140 | } 141 | } 142 | 143 | showStatusBars() { 144 | Object.keys(this._statusBars).forEach(key => { 145 | this._statusBars[key as keyof StatusBars]?.show(); 146 | }); 147 | } 148 | 149 | hideStatusBars() { 150 | Object.keys(this._statusBars).forEach(key => { 151 | this._statusBars[key as keyof StatusBars]?.hide(); 152 | }); 153 | } 154 | } 155 | --------------------------------------------------------------------------------