mirror of
https://github.com/We-Dont-Byte/Mind_Reader.git
synced 2025-01-18 18:45:59 +00:00
Merge pull request #4 from We-Dont-Byte/merge-johnbreaux-thomaslane
Merge "merge-johnbreaux-thomaslane" into "master" This includes breaking changes! See pull request #4 for list of changes.
This commit is contained in:
commit
0a39522eca
15
.github/workflows/vscode-test.yaml
vendored
15
.github/workflows/vscode-test.yaml
vendored
@ -10,15 +10,22 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [macos-11, ubuntu-latest, windows-latest]
|
os:
|
||||||
|
- macos-11
|
||||||
|
- ubuntu-latest
|
||||||
|
- windows-latest
|
||||||
|
node_version:
|
||||||
|
- 16
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
- name: Install Node.js
|
- name: Install Node.js
|
||||||
uses: actions/setup-node@v1
|
uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
node-version: 10.x
|
node-version: ${{ matrix.node_version }}
|
||||||
|
cache: 'npm'
|
||||||
|
cache-dependency-path: '**/package-lock.json'
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: xvfb-run -a npm test
|
- run: xvfb-run -a npm test
|
||||||
if: runner.os == 'Linux'
|
if: runner.os == 'Linux'
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,4 +2,5 @@ out
|
|||||||
dist
|
dist
|
||||||
node_modules
|
node_modules
|
||||||
.vscode-test/
|
.vscode-test/
|
||||||
|
*.code-workspace
|
||||||
*.vsix
|
*.vsix
|
||||||
|
12
README.md
12
README.md
@ -3,7 +3,7 @@
|
|||||||
<img alt="Mind Reader Logo" src="media/logo.png"></img>
|
<img alt="Mind Reader Logo" src="media/logo.png"></img>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h1>Mind_Reader</h1>
|
<h1>Mind Reader</h1>
|
||||||
|
|
||||||
<!-- overview description -->
|
<!-- overview description -->
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ Python programming with LEGO Mindstorms. Our goal is to:
|
|||||||
<img width="50%" height="50%" alt="tools for native modules page with tool installation checked" src="media/nodejs_setup.png"></img>
|
<img width="50%" height="50%" alt="tools for native modules page with tool installation checked" src="media/nodejs_setup.png"></img>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
If the compiled serial port version is incompatible, you may see no options presented in the Mind_Reader actions panel:
|
If the compiled serial port version is incompatible, you may see no options presented in the Mind Reader actions panel:
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img width="50%" height="50%" alt="mind reader actions panel with no items:" src="media/missing_actions.png"></img>
|
<img width="50%" height="50%" alt="mind reader actions panel with no items:" src="media/missing_actions.png"></img>
|
||||||
@ -73,7 +73,7 @@ The electron version should be listed, e.g.: `Electron: 13.5.2`
|
|||||||
<img width="35%" height="35%" alt="vscode information" src="media/vscode_info.png"></img>
|
<img width="35%" height="35%" alt="vscode information" src="media/vscode_info.png"></img>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
### 3 Finding the Mind_Reader extension directory
|
### 3 Finding the Mind Reader extension directory
|
||||||
On MacOS and Linux this is `~/.vscode/extensions`.
|
On MacOS and Linux this is `~/.vscode/extensions`.
|
||||||
|
|
||||||
On Windows this is `C:\<YOUR USER>\.vscode\extensions\`. However, in Git Bash, it will appear like on MacOS and Linux
|
On Windows this is `C:\<YOUR USER>\.vscode\extensions\`. However, in Git Bash, it will appear like on MacOS and Linux
|
||||||
@ -81,7 +81,7 @@ e.g.: `~/.vscode/extensions`.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
Find the Mind_Reader extension folder, this should look like `xxx.mind-reader-x.x.x`.
|
Find the Mind Reader extension folder, this should look like `xxx.mind-reader-x.x.x`.
|
||||||
|
|
||||||
Navigate to the found folder in the terminal.
|
Navigate to the found folder in the terminal.
|
||||||
|
|
||||||
@ -102,8 +102,8 @@ $ electron-rebuild --version=ELECTRON_VERSION
|
|||||||
Use the following to set up the extension for development.
|
Use the following to set up the extension for development.
|
||||||
|
|
||||||
```console
|
```console
|
||||||
$ git clone https://github.com/SingleSemesterSnobs/Mind_Reader.git
|
$ git clone https://github.com/SingleSemesterSnobs/Mind Reader.git
|
||||||
$ cd Mind_Reader
|
$ cd Mind Reader
|
||||||
$ npm install
|
$ npm install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<body>
|
<body>
|
||||||
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT6a4XaqHkKcxJ6ZFms1RNrRurcOfl-diW90DAdpAx0Kv-rtrLJXovIhcUpayqFHATkrQ&usqp=CAU" width="600" />
|
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT6a4XaqHkKcxJ6ZFms1RNrRurcOfl-diW90DAdpAx0Kv-rtrLJXovIhcUpayqFHATkrQ&usqp=CAU" width="600" />
|
||||||
<p></p>
|
<p></p>
|
||||||
<h1>Welcome to Mind_Reader!</h1>
|
<h1>Welcome to Mind Reader!</h1>
|
||||||
<p>We are the Single Semester Snobs and this is our tool to Help Blind Students Program Lego Mindstorms Robots in Python.</p>
|
<p>We are the Single Semester Snobs and this is our tool to Help Blind Students Program Lego Mindstorms Robots in Python.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
|
42
package-lock.json
generated
42
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "mind-reader",
|
"name": "mind-reader",
|
||||||
"version": "0.0.1",
|
"version": "2.0.0",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "mind-reader",
|
"name": "mind-reader",
|
||||||
"version": "0.0.1",
|
"version": "2.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"serialport": "^9.2.5"
|
"serialport": "^9.2.5"
|
||||||
},
|
},
|
||||||
@ -26,7 +26,7 @@
|
|||||||
"vscode-test": "^1.5.2"
|
"vscode-test": "^1.5.2"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.60.0"
|
"vscode": "^1.66.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
@ -2101,9 +2101,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/minimist": {
|
"node_modules/minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
|
||||||
},
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
"version": "0.5.5",
|
"version": "0.5.5",
|
||||||
@ -2817,9 +2817,9 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"node_modules/simple-get": {
|
"node_modules/simple-get": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
|
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"decompress-response": "^4.2.0",
|
"decompress-response": "^4.2.0",
|
||||||
"once": "^1.3.1",
|
"once": "^1.3.1",
|
||||||
@ -3205,9 +3205,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/wide-align/node_modules/ansi-regex": {
|
"node_modules/wide-align/node_modules/ansi-regex": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
|
||||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
|
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw==",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
@ -4896,9 +4896,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
"integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.5",
|
"version": "0.5.5",
|
||||||
@ -5405,9 +5405,9 @@
|
|||||||
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
|
"integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q=="
|
||||||
},
|
},
|
||||||
"simple-get": {
|
"simple-get": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz",
|
||||||
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
|
"integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"decompress-response": "^4.2.0",
|
"decompress-response": "^4.2.0",
|
||||||
"once": "^1.3.1",
|
"once": "^1.3.1",
|
||||||
@ -5715,9 +5715,9 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.1.tgz",
|
||||||
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
"integrity": "sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw=="
|
||||||
},
|
},
|
||||||
"is-fullwidth-code-point": {
|
"is-fullwidth-code-point": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
562
package.json
562
package.json
@ -1,10 +1,56 @@
|
|||||||
{
|
{
|
||||||
"name": "mind-reader",
|
"name": "mind-reader",
|
||||||
"displayName": "Mind_Reader",
|
"displayName": "Mind Reader",
|
||||||
"repository": "https://github.com/SingleSemesterSnobs/Mind_Reader",
|
"homepage": "https://github.com/We-Dont-Byte/Mind_Reader/wiki",
|
||||||
"version": "1.0.0",
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/We-Dont-Byte/Mind_Reader"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/We-Dont-Byte/Mind_Reader/issues"
|
||||||
|
},
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name" : "Jake Grossman",
|
||||||
|
"email" : "JacobGrossman2@my.unt.edu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "Cal Wooten",
|
||||||
|
"email" : "calwooten@my.unt.edu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "Josiah Mosesn",
|
||||||
|
"email" : "josiahmoses@my.unt.edu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "Sophia Drewfs",
|
||||||
|
"email" : "sophiadrewfs@my.unt.edu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "John Breaux",
|
||||||
|
"email" : "JohnBreaux@my.unt.edu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "Thomas Lane",
|
||||||
|
"email" : "ThomasLane2@my.unt.edu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "Ryan Tolbert",
|
||||||
|
"email" : "RyanTolbert@my.unt.edu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "Kendrick Johnson",
|
||||||
|
"email" : "KendrickJohnson@my.unt.edu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name" : "Pedro Alvarez",
|
||||||
|
"email" : "PedroAlvarez3@my.unt.edu"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": "2.0.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.60.0"
|
"vscode": "^1.66.0"
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"Other"
|
"Other"
|
||||||
@ -15,199 +61,249 @@
|
|||||||
"main": "./out/extension.js",
|
"main": "./out/extension.js",
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
|
||||||
"command": "mind-reader.helloWorld",
|
|
||||||
"title": "Hello World"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"command": "mind-reader.increaseFontScale",
|
"command": "mind-reader.increaseFontScale",
|
||||||
"title": "Increase Font Scale"
|
"title": "Increase Font Scale",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.decreaseFontScale",
|
"command": "mind-reader.decreaseFontScale",
|
||||||
"title": "Decrease Font Scale"
|
"title": "Decrease Font Scale",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.resetFontScale",
|
"command": "mind-reader.resetFontScale",
|
||||||
"title": "Reset Font Scale"
|
"title": "Reset Font Scale",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.increaseEditorScale",
|
"command": "mind-reader.increaseEditorScale",
|
||||||
"title": "Increase Editor Scale"
|
"title": "Increase Editor Scale",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.decreaseEditorScale",
|
"command": "mind-reader.decreaseEditorScale",
|
||||||
"title": "Decrease Editor Scale"
|
"title": "Decrease Editor Scale",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.resetEditorScale",
|
"command": "mind-reader.resetEditorScale",
|
||||||
"title": "Reset Editor Scale"
|
"title": "Reset Editor Scale",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.selectTheme",
|
"command": "mind-reader.selectTheme",
|
||||||
"title": "Select Theme"
|
"title": "Select Theme",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.openWebview",
|
"command": "mind-reader.openWebview",
|
||||||
"title": "Mind Reader Webview"
|
"title": "Mind Reader Webview"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.openKeyBindWin",
|
"command": "mind-reader.openKeybinds",
|
||||||
"title": "Key Bindings for Windows"
|
"title": "Edit Keybinds",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.openKeyBindMac",
|
"command": "mind-reader.getLineScope",
|
||||||
"title": "Key Bindings for Mac"
|
"title": "Get Scope of the Current Line",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.runLineContext",
|
"command": "mind-reader.getWordsUnderCursor",
|
||||||
"title": "Run Line Context"
|
"title": "Get Words Under the Cursor",
|
||||||
|
"category": "Mind Reader"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.runCursorContext",
|
"command": "mind-reader.getLineNumber",
|
||||||
"title": "Run Cursor Context"
|
"title": "Get The Current Line Number"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.getIndent",
|
"command": "mind-reader.getIndent",
|
||||||
"title": "Get Line Indentation"
|
"title": "Get The Number Of Line Indentations"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.getLeadingSpaces",
|
||||||
|
"title": "Get The Number Of Leading Spaces"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.selectLeadingWhitespace",
|
||||||
|
"title": "Select The Leading Whitespace"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.getNumberOfSelectedLines",
|
||||||
|
"title": "Get The Number Of Selected Lines"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.connectHub",
|
"command": "mind-reader.connectHub",
|
||||||
"title": "Connect LEGO Hub"
|
"title": "Connect LEGO SPIKE Prime Hub",
|
||||||
|
"category": "SPIKE Prime"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.disconnectHub",
|
"command": "mind-reader.disconnectHub",
|
||||||
"title": "Disconnect LEGO Hub"
|
"title": "Disconnect LEGO SPIKE Prime Hub",
|
||||||
|
"category": "SPIKE Prime"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.uploadCurrentFile",
|
"command": "mind-reader.uploadCurrentFile",
|
||||||
"title": "Upload current file to LEGO Hub"
|
"title": "Upload Current File to LEGO SPIKE Prime Hub",
|
||||||
|
"category": "SPIKE Prime"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.runProgram",
|
"command": "mind-reader.runProgram",
|
||||||
"title": "Run a program from the LEGO Hub"
|
"title": "Run a Program on the LEGO SPIKE Prime Hub",
|
||||||
|
"category": "SPIKE Prime"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.stopExecution",
|
"command": "mind-reader.stopExecution",
|
||||||
"title": "Stop running program on the LEGO Hub"
|
"title": "Stop Running Program on the LEGO SPIKE Prime Hub",
|
||||||
|
"category": "SPIKE Prime"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.deleteProgram",
|
"command": "mind-reader.deleteProgram",
|
||||||
"title": "Delete a program from the LEGO Hub"
|
"title": "Delete a Program from the LEGO SPIKE Prime Hub",
|
||||||
|
"category": "SPIKE Prime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.uploadCurrentFile",
|
||||||
|
"title": "Upload Current File to the LEGO SPIKE Prime Hub",
|
||||||
|
"category": "SPIKE Prime"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.getLeadingSpaces",
|
||||||
|
"title": "Get Leading Spaces",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.getLineNumber",
|
||||||
|
"title": "Get Line Number",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.getQuickInputBack",
|
||||||
|
"title": "Go Back in Quick Input",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.gotoLine",
|
||||||
|
"title": "Go to Line",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.gotoSymbol",
|
||||||
|
"title": "Go to Symbol",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.navigateBack",
|
||||||
|
"title": "Navigate Backward",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.navigateForward",
|
||||||
|
"title": "Navigate Forward",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.nextInFiles",
|
||||||
|
"title": "Go to Next Problem in Files (Error, Warning, Info)",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.prevInFiles",
|
||||||
|
"title": "Go to Previous Problem in Files (Error, Warning, Info)",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.quickOpen",
|
||||||
|
"title": "Go to File...",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.quickOpenPreviousRecentlyUsedEditorInGroup",
|
||||||
|
"title": "View: Quick Open Previous Recently Used Editor in Group"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.showAllSymbols",
|
||||||
|
"title": "Go to Symbol in Workspace...",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.showProblems",
|
||||||
|
"title": "Show Problems",
|
||||||
|
"category": "Mind Reader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.showCommands",
|
||||||
|
"title": "Show All Commands",
|
||||||
|
"category": "Mind Reader"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"keybindings": [
|
"keybindings": [
|
||||||
{
|
{
|
||||||
"command": "mind-reader.decreaseFontScale",
|
"command": "editor.action.fontZoomOut",
|
||||||
"key": "numpad_subtract",
|
"key": "Shift+Alt+z -",
|
||||||
"mac": "d"
|
"when": "editorTextFocus && config.mind-reader.reader.screenReader != JAWS"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.increaseFontScale",
|
"command": "editor.action.fontZoomIn",
|
||||||
"key": "numpad_add",
|
"key": "Shift+Alt+z =",
|
||||||
"mac": "[NumpadAdd]"
|
"when": "editorTextFocus && config.mind-reader.reader.screenReader != JAWS"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.increaseEditorScale",
|
"command": "editor.action.fontZoomReset",
|
||||||
"key": "shift+numpad_add",
|
"key": "Shift+Alt+z 0",
|
||||||
"mac": "Shift+[NumpadAdd]"
|
"when": "editorTextFocus && config.mind-reader.reader.screenReader != JAWS"
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.decreaseEditorScale",
|
|
||||||
"key": "shift+numpad_subtract",
|
|
||||||
"mac": "Shift+[NumpadSubtract]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.resetEditorScale",
|
|
||||||
"key": "shift+enter",
|
|
||||||
"mac": "Shift+[Enter]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.showAllSymbols",
|
|
||||||
"key": "Ctrl+T",
|
|
||||||
"mac": "Cmd+[KeyT]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.gotoLine",
|
|
||||||
"key": "CTRL+G",
|
|
||||||
"mac": "Cmd+[KeyG]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.quickOpen",
|
|
||||||
"key": "CTRL+P",
|
|
||||||
"mac": "Cmd+[KeyP]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.gotoSymbol",
|
|
||||||
"key": "Ctrl+Shift+O",
|
|
||||||
"mac": "Cmd+Shift+[KeyO]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.showProblems",
|
|
||||||
"key": "Ctrl+Shift+M",
|
|
||||||
"mac": "Cmd+Shift+[KeyM]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.nextInFiles",
|
|
||||||
"key": "F8",
|
|
||||||
"mac": "[F8]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.prevInFiles",
|
|
||||||
"key": "Shift+F8",
|
|
||||||
"mac": "Shift+[F8]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.quickOpenPreviousRecentlyUsedEditorInGroup",
|
|
||||||
"key": "Ctrl+Tab",
|
|
||||||
"mac": "Cmd+[Tab]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.navigateBack",
|
|
||||||
"key": "Ctrl+Alt+-",
|
|
||||||
"mac": "Cmd+Alt+[Minus]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.getQuickInputBack",
|
|
||||||
"key": "Ctrl+Alt+-",
|
|
||||||
"mac": "Cmd+Alt+[Minus]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.navigateForward",
|
|
||||||
"key": "Ctrl+Shift+-",
|
|
||||||
"mac": "Cmd+Shift+[Minus]"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.selectTheme",
|
|
||||||
"key": "Ctrl+Shift+1",
|
|
||||||
"mac": "Cmd+Shift+[Digit1]"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.getIndent",
|
"command": "mind-reader.getIndent",
|
||||||
"key": "Shift+Tab",
|
"key": "Ctrl+Shift+/ I",
|
||||||
"mac": "Shift+[Tab]"
|
"mac": "Cmd+Shift+[Slash] I",
|
||||||
|
"when": "editorTextFocus"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.openKeyBindWin",
|
"command": "mind-reader.getLeadingSpaces",
|
||||||
"key": "Ctrl+Shift+8",
|
"key": "Ctrl+Shift+/ S",
|
||||||
"mac": "Cmd+Shift+8"
|
"mac": "Cmd+Shift+[Slash] S",
|
||||||
|
"when": "editorTextFocus",
|
||||||
|
"comment": "Requires python language"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.openKeyBindMac",
|
"command": "mind-reader.getLineNumber",
|
||||||
"key": "Ctrl+Shift+9",
|
"key": "Ctrl+Shift+/ L",
|
||||||
"mac": "Cmd+Shift+9"
|
"mac": "Cmd+Shift+[Slash] L",
|
||||||
|
"when": "editorTextFocus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.getLineScope",
|
||||||
|
"key": "Ctrl+Shift+/ C",
|
||||||
|
"mac": "Cmd+Shift+[Slash] C",
|
||||||
|
"when": "editorTextFocus && editorLangId == python"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.openKeybinds",
|
||||||
|
"key": "Ctrl+Shift+/ K",
|
||||||
|
"mac": "Cmd+Shift+[Slash] K"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.ev3.test",
|
||||||
|
"key": "Ctrl+E Ctrl+V"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"menus": {
|
"menus": {
|
||||||
"editor/context": [
|
"editor/context": [{
|
||||||
{
|
"submenu": "mind-reader.editor.context",
|
||||||
"submenu": "mind-reader.editor.context",
|
"group": "mind-reader"
|
||||||
"group": "mind-reader"
|
}],
|
||||||
}
|
|
||||||
],
|
|
||||||
"mind-reader.editor.context": [
|
"mind-reader.editor.context": [
|
||||||
{
|
{
|
||||||
"command": "mind-reader.increaseEditorScale",
|
"command": "mind-reader.selectTheme",
|
||||||
|
"group": "mind-reader",
|
||||||
|
"when": "activeEditor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.increaseFontScale",
|
||||||
"group": "mind-reader",
|
"group": "mind-reader",
|
||||||
"when": "activeEditor"
|
"when": "activeEditor"
|
||||||
},
|
},
|
||||||
@ -237,7 +333,27 @@
|
|||||||
"when": "activeEditor"
|
"when": "activeEditor"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.selectTheme",
|
"command": "mind-reader.getLineNumber",
|
||||||
|
"group": "mind-reader",
|
||||||
|
"when": "activeEditor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.getIndent",
|
||||||
|
"group": "mind-reader",
|
||||||
|
"when": "activeEditor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.getLeadingSpaces",
|
||||||
|
"group": "mind-reader",
|
||||||
|
"when": "activeEditor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.selectLeadingWhitespace",
|
||||||
|
"group": "mind-reader",
|
||||||
|
"when": "activeEditor"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mind-reader.getNumberOfSelectedLines",
|
||||||
"group": "mind-reader",
|
"group": "mind-reader",
|
||||||
"when": "activeEditor"
|
"when": "activeEditor"
|
||||||
},
|
},
|
||||||
@ -247,30 +363,25 @@
|
|||||||
"when": "activeEditor"
|
"when": "activeEditor"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "mind-reader.openKeyBindWin",
|
"command": "mind-reader.openKeybinds",
|
||||||
"group": "mind-reader",
|
|
||||||
"when": "activeEditor"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "mind-reader.openKeyBindMac",
|
|
||||||
"group": "mind-reader",
|
"group": "mind-reader",
|
||||||
"when": "activeEditor"
|
"when": "activeEditor"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"submenus": [
|
"submenus": [{
|
||||||
{
|
"id": "mind-reader.editor.context",
|
||||||
"id": "mind-reader.editor.context",
|
"label": "Mind Reader"
|
||||||
"label": "Mind_Reader"
|
}],
|
||||||
}
|
"configuration": [{
|
||||||
],
|
"title": "Mind Reader",
|
||||||
"configuration": {
|
"order": 0,
|
||||||
"title": "Mind_Reader",
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"mindReader.productType": {
|
"mind-reader.productType": {
|
||||||
|
"order": 1,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Specifies the LEGO® product.",
|
"description": "Specifies the LEGO® product.",
|
||||||
"default": "MINDSTORMS EV3",
|
"default": "SPIKE Prime",
|
||||||
"enum": [
|
"enum": [
|
||||||
"MINDSTORMS EV3",
|
"MINDSTORMS EV3",
|
||||||
"SPIKE Prime"
|
"SPIKE Prime"
|
||||||
@ -280,40 +391,177 @@
|
|||||||
"LEGO® Education SPIKE™ Prime Set (45678)"
|
"LEGO® Education SPIKE™ Prime Set (45678)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mindReader.reader.screenReader": {
|
"mind-reader.reader.screenReader": {
|
||||||
|
"order": 0,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Specifies which screen reader to optimize for.",
|
"description": "Specifies which screen reader to optimize for.",
|
||||||
"default": "NVDA",
|
"default": "NVDA",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
"JAWS",
|
||||||
"NVDA",
|
"NVDA",
|
||||||
"Orca",
|
"Orca",
|
||||||
"VoiceOver"
|
"VoiceOver"
|
||||||
],
|
],
|
||||||
"enumDescriptions": [
|
"enumDescriptions": [
|
||||||
|
"Job Access With Speech (Windows)",
|
||||||
"NonVisual Desktop Access (Windows)",
|
"NonVisual Desktop Access (Windows)",
|
||||||
"Orca (Linux)",
|
"Orca (Linux)",
|
||||||
"Apple VoiceOver (macOS)"
|
"Apple VoiceOver (macOS)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"mindReader.reader.contextWindow": {
|
"mind-reader.reader.contextWindow": {
|
||||||
|
"order": 3,
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"description": "The number of words around the cursor to use when reading the cursor context",
|
"description": "The number of words around the cursor to use when reading the cursor context",
|
||||||
"default": 1
|
"default": 1
|
||||||
},
|
},
|
||||||
"mindReader.connection.portPath": {
|
"mind-reader.connection.portPath": {
|
||||||
|
"order": 2,
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"markdownDescription": "The default port to try and establish a connection on."
|
"markdownDescription": "The default port to try and establish a connection on."
|
||||||
},
|
|
||||||
"mindReader.connection.clearOutputOnRun": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Whether to clear the output each time the program is run",
|
|
||||||
"default": "true"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"title": "Line Highlighter [Must Close Settings And RESTART VSCode For The Line Highlighter To Function]",
|
||||||
|
"order": 1,
|
||||||
|
"properties": {
|
||||||
|
"mind-reader.lineHighlighter.isEnabled": {
|
||||||
|
"order": 4,
|
||||||
|
"type": "boolean",
|
||||||
|
"markdownDescription": "Enable/Disable the line highlighter.\n\n\n* `Enabled (our default)`: Checked: Line Highlighter is turned `ON`\n* `Disabled`: Unchecked: Line Highlighter is turned `OFF`\n\n### `NOTE`: You Must Close Settings And RESTART Visual Studio Code For The Line Highlighter To Function\n#### Even If No Changes Were Made",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.multiLineIsEnabled": {
|
||||||
|
"order": 5,
|
||||||
|
"type": "boolean",
|
||||||
|
"markdownDescription": "Temporarily Disable highlighting when highlighting multiple lines.\n\n\n* `Enabled`: Checked: Multiline Highlighting is turned `ON`:\n* * When you click and drag line highlights will be applied to all lines\n* `Disabled (our default)`: Unchecked: Multiline Highlighting is turned `OFF`:\n* * When you click and drag the line highlighter will disable itself then re-enable itself when you click onto a single line.",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.backgroundColor": {
|
||||||
|
"order": 6,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the background color to be used by the line highlighter.\n\nSyntax: _color_ or `transparent`\n\nAvailable color formats include:\n* `HEX(A)`: for Hexadecimal Colors: `#RRGGBB` or `#RRGGBBAA` to add transparency\n* `RGB(A)`: for RGB Colors: `rgb(red, green, blue)` or `rgba(red, green, blue, alpha)`\n* `HSL(A)`: for HSL Colors: `hsl(hue, saturation, lightness)` or `hsla(hue, saturation, lightness, alpha)`\n* `Predefined Color Names`: 140 color names are predefined in the HTML and CSS color specification: `blue`, `red`, `coral`, `brown`, [etc...](https://www.w3schools.com/colors/colors_names.asp)\n* `None`: For no color to be applied: Sometimes VSCode will pull a color from your theme, other times it uses black\n* `#232C5C` is our default",
|
||||||
|
"default": "#232C5C"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.outlineColor": {
|
||||||
|
"order": 7,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the outline color to be used by the line highlighter.\n\nSyntax: _color_ or `transparent`\n\nAvailable color formats include:\n* `HEX(A)`: for Hexadecimal Colors: `#RRGGBB` or `#RRGGBBAA` to add transparency\n* `RGB(A)`: for RGB Colors: `rgb(red, green, blue)` or `rgba(red, green, blue, alpha)`\n* `HSL(A)`: for HSL Colors: `hsl(hue, saturation, lightness)` or `hsla(hue, saturation, lightness, alpha)`\n* `Predefined Color Names`: 140 color names are predefined in the HTML and CSS color specification: `blue`, `red`, `coral`, `brown`, [etc...](https://www.w3schools.com/colors/colors_names.asp)\n* `None`: For no color to be applied: Sometimes VSCode will pull a color from your theme, other times it uses black\n* `#4866FE` is our default",
|
||||||
|
"default": "#4866FE"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.outlineWidth": {
|
||||||
|
"order": 8,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the outline width to be used by the line highlighter.\n\nSyntax: `medium` or `thin` or `thick` or `length` or `none`\n* `medium`: Specifies a medium outline. (usual default)\n* `thin`: Specifies a thin outline\n* `thick`: Specifies a thick outline\n* `length`: you to define the thickness of the outline in [length](https://www.w3schools.com/cssref/css_units.asp) units.\n* `none`: No outline width will be applied\n* `1px` is our default",
|
||||||
|
"default": "1px"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.outlineStyle": {
|
||||||
|
"order": 9,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the outline style to be used by the line highlighter.\n\nSyntax: `none` or `hidden` or `dotted` or `dashed` or `solid` or `double` or `groove` or `ridge` or `inset` or `outset`\n* `none`: No border will be applied (usual default)\n* `hidden`: The same as `none`\n* `dotted`: Dotted border\n* `dashed`: Dashed border\n* `solid (our default)`: Solid border\n* `double`: Double border\n* `groove`: 3D grooved border, depends on the outline-color value.\n* `ridge`: 3D ridged border, depends on the outline-color value.\n* `inset`: 3D inset border, depends on the outline-color value.\n* `outset`: 3D outset border, depends on the outline-color value.",
|
||||||
|
"default": "solid"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderColorTop": {
|
||||||
|
"order": 10,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the top border color to be used by the line highlighter.\n\nSyntax: _color_ or `transparent`\n\nAvailable color formats include:\n* `HEX(A)`: for Hexadecimal Colors: `#RRGGBB` or `#RRGGBBAA` to add transparency\n* `RGB(A)`: for RGB Colors: `rgb(red, green, blue)` or `rgba(red, green, blue, alpha)`\n* `HSL(A)`: for HSL Colors: `hsl(hue, saturation, lightness)` or `hsla(hue, saturation, lightness, alpha)`\n* `Predefined Color Names`: 140 color names are predefined in the HTML and CSS color specification: `blue`, `red`, `coral`, `brown`, [etc...](https://www.w3schools.com/colors/colors_names.asp)\n* `None`: For no color to be applied: Sometimes VSCode will pull a color from your theme, other times it uses black\n* `#FFFFFF` is our default",
|
||||||
|
"default": "#FFFFFF"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderColorRight": {
|
||||||
|
"order": 11,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the right border color to be used by the line highlighter.\n\nSyntax: _color_ or `transparent`\n\nAvailable color formats include:\n* `HEX(A)`: for Hexadecimal Colors: `#RRGGBB` or `#RRGGBBAA` to add transparency\n* `RGB(A)`: for RGB Colors: `rgb(red, green, blue)` or `rgba(red, green, blue, alpha)`\n* `HSL(A)`: for HSL Colors: `hsl(hue, saturation, lightness)` or `hsla(hue, saturation, lightness, alpha)`\n* `Predefined Color Names`: 140 color names are predefined in the HTML and CSS color specification: `blue`, `red`, `coral`, `brown`, [etc...](https://www.w3schools.com/colors/colors_names.asp)\n* `None`: For no color to be applied: Sometimes VSCode will pull a color from your theme, other times it uses black\n* `#FFFFFF` is our default",
|
||||||
|
"default": "#FFFFFF"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderColorBottom": {
|
||||||
|
"order": 12,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the bottom border color to be used by the line highlighter.\n\nSyntax: _color_ or `transparent`\n\nAvailable color formats include:\n* `HEX(A)`: for Hexadecimal Colors: `#RRGGBB` or `#RRGGBBAA` to add transparency\n* `RGB(A)`: for RGB Colors: `rgb(red, green, blue)` or `rgba(red, green, blue, alpha)`\n* `HSL(A)`: for HSL Colors: `hsl(hue, saturation, lightness)` or `hsla(hue, saturation, lightness, alpha)`\n* `Predefined Color Names`: 140 color names are predefined in the HTML and CSS color specification: `blue`, `red`, `coral`, `brown`, [etc...](https://www.w3schools.com/colors/colors_names.asp)\n* `None`: For no color to be applied: Sometimes VSCode will pull a color from your theme, other times it uses black\n* `#FFFFFF` is our default",
|
||||||
|
"default": "#FFFFFF"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderColorLeft": {
|
||||||
|
"order": 13,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the left border color to be used by the line highlighter.\n\nSyntax: _color_ or `transparent`\n\nAvailable color formats include:\n* `HEX(A)`: for Hexadecimal Colors: `#RRGGBB` or `#RRGGBBAA` to add transparency\n* `RGB(A)`: for RGB Colors: `rgb(red, green, blue)` or `rgba(red, green, blue, alpha)`\n* `HSL(A)`: for HSL Colors: `hsl(hue, saturation, lightness)` or `hsla(hue, saturation, lightness, alpha)`\n* `Predefined Color Names`: 140 color names are predefined in the HTML and CSS color specification: `blue`, `red`, `coral`, `brown`, [etc...](https://www.w3schools.com/colors/colors_names.asp)\n* `None`: For no color to be applied: Sometimes VSCode will pull a color from your theme, other times it uses black\n* `#FFFFFF` is our default",
|
||||||
|
"default": "#FFFFFF"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderWidthTop": {
|
||||||
|
"order": 14,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the top border width to be used by the line highlighter.\n\nSyntax: `medium` or `thin` or `thick` or `length` or `none`\n* `medium`: Specifies a medium border. (usual default)\n* `thin`: Specifies a thin border\n* `thick`: Specifies a thick border\n* `length`: you to define the thickness of the border in [length](https://www.w3schools.com/cssref/css_units.asp) units.\n* `none`: No border width will be applied\n* `1px` is our default",
|
||||||
|
"default": "1px"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderWidthRight": {
|
||||||
|
"order": 15,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the right border width to be used by the line highlighter.\n\nSyntax: `medium` or `thin` or `thick` or `length` or `none`\n* `medium`: Specifies a medium border. (usual default)\n* `thin`: Specifies a thin border\n* `thick`: Specifies a thick border\n* `length`: you to define the thickness of the border in [length](https://www.w3schools.com/cssref/css_units.asp) units.\n* `none`: No border width will be applied\n* `16px` is our default\n\n#### \nborderWidthRight exhibits odd behavior, play around with different sizes to find what works best for your environment.",
|
||||||
|
"default": "16px"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderWidthBottom": {
|
||||||
|
"order": 16,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the bottom border width to be used by the line highlighter.\n\nSyntax: `medium` or `thin` or `thick` or `length` or `none`\n* `medium`: Specifies a medium border. (usual default)\n* `thin`: Specifies a thin border\n* `thick`: Specifies a thick border\n* `length`: you to define the thickness of the border in [length](https://www.w3schools.com/cssref/css_units.asp) units.\n* `none`: No border width will be applied\n* `1px` is our default",
|
||||||
|
"default": "1px"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderWidthLeft": {
|
||||||
|
"order": 17,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the left border width to be used by the line highlighter.\n\nSyntax: `medium` or `thin` or `thick` or `length` or `none`\n* `medium`: Specifies a medium border. (usual default)\n* `thin`: Specifies a thin border\n* `thick`: Specifies a thick border\n* `length`: you to define the thickness of the border in [length](https://www.w3schools.com/cssref/css_units.asp) units.\n* `none`: No border width will be applied\n* `1px` is our default",
|
||||||
|
"default": "1px"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderStyleTop": {
|
||||||
|
"order": 18,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the top border style to be used by the line highlighter.\n\nSyntax: `none` or `hidden` or `dotted` or `dashed` or `solid` or `double` or `groove` or `ridge` or `inset` or `outset`\n* `none`: No border will be applied (usual default)\n* `hidden`: The same as `none`\n* `dotted`: Dotted border\n* `dashed`: Dashed border\n* `solid (our default)`: Solid border\n* `double`: Double border\n* `groove`: 3D grooved border, depends on the border-color value.\n* `ridge`: 3D ridged border, depends on the border-color value.\n* `inset`: 3D inset border, depends on the border-color value.\n* `outset`: 3D outset border, depends on the border-color value.",
|
||||||
|
"default": "solid"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderStyleRight": {
|
||||||
|
"order": 19,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the right border style to be used by the line highlighter.\n\nSyntax: `none` or `hidden` or `dotted` or `dashed` or `solid` or `double` or `groove` or `ridge` or `inset` or `outset`\n* `none`: No border will be applied (usual default)\n* `hidden`: The same as `none`\n* `dotted`: Dotted border\n* `dashed`: Dashed border\n* `solid (our default)`: Solid border\n* `double`: Double border\n* `groove`: 3D grooved border, depends on the border-color value.\n* `ridge`: 3D ridged border, depends on the border-color value.\n* `inset`: 3D inset border, depends on the border-color value.\n* `outset`: 3D outset border, depends on the border-color value.",
|
||||||
|
"default": "solid"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderStyleBottom": {
|
||||||
|
"order": 20,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the bottom border style to be used by the line highlighter.\n\nSyntax: `none` or `hidden` or `dotted` or `dashed` or `solid` or `double` or `groove` or `ridge` or `inset` or `outset`\n* `none`: No border will be applied (usual default)\n* `hidden`: The same as `none`\n* `dotted`: Dotted border\n* `dashed`: Dashed border\n* `solid (our default)`: Solid border\n* `double`: Double border\n* `groove`: 3D grooved border, depends on the border-color value.\n* `ridge`: 3D ridged border, depends on the border-color value.\n* `inset`: 3D inset border, depends on the border-color value.\n* `outset`: 3D outset border, depends on the border-color value.",
|
||||||
|
"default": "solid"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.borderStyleLeft": {
|
||||||
|
"order": 21,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the left border style to be used by the line highlighter.\n\nSyntax: `none` or `hidden` or `dotted` or `dashed` or `solid` or `double` or `groove` or `ridge` or `inset` or `outset`\n* `none`: No border will be applied (usual default)\n* `hidden`: The same as `none`\n* `dotted`: Dotted border\n* `dashed`: Dashed border\n* `solid (our default)`: Solid border\n* `double`: Double border\n* `groove`: 3D grooved border, depends on the border-color value.\n* `ridge`: 3D ridged border, depends on the border-color value.\n* `inset`: 3D inset border, depends on the border-color value.\n* `outset`: 3D outset border, depends on the border-color value.",
|
||||||
|
"default": "solid"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.fontStyle": {
|
||||||
|
"order": 22,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the font style to be used by the line highlighter.\n\nSyntax: `normal` or `italic` or `oblique` or `none`\n* `normal (our default)`: Displays a normal font style. This is default\n* `italic`: Displays an italic font style\n* `oblique`: Displays an oblique font style\n* `none`: No font style will be applied",
|
||||||
|
"default": "normal"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.fontWeight": {
|
||||||
|
"order": 23,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the font weight to be used by the line highlighter.\n\nSyntax: `normal` or `bold` or `bolder` or `lighter` or _number_ or `none`\n* `normal`: Normal Characters. (usual default)\n* `bold`: Thick Characters\n* `bolder (our default)`: Thicker Characters\n* `lighter`: Lighter Characters\n * _number_: From `thin` to `thick` characters: `100`, `200`, `300`, `400`, `500`, `600`, `700`, `800`, or `900`: `400` is the same as normal, and `700` is the same as bold.\n* `none`: No font weight will be applied",
|
||||||
|
"default": "bolder"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.textDecoration": {
|
||||||
|
"order": 24,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the text decoration to be used by the line highlighter.\n\nSyntax: `(text-decoration-line)` `(text-decoration-color)` `(text-decoration-style)` `(text-decoration-thickness)`\n* `text-decoration-line (required)`: Sets the kind of text decoration to use: `underline`, `overline`, `line-through`\n* `text-decoration-color`: Sets the color of the text decoration\n* `text-decoration-style`: Sets the style of the text decoration: `solid`, `wavy`, `dotted`, `dashed`, `double`\n* `text-decoration-thickness`: Sets the thickness of the decoration line\n* `none (our default)`: No text decorations will be applied\n\n`Examples`:\n1. underline blue wavy 5px\n2. line-through\n3. underline overline dotted red",
|
||||||
|
"default": "none"
|
||||||
|
},
|
||||||
|
"mind-reader.lineHighlighter.textColor": {
|
||||||
|
"order": 25,
|
||||||
|
"type": "string",
|
||||||
|
"markdownDescription": "Set the text color to be used by the line highlighter.\n\nSyntax: _color_ or `transparent`\n\nAvailable color formats include:\n* `HEX(A)`: for Hexadecimal Colors: `#RRGGBB` or `#RRGGBBAA` to add transparency\n* `RGB(A)`: for RGB Colors: `rgb(red, green, blue)` or `rgba(red, green, blue, alpha)`\n* `HSL(A)`: for HSL Colors: `hsl(hue, saturation, lightness)` or `hsla(hue, saturation, lightness, alpha)`\n* `Predefined Color Names`: 140 color names are predefined in the HTML and CSS color specification: `blue`, `red`, `coral`, `brown`, [etc...](https://www.w3schools.com/colors/colors_names.asp)\n* `None`: For no color to be applied: Sometimes VSCode will pull a color from your theme, other times it uses black\n* `#FFFFFF` is our default",
|
||||||
|
"default": "#FFFFFF"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}],
|
||||||
"views": {
|
"views": {
|
||||||
"MindReader": [
|
"MindReader": [{
|
||||||
{
|
|
||||||
"id": "accessActions",
|
"id": "accessActions",
|
||||||
"name": "Access Actions",
|
"name": "Access Actions",
|
||||||
"icon": "media/dep.svg",
|
"icon": "media/dep.svg",
|
||||||
@ -328,13 +576,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"viewsContainers": {
|
"viewsContainers": {
|
||||||
"activitybar": [
|
"activitybar": [{
|
||||||
{
|
"id": "MindReader",
|
||||||
"id": "MindReader",
|
"title": "MindReader Actions",
|
||||||
"title": "MindReader Actions",
|
"icon": "media/dep.svg"
|
||||||
"icon": "media/dep.svg"
|
}]
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
65
setup-development/linux/install-linux.sh
Executable file
65
setup-development/linux/install-linux.sh
Executable file
@ -0,0 +1,65 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#* linux-install.sh: First-run setup script
|
||||||
|
#* Ensures git is installed, clones the repo, and then runs
|
||||||
|
|
||||||
|
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||||
|
ELEVATE='';if (( $UID !=0 )); then ELEVATE='sudo';fi
|
||||||
|
|
||||||
|
help () {
|
||||||
|
echo "Usage: $0 [-d] [-g path/to/git/directory]"
|
||||||
|
exit 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
gitdir=~/git
|
||||||
|
|
||||||
|
# Get option flags:
|
||||||
|
dry=false
|
||||||
|
while getopts ghd arg; do
|
||||||
|
case $arg in
|
||||||
|
g) gitdir="$OPTARG";;
|
||||||
|
h) help;;
|
||||||
|
d) dry=true;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
function dryrun {
|
||||||
|
if $dry; then
|
||||||
|
echo "> $* [dry]";
|
||||||
|
else
|
||||||
|
echo "> $*"
|
||||||
|
$@
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
setupdir="Mind_Reader/setup-development/linux"
|
||||||
|
repouri="https://github.com/We-Dont-Byte/Mind_Reader.git"
|
||||||
|
|
||||||
|
# Install git
|
||||||
|
if which git; then
|
||||||
|
echo "Git already installed."
|
||||||
|
elif which pacman; then
|
||||||
|
# using pacman
|
||||||
|
dryrun $ELEVATE pacman -Sy git
|
||||||
|
elif which apt; then
|
||||||
|
# using apt
|
||||||
|
dryrun $ELEVATE apt-get update && \
|
||||||
|
dryrun $ELEVATE apt-get install git -y
|
||||||
|
fi #? TODO: other package managers?
|
||||||
|
|
||||||
|
printf "\nCloning repository into $gitdir\n"
|
||||||
|
dryrun mkdir "$gitdir"
|
||||||
|
cd $gitdir && dryrun git clone "$repouri"
|
||||||
|
|
||||||
|
# TODO: remove this when merging!
|
||||||
|
cd Mind_Reader
|
||||||
|
dryrun git checkout johnBreaux
|
||||||
|
# TODO: remove this when merging!
|
||||||
|
|
||||||
|
cd "$gitdir/$setupdir"
|
||||||
|
bash ./upgrade-linux.sh $@
|
||||||
|
|
||||||
|
echo "Opening VS Code..."
|
||||||
|
cd $gitdir/Mind_Reader
|
||||||
|
code .
|
@ -0,0 +1,4 @@
|
|||||||
|
apt-transport-https
|
||||||
|
build-essential
|
||||||
|
python3
|
||||||
|
wget
|
@ -0,0 +1,4 @@
|
|||||||
|
base-devel
|
||||||
|
git
|
||||||
|
wget
|
||||||
|
python3
|
141
setup-development/linux/upgrade-linux.sh
Executable file
141
setup-development/linux/upgrade-linux.sh
Executable file
@ -0,0 +1,141 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
#* linux-update.sh: Install and update dependencies of Mind Reader, on linux.
|
||||||
|
#* Heads-up, this expects to be run from Mind_Reader/setup-development/linux.
|
||||||
|
|
||||||
|
# If run with bash -vx, print useful information instead of just a + sign
|
||||||
|
export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'
|
||||||
|
# If run as root, it could be because sudo isn't installed (some people disagree with sudo, especially on Arch)
|
||||||
|
ELEVATE='';if (( $UID !=0 )); then ELEVATE='sudo';fi
|
||||||
|
|
||||||
|
# Get option flags:
|
||||||
|
dry=false
|
||||||
|
while getopts d arg; do
|
||||||
|
case $arg in
|
||||||
|
d) dry=true;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
function dryrun {
|
||||||
|
if $dry; then
|
||||||
|
echo "> $* [dry]";
|
||||||
|
else
|
||||||
|
echo "> $*"
|
||||||
|
$@
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get whether the user is running in Windows Subsystem for Linux
|
||||||
|
function getwsl {
|
||||||
|
grep "[Mm]icrosoft" /proc/version > /dev/null
|
||||||
|
return $?
|
||||||
|
}
|
||||||
|
|
||||||
|
# Get the user's default login shell
|
||||||
|
function getsh {
|
||||||
|
#* This code was created by user [Todd A. Jacobs](https://stackoverflow.com/users/1301972/todd-a-jacobs) on [StackOverflow](https://stackoverflow.com/a/11059152) and is used in accordance with Creative Commons CC BY-SA 3.0
|
||||||
|
getent passwd $LOGNAME | cut -d: -f7
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install NVM (this is gross, but the recommended way to install nvm)
|
||||||
|
function installnvm {
|
||||||
|
# nvm's install script tries to be smart, so we have to work around its supposed cleverness
|
||||||
|
usershell=`getsh`
|
||||||
|
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | dryrun "$usershell"
|
||||||
|
# Reload profile
|
||||||
|
case $usershell in
|
||||||
|
*/bash) dryrun . ~/.bashrc ~/.bashprofile;;
|
||||||
|
*/zsh) dryrun . ~/.zshrc;;
|
||||||
|
*) "Your shell, $usershell, is currently unsupported by nvm. It's up to you to set up your development environment."; exit;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set these variables if you need to install for a different architecture
|
||||||
|
# Valid architectures are "x64", "arm64", "armhf"
|
||||||
|
arch=""
|
||||||
|
case `uname -i` in
|
||||||
|
"x86_64") arch="x64";;
|
||||||
|
"armv[6-8]*") arch="armhf";;
|
||||||
|
"aarch64") arch="arm64";;
|
||||||
|
*) echo "Architecture '$(uname -i)' unknown. Assuming x86_64..."
|
||||||
|
arch="x64";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
if which pacman; then
|
||||||
|
# Install dependencies with pacman
|
||||||
|
printf "Installing dependencies with pacman...\n"
|
||||||
|
cat ./package-managers/pacman.dependencies | dryrun $ELEVATE pacman -S --needed -
|
||||||
|
# If not in Windows Subsystem for Linux, install vscode
|
||||||
|
[[ !(getwsl) ]] && dryrun $ELEVATE pacman -S --needed code
|
||||||
|
# Install Node Version Manager
|
||||||
|
installnvm
|
||||||
|
|
||||||
|
elif which apt-get; then
|
||||||
|
# Install dependencies using apt-get
|
||||||
|
printf "Installing dependencies with apt...\n"
|
||||||
|
dryrun xargs -a ./package-managers/apt.dependencies $ELEVATE apt-get install -y
|
||||||
|
# Check if vscode exists, if not, install it.
|
||||||
|
# Microsoft doesn't put it in any Ubuntu repos, you have to get it straight from them.
|
||||||
|
# This does have the side effect, however, of installing the official repository
|
||||||
|
# Don't attempt to install vscode if running in WSL; it can cause problems.
|
||||||
|
if !(which code) && !(getwsl); then
|
||||||
|
#* Install VSCode
|
||||||
|
vscodepackagename="code_amd64.deb"
|
||||||
|
dryrun wget "https://code.visualstudio.com/sha/download?build=stable&os=linux-deb-$arch" -O ./code.deb
|
||||||
|
dryrun $ELEVATE apt install ./code.deb
|
||||||
|
dryrun rm ./code.deb
|
||||||
|
fi
|
||||||
|
# Install Node Version Manager (nvm)
|
||||||
|
installnvm
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
cdir=$(pwd)
|
||||||
|
# Go back to source tree root
|
||||||
|
cd ../..
|
||||||
|
|
||||||
|
# Check the VSCode version
|
||||||
|
nodeversion="node"
|
||||||
|
electronversion=""
|
||||||
|
#* Note:
|
||||||
|
#* When adding support for new VSCode versions, update this case
|
||||||
|
#* By the time you're working on this project, things are likely going to differ!
|
||||||
|
case `code --version` in
|
||||||
|
#* Each version of VSCode has a corresponding Electron version and Node version
|
||||||
|
#* These are used when configuring nvm
|
||||||
|
1.66.*) electronversion="17.2.0"; nodeversion="16.13.0";;
|
||||||
|
1.67.*) electronversion="17.4.1"; nodeversion="16.13.0";;
|
||||||
|
*) nodeversion="--lts";;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Install NodeJS and npm
|
||||||
|
printf "\nInstalling node $nodeversion\n"
|
||||||
|
dryrun nvm install "$nodeversion"
|
||||||
|
dryrun nvm use "$nodeversion"
|
||||||
|
|
||||||
|
# Use npm to install electron-rebuild and yo
|
||||||
|
printf "Installing electron-rebuild, yo, and generator-code\n"
|
||||||
|
dryrun npm install electron-rebuild yo generator-code
|
||||||
|
|
||||||
|
# use npm to acquire dependencies for Mind-Reader
|
||||||
|
printf "\nAcquiring dependencies...\n"
|
||||||
|
dryrun npm install
|
||||||
|
|
||||||
|
# automatically update vulnerable packages, if possible
|
||||||
|
printf "\nUpdating vulnerable packages, if possible...\n"
|
||||||
|
dryrun npm audit fix
|
||||||
|
|
||||||
|
# Use electron-rebuild to rebuild electron
|
||||||
|
if [[ "$electronversion" != "" ]]; then
|
||||||
|
printf "\nRebuilding electron with version $electronversion...\n"
|
||||||
|
dryrun electron-rebuild --version $electronversion
|
||||||
|
else
|
||||||
|
printf "\n%s\n%s\n%s\n%s\n" \
|
||||||
|
"Open Visual Studio Code, select the 'Help' tab in the toolbar, and go to 'About'." \
|
||||||
|
"Find the line that says 'Electron: [electron version]'" \
|
||||||
|
"Run the command below, filling in the Electron version with the one from that menu:" \
|
||||||
|
"electron-rebuild --version [electron version]"
|
||||||
|
fi
|
||||||
|
|
||||||
|
cd $cdir
|
||||||
|
echo "Done!"
|
179
setup-development/windows/install-windows.ps1
Normal file
179
setup-development/windows/install-windows.ps1
Normal file
@ -0,0 +1,179 @@
|
|||||||
|
<#
|
||||||
|
.synopsis
|
||||||
|
Dependency installer for Mind Reader on Windows.
|
||||||
|
This sets up a development environment from a BARE windows install.
|
||||||
|
|
||||||
|
.description
|
||||||
|
Install Git for Windows, clone the Mind Reader repository, and install all dependencies.
|
||||||
|
|
||||||
|
The script uses winget (A.K.A. "App Installer") to download and install the latest versions of each dependency, defined in winget/dependencies.json
|
||||||
|
|
||||||
|
Winget comes preinstalled on Windows 11 (21H2)/10 (21H1) or newer, and can be installed on Windows 10 1704+ through the Windows Store.
|
||||||
|
If you download Microsoft's developer VM, you have it!
|
||||||
|
As WinGet is built into Windows, it sidesteps any annoying third-party package managers, and is the lowest common denominator for package installation.
|
||||||
|
|
||||||
|
.link
|
||||||
|
https://github.com/We-Dont-Byte/Mind_Reader/
|
||||||
|
|
||||||
|
.parameter GitDir
|
||||||
|
Path to clone the git repo into (Default: $HOME/git/)
|
||||||
|
|
||||||
|
.parameter AllowAdministrator
|
||||||
|
Force-allow running this script as Administrator (not recommended, despite the frequent UAC prompts!)
|
||||||
|
|
||||||
|
.parameter NoPrompt
|
||||||
|
Disable all prompts for user input, and all waiting. (not recommended when combined with AllowAdministrator!)
|
||||||
|
|
||||||
|
.parameter ForceInstall
|
||||||
|
Force installation/upgrade of all modules, even if already present on the system.
|
||||||
|
|
||||||
|
.parameter DryRun
|
||||||
|
Perform a "dry run" of the script, changing directories and running commands, but without modifying anything.
|
||||||
|
|
||||||
|
.example
|
||||||
|
./install-windows.ps1
|
||||||
|
Perform a default upgrade of all Mind Reader dependencies
|
||||||
|
|
||||||
|
.example
|
||||||
|
./install-windows.ps1 -DryRun
|
||||||
|
Perform a dry run of the upgrade process, so you can evaluate what commands will be run
|
||||||
|
|
||||||
|
.example
|
||||||
|
./install-windows.ps1 -NoPrompt
|
||||||
|
Don't prompt for user input when upgrading
|
||||||
|
|
||||||
|
.example
|
||||||
|
./install-windows.ps1 AllowAdministrator
|
||||||
|
Allow script to run as Administrator
|
||||||
|
#>
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$GitDir = "$HOME/git/", # Path to clone the git repo into
|
||||||
|
[switch]$h, [switch]$Help, # Get help
|
||||||
|
[switch]$AllowAdministrator, # Force allow installation as administrator
|
||||||
|
[switch]$NoPrompt, # Disable the 3-second wait and press-any-key prompt
|
||||||
|
[switch]$ForceInstall, # Always try to install
|
||||||
|
[switch]$DryRun # Run script without installing
|
||||||
|
)
|
||||||
|
|
||||||
|
$RepoURI = "https://github.com/We-Dont-Byte/Mind_Reader.git"
|
||||||
|
$RepoPath = "$GitDir\Mind_Reader"
|
||||||
|
$SetupPath = "$RepoPath\setup-development\windows"
|
||||||
|
|
||||||
|
if ($h -or $Help) {
|
||||||
|
Get-Help ./install-windows.ps1
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
# .description
|
||||||
|
# Get-CommandAvailable: Checks whether a given command is available.
|
||||||
|
# If command is available, returns $false
|
||||||
|
function Get-CommandAvailable {
|
||||||
|
param ($command)
|
||||||
|
# Use a wildcard here so the command doesn't throw an exception we'd have to trycatch
|
||||||
|
# It's not a filthy hack if it's elegant!
|
||||||
|
RETURN (Get-Command -Name $command*)
|
||||||
|
}
|
||||||
|
|
||||||
|
#.description
|
||||||
|
# Invoke-DryRun a powershell statement
|
||||||
|
function Invoke-DryRun {
|
||||||
|
param ([string] $command)
|
||||||
|
$prompt = "> "
|
||||||
|
if ($DryRun) {
|
||||||
|
Write-Host "$prompt$command [dry]" -ForegroundColor darkgray
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "$prompt$command" -ForegroundColor white
|
||||||
|
Invoke-Expression $command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#.description
|
||||||
|
# Reset-Path: Reload the Path environment variable
|
||||||
|
function Reset-Path {
|
||||||
|
Write-Output "Reloading Path..."
|
||||||
|
#* This code was created by user [mpen](https://stackoverflow.com/users/65387/mpen) on [StackOverflow](https://stackoverflow.com/a/31845512) and is used in accordance with Creative Commons CC BY-SA 3.0
|
||||||
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path","Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path","User")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Check if Winget is available
|
||||||
|
if ( -not (Get-CommandAvailable winget) ) {
|
||||||
|
Write-Warning "It looks like winget isn't available.`n"
|
||||||
|
Write-Host "Update 'App Installer' through the Microsoft Store, or grab the '.msixbundle' from the winget-cli repository:"
|
||||||
|
Write-Host "( https://github.com/microsoft/winget-cli/releases/latest )`n" -ForegroundColor White
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if the user ran the script with administrator privileges.
|
||||||
|
# Warn them.
|
||||||
|
if ( ([Security.Principal.WindowsIdentity]::GetCurrent().Groups -contains 'S-1-5-32-544') ) {
|
||||||
|
# If an administrator requests installation as administator,
|
||||||
|
# for example, to keep UAC prompts to a minimum, allow it.
|
||||||
|
if ($AllowAdministrator) {
|
||||||
|
Write-Warning "Script was run as Administrator. Exit now if you didn't mean to do this!"
|
||||||
|
# If you pass NoPrompt as an arg, you're very aware of the damage this script could do to your build env, and you just don't care
|
||||||
|
# The true chad of sysadmins.
|
||||||
|
if (!$NoPrompt) {
|
||||||
|
for ( $i = 3; $i -gt 0; $i--) {
|
||||||
|
Write-Host "Press Ctrl+C to exit. Continuing in $i...`r" -NoNewLine
|
||||||
|
Start-Sleep 1
|
||||||
|
}
|
||||||
|
Write-Host "Press any key to continue... "
|
||||||
|
[void][Console]::ReadKey(1) # Equivalent to Command Prompt's `pause` command
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
# Throw a fatal error if the user tries to run as administrator.
|
||||||
|
Throw "Script must be run as a normal user."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Install Git
|
||||||
|
if ( -not (Get-CommandAvailable git) ) {
|
||||||
|
Write-Host "`nInstalling Git with winget..."
|
||||||
|
Invoke-DryRun 'winget install --id Git.Git'
|
||||||
|
Reset-Path
|
||||||
|
if ( -not (Get-CommandAvailable git)) {
|
||||||
|
Throw "Git failed to install. Aborting."
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Write-Host "Git already installed." -ForegroundColor green
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create git directory in GitDir
|
||||||
|
if ( -not (Test-Path "$GitDir") ) {
|
||||||
|
Invoke-DryRun "mkdir '$GitDir'"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Clone the repository in GitDir
|
||||||
|
$dir = $pwd
|
||||||
|
Set-Location $GitDir
|
||||||
|
Invoke-DryRun "git clone '$RepoURI'"
|
||||||
|
|
||||||
|
# TODO: Remove this when merging
|
||||||
|
Set-Location Mind_reader
|
||||||
|
Invoke-DryRun "git checkout johnBreaux"
|
||||||
|
Set-Location ..
|
||||||
|
# TODO: Remove this when merging
|
||||||
|
|
||||||
|
# Run the install script
|
||||||
|
if ( -not (Test-Path "$SetupPath")) {
|
||||||
|
Throw "Repository contains no subdirectory '$SetupPath'."
|
||||||
|
}
|
||||||
|
Set-Location $SetupPath
|
||||||
|
# Run upgrade-windows to install the rest of the dependency chain.
|
||||||
|
$upgradeArgs = if ($AllowAdministrator) {" -AllowAdministrator"} else {""}
|
||||||
|
$upgradeArgs += if ($DryRun) {" -DryRun"} else {""}
|
||||||
|
PowerShell ("./upgrade-windows.ps1 -Install -NoPrompt" + $upgradeArgs)
|
||||||
|
Reset-Path
|
||||||
|
|
||||||
|
# Open VSCode in the repository location
|
||||||
|
Write-Host "`nOpening Visual Studio Code"
|
||||||
|
Set-Location $RepoPath
|
||||||
|
Invoke-DryRun "code ."
|
||||||
|
|
||||||
|
Set-Location $dir
|
||||||
|
if ( -not $NoPrompt ) {
|
||||||
|
Write-Host "`nPress any key to exit."; [void][Console]::ReadKey(1)
|
||||||
|
}
|
214
setup-development/windows/upgrade-windows.ps1
Normal file
214
setup-development/windows/upgrade-windows.ps1
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
<#
|
||||||
|
.synopsis
|
||||||
|
Dependency updater for Mind Reader on Windows.
|
||||||
|
This script expects to be run from Mind_Reader/setup-development
|
||||||
|
|
||||||
|
.description
|
||||||
|
Updates dependencies (NodeJS, Python, etc.), VSCode, NVDA
|
||||||
|
|
||||||
|
The script uses winget (A.K.A. "App Installer") to download and install the latest versions of each dependency, defined in winget/dependencies.json
|
||||||
|
|
||||||
|
Winget comes preinstalled on Windows 11 (21H2)/10 (21H1) or newer, and can be installed on Windows 10 1704+ through the Windows Store.
|
||||||
|
If you download Microsoft's developer VM, you have it!
|
||||||
|
As WinGet is built into Windows, it sidesteps any annoying third-party package managers, and is the lowest common denominator for package installation.
|
||||||
|
|
||||||
|
.link
|
||||||
|
https://github.com/We-Dont-Byte/Mind_Reader/
|
||||||
|
|
||||||
|
.parameter GitDir
|
||||||
|
Path to clone the git repo into (Default: $HOME/git/)
|
||||||
|
|
||||||
|
.parameter AllowAdministrator
|
||||||
|
Force-allow running this script as Administrator (not recommended, despite the frequent UAC prompts!)
|
||||||
|
|
||||||
|
.parameter NoPrompt
|
||||||
|
Disable all prompts for user input, and all waiting. (not recommended when combined with AllowAdministrator!)
|
||||||
|
|
||||||
|
.parameter Install
|
||||||
|
Force installation/upgrade of all modules, even if already present on the system.
|
||||||
|
|
||||||
|
.parameter DryRun
|
||||||
|
Perform a "dry run" of the script, changing directories and running commands, but without modifying anything.
|
||||||
|
|
||||||
|
.example
|
||||||
|
./upgrade-windows.ps1
|
||||||
|
Perform a default upgrade of all Mind Reader dependencies
|
||||||
|
|
||||||
|
.example
|
||||||
|
./upgrade-windows.ps1 -DryRun
|
||||||
|
Perform a dry run of the upgrade process, so you can evaluate what commands will be run
|
||||||
|
|
||||||
|
.example
|
||||||
|
./upgrade-windows.ps1 -NoPrompt
|
||||||
|
Don't prompt for user input when upgrading
|
||||||
|
|
||||||
|
.example
|
||||||
|
./upgrade-windows.ps1 -AllowAdministrator
|
||||||
|
Allow script to be run as Administrator
|
||||||
|
#>
|
||||||
|
|
||||||
|
param (
|
||||||
|
[switch]$AllowAdministrator, # Force allow installation as administrator
|
||||||
|
[switch]$NoPrompt, # Disable the 3-second wait and press-any-key prompt
|
||||||
|
[switch]$Install, # Perform all installations, even when commands are present
|
||||||
|
[switch]$DryRun, # Run script without installing
|
||||||
|
[switch]$NoWinget # Don't update dependdencies with winget
|
||||||
|
)
|
||||||
|
|
||||||
|
# .description
|
||||||
|
# Get-CommandAvailable: Checks whether a given command is available.
|
||||||
|
# If command is available, returns $false
|
||||||
|
function Get-CommandAvailable {
|
||||||
|
param ($command)
|
||||||
|
# Use a wildcard here so the command doesn't throw an exception we'd have to trycatch
|
||||||
|
# It's not a filthy hack if it's elegant!
|
||||||
|
RETURN (Get-Command -Name $command*)
|
||||||
|
}
|
||||||
|
|
||||||
|
#.description
|
||||||
|
# Invoke-Dryrun a powershell statement
|
||||||
|
function Invoke-Dryrun {
|
||||||
|
param ([string] $command)
|
||||||
|
$prompt = "> "
|
||||||
|
if ($DryRun) {
|
||||||
|
Write-Host "$prompt$command [dry]" -ForegroundColor darkgray
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "$prompt$command" -ForegroundColor white
|
||||||
|
Invoke-Expression $command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#.description
|
||||||
|
# Reset-Path: Reload the Path environment variable
|
||||||
|
function Reset-Path {
|
||||||
|
Write-Output "Reloading Path..."
|
||||||
|
#* This code was created by user [mpen](https://stackoverflow.com/users/65387/mpen) on [StackOverflow](https://stackoverflow.com/a/31845512) and is used in accordance with Creative Commons CC BY-SA 3.0
|
||||||
|
$env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
# Check if Winget is available
|
||||||
|
if ( -not (Get-CommandAvailable winget) ) {
|
||||||
|
Write-Warning "It looks like winget isn't available.`n"
|
||||||
|
Write-Host "Update 'App Installer' through the Microsoft Store, or grab the '.msixbundle' from the winget-cli repository:"
|
||||||
|
Write-Host "( https://github.com/microsoft/winget-cli/releases/latest )`n" -ForegroundColor White
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if the user ran the script with administrator privileges.
|
||||||
|
# Warn them.
|
||||||
|
if ( ([Security.Principal.WindowsIdentity]::GetCurrent().Groups -contains 'S-1-5-32-544') ) {
|
||||||
|
# If an administrator requests installation as administator,
|
||||||
|
# for example, to keep UAC prompts to a minimum, allow it.
|
||||||
|
if ($AllowAdministrator) {
|
||||||
|
# If you pass -AllowAdministrator -NoPrompt as an arg, you're very aware of the damage this script could do to your build env, and you just don't care
|
||||||
|
# The true chad of sysadmins.
|
||||||
|
if (!$NoPrompt) {
|
||||||
|
Write-Warning "Script was run as Administrator. Exit now if you didn't mean to do this!"
|
||||||
|
for ( $i = 3; $i -gt 0; $i--) {
|
||||||
|
Write-Host "Press Ctrl+C to exit. Continuing in $i...`r" -NoNewLine
|
||||||
|
Start-Sleep 1
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Press any key to continue... "
|
||||||
|
[void][Console]::ReadKey(1) # Equivalent to Command Prompt's `pause` command
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
# Throw a fatal errorOccurred if the user tries to run as administrator.
|
||||||
|
Throw "Script must be run as a normal user."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Import the packages from dependencies.json (autogenerated file, do not edit!)
|
||||||
|
if ( -not $NoWinget) {
|
||||||
|
Write-Host "`nInstalling packages with winget..."
|
||||||
|
Invoke-Dryrun 'winget install Microsoft.VisualStudio.2022.BuildTools --override "--wait --quiet --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended"'
|
||||||
|
Invoke-Dryrun "winget import winget/dependencies.json"
|
||||||
|
# Reload the PATH, so we can use some of those sweet new commands we just installed
|
||||||
|
Reset-Path
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check whether everything is available now:
|
||||||
|
$errorOccurred = 0
|
||||||
|
if ( -not (Get-CommandAvailable code) ) {
|
||||||
|
$errorOccurred += 1; Write-Host -ForegroundColor red "Visual Studio Code not available"
|
||||||
|
}
|
||||||
|
if ( -not (Get-CommandAvailable node) ) {
|
||||||
|
$errorOccurred += 2; Write-Host -ForegroundColor red "NodeJS not available"
|
||||||
|
}
|
||||||
|
if ( -not (Get-CommandAvailable npm ) ) {
|
||||||
|
$errorOccurred += 4; Write-Host -ForegroundColor red "Node Package Manager not available";
|
||||||
|
}
|
||||||
|
if ( $errorOccurred ) { exit }
|
||||||
|
|
||||||
|
# .description
|
||||||
|
# EnsureNodePackageInstalled:
|
||||||
|
# Checks for the presence of a cmdlet with a given name
|
||||||
|
# If it's not found, attempt to install it using npm
|
||||||
|
# If it's still not found, abort (this may not be good behavior?)
|
||||||
|
function EnsureNodePackageInstalled {
|
||||||
|
param (
|
||||||
|
[string[]]$command
|
||||||
|
)
|
||||||
|
if ( ($Install) -or -not (Get-CommandAvailable $command[0]) ) {
|
||||||
|
Write-Host "`nInstalling $($command[0])..."
|
||||||
|
Invoke-Dryrun "npm install -g $([string]$command)"
|
||||||
|
Reset-Path
|
||||||
|
if ( -not (Get-CommandAvailable $command[0])) {
|
||||||
|
Throw "$command failed to install. Aborting."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "`n$($command[0]) already installed." -ForegroundColor green
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if electron-rebuild is installed, if not, install it
|
||||||
|
EnsureNodePackageInstalled electron-rebuild
|
||||||
|
|
||||||
|
# These are useful (but not necessary) packages to have installed when working on new VSCode extensions
|
||||||
|
EnsureNodePackageInstalled yo, generator-code
|
||||||
|
|
||||||
|
# We're about to do some path traversal, so save the current directory
|
||||||
|
$prev_directory = $pwd
|
||||||
|
|
||||||
|
# install NodeJS dependencies for this extension
|
||||||
|
Write-Host "`nInstalling NodeJS Dependencies..."
|
||||||
|
Set-Location ..\..
|
||||||
|
Invoke-Dryrun "npm install"
|
||||||
|
|
||||||
|
# Run npm audit fix to upgrade vulnerable dependencies, except breaking changes.
|
||||||
|
Invoke-Dryrun "npm audit fix"
|
||||||
|
|
||||||
|
# if we're on a known VSCode version, go ahead and run electron-rebuild
|
||||||
|
switch -Regex (code --version) {
|
||||||
|
#?: Do we update this in the future, or stop maintaining it and remove this entire switch block?
|
||||||
|
"1\.67\.\d+" { $electronversion = "17.4.1"; break } # April 2022 update
|
||||||
|
"1\.66\.\d+" { $electronversion = "17.2.0"; break } # March 2022 update
|
||||||
|
default { $electronversion = $false } # Unknown update
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( $electronversion ) {
|
||||||
|
Write-Host "`nRebuilding Electron for your version of VSCode..."
|
||||||
|
Invoke-Dryrun "electron-rebuild --version='$electronversion'"
|
||||||
|
Write-Host "Done!" -ForegroundColor green
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host "`nOpen Visual Studio Code, select the `"Help`" tab in the Toolbar, and go to `"About`".`nYou should see a page that looks like the following:" -ForegroundColor darkcyan
|
||||||
|
|
||||||
|
Write-Host " `(i`) Visual Studio Code`n`n Version: 1.66.2 `(user setup`)`n Commit: [Commit ID]`n Date: 2022-04-11T07:46:01.075Z`n Electron: 17.2.0`n [ ... ]" -ForegroundColor White
|
||||||
|
|
||||||
|
Write-Host "Note the Electron version `(17.2.0 in the above example`)." -ForegroundColor darkcyan
|
||||||
|
|
||||||
|
Write-Host "Run the command " -NoNewLine
|
||||||
|
Write-Host "electron-rebuild --version ELECTRON_VERSION" -NoNewLine -ForegroundColor green
|
||||||
|
Write-Host " in Mind Reader`'s root folder.`n"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Return from whence we came
|
||||||
|
Set-Location $prev_directory
|
||||||
|
if ( -not $NoPrompt ) {
|
||||||
|
Write-Host "`nPress any key to exit."; [void][Console]::ReadKey(1)
|
||||||
|
}
|
29
setup-development/windows/winget/dependencies.json
Normal file
29
setup-development/windows/winget/dependencies.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://aka.ms/winget-packages.schema.2.0.json",
|
||||||
|
"CreationDate": "2022-04-23T21:13:03.702-00:00",
|
||||||
|
"Sources": [
|
||||||
|
{
|
||||||
|
"Packages": [
|
||||||
|
{
|
||||||
|
"PackageIdentifier": "Python.Python.3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PackageIdentifier": "Git.Git"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PackageIdentifier": "OpenJS.NodeJS.LTS"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"PackageIdentifier": "Microsoft.VisualStudioCode"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"SourceDetails": {
|
||||||
|
"Argument": "https://winget.azureedge.net/cache",
|
||||||
|
"Identifier": "Microsoft.Winget.Source_8wekyb3d8bbwe",
|
||||||
|
"Name": "winget",
|
||||||
|
"Type": "Microsoft.PreIndexed.Package"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"WinGetVersion": "1.2.10271"
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import HubManager from '../hubManager';
|
import HubManager from '../hubManager';
|
||||||
|
//import EV3Manager from '../ev3Manager';
|
||||||
|
|
||||||
import { CommandEntry } from './commandEntry';
|
import { CommandEntry } from './commandEntry';
|
||||||
|
|
||||||
@ -33,12 +34,23 @@ export const hubCommands: CommandEntry[] = [
|
|||||||
{
|
{
|
||||||
name: 'mind-reader.deleteProgram',
|
name: 'mind-reader.deleteProgram',
|
||||||
callback: deleteProgram
|
callback: deleteProgram
|
||||||
},
|
}/*,
|
||||||
|
{
|
||||||
|
name: 'mind-reader.ev3.test',
|
||||||
|
callback: ev3test
|
||||||
|
}*/
|
||||||
];
|
];
|
||||||
|
|
||||||
// Current connected hub
|
// Current connected hub
|
||||||
let hub: HubManager | null = null;
|
let hub: HubManager | null = null;
|
||||||
|
/*
|
||||||
|
let ev3: EV3Manager | null = null;
|
||||||
|
|
||||||
|
async function ev3test(): Promise<void> {
|
||||||
|
ev3 = await EV3Manager.activate();
|
||||||
|
ev3.test();
|
||||||
|
}
|
||||||
|
*/
|
||||||
async function connectHub(): Promise<void> {
|
async function connectHub(): Promise<void> {
|
||||||
if (hub && hub.isOpen()) {
|
if (hub && hub.isOpen()) {
|
||||||
vscode.window.showWarningMessage('LEGO Hub is already connected, reconnecting...');
|
vscode.window.showWarningMessage('LEGO Hub is already connected, reconnecting...');
|
||||||
@ -53,7 +65,7 @@ async function connectHub(): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let portPath: string | undefined = vscode.workspace.getConfiguration('mindReader.connection').get('portPath');
|
let portPath: string | undefined = vscode.workspace.getConfiguration('mind-reader.connection').get('portPath');
|
||||||
|
|
||||||
if (!portPath) {
|
if (!portPath) {
|
||||||
let slots: vscode.QuickPickItem[] = [];
|
let slots: vscode.QuickPickItem[] = [];
|
||||||
|
@ -1,24 +1,19 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from "vscode";
|
||||||
import * as fs from 'fs';
|
|
||||||
|
|
||||||
import { CommandEntry } from './commandEntry';
|
import { CommandEntry } from "./commandEntry";
|
||||||
|
|
||||||
export const navCommands: CommandEntry[] = [
|
export const navCommands: CommandEntry[] = [
|
||||||
{
|
{
|
||||||
name: 'mind-reader.openWebview',
|
name: 'mind-reader.openWebview',
|
||||||
callback: openWebview,
|
callback: openWebview,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: 'mind-reader.openKeyBindWin',
|
name: "mind-reader.openKeybinds",
|
||||||
callback: () => openKeyBindWin('Windows')
|
callback: () => vscode.commands.executeCommand("workbench.action.openGlobalKeybindings", "mind-reader"),
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'mind-reader.openKeyBindMac',
|
|
||||||
callback: () => openKeyBindWin('Mac'),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
//Navigation Keys......
|
//Navigation Keys......
|
||||||
|
// TODO: Why is this here? Extensions can rebind existing keybinds.
|
||||||
{
|
{
|
||||||
name: 'mind-reader.showAllSymbols',
|
name: 'mind-reader.showAllSymbols',
|
||||||
callback: () => vscode.commands.executeCommand('workbench.action.showAllSymbols'),
|
callback: () => vscode.commands.executeCommand('workbench.action.showAllSymbols'),
|
||||||
@ -82,35 +77,58 @@ export const navCommands: CommandEntry[] = [
|
|||||||
|
|
||||||
// COMMAND CALLBACK IMPLEMENTATIONS
|
// COMMAND CALLBACK IMPLEMENTATIONS
|
||||||
function openWebview(): void {
|
function openWebview(): void {
|
||||||
//vscode.commands.executeCommand('workbench.action.zoomOut');
|
|
||||||
const panel = vscode.window.createWebviewPanel(
|
const panel = vscode.window.createWebviewPanel(
|
||||||
'mindReader', // Identifies the type of the webview. Used internally
|
"mind-reader", // Identifies the type of the webview. Used internally
|
||||||
'Mind Reader', // Title of the panel displayed to the user
|
"Mind Reader", // Title of the panel displayed to the user
|
||||||
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
|
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
|
||||||
{}
|
{}
|
||||||
); // Webview options. More on these later.
|
); // Webview options. More on these later.
|
||||||
|
|
||||||
panel.webview.html = getWebviewContent('media/html/main.html');
|
panel.webview.html = getWebviewContent();
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWebviewContent(filepath: string) {
|
function getWebviewContent() {
|
||||||
return fs.readFileSync(filepath, {encoding: 'utf-8'});
|
return `<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Mind Reader</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<img src="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT6a4XaqHkKcxJ6ZFms1RNrRurcOfl-diW90DAdpAx0Kv-rtrLJXovIhcUpayqFHATkrQ&usqp=CAU" width="600" />
|
||||||
|
<p></p>
|
||||||
|
<h1>Welcome to Mind Reader!</h1>
|
||||||
|
<p>We are the Single Semester Snobs and this is our tool to Help Blind Students Program Lego Mindstorms Robots in Python.</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
This tool includes features such as a hotkey that says how many spaces in the text starts, an Accessibility Pane,
|
||||||
|
Audio Alerts, and an advanced settings window.
|
||||||
|
<br>
|
||||||
|
The tool has hotkeys for both PC and Mac commands.
|
||||||
|
</li>
|
||||||
|
<li>This system is intended for everyone, but primarily for students K-12 who are visually impaired. </li>
|
||||||
|
<li>
|
||||||
|
Our goal is to provide an enhanced experience for students who are visually impaired that is transparent to
|
||||||
|
sighted students.
|
||||||
|
<br>
|
||||||
|
This allows for everyone to use the same software solution, whether or not they are
|
||||||
|
vision impaired.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<p>Use the following key binding to bring up a page for all key bindings for windows
|
||||||
|
<br>
|
||||||
|
Control and Shift and 8
|
||||||
|
</p>
|
||||||
|
<p>Use this key binding to do the same for mac computers:
|
||||||
|
<br>
|
||||||
|
Command and Shift and 9
|
||||||
|
</p>
|
||||||
|
<h2>This is the Lego Spike Prime!</h2z>
|
||||||
|
<p></p>
|
||||||
|
<img src="https://cdn.vox-cdn.com/thumbor/qoaa6N2ppl7oj97MR-aj43qPy0w=/0x0:1024x576/920x613/filters:focal(431x207:593x369):format(webp)/cdn.vox-cdn.com/uploads/chorus_image/image/63339099/lego_spike.0.png" width="300" />
|
||||||
|
<p></p>
|
||||||
|
<a href="https://www.lego.com/en-us/product/lego-education-spike-prime-set-45678">Get the robot!</a>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function openKeyBindWin(os: 'Mac' | 'Windows'): void {
|
|
||||||
//vscode.commands.executeCommand('workbench.action.zoomOut');
|
|
||||||
const panel = vscode.window.createWebviewPanel(
|
|
||||||
'mindReader', // Identifies the type of the webview. Used internally
|
|
||||||
'MR Key Bindings', // Title of the panel displayed to the user
|
|
||||||
vscode.ViewColumn.One, // Editor column to show the new webview panel in.
|
|
||||||
{}
|
|
||||||
); // Webview options. More on these later.
|
|
||||||
|
|
||||||
if (os === 'Windows') {
|
|
||||||
panel.webview.html = getWebviewContent('media/html/winkeys.html');
|
|
||||||
} else if (os === 'Mac') {
|
|
||||||
panel.webview.html = getWebviewContent('media/html/mackeys.html');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,168 +1,388 @@
|
|||||||
import * as vscode from 'vscode';
|
"use strict";
|
||||||
import * as pl from '../pylex';
|
import pl = require("../pylex");
|
||||||
|
import { CommandEntry } from './commandEntry';
|
||||||
import { CommandEntry } from './commandEntry';
|
import { Position, Selection, TextEditor, TextLine, window, workspace } from "vscode";
|
||||||
|
|
||||||
export const textCommands: CommandEntry[] = [
|
export const textCommands: CommandEntry[] = [
|
||||||
{
|
{
|
||||||
name: 'mind-reader.getIndent',
|
name: 'mind-reader.getLineNumber',
|
||||||
callback: getIndent,
|
callback: getLineNumber,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'mind-reader.getIndent',
|
||||||
|
callback: getIndent,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mind-reader.getLeadingSpaces',
|
||||||
|
callback: getLeadingSpaces,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mind-reader.selectLeadingWhitespace',
|
||||||
|
callback: selectLeadingWhitespace
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mind-reader.getNumberOfSelectedLines',
|
||||||
|
callback: getNumberOfSelectedLines,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mind-reader.getLineScope',
|
||||||
|
callback: runLineContext,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'mind-reader.getWordsUnderCursor',
|
||||||
|
callback: runCursorContext
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
{
|
/** Helper Function
|
||||||
name: 'mind-reader.runLineContext',
|
*
|
||||||
callback: runLineContext,
|
* @param editor
|
||||||
},
|
* @returns numSpaces
|
||||||
|
** There are two methods that can be used to find the leading spaces:
|
||||||
|
** method 1:
|
||||||
|
** calculates the number of leading spaces by finding the length of the current line
|
||||||
|
** then subtracting from that the length of the text after trimming the whitespace at the start
|
||||||
|
** which will equal the number of whitespace characters
|
||||||
|
**
|
||||||
|
** TO-USE: set calculateLeadingSpaces to true
|
||||||
|
**
|
||||||
|
** method 2 (default):
|
||||||
|
** finds the index position of the first non-whitespace character in a 0-index
|
||||||
|
** this number will equal the number of spaces preceding the non-whitespace character
|
||||||
|
** due to the nature of 0-indexes.
|
||||||
|
**
|
||||||
|
** TO-USE: set calculateLeadingSpaces to false
|
||||||
|
*/
|
||||||
|
function fetchNumberOfLeadingSpaces(editor: TextEditor | undefined): number {
|
||||||
|
let numSpaces: number = 0;
|
||||||
|
|
||||||
{
|
|
||||||
name: 'mind-reader.runCursorContext',
|
|
||||||
callback: runCursorContext
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
/*
|
||||||
|
* set true to use method 1: find the number of leading spaces through arithmetic
|
||||||
|
* set false to use method 2: find the index position of the first non-whitespace character in a 0-index
|
||||||
|
* default: false
|
||||||
|
*/
|
||||||
|
const calculateLeadingSpaces: boolean = false; // change boolean value to change method
|
||||||
|
const line : TextLine = fetchLine(editor);
|
||||||
|
|
||||||
|
/* If true, calculate by arithmetic otherwise get index */
|
||||||
|
numSpaces = (calculateLeadingSpaces)
|
||||||
|
? pl.Lexer.getLeadingSpacesByArithmetic(line)
|
||||||
|
: pl.Lexer.getLeadingSpacesByIndex(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
return numSpaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper Function
|
||||||
|
* * This function returns the number of selected lines in the active text editor window
|
||||||
|
@param editor
|
||||||
|
@returns numberOfSelectedLines
|
||||||
|
*/
|
||||||
|
function fetchNumberOfSelectedLines(editor: TextEditor | undefined): number {
|
||||||
|
let numberOfSelectedLines: number = 0;
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
numberOfSelectedLines = editor.selections.reduce((prev, curr) => prev + (curr.end.line - curr.start.line), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return numberOfSelectedLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper Function
|
||||||
|
** This function returns the line number of the active text editor window
|
||||||
|
* @param editor
|
||||||
|
* @returns editor!.selection.active.line + 1
|
||||||
|
*/
|
||||||
|
function fetchLineNumber(editor: TextEditor | undefined): number {
|
||||||
|
return editor!.selection.active.line + 1; // line numbers start at 1, not 0, so we add 1 to the result
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Helper Function
|
||||||
|
** This function returns the text from the current line of the active text editor window
|
||||||
|
* @param editor
|
||||||
|
* @returns editor.document.lineAt(fetchLineNumber(editor) - 1)
|
||||||
|
*/
|
||||||
|
function fetchLine(editor: TextEditor | undefined): TextLine {
|
||||||
|
return editor!.document.lineAt(fetchLineNumber(editor) - 1); // We want the line index, so we remove the 1 we added to the result in fetchLineNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function
|
||||||
|
* Function to return the number of selected (highlighted) lines
|
||||||
|
* Changes output to 'Line' for 1 line and 'Lines' for all other instances
|
||||||
|
*/
|
||||||
|
function getNumberOfSelectedLines(): void {
|
||||||
|
const editor: TextEditor | undefined = window.activeTextEditor;
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
const numberOfSelectedLines: number = fetchNumberOfSelectedLines(editor);
|
||||||
|
|
||||||
|
(numberOfSelectedLines !== 1)
|
||||||
|
? window.showInformationMessage(`${numberOfSelectedLines.toString()} Lines Selected`)
|
||||||
|
: window.showInformationMessage(`${numberOfSelectedLines.toString()} Line Selected`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.showErrorMessage('No document currently active');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function
|
||||||
|
* Outputs the current line number the cursor is on
|
||||||
|
*/
|
||||||
|
function getLineNumber(): void {
|
||||||
|
const editor: TextEditor | undefined = window.activeTextEditor;
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
const lineNum: number = fetchLineNumber(editor);
|
||||||
|
|
||||||
|
window.showInformationMessage(`Line ${lineNum.toString()}`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.showErrorMessage('No document currently active');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function
|
||||||
|
* Used to get the number of indents on a line
|
||||||
|
*/
|
||||||
function getIndent(): void {
|
function getIndent(): void {
|
||||||
let editor = vscode.window.activeTextEditor;
|
const editor: TextEditor | undefined = window.activeTextEditor;
|
||||||
if(editor)
|
|
||||||
{
|
if (editor) {
|
||||||
let lineNum = editor.selection.active.line + 1;
|
const lineNum: number = (fetchLineNumber(editor));
|
||||||
let textLine = editor.document.lineAt(lineNum - 1);
|
const line : TextLine = fetchLine(editor);
|
||||||
if(textLine.isEmptyOrWhitespace)
|
|
||||||
{
|
if (line.isEmptyOrWhitespace) {
|
||||||
vscode.window.showInformationMessage("Line number " + lineNum.toString() + " Is Empty");
|
window.showInformationMessage(`Line ${lineNum.toString()} is Empty`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Grab tab format from open document
|
||||||
|
const tabFmt: pl.TabInfo = {
|
||||||
|
size: typeof editor.options.tabSize === 'number'? editor.options.tabSize: 4,
|
||||||
|
hard: !editor.options.insertSpaces
|
||||||
|
};
|
||||||
|
const i: number = pl.Lexer.getIndent(line.text, tabFmt);
|
||||||
|
|
||||||
|
(i !== 1)
|
||||||
|
? window.showInformationMessage(`Line ${lineNum.toString()}: ${i.toString()} indents`)
|
||||||
|
: window.showInformationMessage(`Line ${lineNum.toString()}: ${i.toString()} indent`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
{
|
window.showErrorMessage('No document currently active');
|
||||||
// Grab tab format from open document
|
}
|
||||||
let tabFmt = {
|
|
||||||
size: editor.options.tabSize as number,
|
}
|
||||||
hard: !editor.options.insertSpaces
|
|
||||||
};
|
/* Function
|
||||||
let i = pl.Lexer.getIndent(textLine.text, tabFmt);
|
* Returns the number of leading spaces on the line the cursor is on
|
||||||
vscode.window.showInformationMessage("Line Number " + lineNum.toString() + " Indentation " + i.toString());
|
*/
|
||||||
|
function getLeadingSpaces(): void {
|
||||||
|
const editor: TextEditor | undefined = window.activeTextEditor;
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
const lineNum : number = fetchLineNumber(editor);
|
||||||
|
const line : TextLine | undefined = fetchLine(editor);
|
||||||
|
|
||||||
|
if (line.isEmptyOrWhitespace) {
|
||||||
|
window.showInformationMessage(`Line ${lineNum.toString()} is empty`);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const numSpaces = fetchNumberOfLeadingSpaces(editor);
|
||||||
|
|
||||||
|
/* Ternary operator to change the tense of 'space' to 'spaces' for the output if numSpaces is 0 or greater than 1 */
|
||||||
|
(numSpaces !== 1)
|
||||||
|
? window.showInformationMessage(`Line ${lineNum.toString()}: ${numSpaces.toString()} spaces`)
|
||||||
|
: window.showInformationMessage(`Line ${lineNum.toString()}: ${numSpaces.toString()} space`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.showErrorMessage('No document currently active');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Function
|
||||||
|
* Selects the leading whitespace at the beginning of a line
|
||||||
|
* This feature was a request from Senior Design Day Spring 2022
|
||||||
|
*/
|
||||||
|
function selectLeadingWhitespace(): void {
|
||||||
|
const editor : TextEditor | undefined = window.activeTextEditor;
|
||||||
|
|
||||||
|
if (editor) {
|
||||||
|
const numSpaces = fetchNumberOfLeadingSpaces(editor); // This will be used for the output message
|
||||||
|
const lineNum : number = (fetchLineNumber(editor)); // Get the displayed line number
|
||||||
|
|
||||||
|
/* If numSpaces isn't greater than 1, then there is no leading whitespace to select */
|
||||||
|
if (numSpaces >= 1) {
|
||||||
|
const line : TextLine = fetchLine(editor);
|
||||||
|
const startPos: number = line.range.start.character; // Start at the starting character position
|
||||||
|
const endPos : number = line.firstNonWhitespaceCharacterIndex; // End at the first non whitespace character index
|
||||||
|
|
||||||
|
/* Apply our selection */
|
||||||
|
/* We need to subtract 1 from lineNum because we added 1 during the fetchLineNumber above and we want the 0-index for position, so remove it */
|
||||||
|
editor.selection = new Selection(new Position((lineNum - 1), startPos), new Position((lineNum - 1), endPos));
|
||||||
|
|
||||||
|
|
||||||
|
/* Ternary operator to change the tense of 'space' to 'spaces' for the output if numSpaces is 0 or greater than 1 */
|
||||||
|
(numSpaces !== 1)
|
||||||
|
? window.showInformationMessage(`Line ${lineNum.toString()}: ${numSpaces.toString()} spaces selected`)
|
||||||
|
: window.showInformationMessage(`Line ${lineNum.toString()}: ${numSpaces.toString()} space selected`);
|
||||||
|
|
||||||
|
// Move the cursor to the new selection
|
||||||
|
window.showTextDocument(editor.document);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.showErrorMessage(`Line ${lineNum.toString()}: No leading spaces to select!`); // No whitespace to select
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
window.showErrorMessage('No document currently active'); // No active document
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else{
|
|
||||||
vscode.window.showErrorMessage('No document currently active');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function runLineContext(): void {
|
function runLineContext(): void {
|
||||||
let editor = vscode.window.activeTextEditor;
|
const editor: TextEditor | undefined = window.activeTextEditor;
|
||||||
if (editor){
|
|
||||||
// current text and line number
|
|
||||||
let editorText = editor.document.getText();
|
|
||||||
let line = editor.selection.active.line;
|
|
||||||
|
|
||||||
// get tab info settings
|
if (editor) {
|
||||||
let size = parseInt(editor.options.tabSize as string);
|
// current text and line number
|
||||||
let hard = !editor.options.insertSpaces;
|
const editorText: string = editor.document.getText();
|
||||||
|
const line : number = editor.selection.active.line;
|
||||||
|
// get tab info settings
|
||||||
|
const size : number = typeof editor.options.tabSize === 'number'? editor.options.tabSize: 4;
|
||||||
|
const hard : boolean = !editor.options.insertSpaces;
|
||||||
|
// initialize parser
|
||||||
|
const parser : pl.Parser = new pl.Parser(editorText, {
|
||||||
|
size,
|
||||||
|
hard
|
||||||
|
});
|
||||||
|
|
||||||
// initialize parser
|
parser.parse();
|
||||||
let parser = new pl.Parser(editorText, {size, hard});
|
const context: pl.LexNode[] = parser.context(line);
|
||||||
parser.parse();
|
// build text
|
||||||
|
const contentString: string = createContextString(context, line);
|
||||||
|
|
||||||
let context = parser.context(line);
|
window.showInformationMessage(contentString);
|
||||||
|
}
|
||||||
// build text
|
else {
|
||||||
let contentString = createContextString(context, line);
|
window.showErrorMessage('No document currently active');
|
||||||
vscode.window.showInformationMessage(contentString);
|
}
|
||||||
} else {
|
|
||||||
vscode.window.showErrorMessage('No document currently active');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createContextString(context: pl.LexNode[], line: number): string {
|
function createContextString(context: pl.LexNode[], line: number): string {
|
||||||
if (context.length < 1) {
|
if (context.length < 1) {
|
||||||
throw new Error('Cannot create context string for empty context');
|
throw new Error('Cannot create context string for empty context');
|
||||||
}
|
}
|
||||||
|
|
||||||
let contextString = 'Line ' + (line+1); // 1 based
|
let contextString: string = `Line ${line + 1}`; // 1 based
|
||||||
|
// Print the current line
|
||||||
if (context[0].token && context[0].token.attr) {
|
if (context[0].token && context[0].token.attr) {
|
||||||
contextString += ': ' + context[0].token.type.toString() + ' ' + context[0].token.attr.toString();
|
let tokenTypeString: string = `${context[0].token.type.toString()}`;
|
||||||
|
contextString += `: ${tokenTypeString !== pl.PylexSymbol.STATEMENT?tokenTypeString:""
|
||||||
|
} ${context[0].token.attr.toString()}`;
|
||||||
}
|
}
|
||||||
for (let i = 1; i < context.length; i++) {
|
|
||||||
let node = context[i];
|
|
||||||
if (node.label === 'root') {
|
|
||||||
// root
|
|
||||||
contextString += ' in the Document Root';
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node.token!.type !== pl.PylexSymbol.EMPTY &&
|
for (let i: number = 1; i < context.length; i++) {
|
||||||
node.token!.type !== pl.PylexSymbol.INDENT) {
|
const node: pl.LexNode = context[i];
|
||||||
contextString += ' inside ' + node.token!.type.toString();
|
const inside: string = "inside";
|
||||||
if (node.token!.attr) {
|
// Node contains information relevant to the current line
|
||||||
contextString += ' ' + node.token!.attr.toString();
|
if (node.token && node.token.type !== pl.PylexSymbol.EMPTY &&
|
||||||
|
node.token.type !== pl.PylexSymbol.STATEMENT) {
|
||||||
|
contextString += ` ${inside} ${node.token.type.toString()}`;
|
||||||
|
if (node.token.attr) {
|
||||||
|
contextString += ` ${node.token.attr.toString()}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Node is the document root
|
||||||
|
if (node.label === 'root') {
|
||||||
|
// Append the name (relative path) of the document in the workspace
|
||||||
|
if (window.activeTextEditor?.document.uri) {
|
||||||
|
contextString += ` ${inside} ${workspace.asRelativePath(window.activeTextEditor?.document.uri)}`;
|
||||||
|
} else {
|
||||||
|
contextString += ` ${inside} the Document`;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return contextString;
|
return contextString;
|
||||||
}
|
}
|
||||||
|
|
||||||
// find up to `n` words around the cursor, where `n` is
|
/*
|
||||||
// the value of `#mindReader.reader.contextWindow`
|
* find up to `n` words around the cursor, where `n` is
|
||||||
|
* the value of `#mind-reader.reader.contextWindow`
|
||||||
|
*/
|
||||||
function runCursorContext(): void {
|
function runCursorContext(): void {
|
||||||
let editor = vscode.window.activeTextEditor;
|
const editor: TextEditor | undefined = window.activeTextEditor;
|
||||||
if (!editor) {
|
|
||||||
vscode.window.showErrorMessage('RunCursorContext: No Active Editor');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const cursorPos: vscode.Position = editor.selection.active;
|
if (!editor) {
|
||||||
const text: string = editor.document.lineAt(cursorPos).text;
|
window.showErrorMessage('RunCursorContext: No Active Editor');
|
||||||
const windowSize: number = vscode.workspace.getConfiguration('mindReader').get('reader.contextWindow')!;
|
return;
|
||||||
|
|
||||||
let trimmedText = text.trimStart(); // trim leading whitespace
|
|
||||||
let leadingWS = text.length - trimmedText.length; // # of characters of leading whitespace
|
|
||||||
trimmedText = trimmedText.trimEnd(); // trim trailing whitespace
|
|
||||||
let pos = leadingWS;
|
|
||||||
let maxPos = text.length;
|
|
||||||
|
|
||||||
// clamp cursor start/end to new range
|
|
||||||
let col = cursorPos.character; // effective column of the cursor position
|
|
||||||
if (col < leadingWS) {
|
|
||||||
// move effective start to first non-whitespace character in the line
|
|
||||||
col = leadingWS;
|
|
||||||
} else if (col > leadingWS + trimmedText.length - 1) {
|
|
||||||
// move effective end to last non-whitespace character in the line
|
|
||||||
col = leadingWS + trimmedText.length - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate list of space separate words with range data (start, end)
|
|
||||||
// TODO: can find user position to be done in one pass
|
|
||||||
let spaceWords: {word: string, start: number, end: number}[] = [];
|
|
||||||
while (pos < maxPos && trimmedText.length > 0) {
|
|
||||||
let word = trimmedText.replace(/ .*/, '');
|
|
||||||
spaceWords.push({word, start: pos, end: pos+word.length});
|
|
||||||
|
|
||||||
// remove processed word from trimmed text
|
|
||||||
const oldText = trimmedText;
|
|
||||||
trimmedText = trimmedText.replace(/[^ ]+/, '').trimStart();
|
|
||||||
|
|
||||||
// update pos to start of next word
|
|
||||||
pos += oldText.length - trimmedText.length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find word the user is in
|
|
||||||
let contextStart: number = -1, contextEnd: number = -1;
|
|
||||||
for (let i = 0; i < spaceWords.length; i++) {
|
|
||||||
if (col >= spaceWords[i].start && col <= spaceWords[i].end) {
|
|
||||||
// found the word
|
|
||||||
contextStart = Math.max(0, i - windowSize); // clamp start index
|
|
||||||
contextEnd = Math.min(spaceWords.length, i + windowSize + 1); // clamp end index
|
|
||||||
|
|
||||||
// construct cursor context string
|
|
||||||
let contextString = '';
|
|
||||||
for (let i = contextStart; i < contextEnd; i++) {
|
|
||||||
contextString += spaceWords[i].word + ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
// output cursor context string
|
|
||||||
vscode.window.showInformationMessage(contextString);
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
const cursorPos : Position = editor.selection.active;
|
||||||
|
const text : string = editor.document.lineAt(cursorPos).text;
|
||||||
|
const windowSize : any = workspace.getConfiguration('mind-reader').get('reader.contextWindow');
|
||||||
|
let trimmedText: string = text.trimStart(); // trim leading whitespace
|
||||||
|
const leadingWS : number = text.length - trimmedText.length; // # of characters of leading whitespace
|
||||||
|
let pos : number = leadingWS;
|
||||||
|
const maxPos : number = text.length;
|
||||||
|
// clamp cursor start/end to new range
|
||||||
|
let col : number = cursorPos.character; // effective column of the cursor position
|
||||||
|
|
||||||
|
trimmedText = trimmedText.trimEnd(); // trim trailing whitespace
|
||||||
|
|
||||||
|
if (col < leadingWS) {
|
||||||
|
// move effective start to first non-whitespace character in the line
|
||||||
|
col = leadingWS;
|
||||||
|
}
|
||||||
|
else if (col > leadingWS + trimmedText.length - 1) {
|
||||||
|
// move effective end to last non-whitespace character in the line
|
||||||
|
col = leadingWS + trimmedText.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate list of space separate words with range data (start, end)
|
||||||
|
// TODO: can find user position to be done in one pass
|
||||||
|
const spaceWords: any[] = [];
|
||||||
|
|
||||||
|
while (pos < maxPos && trimmedText.length > 0) {
|
||||||
|
const word: string = trimmedText.replace(/ .*/, '');
|
||||||
|
|
||||||
|
spaceWords.push({
|
||||||
|
word,
|
||||||
|
start: pos,
|
||||||
|
end: pos + word.length
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove processed word from trimmed text
|
||||||
|
const oldText: string = trimmedText;
|
||||||
|
trimmedText = trimmedText.replace(/[^ ]+/, '').trimStart();
|
||||||
|
// update pos to start of next word
|
||||||
|
pos += oldText.length - trimmedText.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// find word the user is in
|
||||||
|
let contextStart: number = -1;
|
||||||
|
let contextEnd : number = -1;
|
||||||
|
|
||||||
|
for (let i: number = 0; i < spaceWords.length; i++) {
|
||||||
|
if (col >= spaceWords[i].start && col <= spaceWords[i].end) {
|
||||||
|
// found the word
|
||||||
|
contextStart = Math.max(0, i - windowSize); // clamp start index
|
||||||
|
contextEnd = Math.min(spaceWords.length, i + windowSize + 1); // clamp end index
|
||||||
|
// construct cursor context string
|
||||||
|
let contextString: string = '';
|
||||||
|
|
||||||
|
for (let i: number = contextStart; i < contextEnd; i++) {
|
||||||
|
contextString += spaceWords[i].word + ' ';
|
||||||
|
}
|
||||||
|
// output cursor context string
|
||||||
|
window.showInformationMessage(contextString);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
31
src/ev3Manager.ts
Normal file
31
src/ev3Manager.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
//import * as fs from 'fs';
|
||||||
|
//import { logger } from './extension';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export default class EV3Manager {
|
||||||
|
private ev3devBrowser: vscode.Extension<any> | undefined = vscode.extensions.getExtension("ev3dev.ev3dev-browser");
|
||||||
|
|
||||||
|
private constructor() {}
|
||||||
|
public test() {
|
||||||
|
//console.log(this.ev3devBrowser);
|
||||||
|
// This seems to be the only thing we, as an extension,
|
||||||
|
// are allowed to do with this other extension.
|
||||||
|
vscode.commands.executeCommand("ev3devBrowser.action.pickDevice", null);
|
||||||
|
}
|
||||||
|
public static activate(): Promise<EV3Manager> {
|
||||||
|
return new Promise (async (resolve) => {
|
||||||
|
try {
|
||||||
|
let mgr = new EV3Manager();
|
||||||
|
// Wait for ev3devBrowser to start
|
||||||
|
await mgr.ev3devBrowser?.activate();
|
||||||
|
// Return ev3Manager
|
||||||
|
return resolve(mgr);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -1,49 +1,47 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from "vscode";
|
||||||
import * as pl from './pylex';
|
import * as pl from "./pylex";
|
||||||
|
import CommandNodeProvider from "./commandNodeProvider";
|
||||||
|
import Logger from "./log";
|
||||||
|
import { lineHighlighter } from "./lineHighlighter";
|
||||||
|
|
||||||
import {
|
import { accessCommands, hubCommands, navCommands, textCommands } from "./commands";
|
||||||
accessCommands,
|
|
||||||
hubCommands,
|
|
||||||
navCommands,
|
|
||||||
textCommands
|
|
||||||
} from './commands';
|
|
||||||
|
|
||||||
import CommandNodeProvider from './commandNodeProvider';
|
|
||||||
import Logger from './log';
|
|
||||||
|
|
||||||
// Output Logger
|
// Output Logger
|
||||||
const product: string = vscode.workspace.getConfiguration('mindReader').get('productType')!;
|
const product: string = vscode.workspace.getConfiguration("mind-reader").get("productType")!;
|
||||||
const outputChannel = vscode.window.createOutputChannel(product + " Output");
|
const outputChannel = vscode.window.createOutputChannel(product + " Output");
|
||||||
export const logger = new Logger(outputChannel);
|
export const logger = new Logger(outputChannel);
|
||||||
|
|
||||||
let parser: pl.Parser = new pl.Parser();
|
let parser: pl.Parser = new pl.Parser();
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
vscode.window.showInformationMessage('Mind_Reader is loaded!');
|
// Engage LineHighlighter
|
||||||
|
lineHighlighter();
|
||||||
|
|
||||||
parser.parse('Beep Boop');
|
parser.parse("Beep Boop");
|
||||||
|
|
||||||
const allCommands = [
|
const allCommands = [
|
||||||
accessCommands,
|
accessCommands,
|
||||||
hubCommands,
|
hubCommands,
|
||||||
navCommands,
|
navCommands,
|
||||||
textCommands
|
textCommands,
|
||||||
].flat(1);
|
].flat(1);
|
||||||
|
|
||||||
// Register Commands
|
// Register Commands
|
||||||
allCommands.forEach(command => {
|
allCommands.forEach((command) => {
|
||||||
let disposable = vscode.commands.registerCommand(
|
context.subscriptions.push(
|
||||||
command.name,
|
vscode.commands.registerCommand(command.name, command.callback)
|
||||||
command.callback
|
|
||||||
);
|
);
|
||||||
context.subscriptions.push(disposable);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let accessProvider = new CommandNodeProvider([accessCommands, textCommands].flat(1));
|
let accessProvider = new CommandNodeProvider(
|
||||||
vscode.window.registerTreeDataProvider('accessActions', accessProvider);
|
[accessCommands, textCommands].flat(1)
|
||||||
|
);
|
||||||
|
vscode.window.registerTreeDataProvider("accessActions", accessProvider);
|
||||||
|
|
||||||
let hubProvider = new CommandNodeProvider(hubCommands);
|
let hubProvider = new CommandNodeProvider(hubCommands);
|
||||||
vscode.window.registerTreeDataProvider('hubActions', hubProvider);
|
vscode.window.registerTreeDataProvider("hubActions", hubProvider);
|
||||||
|
|
||||||
|
vscode.window.showInformationMessage("Mind Reader finished loading!");
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate() {}
|
export function deactivate() {}
|
||||||
|
@ -76,12 +76,14 @@ export default class HubManager {
|
|||||||
|
|
||||||
// get full lines in buffer
|
// get full lines in buffer
|
||||||
|
|
||||||
let msgs = this.receiveBuffer.split(/\r/); // split by newline
|
let msgs = this.receiveBuffer.split(/[\r>]/); // split by newline
|
||||||
this.receiveBuffer = msgs.pop()!; // store unhandled data
|
this.receiveBuffer = msgs.pop()!; // store unhandled data
|
||||||
|
|
||||||
msgs = msgs.filter(x => !x.startsWith('{"m":0,"p":')); // drop sensor broadcast response spam
|
msgs = msgs.filter(x => !x.match(/{"m":\d+,"p":/)); // drop sensor broadcast response spam
|
||||||
|
|
||||||
for (const msg of msgs) {
|
for (const msg of msgs) {
|
||||||
|
// check if message is actually json
|
||||||
|
if (!msg.includes("{")) { continue; }
|
||||||
// check if this msg is a response to a pending request
|
// check if this msg is a response to a pending request
|
||||||
try {
|
try {
|
||||||
let json: { [key: string]: any };
|
let json: { [key: string]: any };
|
||||||
@ -112,11 +114,15 @@ export default class HubManager {
|
|||||||
case 'runtime_error':
|
case 'runtime_error':
|
||||||
logger.error(Buffer.from(params[3], 'base64').toString());
|
logger.error(Buffer.from(params[3], 'base64').toString());
|
||||||
break;
|
break;
|
||||||
|
case 2:
|
||||||
|
logger.info(`Battery at ${params[0]}V`);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
vscode.window.showErrorMessage("Program Error.");
|
vscode.window.showErrorMessage("Program Error.");
|
||||||
|
console.log(`Program error: ${msg}`);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log('Could not parse JSON:', msg);
|
console.log('Could not parse JSON:', msg, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
311
src/lineHighlighter.ts
Normal file
311
src/lineHighlighter.ts
Normal file
@ -0,0 +1,311 @@
|
|||||||
|
/**
|
||||||
|
* ? ██╗ ██╗██╗ ██████╗ ██╗ ██╗██╗ ██╗ ██████╗ ██╗ ██╗████████╗ ██╗████████╗
|
||||||
|
* ? ██║ ██║██║██╔════╝ ██║ ██║██║ ██║██╔════╝ ██║ ██║╚══██╔══╝ ██║╚══██╔══╝
|
||||||
|
* ? ███████║██║██║ ███╗███████║██║ ██║██║ ███╗███████║ ██║ █████╗██║ ██║
|
||||||
|
* ? ██╔══██║██║██║ ██║██╔══██║██║ ██║██║ ██║██╔══██║ ██║ ╚════╝██║ ██║
|
||||||
|
* ? ██║ ██║██║╚██████╔╝██║ ██║███████╗██║╚██████╔╝██║ ██║ ██║ ██║ ██║
|
||||||
|
* ? ╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝
|
||||||
|
* ! Initial Setup:
|
||||||
|
* ! Open settings.json (ctrl+shift+p type 'settings' choose: 'Preferences: Open Settings (JSON))
|
||||||
|
* ! Add the following to the bottom (may have to add a comma to the line above if it's not there, also remove the *s):
|
||||||
|
* "mind-reader.lineHighlighter.isEnabled" : true,
|
||||||
|
* "mind-reader.lineHighlighter.multiLineIsEnabled" : false,
|
||||||
|
*
|
||||||
|
* "mind-reader.lineHighlighter.backgroundColor" : "#232C5C",
|
||||||
|
|
||||||
|
* "mind-reader.lineHighlighter.outlineColor" : "#4866FE",
|
||||||
|
* "mind-reader.lineHighlighter.outlineWidth" : "1px",
|
||||||
|
* "mind-reader.lineHighlighter.outlineStyle" : "solid",
|
||||||
|
*
|
||||||
|
* "mind-reader.lineHighlighter.borderColorTop" : "#FFFFFF",
|
||||||
|
* "mind-reader.lineHighlighter.borderColorRight" : "#FFFFFF",
|
||||||
|
* "mind-reader.lineHighlighter.borderColorBottom" : "#FFFFFF",
|
||||||
|
* "mind-reader.lineHighlighter.borderColorLeft" : "#FFFFFF",
|
||||||
|
*
|
||||||
|
* "mind-reader.lineHighlighter.borderWidthTop" : "1px",
|
||||||
|
* "mind-reader.lineHighlighter.borderWidthRight" : "16px",
|
||||||
|
* "mind-reader.lineHighlighter.borderWidthBottom" : "1px",
|
||||||
|
* "mind-reader.lineHighlighter.borderWidthLeft" : "1px",
|
||||||
|
*
|
||||||
|
* "mind-reader.lineHighlighter.borderStyleTop" : "solid",
|
||||||
|
* "mind-reader.lineHighlighter.borderStyleRight" : "solid",
|
||||||
|
* "mind-reader.lineHighlighter.borderStyleBottom" : "solid",
|
||||||
|
* "mind-reader.lineHighlighter.borderStyleLeft" : "solid",
|
||||||
|
*
|
||||||
|
* "mind-reader.lineHighlighter.fontStyle" : "normal",
|
||||||
|
* "mind-reader.lineHighlighter.fontWeight" : "bolder",
|
||||||
|
* "mind-reader.lineHighlighter.textColor" : "#FFFFFF",
|
||||||
|
*
|
||||||
|
* ! Restart VSCode for changes to take effect (if they didn't automatically)
|
||||||
|
* ! Afterwards you can now edit using the settings window, or manually edit them
|
||||||
|
* ! directly in settings.json by editing the values.
|
||||||
|
*
|
||||||
|
* TODO: FEATURE: Add ability for user to change options through a command pallette configurator
|
||||||
|
* TODO: FEATURE: Add hotkey to toggle linehighlighter on/off
|
||||||
|
* TODO: BUG: Adding the settings configurator made default settings break (if no values are found in settings.json)
|
||||||
|
**/
|
||||||
|
'use strict';
|
||||||
|
import { Position, window, workspace, TextEditorDecorationType, TextEditor, WorkspaceConfiguration, Range } from 'vscode';
|
||||||
|
|
||||||
|
export { lineHighlighter };
|
||||||
|
|
||||||
|
let highlightStyle: TextEditorDecorationType;
|
||||||
|
|
||||||
|
function lineHighlighter(): void {
|
||||||
|
let highlightStyle : TextEditorDecorationType = getHighlighterStyle();
|
||||||
|
let activeTextEditor : TextEditor | undefined = window.activeTextEditor;
|
||||||
|
let isEnabled : boolean | undefined = getHighlighterStatus();
|
||||||
|
let multiLineIsEnabled: boolean | undefined = getMultiLineHighlighterStatus();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger the line highlight when the extension loads so current line gets highlighted
|
||||||
|
*/
|
||||||
|
triggerHighlight();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger for when the active text editor changes
|
||||||
|
*/
|
||||||
|
window.onDidChangeActiveTextEditor((editor) => {
|
||||||
|
if (!editor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerHighlight();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger for when text selection changes
|
||||||
|
*/
|
||||||
|
window.onDidChangeTextEditorSelection((editor) => {
|
||||||
|
if (!editor.textEditor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerHighlight();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger for when the text document changes
|
||||||
|
*/
|
||||||
|
workspace.onDidChangeTextDocument(() => {
|
||||||
|
if (!activeTextEditor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerHighlight();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger for when the window state changes
|
||||||
|
*/
|
||||||
|
window.onDidChangeWindowState((editor) => {
|
||||||
|
if (!editor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
triggerHighlight();
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trigger for when configuration changes
|
||||||
|
*/
|
||||||
|
workspace.onDidChangeConfiguration((editor) => {
|
||||||
|
if (!editor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
highlightStyle.dispose(); // Dump existing styling
|
||||||
|
isEnabled = getHighlighterStatus(); // check if line highlighter is enable/disabled
|
||||||
|
multiLineIsEnabled = getMultiLineHighlighterStatus(); // Check if multiline highlighting is enabled/disabled
|
||||||
|
highlightStyle = getHighlighterStyle(); // get new line highlighter styling
|
||||||
|
triggerHighlight(); // trigger highlight with new styling
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* main function that triggers the highlights
|
||||||
|
*/
|
||||||
|
function triggerHighlight(): void {
|
||||||
|
if (!activeTextEditor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the activeTextEditor to the current active window
|
||||||
|
*/
|
||||||
|
activeTextEditor = window.activeTextEditor;
|
||||||
|
if (activeTextEditor !== undefined) {
|
||||||
|
/**
|
||||||
|
* If the line highlighter function is enabled
|
||||||
|
* set the decorations with our chosen highlighting style on the selection
|
||||||
|
* otherwise (highlighter is disabled) dump our highlighting style
|
||||||
|
*/
|
||||||
|
switch (isEnabled) {
|
||||||
|
case true: /* isEnabled is true */
|
||||||
|
switch (multiLineIsEnabled) {
|
||||||
|
case true: /* isEnabled is true and multiLineIsEnabled is true */
|
||||||
|
activeTextEditor.setDecorations(highlightStyle, activeTextEditor.selections);
|
||||||
|
break;
|
||||||
|
case false: /* isEnabled is true and multiLineIsEnabled is false */
|
||||||
|
switch (activeTextEditor.selection.isSingleLine) {
|
||||||
|
case true: /* isEnabled is true and multiLineIsEnabled is false and VSCode is reporting a single line */
|
||||||
|
let currentPosition = [];
|
||||||
|
for (let i = 0; i < activeTextEditor.selections.length; i++) {
|
||||||
|
currentPosition[i] = { range: new Range(activeTextEditor.selections[i].anchor, activeTextEditor.selections[i].anchor) };
|
||||||
|
}
|
||||||
|
|
||||||
|
activeTextEditor.setDecorations(highlightStyle, currentPosition);
|
||||||
|
break;
|
||||||
|
case false: /* isEnabled is true and multiLineIsEnabled is false and VSCode is reporting multiple lines */
|
||||||
|
// Dispose of our highlighting style so multiple lines aren't all highlighted when clicking and dragging to highlight
|
||||||
|
activeTextEditor.setDecorations(highlightStyle, []); // This will dispose of a single editor instead of all editors
|
||||||
|
break;
|
||||||
|
default: /* isEnabled is true and multiLineIsEnabled is false and VSCode is reporting something else - break out of 3rd switch */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: /* isEnabled is true and multiLineIsEnabled is undetected - break out of 2nd switch statement */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case false: /* isEnabled is false */
|
||||||
|
highlightStyle.dispose();
|
||||||
|
break;
|
||||||
|
default: /* break out of initial switch if 'true or false' is not found */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep track of position
|
||||||
|
new Position(activeTextEditor.selection.start.line, activeTextEditor.selection.start.character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * Function to get the user configured highlighting styles, or use defaults
|
||||||
|
*
|
||||||
|
* * Designed with user configuration in mind, able to control different sides
|
||||||
|
* * independently from each other (in most cases). This allows for many different
|
||||||
|
* * configurations.
|
||||||
|
*
|
||||||
|
* ? Colors Can be input with the following values:
|
||||||
|
* * https://www.w3schools.com/cssref/css_colors.asp for string based color values
|
||||||
|
* * Hex -> #<value> | rgb(###, ###, ###) | rgba(###, ###, ###, ###) | hsla(##, ##%, ##%, .#)
|
||||||
|
*
|
||||||
|
* ? Width Input Values
|
||||||
|
* ! Some work better than others, if one isn't working try a different method:
|
||||||
|
* * thin | medium | thick | px | rem | em | cm
|
||||||
|
*
|
||||||
|
* ? Other values
|
||||||
|
* * font-style : none|normal|italic|oblique;
|
||||||
|
* * font-weight : none|normal|bold|bolder|lighter|number;
|
||||||
|
* * border-style : none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset;
|
||||||
|
* * outline-style : none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset;
|
||||||
|
* * outline-width : none|medium|thin|thick|length;
|
||||||
|
* * border-width : none|medium|thin|thick|length;
|
||||||
|
* ? https://www.w3schools.com/cssref/pr_text_text-decoration.asp for text-decoration
|
||||||
|
*
|
||||||
|
* ! borderWidthRight acts weirdly, on my system 16px works best with the other directions set to 1px
|
||||||
|
*
|
||||||
|
* @returns highlighterStyle
|
||||||
|
*/
|
||||||
|
function getHighlighterStyle(): TextEditorDecorationType {
|
||||||
|
// Used so we don't have to type out workspace.getConfiguration('mind-reader.lineHighlighter') on every line, ie: shorthand
|
||||||
|
const userConfig: WorkspaceConfiguration = workspace.getConfiguration('mind-reader.lineHighlighter');
|
||||||
|
|
||||||
|
const borderWidthTop : string = userConfig.get('borderWidthTop') || "1px";
|
||||||
|
const borderWidthRight : string = userConfig.get('borderWidthRight') || "16px";
|
||||||
|
const borderWidthBottom : string = userConfig.get('borderWidthBottom') || "1px";
|
||||||
|
const borderWidthLeft : string = userConfig.get('borderWidthLeft') || "1px";
|
||||||
|
|
||||||
|
const borderStyleTop : string = userConfig.get('borderStyleTop') || "solid";
|
||||||
|
const borderStyleRight : string = userConfig.get('borderStyleRight') || "solid";
|
||||||
|
const borderStyleBottom : string = userConfig.get('borderStyleBottom') || "solid";
|
||||||
|
const borderStyleLeft : string = userConfig.get('borderStyleLeft') || "solid";
|
||||||
|
|
||||||
|
const borderColorTop : string = userConfig.get('borderColorTop') || "#FFFFFF";
|
||||||
|
const borderColorRight : string = userConfig.get('borderColorRight') || "#FFFFFF";
|
||||||
|
const borderColorBottom : string = userConfig.get('borderColorBottom') || "#FFFFFF";
|
||||||
|
const borderColorLeft : string = userConfig.get('borderColorLeft') || "#FFFFFF";
|
||||||
|
|
||||||
|
const backgroundColor : string = userConfig.get('backgroundColor') || "#232C5C";
|
||||||
|
|
||||||
|
const fontStyle : string = userConfig.get('fontStyle') || "normal";
|
||||||
|
const fontWeight : string = userConfig.get('fontWeight') || "bolder";
|
||||||
|
const outlineColor : string = userConfig.get('outlineColor') || "#4866FE";
|
||||||
|
const outlineStyle : string = userConfig.get('outlineStyle') || "solid";
|
||||||
|
const outlineWidth : string = userConfig.get('outlineWidth') || "1px";
|
||||||
|
const textDecoration : string = userConfig.get('textDecoration') || "none";
|
||||||
|
const textColor : string = userConfig.get('textColor') || "#FFFFFF";
|
||||||
|
|
||||||
|
// Combine all our styling into a single variable to return
|
||||||
|
const highlighterStyle : TextEditorDecorationType = window.createTextEditorDecorationType({
|
||||||
|
isWholeLine : true,
|
||||||
|
backgroundColor : `${backgroundColor}`,
|
||||||
|
fontStyle : `${fontStyle}`,
|
||||||
|
fontWeight : `${fontWeight}`,
|
||||||
|
textDecoration : `${textDecoration}`,
|
||||||
|
color : `${textColor}`,
|
||||||
|
borderColor : `${borderColorTop} ${borderColorRight} ${borderColorBottom} ${borderColorLeft}`,
|
||||||
|
borderWidth : `${borderWidthTop} ${borderWidthRight} ${borderWidthBottom} ${borderWidthLeft}`,
|
||||||
|
borderStyle : `${borderStyleTop} ${borderStyleRight} ${borderStyleBottom} ${borderStyleLeft}`,
|
||||||
|
outlineColor : `${outlineColor}`,
|
||||||
|
outlineWidth : `${outlineWidth}`,
|
||||||
|
outlineStyle : `${outlineStyle}`,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Return our variable
|
||||||
|
return highlighterStyle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Function to retrieve the 'isEnabled' status
|
||||||
|
*
|
||||||
|
* This will determine if the line highlighter will display or not
|
||||||
|
* - enabled -> will show
|
||||||
|
* - disabled -> will not show
|
||||||
|
*
|
||||||
|
* @returns enabledStatus
|
||||||
|
*/
|
||||||
|
function getHighlighterStatus(): boolean | undefined {
|
||||||
|
// set a boolean variable
|
||||||
|
let enabledStatus: boolean | undefined;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* if 'isEnabled' is missing from the settings (aka undefined)
|
||||||
|
* - set our variable to true (default)
|
||||||
|
* otherwise, 'isEnabled' is listed in the settings
|
||||||
|
* - so we just pull its value
|
||||||
|
*/
|
||||||
|
(workspace.getConfiguration('mind-reader.lineHighlighter').get('isEnabled') === undefined)
|
||||||
|
? (enabledStatus = true)
|
||||||
|
: (enabledStatus = workspace.getConfiguration('mind-reader.lineHighlighter').get('isEnabled'));
|
||||||
|
|
||||||
|
// return the enabledStatus
|
||||||
|
return enabledStatus;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getMultiLineHighlighterStatus(): boolean | undefined {
|
||||||
|
// set a boolean variable
|
||||||
|
let multiLineIsEnabled: boolean | undefined;
|
||||||
|
|
||||||
|
/***
|
||||||
|
* if 'isEnabled' is missing from the settings (aka undefined)
|
||||||
|
* - set our variable to true (default)
|
||||||
|
* otherwise, 'isEnabled' is listed in the settings
|
||||||
|
* - so we just pull its value
|
||||||
|
*/
|
||||||
|
(workspace.getConfiguration('mind-reader.lineHighlighter').get('multiLineIsEnabled') === undefined)
|
||||||
|
? (multiLineIsEnabled = true)
|
||||||
|
: (multiLineIsEnabled = workspace.getConfiguration('mind-reader.lineHighlighter').get('multiLineIsEnabled'));
|
||||||
|
|
||||||
|
// return the enabledStatus
|
||||||
|
return multiLineIsEnabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean-up after ourself
|
||||||
|
export function deactivate() {
|
||||||
|
// when the plugin is terminated remove all highlighting
|
||||||
|
if (highlightStyle !== undefined) {
|
||||||
|
highlightStyle.dispose();
|
||||||
|
}
|
||||||
|
}
|
@ -1,9 +1,9 @@
|
|||||||
import { LineToken } from '.';
|
import { LineToken } from '.';
|
||||||
import { Symbol, EOFTOKEN, TabInfo } from './token';
|
import { Symbol, EOFTOKEN, TabInfo } from './token';
|
||||||
|
|
||||||
type Rule = {
|
type Rule = {
|
||||||
pattern: RegExp,
|
pattern: RegExp,
|
||||||
type: Symbol,
|
type : Symbol,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -11,205 +11,248 @@ type Rule = {
|
|||||||
* The first item is a recognition pattern, used to recognize the token
|
* The first item is a recognition pattern, used to recognize the token
|
||||||
* the second item is the token type
|
* the second item is the token type
|
||||||
*/
|
*/
|
||||||
const rules: Rule[] = [
|
const rules: Rule[] = [{
|
||||||
{
|
pattern: /^\s*def\s+(?<attr>[a-zA-Z_][a-zA-Z0-9_]*)\(/,
|
||||||
pattern: /^\s*def\s+(?<attr>[a-zA-Z_][a-zA-Z0-9_]*)\(/,
|
type: Symbol.FUNCTION
|
||||||
type: Symbol.FUNCTION
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*class\s+(?<attr>[a-zA-Z_][a-zA-Z0-9_]*)/,
|
||||||
pattern: /^\s*class\s+(?<attr>[a-zA-Z_][a-zA-Z0-9_]*)/,
|
type: Symbol.CLASS
|
||||||
type: Symbol.CLASS
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*if\s+(?<attr>[^:]+):\s*/,
|
||||||
pattern: /^\s*if\s+(?<attr>[^:]+):\s*/,
|
type: Symbol.IF
|
||||||
type: Symbol.IF
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*elif\s+(?<attr>[^:]+):\s*$/,
|
||||||
pattern: /^\s*elif\s+(?<attr>[^:]+):\s*$/,
|
type: Symbol.ELIF
|
||||||
type: Symbol.ELIF
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*else\s*:/,
|
||||||
pattern: /^\s*else\s*:/,
|
type: Symbol.ELSE
|
||||||
type: Symbol.ELSE
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*for\s+(?<attr>[^:]+):\s*$/,
|
||||||
pattern: /^\s*for\s+(?<attr>[^:]+):\s*$/,
|
type: Symbol.FOR
|
||||||
type: Symbol.FOR
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*while\s+(?<attr>[^:]+):\s*$/,
|
||||||
pattern: /^\s*while\s+(?<attr>[^:]+):\s*$/,
|
type: Symbol.WHILE
|
||||||
type: Symbol.WHILE
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*try\s*:/,
|
||||||
pattern: /^\s*try\s*:/,
|
type: Symbol.TRY
|
||||||
type: Symbol.TRY
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*except(\s*(?<attr>[^:]+))?:\s*$/,
|
||||||
pattern: /^\s*except(\s*(?<attr>[^:]+))?:\s*$/,
|
type: Symbol.EXCEPT
|
||||||
type: Symbol.EXCEPT
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*finally\s*:\s*$/,
|
||||||
pattern: /^\s*finally\s*:\s*$/,
|
type: Symbol.FINALLY
|
||||||
type: Symbol.FINALLY
|
},
|
||||||
},
|
{
|
||||||
{
|
pattern: /^\s*with\s+(?<attr>[^:]+):\s*$/,
|
||||||
pattern: /^\s*with\s+(?<attr>[^:]+):\s*$/,
|
type: Symbol.WITH
|
||||||
type: Symbol.WITH
|
},
|
||||||
},
|
{
|
||||||
|
pattern: /^\s*#+\s*(?<attr>.*)\s*$/,
|
||||||
|
type: Symbol.COMMENT
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /^\s*$/,
|
||||||
|
type: Symbol.EMPTY
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: /^\s*(?<attr>[^#]+)+\s*$/,
|
||||||
|
type: Symbol.STATEMENT
|
||||||
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Line-By-Line Lexer
|
* Line-By-Line Lexer
|
||||||
*/
|
*/
|
||||||
export default class Lexer {
|
export default class Lexer {
|
||||||
private textLines: string[] = []; // array of text lines
|
private textLines : string[] = []; // array of text lines
|
||||||
private pos: number = 0;
|
private pos : number = 0;
|
||||||
private _currToken: LineToken = EOFTOKEN;
|
private _currToken: LineToken = EOFTOKEN;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculates indentation level for a line. If using soft tabs,
|
* @param `text` The text to lex.
|
||||||
* indent level rounds up (so, tabSize+1 spaces is 2 levels,
|
* @param `tabFmt` A tab information descriptor
|
||||||
* 2*tabSize+1 is 3, etc.)
|
*/
|
||||||
*
|
constructor(text ? : string, private tabFmt ? : TabInfo) {
|
||||||
* @param `text` The line of text.
|
// default is 4 wide expanded tabs
|
||||||
* @param `tabFmt` A tab information descriptor.
|
this.tabFmt = {
|
||||||
* @return The indent of `text` with consideration for `tabFmt`.
|
...{
|
||||||
*/
|
size: 4,
|
||||||
static getIndent(text: string, tabFmt: TabInfo): number {
|
hard: false
|
||||||
let leadingSpace: number = text.length - text.trimLeft().length;
|
},
|
||||||
let indent: number;
|
...tabFmt
|
||||||
if (tabFmt.hard) {
|
};
|
||||||
// used tabs
|
|
||||||
indent = leadingSpace;
|
|
||||||
} else {
|
|
||||||
// use spaces
|
|
||||||
indent = Math.ceil(leadingSpace/tabFmt.size!);
|
|
||||||
}
|
|
||||||
|
|
||||||
return indent;
|
if (text) {
|
||||||
}
|
// normalize line feeds
|
||||||
|
text = text.replace('\r\n', '\n');
|
||||||
/**
|
|
||||||
* @param `text` The text to lex.
|
|
||||||
* @param `tabFmt` A tab information descriptor
|
|
||||||
*/
|
|
||||||
constructor(text?: string, private tabFmt?: TabInfo) {
|
|
||||||
// default is 4 wide expanded tabs
|
|
||||||
this.tabFmt = {
|
|
||||||
...{size: 4, hard: false},
|
|
||||||
...tabFmt
|
|
||||||
};
|
|
||||||
|
|
||||||
if (text) {
|
|
||||||
// normalize linefeeds
|
|
||||||
text = text.replace('\r\n', '\n');
|
|
||||||
}
|
|
||||||
this.restart(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Restart lexer with new text.
|
|
||||||
*
|
|
||||||
* @param `text` The new text to lex.
|
|
||||||
*/
|
|
||||||
restart(text?: string): void {
|
|
||||||
this.pos = 0;
|
|
||||||
this._currToken = EOFTOKEN; // if no input, already on EOFTOKEN
|
|
||||||
if (text) {
|
|
||||||
this.textLines = text.split('\n');
|
|
||||||
this.next(); // advance to the first token
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the current {@link LineToken}.
|
|
||||||
*/
|
|
||||||
currToken(): LineToken { return this._currToken; }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Advance the position in the token stream.
|
|
||||||
*
|
|
||||||
* @return The new current token, after advancing
|
|
||||||
*/
|
|
||||||
next(): LineToken {
|
|
||||||
if (this._currToken === EOFTOKEN && this.pos > this.textLines.length) {
|
|
||||||
throw new Error('Cannot advance past end');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Until a LineToken is found, or EOF
|
|
||||||
while (this.pos < this.textLines.length) {
|
|
||||||
let line: string = this.textLines[this.pos];
|
|
||||||
let indent: number = Lexer.getIndent(line, this.tabFmt!);
|
|
||||||
let token: LineToken;
|
|
||||||
for (var r of rules) {
|
|
||||||
// Does line match pattern?
|
|
||||||
let match: RegExpMatchArray | null = line.match(r.pattern);
|
|
||||||
if (match) {
|
|
||||||
// Yes...
|
|
||||||
if (match.groups) {
|
|
||||||
token = new LineToken(r.type, this.pos, indent, match.groups["attr"]);
|
|
||||||
} else {
|
|
||||||
token = new LineToken(r.type, this.pos, indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._currToken = token;
|
|
||||||
this.pos++;
|
|
||||||
return this.currToken();
|
|
||||||
}
|
}
|
||||||
}
|
this.restart(text);
|
||||||
// No rules matched
|
|
||||||
|
|
||||||
// TODO: move to rules
|
|
||||||
if (/^\s*(#.*)?$/.test(line)) {
|
|
||||||
// "empty" line
|
|
||||||
token = new LineToken(Symbol.EMPTY, this.pos, 999999);
|
|
||||||
} else {
|
|
||||||
// This is an INDENT token
|
|
||||||
token = new LineToken(Symbol.INDENT, this.pos, indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
this._currToken = token;
|
|
||||||
this.pos++;
|
|
||||||
return this.currToken();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Didn't return, must be EOF
|
/**
|
||||||
this._currToken = EOFTOKEN;
|
* Restart lexer with new text.
|
||||||
this.pos++;
|
*
|
||||||
return this.currToken();
|
* @param `text` The new text to lex.
|
||||||
}
|
*/
|
||||||
|
restart(text ? : string): void {
|
||||||
/**
|
this.pos = 0;
|
||||||
* Move backwards in the token stream
|
this._currToken = EOFTOKEN; // if no input, already on EOFTOKEN
|
||||||
*
|
if (text) {
|
||||||
* @param `n` The number of positions to retract.
|
this.textLines = text.split('\n');
|
||||||
* @return The new current token after retracting.
|
this.next(); // advance to the first token
|
||||||
*/
|
}
|
||||||
retract(n: number = 1): LineToken {
|
|
||||||
if (this.pos - 1 - n < 0) {
|
|
||||||
// -1 because this.pos is currently on the next token
|
|
||||||
throw new RangeError('Cannot retract past start');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n <= 0) {
|
/**
|
||||||
throw new RangeError('Retract distance must be positive');
|
* @return the current {@link LineToken}.
|
||||||
|
*/
|
||||||
|
currToken(): LineToken {
|
||||||
|
return this._currToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.pos - n === 0) {
|
/**
|
||||||
// just restart
|
* Advance the position in the token stream.
|
||||||
this.pos = 0;
|
*
|
||||||
return this.next();
|
* @return The new current token, after advancing
|
||||||
|
*/
|
||||||
|
next(): LineToken {
|
||||||
|
if (this._currToken === EOFTOKEN && this.pos > this.textLines.length) {
|
||||||
|
throw new Error('Cannot advance past end');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Until a LineToken is found, or EOF
|
||||||
|
while (this.pos < this.textLines.length) {
|
||||||
|
const line : string = this.textLines[this.pos];
|
||||||
|
const indent: number = Lexer.getIndent(line, this.tabFmt!);
|
||||||
|
let token : LineToken;
|
||||||
|
|
||||||
|
for (var r of rules) {
|
||||||
|
// Does line match pattern?
|
||||||
|
const match: RegExpMatchArray | null = line.match(r.pattern);
|
||||||
|
if (match) {
|
||||||
|
// Yes...
|
||||||
|
if (match.groups) {
|
||||||
|
token = new LineToken(r.type, this.pos, indent, match.groups["attr"]);
|
||||||
|
} else {
|
||||||
|
token = new LineToken(r.type, this.pos, indent);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._currToken = token;
|
||||||
|
this.pos++;
|
||||||
|
|
||||||
|
return this.currToken();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No rules matched
|
||||||
|
token = new LineToken(Symbol.INVALID, this.pos, 999999);
|
||||||
|
this._currToken = token;
|
||||||
|
this.pos++;
|
||||||
|
|
||||||
|
return this.currToken();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Didn't return, must be EOF
|
||||||
|
this._currToken = EOFTOKEN;
|
||||||
|
this.pos++;
|
||||||
|
|
||||||
|
return this.currToken();
|
||||||
}
|
}
|
||||||
|
|
||||||
let c = n + 1;
|
/**
|
||||||
while (c > 0) {
|
* Move backwards in the token stream
|
||||||
this.pos--;
|
*
|
||||||
while (/^\s*(#.*)?$/.test(this.textLines[this.pos])) {
|
* @param `n` The number of positions to retract.
|
||||||
// Skip empty lines
|
* @return The new current token after retracting.
|
||||||
this.pos--;
|
*/
|
||||||
}
|
retract(n: number = 1): LineToken {
|
||||||
c--;
|
if (this.pos - 1 - n < 0) {
|
||||||
|
// -1 because this.pos is currently on the next token
|
||||||
|
throw new RangeError('Cannot retract past start');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (n <= 0) {
|
||||||
|
throw new RangeError('Retract distance must be positive');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.pos - n === 0) {
|
||||||
|
// just restart
|
||||||
|
this.pos = 0;
|
||||||
|
return this.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
let c = n + 1;
|
||||||
|
while (c > 0) {
|
||||||
|
this.pos--;
|
||||||
|
while (/^\s*(#.*)?$/.test(this.textLines[this.pos])) {
|
||||||
|
// Skip empty lines
|
||||||
|
this.pos--;
|
||||||
|
}
|
||||||
|
c--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates indentation level for a line. If using soft tabs,
|
||||||
|
* indent level rounds up (so, tabSize+1 spaces is 2 levels,
|
||||||
|
* 2*tabSize+1 is 3, etc.)
|
||||||
|
*
|
||||||
|
* @param `text` The line of text.
|
||||||
|
* @param `tabFmt` A tab information descriptor.
|
||||||
|
* @return The indent of `text` with consideration for `tabFmt`.
|
||||||
|
*/
|
||||||
|
static getIndent(text: string, tabFmt: TabInfo): number {
|
||||||
|
const leadingSpace: number = text.length - text.trimStart().length;
|
||||||
|
let indent: number;
|
||||||
|
|
||||||
|
if (tabFmt.hard) {
|
||||||
|
// used tabs
|
||||||
|
indent = leadingSpace;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// used spaces
|
||||||
|
//? indent = Math.round(leadingSpace / tabFmt.size! * 10) / 10; // fractional indentation support?
|
||||||
|
indent = Math.ceil(leadingSpace / tabFmt.size!);
|
||||||
|
}
|
||||||
|
|
||||||
|
return indent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates leading spaces for a line.
|
||||||
|
* This method uses arithmetic to calculate the number of leading spaces
|
||||||
|
*
|
||||||
|
* @param `line` The line of text.
|
||||||
|
* @return The number of leading spaces of `text`.
|
||||||
|
*/
|
||||||
|
static getLeadingSpacesByArithmetic(line: any): number {
|
||||||
|
const leadingSpaces: number = line.text.length - line.text.trimStart().length;
|
||||||
|
|
||||||
|
return leadingSpaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates leading spaces for a line.
|
||||||
|
* This method finds the index position of the first non-whitespace character
|
||||||
|
* Since the index is built using a 0-index, the position of this character
|
||||||
|
* will equal the number of spaces preceding the character.
|
||||||
|
*
|
||||||
|
* @param `text` The line of text.
|
||||||
|
* @return The number of leading spaces of `text` with respect to the index position of the first non-whitespace character.
|
||||||
|
*/
|
||||||
|
static getLeadingSpacesByIndex(text: any): number {
|
||||||
|
const indexNum: number = text.firstNonWhitespaceCharacterIndex;
|
||||||
|
|
||||||
|
return indexNum;
|
||||||
}
|
}
|
||||||
return this.next();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -74,8 +74,9 @@ export default class Parser {
|
|||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.lexer.currToken().type === Symbol.INDENT ||
|
if (this.lexer.currToken().type === Symbol.STATEMENT ||
|
||||||
this.lexer.currToken().type === Symbol.EMPTY) {
|
this.lexer.currToken().type === Symbol.EMPTY ||
|
||||||
|
this.lexer.currToken().type === Symbol.INVALID) {
|
||||||
const label = this.lexer.currToken().type;
|
const label = this.lexer.currToken().type;
|
||||||
// regular code, advance and stay in same block
|
// regular code, advance and stay in same block
|
||||||
children.push(new LexNode(
|
children.push(new LexNode(
|
||||||
|
@ -16,8 +16,10 @@ export enum Symbol {
|
|||||||
EXCEPT = "except",
|
EXCEPT = "except",
|
||||||
FINALLY = "finally",
|
FINALLY = "finally",
|
||||||
WITH = "with",
|
WITH = "with",
|
||||||
INDENT = "INDENT", // Indent token, default if not EOF, only contains indent information
|
STATEMENT = "statement", // Indent token, contains non-empty code lines
|
||||||
|
COMMENT = "Comment",
|
||||||
EMPTY = "EMPTY", // empty line, used only to associate with the previous line
|
EMPTY = "EMPTY", // empty line, used only to associate with the previous line
|
||||||
|
INVALID = "INVALID",
|
||||||
EOF = "EOF"
|
EOF = "EOF"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +55,7 @@ export default class LineToken {
|
|||||||
* @return A string representation of the token
|
* @return A string representation of the token
|
||||||
*/
|
*/
|
||||||
toString(): string {
|
toString(): string {
|
||||||
return this.type + ", linenr:" + (this.linenr+1) + ", indentLevel: " + this.indentLevel + ", attr: " + this.attr;
|
return `${this.type}, linenr: ${this.linenr+1}, indentLevel: ${this.indentLevel}, attr: ${this.attr}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ suite('Lexer Test Suite', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Empty String', () => {
|
test('Empty String', () => {
|
||||||
let l: Lexer = new Lexer(undefined);
|
let l: Lexer = new Lexer("");
|
||||||
assert.deepStrictEqual(l.currToken(), EOFTOKEN);
|
assert.deepStrictEqual(l.currToken(), EOFTOKEN);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -22,18 +22,19 @@ suite('Lexer Test Suite', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Whitespace', () => {
|
test('Whitespace', () => {
|
||||||
let l: Lexer = new Lexer(' \t\t'.repeat(4).repeat(4));
|
let s: string = ' '.repeat(4).repeat(4);
|
||||||
assert.deepStrictEqual(l.currToken(), new LineToken(Symbol.EMPTY, 0, 999999));
|
let l: Lexer = new Lexer(s);
|
||||||
|
assert.deepStrictEqual(l.currToken(), new LineToken(Symbol.EMPTY, 0, s.length/4));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Comment', () => {
|
test('Comment', () => {
|
||||||
let l: Lexer = new Lexer('# ur mom eats toes');
|
let l: Lexer = new Lexer('# this is a comment');
|
||||||
assert.deepStrictEqual(l.currToken(), new LineToken(Symbol.EMPTY, 0, 999999));
|
assert.deepStrictEqual(l.currToken(), new LineToken(Symbol.COMMENT, 0, 0, 'this is a comment'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Non-Whitespace with no construct', () => {
|
test('Non-Whitespace with no construct', () => {
|
||||||
let l: Lexer = new Lexer('foobar');
|
let l: Lexer = new Lexer('foobar');
|
||||||
assert.deepStrictEqual(l.currToken(), new LineToken(Symbol.INDENT, 0, 0));
|
assert.deepStrictEqual(l.currToken(), new LineToken(Symbol.STATEMENT, 0, 0, 'foobar'));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getIndent() accuracy, spaces', () => {
|
test('getIndent() accuracy, spaces', () => {
|
||||||
@ -50,11 +51,14 @@ suite('Lexer Test Suite', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getIndent() accuracy, spaces with incomplete tab', () => {
|
test('getIndent() accuracy, spaces with incomplete indentation', () => {
|
||||||
|
let size: number = 4;
|
||||||
for (var i = 0; i < 100; i++) {
|
for (var i = 0; i < 100; i++) {
|
||||||
for (var j = 1; j <= 3; j++) {
|
for (var j = 1; j <= 3; j++) {
|
||||||
let l: Lexer = new Lexer(' '.repeat(i) + ' '.repeat(j) + 'foobar', {size: 4, hard: false});
|
let l: Lexer = new Lexer(' '.repeat(i) + ' '.repeat(j) + 'foobar', {size: size, hard: false});
|
||||||
assert.strictEqual(l.currToken().indentLevel, i+1);
|
// TODO: Swap these out when fractional indentation is used
|
||||||
|
//assert.strictEqual(l.currToken().indentLevel, i + (Math.round(j / size * 100) / 100));
|
||||||
|
assert.strictEqual(l.currToken().indentLevel, i + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -150,7 +154,7 @@ suite('Lexer Test Suite', () => {
|
|||||||
test('retract() 1-100', () => {
|
test('retract() 1-100', () => {
|
||||||
let lines: string[] = Array.from(Array(100), (_, i) => 'line' + i);
|
let lines: string[] = Array.from(Array(100), (_, i) => 'line' + i);
|
||||||
let reference: LineToken[] = lines.map((_, i) => {
|
let reference: LineToken[] = lines.map((_, i) => {
|
||||||
return new LineToken(Symbol.INDENT, i, 0);
|
return new LineToken(Symbol.STATEMENT, i, 0, `line${i}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
for (var i = 0; i < 100; i++) {
|
for (var i = 0; i < 100; i++) {
|
||||||
@ -169,7 +173,7 @@ suite('Lexer Test Suite', () => {
|
|||||||
test('2 full lex and retract passes', () => {
|
test('2 full lex and retract passes', () => {
|
||||||
let lines: string[] = Array.from(Array(100), (_, i)=> 'line' + i);
|
let lines: string[] = Array.from(Array(100), (_, i)=> 'line' + i);
|
||||||
let reference: LineToken[] = lines.map((_, i) => {
|
let reference: LineToken[] = lines.map((_, i) => {
|
||||||
return new LineToken(Symbol.INDENT, i, 0);
|
return new LineToken(Symbol.STATEMENT, i, 0, `line${i}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
let l: Lexer = new Lexer(lines.join('\n'));
|
let l: Lexer = new Lexer(lines.join('\n'));
|
||||||
|
@ -13,7 +13,7 @@ suite('LexNode Test Suite', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('children() of leaf', () => {
|
test('children() of leaf', () => {
|
||||||
let n: LexNode = new LexNode('leafLexNode', vscode.TreeItemCollapsibleState.None, new LineToken(Symbol.INDENT, 0, 0));
|
let n: LexNode = new LexNode('leafLexNode', vscode.TreeItemCollapsibleState.None, new LineToken(Symbol.STATEMENT, 0, 0));
|
||||||
assert.strictEqual(n.children(), null);
|
assert.strictEqual(n.children(), null);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -7,7 +7,7 @@ import LexNode from '../../../pylex/node';
|
|||||||
import LineToken from '../../../pylex/token';
|
import LineToken from '../../../pylex/token';
|
||||||
import { Symbol } from '../../../pylex/token';
|
import { Symbol } from '../../../pylex/token';
|
||||||
|
|
||||||
import { root,indent,empty } from '../../util';
|
import { root, statement } from '../../util';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test Descriptor
|
* Test Descriptor
|
||||||
@ -23,23 +23,24 @@ const tests: ParserTest[] = [
|
|||||||
{ name: 'Single Empty Line', input: [''], output: root(null) },
|
{ name: 'Single Empty Line', input: [''], output: root(null) },
|
||||||
{
|
{
|
||||||
name: 'Single Whitespace Only Line',
|
name: 'Single Whitespace Only Line',
|
||||||
input: [' '],
|
input: [' '], // length 20
|
||||||
output: root([
|
output: root([
|
||||||
empty(0)
|
new LexNode(Symbol.EMPTY, 0, new LineToken(Symbol.EMPTY, 0, 20 / 4)) // 4 spaces per indent
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Single Comment Only Line',
|
name: 'Single Comment Only Line',
|
||||||
input: ['# ur mom likes peas'],
|
input: ['# this is a comment'],
|
||||||
output: root([
|
output: root([
|
||||||
empty(0)
|
new LexNode(Symbol.EMPTY, 0, new LineToken(Symbol.COMMENT, 0, 0, "this is a comment"))
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Single Non-Control Line',
|
name: 'Single Non-Control Line',
|
||||||
input: ['my_age = 42'],
|
input: ['my_age = 42'],
|
||||||
output: root([
|
output: root([
|
||||||
indent(0, 0)
|
//statement(0, 0)
|
||||||
|
new LexNode("name", 0, new LineToken(Symbol.STATEMENT, 0, 0, 'my_age = 42'))
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -55,7 +56,10 @@ const tests: ParserTest[] = [
|
|||||||
'bar = "Blue M&Ms make me happy <:)"',
|
'bar = "Blue M&Ms make me happy <:)"',
|
||||||
'reba = "A hard working gal"'
|
'reba = "A hard working gal"'
|
||||||
],
|
],
|
||||||
output: root([indent(0,0), indent(1,0)]),
|
output: root([
|
||||||
|
new LexNode("name", 0, new LineToken(Symbol.STATEMENT, 0, 0, 'bar = "Blue M&Ms make me happy <:)"')),
|
||||||
|
new LexNode("name", 0, new LineToken(Symbol.STATEMENT, 1, 0, 'reba = "A hard working gal"'))
|
||||||
|
]),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
@ -66,11 +70,13 @@ const tests: ParserTest[] = [
|
|||||||
'billy = "Scrubbly Bubbles!"'
|
'billy = "Scrubbly Bubbles!"'
|
||||||
],
|
],
|
||||||
output: root([
|
output: root([
|
||||||
new LexNode('if radioshack',
|
new LexNode('if radioshack', 0,
|
||||||
vscode.TreeItemCollapsibleState.None,
|
|
||||||
new LineToken(Symbol.IF, 0, 0, 'radioshack'),
|
new LineToken(Symbol.IF, 0, 0, 'radioshack'),
|
||||||
[indent(1, 1)]),
|
[
|
||||||
indent(2, 0)
|
new LexNode('print radioshack.hours', 0, new LineToken(Symbol.STATEMENT, 1, 1, 'print radioshack.hours'))
|
||||||
|
]
|
||||||
|
),
|
||||||
|
new LexNode('billy = "Scrubbly Bubbles!"', 0, new LineToken(Symbol.STATEMENT, 2, 0, 'billy = "Scrubbly Bubbles!"'))
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -82,11 +88,12 @@ const tests: ParserTest[] = [
|
|||||||
' print radioshack.hours'
|
' print radioshack.hours'
|
||||||
],
|
],
|
||||||
output: root([
|
output: root([
|
||||||
indent(0, 0),
|
new LexNode('billy = "Scrubbly Bubbles!"', 0, new LineToken(Symbol.STATEMENT, 0, 0, 'billy = "Scrubbly Bubbles!"')),
|
||||||
new LexNode('if radioshack',
|
new LexNode('if radioshack', 0, new LineToken(Symbol.IF, 1, 0, 'radioshack'),
|
||||||
vscode.TreeItemCollapsibleState.None,
|
[
|
||||||
new LineToken(Symbol.IF, 1, 0, 'radioshack'),
|
new LexNode('print radioshack.hours', 0, new LineToken(Symbol.STATEMENT, 2, 1, 'print radioshack.hours'))
|
||||||
[indent(2, 1)])
|
]
|
||||||
|
)
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -101,15 +108,18 @@ const tests: ParserTest[] = [
|
|||||||
' print("You really eat this?")',
|
' print("You really eat this?")',
|
||||||
],
|
],
|
||||||
output: root([
|
output: root([
|
||||||
new LexNode('if yummy',
|
new LexNode('if yummy', 0, new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
||||||
vscode.TreeItemCollapsibleState.None,
|
[
|
||||||
new LineToken(Symbol.IF, 0, 0, 'yummy'), [indent(1, 1)]),
|
statement(1, 1, 'print("HOoray!")')
|
||||||
new LexNode('elif just_ok',
|
]),
|
||||||
vscode.TreeItemCollapsibleState.None,
|
new LexNode('elif just_ok', 0, new LineToken(Symbol.ELIF, 2, 0, 'just_ok'),
|
||||||
new LineToken(Symbol.ELIF, 2, 0, 'just_ok'), [indent(3, 1)]),
|
[
|
||||||
new LexNode('else',
|
statement(3, 1, 'print("Do you have anything else?")')
|
||||||
vscode.TreeItemCollapsibleState.None,
|
]),
|
||||||
new LineToken(Symbol.ELSE, 4, 0), [indent(5,1)]),
|
new LexNode('else', 0, new LineToken(Symbol.ELSE, 4, 0),
|
||||||
|
[
|
||||||
|
statement(5, 1, 'print("You really eat this?")')
|
||||||
|
]),
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -122,13 +132,14 @@ const tests: ParserTest[] = [
|
|||||||
],
|
],
|
||||||
output: root([
|
output: root([
|
||||||
new LexNode('if yummy',
|
new LexNode('if yummy',
|
||||||
vscode.TreeItemCollapsibleState.None,
|
0,
|
||||||
new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
||||||
[
|
[
|
||||||
new LexNode('if in_my_tummy',
|
new LexNode('if in_my_tummy', 0, new LineToken(Symbol.IF, 1, 1, 'in_my_tummy'),
|
||||||
vscode.TreeItemCollapsibleState.None,
|
[
|
||||||
new LineToken(Symbol.IF, 1, 1, 'in_my_tummy'),
|
statement(2, 2, 'exclaim("Scrumdiddlyumptious!")')
|
||||||
[indent(2, 2)])
|
]
|
||||||
|
)
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
@ -141,23 +152,20 @@ const tests: ParserTest[] = [
|
|||||||
' if in_my_tummy:',
|
' if in_my_tummy:',
|
||||||
' exclaim("Scrumdiddlyumptious!")',
|
' exclaim("Scrumdiddlyumptious!")',
|
||||||
'else:',
|
'else:',
|
||||||
' exclaim("DAESGUSTEN~)"'
|
' exclaim("DISGUSTING!")'
|
||||||
],
|
],
|
||||||
output: root([
|
output: root([
|
||||||
new LexNode('if yummy',
|
new LexNode('if yummy', 0, new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
||||||
vscode.TreeItemCollapsibleState.None,
|
|
||||||
new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
|
||||||
[
|
[
|
||||||
new LexNode('if in_my_tummy',
|
new LexNode('if in_my_tummy', 0, new LineToken(Symbol.IF, 1, 1, 'in_my_tummy'),
|
||||||
vscode.TreeItemCollapsibleState.None,
|
[
|
||||||
new LineToken(Symbol.IF, 1, 1, 'in_my_tummy'),
|
statement(2, 2, 'exclaim("Scrumdiddlyumptious!")')
|
||||||
[indent(2, 2)])
|
]
|
||||||
|
)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
new LexNode('else',
|
new LexNode('else', 0, new LineToken(Symbol.ELSE, 3, 0),
|
||||||
vscode.TreeItemCollapsibleState.None,
|
[statement(4, 1, 'exclaim("DISGUSTING!")')]
|
||||||
new LineToken(Symbol.ELSE, 3, 0),
|
|
||||||
[indent(4, 1)]
|
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
@ -168,31 +176,27 @@ const tests: ParserTest[] = [
|
|||||||
'if yummy:',
|
'if yummy:',
|
||||||
' if in_my_tummy:',
|
' if in_my_tummy:',
|
||||||
' if looks_like_a_mummy:',
|
' if looks_like_a_mummy:',
|
||||||
' print("you have a spot on your tummy"',
|
' print("you have a spot on your tummy")',
|
||||||
'else:',
|
'else:',
|
||||||
' print("Food is food...")'
|
' print("Food is food...")'
|
||||||
],
|
],
|
||||||
output: root([
|
output: root([
|
||||||
new LexNode('if yummy',
|
new LexNode('if yummy',
|
||||||
vscode.TreeItemCollapsibleState.None,
|
0,
|
||||||
new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
||||||
[
|
[
|
||||||
new LexNode('if in_my_tummy',
|
new LexNode('if in_my_tummy', 0, new LineToken(Symbol.IF, 1, 1, 'in_my_tummy'),
|
||||||
vscode.TreeItemCollapsibleState.None,
|
|
||||||
new LineToken(Symbol.IF, 1, 1, 'in_my_tummy'),
|
|
||||||
[
|
[
|
||||||
new LexNode('if looks_like_a_mummy',
|
new LexNode('if looks_like_a_mummy', 0, new LineToken(Symbol.IF, 2, 2, 'looks_like_a_mummy'),
|
||||||
vscode.TreeItemCollapsibleState.None,
|
[statement(3, 3, 'print("you have a spot on your tummy")')])
|
||||||
new LineToken(Symbol.IF, 2, 2, 'looks_like_a_mummy'),
|
|
||||||
[indent(3, 3)])
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
new LexNode('else',
|
new LexNode('else',
|
||||||
vscode.TreeItemCollapsibleState.None,
|
0,
|
||||||
new LineToken(Symbol.ELSE, 4, 0),
|
new LineToken(Symbol.ELSE, 4, 0),
|
||||||
[indent(5, 1)]
|
[statement(5, 1, 'print("Food is food...")')]
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
@ -203,44 +207,42 @@ const tests: ParserTest[] = [
|
|||||||
'if yummy:',
|
'if yummy:',
|
||||||
' if in_my_tummy:',
|
' if in_my_tummy:',
|
||||||
' if looks_like_a_mummy:',
|
' if looks_like_a_mummy:',
|
||||||
' print("you have a spot on your tummy"',
|
' print("you have a spot on your tummy")',
|
||||||
' else:',
|
' else:',
|
||||||
' print("eek! a zombie!)',
|
' print("eek! a zombie!")',
|
||||||
' elif in_my_mouth:',
|
' elif in_my_mouth:',
|
||||||
' print("itll be in my tummy soon!"',
|
' print("itll be in my tummy soon!")',
|
||||||
'else:',
|
'else:',
|
||||||
' print("Food is food...")'
|
' print("Food is food...")'
|
||||||
],
|
],
|
||||||
output: root([
|
output: root([
|
||||||
new LexNode('if yummy',
|
new LexNode('if yummy', 0,
|
||||||
vscode.TreeItemCollapsibleState.None,
|
|
||||||
new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
||||||
[
|
[
|
||||||
new LexNode('if in_my_tummy',
|
new LexNode('if in_my_tummy', 0,
|
||||||
vscode.TreeItemCollapsibleState.None,
|
|
||||||
new LineToken(Symbol.IF, 1, 1, 'in_my_tummy'),
|
new LineToken(Symbol.IF, 1, 1, 'in_my_tummy'),
|
||||||
[
|
[
|
||||||
new LexNode('if looks_like_a_mummy',
|
new LexNode('if looks_like_a_mummy',
|
||||||
vscode.TreeItemCollapsibleState.None,
|
0,
|
||||||
new LineToken(Symbol.IF, 2, 2, 'looks_like_a_mummy'),
|
new LineToken(Symbol.IF, 2, 2, 'looks_like_a_mummy'),
|
||||||
[indent(3, 3)]),
|
[statement(3, 3, 'print("you have a spot on your tummy")')]),
|
||||||
new LexNode('else',
|
new LexNode('else',
|
||||||
vscode.TreeItemCollapsibleState.None,
|
0,
|
||||||
new LineToken(Symbol.ELSE, 4, 2),
|
new LineToken(Symbol.ELSE, 4, 2),
|
||||||
[indent(5, 3)])
|
[statement(5, 3, 'print("eek! a zombie!")')])
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
new LexNode('elif in_my_mouth',
|
new LexNode('elif in_my_mouth',
|
||||||
vscode.TreeItemCollapsibleState.None,
|
0,
|
||||||
new LineToken(Symbol.ELIF, 6, 1, 'in_my_mouth'),
|
new LineToken(Symbol.ELIF, 6, 1, 'in_my_mouth'),
|
||||||
[indent(7, 2)]
|
[statement(7, 2, 'print("itll be in my tummy soon!")')]
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
new LexNode('else',
|
new LexNode('else',
|
||||||
vscode.TreeItemCollapsibleState.None,
|
0,
|
||||||
new LineToken(Symbol.ELSE, 8, 0),
|
new LineToken(Symbol.ELSE, 8, 0),
|
||||||
[indent(9, 1)]
|
[statement(9, 1, 'print("Food is food...")')]
|
||||||
)
|
)
|
||||||
])
|
])
|
||||||
},
|
},
|
||||||
@ -248,21 +250,24 @@ const tests: ParserTest[] = [
|
|||||||
name: 'Multiline Block',
|
name: 'Multiline Block',
|
||||||
input: [
|
input: [
|
||||||
'if yummy:',
|
'if yummy:',
|
||||||
' print("you have a spot on your tummy"',
|
' print("you have a spot on your tummy")',
|
||||||
' print("eek! a zombie!)',
|
' print("eek! a zombie!)',
|
||||||
' print("itll be in my tummy soon!"',
|
' print("itll be in my tummy soon!")',
|
||||||
'else:',
|
'else:',
|
||||||
' print("Food is food...")'
|
' print("Food is food...")'
|
||||||
],
|
],
|
||||||
output: root([
|
output: root([
|
||||||
new LexNode('if yummy', 0, new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
new LexNode('if yummy', 0, new LineToken(Symbol.IF, 0, 0, 'yummy'),
|
||||||
[
|
[
|
||||||
indent(1, 1),
|
statement(1, 1, 'print("you have a spot on your tummy")'),
|
||||||
indent(2, 1),
|
statement(2, 1, 'print("eek! a zombie!)'),
|
||||||
indent(3, 1),
|
statement(3, 1, 'print("itll be in my tummy soon!")'),
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
new LexNode('else', 0, new LineToken(Symbol.ELSE, 4, 0), [indent(5, 1)])
|
new LexNode('else', 0, new LineToken(Symbol.ELSE, 4, 0),
|
||||||
|
[
|
||||||
|
statement(5, 1, 'print("Food is food...")')
|
||||||
|
])
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
@ -50,19 +50,19 @@ function root(nodes: LexNode[] | null): LexNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* short hand for returning an indentation token for a certain line and indentation */
|
/* short hand for returning an indentation token for a certain line and indentation */
|
||||||
function indent(linenr: number, indentLevel: number): LexNode {
|
function statement(linenr: number, indentLevel: number, text: string = ""): LexNode {
|
||||||
return new LexNode('INDENT', 0, new LineToken(PylexSymbol.INDENT, linenr, indentLevel));
|
return new LexNode(PylexSymbol.STATEMENT, 0, new LineToken(PylexSymbol.STATEMENT, linenr, indentLevel, text));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* short hand for returning an empty token for a certain line*/
|
/* short hand for returning an empty token for a certain line*/
|
||||||
function empty(linenr: number): LexNode {
|
function empty(linenr: number): LexNode {
|
||||||
return new LexNode('EMPTY', 0, new LineToken(PylexSymbol.EMPTY, linenr, 999999));
|
return new LexNode(PylexSymbol.EMPTY, 0, new LineToken(PylexSymbol.EMPTY, linenr, 999999));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
deparent,
|
deparent,
|
||||||
root,
|
root,
|
||||||
indent,
|
statement as statement,
|
||||||
empty
|
empty
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user