mirror of
https://github.com/godotengine/godot-vscode-plugin.git
synced 2026-01-05 14:10:13 +03:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ba776dc40 | ||
|
|
abaa5d32d0 | ||
|
|
06817de78e | ||
|
|
6aab0be1d4 | ||
|
|
307e29a7ec | ||
|
|
58e8626cac | ||
|
|
3ac359af86 | ||
|
|
c20909fdb3 | ||
|
|
ec9fe7fdc1 | ||
|
|
c84d7f9c12 | ||
|
|
492fe5663c | ||
|
|
8f5da41a41 | ||
|
|
e4d86f35be | ||
|
|
eed2d4f516 | ||
|
|
63b10b1d72 | ||
|
|
fdc07e4743 | ||
|
|
80ce466d53 | ||
|
|
7e3e95086b | ||
|
|
7c8696abc1 | ||
|
|
8ddc7dd310 | ||
|
|
e76c06a31a | ||
|
|
4c0f864cf8 | ||
|
|
462a7bdbd7 | ||
|
|
e2dbf8146f | ||
|
|
7b21267d07 | ||
|
|
ef3a70f417 | ||
|
|
fc027ea9ad | ||
|
|
4c47fff9af | ||
|
|
d7ff45edac | ||
|
|
38b0898649 | ||
|
|
a3b062e242 | ||
|
|
071e59364f | ||
|
|
a47980981b | ||
|
|
edcb8b96d1 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,3 +6,4 @@ test
|
|||||||
*.vsix
|
*.vsix
|
||||||
configurations/tmp.txt
|
configurations/tmp.txt
|
||||||
configurations/test.py
|
configurations/test.py
|
||||||
|
.vscode-test
|
||||||
|
|||||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -1,5 +1,35 @@
|
|||||||
# Change Log
|
# Change Log
|
||||||
|
|
||||||
|
### 0.3.7
|
||||||
|
* Add `lint` configuration to control the behaviors of syntax checking
|
||||||
|
* Fix error with run godot editor when the editor contains spaces
|
||||||
|
* Disable semicolons and brackets checks as default can be enabled with project settings
|
||||||
|
* Fix bugs in syntax valiadating
|
||||||
|
* Sync documentations with godot 3.0.4
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"lint": {
|
||||||
|
"semicolon": true,
|
||||||
|
"conditionBrackets": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 0.3.6
|
||||||
|
* Fix project configuartion file path
|
||||||
|
|
||||||
|
### 0.3.5
|
||||||
|
* Add option to disable syntax checking for GDScript
|
||||||
|
* Improved inline if else statement syntax checking
|
||||||
|
* More resource type supported for syntax highglight
|
||||||
|
* Bump default godot version to 3.0
|
||||||
|
* Sync the documentations from godot 3.0
|
||||||
|
|
||||||
|
### 0.3.4
|
||||||
|
* Fix bug with builtin symbols parsing for godot 2.1
|
||||||
|
* Improved hover documentation
|
||||||
|
* Show window progress when parsing workspace symbols
|
||||||
|
|
||||||
### 0.3.3
|
### 0.3.3
|
||||||
* Fix some syntax checking errors.
|
* Fix some syntax checking errors.
|
||||||
* Fix problems with hover documentation with latest VSCode.
|
* Fix problems with hover documentation with latest VSCode.
|
||||||
|
|||||||
88
README.md
88
README.md
@@ -2,77 +2,63 @@ A complete set of tools to code games with the [Godot game engine](http://www.go
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
The plug-in comes with a wealth of features to make your programming experience as comfortable as possible
|
The extension comes with a wealth of features to make your Godot programming experience as comfortable as possible:
|
||||||
|
|
||||||
- Syntax highlighting for the GDscript language
|
- Syntax highlighting for the GDscript (`.gd`) language
|
||||||
- Syntax highlighting for the tscn and tres scene formats
|
- Syntax highlighting for the `.tscn` and `.tres` scene formats
|
||||||
- Function definitions and documentation on hover
|
- Function definitions and documentation display on hover (see image below)
|
||||||
- Rich auto completion
|
- Rich auto-completion
|
||||||
- Static code validation
|
- Static code validation
|
||||||
- Open projects and scenes in Godot from VScode
|
- Open projects and scenes in Godot from VS Code
|
||||||
- Ctrl click on a variable or method call to jump to its definition
|
- Ctrl-click on a variable or method call to jump to its definition
|
||||||
- Full documentation supported with API of godot engine
|
- Full documentation of the Godot engine's API supported
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## Available commands
|
## Available Commands
|
||||||
|
|
||||||
The plug-ins adds a few entries to the command palette
|
The extension adds a few entries to the VS Code Command Palette under "GodotTools":
|
||||||
|
|
||||||
- Update Workspace Symbols
|
- Update workspace symbols
|
||||||
- Run workspace as godot project
|
- Run workspace as Godot project
|
||||||
- Open workspace with godot editor
|
- Open workspace with Godot editor
|
||||||
- Run current scene
|
- Run current scene
|
||||||
|
|
||||||
## Settings
|
## Settings
|
||||||
|
|
||||||
If you like this plugin you can set VSCode as your default script editor with following steps:
|
### Godot
|
||||||
|
|
||||||
|
If you like this extension, you can set VS Code as your default script editor for Godot by following these steps:
|
||||||
1. Open editor settings
|
1. Open editor settings
|
||||||
2. Select `Text Editor / External`
|
2. Select `Text Editor / External`
|
||||||
3. Check the `Use External Editor` box with mouse click
|
3. Make sure the `Use External Editor` box is checked
|
||||||
4. Fill `Exec Path` to the path of your Visual Studio Code
|
4. Fill `Exec Path` with the path to your VS Code executable
|
||||||
5. Fill `Exec Flags` with `{project} --goto {file}:{line}:{col}`
|
5. Fill `Exec Flags` with `{project} --goto {file}:{line}:{col}`
|
||||||
|
|
||||||
You can use the following settings to setup the Godot Tools:
|
### VS Code
|
||||||
- GodotTools.godotVersion: The godot version of your project
|
|
||||||
- GodotTools.editorPath: An absolute path pointing at the Godot Editor executable file. Required to run the project and test scenes from VScode
|
|
||||||
- GodotTools.workspaceDocumentWithMarkdown: Control the documentations of workspace symbols should be rendered as plain text or html from markdown
|
|
||||||
- GodotTools.ignoreIndentedVars: Parse variables defined after indent of not
|
|
||||||
- GodotTools.parseTextScene: Parse scene files with extension ends with tscn
|
|
||||||
- GodotTools.completeNodePath: Show node paths of of workspace in the code completion
|
|
||||||
- GodotTools.godotProjectRoot: The godot project directory wich contains project.godot or engine.cfg
|
|
||||||
## Issues and contributions
|
|
||||||
|
|
||||||
The [Godot Tools](https://github.com/GodotExplorer/godot-tools) and the go to [engine modules](https://github.com/GodotExplorer/editor-server) are all hosted on GitHub. Feel free to open issues there and create pull requests anytime.
|
You can use the following settings to configure Godot Tools:
|
||||||
|
- **GodotTools.godotVersion** - The Godot version of your project.
|
||||||
|
- **GodotTools.editorPath** - The absolute path to the Godot executable. Required to run the project and test scenes directly from VS Code.
|
||||||
|
- **GodotTools.workspaceDocumentWithMarkdown** - Control how the documentation of workspace symbols should be rendered: as plain text or as HTML from Markdown.
|
||||||
|
- **GodotTools.ignoreIndentedVars** - Only parse variables defined on lines without an indentation.
|
||||||
|
- **GodotTools.parseTextScene** - Parse a file as a Godot scene when the file name ends with `.tscn`.
|
||||||
|
- **GodotTools.completeNodePath** - Show node paths within a workspace as part of code completion.
|
||||||
|
- **GodotTools.godotProjectRoot** - Your Godot project's directory, which contains `project.godot` or `engine.cfg`.
|
||||||
|
|
||||||
|
## Issues and Contributions
|
||||||
|
|
||||||
|
The [Godot Tools](https://github.com/GodotExplorer/godot-tools) extension and [engine modules](https://github.com/GodotExplorer/editor-server) are both hosted on GitHub. Feel free to open issues there and create pull requests anytime.
|
||||||
|
|
||||||
|
See the [full changelog](https://github.com/GodotExplorer/godot-tools/blob/master/CHANGELOG.md) for the latest changes.
|
||||||
|
|
||||||
## FAQ
|
## FAQ
|
||||||
|
|
||||||
### Intelisense isn't showing up for me
|
### Why isn't Intellisense showing up for me?
|
||||||
|
|
||||||
Make sure you save your .gd file, then run "GodotTools: Update Workspace Symbols" from the command palate
|
Make sure you save your `.gd` file, then run "GodotTools: Update Workspace Symbols" from the Command Palette.
|
||||||
|
|
||||||
## Release Notes
|
## TODO:
|
||||||
|
* Convert official BBCode documentation into Markdown and render it into HTML with documentation previewer pages
|
||||||
### 0.3.3
|
|
||||||
* Fix some syntax checking errors.
|
|
||||||
* Fix problems with hover documentation with latest VSCode.
|
|
||||||
* Improved builtin class documentation page.
|
|
||||||
* Update the documentation data with latest godot version.
|
|
||||||
|
|
||||||
### 0.3.2
|
|
||||||
* Fix syntax checking error with match statement.
|
|
||||||
* Improved documentation for builtin code blocks.
|
|
||||||
* Start using MarkdonwString to keep links valid.
|
|
||||||
|
|
||||||
### 0.3.1
|
|
||||||
* Update documentations with latest godot.
|
|
||||||
* Fix errors with run script and run project.
|
|
||||||
* Improve code completion with opening script file and constants.
|
|
||||||
* Some improvements for documentations.
|
|
||||||
|
|
||||||
[Full change log](https://github.com/GodotExplorer/godot-tools/blob/master/CHANGELOG.md)
|
|
||||||
|
|
||||||
## TODOS:
|
|
||||||
* Convert official BBCode documentation into Markdown and render it to HTML with documentation previewer pages
|
|
||||||
* Add mermaid support with documentation
|
* Add mermaid support with documentation
|
||||||
* Undefined variable checking
|
* Undefined variable checking
|
||||||
|
|||||||
179407
doc/classes-3.0.json
179407
doc/classes-3.0.json
File diff suppressed because it is too large
Load Diff
@@ -4,6 +4,15 @@ import xml.etree.ElementTree as ET
|
|||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
def glob_path(path, pattern):
|
||||||
|
import os, fnmatch
|
||||||
|
result = []
|
||||||
|
for root, _, files in os.walk(path):
|
||||||
|
for filename in files:
|
||||||
|
if fnmatch.fnmatch(filename, pattern):
|
||||||
|
result.append(os.path.join(root, filename))
|
||||||
|
return result
|
||||||
|
|
||||||
def parseClass(data):
|
def parseClass(data):
|
||||||
dictCls = dict(data.attrib)
|
dictCls = dict(data.attrib)
|
||||||
dictCls['brief_description'] = data.find("brief_description").text.strip()
|
dictCls['brief_description'] = data.find("brief_description").text.strip()
|
||||||
@@ -56,13 +65,14 @@ def main():
|
|||||||
if len(sys.argv) >=2 :
|
if len(sys.argv) >=2 :
|
||||||
if os.path.isdir(sys.argv[1]):
|
if os.path.isdir(sys.argv[1]):
|
||||||
classes = {}
|
classes = {}
|
||||||
for fname in os.listdir(sys.argv[1]):
|
for f in glob_path(sys.argv[1], "**.xml"):
|
||||||
f = os.path.join(sys.argv[1], fname)
|
if f.find("/classes/") == -1 and f.find("/doc_classes/") == -1:
|
||||||
|
continue
|
||||||
tree = ET.parse(open(f, 'r'))
|
tree = ET.parse(open(f, 'r'))
|
||||||
cls = tree.getroot()
|
cls = tree.getroot()
|
||||||
dictCls = parseClass(cls)
|
dictCls = parseClass(cls)
|
||||||
classes[dictCls['name']] = dictCls
|
classes[dictCls['name']] = dictCls
|
||||||
jsonContent = json.dumps({"classes": classes, "version": "3.0.alpha"}, ensure_ascii=False, indent=2)
|
jsonContent = json.dumps({"classes": classes, "version": "3.0.4"}, ensure_ascii=False, indent=2)
|
||||||
print(jsonContent)
|
print(jsonContent)
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
2235
package-lock.json
generated
2235
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
57
package.json
57
package.json
@@ -3,12 +3,12 @@
|
|||||||
"displayName": "Godot Tools",
|
"displayName": "Godot Tools",
|
||||||
"icon": "icon.png",
|
"icon": "icon.png",
|
||||||
"description": "Tools for game development with godot game engine",
|
"description": "Tools for game development with godot game engine",
|
||||||
"version": "0.3.3",
|
"version": "0.3.7",
|
||||||
"publisher": "geequlim",
|
"publisher": "geequlim",
|
||||||
"repository": "https://github.com/GodotExplorer/godot-tools",
|
"repository": "https://github.com/GodotExplorer/godot-tools",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.16.1"
|
"vscode": "^1.1.21"
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"Other"
|
"Other"
|
||||||
@@ -23,15 +23,15 @@
|
|||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"command": "godot.updateWorkspaceSymbols",
|
"command": "godot.updateWorkspaceSymbols",
|
||||||
"title": "GodotTools: Update Workspace Symbols"
|
"title": "GodotTools: Update workspace symbols"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "godot.runWorkspace",
|
"command": "godot.runWorkspace",
|
||||||
"title": "GodotTools: Run workspace as godot project"
|
"title": "GodotTools: Run workspace as Godot project"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "godot.openWithEditor",
|
"command": "godot.openWithEditor",
|
||||||
"title": "GodotTools: Open workspace with godot editor"
|
"title": "GodotTools: Open workspace with Godot editor"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "godot.runCurrentScene",
|
"command": "godot.runCurrentScene",
|
||||||
@@ -40,7 +40,7 @@
|
|||||||
],
|
],
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "Godot tools configuration",
|
"title": "Godot Tools configuration",
|
||||||
"properties": {
|
"properties": {
|
||||||
"GodotTools.maxNumberOfProblems": {
|
"GodotTools.maxNumberOfProblems": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
@@ -50,12 +50,12 @@
|
|||||||
"GodotTools.editorPath": {
|
"GodotTools.editorPath": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "The absolute path of your godot editor"
|
"description": "The absolute path to the Godot executable"
|
||||||
},
|
},
|
||||||
"GodotTools.workspaceDocumentWithMarkdown": {
|
"GodotTools.workspaceDocumentWithMarkdown": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Render workspace documentations as markdown content"
|
"description": "Render workspace documentations as Markdown content"
|
||||||
},
|
},
|
||||||
"GodotTools.ignoreIndentedVars": {
|
"GodotTools.ignoreIndentedVars": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
@@ -64,23 +64,37 @@
|
|||||||
},
|
},
|
||||||
"GodotTools.godotVersion": {
|
"GodotTools.godotVersion": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 2.1,
|
"default": 3.0,
|
||||||
"description": "The godot version of your project"
|
"description": "The Godot version of your project"
|
||||||
},
|
},
|
||||||
"GodotTools.parseTextScene": {
|
"GodotTools.parseTextScene": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true,
|
"default": true,
|
||||||
"description": "Parse scene files with extention ends with tscn"
|
"description": "Parse a file as a Godot scene when the file name ends with tscn"
|
||||||
},
|
},
|
||||||
"GodotTools.completeNodePath": {
|
"GodotTools.completeNodePath": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Show node pathes of of workspace in the code completion"
|
"description": "Show node paths within a workspace as part of code completion"
|
||||||
},
|
},
|
||||||
"GodotTools.godotProjectRoot": {
|
"GodotTools.godotProjectRoot": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "${workspaceRoot}",
|
"default": "${workspaceRoot}",
|
||||||
"description": "Relate path to the godot project"
|
"description": "Your Godot project's directory"
|
||||||
|
},
|
||||||
|
"GodotTools.enableSyntaxChecking": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Turn on/off syntax checking for GDScript"
|
||||||
|
},
|
||||||
|
"GodotTools.lint": {
|
||||||
|
"type": "object",
|
||||||
|
"default": {
|
||||||
|
"semicolon": false,
|
||||||
|
"conditionBrackets": false,
|
||||||
|
"unusedSymbols": true
|
||||||
|
},
|
||||||
|
"description": "Lint configuration"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -99,9 +113,12 @@
|
|||||||
{
|
{
|
||||||
"id": "properties",
|
"id": "properties",
|
||||||
"extensions": [
|
"extensions": [
|
||||||
".cfg",
|
"cfg",
|
||||||
"tres",
|
"tres",
|
||||||
"tscn"
|
"tscn",
|
||||||
|
"godot",
|
||||||
|
"gdns",
|
||||||
|
"gdnlib"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
@@ -126,11 +143,11 @@
|
|||||||
"test": "node ./node_modules/vscode/bin/test"
|
"test": "node ./node_modules/vscode/bin/test"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^2.0.3",
|
"@types/mocha": "^5.2.5",
|
||||||
"vscode": "^1.1.5",
|
"@types/node": "^10.9.4",
|
||||||
"mocha": "^2.3.3",
|
"mocha": "^5.2.0",
|
||||||
"@types/node": "^6.0.40",
|
"typescript": "^3.0.3",
|
||||||
"@types/mocha": "^2.2.32"
|
"vscode": "^1.1.21"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"glob": "^7.1.1",
|
"glob": "^7.1.1",
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ class Config {
|
|||||||
// ---------------------- class -----------------
|
// ---------------------- class -----------------
|
||||||
const item: CompletionItem = new CompletionItem(classdoc.name, CompletionItemKind.Class);
|
const item: CompletionItem = new CompletionItem(classdoc.name, CompletionItemKind.Class);
|
||||||
item.detail = 'Native Class';
|
item.detail = 'Native Class';
|
||||||
item.documentation = classdoc.brief_description + " \n\n" +classdoc.description;
|
item.documentation = classdoc.brief_description + " \n" +classdoc.description;
|
||||||
this.builtinCompletions.classes.push(item);
|
this.builtinCompletions.classes.push(item);
|
||||||
builtinSymbolInfoMap[classdoc.name] = {completionItem: item, rowDoc: classdoc};
|
builtinSymbolInfoMap[classdoc.name] = {completionItem: item, rowDoc: classdoc};
|
||||||
// ----------------------- functions -----------------------
|
// ----------------------- functions -----------------------
|
||||||
@@ -192,6 +192,11 @@ class Config {
|
|||||||
script_files = Object.keys(this.workspaceSymbols);
|
script_files = Object.keys(this.workspaceSymbols);
|
||||||
for (let path of script_files) {
|
for (let path of script_files) {
|
||||||
const script = this.workspaceSymbols[path];
|
const script = this.workspaceSymbols[path];
|
||||||
|
if (workspace) {
|
||||||
|
const root = this.normalizePath(workspace.rootPath) + "/";
|
||||||
|
if (path.startsWith(root))
|
||||||
|
path = path.replace(root, "");
|
||||||
|
}
|
||||||
const addScriptItems = (items, kind: CompletionItemKind, kindName:string = "Symbol", insertText = (n)=>n)=>{
|
const addScriptItems = (items, kind: CompletionItemKind, kindName:string = "Symbol", insertText = (n)=>n)=>{
|
||||||
const _items: CompletionItem[] = [];
|
const _items: CompletionItem[] = [];
|
||||||
for (let name of Object.keys(items)) {
|
for (let name of Object.keys(items)) {
|
||||||
@@ -203,7 +208,7 @@ class Config {
|
|||||||
item.detail = cvalue;
|
item.detail = cvalue;
|
||||||
item.insertText = insertText(name) + (signature=="()"?"()":"");
|
item.insertText = insertText(name) + (signature=="()"?"()":"");
|
||||||
item.documentation = (script.documents && script.documents[name])?script.documents[name]+"\r\n":"";
|
item.documentation = (script.documents && script.documents[name])?script.documents[name]+"\r\n":"";
|
||||||
item.documentation += `${kindName} defined in ${workspace.asRelativePath(path)}`;
|
item.documentation += `${kindName} defined in ${path}`;
|
||||||
_items.push(item);
|
_items.push(item);
|
||||||
}
|
}
|
||||||
return _items;
|
return _items;
|
||||||
@@ -323,4 +328,4 @@ class Config {
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default new Config();
|
export default new Config();
|
||||||
|
|||||||
@@ -1,189 +1,194 @@
|
|||||||
import requestGodot from "../request";
|
import requestGodot from "../request";
|
||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import {DiagnosticCollection, DiagnosticSeverity} from 'vscode';
|
import {DiagnosticCollection, DiagnosticSeverity} from 'vscode';
|
||||||
import config from '../config';
|
import config from '../config';
|
||||||
|
|
||||||
interface GDParseError {
|
interface GDParseError {
|
||||||
message : string,
|
message : string,
|
||||||
column : number,
|
column : number,
|
||||||
row : number
|
row : number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GDScript {
|
interface GDScript {
|
||||||
members : {
|
members : {
|
||||||
constants: {},
|
constants: {},
|
||||||
functions: {},
|
functions: {},
|
||||||
variables: {},
|
variables: {},
|
||||||
signals: {}
|
signals: {}
|
||||||
},
|
},
|
||||||
base : string,
|
base : string,
|
||||||
errors : GDParseError[],
|
errors : GDParseError[],
|
||||||
valid : boolean,
|
valid : boolean,
|
||||||
is_tool : boolean,
|
is_tool : boolean,
|
||||||
native : string
|
native : string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ParseRequest {
|
interface ParseRequest {
|
||||||
text : string,
|
text : string,
|
||||||
path : string
|
path : string
|
||||||
}
|
}
|
||||||
|
|
||||||
class GDScriptDiagnosticSeverity {
|
class GDScriptDiagnosticSeverity {
|
||||||
private _subscription : DiagnosticCollection;
|
private _subscription : DiagnosticCollection;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this._subscription = vscode.languages.createDiagnosticCollection("gdscript")
|
this._subscription = vscode.languages.createDiagnosticCollection("gdscript")
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this._subscription.dispose()
|
this._subscription.dispose()
|
||||||
}
|
}
|
||||||
|
|
||||||
async validateScript(doc : vscode.TextDocument, script : any) {
|
async validateScript(doc : vscode.TextDocument, script : any) {
|
||||||
if (doc.languageId == 'gdscript') {
|
if (doc.languageId == 'gdscript') {
|
||||||
if (script) {
|
if (script) {
|
||||||
let diagnostics = [ ...(this.validateExpression(doc)), ...(this.validateUnusedSymbols(doc, script)) ];
|
let diagnostics = [ ...(this.validateExpression(doc)), ...(this.validateUnusedSymbols(doc, script)) ];
|
||||||
this._subscription.set(doc.uri, diagnostics);
|
this._subscription.set(doc.uri, diagnostics);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private validateUnusedSymbols(doc : vscode.TextDocument, script) {
|
private validateUnusedSymbols(doc : vscode.TextDocument, script) {
|
||||||
let diagnostics = [];
|
let diagnostics = [];
|
||||||
const text = doc.getText();
|
let cfg : any = vscode.workspace.getConfiguration("GodotTools").get("lint");
|
||||||
|
if (!cfg.unusedSymbols)
|
||||||
const check = (name : string, range : vscode.Range) => {
|
return diagnostics
|
||||||
var matchs = text.match(new RegExp(`([^\\w]|\\[|\\{)\\s*${name}\\s*([^\\w]|\\[|\\{)`, 'g'));
|
|
||||||
let count = matchs ? matchs.length : 0;
|
const text = doc.getText();
|
||||||
var incomment = text.match(new RegExp(`#.*?([^\\w]|\\[|\\{)\\s*${name}\\s*([^\\w]|\\[|\\{)`, 'g'));
|
const check = (name : string, range : vscode.Range) => {
|
||||||
count -= incomment ? incomment.length : 0;
|
var matchs = text.match(new RegExp(`([^\\w]|\\[|\\{)\\s*${name}\\s*([^\\w]|\\[|\\{)`, 'g'));
|
||||||
if (count <= 1)
|
let count = matchs ? matchs.length : 0;
|
||||||
diagnostics.push(new vscode.Diagnostic(range, `${name} is never used.`, DiagnosticSeverity.Warning));
|
var incomment = text.match(new RegExp(`#.*?([^\\w]|\\[|\\{)\\s*${name}\\s*([^\\w]|\\[|\\{)`, 'g'));
|
||||||
};
|
count -= incomment ? incomment.length : 0;
|
||||||
// Unused variables
|
if (count <= 1)
|
||||||
for (let key of Object.keys(script.variables))
|
diagnostics.push(new vscode.Diagnostic(range, `${name} is never used.`, DiagnosticSeverity.Warning));
|
||||||
check(key, script.variables[key]);
|
};
|
||||||
for (let key of Object.keys(script.constants))
|
// Unused variables
|
||||||
check(key, script.constants[key]);
|
for (let key of Object.keys(script.variables))
|
||||||
return diagnostics;
|
check(key, script.variables[key]);
|
||||||
}
|
for (let key of Object.keys(script.constants))
|
||||||
|
check(key, script.constants[key]);
|
||||||
private validateExpression(doc : vscode.TextDocument) {
|
return diagnostics;
|
||||||
let diagnostics = [];
|
}
|
||||||
let expectEndOfLine = false;
|
|
||||||
const text = doc.getText();
|
private validateExpression(doc : vscode.TextDocument) {
|
||||||
const lines = text.split(/\r?\n/);
|
let cfg : any = vscode.workspace.getConfiguration("GodotTools").get("lint");
|
||||||
lines.map((line : string, i : number) => {
|
|
||||||
let matchstart = /[^\s]+.*/.exec(line);
|
let diagnostics = [];
|
||||||
let curLineStartAt = 0;
|
let expectEndOfLine = false;
|
||||||
if (matchstart)
|
const text = doc.getText();
|
||||||
curLineStartAt = matchstart.index;
|
const lines = text.split(/\r?\n/);
|
||||||
|
lines.map((line : string, i : number) => {
|
||||||
// ignore comments
|
let matchstart = /[^\s]+.*/.exec(line);
|
||||||
if (line.match(/^\s*#.*/) || line.match(/^#.*/))
|
let curLineStartAt = 0;
|
||||||
return
|
if (matchstart)
|
||||||
// normalize line content
|
curLineStartAt = matchstart.index;
|
||||||
line = "\t" + line + "\t";
|
|
||||||
var range = new vscode.Range(i, curLineStartAt, i, line.length);
|
// ignore comments
|
||||||
|
if (line.match(/^\s*#.*/) || line.match(/^#.*/))
|
||||||
if (line.match(/[^#].*?\;/) && !line.match(/[#].*?\;/)) {
|
return
|
||||||
const semicolonIndex = line.indexOf(';');
|
// normalize line content
|
||||||
diagnostics.push(new vscode.Diagnostic(new vscode.Range(i, semicolonIndex, i, semicolonIndex + 1), "Statement contains a semicolon.", DiagnosticSeverity.Warning));
|
line = "\t" + line + "\t";
|
||||||
}
|
var range = new vscode.Range(i, curLineStartAt, i, line.length);
|
||||||
if (line.match(/[^#].*?/) && expectEndOfLine) {
|
|
||||||
if (!line.match(/.*?(\\|\:)/)) {
|
if (cfg.semicolon && line.match(/[^#].*?\;/) && !line.match(/[#].*?\;/)) {
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "': or \\' expected at end of the line.", DiagnosticSeverity.Error));
|
const semicolonIndex = line.indexOf(';');
|
||||||
expectEndOfLine = false;
|
diagnostics.push(new vscode.Diagnostic(new vscode.Range(i, semicolonIndex, i, semicolonIndex + 1), "Statement contains a semicolon.", DiagnosticSeverity.Warning));
|
||||||
}
|
}
|
||||||
if (line.match(/.*?\:/))
|
if (line.match(/[^#].*?/) && expectEndOfLine) {
|
||||||
expectEndOfLine = false;
|
if (!line.match(/.*?(\\|\:)/)) {
|
||||||
}
|
diagnostics.push(new vscode.Diagnostic(range, "': or \\' expected at end of the line.", DiagnosticSeverity.Error));
|
||||||
const colonKeywords = /\b(if|elif|else|for|while|func|class|match)\b/;
|
expectEndOfLine = false;
|
||||||
let keywords = line.match(colonKeywords)
|
}
|
||||||
if (keywords) {
|
if (line.match(/.*?\:/))
|
||||||
if(line.match(new RegExp(`".*?\\s${keywords[1]}\\s.*?"`)) || line.match(new RegExp(`'.*?\\s${keywords[1]}\\s.*?\'`)))
|
expectEndOfLine = false;
|
||||||
return
|
}
|
||||||
if(line.match(new RegExp(`.*?#.*?\\s${keywords[1]}\\s.*?`)))
|
const colonKeywords = /\b(if|elif|else|for|while|func|class|match)\b/;
|
||||||
return
|
let keywords = line.match(colonKeywords)
|
||||||
if(line.match(/.*?\sif\s+\w.*?\s+else\s+\w.*/))
|
if (keywords) {
|
||||||
return
|
if(line.match(new RegExp(`".*?\\s${keywords[1]}\\s.*?"`)) || line.match(new RegExp(`'.*?\\s${keywords[1]}\\s.*?\'`)))
|
||||||
if (line.match(/.*?\\/))
|
return
|
||||||
expectEndOfLine = true;
|
if(line.match(new RegExp(`.*?#.*?\\s${keywords[1]}\\s.*?`)))
|
||||||
else if (line.match(/.*?\:[\s+]+[^#\s]+/))
|
return
|
||||||
return
|
if(line.match(/.*?\sif\s+(\!|\[|\{|\w|").*?\s+else\s+[^\s]+/))
|
||||||
else if (!line.match(/.*?(\\|\:)/))
|
return
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "': or \\' expected at end of the line.", DiagnosticSeverity.Error));
|
if (line.match(/.*?\\/))
|
||||||
else if (line.match(/(if|elif|while|func|class|match)\s*\:/))
|
expectEndOfLine = true;
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Indentifier expected before ':'", DiagnosticSeverity.Error));
|
else if (line.match(/.*?\:[\s+]+[^#\s]+/))
|
||||||
else if (line.match(/[^\w]for[^\w]/) && !line.match(/\s+for\s\w+\s+in\s+|[\w+]|\{.*?\}|\[.*?\]|\(.*?\)/)){
|
return
|
||||||
if(!(line.match(/".*?for.*?"/) || line.match(/'.*?for.*?'/)))
|
else if (!line.match(/.*?(\\|\:)/))
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Invalid for expression", DiagnosticSeverity.Error));
|
diagnostics.push(new vscode.Diagnostic(range, "': or \\' expected at end of the line.", DiagnosticSeverity.Error));
|
||||||
}
|
else if (line.match(/\s(if|elif|while|func|class|match)\s*\:/))
|
||||||
else if (line.match(/(if|elif|while|match)\s*\(.*\)/))
|
diagnostics.push(new vscode.Diagnostic(range, "Indentifier expected before ':'", DiagnosticSeverity.Error));
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Extra brackets in condition expression.", DiagnosticSeverity.Warning));
|
else if (line.match(/[^\w]for[^\w]/) && !line.match(/\s+for\s\w+\s+in\s+|[\w+]|\{.*?\}|\[.*?\]|\(.*?\)/)){
|
||||||
const blockIndetCheck = function() {
|
if(!(line.match(/".*?for.*?"/) || line.match(/'.*?for.*?'/)))
|
||||||
const err = new vscode.Diagnostic(range, "Expected indented block after expression", DiagnosticSeverity.Error);
|
diagnostics.push(new vscode.Diagnostic(range, "Invalid for expression", DiagnosticSeverity.Error));
|
||||||
if (i < lines.length - 1) {
|
}
|
||||||
let next = i + 1;
|
else if (cfg.conditionBrackets && line.match(/\s(if|elif|while|match)\s*\(.*\)\s*:\s*$/))
|
||||||
let nextline = lines[next];
|
diagnostics.push(new vscode.Diagnostic(range, "Extra brackets in condition expression.", DiagnosticSeverity.Warning));
|
||||||
// changes nextline until finds a line containg text or comes to the last line
|
const blockIndetCheck = function() {
|
||||||
while (((!nextline || !nextline.trim().length) || nextline.match(/^\s*#/)) && next < lines.length - 1) {
|
const err = new vscode.Diagnostic(range, "Expected indented block after expression", DiagnosticSeverity.Error);
|
||||||
++next;
|
if (i < lines.length - 1) {
|
||||||
nextline = lines[next];
|
let next = i + 1;
|
||||||
}
|
let nextline = lines[next];
|
||||||
let nextLineStartAt = -1;
|
// changes nextline until finds a line containg text or comes to the last line
|
||||||
let match = /[^\s]+.*/.exec(nextline);
|
while (((!nextline || !nextline.trim().length) || nextline.match(/^\s*#/)) && next < lines.length - 1) {
|
||||||
if (match)
|
++next;
|
||||||
nextLineStartAt = match.index;
|
nextline = lines[next];
|
||||||
|
}
|
||||||
if (nextLineStartAt <= curLineStartAt)
|
let nextLineStartAt = -1;
|
||||||
diagnostics.push(err);
|
let match = /[^\s]+.*/.exec(nextline);
|
||||||
}
|
if (match)
|
||||||
else if(line.match(/\:\s*$/))
|
nextLineStartAt = match.index;
|
||||||
diagnostics.push(err);
|
|
||||||
};
|
if (nextLineStartAt <= curLineStartAt)
|
||||||
if(!expectEndOfLine)
|
diagnostics.push(err);
|
||||||
blockIndetCheck();
|
}
|
||||||
}
|
else if(line.match(/\:\s*$/))
|
||||||
// Do not check : for end of statement as it breaks match statment
|
diagnostics.push(err);
|
||||||
let endOfStateMentWithComma = false;
|
};
|
||||||
if(endOfStateMentWithComma && !line.match(colonKeywords) && line.match(/\:\s*$/)) {
|
if(!expectEndOfLine)
|
||||||
let showErr = true;
|
blockIndetCheck();
|
||||||
if( i >= 1 ) {
|
}
|
||||||
let previous = i - 1;
|
// Do not check : for end of statement as it breaks match statment
|
||||||
let previousline = lines[previous];
|
let endOfStateMentWithComma = false;
|
||||||
while(previousline.match(/\\\s*$/) && previous>=1) {
|
if(endOfStateMentWithComma && !line.match(colonKeywords) && line.match(/\:\s*$/)) {
|
||||||
--previous;
|
let showErr = true;
|
||||||
const ppreviousline = lines[previous];
|
if( i >= 1 ) {
|
||||||
if(ppreviousline.match(/\\\s*$/))
|
let previous = i - 1;
|
||||||
previousline = ppreviousline;
|
let previousline = lines[previous];
|
||||||
}
|
while(previousline.match(/\\\s*$/) && previous>=1) {
|
||||||
const keywords = previousline.match(colonKeywords);
|
--previous;
|
||||||
if(keywords && !(previousline.match(new RegExp(`".*?\\s${keywords[1]}\\s.*?"`)) || previousline.match(new RegExp(`'.*?\\s${keywords[1]}\\s.*?'`)) ))
|
const ppreviousline = lines[previous];
|
||||||
showErr = false
|
if(ppreviousline.match(/\\\s*$/))
|
||||||
}
|
previousline = ppreviousline;
|
||||||
if(showErr)
|
}
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Expected end of statement after expression", DiagnosticSeverity.Error));
|
const keywords = previousline.match(colonKeywords);
|
||||||
}
|
if(keywords && !(previousline.match(new RegExp(`".*?\\s${keywords[1]}\\s.*?"`)) || previousline.match(new RegExp(`'.*?\\s${keywords[1]}\\s.*?'`)) ))
|
||||||
if (line.match(/(if|elif|while|return)\s+\w+\s*=\s*\w+/))
|
showErr = false
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Assignment in condition or return expressions", DiagnosticSeverity.Warning));
|
}
|
||||||
else if (line.indexOf("==") > 0 && !line.match(/\:\s*/)) {
|
if(showErr)
|
||||||
const endAt = line.indexOf("==");
|
diagnostics.push(new vscode.Diagnostic(range, "Expected end of statement after expression", DiagnosticSeverity.Error));
|
||||||
const precontent = line.substring(0, endAt);
|
}
|
||||||
if (!precontent.match(/\s(if|elif|while|return)\s/) && !precontent.match(/=[^=]/) && !expectEndOfLine) {
|
if (line.match(/(if|elif|while|return)\s+\w+\s*=\s*\w+/))
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Unhandled comparation expression contains", DiagnosticSeverity.Warning));
|
diagnostics.push(new vscode.Diagnostic(range, "Assignment in condition or return expressions", DiagnosticSeverity.Warning));
|
||||||
}
|
else if (line.indexOf("==") > 0 && !line.match(/\:\s*/)) {
|
||||||
}
|
const endAt = line.indexOf("==");
|
||||||
let match = /var\s+(\w+)\s*=\s*(\w+)/.exec(line);
|
const precontent = line.substring(0, endAt);
|
||||||
if (match && match.length > 2 && match[1].length > 0 && match[1] == match[2]) {
|
if (!precontent.match(/\s(if|elif|while|return)\s/) && !precontent.match(/=[^=]/) && !precontent.match(/assert\s*\(/) && !expectEndOfLine) {
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Self Assignment may cause error.", DiagnosticSeverity.Warning));
|
diagnostics.push(new vscode.Diagnostic(range, "Unhandled comparation expression contains", DiagnosticSeverity.Warning));
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
return diagnostics;
|
let match = /var\s+(\w+)\s*=\s*(\w+)/.exec(line);
|
||||||
}
|
if (match && match.length > 2 && match[1].length > 0 && match[1] == match[2]) {
|
||||||
|
diagnostics.push(new vscode.Diagnostic(range, "Self Assignment may cause error.", DiagnosticSeverity.Warning));
|
||||||
}
|
}
|
||||||
|
});
|
||||||
export default GDScriptDiagnosticSeverity;
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GDScriptDiagnosticSeverity;
|
||||||
|
|||||||
@@ -44,16 +44,19 @@ class GDScriptHoverProvider implements HoverProvider {
|
|||||||
|
|
||||||
// check from workspace
|
// check from workspace
|
||||||
const genWorkspaceTips = ()=> {
|
const genWorkspaceTips = ()=> {
|
||||||
for (let path of Object.keys(workspaceSymbols)) {
|
for (let filepath of Object.keys(workspaceSymbols)) {
|
||||||
const script = workspaceSymbols[path];
|
const script = workspaceSymbols[filepath];
|
||||||
let scriptips: MarkdownString[] = [];
|
let scriptips: MarkdownString[] = [];
|
||||||
const getHoverText = (items, type, path): MarkdownString[] => {
|
const getHoverText = (items, type, gdpath): MarkdownString[] => {
|
||||||
const _items: MarkdownString[] = [];
|
const _items: MarkdownString[] = [];
|
||||||
for (let name of Object.keys(items)) {
|
for (let name of Object.keys(items)) {
|
||||||
if (name == hoverText) {
|
if (name == hoverText) {
|
||||||
let dfile = path;
|
let dfile = gdpath;
|
||||||
if (workspace && workspace.asRelativePath(dfile))
|
if (workspace) {
|
||||||
dfile = workspace.asRelativePath(dfile);
|
const root = config.normalizePath(workspace.rootPath) + "/";
|
||||||
|
if (gdpath.startsWith(root))
|
||||||
|
dfile = gdpath.replace(root, "");
|
||||||
|
}
|
||||||
let signature = "";
|
let signature = "";
|
||||||
if(type == "func"|| type == "signal" && script.signatures[name])
|
if(type == "func"|| type == "signal" && script.signatures[name])
|
||||||
signature = script.signatures[name];
|
signature = script.signatures[name];
|
||||||
@@ -65,21 +68,21 @@ class GDScriptHoverProvider implements HoverProvider {
|
|||||||
rowDoc += "```plaintext\r\n"+rowDoc+"\r\n```";
|
rowDoc += "```plaintext\r\n"+rowDoc+"\r\n```";
|
||||||
doc += rowDoc;
|
doc += rowDoc;
|
||||||
doc = doc?doc+"\r\n\r\n":"";
|
doc = doc?doc+"\r\n\r\n":"";
|
||||||
if(path != "autoload")
|
if(gdpath != "autoload")
|
||||||
doc += `*Defined in [${dfile}](${Uri.file(path).toString()})*`;
|
doc += `*Defined in [${dfile}](${Uri.file(gdpath).toString()})*`;
|
||||||
_items.push(makeMarkdown(doc));
|
_items.push(makeMarkdown(doc));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return _items;
|
return _items;
|
||||||
}
|
}
|
||||||
scriptips = [...scriptips, ...getHoverText(script.variables, 'var', path)];
|
scriptips = [...scriptips, ...getHoverText(script.variables, 'var', filepath)];
|
||||||
scriptips = [...scriptips, ...getHoverText(script.constants, 'const', path)];
|
scriptips = [...scriptips, ...getHoverText(script.constants, 'const', filepath)];
|
||||||
scriptips = [...scriptips, ...getHoverText(script.functions, 'func', path)];
|
scriptips = [...scriptips, ...getHoverText(script.functions, 'func', filepath)];
|
||||||
scriptips = [...scriptips, ...getHoverText(script.signals, 'signal', path)];
|
scriptips = [...scriptips, ...getHoverText(script.signals, 'signal', filepath)];
|
||||||
scriptips = [...scriptips, ...getHoverText(script.classes, 'class', path)];
|
scriptips = [...scriptips, ...getHoverText(script.classes, 'class', filepath)];
|
||||||
if(script.enumerations)
|
if(script.enumerations)
|
||||||
scriptips = [...scriptips, ...getHoverText(script.enumerations, 'const', path)];
|
scriptips = [...scriptips, ...getHoverText(script.enumerations, 'const', filepath)];
|
||||||
tips = [...tips, ...scriptips];
|
tips = [...tips, ...scriptips];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -153,18 +156,18 @@ class GDScriptHoverProvider implements HoverProvider {
|
|||||||
|
|
||||||
switch (item.kind) {
|
switch (item.kind) {
|
||||||
case CompletionItemKind.Class:
|
case CompletionItemKind.Class:
|
||||||
return makeMarkdown(`Native Class ${genLink(classname, classname)} ${doc}`);
|
return makeMarkdown(`Native Class ${genLink(classname, classname)}\n${doc}`);
|
||||||
case CompletionItemKind.Method:
|
case CompletionItemKind.Method:
|
||||||
doc = doc.substring(doc.indexOf("\n")+1, doc.length);
|
doc = doc.substring(doc.indexOf("\n")+1, doc.length);
|
||||||
return makeMarkdown(`${genMethodMarkDown()} ${doc}`);
|
return makeMarkdown(`${genMethodMarkDown()}\n${doc}`);
|
||||||
case CompletionItemKind.Interface:
|
case CompletionItemKind.Interface:
|
||||||
doc = doc.substring(doc.indexOf("\n")+1, doc.length);
|
doc = doc.substring(doc.indexOf("\n")+1, doc.length);
|
||||||
return makeMarkdown(`signal + ${genMethodMarkDown()} ${doc}`);
|
return makeMarkdown(`signal ${genMethodMarkDown()}\n${doc}`);
|
||||||
case CompletionItemKind.Variable:
|
case CompletionItemKind.Variable:
|
||||||
case CompletionItemKind.Property:
|
case CompletionItemKind.Property:
|
||||||
return makeMarkdown(`${rowDoc.type} ${genLink(classname, classname)}.${genLink(rowDoc.name, classname+"."+rowDoc.name)} ${doc}`);
|
return makeMarkdown(`${rowDoc.type} ${genLink(classname, classname)}.${genLink(rowDoc.name, classname + "." + rowDoc.name)}\n${doc}`);
|
||||||
case CompletionItemKind.Enum:
|
case CompletionItemKind.Enum:
|
||||||
return makeMarkdown(`const ${genLink(classname, classname)}.${genLink(rowDoc.name, classname+"."+rowDoc.name)} = ${rowDoc.value} ${doc}`);
|
return makeMarkdown(`const ${genLink(classname, classname)}.${genLink(rowDoc.name, classname + "." + rowDoc.name)} = ${rowDoc.value}\n${doc}`);
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,21 +18,22 @@ class ToolManager {
|
|||||||
private workspacesymbolprovider: GDScriptWorkspaceSymbolProvider = null;
|
private workspacesymbolprovider: GDScriptWorkspaceSymbolProvider = null;
|
||||||
private _disposable: vscode.Disposable;
|
private _disposable: vscode.Disposable;
|
||||||
private _context: vscode.ExtensionContext;
|
private _context: vscode.ExtensionContext;
|
||||||
private _projectFile : string = "engine.cfg";
|
private _projectFile : string = "project.godot";
|
||||||
private _rootDir : string = "";
|
private _rootDir : string = "";
|
||||||
private _biuitinDocFile : string = "doc/classes-2.1.json";
|
private _biuitinDocFile : string = "doc/classes-3.0.json";
|
||||||
|
|
||||||
constructor(context: vscode.ExtensionContext) {
|
constructor(context: vscode.ExtensionContext) {
|
||||||
this._context = context;
|
this._context = context;
|
||||||
this.workspaceDir = vscode.workspace.rootPath;
|
this.workspaceDir = vscode.workspace.rootPath;
|
||||||
let completionDollar = false;
|
let completionDollar = false;
|
||||||
|
|
||||||
if (vscode.workspace.getConfiguration("GodotTools").get("godotVersion", 2.1) >= 3) {
|
if (vscode.workspace.getConfiguration("GodotTools").get("godotVersion", 3.0) < 3) {
|
||||||
this._projectFile = "project.godot";
|
this._projectFile = "engine.cfg";
|
||||||
this._biuitinDocFile = "doc/classes-3.0.json";
|
this._biuitinDocFile = "doc/classes-2.1.json";
|
||||||
completionDollar = true;
|
completionDollar = true;
|
||||||
this.loadClasses();
|
|
||||||
}
|
}
|
||||||
|
this.loadClasses();
|
||||||
|
|
||||||
if (vscode.workspace && this.workspaceDir) {
|
if (vscode.workspace && this.workspaceDir) {
|
||||||
vscode.workspace.registerTextDocumentContentProvider('godotdoc', new GDScriptDocumentContentProvider());
|
vscode.workspace.registerTextDocumentContentProvider('godotdoc', new GDScriptDocumentContentProvider());
|
||||||
this.workspaceDir = this.workspaceDir.replace(/\\/g, "/");
|
this.workspaceDir = this.workspaceDir.replace(/\\/g, "/");
|
||||||
@@ -77,12 +78,12 @@ class ToolManager {
|
|||||||
if (path && path.length > 0 && path.endsWith("/"))
|
if (path && path.length > 0 && path.endsWith("/"))
|
||||||
path = path.substring(0, path.length - 1)
|
path = path.substring(0, path.length - 1)
|
||||||
if (path.toLowerCase() == self.workspaceDir.toLowerCase())
|
if (path.toLowerCase() == self.workspaceDir.toLowerCase())
|
||||||
vscode.window.showInformationMessage("Connected to godot editor server");
|
vscode.window.showInformationMessage("Connected to the Godot editor server");
|
||||||
else {
|
else {
|
||||||
vscode.window.showWarningMessage("The opened project is not same with godot editor");
|
vscode.window.showWarningMessage("The opened project is not the same within the Godot editor");
|
||||||
}
|
}
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
vscode.window.showErrorMessage("Failed connect to godot editor server");
|
vscode.window.showErrorMessage("Failed connecting to the Godot editor server");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -123,7 +124,7 @@ class ToolManager {
|
|||||||
gdpath = path.join(this._rootDir, gdpath);
|
gdpath = path.join(this._rootDir, gdpath);
|
||||||
let showgdpath = vscode.workspace.asRelativePath(gdpath);
|
let showgdpath = vscode.workspace.asRelativePath(gdpath);
|
||||||
|
|
||||||
let doc = "Auto loaded instance of " + `[${showgdpath}](${vscode.Uri.file(gdpath).toString()})`;
|
let doc = "Autoloaded instance of " + `[${showgdpath}](${vscode.Uri.file(gdpath).toString()})`;
|
||||||
doc = doc.replace(/"/g, " ");
|
doc = doc.replace(/"/g, " ");
|
||||||
|
|
||||||
script.constants[name] = new vscode.Range(0, 0, 0, 0);
|
script.constants[name] = new vscode.Range(0, 0, 0, 0);
|
||||||
@@ -156,13 +157,16 @@ class ToolManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private loadWorkspaceSymbols() {
|
private loadWorkspaceSymbols() {
|
||||||
|
let handle = this.showProgress("Loading symbols");
|
||||||
if (vscode.workspace.getConfiguration("GodotTools").get("parseTextScene", false)) {
|
if (vscode.workspace.getConfiguration("GodotTools").get("parseTextScene", false)) {
|
||||||
this.loadAllNodesInWorkspace();
|
this.loadAllNodesInWorkspace();
|
||||||
}
|
}
|
||||||
this.loadAllSymbols().then(symbols => {
|
this.loadAllSymbols().then(symbols => {
|
||||||
|
handle();
|
||||||
vscode.window.setStatusBarMessage("$(check) Workspace symbols", 5000);
|
vscode.window.setStatusBarMessage("$(check) Workspace symbols", 5000);
|
||||||
config.setAllSymbols(symbols);
|
config.setAllSymbols(symbols);
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
|
handle();
|
||||||
vscode.window.setStatusBarMessage("$(x) Workspace symbols", 5000);
|
vscode.window.setStatusBarMessage("$(x) Workspace symbols", 5000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -179,10 +183,10 @@ class ToolManager {
|
|||||||
let pathFlag = "-path";
|
let pathFlag = "-path";
|
||||||
if (vscode.workspace.getConfiguration("GodotTools").get("godotVersion", 2.1) >= 3)
|
if (vscode.workspace.getConfiguration("GodotTools").get("godotVersion", 2.1) >= 3)
|
||||||
pathFlag = "--path";
|
pathFlag = "--path";
|
||||||
this.runEditor(`${pathFlag} ${this._rootDir} ${params}`);
|
this.runEditor(`${pathFlag} "${this._rootDir}" ${params}`);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
vscode.window.showErrorMessage("Current workspace is not a godot project");
|
vscode.window.showErrorMessage("Current workspace is not a Godot project");
|
||||||
}
|
}
|
||||||
|
|
||||||
private runEditor(params = "") {
|
private runEditor(params = "") {
|
||||||
@@ -192,8 +196,13 @@ class ToolManager {
|
|||||||
if (!fs.existsSync(editorPath) || !fs.statSync(editorPath).isFile()) {
|
if (!fs.existsSync(editorPath) || !fs.statSync(editorPath).isFile()) {
|
||||||
vscode.window.showErrorMessage("Invalid editor path to run the project");
|
vscode.window.showErrorMessage("Invalid editor path to run the project");
|
||||||
} else {
|
} else {
|
||||||
let terminal = vscode.window.createTerminal("Godot");
|
let existingTerminal = vscode.window.terminals.find(t => t._name === "GodotTools")
|
||||||
let cmmand = `${editorPath.replace(" ", "\\ ")} ${params}`;
|
if (existingTerminal) {
|
||||||
|
existingTerminal.dispose()
|
||||||
|
}
|
||||||
|
let terminal = vscode.window.createTerminal("GodotTools");
|
||||||
|
editorPath = this.escapeCmd(editorPath);
|
||||||
|
let cmmand = `${editorPath} ${params}`;
|
||||||
terminal.sendText(cmmand, true);
|
terminal.sendText(cmmand, true);
|
||||||
terminal.show();
|
terminal.show();
|
||||||
}
|
}
|
||||||
@@ -214,7 +223,7 @@ class ToolManager {
|
|||||||
const script = config.loadSymbolsFromFile(absFilePath);
|
const script = config.loadSymbolsFromFile(absFilePath);
|
||||||
if (script) {
|
if (script) {
|
||||||
if(script.native == "SceneTree" || script.native == "MainLoop") {
|
if(script.native == "SceneTree" || script.native == "MainLoop") {
|
||||||
this.runEditor(`-s ${absFilePath}`);
|
this.runEditor(`-s "${absFilePath}"`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -222,9 +231,9 @@ class ToolManager {
|
|||||||
}
|
}
|
||||||
if (scenePath) {
|
if (scenePath) {
|
||||||
if (scenePath.endsWith(".gd"))
|
if (scenePath.endsWith(".gd"))
|
||||||
scenePath = ` -s res://${scenePath} `;
|
scenePath = ` -s "res://${scenePath}" `;
|
||||||
else
|
else
|
||||||
scenePath = ` res://${scenePath} `;
|
scenePath = ` "res://${scenePath}" `;
|
||||||
this.openWorkspaceWithEditor(scenePath);
|
this.openWorkspaceWithEditor(scenePath);
|
||||||
} else
|
} else
|
||||||
vscode.window.showErrorMessage("Current document is not a scene file or MainLoop");
|
vscode.window.showErrorMessage("Current document is not a scene file or MainLoop");
|
||||||
@@ -237,12 +246,38 @@ class ToolManager {
|
|||||||
if (!done)
|
if (!done)
|
||||||
done = config.loadClasses(path.join(this._context.extensionPath, this._biuitinDocFile));
|
done = config.loadClasses(path.join(this._context.extensionPath, this._biuitinDocFile));
|
||||||
if (!done)
|
if (!done)
|
||||||
vscode.window.showErrorMessage("Load GDScript documentations failed");
|
vscode.window.showErrorMessage("Loading GDScript documentation failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose() {
|
dispose() {
|
||||||
this._disposable.dispose();
|
this._disposable.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private showProgress(message: string) {
|
||||||
|
let r_resolve;
|
||||||
|
vscode.window.withProgress({ location: vscode.ProgressLocation.Window}, p => {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
p.report({message});
|
||||||
|
r_resolve = resolve;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return r_resolve;
|
||||||
|
}
|
||||||
|
|
||||||
|
private escapeCmd(cmd: string) {
|
||||||
|
// Double quote command (should work in at least cmd.exe and bash)
|
||||||
|
let cmdEsc = `"${cmd}"`;
|
||||||
|
|
||||||
|
// Fetch Windows shell type
|
||||||
|
let shell = vscode.workspace.getConfiguration("terminal.integrated.shell").get("windows", "");
|
||||||
|
|
||||||
|
// For powershell we prepend an & to prevent the command being treated as a string
|
||||||
|
if (shell.endsWith("powershell.exe") && process.platform === "win32") {
|
||||||
|
cmdEsc = `&${cmdEsc}`;
|
||||||
|
}
|
||||||
|
return cmdEsc
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ToolManager;
|
export default ToolManager;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
import {Disposable, window} from 'vscode';
|
import {Disposable, window} from 'vscode';
|
||||||
import GDScriptDiagnosticSeverity from './gdscript/diagnostic';
|
import GDScriptDiagnosticSeverity from './gdscript/diagnostic';
|
||||||
import GDScriptCompleter from './gdscript/completion';
|
import GDScriptCompleter from './gdscript/completion';
|
||||||
@@ -40,7 +41,9 @@ class WindowWatcher {
|
|||||||
if(window.activeTextEditor != undefined) {
|
if(window.activeTextEditor != undefined) {
|
||||||
const doc = window.activeTextEditor.document;
|
const doc = window.activeTextEditor.document;
|
||||||
const script = config.loadSymbolsFromFile(doc.fileName);
|
const script = config.loadSymbolsFromFile(doc.fileName);
|
||||||
this._diagnosticSeverity.validateScript(doc, script).then(()=>{});
|
if (vscode.workspace.getConfiguration("GodotTools").get("enableSyntaxChecking", true)) {
|
||||||
|
this._diagnosticSeverity.validateScript(doc, script).then(()=>{});
|
||||||
|
}
|
||||||
this._lastText = {path: doc.fileName, version: doc.version};
|
this._lastText = {path: doc.fileName, version: doc.version};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -55,7 +58,9 @@ class WindowWatcher {
|
|||||||
// Check content changed
|
// Check content changed
|
||||||
if(this._lastText.path != curText.path || this._lastText.version != curText.version) {
|
if(this._lastText.path != curText.path || this._lastText.version != curText.version) {
|
||||||
const script = config.loadSymbolsFromFile(doc.fileName);
|
const script = config.loadSymbolsFromFile(doc.fileName);
|
||||||
this._diagnosticSeverity.validateScript(doc, script).then(()=>{});
|
if (vscode.workspace.getConfiguration("GodotTools").get("enableSyntaxChecking", true)) {
|
||||||
|
this._diagnosticSeverity.validateScript(doc, script).then(()=>{});
|
||||||
|
}
|
||||||
this._lastText = curText;
|
this._lastText = curText;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user