diff --git a/package.json b/package.json index fe4426d90..a8a320a1e 100644 --- a/package.json +++ b/package.json @@ -149,19 +149,47 @@ { "category": "Godot Tools", "command": "godotTools.scenePreview.refresh", - "title": "Refresh Scene Preview" + "title": "Refresh Scene Preview", + "icon": { + "light": "resources/godot_icons/light/Reload.svg", + "dark": "resources/godot_icons/dark/Reload.svg" + } }, { "category": "Godot Tools", - "command": "godotTools.scenePreview.pin", - "title": "Pin Scene Preview", - "icon": "resources/pin_off.svg" + "command": "godotTools.scenePreview.openCurrentScene", + "title": "Open the Scene Preview's current scene", + "icon": { + "light": "resources/godot_icons/light/PackedScene.svg", + "dark": "resources/godot_icons/dark/PackedScene.svg" + } }, { "category": "Godot Tools", - "command": "godotTools.scenePreview.unpin", - "title": "Unpin Scene Preview", - "icon": "resources/pin_on.svg" + "command": "godotTools.scenePreview.openMainScript", + "title": "Open the main script of the Scene Preview's current scene", + "icon": { + "light": "resources/godot_icons/light/Script.svg", + "dark": "resources/godot_icons/dark/Script.svg" + } + }, + { + "category": "Godot Tools", + "command": "godotTools.scenePreview.lock", + "title": "Lock Scene Preview", + "icon": { + "light": "resources/godot_icons/light/Unlock.svg", + "dark": "resources/godot_icons/dark/Unlock.svg" + } + }, + { + "category": "Godot Tools", + "command": "godotTools.scenePreview.unlock", + "title": "Unlock Scene Preview", + "icon": { + "light": "resources/godot_icons/light/Lock.svg", + "dark": "resources/godot_icons/dark/Lock.svg" + } }, { "category": "Godot Tools", @@ -628,10 +656,6 @@ "command": "godotTools.listGodotClasses", "when": "godotTools.context.connectedToLSP" }, - { - "command": "godotTools.scenePreview.refresh", - "when": "false" - }, { "command": "godotTools.scenePreview.goToDefinition", "when": "false" @@ -640,14 +664,6 @@ "command": "godotTools.scenePreview.openDocumentation", "when": "false" }, - { - "command": "godotTools.scenePreview.pin", - "when": "false" - }, - { - "command": "godotTools.scenePreview.unpin", - "when": "false" - }, { "command": "godotTools.scenePreview.copyNodePath", "when": "false" @@ -693,14 +709,29 @@ "group": "navigation" }, { - "command": "godotTools.scenePreview.pin", - "when": "view == scenePreview && !godotTools.context.scenePreview.pinned", - "group": "navigation" + "command": "godotTools.scenePreview.lock", + "when": "view == scenePreview && !godotTools.context.scenePreview.locked", + "group": "navigation@1" }, { - "command": "godotTools.scenePreview.unpin", - "when": "view == scenePreview && godotTools.context.scenePreview.pinned", - "group": "navigation" + "command": "godotTools.scenePreview.unlock", + "when": "view == scenePreview && godotTools.context.scenePreview.locked", + "group": "navigation@1" + }, + { + "command": "godotTools.scenePreview.refresh", + "when": "view == scenePreview", + "group": "navigation@2" + }, + { + "command": "godotTools.scenePreview.openMainScript", + "when": "view == scenePreview", + "group": "navigation@3" + }, + { + "command": "godotTools.scenePreview.openCurrentScene", + "when": "view == scenePreview", + "group": "navigation@4" } ], "view/item/context": [ diff --git a/src/scene_tools/preview.ts b/src/scene_tools/preview.ts index aab4a9c5e..b9b1148ee 100644 --- a/src/scene_tools/preview.ts +++ b/src/scene_tools/preview.ts @@ -1,23 +1,23 @@ import * as vscode from "vscode"; import { - TreeDataProvider, - TreeDragAndDropController, - ExtensionContext, + type TreeDataProvider, + type TreeDragAndDropController, + type ExtensionContext, EventEmitter, - Event, - TreeView, - ProviderResult, - TreeItem, + type Event, + type TreeView, + type ProviderResult, + type TreeItem, TreeItemCollapsibleState, window, languages, - Uri, - CancellationToken, - FileDecoration, - DocumentDropEditProvider, + type Uri, + type CancellationToken, + type FileDecoration, + type DocumentDropEditProvider, workspace, } from "vscode"; -import * as fs from "fs"; +import * as fs from "node:fs"; import { get_configuration, find_file, @@ -28,15 +28,17 @@ import { make_docs_uri, } from "../utils"; import { SceneParser } from "./parser"; -import { SceneNode, Scene } from "./types"; +import type { SceneNode, Scene } from "./types"; const log = createLogger("scenes.preview"); -export class ScenePreviewProvider implements TreeDataProvider, TreeDragAndDropController, DocumentDropEditProvider { +export class ScenePreviewProvider + implements TreeDataProvider, TreeDragAndDropController, DocumentDropEditProvider +{ public dropMimeTypes = []; public dragMimeTypes = []; private tree: TreeView; - private scenePreviewPinned = false; + private scenePreviewLocked = false; private currentScene = ""; public parser = new SceneParser(); public scene: Scene; @@ -52,7 +54,7 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr constructor(private context: ExtensionContext) { this.tree = vscode.window.createTreeView("scenePreview", { treeDataProvider: this, - dragAndDropController: this + dragAndDropController: this, }); const selector = [ @@ -60,12 +62,14 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr { language: "gdscript", scheme: "file" }, ]; context.subscriptions.push( - register_command("scenePreview.pin", this.pin_preview.bind(this)), - register_command("scenePreview.unpin", this.unpin_preview.bind(this)), + register_command("scenePreview.lock", this.lock_preview.bind(this)), + register_command("scenePreview.unlock", this.unlock_preview.bind(this)), register_command("scenePreview.copyNodePath", this.copy_node_path.bind(this)), register_command("scenePreview.copyResourcePath", this.copy_resource_path.bind(this)), register_command("scenePreview.openScene", this.open_scene.bind(this)), register_command("scenePreview.openScript", this.open_script.bind(this)), + register_command("scenePreview.openCurrentScene", this.open_current_scene.bind(this)), + register_command("scenePreview.openCurrentScript", this.open_main_script.bind(this)), register_command("scenePreview.goToDefinition", this.go_to_definition.bind(this)), register_command("scenePreview.openDocumentation", this.open_documentation.bind(this)), register_command("scenePreview.refresh", this.refresh.bind(this)), @@ -82,12 +86,21 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr this.refresh(); } - public handleDrag(source: readonly SceneNode[], data: vscode.DataTransfer, token: vscode.CancellationToken): void | Thenable { + public handleDrag( + source: readonly SceneNode[], + data: vscode.DataTransfer, + token: vscode.CancellationToken, + ): void | Thenable { data.set("godot/path", new vscode.DataTransferItem(source[0].relativePath)); data.set("godot/class", new vscode.DataTransferItem(source[0].className)); } - public provideDocumentDropEdits(document: vscode.TextDocument, position: vscode.Position, dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): vscode.ProviderResult { + public provideDocumentDropEdits( + document: vscode.TextDocument, + position: vscode.Position, + dataTransfer: vscode.DataTransfer, + token: vscode.CancellationToken, + ): vscode.ProviderResult { const path = dataTransfer.get("godot/path").value; const className = dataTransfer.get("godot/class").value; @@ -106,7 +119,7 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr return; } setTimeout(async () => { - if (uri.fsPath == this.currentScene) { + if (uri.fsPath === this.currentScene) { this.refresh(); } else { const document = await vscode.workspace.openTextDocument(uri); @@ -116,7 +129,7 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr } public async refresh() { - if (this.scenePreviewPinned) { + if (this.scenePreviewLocked) { return; } @@ -128,7 +141,7 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr if (!fileName.endsWith(".tscn")) { const searchName = fileName.replace(".gd", ".tscn").replace(".cs", ".tscn"); - if (mode == "anyFolder") { + if (mode === "anyFolder") { const relatedScene = await find_file(searchName); if (!relatedScene) { return; @@ -136,14 +149,14 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr fileName = relatedScene.fsPath; } - if (mode == "sameFolder") { + if (mode === "sameFolder") { if (fs.existsSync(searchName)) { fileName = searchName; } else { return; } } - if (mode == "off") { + if (mode === "off") { return; } } @@ -162,20 +175,20 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr } } - private pin_preview() { - this.scenePreviewPinned = true; - set_context("scenePreview.pinned", true); + private lock_preview() { + this.scenePreviewLocked = true; + set_context("scenePreview.locked", true); } - private unpin_preview() { - this.scenePreviewPinned = false; - set_context("scenePreview.pinned", false); + private unlock_preview() { + this.scenePreviewLocked = false; + set_context("scenePreview.locked", false); this.refresh(); } private copy_node_path(item: SceneNode) { if (item.unique) { - vscode.env.clipboard.writeText("%" + item.label); + vscode.env.clipboard.writeText(`%${item.label}`); return; } vscode.env.clipboard.writeText(item.relativePath); @@ -201,6 +214,26 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr } } + private async open_current_scene() { + if (this.currentScene) { + const document = await vscode.workspace.openTextDocument(this.currentScene); + vscode.window.showTextDocument(document); + } + } + + private async open_main_script() { + if (this.currentScene) { + const root = this.scene.root; + if (root?.hasScript) { + const path = this.scene.externalResources[root.scriptId].path; + const uri = await convert_resource_path_to_uri(path); + 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); @@ -216,7 +249,6 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr private tree_selection_changed(event: vscode.TreeViewSelectionChangeEvent) { // const item = event.selection[0]; // log(item.body); - // const editor = vscode.window.activeTextEditor; // const range = editor.document.getText() // editor.revealRange(range) @@ -226,12 +258,10 @@ export class ScenePreviewProvider implements TreeDataProvider, TreeDr if (!element) { if (!this.scene?.root) { return Promise.resolve([]); - } else { - return Promise.resolve([this.scene?.root]); } - } else { - return Promise.resolve(element.children); + return Promise.resolve([this.scene?.root]); } + return Promise.resolve(element.children); } public getTreeItem(element: SceneNode): TreeItem | Thenable { @@ -254,13 +284,13 @@ class UniqueDecorationProvider implements vscode.FileDecorationProvider { return this.changeDecorationsEvent.event; } - constructor(private previewer: ScenePreviewProvider) { } + constructor(private previewer: ScenePreviewProvider) {} provideFileDecoration(uri: Uri, token: CancellationToken): FileDecoration | undefined { if (uri.scheme !== "godot") return undefined; const node = this.previewer.scene?.nodes.get(uri.path); - if (node && node.unique) { + if (node?.unique) { return { badge: "%", }; @@ -274,13 +304,13 @@ class ScriptDecorationProvider implements vscode.FileDecorationProvider { return this.changeDecorationsEvent.event; } - constructor(private previewer: ScenePreviewProvider) { } + constructor(private previewer: ScenePreviewProvider) {} provideFileDecoration(uri: Uri, token: CancellationToken): FileDecoration | undefined { if (uri.scheme !== "godot") return undefined; const node = this.previewer.scene?.nodes.get(uri.path); - if (node && node.hasScript) { + if (node?.hasScript) { return { badge: "S", };