mirror of
https://github.com/godotengine/godot-vscode-plugin.git
synced 2026-01-04 10:09:58 +03:00
Compare commits
98 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 | ||
|
|
1248d8e25a | ||
|
|
ae0830638b | ||
|
|
bab6fed5cf | ||
|
|
27d7501672 | ||
|
|
4dff47d97b | ||
|
|
7a8f00422b | ||
|
|
447af0183f | ||
|
|
1cb8a5724d | ||
|
|
0a9a0117f0 | ||
|
|
d8b9dee510 | ||
|
|
0f31c66c5a | ||
|
|
638a5362e6 | ||
|
|
4f0550ce86 | ||
|
|
bc96a9462b | ||
|
|
749148841d | ||
|
|
2384004ef9 | ||
|
|
927297ad03 | ||
|
|
5b1bee0c68 | ||
|
|
7f5b244113 | ||
|
|
670f46014b | ||
|
|
203e32c3ed | ||
|
|
b7dbbcc589 | ||
|
|
ec7e1013aa | ||
|
|
4b3282cf03 | ||
|
|
58203708ba | ||
|
|
57b6f1ad01 | ||
|
|
921977fbdb | ||
|
|
0618034ace | ||
|
|
2fb1e333b1 | ||
|
|
07740b5c97 | ||
|
|
b08c61ac8d | ||
|
|
f36169d685 | ||
|
|
0be4aef2bd | ||
|
|
32b3449bf2 | ||
|
|
a45a5e27fa | ||
|
|
dda701026c | ||
|
|
90457a0df6 | ||
|
|
b2c5d69692 | ||
|
|
43e31f04cb | ||
|
|
4a1e59697a | ||
|
|
911f5c8d1c | ||
|
|
4918a938b7 | ||
|
|
eac1bbd042 | ||
|
|
d97c586327 | ||
|
|
3c547cc595 | ||
|
|
25afaedfb3 | ||
|
|
39c642ae82 | ||
|
|
55b16c3824 | ||
|
|
86ccb8318f | ||
|
|
2834c2b19c | ||
|
|
71e431a5ec | ||
|
|
65cb8c2deb | ||
|
|
cf5faf2152 | ||
|
|
0f7d4902fd | ||
|
|
f40f091421 | ||
|
|
e21de33ffc | ||
|
|
2d8df590b4 | ||
|
|
590f9e51e7 | ||
|
|
519add7029 | ||
|
|
236adcab1c | ||
|
|
77dcdf5a5b | ||
|
|
82f4765bcc | ||
|
|
91c6acb1fd | ||
|
|
c657fc16de |
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
|
||||||
|
|||||||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -10,7 +10,7 @@
|
|||||||
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
|
"args": ["--extensionDevelopmentPath=${workspaceRoot}" ],
|
||||||
"stopOnEntry": false,
|
"stopOnEntry": false,
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
"outFiles": ["${workspaceRoot}/out/src"],
|
"outFiles": ["${workspaceRoot}/out/src/**/*.js"],
|
||||||
"preLaunchTask": "npm"
|
"preLaunchTask": "npm"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
114
CHANGELOG.md
114
CHANGELOG.md
@@ -1,5 +1,119 @@
|
|||||||
# 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
|
||||||
|
* 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.
|
||||||
|
|
||||||
|
### 0.3.0
|
||||||
|
* Add project root configuration settings as `GodotTools.godotProjectRoot` thanks Konstantin Zaitcev
|
||||||
|
* Add auto indent support for gdscript language
|
||||||
|
* More friendly with godot 3.0 alpha
|
||||||
|
* Updated script snippets
|
||||||
|
* Fix highglight error with gdscript language
|
||||||
|
* Limited code completions
|
||||||
|
|
||||||
|
### 0.2.9
|
||||||
|
* Add configuration `GodotTools.completeNodePath` to switch is complete node pathes
|
||||||
|
* Enhanced syntax highlight with GDScript
|
||||||
|
* Enhanced code completion with GDScript
|
||||||
|
|
||||||
|
### 0.2.8
|
||||||
|
* Add godot 3.0 project support with configuration `GodotTools.parseTextScene` >= 3
|
||||||
|
* Add configuration `GodotTools.parseTextScene` to allow disable node path parsing
|
||||||
|
* Remove `GodotTools.editorServerPort` configuration
|
||||||
|
|
||||||
|
### 0.2.7
|
||||||
|
|
||||||
|
* Fix some error with syntax checking
|
||||||
|
* Add symbol support for enumerations
|
||||||
|
* Remove key bindings for `F5`~`F8` as it might be confict with other functionalities of VSCode
|
||||||
|
* You can bind the key bindings back by add following configurations
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"command": "godot.runWorkspace",
|
||||||
|
"key": "F5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "godot.runCurrentScene",
|
||||||
|
"key": "F6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "godot.openWithEditor",
|
||||||
|
"key": "F7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "godot.updateWorkspaceSymbols",
|
||||||
|
"key": "F8"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
For more references please ready [keybindings](https://code.visualstudio.com/docs/getstarted/keybindings)
|
||||||
|
|
||||||
|
### 0.2.6
|
||||||
|
|
||||||
|
* Add shorthand if else expression support
|
||||||
|
* Add `enum` and `match` expression support
|
||||||
|
* Fix bugs with syntax checking
|
||||||
|
* Updated documentation data with godot 2.1.3
|
||||||
|
* Add syntax checking for end of expression
|
||||||
|
* The pulugin is compiled with latest VSCode thanks @arrkiin
|
||||||
|
* Add key bindings for open workspace with godot editor with `F7` and update workspace symbols with `F8`
|
||||||
|
|
||||||
|
### 0.2.5
|
||||||
|
|
||||||
|
* Run games within VSCode terminals
|
||||||
|
* Add key bindings for `F5 to run the workspace` and `F6 to run the edting scene`
|
||||||
|
* Fix a lot of bugs with unused vaiable cheching
|
||||||
|
* Move workspace symbols state notice to status bar
|
||||||
|
|
||||||
|
### 0.2.4
|
||||||
|
|
||||||
|
* Add code cheching for asignments and comparations
|
||||||
|
* Impoved builtin documentation preview page
|
||||||
|
* Fix bugs with unused vaiable cheching
|
||||||
|
|
||||||
### 0.2.3
|
### 0.2.3
|
||||||
* Fix known errors with code syntax checking
|
* Fix known errors with code syntax checking
|
||||||
* Add configuration `ignoreIndentedVars` to allow ignore indented variables in scripts
|
* Add configuration `ignoreIndentedVars` to allow ignore indented variables in scripts
|
||||||
|
|||||||
97
README.md
97
README.md
@@ -2,78 +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
|
||||||
- Run/debug the godot game with VSCode with F5(coming soon)
|
- 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
|
||||||
|
|
||||||
You can use the following settings to setup the Godot Tools:
|
### Godot
|
||||||
|
|
||||||
- GodotTools.editorServerPort: The http server port used by the EditorServer Godot module (_see Extra Functionality below_)
|
If you like this extension, you can set VS Code as your default script editor for Godot by following these steps:
|
||||||
- GodotTools.maxNumberOfProblems: Sets the limit for the issues reported by the static code validator
|
1. Open editor settings
|
||||||
- GodotTools.editorPath: An absolute path pointing at the Godot Editor executable file. Required to run the project and test scenes from VScode
|
2. Select `Text Editor / External`
|
||||||
- GodotTools.workspaceDocumentWithMarkdown: Control the documentations of workspace symbols should be rendered as plain text or html from markdown
|
3. Make sure the `Use External Editor` box is checked
|
||||||
- GodotTools.ignoreIndentedVars: Parse variables defined after indent of not
|
4. Fill `Exec Path` with the path to your VS Code executable
|
||||||
|
5. Fill `Exec Flags` with `{project} --goto {file}:{line}:{col}`
|
||||||
|
|
||||||
## Extra functionality
|
### VS Code
|
||||||
|
|
||||||
If you want to get an even better experience with this plug-in, you can extend its functionality using the following modules and VScode extensions:
|
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`.
|
||||||
|
|
||||||
### Godot modules
|
## Issues and Contributions
|
||||||
|
|
||||||
These are modules for the goats editor itself, programmed in C++. In order to use them, you have to create a [custom build](http://docs.godotengine.org/en/stable/reference/compiling_for_windows.html) of the engine. Only do that if you know what you're doing.
|
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.
|
||||||
|
|
||||||
- [EditorServer](https://github.com/GodotExplorer/editor-server/tree/master/editor_server): Using HTTP requests, this module gets extra information from Godot to improve autocompletion.
|
See the [full changelog](https://github.com/GodotExplorer/godot-tools/blob/master/CHANGELOG.md) for the latest changes.
|
||||||
- [VSCode](https://github.com/GodotExplorer/editor-server/tree/master/vscode_tools): The VS code module generates a setting file that Visual Studio code can use to generate Tasks automatically.
|
|
||||||
|
|
||||||
### VScode extensions
|
## FAQ
|
||||||
|
|
||||||
|
### Why isn't Intellisense showing up for me?
|
||||||
|
|
||||||
- [TOML language](https://marketplace.visualstudio.com/items?itemName=be5invis.toml): Godot uses this minimal language to store settings. For example in your project config file. If you want to get syntax highlighting for these files, you will have to install the TOML language extension.
|
Make sure you save your `.gd` file, then run "GodotTools: Update Workspace Symbols" from the Command Palette.
|
||||||
|
|
||||||
## Issues and contributions
|
## TODO:
|
||||||
|
* Convert official BBCode documentation into Markdown and render it into HTML with documentation previewer pages
|
||||||
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.
|
* Add mermaid support with documentation
|
||||||
|
* Undefined variable checking
|
||||||
## Release Notes
|
|
||||||
|
|
||||||
### 0.2.3
|
|
||||||
* Fix known errors with code syntax checking
|
|
||||||
* Add configuration `GodotTools.ignoreIndentedVars` to allow ignore indented variables in scripts
|
|
||||||
* Enhanced hover tip documentation rendering with code examples
|
|
||||||
* Add launch configurations to launch game with F5(expiremental)
|
|
||||||
* The plugin is open source under MIT license
|
|
||||||
|
|
||||||
### 0.2.2
|
|
||||||
* Better Syntax validating for code blocks
|
|
||||||
* More waring for non-python liked expression
|
|
||||||
|
|
||||||
### 0.2.1
|
|
||||||
* Support markdown render in hover tips for documentations in workspace symbols
|
|
||||||
* Add configuration `GodotTools.workspaceDocumentWithMarkdown` to control workspace documentation rendering
|
|
||||||
|
|
||||||
[Read more from the full change log](https://github.com/GodotExplorer/godot-tools/blob/master/CHANGELOG.md)
|
|
||||||
|
|
||||||
|
|
||||||
## TODOS:
|
|
||||||
* Print game output log into VSCode console while game launched from the plugin
|
|
||||||
* Convert official BBCode documentation into Markdown and render it to HTML with documentation previewer pages
|
|
||||||
* Add mermaid support with documentation
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
"name": "comment.line.number-sign.gdscript"
|
"name": "comment.line.number-sign.gdscript"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"match": "\\b(?i:elif|else|for|if|while|break|continue|pass|and|in|is|not|or|return|onready|setget|breakpoint)\\b",
|
"match": "\\b(?i:elif|else|for|if|while|break|continue|pass|and|in|is|not|or|return|onready|setget|enum|match|breakpoint)\\b",
|
||||||
"name": "keyword.control.gdscript"
|
"name": "keyword.control.gdscript"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -21,5 +21,9 @@
|
|||||||
["(", ")"],
|
["(", ")"],
|
||||||
["[", "]"],
|
["[", "]"],
|
||||||
["{", "}"]
|
["{", "}"]
|
||||||
]
|
],
|
||||||
}
|
"indentationRules": {
|
||||||
|
"increaseIndentPattern": "^\\s*((class|func|else|elif|for|if|match|while|enum)|(.*\\sdo\\b))\\b[^\\{;]*$",
|
||||||
|
"decreaseIndentPattern": "^\\s*([}\\]]([,)]?\\s*(#|$)|\\.[a-zA-Z_]\\w*\\b)|(else|elif)\\b)"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
// description. The prefix is what is used to trigger the snippet and the body will be expanded and inserted. Possible variables are:
|
||||||
// $1, $2 for tab stops, ${id} and ${id:label} and ${1:label} for variables. Variables with the same id are connected.
|
// $1, $2 for tab stops, ${id} and ${id:label} and ${1:label} for variables. Variables with the same id are connected.
|
||||||
// Example:
|
// Example:
|
||||||
"Subclass": {
|
"Inner class": {
|
||||||
"prefix": "class",
|
"prefix": "class",
|
||||||
"body": [
|
"body": [
|
||||||
"class $1 extends ${2:Reference}",
|
"class $1 extends ${2:Reference}",
|
||||||
@@ -57,7 +57,23 @@
|
|||||||
"func _input_event(event):",
|
"func _input_event(event):",
|
||||||
"\t${1:pass}"
|
"\t${1:pass}"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"_draw method of Node": {
|
||||||
|
"prefix": "draw",
|
||||||
|
"body": [
|
||||||
|
"func _draw():",
|
||||||
|
"\t${1:pass}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"_gui_input method of Node": {
|
||||||
|
"prefix": "guii",
|
||||||
|
"body": [
|
||||||
|
"func _gui_input(event):",
|
||||||
|
"\t${1:pass}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
"for loop": {
|
"for loop": {
|
||||||
"prefix": "for",
|
"prefix": "for",
|
||||||
@@ -145,7 +161,7 @@
|
|||||||
"define onready variables": {
|
"define onready variables": {
|
||||||
"prefix": "onready",
|
"prefix": "onready",
|
||||||
"body": [
|
"body": [
|
||||||
"onready var ${1:name}${2: = default}${3: setget }"
|
"onready var ${1:name} = get_node($2)"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -156,6 +172,13 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"Is instance of a class or script": {
|
||||||
|
"prefix": "is",
|
||||||
|
"body": [
|
||||||
|
"${1:instance} is ${2:class}"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
"element in array": {
|
"element in array": {
|
||||||
"prefix": "in",
|
"prefix": "in",
|
||||||
"body": [
|
"body": [
|
||||||
@@ -192,5 +215,11 @@
|
|||||||
"body": [
|
"body": [
|
||||||
"set_process_input(true)"
|
"set_process_input(true)"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"pass statement": {
|
||||||
|
"prefix": "pass",
|
||||||
|
"body": [
|
||||||
|
"pass"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
2
doc/.gitignore
vendored
Normal file
2
doc/.gitignore
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
classes/*.xml
|
||||||
|
classes-*.xml
|
||||||
83763
doc/classes-2.1.json
Normal file
83763
doc/classes-2.1.json
Normal file
File diff suppressed because it is too large
Load Diff
90257
doc/classes-3.0.json
Normal file
90257
doc/classes-3.0.json
Normal file
File diff suppressed because it is too large
Load Diff
66075
doc/classes.json
66075
doc/classes.json
File diff suppressed because it is too large
Load Diff
66
doc/xmldoc2json-2.1.py
Executable file
66
doc/xmldoc2json-2.1.py
Executable file
@@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import json
|
||||||
|
|
||||||
|
def parseClass(data):
|
||||||
|
dictCls = dict(data.attrib)
|
||||||
|
dictCls['brief_description'] = data.find("brief_description").text.strip()
|
||||||
|
dictCls['description'] = data.find("description").text.strip()
|
||||||
|
dictCls['methods'] = []
|
||||||
|
for m in data.find("methods"):
|
||||||
|
dictCls['methods'].append(parseMethod(m))
|
||||||
|
dictCls['signals'] = []
|
||||||
|
for s in (data.find("signals") if data.find("signals") is not None else []):
|
||||||
|
dictCls['signals'].append(parseMethod(s))
|
||||||
|
dictCls['constants'] = []
|
||||||
|
for c in (data.find("constants") if data.find("constants") is not None else []):
|
||||||
|
dictCls['constants'].append(parseConstant(c))
|
||||||
|
dictCls['properties'] = []
|
||||||
|
for m in (data.find("members") if data.find("members") is not None else []):
|
||||||
|
dictCls['properties'].append(parseProperty(m))
|
||||||
|
dictCls['theme_properties'] = []
|
||||||
|
for thi in (data.find("theme_items") if data.find("theme_items") is not None else []):
|
||||||
|
dictCls['theme_properties'].append(parseProperty(thi))
|
||||||
|
return dictCls
|
||||||
|
|
||||||
|
def parseMethod(data):
|
||||||
|
dictMethod = dict(data.attrib)
|
||||||
|
dictMethod['description'] = data.find("description").text.strip()
|
||||||
|
dictMethod['return_type'] = data.find("return").attrib["type"] if data.find("return") is not None else ""
|
||||||
|
if "qualifiers" not in dictMethod: dictMethod["qualifiers"] = ""
|
||||||
|
dictMethod["arguments"] = []
|
||||||
|
for arg in data.iter('argument'):
|
||||||
|
dictMethod["arguments"].append(parseArgument(arg))
|
||||||
|
return dictMethod
|
||||||
|
|
||||||
|
def parseArgument(data):
|
||||||
|
dictArg = dict(data.attrib)
|
||||||
|
if "dictArg" in dictArg: dictArg.pop("index")
|
||||||
|
dictArg["default_value"] = dictArg["default"] if "default" in dictArg else ""
|
||||||
|
if "default" in dictArg: dictArg.pop("default")
|
||||||
|
return dictArg
|
||||||
|
|
||||||
|
def parseConstant(data):
|
||||||
|
dictConst = dict(data.attrib)
|
||||||
|
dictConst["description"] = data.text.strip()
|
||||||
|
return dictConst
|
||||||
|
|
||||||
|
def parseProperty(data):
|
||||||
|
dictProp = dict(data.attrib)
|
||||||
|
dictProp["description"] = data.text.strip()
|
||||||
|
return dictProp
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) >=2 :
|
||||||
|
tree = ET.parse(open(sys.argv[1], 'r'))
|
||||||
|
classes = {}
|
||||||
|
for cls in tree.getroot():
|
||||||
|
dictCls = parseClass(cls)
|
||||||
|
classes[dictCls['name']] = dictCls
|
||||||
|
jsonContent = json.dumps({"classes": classes, "version": "2.1.4"}, ensure_ascii=False, indent=2)
|
||||||
|
print(jsonContent)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
80
doc/xmldoc2json-3.0.py
Executable file
80
doc/xmldoc2json-3.0.py
Executable file
@@ -0,0 +1,80 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
import sys
|
||||||
|
import xml.etree.ElementTree as ET
|
||||||
|
import json
|
||||||
|
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):
|
||||||
|
dictCls = dict(data.attrib)
|
||||||
|
dictCls['brief_description'] = data.find("brief_description").text.strip()
|
||||||
|
dictCls['description'] = data.find("description").text.strip()
|
||||||
|
dictCls['methods'] = []
|
||||||
|
for m in data.find("methods"):
|
||||||
|
dictCls['methods'].append(parseMethod(m))
|
||||||
|
dictCls['signals'] = []
|
||||||
|
for s in (data.find("signals") if data.find("signals") is not None else []):
|
||||||
|
dictCls['signals'].append(parseMethod(s))
|
||||||
|
dictCls['constants'] = []
|
||||||
|
for c in (data.find("constants") if data.find("constants") is not None else []):
|
||||||
|
dictCls['constants'].append(parseConstant(c))
|
||||||
|
dictCls['properties'] = []
|
||||||
|
for m in (data.find("members") if data.find("members") is not None else []):
|
||||||
|
dictCls['properties'].append(parseProperty(m))
|
||||||
|
dictCls['theme_properties'] = []
|
||||||
|
for thi in (data.find("theme_items") if data.find("theme_items") is not None else []):
|
||||||
|
dictCls['theme_properties'].append(parseProperty(thi))
|
||||||
|
return dictCls
|
||||||
|
|
||||||
|
def parseMethod(data):
|
||||||
|
dictMethod = dict(data.attrib)
|
||||||
|
dictMethod['description'] = data.find("description").text.strip()
|
||||||
|
dictMethod['return_type'] = data.find("return").attrib["type"] if data.find("return") is not None else ""
|
||||||
|
if "qualifiers" not in dictMethod: dictMethod["qualifiers"] = ""
|
||||||
|
dictMethod["arguments"] = []
|
||||||
|
for arg in data.iter('argument'):
|
||||||
|
dictMethod["arguments"].append(parseArgument(arg))
|
||||||
|
return dictMethod
|
||||||
|
|
||||||
|
def parseArgument(data):
|
||||||
|
dictArg = dict(data.attrib)
|
||||||
|
if "dictArg" in dictArg: dictArg.pop("index")
|
||||||
|
dictArg["default_value"] = dictArg["default"] if "default" in dictArg else ""
|
||||||
|
if "default" in dictArg: dictArg.pop("default")
|
||||||
|
return dictArg
|
||||||
|
|
||||||
|
def parseConstant(data):
|
||||||
|
dictConst = dict(data.attrib)
|
||||||
|
dictConst["description"] = data.text.strip()
|
||||||
|
return dictConst
|
||||||
|
|
||||||
|
def parseProperty(data):
|
||||||
|
dictProp = dict(data.attrib)
|
||||||
|
dictProp["description"] = data.text.strip()
|
||||||
|
return dictProp
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) >=2 :
|
||||||
|
if os.path.isdir(sys.argv[1]):
|
||||||
|
classes = {}
|
||||||
|
for f in glob_path(sys.argv[1], "**.xml"):
|
||||||
|
if f.find("/classes/") == -1 and f.find("/doc_classes/") == -1:
|
||||||
|
continue
|
||||||
|
tree = ET.parse(open(f, 'r'))
|
||||||
|
cls = tree.getroot()
|
||||||
|
dictCls = parseClass(cls)
|
||||||
|
classes[dictCls['name']] = dictCls
|
||||||
|
jsonContent = json.dumps({"classes": classes, "version": "3.0.4"}, ensure_ascii=False, indent=2)
|
||||||
|
print(jsonContent)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
BIN
icon.png
BIN
icon.png
Binary file not shown.
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 4.6 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 23 KiB |
BIN
img/godot-tools.jpg
Normal file
BIN
img/godot-tools.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 194 KiB |
2236
package-lock.json
generated
Normal file
2236
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
147
package.json
147
package.json
@@ -2,35 +2,36 @@
|
|||||||
"name": "godot-tools",
|
"name": "godot-tools",
|
||||||
"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.2.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.5.0"
|
"vscode": "^1.1.21"
|
||||||
},
|
},
|
||||||
"categories": [
|
"categories": [
|
||||||
"Other"
|
"Other"
|
||||||
],
|
],
|
||||||
"activationEvents": [
|
"activationEvents": [
|
||||||
"workspaceContains:engine.cfg",
|
"workspaceContains:engine.cfg",
|
||||||
|
"workspaceContains:project.godot",
|
||||||
"onLanguage:gdscript"
|
"onLanguage:gdscript"
|
||||||
],
|
],
|
||||||
"main": "./out/src/extension",
|
"main": "./out/src/extension",
|
||||||
"contributes": {
|
"contributes": {
|
||||||
"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",
|
||||||
@@ -39,13 +40,8 @@
|
|||||||
],
|
],
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"title": "Godot tools configuration",
|
"title": "Godot Tools configuration",
|
||||||
"properties": {
|
"properties": {
|
||||||
"GodotTools.editorServerPort": {
|
|
||||||
"type": "number",
|
|
||||||
"default": 6996,
|
|
||||||
"description": "The server port of your EditorServer"
|
|
||||||
},
|
|
||||||
"GodotTools.maxNumberOfProblems": {
|
"GodotTools.maxNumberOfProblems": {
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"default": 100,
|
"default": 100,
|
||||||
@@ -54,17 +50,51 @@
|
|||||||
"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",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Only parse variables without indents in GDScript"
|
"description": "Only parse variables without indents in GDScript"
|
||||||
|
},
|
||||||
|
"GodotTools.godotVersion": {
|
||||||
|
"type": "number",
|
||||||
|
"default": 3.0,
|
||||||
|
"description": "The Godot version of your project"
|
||||||
|
},
|
||||||
|
"GodotTools.parseTextScene": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "Parse a file as a Godot scene when the file name ends with tscn"
|
||||||
|
},
|
||||||
|
"GodotTools.completeNodePath": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "Show node paths within a workspace as part of code completion"
|
||||||
|
},
|
||||||
|
"GodotTools.godotProjectRoot": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "${workspaceRoot}",
|
||||||
|
"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"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -72,13 +102,24 @@
|
|||||||
{
|
{
|
||||||
"id": "gdscript",
|
"id": "gdscript",
|
||||||
"aliases": [
|
"aliases": [
|
||||||
"Godot Engine Script",
|
"GDScript",
|
||||||
"gdscript"
|
"gdscript"
|
||||||
],
|
],
|
||||||
"extensions": [
|
"extensions": [
|
||||||
".gd"
|
".gd"
|
||||||
],
|
],
|
||||||
"configuration": "./configurations/gdscript-configuration.json"
|
"configuration": "./configurations/gdscript-configuration.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "properties",
|
||||||
|
"extensions": [
|
||||||
|
"cfg",
|
||||||
|
"tres",
|
||||||
|
"tscn",
|
||||||
|
"godot",
|
||||||
|
"gdns",
|
||||||
|
"gdnlib"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"grammars": [
|
"grammars": [
|
||||||
@@ -93,82 +134,24 @@
|
|||||||
"language": "gdscript",
|
"language": "gdscript",
|
||||||
"path": "./configurations/snippets.json"
|
"path": "./configurations/snippets.json"
|
||||||
}
|
}
|
||||||
],
|
]
|
||||||
"breakpoints": [
|
|
||||||
{
|
|
||||||
"language": "gdscript"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"debuggers": [
|
|
||||||
{
|
|
||||||
"type": "godot",
|
|
||||||
"label": "Godot Game",
|
|
||||||
"program": "./out/src/debug/godotDebugger.js",
|
|
||||||
"runtime": "node",
|
|
||||||
"configurationSnippets": [
|
|
||||||
{
|
|
||||||
"label": "Godot Game: Launch",
|
|
||||||
"description": "A new configuration for launching a godot game",
|
|
||||||
"body": {
|
|
||||||
"type": "godot",
|
|
||||||
"request": "launch",
|
|
||||||
"name": "Godot Game",
|
|
||||||
"godot": "${1:The abusolut path of your godot binary}",
|
|
||||||
"projectDir": "^\"\\${workspaceRoot}\"",
|
|
||||||
"params": [],
|
|
||||||
"runWithEditor": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
|
|
||||||
"configurationAttributes": {
|
|
||||||
"launch": {
|
|
||||||
"required": [ "godot", "runWithEditor", "projectDir" ],
|
|
||||||
"properties": {
|
|
||||||
"godot": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The dirctory of your godot project",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"runWithEditor": {
|
|
||||||
"type": "boolean",
|
|
||||||
"description": "Launch the game with godot editor.",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"projectDir": {
|
|
||||||
"type": "string",
|
|
||||||
"description": "The dirctory of your godot project",
|
|
||||||
"default": "${workspaceRoot}"
|
|
||||||
},
|
|
||||||
"params": {
|
|
||||||
"type": "array",
|
|
||||||
"description": "Addtional params passed to godot",
|
|
||||||
"default": []
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"initialConfigurations": "godot.provideInitialDebugConfigurations"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"vscode:prepublish": "tsc -p ./",
|
"vscode:prepublish": "tsc -p ./",
|
||||||
"compile": "tsc -watch -p ./",
|
"compile": "node ./node_modules/typescript/bin/tsc -p ./",
|
||||||
"postinstall": "node ./node_modules/vscode/bin/install",
|
"postinstall": "node ./node_modules/vscode/bin/install",
|
||||||
"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.0.0",
|
"@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",
|
||||||
"node-cmd": "1.2.0",
|
|
||||||
"vscode-debugprotocol": "^1.17.0",
|
"vscode-debugprotocol": "^1.17.0",
|
||||||
"vscode-debugadapter": "^1.17.0"
|
"vscode-debugadapter": "^1.17.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
189
src/config.ts
189
src/config.ts
@@ -9,10 +9,21 @@ interface NodeInfo {
|
|||||||
instance: string
|
instance: string
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface CompletionSymbols {
|
||||||
|
classes : CompletionItem[],
|
||||||
|
functions : CompletionItem[],
|
||||||
|
signals : CompletionItem[],
|
||||||
|
constants : CompletionItem[],
|
||||||
|
properties : CompletionItem[],
|
||||||
|
nodes : CompletionItem[],
|
||||||
|
builtinConstants: CompletionItem[]
|
||||||
|
};
|
||||||
|
|
||||||
class Config {
|
class Config {
|
||||||
private symbols;
|
|
||||||
private classes;
|
private workspaceSymbols; // filePath: GDScript in symbolparser.ts
|
||||||
public bintinSybmolInfoList: CompletionItem[];
|
private builtinCompletions : CompletionSymbols;
|
||||||
|
private builtinClassDoc;
|
||||||
public parser: GDScriptSymbolParser;
|
public parser: GDScriptSymbolParser;
|
||||||
// scriptpath : scenepath
|
// scriptpath : scenepath
|
||||||
public scriptSceneMap: Object;
|
public scriptSceneMap: Object;
|
||||||
@@ -22,8 +33,16 @@ class Config {
|
|||||||
public builtinSymbolInfoMap: Object;
|
public builtinSymbolInfoMap: Object;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.symbols = {};
|
this.builtinCompletions = {
|
||||||
this.bintinSybmolInfoList = [];
|
classes : [],
|
||||||
|
functions : [],
|
||||||
|
signals : [],
|
||||||
|
constants : [],
|
||||||
|
properties : [],
|
||||||
|
nodes : [],
|
||||||
|
builtinConstants: []
|
||||||
|
};
|
||||||
|
this.workspaceSymbols = {};
|
||||||
this.builtinSymbolInfoMap = {};
|
this.builtinSymbolInfoMap = {};
|
||||||
this.nodeInfoMap = {};
|
this.nodeInfoMap = {};
|
||||||
this.scriptSceneMap = {};
|
this.scriptSceneMap = {};
|
||||||
@@ -40,19 +59,19 @@ class Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSymbols(path, s) {
|
setSymbols(path, s) {
|
||||||
this.symbols[this.normalizePath(path)] = s;
|
this.workspaceSymbols[this.normalizePath(path)] = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
getSymbols(path) {
|
getSymbols(path) {
|
||||||
return this.symbols[this.normalizePath(path)];
|
return this.workspaceSymbols[this.normalizePath(path)];
|
||||||
}
|
}
|
||||||
|
|
||||||
setAllSymbols(s) {
|
setAllSymbols(s) {
|
||||||
this.symbols = s;
|
this.workspaceSymbols = s;
|
||||||
}
|
}
|
||||||
|
|
||||||
getAllSymbols() {
|
getAllSymbols() {
|
||||||
return this.symbols;
|
return this.workspaceSymbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
normalizePath(path) {
|
normalizePath(path) {
|
||||||
@@ -75,7 +94,7 @@ class Config {
|
|||||||
const content = fs.readFileSync(docfile, "utf-8");
|
const content = fs.readFileSync(docfile, "utf-8");
|
||||||
const docdata = JSON.parse(content);
|
const docdata = JSON.parse(content);
|
||||||
if(docdata.classes) {
|
if(docdata.classes) {
|
||||||
this.classes = docdata.classes;
|
this.builtinClassDoc = docdata.classes;
|
||||||
done = true;
|
done = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,18 +102,16 @@ class Config {
|
|||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
if(done) {
|
if(done) {
|
||||||
for (let key of Object.keys(this.classes)) {
|
for (let key of Object.keys(this.builtinClassDoc)) {
|
||||||
const classdoc = this.classes[key];
|
const classdoc = this.builtinClassDoc[key];
|
||||||
const bintinSybmolInfoList = this.bintinSybmolInfoList;
|
|
||||||
const builtinSymbolInfoMap = this.builtinSymbolInfoMap;
|
const builtinSymbolInfoMap = this.builtinSymbolInfoMap;
|
||||||
// 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;
|
||||||
bintinSybmolInfoList.push(item);
|
this.builtinCompletions.classes.push(item);
|
||||||
builtinSymbolInfoMap[classdoc.name] = {completionItem: item, rowDoc: classdoc};
|
builtinSymbolInfoMap[classdoc.name] = {completionItem: item, rowDoc: classdoc};
|
||||||
// methods
|
// ----------------------- functions -----------------------
|
||||||
const methods = classdoc.methods
|
|
||||||
const parsMethod = (m, kind: CompletionItemKind, insertAction=(name)=>name)=>{
|
const parsMethod = (m, kind: CompletionItemKind, insertAction=(name)=>name)=>{
|
||||||
const mi = new CompletionItem(m.name, kind);
|
const mi = new CompletionItem(m.name, kind);
|
||||||
mi.insertText = insertAction(m.name) + (m.arguments.length==0?"()":"");
|
mi.insertText = insertAction(m.name) + (m.arguments.length==0?"()":"");
|
||||||
@@ -103,38 +120,55 @@ class Config {
|
|||||||
mi.detail = m.return_type;
|
mi.detail = m.return_type;
|
||||||
let argstr = "";
|
let argstr = "";
|
||||||
m.arguments.map(arg=>{
|
m.arguments.map(arg=>{
|
||||||
argstr += `${arg.type} ${arg.name}${arg.default_value.length>0?'='+arg.default_value.length:''}${m.arguments.indexOf(arg)==m.arguments.length-1?'':', '}`;
|
argstr += `${arg.type} ${arg.name}${arg.default_value.length>0?'='+arg.default_value:''}${m.arguments.indexOf(arg)==m.arguments.length-1?'':', '}`;
|
||||||
});
|
});
|
||||||
// mi.label=`${m.name}(${argstr}) ${m.qualifiers}`;
|
// mi.label=`${m.name}(${argstr}) ${m.qualifiers}`;
|
||||||
let mdoc = `${m.return_type} ${classdoc.name}.${m.name}(${argstr}) ${m.qualifiers}`;
|
let methodName = `${classdoc.name}.${m.name}`;
|
||||||
|
if (classdoc.name == m.name) methodName = m.name;
|
||||||
|
let mdoc = `${m.return_type} ${methodName}(${argstr}) ${m.qualifiers}`;
|
||||||
mdoc += " \n\n";
|
mdoc += " \n\n";
|
||||||
mdoc += m.description;
|
mdoc += m.description;
|
||||||
mi.documentation = mdoc;
|
mi.documentation = mdoc;
|
||||||
bintinSybmolInfoList.push(mi);
|
if(CompletionItemKind.Interface == kind)
|
||||||
|
this.builtinCompletions.signals.push(mi);
|
||||||
|
else
|
||||||
|
this.builtinCompletions.functions.push(mi);
|
||||||
builtinSymbolInfoMap[`${classdoc.name}.${m.name}`] = {completionItem: mi, rowDoc: m};
|
builtinSymbolInfoMap[`${classdoc.name}.${m.name}`] = {completionItem: mi, rowDoc: m};
|
||||||
};
|
};
|
||||||
|
// methods
|
||||||
|
const methods = classdoc.methods
|
||||||
methods.map(m=>parsMethod(m, CompletionItemKind.Method));
|
methods.map(m=>parsMethod(m, CompletionItemKind.Method));
|
||||||
// signals
|
// signals
|
||||||
const signals = classdoc.signals;
|
const signals = classdoc.signals;
|
||||||
signals.map(s=>parsMethod(s, CompletionItemKind.Interface));
|
signals.map(s=>parsMethod(s, CompletionItemKind.Interface));
|
||||||
// constants
|
// ------------------------------ constants ---------------------
|
||||||
const constants = classdoc.constants;
|
const constants = classdoc.constants;
|
||||||
constants.map(c=>{
|
constants.map(c=>{
|
||||||
const ci = new CompletionItem(c.name, CompletionItemKind.Enum);
|
const ci = new CompletionItem(c.name, CompletionItemKind.Enum);
|
||||||
ci.detail = c.value;
|
ci.detail = c.value;
|
||||||
ci.documentation = `${classdoc.name}.${c.name} = ${c.value}`;
|
ci.documentation = `${classdoc.name}.${c.name} = ${c.value}`;
|
||||||
bintinSybmolInfoList.push(ci);
|
if(key[0] == "@" || key == "Node" || key == "Control")
|
||||||
|
this.builtinCompletions.builtinConstants.push(ci);
|
||||||
|
else
|
||||||
|
this.builtinCompletions.constants.push(ci);
|
||||||
builtinSymbolInfoMap[`${classdoc.name}.${c.name}`] = {completionItem: ci, rowDoc: c};
|
builtinSymbolInfoMap[`${classdoc.name}.${c.name}`] = {completionItem: ci, rowDoc: c};
|
||||||
});
|
});
|
||||||
// properties
|
// ----------------------- properties -----------------------
|
||||||
const properties = classdoc.properties;
|
const parseProp = (p) => {
|
||||||
const parseProp = (p)=>{
|
|
||||||
const pi = new CompletionItem(p.name, CompletionItemKind.Property);
|
const pi = new CompletionItem(p.name, CompletionItemKind.Property);
|
||||||
pi.detail = `${p.type} of ${classdoc.name}`;
|
pi.detail = `${p.type} of ${classdoc.name}`;
|
||||||
pi.documentation = p.description;
|
pi.documentation = p.description;
|
||||||
bintinSybmolInfoList.push(pi);
|
this
|
||||||
builtinSymbolInfoMap[`${classdoc.name}.${p.name}`] = {completionItem: pi, rowDoc: p};
|
.builtinCompletions
|
||||||
|
.properties
|
||||||
|
.push(pi);
|
||||||
|
builtinSymbolInfoMap[`${classdoc.name}.${p.name}`] = {
|
||||||
|
completionItem: pi,
|
||||||
|
rowDoc: p
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
// properties
|
||||||
|
const properties = classdoc.properties;
|
||||||
properties.map(p=>parseProp(p));
|
properties.map(p=>parseProp(p));
|
||||||
// theme_properties
|
// theme_properties
|
||||||
const theme_properties = classdoc.theme_properties;
|
const theme_properties = classdoc.theme_properties;
|
||||||
@@ -144,10 +178,25 @@ class Config {
|
|||||||
return done;
|
return done;
|
||||||
};
|
};
|
||||||
|
|
||||||
getWorkspaceCompletionItems(): CompletionItem[] {
|
getWorkspaceCompletionItems(script_files = []) : CompletionSymbols {
|
||||||
let items: CompletionItem[] = [];
|
const symbols = {
|
||||||
for (let path of Object.keys(this.symbols)) {
|
classes: [],
|
||||||
const script = this.symbols[path];
|
functions: [],
|
||||||
|
signals: [],
|
||||||
|
constants: [],
|
||||||
|
properties: [],
|
||||||
|
nodes: [],
|
||||||
|
builtinConstants: []
|
||||||
|
};
|
||||||
|
if (script_files.length == 0)
|
||||||
|
script_files = Object.keys(this.workspaceSymbols);
|
||||||
|
for (let path of script_files) {
|
||||||
|
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)) {
|
||||||
@@ -159,41 +208,47 @@ 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;
|
||||||
}
|
}
|
||||||
items = [...items, ...addScriptItems(script.classes, CompletionItemKind.Class, "Class")];
|
|
||||||
items = [...items, ...addScriptItems(script.functions, CompletionItemKind.Method, "Method")];
|
symbols.classes = [ ...(symbols.classes), ...(addScriptItems(script.classes, CompletionItemKind.Class, "Class"))]
|
||||||
items = [...items, ...addScriptItems(script.variables, CompletionItemKind.Variable, "Variable")];
|
symbols.functions = [ ...(symbols.functions), ...(addScriptItems(script.functions, CompletionItemKind.Method, "Method"))]
|
||||||
items = [...items, ...addScriptItems(script.signals, CompletionItemKind.Interface, "Signal")];
|
symbols.signals = [ ...(symbols.signals), ...(addScriptItems(script.signals, CompletionItemKind.Interface, "Signal"))]
|
||||||
items = [...items, ...addScriptItems(script.constants, CompletionItemKind.Enum, "Constant")];
|
symbols.properties = [ ...(symbols.properties), ...(addScriptItems(script.variables, CompletionItemKind.Variable, "Variable"))]
|
||||||
|
symbols.constants = [ ...(symbols.constants), ...(addScriptItems(script.constants, CompletionItemKind.Enum, "Constant"))]
|
||||||
|
|
||||||
|
if(script.enumerations)
|
||||||
|
symbols.constants = [...(symbols.constants), ...(addScriptItems(script.enumerations, CompletionItemKind.Enum, "Enumeration"))];
|
||||||
|
}
|
||||||
|
|
||||||
|
if(workspace.getConfiguration("GodotTools").get("completeNodePath", false)) {
|
||||||
|
const addSceneNodes = ()=>{
|
||||||
|
const _items: CompletionItem[] = [];
|
||||||
|
for (let scnenepath of Object.keys(this.nodeInfoMap)) {
|
||||||
|
const nodes: NodeInfo[] = this.nodeInfoMap[scnenepath];
|
||||||
|
nodes.map((n=>{
|
||||||
|
const item = new CompletionItem(n.name, CompletionItemKind.Reference);
|
||||||
|
item.detail = n.type;
|
||||||
|
item.documentation = `${n.parent}/${n.name} in ${scnenepath}`;
|
||||||
|
_items.push(item);
|
||||||
|
|
||||||
|
const fullitem = new CompletionItem(`${n.parent}/${n.name}`, CompletionItemKind.Reference);
|
||||||
|
fullitem.detail = n.type;
|
||||||
|
fullitem.filterText = n.name;
|
||||||
|
fullitem.sortText = n.name;
|
||||||
|
fullitem.documentation = `${n.parent}/${n.name} in ${scnenepath}`;
|
||||||
|
_items.push(fullitem);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return _items;
|
||||||
|
};
|
||||||
|
symbols.nodes = [...(symbols.nodes), ...(addSceneNodes())];
|
||||||
}
|
}
|
||||||
|
|
||||||
const addSceneNodes = ()=>{
|
return symbols;
|
||||||
const _items: CompletionItem[] = [];
|
|
||||||
for (let scnenepath of Object.keys(this.nodeInfoMap)) {
|
|
||||||
const nodes: NodeInfo[] = this.nodeInfoMap[scnenepath];
|
|
||||||
nodes.map((n=>{
|
|
||||||
const item = new CompletionItem(n.name, CompletionItemKind.Reference);
|
|
||||||
item.detail = n.type;
|
|
||||||
item.documentation = `${n.parent}/${n.name} in ${scnenepath}`;
|
|
||||||
_items.push(item);
|
|
||||||
|
|
||||||
const fullitem = new CompletionItem(`${n.parent}/${n.name}`, CompletionItemKind.Reference);
|
|
||||||
fullitem.detail = n.type;
|
|
||||||
fullitem.filterText = n.name;
|
|
||||||
fullitem.sortText = n.name;
|
|
||||||
fullitem.documentation = `${n.parent}/${n.name} in ${scnenepath}`;
|
|
||||||
_items.push(fullitem);
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
return _items;
|
|
||||||
};
|
|
||||||
items = [...items, ...addSceneNodes()];
|
|
||||||
|
|
||||||
return items;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadScene(scenePath: string) {
|
loadScene(scenePath: string) {
|
||||||
@@ -255,13 +310,17 @@ class Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getClass(name: string) {
|
getClass(name: string) {
|
||||||
return this.classes[name];
|
return this.builtinClassDoc[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
getBuiltinCompletions() {
|
||||||
|
return this.builtinCompletions;
|
||||||
}
|
}
|
||||||
|
|
||||||
getBuiltinClassNameList() {
|
getBuiltinClassNameList() {
|
||||||
let namelist = null;
|
let namelist = null;
|
||||||
if(this.classes)
|
if (this.builtinClassDoc)
|
||||||
namelist = Object.keys(this.classes);
|
namelist = Object.keys(this.builtinClassDoc);
|
||||||
if(!namelist)
|
if(!namelist)
|
||||||
namelist = [];
|
namelist = [];
|
||||||
return namelist;
|
return namelist;
|
||||||
|
|||||||
@@ -1,162 +1,162 @@
|
|||||||
import {
|
// import {
|
||||||
DebugSession,
|
// DebugSession,
|
||||||
InitializedEvent, TerminatedEvent, StoppedEvent, BreakpointEvent, OutputEvent, Event,
|
// InitializedEvent, TerminatedEvent, StoppedEvent, BreakpointEvent, OutputEvent, Event,
|
||||||
Thread, StackFrame, Scope, Source, Handles, Breakpoint
|
// Thread, StackFrame, Scope, Source, Handles, Breakpoint
|
||||||
} from 'vscode-debugadapter';
|
// } from 'vscode-debugadapter';
|
||||||
import {DebugProtocol} from 'vscode-debugprotocol';
|
// import {DebugProtocol} from 'vscode-debugprotocol';
|
||||||
import * as fs from 'fs';
|
// import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
// import * as path from 'path';
|
||||||
const cmd = require('node-cmd');
|
// const cmd = require('node-cmd');
|
||||||
|
|
||||||
export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
|
// export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
|
||||||
godot: string;
|
// godot: string;
|
||||||
projectDir: string;
|
// projectDir: string;
|
||||||
runWithEditor: boolean;
|
// runWithEditor: boolean;
|
||||||
params: string[];
|
// params: string[];
|
||||||
}
|
// }
|
||||||
|
|
||||||
class GodotDebugSession extends DebugSession {
|
// class GodotDebugSession extends DebugSession {
|
||||||
|
|
||||||
// we don't support multiple threads, so we can use a hardcoded ID for the default thread
|
// // we don't support multiple threads, so we can use a hardcoded ID for the default thread
|
||||||
private static THREAD_ID = 1;
|
// private static THREAD_ID = 1;
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Creates a new debug adapter that is used for one debug session.
|
// * Creates a new debug adapter that is used for one debug session.
|
||||||
* We configure the default implementation of a debug adapter here.
|
// * We configure the default implementation of a debug adapter here.
|
||||||
*/
|
// */
|
||||||
public constructor() {
|
// public constructor() {
|
||||||
super();
|
// super();
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* The 'initialize' request is the first request called by the frontend
|
// * The 'initialize' request is the first request called by the frontend
|
||||||
* to interrogate the features the debug adapter provides.
|
// * to interrogate the features the debug adapter provides.
|
||||||
*/
|
// */
|
||||||
protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
|
// protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
|
||||||
|
|
||||||
// since this debug adapter can accept configuration requests like 'setBreakpoint' at any time,
|
// // since this debug adapter can accept configuration requests like 'setBreakpoint' at any time,
|
||||||
// we request them early by sending an 'initializeRequest' to the frontend.
|
// // we request them early by sending an 'initializeRequest' to the frontend.
|
||||||
// The frontend will end the configuration sequence by calling 'configurationDone' request.
|
// // The frontend will end the configuration sequence by calling 'configurationDone' request.
|
||||||
this.sendEvent(new InitializedEvent());
|
// this.sendEvent(new InitializedEvent());
|
||||||
|
|
||||||
// This debug adapter implements the configurationDoneRequest.
|
// // This debug adapter implements the configurationDoneRequest.
|
||||||
response.body.supportsConfigurationDoneRequest = true;
|
// response.body.supportsConfigurationDoneRequest = true;
|
||||||
|
|
||||||
// make VS Code to use 'evaluate' when hovering over source
|
// // make VS Code to use 'evaluate' when hovering over source
|
||||||
response.body.supportsEvaluateForHovers = true;
|
// response.body.supportsEvaluateForHovers = true;
|
||||||
|
|
||||||
// make VS Code to show a 'step back' button
|
// // make VS Code to show a 'step back' button
|
||||||
response.body.supportsStepBack = true;
|
// response.body.supportsStepBack = true;
|
||||||
|
|
||||||
this.log("initializeRequest");
|
// this.log("initializeRequest");
|
||||||
this.log_err("initializeRequest");
|
// this.log_err("initializeRequest");
|
||||||
this.log_console("initializeRequest");
|
// this.log_console("initializeRequest");
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
|
// protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
|
||||||
for(let key of Object.keys(args))
|
// for(let key of Object.keys(args))
|
||||||
this.log(`${key} : ${args[key]}`);
|
// this.log(`${key} : ${args[key]}`);
|
||||||
let workspaceValid = false
|
// let workspaceValid = false
|
||||||
if(args.godot && fs.existsSync(args.godot) && fs.statSync(args.godot).isFile() ) {
|
// if(args.godot && fs.existsSync(args.godot) && fs.statSync(args.godot).isFile() ) {
|
||||||
if(args.projectDir && fs.existsSync(args.projectDir) && fs.statSync(args.projectDir).isDirectory() ) {
|
// if(args.projectDir && fs.existsSync(args.projectDir) && fs.statSync(args.projectDir).isDirectory() ) {
|
||||||
let cfg = path.join(args.projectDir, "engine.cfg");
|
// let cfg = path.join(args.projectDir, "engine.cfg");
|
||||||
if( fs.existsSync(cfg) && fs.statSync(cfg).isFile())
|
// if( fs.existsSync(cfg) && fs.statSync(cfg).isFile())
|
||||||
workspaceValid = true;
|
// workspaceValid = true;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
if(workspaceValid) {
|
// if(workspaceValid) {
|
||||||
let params = `-path ${args.projectDir} `;
|
// let params = `-path ${args.projectDir} `;
|
||||||
if(args.runWithEditor)
|
// if(args.runWithEditor)
|
||||||
params += "-e";
|
// params += "-e";
|
||||||
if(args.params) {
|
// if(args.params) {
|
||||||
for(let p of args.params)
|
// for(let p of args.params)
|
||||||
params += " " + p;
|
// params += " " + p;
|
||||||
}
|
// }
|
||||||
let cmdcontent = `${args.godot} ${params}`;
|
// let cmdcontent = `${args.godot} ${params}`;
|
||||||
this.log(cmdcontent)
|
// this.log(cmdcontent)
|
||||||
// TODO: print outputs in terminal console
|
// // TODO: print outputs in terminal console
|
||||||
cmd.run(cmdcontent);
|
// cmd.run(cmdcontent);
|
||||||
this.sendEvent(new TerminatedEvent());
|
// this.sendEvent(new TerminatedEvent());
|
||||||
}
|
// }
|
||||||
else {
|
// else {
|
||||||
this.log_err("Invalidate path of projectDir or godot:");
|
// this.log_err("Invalidate path of projectDir or godot:");
|
||||||
this.log_err(JSON.stringify(args, null, '\t'));
|
// this.log_err(JSON.stringify(args, null, '\t'));
|
||||||
this.sendEvent(new TerminatedEvent());
|
// this.sendEvent(new TerminatedEvent());
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
|
// protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
|
||||||
|
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {
|
// protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {
|
||||||
|
|
||||||
// return the default thread
|
// // return the default thread
|
||||||
response.body = {
|
// response.body = {
|
||||||
threads: [
|
// threads: [
|
||||||
new Thread(GodotDebugSession.THREAD_ID, "thread 1")
|
// new Thread(GodotDebugSession.THREAD_ID, "thread 1")
|
||||||
]
|
// ]
|
||||||
};
|
// };
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Returns a fake 'stacktrace' where every 'stackframe' is a word from the current line.
|
// * Returns a fake 'stacktrace' where every 'stackframe' is a word from the current line.
|
||||||
*/
|
// */
|
||||||
protected stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): void {
|
// protected stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): void {
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
|
// protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): void {
|
// protected variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): void {
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
|
// protected continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void {
|
||||||
this.sendEvent(new TerminatedEvent());
|
// this.sendEvent(new TerminatedEvent());
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected reverseContinueRequest(response: DebugProtocol.ReverseContinueResponse, args: DebugProtocol.ReverseContinueArguments) : void {
|
// protected reverseContinueRequest(response: DebugProtocol.ReverseContinueResponse, args: DebugProtocol.ReverseContinueArguments) : void {
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected nextRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments): void {
|
// protected nextRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments): void {
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected stepBackRequest(response: DebugProtocol.StepBackResponse, args: DebugProtocol.StepBackArguments): void {
|
// protected stepBackRequest(response: DebugProtocol.StepBackResponse, args: DebugProtocol.StepBackArguments): void {
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void {
|
// protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void {
|
||||||
this.sendResponse(response);
|
// this.sendResponse(response);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* Fire StoppedEvent if line is not empty.
|
// * Fire StoppedEvent if line is not empty.
|
||||||
*/
|
// */
|
||||||
private fireStepEvent(response: DebugProtocol.Response, ln: number): boolean {
|
// private fireStepEvent(response: DebugProtocol.Response, ln: number): boolean {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
|
|
||||||
private log(msg: string) {
|
// private log(msg: string) {
|
||||||
const e = new OutputEvent(msg, "stdout");
|
// const e = new OutputEvent(msg, "stdout");
|
||||||
this.sendEvent(e);
|
// this.sendEvent(e);
|
||||||
}
|
// }
|
||||||
private log_err(msg: string) {
|
// private log_err(msg: string) {
|
||||||
const e = new OutputEvent(msg, "stderr");
|
// const e = new OutputEvent(msg, "stderr");
|
||||||
this.sendEvent(e);
|
// this.sendEvent(e);
|
||||||
}
|
// }
|
||||||
private log_console(msg: string) {
|
// private log_console(msg: string) {
|
||||||
const e = new OutputEvent(msg, "console");
|
// const e = new OutputEvent(msg, "console");
|
||||||
this.sendEvent(e);
|
// this.sendEvent(e);
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
DebugSession.run(GodotDebugSession);
|
// DebugSession.run(GodotDebugSession);
|
||||||
|
|||||||
@@ -34,14 +34,67 @@ class GDScriptCompletionItemProvider implements CompletionItemProvider {
|
|||||||
constructor() {
|
constructor() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private get_previous_flag(document : TextDocument, position : Position): string {
|
||||||
|
const line = document.lineAt(position).text;
|
||||||
|
let res = "";
|
||||||
|
for (let index = position.character; index >= 0; index--) {
|
||||||
|
res = line[index];
|
||||||
|
if (['.', '$', '"', "'"].indexOf(res) != -1 )
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
provideCompletionItems(document : TextDocument, position : Position, token : CancellationToken) : CompletionItem[] | Thenable < CompletionItem[] > | CompletionList | Thenable < CompletionList > {
|
provideCompletionItems(document : TextDocument, position : Position, token : CancellationToken) : CompletionItem[] | Thenable < CompletionItem[] > | CompletionList | Thenable < CompletionList > {
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
const lastFlag = this.get_previous_flag(document, position);
|
||||||
let items:CompletionItem[] = config.getWorkspaceCompletionItems();
|
const builtins = config.getBuiltinCompletions();
|
||||||
items = [...items, ...config.bintinSybmolInfoList];
|
|
||||||
resolve(items);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
let items:CompletionItem[] = [...(builtins.builtinConstants)];
|
||||||
|
if(!lastFlag || lastFlag.trim().length == 0) {
|
||||||
|
const workspaces = config.getWorkspaceCompletionItems([config.normalizePath(document.fileName)]);
|
||||||
|
items = [
|
||||||
|
...items,
|
||||||
|
...(workspaces.functions),
|
||||||
|
...(workspaces.classes),
|
||||||
|
...(workspaces.constants),
|
||||||
|
...(workspaces.properties),
|
||||||
|
...(builtins.functions),
|
||||||
|
...(builtins.classes),
|
||||||
|
...(builtins.constants),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const workspaces = config.getWorkspaceCompletionItems();
|
||||||
|
if(lastFlag.trim() == ".") {
|
||||||
|
items = [
|
||||||
|
...items,
|
||||||
|
...(workspaces.functions),
|
||||||
|
...(workspaces.constants),
|
||||||
|
...(workspaces.properties),
|
||||||
|
...(workspaces.classes),
|
||||||
|
...(builtins.functions),
|
||||||
|
...(builtins.constants),
|
||||||
|
...(builtins.properties)
|
||||||
|
]
|
||||||
|
}
|
||||||
|
else if(lastFlag.trim() == "'" || lastFlag.trim() == '"') {
|
||||||
|
items = [
|
||||||
|
...items,
|
||||||
|
...(workspaces.signals),
|
||||||
|
...(workspaces.functions),
|
||||||
|
...(workspaces.properties),
|
||||||
|
...(builtins.signals),
|
||||||
|
...(builtins.functions),
|
||||||
|
...(builtins.properties),
|
||||||
|
...(workspaces.nodes),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
else if(lastFlag.trim() == "$") {
|
||||||
|
items = [ ...(workspaces.nodes) ]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveCompletionItem(item : CompletionItem, token : CancellationToken) : CompletionItem | Thenable < CompletionItem > {
|
resolveCompletionItem(item : CompletionItem, token : CancellationToken) : CompletionItem | Thenable < CompletionItem > {
|
||||||
|
|||||||
@@ -15,16 +15,19 @@ import config from '../config';
|
|||||||
import {isStr, getSelectedContent, getStrContent} from './utils';
|
import {isStr, getSelectedContent, getStrContent} from './utils';
|
||||||
|
|
||||||
class GDScriptDefinitionProivder implements DefinitionProvider {
|
class GDScriptDefinitionProivder implements DefinitionProvider {
|
||||||
constructor() {
|
private _rootFolder : string = "";
|
||||||
|
|
||||||
|
constructor(rootFolder: string) {
|
||||||
|
this._rootFolder = rootFolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
provideDefinition(document: TextDocument, position: Position, token: CancellationToken): Definition | Thenable < Definition > {
|
provideDefinition(document: TextDocument, position: Position, token: CancellationToken): Definition | Thenable < Definition > {
|
||||||
const getDefinitions = (content: string):Location[]| Location => {
|
const getDefinitions = (content: string):Location[]| Location => {
|
||||||
if(content.startsWith("res://")) {
|
if(content.startsWith("res://")) {
|
||||||
content = content.replace("res://", "");
|
content = content.replace("res://", "");
|
||||||
if(workspace && workspace.rootPath)
|
if(workspace && workspace.rootPath) {
|
||||||
content = path.join(workspace.rootPath, content)
|
content = path.join(this._rootFolder, content);
|
||||||
|
}
|
||||||
return new Location(Uri.file(content), new Range(0,0,0,0));
|
return new Location(Uri.file(content), new Range(0,0,0,0));
|
||||||
}
|
}
|
||||||
else if(fs.existsSync(content) && fs.statSync(content).isFile()) {
|
else if(fs.existsSync(content) && fs.statSync(content).isFile()) {
|
||||||
@@ -54,6 +57,8 @@ class GDScriptDefinitionProivder implements DefinitionProvider {
|
|||||||
scriptitems = [...scriptitems, ...checkDifinition(script.functions)];
|
scriptitems = [...scriptitems, ...checkDifinition(script.functions)];
|
||||||
scriptitems = [...scriptitems, ...checkDifinition(script.signals)];
|
scriptitems = [...scriptitems, ...checkDifinition(script.signals)];
|
||||||
scriptitems = [...scriptitems, ...checkDifinition(script.classes)];
|
scriptitems = [...scriptitems, ...checkDifinition(script.classes)];
|
||||||
|
if(script.enumerations)
|
||||||
|
scriptitems = [...scriptitems, ...checkDifinition(script.enumerations)];
|
||||||
locations = [...locations, ...scriptitems];
|
locations = [...locations, ...scriptitems];
|
||||||
}
|
}
|
||||||
// check from builtin
|
// check from builtin
|
||||||
|
|||||||
@@ -1,134 +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 {
|
||||||
|
private _subscription : DiagnosticCollection;
|
||||||
class GDScriptDiagnosticSeverity {
|
|
||||||
private _subscription: DiagnosticCollection;
|
constructor() {
|
||||||
|
this._subscription = vscode.languages.createDiagnosticCollection("gdscript")
|
||||||
constructor() {
|
}
|
||||||
this._subscription = vscode.languages.createDiagnosticCollection("gdscript")
|
|
||||||
}
|
dispose() {
|
||||||
|
this._subscription.dispose()
|
||||||
dispose() {
|
}
|
||||||
this._subscription.dispose()
|
|
||||||
}
|
async validateScript(doc : vscode.TextDocument, script : any) {
|
||||||
|
if (doc.languageId == 'gdscript') {
|
||||||
async validateScript(doc: vscode.TextDocument, script: any) {
|
if (script) {
|
||||||
if(doc.languageId == 'gdscript') {
|
let diagnostics = [ ...(this.validateExpression(doc)), ...(this.validateUnusedSymbols(doc, script)) ];
|
||||||
if(script) {
|
this._subscription.set(doc.uri, diagnostics);
|
||||||
let diagnostics = [
|
return true;
|
||||||
...(this.validateExpression(doc)),
|
}
|
||||||
...(this.validateUnusedSymbols(doc, script)),
|
}
|
||||||
];
|
return false;
|
||||||
this._subscription.set(doc.uri, diagnostics);
|
}
|
||||||
return true;
|
|
||||||
}
|
private validateUnusedSymbols(doc : vscode.TextDocument, script) {
|
||||||
}
|
let diagnostics = [];
|
||||||
return false;
|
let cfg : any = vscode.workspace.getConfiguration("GodotTools").get("lint");
|
||||||
}
|
if (!cfg.unusedSymbols)
|
||||||
|
return diagnostics
|
||||||
private validateUnusedSymbols(doc: vscode.TextDocument,script) {
|
|
||||||
let diagnostics = [];
|
const text = doc.getText();
|
||||||
const text = doc.getText();
|
const check = (name : string, range : vscode.Range) => {
|
||||||
|
var matchs = text.match(new RegExp(`([^\\w]|\\[|\\{)\\s*${name}\\s*([^\\w]|\\[|\\{)`, 'g'));
|
||||||
const check = (name:string, range: vscode.Range) => {
|
let count = matchs ? matchs.length : 0;
|
||||||
var matchs = text.match(new RegExp(`[^0-9A-Za-z_]\\s*${name}[^0-9A-Za-z_]\\s*`, 'g'));
|
var incomment = text.match(new RegExp(`#.*?([^\\w]|\\[|\\{)\\s*${name}\\s*([^\\w]|\\[|\\{)`, 'g'));
|
||||||
let count = matchs?matchs.length:0;
|
count -= incomment ? incomment.length : 0;
|
||||||
var incomment = text.match(new RegExp(`#[^0-9A-z_]*${name}[^0-9A-z_]`, 'g'));
|
if (count <= 1)
|
||||||
count -= incomment?incomment.length:0;
|
diagnostics.push(new vscode.Diagnostic(range, `${name} is never used.`, DiagnosticSeverity.Warning));
|
||||||
if(count <= 1)
|
};
|
||||||
diagnostics.push(new vscode.Diagnostic(range, `${name} is never used.`, DiagnosticSeverity.Warning));
|
// Unused variables
|
||||||
};
|
for (let key of Object.keys(script.variables))
|
||||||
// Unused variables
|
check(key, script.variables[key]);
|
||||||
for (let key of Object.keys(script.variables))
|
for (let key of Object.keys(script.constants))
|
||||||
check(key, script.variables[key]);
|
check(key, script.constants[key]);
|
||||||
for (let key of Object.keys(script.constants))
|
return diagnostics;
|
||||||
check(key, script.constants[key]);
|
}
|
||||||
return diagnostics;
|
|
||||||
}
|
private validateExpression(doc : vscode.TextDocument) {
|
||||||
|
let cfg : any = vscode.workspace.getConfiguration("GodotTools").get("lint");
|
||||||
private validateExpression(doc: vscode.TextDocument) {
|
|
||||||
let diagnostics = [];
|
let diagnostics = [];
|
||||||
const text = doc.getText();
|
let expectEndOfLine = false;
|
||||||
const lines = text.split(/\r?\n/);
|
const text = doc.getText();
|
||||||
lines.map((line:string, i: number) =>{
|
const lines = text.split(/\r?\n/);
|
||||||
let matchstart = /[^\s]+.*/.exec(line);
|
lines.map((line : string, i : number) => {
|
||||||
let curLineStartAt = 0;
|
let matchstart = /[^\s]+.*/.exec(line);
|
||||||
if(matchstart)
|
let curLineStartAt = 0;
|
||||||
curLineStartAt = matchstart.index;
|
if (matchstart)
|
||||||
// ignore comments
|
curLineStartAt = matchstart.index;
|
||||||
if(line.match(/^\s*#.*/) || line.match(/^#.*/)) return
|
|
||||||
// normalize line content
|
// ignore comments
|
||||||
line = "\t" + line + "\t";
|
if (line.match(/^\s*#.*/) || line.match(/^#.*/))
|
||||||
|
return
|
||||||
if(line.match(/[^#].*?\;/) && !line.match(/[#].*?\;/)) {
|
// normalize line content
|
||||||
const semicolonIndex = line.indexOf(';');
|
line = "\t" + line + "\t";
|
||||||
diagnostics.push(new vscode.Diagnostic(new vscode.Range(i, semicolonIndex, i, semicolonIndex+1), "Statement contains a semicolon.", DiagnosticSeverity.Warning));
|
var range = new vscode.Range(i, curLineStartAt, i, line.length);
|
||||||
}
|
|
||||||
if(line.match(/[^\w](if|elif|else|for|while|func|class)[^\w].*?/) && !line.match(/#.*?[^\w](if|elif|else|for|while|func|class)[^\w].*?/)) {
|
if (cfg.semicolon && line.match(/[^#].*?\;/) && !line.match(/[#].*?\;/)) {
|
||||||
var range = new vscode.Range(i, curLineStartAt, i, line.length);
|
const semicolonIndex = line.indexOf(';');
|
||||||
if(!line.match(/(if|elif|else|for|while|func|class).*?\:/))
|
diagnostics.push(new vscode.Diagnostic(new vscode.Range(i, semicolonIndex, i, semicolonIndex + 1), "Statement contains a semicolon.", DiagnosticSeverity.Warning));
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "':' expected at end of the line.", DiagnosticSeverity.Error));
|
}
|
||||||
else if(line.match(/(if|elif|while|func|class)\s*\:/))
|
if (line.match(/[^#].*?/) && expectEndOfLine) {
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Indentifier expected before ':'", DiagnosticSeverity.Error));
|
if (!line.match(/.*?(\\|\:)/)) {
|
||||||
else if(line.match(/[^\w]for[^\w]/) && !line.match(/\s+for\s\w+\s+in\s+[\w+]|\{.*?\}|\[.*?\]/))
|
diagnostics.push(new vscode.Diagnostic(range, "': or \\' expected at end of the line.", DiagnosticSeverity.Error));
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Invalid for expression", DiagnosticSeverity.Error));
|
expectEndOfLine = false;
|
||||||
else if(line.match(/(if|elif|while)\s*\(.*\)/))
|
}
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Extra brackets in condition expression.", DiagnosticSeverity.Warning));
|
if (line.match(/.*?\:/))
|
||||||
|
expectEndOfLine = false;
|
||||||
if(line.match(/([^\w]if|elif|else|for|while|func|class[^\w]).*\:[ \t]+[^#\s]+/))
|
}
|
||||||
return
|
const colonKeywords = /\b(if|elif|else|for|while|func|class|match)\b/;
|
||||||
else if( i < lines.length-1) {
|
let keywords = line.match(colonKeywords)
|
||||||
let next = i+1;
|
if (keywords) {
|
||||||
let nextline = lines[next];
|
if(line.match(new RegExp(`".*?\\s${keywords[1]}\\s.*?"`)) || line.match(new RegExp(`'.*?\\s${keywords[1]}\\s.*?\'`)))
|
||||||
// changes nextline until finds a line containg text or comes to the last line
|
return
|
||||||
while ((!nextline || nextline.match(/\s+$/)) && next < lines.length-1) {
|
if(line.match(new RegExp(`.*?#.*?\\s${keywords[1]}\\s.*?`)))
|
||||||
++next;
|
return
|
||||||
nextline = lines[next];
|
if(line.match(/.*?\sif\s+(\!|\[|\{|\w|").*?\s+else\s+[^\s]+/))
|
||||||
}
|
return
|
||||||
let nextLineStartAt = -1;
|
if (line.match(/.*?\\/))
|
||||||
let match = /[^\s]+.*/.exec(nextline);
|
expectEndOfLine = true;
|
||||||
if(match)
|
else if (line.match(/.*?\:[\s+]+[^#\s]+/))
|
||||||
nextLineStartAt = match.index;
|
return
|
||||||
|
else if (!line.match(/.*?(\\|\:)/))
|
||||||
if(nextLineStartAt <= curLineStartAt)
|
diagnostics.push(new vscode.Diagnostic(range, "': or \\' expected at end of the line.", DiagnosticSeverity.Error));
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Expected indented block after expression", DiagnosticSeverity.Error));
|
else if (line.match(/\s(if|elif|while|func|class|match)\s*\:/))
|
||||||
}
|
diagnostics.push(new vscode.Diagnostic(range, "Indentifier expected before ':'", DiagnosticSeverity.Error));
|
||||||
else
|
else if (line.match(/[^\w]for[^\w]/) && !line.match(/\s+for\s\w+\s+in\s+|[\w+]|\{.*?\}|\[.*?\]|\(.*?\)/)){
|
||||||
diagnostics.push(new vscode.Diagnostic(range, "Expected indented block after expression", DiagnosticSeverity.Error));
|
if(!(line.match(/".*?for.*?"/) || line.match(/'.*?for.*?'/)))
|
||||||
}
|
diagnostics.push(new vscode.Diagnostic(range, "Invalid for expression", DiagnosticSeverity.Error));
|
||||||
});
|
}
|
||||||
return diagnostics;
|
else if (cfg.conditionBrackets && line.match(/\s(if|elif|while|match)\s*\(.*\)\s*:\s*$/))
|
||||||
}
|
diagnostics.push(new vscode.Diagnostic(range, "Extra brackets in condition expression.", DiagnosticSeverity.Warning));
|
||||||
|
const blockIndetCheck = function() {
|
||||||
}
|
const err = new vscode.Diagnostic(range, "Expected indented block after expression", DiagnosticSeverity.Error);
|
||||||
|
if (i < lines.length - 1) {
|
||||||
export default GDScriptDiagnosticSeverity;
|
let next = i + 1;
|
||||||
|
let nextline = lines[next];
|
||||||
|
// changes nextline until finds a line containg text or comes to the last line
|
||||||
|
while (((!nextline || !nextline.trim().length) || nextline.match(/^\s*#/)) && next < lines.length - 1) {
|
||||||
|
++next;
|
||||||
|
nextline = lines[next];
|
||||||
|
}
|
||||||
|
let nextLineStartAt = -1;
|
||||||
|
let match = /[^\s]+.*/.exec(nextline);
|
||||||
|
if (match)
|
||||||
|
nextLineStartAt = match.index;
|
||||||
|
|
||||||
|
if (nextLineStartAt <= curLineStartAt)
|
||||||
|
diagnostics.push(err);
|
||||||
|
}
|
||||||
|
else if(line.match(/\:\s*$/))
|
||||||
|
diagnostics.push(err);
|
||||||
|
};
|
||||||
|
if(!expectEndOfLine)
|
||||||
|
blockIndetCheck();
|
||||||
|
}
|
||||||
|
// Do not check : for end of statement as it breaks match statment
|
||||||
|
let endOfStateMentWithComma = false;
|
||||||
|
if(endOfStateMentWithComma && !line.match(colonKeywords) && line.match(/\:\s*$/)) {
|
||||||
|
let showErr = true;
|
||||||
|
if( i >= 1 ) {
|
||||||
|
let previous = i - 1;
|
||||||
|
let previousline = lines[previous];
|
||||||
|
while(previousline.match(/\\\s*$/) && previous>=1) {
|
||||||
|
--previous;
|
||||||
|
const ppreviousline = lines[previous];
|
||||||
|
if(ppreviousline.match(/\\\s*$/))
|
||||||
|
previousline = ppreviousline;
|
||||||
|
}
|
||||||
|
const keywords = previousline.match(colonKeywords);
|
||||||
|
if(keywords && !(previousline.match(new RegExp(`".*?\\s${keywords[1]}\\s.*?"`)) || previousline.match(new RegExp(`'.*?\\s${keywords[1]}\\s.*?'`)) ))
|
||||||
|
showErr = false
|
||||||
|
}
|
||||||
|
if(showErr)
|
||||||
|
diagnostics.push(new vscode.Diagnostic(range, "Expected end of statement after expression", DiagnosticSeverity.Error));
|
||||||
|
}
|
||||||
|
if (line.match(/(if|elif|while|return)\s+\w+\s*=\s*\w+/))
|
||||||
|
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("==");
|
||||||
|
const precontent = line.substring(0, endAt);
|
||||||
|
if (!precontent.match(/\s(if|elif|while|return)\s/) && !precontent.match(/=[^=]/) && !precontent.match(/assert\s*\(/) && !expectEndOfLine) {
|
||||||
|
diagnostics.push(new vscode.Diagnostic(range, "Unhandled comparation expression contains", DiagnosticSeverity.Warning));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return diagnostics;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GDScriptDiagnosticSeverity;
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ function genLink(title:string, uri:string, span=true):string {
|
|||||||
|
|
||||||
function getProp(rawDoc:any, propname: string, action=(s :string)=>s): string {
|
function getProp(rawDoc:any, propname: string, action=(s :string)=>s): string {
|
||||||
let prop = rawDoc[propname];
|
let prop = rawDoc[propname];
|
||||||
if(prop && prop.length > 0)
|
return action(prop);
|
||||||
prop = action(prop);
|
|
||||||
return prop;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class GDScriptDocumentContentProvider implements TextDocumentContentProvider{
|
class GDScriptDocumentContentProvider implements TextDocumentContentProvider{
|
||||||
@@ -67,9 +65,55 @@ class GDScriptDocumentContentProvider implements TextDocumentContentProvider{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format_documentation(text: string): string {
|
||||||
|
let doc = text.replace(/\[code\]/g, "<code>").replace(/\[\/code\]/g, "</code>");
|
||||||
|
doc = doc.replace(/\[codeblock\]/g, '<pre><code class="gdscript">').replace(/\[\/codeblock]/g, "</code></pre>");
|
||||||
|
doc = doc.replace(/\[i\]/g, "<i>").replace(/\[\/i\]/g, "</i>");
|
||||||
|
doc = doc.replace(/\[b\]/g, "<b>").replace(/\[\/b\]/g, "</b>");
|
||||||
|
doc = doc.replace(/\[u\]/g, "<u>").replace(/\[\/u\]/g, "</u>");
|
||||||
|
doc = doc.replace(/\n\t\t\t\t/g, "\n\t");
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
|
||||||
genMethodDoc(mDoc:any):string {
|
genMethodDoc(mDoc:any):string {
|
||||||
let ret_type = getProp(mDoc, "return_type", (type:string):string =>{
|
let ret_type = getProp(mDoc, "return_type", (type:string):string =>{
|
||||||
return `${genLink(type,type)} `;
|
if(type.length > 0)
|
||||||
|
return `${genLink(type,type)} `;
|
||||||
|
else
|
||||||
|
return "void";
|
||||||
|
});
|
||||||
|
let args = "";
|
||||||
|
for(let arg of mDoc.arguments){
|
||||||
|
if(mDoc.arguments.indexOf(arg)!=0)
|
||||||
|
args += ", ";
|
||||||
|
args += `${genLink(arg.type, arg.type)} ${arg.name}`
|
||||||
|
if(arg.default_value && arg.default_value.length > 0)
|
||||||
|
args += `=${arg.default_value}`;
|
||||||
|
}
|
||||||
|
var docContent = mDoc.description;
|
||||||
|
if (!docContent) {
|
||||||
|
docContent = `There is currently no description for this method. Please help us by <span><a href="http://docs.godotengine.org/en/latest/community/contributing/updating_the_class_reference.html">contributing one</a></span>!`;
|
||||||
|
}
|
||||||
|
let doc = `
|
||||||
|
<li>
|
||||||
|
<h4 id="${mDoc.name}">${ret_type} ${mDoc.name} (${args}) <i>${mDoc.qualifiers}</i></h4>
|
||||||
|
<p>${docContent}</p>
|
||||||
|
</li>
|
||||||
|
`;
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
genPropHeader(mDoc:any, classname:string): string {
|
||||||
|
let type = getProp(mDoc, "type", (type:string):string => `${genLink(type,type)} `);
|
||||||
|
return `<li>${type} ${genLink(mDoc.name, classname+"."+mDoc.name)}</li>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
genMethodHeader(mDoc:any, classname:string):string {
|
||||||
|
let ret_type = getProp(mDoc, "return_type", (type:string):string =>{
|
||||||
|
if(type.length > 0)
|
||||||
|
return `${genLink(type,type)} `;
|
||||||
|
else
|
||||||
|
return "void";
|
||||||
});
|
});
|
||||||
let args = "";
|
let args = "";
|
||||||
for(let arg of mDoc.arguments){
|
for(let arg of mDoc.arguments){
|
||||||
@@ -81,18 +125,30 @@ class GDScriptDocumentContentProvider implements TextDocumentContentProvider{
|
|||||||
}
|
}
|
||||||
let doc = `
|
let doc = `
|
||||||
<li>
|
<li>
|
||||||
<h4>${ret_type} ${mDoc.name} (${args}) <i>${mDoc.qualifiers}</i></h4>
|
${ret_type} ${genLink(mDoc.name, classname+"."+mDoc.name)} (${args}) <i>${mDoc.qualifiers}</i>
|
||||||
<p>${mDoc.description}</p>
|
|
||||||
</li>
|
</li>
|
||||||
`;
|
`;
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
genPropDoc(pDoc:any): string {
|
genPropDoc(pDoc:any): string {
|
||||||
|
let setter = pDoc.setter;
|
||||||
|
if(setter) setter = `<li>Setter: ${setter}(value)</li>`; else setter = "";
|
||||||
|
let getter = pDoc.getter;
|
||||||
|
if(getter) getter = `<li>Getter: ${getter}()</li>`; else getter = "";
|
||||||
|
let descContent = pDoc.description;
|
||||||
|
if(!descContent) {
|
||||||
|
descContent = `There is currently no description for this property. Please help us by <span><a href="http://docs.godotengine.org/en/latest/community/contributing/updating_the_class_reference.html">contributing one</a></span>!`;
|
||||||
|
}
|
||||||
let doc = `
|
let doc = `
|
||||||
<li>
|
<li>
|
||||||
<h4>${genLink(pDoc.type,pDoc.type)} ${pDoc.name}</h4>
|
<h4>${genLink(pDoc.type,pDoc.type)} ${pDoc.name}</h4>
|
||||||
<p>${pDoc.description}</p>
|
<ul>
|
||||||
|
${setter}
|
||||||
|
${getter}
|
||||||
|
</ul>
|
||||||
|
<p>${descContent}</p>
|
||||||
</li>
|
</li>
|
||||||
`;
|
`;
|
||||||
return doc;
|
return doc;
|
||||||
@@ -171,6 +227,7 @@ class GDScriptDocumentContentProvider implements TextDocumentContentProvider{
|
|||||||
return null;
|
return null;
|
||||||
const classname = rawDoc.name;
|
const classname = rawDoc.name;
|
||||||
let inherits = getProp(rawDoc, "inherits", (inherits:string)=>{
|
let inherits = getProp(rawDoc, "inherits", (inherits:string)=>{
|
||||||
|
if (!inherits) return "";
|
||||||
return "<h4>Inherits: " + genLink(inherits, inherits, true) +"</h4>";
|
return "<h4>Inherits: " + genLink(inherits, inherits, true) +"</h4>";
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -189,18 +246,38 @@ class GDScriptDocumentContentProvider implements TextDocumentContentProvider{
|
|||||||
subclasses = "<h3>Inherited by</h3> " + "<ul><li>" + subclasses + "</li></ul>";
|
subclasses = "<h3>Inherited by</h3> " + "<ul><li>" + subclasses + "</li></ul>";
|
||||||
|
|
||||||
let briefDescript = getProp(rawDoc, "brief_description", (dec:string)=>{
|
let briefDescript = getProp(rawDoc, "brief_description", (dec:string)=>{
|
||||||
return "<h3>Brief Description</h3>" + "<ul><li>" + dec + "</li></ul>";
|
return dec;
|
||||||
});
|
});
|
||||||
let descript = getProp(rawDoc, "description", (dec:string)=>{
|
let descript = getProp(rawDoc, "description", (dec:string)=>{
|
||||||
return "<h3>Description</h3>" + "<ul><li>" + dec + "</li></ul>";
|
if(dec)
|
||||||
|
return "<h3>Description</h3>" + "<ul><li>" + dec + "</li></ul>";
|
||||||
|
else
|
||||||
|
return "";
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const setter_getters = {};
|
||||||
|
let propHeaders = ""
|
||||||
|
for(let p of rawDoc.properties) {
|
||||||
|
propHeaders += this.genPropHeader(p, classname);
|
||||||
|
if(p.setter)
|
||||||
|
setter_getters[p.setter] = true;
|
||||||
|
if(p.getter)
|
||||||
|
setter_getters[p.getter] = true;
|
||||||
|
}
|
||||||
|
if(propHeaders.length >0)
|
||||||
|
propHeaders = `<h3>Member List</h3><ul>${propHeaders}</ul/>`;
|
||||||
|
|
||||||
|
let methodHeaders = ""
|
||||||
let methods = "";
|
let methods = "";
|
||||||
for(let m of rawDoc.methods) {
|
for(let m of rawDoc.methods) {
|
||||||
|
if(setter_getters[m.name]) continue;
|
||||||
|
methodHeaders += this.genMethodHeader(m, classname);
|
||||||
methods += this.genMethodDoc(m);
|
methods += this.genMethodDoc(m);
|
||||||
}
|
}
|
||||||
|
if(methodHeaders.length >0)
|
||||||
|
methodHeaders = `<h3>Public Methods</h3><ul>${methodHeaders}</ul/>`;
|
||||||
if(methods.length >0 )
|
if(methods.length >0 )
|
||||||
methods = `<h3>Methods</h3><ul>${methods}</ul/>`;
|
methods = `<h3>Public Methods</h3><ul>${methods}</ul/>`;
|
||||||
|
|
||||||
let signals = "";
|
let signals = "";
|
||||||
for(let s of rawDoc.signals) {
|
for(let s of rawDoc.signals) {
|
||||||
@@ -229,17 +306,19 @@ class GDScriptDocumentContentProvider implements TextDocumentContentProvider{
|
|||||||
let doc = `
|
let doc = `
|
||||||
${linkStyle}
|
${linkStyle}
|
||||||
<h1>Native Class ${classname}</h1>
|
<h1>Native Class ${classname}</h1>
|
||||||
|
<h4>${briefDescript}</h4>
|
||||||
<p>${category}</p>
|
<p>${category}</p>
|
||||||
<p>${inherits}</p>
|
<p>${inherits}</p>
|
||||||
<p>${subclasses}</p>
|
<p>${subclasses}</p>
|
||||||
<p>${briefDescript}</p>
|
|
||||||
<p>${descript}</p>
|
<p>${descript}</p>
|
||||||
<p>${methods}</p>
|
<p>${propHeaders}</p>
|
||||||
|
<p>${methodHeaders}</p>
|
||||||
<p>${signals}</p>
|
<p>${signals}</p>
|
||||||
<p>${constants}</p>
|
<p>${constants}</p>
|
||||||
<p>${props}</p>
|
<p>${props}</p>
|
||||||
|
<p>${methods}</p>
|
||||||
`;
|
`;
|
||||||
return doc;
|
return this.format_documentation(doc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import {
|
|||||||
Position,
|
Position,
|
||||||
CancellationToken,
|
CancellationToken,
|
||||||
Hover,
|
Hover,
|
||||||
MarkedString,
|
MarkdownString,
|
||||||
workspace,
|
workspace,
|
||||||
Uri,
|
Uri,
|
||||||
CompletionItem,
|
CompletionItem,
|
||||||
@@ -32,44 +32,57 @@ class GDScriptHoverProvider implements HoverProvider {
|
|||||||
if (isStr(hoverText))
|
if (isStr(hoverText))
|
||||||
hoverText = getStrContent(hoverText);
|
hoverText = getStrContent(hoverText);
|
||||||
const workspaceSymbols = config.getAllSymbols();
|
const workspaceSymbols = config.getAllSymbols();
|
||||||
let tips: MarkedString[] = [];
|
let tips: MarkdownString[] = [];
|
||||||
const withMarkdwon = workspace.getConfiguration("GodotTools").get("workspaceDocumentWithMarkdown", false);
|
const withMarkdwon = workspace.getConfiguration("GodotTools").get("workspaceDocumentWithMarkdown", false);
|
||||||
|
|
||||||
|
|
||||||
|
const makeMarkdown = (content): MarkdownString => {
|
||||||
|
let md = new MarkdownString(content);
|
||||||
|
md.isTrusted = true;
|
||||||
|
return md;
|
||||||
|
}
|
||||||
|
|
||||||
// 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: MarkedString[] = [];
|
let scriptips: MarkdownString[] = [];
|
||||||
const getHoverText = (items, type, path): MarkedString[] => {
|
const getHoverText = (items, type, gdpath): MarkdownString[] => {
|
||||||
const _items: MarkedString[] = [];
|
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];
|
||||||
if(type == "const" && script.constvalues[name])
|
if(type == "const" && script.constvalues[name])
|
||||||
signature = ` = ${script.constvalues[name]}`;
|
signature = ` = ${script.constvalues[name]}`;
|
||||||
_items.push({language:'gdscript', value:`${type} ${name}${signature}`});
|
let doc ='```gdscript\n' + `${type} ${name}${signature}` + '\n```\n';
|
||||||
let doc = script.documents[name];
|
let rowDoc = script.documents[name];
|
||||||
if(!withMarkdwon)
|
if(!withMarkdwon)
|
||||||
doc = "```plaintext\r\n"+doc+"\r\n```";
|
rowDoc += "```plaintext\r\n"+rowDoc+"\r\n```";
|
||||||
|
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(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)
|
||||||
|
scriptips = [...scriptips, ...getHoverText(script.enumerations, 'const', filepath)];
|
||||||
tips = [...tips, ...scriptips];
|
tips = [...tips, ...scriptips];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -93,8 +106,8 @@ class GDScriptHoverProvider implements HoverProvider {
|
|||||||
instance = ` which is an instance of *[${node.instance}](${Uri.file(instancepath).toString()})*`;
|
instance = ` which is an instance of *[${node.instance}](${Uri.file(instancepath).toString()})*`;
|
||||||
}
|
}
|
||||||
tips = [...tips,
|
tips = [...tips,
|
||||||
`${genLink(node.type, node.type)} ${fullpath}`,
|
makeMarkdown(`${genLink(node.type, node.type)} ${fullpath}`),
|
||||||
`${node.type} defined in *[${scnenepath}](${Uri.file(filepath).toString()})*${instance}`
|
makeMarkdown(`${node.type} defined in *[${scnenepath}](${Uri.file(filepath).toString()})*${instance}`)
|
||||||
];
|
];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -102,11 +115,21 @@ class GDScriptHoverProvider implements HoverProvider {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const format_documentation = (text, cls="") => {
|
||||||
|
let doc = text.replace(/\[code\]/g, "`").replace(/\[\/code\]/g, "`");
|
||||||
|
doc = doc.replace(/\[codeblock\]/g, "\n```gdscript\n").replace(/\[\/codeblock]/g, "\n```");
|
||||||
|
doc = doc.replace(/\[i\]/g, "*").replace(/\[\/i\]/g, "*");
|
||||||
|
doc = doc.replace(/\[b\]/g, "**").replace(/\[\/b\]/g, "**");
|
||||||
|
doc = doc.replace(/\[u\]/g, "__").replace(/\[\/u\]/g, "__");
|
||||||
|
doc = doc.replace(/\n\t\t\t\t/g, "\n");
|
||||||
|
return doc;
|
||||||
|
};
|
||||||
|
|
||||||
// check from builtin
|
// check from builtin
|
||||||
const genBuiltinTips = ()=> {
|
const genBuiltinTips = ()=> {
|
||||||
const item2MarkdStrings = (name: string,item: CompletionItem, rowDoc: any):MarkedString[] => {
|
const item2MarkdStrings = (name: string,item: CompletionItem, rowDoc: any):MarkdownString => {
|
||||||
let value = "";
|
let value = "";
|
||||||
let doc = item.documentation;
|
let doc = format_documentation(item.documentation);
|
||||||
// get class name
|
// get class name
|
||||||
let classname = name;
|
let classname = name;
|
||||||
let matchs = name.match(/[@A-z][A-z0-9]*\./);
|
let matchs = name.match(/[@A-z][A-z0-9]*\./);
|
||||||
@@ -118,8 +141,7 @@ class GDScriptHoverProvider implements HoverProvider {
|
|||||||
|
|
||||||
const genMethodMarkDown = ():string =>{
|
const genMethodMarkDown = ():string =>{
|
||||||
let content = `${genLink(rowDoc.return_type, rowDoc.return_type)} `;
|
let content = `${genLink(rowDoc.return_type, rowDoc.return_type)} `;
|
||||||
let matchs = name.match(/[@A-z][A-z0-9]*\./);
|
if (rowDoc.name != classname) content += `${genLink(classname, classname)}.`;
|
||||||
content += `${genLink(classname, classname)}.`;
|
|
||||||
let args = "";
|
let args = "";
|
||||||
for(let arg of rowDoc.arguments){
|
for(let arg of rowDoc.arguments){
|
||||||
if(rowDoc.arguments.indexOf(arg)!=0)
|
if(rowDoc.arguments.indexOf(arg)!=0)
|
||||||
@@ -128,34 +150,34 @@ class GDScriptHoverProvider implements HoverProvider {
|
|||||||
if(arg.default_value && arg.default_value.length > 0)
|
if(arg.default_value && arg.default_value.length > 0)
|
||||||
args += `=${arg.default_value}`;
|
args += `=${arg.default_value}`;
|
||||||
}
|
}
|
||||||
content += `${genLink(rowDoc.name, classname+'.'+rowDoc.name)}(${args}) ${rowDoc.qualifiers}`;
|
content += `${genLink(rowDoc.name, classname+'.' + rowDoc.name)}(${args}) ${rowDoc.qualifiers}`;
|
||||||
return content;
|
return content;
|
||||||
};
|
};
|
||||||
|
|
||||||
switch (item.kind) {
|
switch (item.kind) {
|
||||||
case CompletionItemKind.Class:
|
case CompletionItemKind.Class:
|
||||||
return [`Native Class ${genLink(classname, classname)}`, doc];
|
return makeMarkdown(`Native Class ${genLink(classname, classname)}\n${doc}`);
|
||||||
case CompletionItemKind.Method:
|
case CompletionItemKind.Method:
|
||||||
doc = item.documentation.substring(item.documentation.indexOf("\n")+1, item.documentation.length);
|
doc = doc.substring(doc.indexOf("\n")+1, doc.length);
|
||||||
return [genMethodMarkDown(), doc];
|
return makeMarkdown(`${genMethodMarkDown()}\n${doc}`);
|
||||||
case CompletionItemKind.Interface:
|
case CompletionItemKind.Interface:
|
||||||
doc = item.documentation.substring(item.documentation.indexOf("\n")+1, item.documentation.length);
|
doc = doc.substring(doc.indexOf("\n")+1, doc.length);
|
||||||
return ['signal ' + genMethodMarkDown(), doc];
|
return makeMarkdown(`signal ${genMethodMarkDown()}\n${doc}`);
|
||||||
case CompletionItemKind.Variable:
|
case CompletionItemKind.Variable:
|
||||||
case CompletionItemKind.Property:
|
case CompletionItemKind.Property:
|
||||||
return [`${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 [`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;
|
||||||
}
|
}
|
||||||
return [name, doc];
|
return makeMarkdown(`${name} ${doc}`);
|
||||||
};
|
};
|
||||||
for (let name of Object.keys(config.builtinSymbolInfoMap)) {
|
for (let name of Object.keys(config.builtinSymbolInfoMap)) {
|
||||||
const pattern = `[A-z@_]+[A-z0-9_]*\\.${hoverText}\\b`;
|
const pattern = `[A-z@_]+[A-z0-9_]*\\.${hoverText}\\b`;
|
||||||
if(name == hoverText || name.match(new RegExp(pattern))) {
|
if(name == hoverText || name.match(new RegExp(pattern))) {
|
||||||
const item: {completionItem: CompletionItem, rowDoc: any} = config.builtinSymbolInfoMap[name];
|
const item: {completionItem: CompletionItem, rowDoc: any} = config.builtinSymbolInfoMap[name];
|
||||||
tips = [...tips, ...(item2MarkdStrings(name, item.completionItem, item.rowDoc))];
|
tips = [...tips, item2MarkdStrings(name, item.completionItem, item.rowDoc)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ interface GDScript {
|
|||||||
// symbol: marked string
|
// symbol: marked string
|
||||||
documents: {},
|
documents: {},
|
||||||
// name : value
|
// name : value
|
||||||
constvalues: {}
|
constvalues: {},
|
||||||
|
enumerations: {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GDScriptSymbolParser {
|
class GDScriptSymbolParser {
|
||||||
@@ -27,14 +28,26 @@ class GDScriptSymbolParser {
|
|||||||
variables: {},
|
variables: {},
|
||||||
signals: {},
|
signals: {},
|
||||||
classes: {},
|
classes: {},
|
||||||
base: "Object",
|
base: "",
|
||||||
native: "Object",
|
native: "",
|
||||||
signatures: {},
|
signatures: {},
|
||||||
documents: {},
|
documents: {},
|
||||||
constvalues: {}
|
constvalues: {},
|
||||||
|
enumerations: {}
|
||||||
}
|
}
|
||||||
const text = content;
|
const text = content;
|
||||||
const lines = text.split(/\r?\n/);
|
const lines = text.split(/\r?\n/);
|
||||||
|
|
||||||
|
// Base class and native class
|
||||||
|
for (let line of lines) {
|
||||||
|
let match;
|
||||||
|
if (match = line.match(/extends\s+(\w+)/)) {
|
||||||
|
script.native = match[1];
|
||||||
|
break;
|
||||||
|
} else if (match = line.match(/extends\s+('|")(.*)('|")/)) {
|
||||||
|
script.base = match[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getMatches = (regex:RegExp, index=1) => {
|
const getMatches = (regex:RegExp, index=1) => {
|
||||||
var matches = [];
|
var matches = [];
|
||||||
@@ -138,7 +151,7 @@ class GDScriptSymbolParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let varreg = /var\s+([_A-Za-z]+[_A-Za-z0-9]*)\s*/;
|
let varreg = /var\s+([_A-Za-z]+[_A-Za-z0-9]*)\s*/;
|
||||||
let varreg2 = "var\\s+$X$\\s*";
|
let varreg2 = "var\\s+$X$([^\\w]|$)";
|
||||||
let vargroup = 1;
|
let vargroup = 1;
|
||||||
if(ignoreIndentedVars) {
|
if(ignoreIndentedVars) {
|
||||||
varreg = /^((export.*?var)|var)\s+([_A-Za-z]+[_A-Za-z0-9]*)\s?/;
|
varreg = /^((export.*?var)|var)\s+([_A-Za-z]+[_A-Za-z0-9]*)\s?/;
|
||||||
@@ -172,14 +185,39 @@ class GDScriptSymbolParser {
|
|||||||
script.constvalues[key] = match[2];
|
script.constvalues[key] = match[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
let classnames = getMatches(/class\s+([_A-Za-z]+[_A-Za-z0-9]*)\s*extends\s+/, 1);
|
let classnames = getMatches(/class\s+([_A-Za-z]+[_A-Za-z0-9]*)(\s|\:)/, 1);
|
||||||
const classes = findLineRanges(classnames, "class\\s+$X$\\s*extends\\s+");
|
const classes = findLineRanges(classnames, "class\\s+$X$(\\s|\\:)");
|
||||||
for (let key of Object.keys(classes)) {
|
for (let key of Object.keys(classes)) {
|
||||||
const r:Range = determRange(key, classes)
|
const r:Range = determRange(key, classes)
|
||||||
script.classes[key] = determRange(key, classes);
|
script.classes[key] = r;
|
||||||
script.documents[key] = parseDocument(r);
|
script.documents[key] = parseDocument(r);
|
||||||
}
|
}
|
||||||
// console.log(script);
|
|
||||||
|
let enumnames = getMatches(/enum\s+([_A-Za-z]+[_A-Za-z0-9]*)\s+\{/, 1);
|
||||||
|
const enums = findLineRanges(enumnames, "enum\\s+$X$\\s+\{");
|
||||||
|
for (let key of Object.keys(enums)) {
|
||||||
|
const r:Range = determRange(key, enums)
|
||||||
|
script.constants[key] = r;
|
||||||
|
script.documents[key] = parseDocument(r);
|
||||||
|
|
||||||
|
let curindex = r.start.line
|
||||||
|
while (curindex < lines.length) {
|
||||||
|
const line = lines[curindex];
|
||||||
|
let matchs = line.match(/([_A-Za-z]+[_A-Za-z0-9]*)/g);
|
||||||
|
if(matchs && matchs.length >= 1 ){
|
||||||
|
for (var i = 0; i < matchs.length; i++)
|
||||||
|
if(line.indexOf(matchs[i]) > line.indexOf("{"))
|
||||||
|
script.enumerations[matchs[i]] = new Range(curindex, 0, curindex, line.length);
|
||||||
|
}
|
||||||
|
if(line.indexOf("}") == -1)
|
||||||
|
curindex += 1;
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: enumerations without name
|
||||||
|
// const unnamedEnums = text.match(/enum\s+\{.*\}/gm)
|
||||||
|
|
||||||
|
|
||||||
return script;
|
return script;
|
||||||
}
|
}
|
||||||
@@ -195,4 +233,4 @@ class GDScriptSymbolParser {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default GDScriptSymbolParser;
|
export default GDScriptSymbolParser;
|
||||||
@@ -48,6 +48,12 @@ class GDScriptSymbolProvider implements DocumentSymbolProvider {
|
|||||||
for (let key of Object.keys(classes))
|
for (let key of Object.keys(classes))
|
||||||
symbols.push(new SymbolInformation(key, SymbolKind.Class, classes[key]));
|
symbols.push(new SymbolInformation(key, SymbolKind.Class, classes[key]));
|
||||||
|
|
||||||
|
if(script.enumerations) {
|
||||||
|
const enumerations = script.enumerations;
|
||||||
|
for (let key of Object.keys(enumerations))
|
||||||
|
symbols.push(new SymbolInformation(key, SymbolKind.Enum, enumerations[key]));
|
||||||
|
}
|
||||||
|
|
||||||
return symbols;
|
return symbols;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,8 @@ class GDScriptWorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider
|
|||||||
queryMembers(query, scrip.variables, vscode.SymbolKind.Variable, path);
|
queryMembers(query, scrip.variables, vscode.SymbolKind.Variable, path);
|
||||||
queryMembers(query, scrip.constants, vscode.SymbolKind.Constant, path);
|
queryMembers(query, scrip.constants, vscode.SymbolKind.Constant, path);
|
||||||
queryMembers(query, scrip.classes, vscode.SymbolKind.Class, path);
|
queryMembers(query, scrip.classes, vscode.SymbolKind.Class, path);
|
||||||
|
if(scrip.enumerations)
|
||||||
|
queryMembers(query, scrip.enumerations, vscode.SymbolKind.Enum, path);
|
||||||
}
|
}
|
||||||
return symbols;
|
return symbols;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ var glob = require("glob")
|
|||||||
import config from './config';
|
import config from './config';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
const cmd = require('node-cmd');
|
|
||||||
class ToolManager {
|
class ToolManager {
|
||||||
|
|
||||||
private workspaceDir: string = "";
|
private workspaceDir: string = "";
|
||||||
@@ -19,19 +18,30 @@ 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 = "project.godot";
|
||||||
|
private _rootDir : string = "";
|
||||||
|
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;
|
||||||
if(vscode.workspace && this.workspaceDir) {
|
let completionDollar = false;
|
||||||
vscode.workspace.registerTextDocumentContentProvider('godotdoc', new GDScriptDocumentContentProvider());
|
|
||||||
this.workspaceDir = this.workspaceDir.replace(/\\/g, "/");
|
if (vscode.workspace.getConfiguration("GodotTools").get("godotVersion", 3.0) < 3) {
|
||||||
this.loadWorkspaceSymbols();
|
this._projectFile = "engine.cfg";
|
||||||
}
|
this._biuitinDocFile = "doc/classes-2.1.json";
|
||||||
if(0) { // TODO: EditorServer validate
|
completionDollar = true;
|
||||||
this.validate();
|
|
||||||
}
|
}
|
||||||
this.loadClasses();
|
this.loadClasses();
|
||||||
|
|
||||||
|
if (vscode.workspace && this.workspaceDir) {
|
||||||
|
vscode.workspace.registerTextDocumentContentProvider('godotdoc', new GDScriptDocumentContentProvider());
|
||||||
|
this.workspaceDir = this.workspaceDir.replace(/\\/g, "/");
|
||||||
|
this._rootDir = vscode.workspace.getConfiguration("GodotTools").get("godotProjectRoot", this.workspaceDir);
|
||||||
|
this._rootDir = this._rootDir.replace("${workspaceRoot}", this.workspaceDir);
|
||||||
|
this.loadWorkspaceSymbols();
|
||||||
|
}
|
||||||
|
|
||||||
// documentation symbol provider
|
// documentation symbol provider
|
||||||
this.symbolprovider = new GDScriptSymbolProvider();
|
this.symbolprovider = new GDScriptSymbolProvider();
|
||||||
vscode.languages.registerDocumentSymbolProvider('gdscript', this.symbolprovider);
|
vscode.languages.registerDocumentSymbolProvider('gdscript', this.symbolprovider);
|
||||||
@@ -39,66 +49,82 @@ class ToolManager {
|
|||||||
this.workspacesymbolprovider = new GDScriptWorkspaceSymbolProvider();
|
this.workspacesymbolprovider = new GDScriptWorkspaceSymbolProvider();
|
||||||
vscode.languages.registerWorkspaceSymbolProvider(this.workspacesymbolprovider);
|
vscode.languages.registerWorkspaceSymbolProvider(this.workspacesymbolprovider);
|
||||||
// definition provider
|
// definition provider
|
||||||
vscode.languages.registerDefinitionProvider('gdscript', new GDScriptDefinitionProivder());
|
vscode.languages.registerDefinitionProvider('gdscript', new GDScriptDefinitionProivder(this._rootDir));
|
||||||
// hover provider
|
// hover provider
|
||||||
vscode.languages.registerHoverProvider('gdscript', new GDScriptHoverProvider());
|
vscode.languages.registerHoverProvider('gdscript', new GDScriptHoverProvider());
|
||||||
// code completion provider
|
// code completion provider
|
||||||
vscode.languages.registerCompletionItemProvider('gdscript', new GDScriptCompletionItemProvider(), '.', '"', "'");
|
if (completionDollar)
|
||||||
|
vscode.languages.registerCompletionItemProvider('gdscript', new GDScriptCompletionItemProvider(), '.', '"', "'", "$");
|
||||||
|
else
|
||||||
|
vscode.languages.registerCompletionItemProvider('gdscript', new GDScriptCompletionItemProvider(), '.', '"', "'");
|
||||||
// signature help provider
|
// signature help provider
|
||||||
vscode.languages.registerSignatureHelpProvider('gdscript', new GDScriptSignatureHelpProvider(), '(', ',');
|
vscode.languages.registerSignatureHelpProvider('gdscript', new GDScriptSignatureHelpProvider(), '(', ',');
|
||||||
// Commands
|
// Commands
|
||||||
this._disposable = vscode.Disposable.from(
|
this._disposable = vscode.Disposable.from(
|
||||||
vscode.commands.registerCommand('godot.updateWorkspaceSymbols', this.loadWorkspaceSymbols.bind(this)),
|
vscode.commands.registerCommand('godot.updateWorkspaceSymbols', this.loadWorkspaceSymbols.bind(this)),
|
||||||
vscode.commands.registerCommand('godot.runWorkspace', ()=>{this.openWorkspaceWithEditor()}),
|
vscode.commands.registerCommand('godot.runWorkspace', () => { this.openWorkspaceWithEditor() }),
|
||||||
vscode.commands.registerCommand('godot.openWithEditor', ()=>{this.openWorkspaceWithEditor("-e")}),
|
vscode.commands.registerCommand('godot.openWithEditor', () => { this.openWorkspaceWithEditor("-e") }),
|
||||||
vscode.commands.registerCommand('godot.runCurrentScene', this.runCurrentScenr.bind(this)),
|
vscode.commands.registerCommand('godot.runCurrentScene', this.runCurrentScene.bind(this)),
|
||||||
vscode.commands.registerCommand('godot.provideInitialDebugConfigurations', this.getDefaultDebugConfig.bind(this))
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
validate() {
|
validate() {
|
||||||
const self = this;
|
const self = this;
|
||||||
godotRequest({action: "editor", command: "projectdir"}).then((res: any)=>{
|
godotRequest({
|
||||||
|
action: "editor",
|
||||||
|
command: "projectdir"
|
||||||
|
}).then((res: any) => {
|
||||||
let path = res.path;
|
let path = res.path;
|
||||||
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");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
loadAllSymbols(): Promise<any> {
|
loadAllSymbols(): Promise < any > {
|
||||||
const self = this;
|
const self = this;
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
glob( self.workspaceDir +"/**/*.gd", (err, files)=>{
|
glob(self.workspaceDir + "/**/*.gd", (err, files) => {
|
||||||
if(!err) {
|
if (!err) {
|
||||||
const symbols = {};
|
const symbols = {};
|
||||||
for(let i=0; i< files.length; i++)
|
for (let i = 0; i < files.length; i++)
|
||||||
symbols[config.normalizePath(files[i])] = config.loadSymbolsFromFile(files[i]);
|
symbols[config.normalizePath(files[i])] = config.loadSymbolsFromFile(files[i]);
|
||||||
// load autoloads from engin.cfg
|
// load autoloads from engin.cfg
|
||||||
const engincfg = path.join(self.workspaceDir, "engine.cfg");
|
const engincfg = path.join(self.workspaceDir, this._projectFile);
|
||||||
if(fs.existsSync(engincfg) && fs.statSync(engincfg).isFile()) {
|
if (fs.existsSync(engincfg) && fs.statSync(engincfg).isFile()) {
|
||||||
try {
|
try {
|
||||||
const script = { constants: {}, functions: {}, variables: {}, signals: {}, classes: {}, base: "Object", native: "Object", constpathes: {}, documents: {}, constvalues: {}};
|
const script = {
|
||||||
|
constants: {},
|
||||||
|
functions: {},
|
||||||
|
variables: {},
|
||||||
|
signals: {},
|
||||||
|
classes: {},
|
||||||
|
base: "Object",
|
||||||
|
native: "Object",
|
||||||
|
constpathes: {},
|
||||||
|
documents: {},
|
||||||
|
constvalues: {}
|
||||||
|
};
|
||||||
let content: string = fs.readFileSync(engincfg, 'utf-8');
|
let content: string = fs.readFileSync(engincfg, 'utf-8');
|
||||||
if(content && content.indexOf("[autoload]") != -1) {
|
if (content && content.indexOf("[autoload]") != -1) {
|
||||||
content = content.substring(content.indexOf("[autoload]")+"[autoload]".length, content.length);
|
content = content.substring(content.indexOf("[autoload]") + "[autoload]".length, content.length);
|
||||||
content = content.substring(0, content.indexOf("["));
|
content = content.substring(0, content.indexOf("["));
|
||||||
const lines = content.split(/\r?\n/);
|
const lines = content.split(/\r?\n/);
|
||||||
lines.map((l)=>{
|
lines.map((l) => {
|
||||||
if(l.indexOf("=") != 0) {
|
if (l.indexOf("=") != 0) {
|
||||||
const name = l.substring(0, l.indexOf("="));
|
const name = l.substring(0, l.indexOf("="));
|
||||||
|
|
||||||
let gdpath = l.substring(l.indexOf("res://")+"res://".length, l.indexOf(".gd")+".gd".length);
|
let gdpath = l.substring(l.indexOf("res://") + "res://".length, l.indexOf(".gd") + ".gd".length);
|
||||||
gdpath = path.join( self.workspaceDir, 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);
|
||||||
@@ -114,106 +140,144 @@ class ToolManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolve(symbols);
|
resolve(symbols);
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadAllNodesInWorkspace() {
|
private loadAllNodesInWorkspace() {
|
||||||
glob( this.workspaceDir +"/**/*.tscn", (err, files)=>{
|
glob(this.workspaceDir + "/**/*.tscn", (err, files) => {
|
||||||
if(!err) {
|
if (!err) {
|
||||||
const symbols = {};
|
const symbols = {};
|
||||||
for(let i=0; i< files.length; i++)
|
for (let i = 0; i < files.length; i++)
|
||||||
config.loadScene(files[i]);
|
config.loadScene(files[i]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private loadWorkspaceSymbols() {
|
private loadWorkspaceSymbols() {
|
||||||
this.loadAllNodesInWorkspace();
|
let handle = this.showProgress("Loading symbols");
|
||||||
this.loadAllSymbols().then(symbols=>{
|
if (vscode.workspace.getConfiguration("GodotTools").get("parseTextScene", false)) {
|
||||||
vscode.window.showInformationMessage("Update GDScript symbols done");
|
this.loadAllNodesInWorkspace();
|
||||||
config.setAllSymbols(symbols);
|
}
|
||||||
}).catch(e=>{
|
this.loadAllSymbols().then(symbols => {
|
||||||
vscode.window.showWarningMessage("Update GDScript symbols failed");
|
handle();
|
||||||
|
vscode.window.setStatusBarMessage("$(check) Workspace symbols", 5000);
|
||||||
|
config.setAllSymbols(symbols);
|
||||||
|
}).catch(e => {
|
||||||
|
handle();
|
||||||
|
vscode.window.setStatusBarMessage("$(x) Workspace symbols", 5000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private openWorkspaceWithEditor(params="") {
|
private openWorkspaceWithEditor(params = "") {
|
||||||
let workspaceValid = false
|
let workspaceValid = false
|
||||||
if(this.workspaceDir) {
|
if (this.workspaceDir) {
|
||||||
let cfg = path.join(this.workspaceDir, "engine.cfg");
|
let cfg = path.join(this._rootDir, this._projectFile);
|
||||||
if( fs.existsSync(cfg) && fs.statSync(cfg).isFile())
|
console.log(cfg);
|
||||||
|
if (fs.existsSync(cfg) && fs.statSync(cfg).isFile())
|
||||||
workspaceValid = true;
|
workspaceValid = true;
|
||||||
}
|
}
|
||||||
if(workspaceValid)
|
if (workspaceValid) {
|
||||||
this.runEditor(`-path ${this.workspaceDir} ${params}`);
|
let pathFlag = "-path";
|
||||||
|
if (vscode.workspace.getConfiguration("GodotTools").get("godotVersion", 2.1) >= 3)
|
||||||
|
pathFlag = "--path";
|
||||||
|
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 = "") {
|
||||||
const editorPath = vscode.workspace.getConfiguration("GodotTools").get("editorPath", "")
|
let editorPath = vscode.workspace.getConfiguration("GodotTools").get("editorPath", "")
|
||||||
if(!fs.existsSync(editorPath) || !fs.statSync(editorPath).isFile()) {
|
editorPath = editorPath.replace("${workspaceRoot}", this.workspaceDir);
|
||||||
|
console.log(editorPath);
|
||||||
|
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 existingTerminal = vscode.window.terminals.find(t => t._name === "GodotTools")
|
||||||
cmd.run(`${editorPath} ${params}`);
|
if (existingTerminal) {
|
||||||
}
|
existingTerminal.dispose()
|
||||||
}
|
|
||||||
|
|
||||||
private runCurrentScenr() {
|
|
||||||
let scenePath = null
|
|
||||||
if(vscode.window.activeTextEditor)
|
|
||||||
scenePath = vscode.workspace.asRelativePath(vscode.window.activeTextEditor.document.uri);
|
|
||||||
if(scenePath.endsWith(".gd"))
|
|
||||||
scenePath = config.scriptSceneMap[config.normalizePath(scenePath)];
|
|
||||||
if(scenePath && (scenePath.endsWith(".tscn") || scenePath.endsWith(".scn"))) {
|
|
||||||
scenePath = ` res://${scenePath} `;
|
|
||||||
this.openWorkspaceWithEditor(scenePath);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
vscode.window.showErrorMessage("Current document is not a scene file");
|
|
||||||
}
|
|
||||||
|
|
||||||
private getDefaultDebugConfig() {
|
|
||||||
const editorPath = vscode.workspace.getConfiguration("GodotTools").get("editorPath", "")
|
|
||||||
if(this.workspaceDir) {
|
|
||||||
const config = {
|
|
||||||
version: '0.2.3',
|
|
||||||
configurations: [{
|
|
||||||
type: 'godot',
|
|
||||||
request: 'launch',
|
|
||||||
name: path.basename(this.workspaceDir),
|
|
||||||
godot: editorPath,
|
|
||||||
projectDir: "${workspaceRoot}",
|
|
||||||
params: [],
|
|
||||||
runWithEditor: false
|
|
||||||
}]
|
|
||||||
}
|
}
|
||||||
return JSON.stringify(config, null, '\t');
|
let terminal = vscode.window.createTerminal("GodotTools");
|
||||||
|
editorPath = this.escapeCmd(editorPath);
|
||||||
|
let cmmand = `${editorPath} ${params}`;
|
||||||
|
terminal.sendText(cmmand, true);
|
||||||
|
terminal.show();
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
vscode.window.showErrorMessage("Cannot create launch without godot project workspace");
|
|
||||||
return ""
|
private runCurrentScene() {
|
||||||
|
const absFilePath = vscode.window.activeTextEditor.document.uri.fsPath;
|
||||||
|
let scenePath = null
|
||||||
|
if (vscode.window.activeTextEditor) {
|
||||||
|
scenePath = path.relative(this._rootDir, absFilePath);
|
||||||
|
scenePath = scenePath.replace(/\\/g, "/");
|
||||||
}
|
}
|
||||||
|
// Run scripts directly which is inhired from SceneTree or MainLoop
|
||||||
|
if (scenePath.endsWith(".gd")) {
|
||||||
|
const scriptPath = scenePath;
|
||||||
|
scenePath = config.scriptSceneMap[config.normalizePath(scenePath)];
|
||||||
|
if (!scenePath) {
|
||||||
|
const script = config.loadSymbolsFromFile(absFilePath);
|
||||||
|
if (script) {
|
||||||
|
if(script.native == "SceneTree" || script.native == "MainLoop") {
|
||||||
|
this.runEditor(`-s "${absFilePath}"`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (scenePath) {
|
||||||
|
if (scenePath.endsWith(".gd"))
|
||||||
|
scenePath = ` -s "res://${scenePath}" `;
|
||||||
|
else
|
||||||
|
scenePath = ` "res://${scenePath}" `;
|
||||||
|
this.openWorkspaceWithEditor(scenePath);
|
||||||
|
} else
|
||||||
|
vscode.window.showErrorMessage("Current document is not a scene file or MainLoop");
|
||||||
}
|
}
|
||||||
|
|
||||||
loadClasses() {
|
loadClasses() {
|
||||||
let done :boolean = false;
|
let done: boolean = false;
|
||||||
if(this.workspaceDir)
|
if (this.workspaceDir)
|
||||||
done = config.loadClasses(path.join(this.workspaceDir, ".vscode", "classes.json"));
|
done = config.loadClasses(path.join(this.workspaceDir, ".vscode", "classes.json"));
|
||||||
if(!done)
|
if (!done)
|
||||||
done = config.loadClasses(path.join(this._context.extensionPath, "doc", "classes.json"));
|
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