mirror of
https://github.com/godotengine/godot-vscode-plugin.git
synced 2025-12-31 13:48:24 +03:00
Add scene preview panel (#413)
This commit is contained in:
128
package.json
128
package.json
@@ -96,6 +96,40 @@
|
||||
"dark": "resources/dark/icon_edit.svg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.refresh",
|
||||
"title": "Godot Tools: Refresh Scene Preview"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.pin",
|
||||
"title": "Pin Scene Preview",
|
||||
"icon": "resources/pin_off.svg"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.unpin",
|
||||
"title": "Unpin Scene Preview",
|
||||
"icon": "resources/pin_on.svg"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.goToDefinition",
|
||||
"title": "Go to Definition"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.copyNodePath",
|
||||
"title": "Copy Node Path"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.openScene",
|
||||
"title": "Open Scene"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.openScript",
|
||||
"title": "Open Script"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.switchSceneScript",
|
||||
"title": "Godot Tools: Switch Scene/Script"
|
||||
},
|
||||
{
|
||||
"command": "godot-tool.set_scene_file",
|
||||
"title": "Set as Scene File"
|
||||
@@ -109,6 +143,13 @@
|
||||
"title": "Godot Tools: Copy Resource Path"
|
||||
}
|
||||
],
|
||||
"keybindings": [
|
||||
{
|
||||
"command": "godotTools.switchSceneScript",
|
||||
"key": "alt+o",
|
||||
"when": "editorLangId == 'gdscript' && editorTextFocus || editorLangId == 'gdresource' && editorTextFocus"
|
||||
}
|
||||
],
|
||||
"configuration": {
|
||||
"type": "object",
|
||||
"title": "Godot Tools configuration",
|
||||
@@ -184,6 +225,20 @@
|
||||
],
|
||||
"default": "beside",
|
||||
"description": "Where to place the native symbol windows"
|
||||
},
|
||||
"godot_tools.scenePreview.previewRelatedScenes": {
|
||||
"enum": [
|
||||
"anyFolder",
|
||||
"sameFolder",
|
||||
"off"
|
||||
],
|
||||
"enumDescriptions": [
|
||||
"Attempt to preview a related scene from anywhere in the workspace.",
|
||||
"Attempt to preview a related scene from the same folder.",
|
||||
"Do not attempt to preview a related scene."
|
||||
],
|
||||
"default": "sameFolder",
|
||||
"description": "Controls where the Scene Preview will search for related scenes when viewing a script file."
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -337,6 +392,15 @@
|
||||
"language": "gdscript"
|
||||
}
|
||||
],
|
||||
"viewsContainers": {
|
||||
"activitybar": [
|
||||
{
|
||||
"id": "godotTools",
|
||||
"title": "Godot Tools",
|
||||
"icon": "resources/godot_icon.svg"
|
||||
}
|
||||
]
|
||||
},
|
||||
"views": {
|
||||
"debug": [
|
||||
{
|
||||
@@ -349,9 +413,37 @@
|
||||
"name": "Inspector",
|
||||
"when": "inDebugMode && debugType == 'godot'"
|
||||
}
|
||||
],
|
||||
"godotTools": [
|
||||
{
|
||||
"id": "scenePreview",
|
||||
"name": "Scene Preview"
|
||||
}
|
||||
]
|
||||
},
|
||||
"menus": {
|
||||
"commandPalette": [
|
||||
{
|
||||
"command": "godotTools.scenePreview.refresh",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.pin",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.unpin",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.copyNodePath",
|
||||
"when": "false"
|
||||
},
|
||||
{
|
||||
"command": "godot-tool.copy_resource_path_context",
|
||||
"when": "false"
|
||||
}
|
||||
],
|
||||
"view/title": [
|
||||
{
|
||||
"command": "godot-tool.debugger.refresh_scene_tree",
|
||||
@@ -362,6 +454,16 @@
|
||||
"command": "godot-tool.debugger.refresh_inspector",
|
||||
"when": "view == inspect-node",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.pin",
|
||||
"when": "view == scenePreview && !godotTools.context.scenePreviewPinned",
|
||||
"group": "navigation"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.unpin",
|
||||
"when": "view == scenePreview && godotTools.context.scenePreviewPinned",
|
||||
"group": "navigation"
|
||||
}
|
||||
],
|
||||
"view/item/context": [
|
||||
@@ -379,6 +481,25 @@
|
||||
"command": "godot-tool.debugger.edit_value",
|
||||
"when": "view == inspect-node && viewItem == editable_value",
|
||||
"group": "inline"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.goToDefinition",
|
||||
"when": "view == scenePreview",
|
||||
"group": "1@1"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.copyNodePath",
|
||||
"when": "view == scenePreview"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.openScene",
|
||||
"when": "view == scenePreview && viewItem =~ /PackedScene/",
|
||||
"group": "1@2"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.scenePreview.openScript",
|
||||
"when": "view == scenePreview && viewItem =~ /hasScript/",
|
||||
"group": "1@2"
|
||||
}
|
||||
],
|
||||
"explorer/context": [
|
||||
@@ -400,8 +521,13 @@
|
||||
"editor/context": [
|
||||
{
|
||||
"command": "godot-tool.open_type_documentation",
|
||||
"when": "godotTools.connectedToEditor",
|
||||
"when": "godotTools.context.connectedToEditor",
|
||||
"group": "navigation@9"
|
||||
},
|
||||
{
|
||||
"command": "godotTools.switchSceneScript",
|
||||
"when": "editorLangId == 'gdscript' || editorLangId == 'gdresource'",
|
||||
"group": "custom1@1"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
1
resources/InstanceOptions.svg
Normal file
1
resources/InstanceOptions.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" transform="translate(0 -1036.4)"><path d="m1 7v6c0 1.1046.89543 2 2 2h12v-8zm4 2h6l-3 4z" transform="translate(0 1036.4)"/><path d="m.71129 1040.4.28871 1.9791 2.2438-.3273-.81826-1.9018-1.7143.25zm3.6933-.5387.81826 1.9018 1.9791-.2887-.81826-1.9018zm3.9581-.5775.81826 1.9018 1.9791-.2887-.81826-1.9018zm3.9581-.5774.81826 1.9018 1.7143-.25-.28871-1.9791-2.2438.3273z"/></g></svg>
|
||||
|
After Width: | Height: | Size: 484 B |
121
resources/godot_icon.svg
Normal file
121
resources/godot_icon.svg
Normal file
@@ -0,0 +1,121 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
width="1024"
|
||||
height="1024"
|
||||
id="svg3030"
|
||||
version="1.1"
|
||||
inkscape:version="1.1 (c68e22c387, 2021-05-23)"
|
||||
sodipodi:docname="godot_icon.svg"
|
||||
inkscape:export-filename="/home/akien/Projects/godot/godot.git/icon.png"
|
||||
inkscape:export-xdpi="24"
|
||||
inkscape:export-ydpi="24"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/">
|
||||
<defs
|
||||
id="defs3032" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="0.8359375"
|
||||
inkscape:cx="511.40187"
|
||||
inkscape:cy="416.29907"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="g82-3"
|
||||
showgrid="false"
|
||||
inkscape:window-width="2560"
|
||||
inkscape:window-height="1377"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:document-rotation="0"
|
||||
inkscape:pagecheckerboard="0" />
|
||||
<metadata
|
||||
id="metadata3035">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-98.519719)"
|
||||
style="display:inline">
|
||||
<g
|
||||
id="g78"
|
||||
transform="matrix(4.162611,0,0,-4.162611,919.24059,771.67186)"
|
||||
style="display:none;stroke-width:0.320312">
|
||||
<path
|
||||
d="m 0,0 c 0,0 -0.325,1.994 -0.515,1.976 l -36.182,-3.491 c -2.879,-0.278 -5.115,-2.574 -5.317,-5.459 l -0.994,-14.247 -27.992,-1.997 -1.904,12.912 c -0.424,2.872 -2.932,5.037 -5.835,5.037 h -38.188 c -2.902,0 -5.41,-2.165 -5.834,-5.037 l -1.905,-12.912 -27.992,1.997 -0.994,14.247 c -0.202,2.886 -2.438,5.182 -5.317,5.46 l -36.2,3.49 c -0.187,0.018 -0.324,-1.978 -0.511,-1.978 l -0.049,-7.83 30.658,-4.944 1.004,-14.374 c 0.203,-2.91 2.551,-5.263 5.463,-5.472 l 38.551,-2.75 c 0.146,-0.01 0.29,-0.016 0.434,-0.016 2.897,0 5.401,2.166 5.825,5.038 l 1.959,13.286 h 28.005 l 1.959,-13.286 c 0.423,-2.871 2.93,-5.037 5.831,-5.037 0.142,0 0.284,0.005 0.423,0.015 l 38.556,2.75 c 2.911,0.209 5.26,2.562 5.463,5.472 l 1.003,14.374 30.645,4.966 z"
|
||||
style="fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312"
|
||||
id="path80"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
id="g82-3"
|
||||
transform="matrix(4.162611,0,0,-4.162611,104.69892,525.90697)"
|
||||
style="display:inline;stroke-width:0.320312">
|
||||
<path
|
||||
id="path84-6"
|
||||
style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.33333"
|
||||
d="m 417.61523,76.875 c -42.39201,9.424151 -84.32671,22.544942 -123.64257,42.33398 0.89912,34.71618 3.14362,67.97967 7.69336,101.76758 -15.26846,9.78214 -31.31507,18.17757 -45.57618,29.62891 -14.49005,11.14747 -29.2896,21.81231 -42.41015,34.84961 C 187.46773,268.1178 159.72502,251.82518 131.14453,237.44336 100.33705,270.59856 71.53124,306.38344 48,346.42773 c 18.493057,29.02877 38.32949,58.20569 56.69922,80.95899 v 197.7832 25.1211 22.86132 c 0.44956,0.004 0.89835,0.0209 1.34375,0.0625 l 150.66992,14.52735 c 7.89231,0.76176 14.07749,7.11449 14.62695,15.02343 l 4.64649,66.50977 131.42969,9.37891 9.05468,-61.38672 c 1.17386,-7.95891 8.00029,-13.85742 16.05078,-13.85742 h 158.96094 c 8.04633,0 14.87302,5.89851 16.04688,13.85742 l 9.05468,61.38672 131.4336,-9.37891 4.64258,-66.50977 c 0.55362,-7.90894 6.73464,-14.25751 14.62695,-15.02343 l 150.61133,-14.52735 c 0.4454,-0.0416 0.89028,-0.0583 1.33984,-0.0625 v -19.61132 l 0.0625,-0.0195 v -226.1348 c 21.2165,-26.70928 41.30684,-56.1715 56.69922,-80.95899 -23.52291,-40.04429 -52.34486,-75.82917 -83.15234,-108.98437 -28.57217,14.38182 -56.32515,30.67444 -82.53711,48.01172 -13.11639,-13.0373 -27.88953,-23.70214 -42.40039,-34.84961 -14.25695,-11.45134 -30.32318,-19.84677 -45.5625,-29.62891 4.53724,-33.78791 6.7803,-67.0514 7.68359,-101.76758 C 690.71123,99.419942 648.78198,86.299151 606.36914,76.875 c -16.9335,28.45977 -32.41939,59.27922 -45.90625,89.4082 -15.99275,-2.67239 -32.05995,-3.66203 -48.14844,-3.85351 v -0.0254 c -0.11239,0 -0.21676,0.0254 -0.3125,0.0254 -0.0999,0 -0.20478,-0.0254 -0.30468,-0.0254 v 0.0254 c -16.11763,0.19148 -32.17106,1.18112 -48.16797,3.85351 C 450.05076,136.15422 434.57371,105.33477 417.61523,76.875 Z M 298.41602,436.39844 c 50.15111,0 90.79882,40.61746 90.79882,90.75195 0,50.16779 -40.64771,90.80859 -90.79882,90.80859 -50.12617,0 -90.78711,-40.6408 -90.78711,-90.80859 0,-50.13449 40.66094,-90.75195 90.78711,-90.75195 z m 427.17773,0 c 50.122,0 90.7793,40.61746 90.7793,90.75195 0,50.16779 -40.6573,90.80859 -90.7793,90.80859 -50.15946,0 -90.80664,-40.6408 -90.80664,-90.80859 0,-50.13449 40.64718,-90.75195 90.80664,-90.75195 z m -213.59961,53.10937 c 16.14261,0 29.25391,11.90816 29.25391,26.56055 v 83.58984 c 0,14.66488 -13.1113,26.5625 -29.25391,26.5625 -16.1426,0 -29.22656,-11.89762 -29.22656,-26.5625 v -83.58984 c 0,-14.65239 13.08396,-26.56055 29.22656,-26.56055 z"
|
||||
transform="matrix(0.24023383,0,0,-0.24023383,-25.152223,102.67288)" />
|
||||
</g>
|
||||
<g
|
||||
id="g86-7"
|
||||
transform="matrix(4.162611,0,0,-4.162611,784.07144,817.24284)"
|
||||
style="display:inline;stroke-width:0.320312">
|
||||
<path
|
||||
d="m 0,0 -1.121,-16.063 c -0.135,-1.936 -1.675,-3.477 -3.611,-3.616 l -38.555,-2.751 c -0.094,-0.007 -0.188,-0.01 -0.281,-0.01 -1.916,0 -3.569,1.406 -3.852,3.33 l -2.211,14.994 H -81.09 l -2.211,-14.994 c -0.297,-2.018 -2.101,-3.469 -4.133,-3.32 l -38.555,2.751 c -1.936,0.139 -3.476,1.68 -3.611,3.616 L -130.721,0 -163.268,3.138 c 0.015,-3.498 0.06,-7.33 0.06,-8.093 0,-34.374 43.605,-50.896 97.781,-51.086 h 0.066 0.067 c 54.176,0.19 97.766,16.712 97.766,51.086 0,0.777 0.047,4.593 0.063,8.093 z"
|
||||
style="fill:#478cbf;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312"
|
||||
id="path88-5"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
id="g90-3"
|
||||
transform="matrix(4.162611,0,0,-4.162611,389.21484,625.67104)"
|
||||
style="display:none;stroke-width:0.320312" />
|
||||
<g
|
||||
id="g94-6"
|
||||
transform="matrix(4.162611,0,0,-4.162611,367.36686,631.05679)"
|
||||
style="display:none;stroke-width:0.320312">
|
||||
<path
|
||||
d="m 0,0 c 0,-7.994 -6.479,-14.473 -14.479,-14.473 -7.996,0 -14.479,6.479 -14.479,14.473 0,7.994 6.483,14.479 14.479,14.479 C -6.479,14.479 0,7.994 0,0"
|
||||
style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312"
|
||||
id="path96-2"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
<g
|
||||
id="g98-9"
|
||||
transform="matrix(4.162611,0,0,-4.162611,511.99336,724.73954)"
|
||||
style="display:inline;stroke-width:0.320312" />
|
||||
<g
|
||||
id="g102-2"
|
||||
transform="matrix(4.162611,0,0,-4.162611,634.78706,625.67104)"
|
||||
style="display:none;stroke-width:0.320312" />
|
||||
<g
|
||||
id="g106-0"
|
||||
transform="matrix(4.162611,0,0,-4.162611,656.64056,631.05679)"
|
||||
style="display:none;stroke-width:0.320312">
|
||||
<path
|
||||
d="m 0,0 c 0,-7.994 6.477,-14.473 14.471,-14.473 8.002,0 14.479,6.479 14.479,14.473 0,7.994 -6.477,14.479 -14.479,14.479 C 6.477,14.479 0,7.994 0,0"
|
||||
style="fill:#414042;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.320312"
|
||||
id="path108-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 7.7 KiB |
3
resources/pin_off.svg
Normal file
3
resources/pin_off.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m9 1.2715-.70703.70703v1.4141l-2.1211 2.123 4.2422 4.2422 2.1211-2.1211h1.4141l.70703-.70703-5.6562-5.6582zm-3.5352 4.9512-3.5352.70703 7.0703 7.0703.70703-3.5352-4.2422-4.2422zm-1.4141 4.2422-1.4141 1.4141-.70703 2.1211 2.1211-.70703 1.4141-1.4141-1.4141-1.4141z" fill="#858585" fill-opacity=".98824" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 424 B |
3
resources/pin_on.svg
Normal file
3
resources/pin_on.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="m9 1.2715-.70703.70703v1.4141l-2.1211 2.123 4.2422 4.2422 2.1211-2.1211h1.4141l.70703-.70703-5.6562-5.6582zm-3.5352 4.9512-3.5352.70703 7.0703 7.0703.70703-3.5352-4.2422-4.2422zm-1.4141 4.2422-1.4141 1.4141-.70703 2.1211 2.1211-.70703 1.4141-1.4141-1.4141-1.4141z" fill="#cccccc" fill-opacity=".98824" fill-rule="evenodd"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 424 B |
@@ -1,9 +1,10 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
import { GDDocumentLinkProvider } from "./document_link_provider";
|
||||
import { ScenePreviewProvider } from "./scene_preview_provider";
|
||||
import GDScriptLanguageClient, { ClientStatus } from "./lsp/GDScriptLanguageClient";
|
||||
import { get_configuration, set_configuration } from "./utils";
|
||||
import { get_configuration, set_configuration, find_file, set_context } from "./utils";
|
||||
|
||||
const CONFIG_CONTAINER = "godot_tools";
|
||||
const TOOL_NAME = "GodotTools";
|
||||
@@ -13,6 +14,7 @@ export class GodotTools {
|
||||
private context: vscode.ExtensionContext;
|
||||
private client: GDScriptLanguageClient = null;
|
||||
private linkProvider: GDDocumentLinkProvider = null;
|
||||
private scenePreviewManager: ScenePreviewProvider = null;
|
||||
|
||||
// deprecated, need to replace with "vscode.workspace.workspaceFolders", but
|
||||
// that's an array and not a single value
|
||||
@@ -29,7 +31,7 @@ export class GodotTools {
|
||||
this.connection_status = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right);
|
||||
|
||||
this.linkProvider = new GDDocumentLinkProvider(p_context);
|
||||
|
||||
|
||||
setInterval(() => {
|
||||
this.retry_callback();
|
||||
}, get_configuration("reconnect_cooldown", 3000));
|
||||
@@ -50,17 +52,20 @@ export class GodotTools {
|
||||
vscode.commands.registerCommand("godot-tool.copy_resource_path_context", this.copy_resource_path.bind(this));
|
||||
vscode.commands.registerCommand("godot-tool.copy_resource_path", this.copy_resource_path.bind(this));
|
||||
vscode.commands.registerCommand("godot-tool.open_type_documentation", this.open_type_documentation.bind(this));
|
||||
vscode.commands.registerCommand("godotTools.switchSceneScript", this.switch_scene_script.bind(this));
|
||||
|
||||
vscode.commands.executeCommand('setContext', 'godotTools.connectedToEditor', false);
|
||||
set_context("godotTools.context.connectedToEditor", false);
|
||||
|
||||
this.scenePreviewManager = new ScenePreviewProvider();
|
||||
|
||||
this.connection_status.text = "$(sync) Initializing";
|
||||
this.connection_status.command = "godot-tool.check_status";
|
||||
this.connection_status.show();
|
||||
|
||||
// TODO: maybe cache this result somehow
|
||||
const klaw = require('klaw');
|
||||
const klaw = require("klaw");
|
||||
klaw(this.workspace_dir)
|
||||
.on('data', item => {
|
||||
.on("data", item => {
|
||||
if (path.basename(item.path) == this.project_file_name) {
|
||||
this.project_dir = path.dirname(item.path);
|
||||
this.project_file = item.path;
|
||||
@@ -104,7 +109,7 @@ export class GodotTools {
|
||||
|
||||
let relative_path = path.normalize(path.relative(this.project_dir, uri.fsPath));
|
||||
relative_path = relative_path.split(path.sep).join(path.posix.sep);
|
||||
relative_path = 'res://' + relative_path;
|
||||
relative_path = "res://" + relative_path;
|
||||
|
||||
vscode.env.clipboard.writeText(relative_path);
|
||||
}
|
||||
@@ -120,6 +125,21 @@ export class GodotTools {
|
||||
this.client.open_documentation(symbolName);
|
||||
}
|
||||
|
||||
private async switch_scene_script() {
|
||||
let path = vscode.window.activeTextEditor.document.uri.fsPath;
|
||||
|
||||
if (path.endsWith(".tscn")) {
|
||||
path = path.replace(".tscn", ".gd");
|
||||
} else if (path.endsWith(".gd")) {
|
||||
path = path.replace(".gd", ".tscn");
|
||||
}
|
||||
|
||||
const file = await find_file(path);
|
||||
if (file) {
|
||||
vscode.window.showTextDocument(file);
|
||||
}
|
||||
}
|
||||
|
||||
private set_scene_file(uri: vscode.Uri) {
|
||||
let right_clicked_scene_path = uri.fsPath;
|
||||
let scene_config = get_configuration("scene_file_config");
|
||||
@@ -245,7 +265,7 @@ export class GodotTools {
|
||||
break;
|
||||
case ClientStatus.CONNECTED:
|
||||
this.retry = false;
|
||||
vscode.commands.executeCommand('setContext', 'godotTools.connectedToEditor', true);
|
||||
set_context("godotTools.context.connectedToEditor", true);
|
||||
this.connection_status.text = `$(check) Connected`;
|
||||
this.connection_status.tooltip = `Connected to the GDScript language server.`;
|
||||
if (!this.client.started) {
|
||||
@@ -257,7 +277,7 @@ export class GodotTools {
|
||||
this.connection_status.text = `$(sync) Connecting ` + this.reconnection_attempts;
|
||||
this.connection_status.tooltip = `Connecting to the GDScript language server...`;
|
||||
} else {
|
||||
vscode.commands.executeCommand('setContext', 'godotTools.connectedToEditor', false);
|
||||
set_context("godotTools.context.connectedToEditor", false);
|
||||
this.connection_status.text = `$(x) Disconnected`;
|
||||
this.connection_status.tooltip = `Disconnected from the GDScript language server.`;
|
||||
}
|
||||
@@ -294,11 +314,11 @@ export class GodotTools {
|
||||
let host = get_configuration("gdscript_lsp_server_host", "localhost");
|
||||
let port = get_configuration("gdscript_lsp_server_port", 6008);
|
||||
let message = `Couldn't connect to the GDScript language server at ${host}:${port}. Is the Godot editor running?`;
|
||||
vscode.window.showErrorMessage(message, 'Open Godot Editor', 'Retry', 'Ignore').then(item => {
|
||||
if (item == 'Retry') {
|
||||
vscode.window.showErrorMessage(message, "Open Godot Editor", "Retry", "Ignore").then(item => {
|
||||
if (item == "Retry") {
|
||||
this.reconnection_attempts = 0;
|
||||
this.client.connect_to_server();
|
||||
} else if (item == 'Open Godot Editor') {
|
||||
} else if (item == "Open Godot Editor") {
|
||||
this.client.status = ClientStatus.PENDING;
|
||||
this.open_workspace_with_editor("-e").then(() => {
|
||||
setTimeout(() => {
|
||||
|
||||
339
src/scene_preview_provider.ts
Normal file
339
src/scene_preview_provider.ts
Normal file
@@ -0,0 +1,339 @@
|
||||
import {
|
||||
TreeDataProvider,
|
||||
EventEmitter,
|
||||
Event,
|
||||
TreeView,
|
||||
ProviderResult,
|
||||
TreeItem,
|
||||
TreeItemCollapsibleState,
|
||||
} from "vscode";
|
||||
import path = require("path");
|
||||
import fs = require("fs");
|
||||
import * as vscode from "vscode";
|
||||
import { get_configuration, set_configuration, find_file, set_context, convert_resource_path_to_uri } from "./utils";
|
||||
import logger from "./logger";
|
||||
|
||||
function log(...messages) {
|
||||
logger.log("[scene preview]", messages);
|
||||
}
|
||||
|
||||
export class ScenePreviewProvider implements TreeDataProvider<SceneNode> {
|
||||
private root: SceneNode | undefined;
|
||||
private tree: TreeView<SceneNode>;
|
||||
private scenePreviewPinned = false;
|
||||
private currentScene = "";
|
||||
private externalResources = {};
|
||||
|
||||
private changeEvent = new EventEmitter<void>();
|
||||
|
||||
public get onDidChangeTreeData(): Event<void> {
|
||||
return this.changeEvent.event;
|
||||
}
|
||||
|
||||
public async refresh() {
|
||||
if (this.scenePreviewPinned) {
|
||||
return;
|
||||
}
|
||||
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (editor) {
|
||||
let fileName = editor.document.uri.fsPath;
|
||||
const mode = get_configuration("scenePreview.previewRelatedScenes");
|
||||
|
||||
if (!fileName.endsWith(".tscn")) {
|
||||
const searchName = fileName.replace(".gd", ".tscn");
|
||||
|
||||
if (mode == "anyFolder") {
|
||||
const relatedScene = await find_file(searchName);
|
||||
if (!relatedScene) {
|
||||
return;
|
||||
}
|
||||
fileName = relatedScene.fsPath;
|
||||
}
|
||||
|
||||
if (mode == "sameFolder") {
|
||||
if (fs.existsSync(searchName)) {
|
||||
fileName = searchName;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mode == "off") {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.currentScene == fileName) {
|
||||
return;
|
||||
}
|
||||
await this.parse_scene(fileName);
|
||||
this.changeEvent.fire();
|
||||
}
|
||||
}
|
||||
|
||||
constructor() {
|
||||
this.tree = vscode.window.createTreeView("scenePreview", {
|
||||
treeDataProvider: this,
|
||||
});
|
||||
|
||||
this.tree.onDidChangeSelection(this.tree_selection_changed);
|
||||
|
||||
vscode.commands.registerCommand("godotTools.scenePreview.pin", this.pin_preview.bind(this));
|
||||
vscode.commands.registerCommand("godotTools.scenePreview.unpin", this.unpin_preview.bind(this));
|
||||
vscode.commands.registerCommand("godotTools.scenePreview.copyNodePath", this.copy_node_path.bind(this));
|
||||
vscode.commands.registerCommand("godotTools.scenePreview.openScene", this.open_scene.bind(this));
|
||||
vscode.commands.registerCommand("godotTools.scenePreview.openScript", this.open_script.bind(this));
|
||||
vscode.commands.registerCommand("godotTools.scenePreview.goToDefinition", this.go_to_definition.bind(this));
|
||||
|
||||
vscode.commands.registerCommand("godotTools.scenePreview.refresh", () =>
|
||||
this.refresh()
|
||||
);
|
||||
|
||||
vscode.window.onDidChangeActiveTextEditor(() => {
|
||||
vscode.commands.executeCommand("godotTools.scenePreview.refresh");
|
||||
});
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
private pin_preview() {
|
||||
this.scenePreviewPinned = true;
|
||||
set_context("godotTools.context.scenePreviewPinned", true);
|
||||
}
|
||||
|
||||
private unpin_preview() {
|
||||
this.scenePreviewPinned = false;
|
||||
set_context("godotTools.context.scenePreviewPinned", false);
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
private copy_node_path(item: SceneNode) {
|
||||
if (item.unique) {
|
||||
vscode.env.clipboard.writeText("%" + item.label);
|
||||
return;
|
||||
}
|
||||
vscode.env.clipboard.writeText(item.relativePath);
|
||||
}
|
||||
|
||||
private async open_scene(item: SceneNode) {
|
||||
const uri = await convert_resource_path_to_uri(item.resourcePath);
|
||||
if (uri) {
|
||||
vscode.window.showTextDocument(uri, {preview:true});
|
||||
}
|
||||
}
|
||||
|
||||
private async open_script(item: SceneNode) {
|
||||
const id = this.externalResources[item.scriptId].path;
|
||||
|
||||
const uri = await convert_resource_path_to_uri(id);
|
||||
if (uri) {
|
||||
vscode.window.showTextDocument(uri, {preview:true});
|
||||
}
|
||||
}
|
||||
|
||||
private async go_to_definition(item: SceneNode) {
|
||||
const document = await vscode.workspace.openTextDocument(this.currentScene);
|
||||
const start = document.positionAt(item.position);
|
||||
const end = document.positionAt(item.position + item.text.length);
|
||||
const range = new vscode.Range(start, end);
|
||||
vscode.window.showTextDocument(document, {selection:range});
|
||||
}
|
||||
|
||||
private tree_selection_changed(event:vscode.TreeViewSelectionChangeEvent<SceneNode>) {
|
||||
// const item = event.selection[0];
|
||||
// log(item.body);
|
||||
|
||||
// const editor = vscode.window.activeTextEditor;
|
||||
// const range = editor.document.getText()
|
||||
// editor.revealRange(range)
|
||||
}
|
||||
|
||||
public async parse_scene(scene: string) {
|
||||
this.currentScene = scene;
|
||||
this.tree.message = path.basename(scene);
|
||||
|
||||
const document = await vscode.workspace.openTextDocument(scene);
|
||||
const text = document.getText();
|
||||
|
||||
this.externalResources = {};
|
||||
|
||||
const resourceRegex = /\[ext_resource path="([\w.:/]*)" type="([\w]*)" id=([0-9]*)/g;
|
||||
for (const match of text.matchAll(resourceRegex)) {
|
||||
let path = match[1];
|
||||
let type = match[2];
|
||||
let id = match[3];
|
||||
this.externalResources[id] = {
|
||||
path: path,
|
||||
type: type,
|
||||
id: id,
|
||||
};
|
||||
}
|
||||
|
||||
let root = "";
|
||||
let nodes = {};
|
||||
let lastNode = null;
|
||||
|
||||
const nodeRegex = /\[node name="([\w]*)"(?: type="([\w]*)")?(?: parent="([\w\/.]*)")?(?: instance=ExtResource\( ([\w\.]*) \))?\]/g;
|
||||
for (const match of text.matchAll(nodeRegex)) {
|
||||
let name = match[1];
|
||||
let type = match[2] ? match[2] : "PackedScene";
|
||||
let parent = match[3];
|
||||
let instance = match[4] ? match[4] : 0;
|
||||
let path = "";
|
||||
let relativePath = "";
|
||||
|
||||
if (parent == undefined) {
|
||||
root = name;
|
||||
path = name;
|
||||
} else if (parent == ".") {
|
||||
parent = root;
|
||||
relativePath = name;
|
||||
path = parent + "/" + name;
|
||||
} else {
|
||||
relativePath = parent + "/" + name;
|
||||
parent = root + "/" + parent;
|
||||
path = parent + "/" + name;
|
||||
}
|
||||
if (lastNode) {
|
||||
lastNode.body = text.slice(lastNode.position, match.index);
|
||||
lastNode.parse_body();
|
||||
}
|
||||
|
||||
let node = new SceneNode(name, type, 0, []);
|
||||
node.path = path;
|
||||
node.description = type;
|
||||
node.relativePath = relativePath;
|
||||
node.parent = parent;
|
||||
node.text = match[0];
|
||||
node.position = match.index;
|
||||
if (instance) {
|
||||
node.tooltip = this.externalResources[instance].path;
|
||||
node.resourcePath = this.externalResources[instance].path;
|
||||
node.contextValue = "PackedScene";
|
||||
}
|
||||
if (path == root) {
|
||||
this.root = node;
|
||||
}
|
||||
if (parent in nodes) {
|
||||
nodes[parent].children.push(node);
|
||||
}
|
||||
nodes[path] = node;
|
||||
|
||||
lastNode = node;
|
||||
}
|
||||
|
||||
lastNode.body = text.slice(lastNode.position, text.length);
|
||||
lastNode.parse_body();
|
||||
}
|
||||
|
||||
public getChildren(element?: SceneNode): ProviderResult<SceneNode[]> {
|
||||
if (!element) {
|
||||
if (!this.root) {
|
||||
return Promise.resolve([]);
|
||||
} else {
|
||||
return Promise.resolve([this.root]);
|
||||
}
|
||||
} else {
|
||||
return Promise.resolve(element.children);
|
||||
}
|
||||
}
|
||||
|
||||
public getTreeItem(element: SceneNode): TreeItem | Thenable<TreeItem> {
|
||||
if (element.children.length > 0) {
|
||||
element.collapsibleState = TreeItemCollapsibleState.Expanded;
|
||||
} else {
|
||||
element.collapsibleState = TreeItemCollapsibleState.None;
|
||||
}
|
||||
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
function match_icon_to_class(class_name: string) {
|
||||
let icon_name = `icon${class_name
|
||||
.replace(/(2|3)D/, "$1d")
|
||||
.replace(/([A-Z0-9])/g, "_$1")
|
||||
.toLowerCase()}.svg`;
|
||||
return icon_name;
|
||||
}
|
||||
|
||||
export class SceneNode extends TreeItem {
|
||||
public path: string;
|
||||
public relativePath: string;
|
||||
public resourcePath: string;
|
||||
public parent: string;
|
||||
public text: string;
|
||||
public position: number;
|
||||
public body: string;
|
||||
public unique: boolean = false;
|
||||
public hasScript: boolean = false;
|
||||
public scriptId: string;
|
||||
|
||||
constructor(
|
||||
public label: string,
|
||||
public class_name: string,
|
||||
public object_id: number,
|
||||
public children: SceneNode[],
|
||||
public collapsibleState?: TreeItemCollapsibleState
|
||||
) {
|
||||
super(label, collapsibleState);
|
||||
|
||||
const iconDir = path.join(__filename, "..", "..", "resources");
|
||||
|
||||
if (class_name == "PackedScene") {
|
||||
this.iconPath = path.join(iconDir, "InstanceOptions.svg");
|
||||
return;
|
||||
}
|
||||
|
||||
const iconName = match_icon_to_class(class_name);
|
||||
|
||||
let light = path.join(iconDir, "light", iconName);
|
||||
if (!fs.existsSync(light)) {
|
||||
light = path.join(iconDir, "light", "node.svg");
|
||||
}
|
||||
let dark = path.join(iconDir, "dark", iconName);
|
||||
if (!fs.existsSync(dark)) {
|
||||
dark = path.join(iconDir, "dark", "node.svg");
|
||||
}
|
||||
|
||||
this.iconPath = {
|
||||
light: light,
|
||||
dark: dark,
|
||||
};
|
||||
}
|
||||
|
||||
public parse_body() {
|
||||
const lines = this.body.split("\n");
|
||||
let newLines = [];
|
||||
let tags = [];
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let line = lines[i];
|
||||
if (line.startsWith("tile_data")) {
|
||||
line = "tile_data = PoolIntArray(...)";
|
||||
}
|
||||
if (line.startsWith("unique_name_in_owner = true")) {
|
||||
tags.push("%");
|
||||
this.unique = true;
|
||||
}
|
||||
if (line.startsWith("script = ExtResource")) {
|
||||
tags.push("S");
|
||||
this.hasScript = true;
|
||||
this.scriptId = line.match(/script = ExtResource\( ([0-9]+) \)/)[1];
|
||||
this.contextValue += "hasScript";
|
||||
}
|
||||
if (line != "") {
|
||||
newLines.push(line);
|
||||
}
|
||||
}
|
||||
this.body = newLines.join("\n");
|
||||
|
||||
let prefix = ""
|
||||
if (tags.length != 0) {
|
||||
prefix = tags.join(" ") + " | "
|
||||
}
|
||||
this.description = prefix + this.description;
|
||||
const content = new vscode.MarkdownString();
|
||||
content.appendCodeblock(this.body, "gdresource");
|
||||
this.tooltip = content;
|
||||
}
|
||||
}
|
||||
28
src/utils.ts
28
src/utils.ts
@@ -1,4 +1,6 @@
|
||||
import * as vscode from "vscode";
|
||||
import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
|
||||
const CONFIG_CONTAINER = "godot_tools";
|
||||
|
||||
@@ -13,3 +15,29 @@ export function set_configuration(name: string, value: any) {
|
||||
export function is_debug_mode(): boolean {
|
||||
return process.env.VSCODE_DEBUG_MODE === "true";
|
||||
}
|
||||
|
||||
export function set_context(name: string, value: any) {
|
||||
vscode.commands.executeCommand("setContext", name, value);
|
||||
}
|
||||
|
||||
export async function find_file(file: string): Promise<vscode.Uri|null> {
|
||||
if (fs.existsSync(file)) {
|
||||
return vscode.Uri.file(file);
|
||||
} else {
|
||||
const fileName = path.basename(file);
|
||||
const results = await vscode.workspace.findFiles("**/" + fileName);
|
||||
if (results.length == 1) {
|
||||
return results[0];
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export async function convert_resource_path_to_uri(resPath: string): Promise<vscode.Uri|null> {
|
||||
const files = await vscode.workspace.findFiles("**/project.godot");
|
||||
if (!files) {
|
||||
return null;
|
||||
}
|
||||
const project_dir = files[0].fsPath.replace("project.godot", "");
|
||||
return vscode.Uri.joinPath(vscode.Uri.file(project_dir), resPath.substring(6));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user