Skip to content

Commit

Permalink
Added GSC side panel with "Workspace", "File" and "Other" views. It s…
Browse files Browse the repository at this point in the history
…hows information about workspace setup, parsed GSC files and available commands to run.
  • Loading branch information
eyza-cod2 committed Oct 17, 2024
1 parent 6a582d9 commit 85f88de
Show file tree
Hide file tree
Showing 9 changed files with 490 additions and 2 deletions.
9 changes: 9 additions & 0 deletions images/gsc-sidebar.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 26 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,32 @@
"path": "./syntaxes/gsc.tmLanguage.json"
}
],
"viewsContainers": {
"activitybar": [
{
"id": "gsc-sidebar",
"title": "GSC",
"icon": "images/gsc-sidebar.svg"
}
]
},
"views": {
"gsc-sidebar": [
{
"id": "gsc-view-workspace-info",
"name": "Workspace info"
},
{
"id": "gsc-view-file-info",
"name": "File info"
},
{
"id": "gsc-view-other",
"name": "Other",
"type": "webview"
}
]
},
"commands": [
{
"command": "gsc.selectGame",
Expand Down
15 changes: 14 additions & 1 deletion src/Events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as vscode from 'vscode';
import { GscConfig } from './GscConfig';
import { GscFiles } from './GscFiles';
import { GscStatusBar } from './GscStatusBar';
import { GscSidePanel } from './GscSidePanel';
import { GscFile } from './GscFile';
import { LoggerOutput } from './LoggerOutput';
import { Issues } from './Issues';
Expand Down Expand Up @@ -35,6 +36,7 @@ export class Events {

await GscFiles.onChangeWorkspaceFolders(e);

GscSidePanel.workspaceInfoProvider.refreshAll();
} catch (error) {
Issues.handleError(error);
}
Expand All @@ -61,6 +63,8 @@ export class Events {
LoggerOutput.log("[Events] Debounce done (250ms) - Active editor changed to " + e?.document.fileName);

await GscStatusBar.updateStatusBar("activeEditorChanged");

GscSidePanel.fileInfoProvider.refresh();
}, 250);

} catch (error) {
Expand Down Expand Up @@ -88,7 +92,10 @@ export class Events {
try {
//LoggerOutput.log("[Events] Editor selection changed.");

GscFiles.onChangeEditorSelection(e);
if (e.kind !== undefined) {
GscFiles.onChangeEditorSelection(e);
}

} catch (error) {
Issues.handleError(error);
}
Expand Down Expand Up @@ -152,6 +159,11 @@ export class Events {
LoggerOutput.log("[Events] GSC file parsed", vscode.workspace.asRelativePath(gscFile.uri));

this.onDidGscFileParsedEvent.fire(gscFile);

// Refresh the side panel if the active editor is the parsed file
if (gscFile.uri.toString() === vscode.window.activeTextEditor?.document.uri.toString()) {
GscSidePanel.fileInfoProvider.refresh();
}
}


Expand All @@ -172,5 +184,6 @@ export class Events {
static GscFileCacheFileHasChanged(fileUri: vscode.Uri) {
LoggerOutput.log("[Events] GSC cache changed for file", vscode.workspace.asRelativePath(fileUri));

GscSidePanel.workspaceInfoProvider.refreshCachedGscFiles(fileUri);
}
}
2 changes: 2 additions & 0 deletions src/Gsc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { GscStatusBar } from './GscStatusBar';
import { GscConfig } from './GscConfig';
import { GscCodeActionProvider } from './GscCodeActionProvider';
import { Issues } from './Issues';
import { GscSidePanel } from './GscSidePanel';
import { LoggerOutput } from './LoggerOutput';
import { Events } from './Events';

Expand All @@ -22,6 +23,7 @@ export class Gsc {

// Register events
try {
await GscSidePanel.activate(context);
await GscConfig.activate(context);
await GscDiagnosticsCollection.activate(context);
await GscFiles.activate(context);
Expand Down
3 changes: 2 additions & 1 deletion src/GscConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { LoggerOutput } from './LoggerOutput';
import { GscDiagnosticsCollection } from './GscDiagnosticsCollection';
import { GscFiles } from './GscFiles';
import { GscStatusBar } from './GscStatusBar';
import { Issues } from './Issues';
import { GscSidePanel } from './GscSidePanel';

// These must match with package.json settings
export enum GscGame {
Expand Down Expand Up @@ -125,6 +125,7 @@ export class GscConfig {
GscFiles.updateConfigurationOfCachedFiles();

// 2. Update tree view
GscSidePanel.workspaceInfoProvider.refreshIncludedWorkspaceFolders();

// 3. Update status bar in case the game has changed
await GscStatusBar.updateStatusBar("configChanged");
Expand Down
26 changes: 26 additions & 0 deletions src/GscSidePanel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import * as vscode from 'vscode';
import { LoggerOutput } from './LoggerOutput';
import { GscWorkspaceTreeDataProvider } from './GscSidePanelWorkspaceTreeDataProvider';
import { GscFileTreeDataProvider } from './GscSidePanelFileTreeDataProvider';
import { OtherViewProvider } from './GscSidePanelOtherViewProvider';

export class GscSidePanel {
public static fileInfoProvider: GscFileTreeDataProvider;
public static workspaceInfoProvider: GscWorkspaceTreeDataProvider;
public static otherViewProvider: OtherViewProvider;

// Activates the logger and registers the necessary disposal function
static async activate(context: vscode.ExtensionContext) {
LoggerOutput.log("[GscSidePanel] Activating");

this.fileInfoProvider = new GscFileTreeDataProvider();
context.subscriptions.push(vscode.window.registerTreeDataProvider("gsc-view-file-info", GscSidePanel.fileInfoProvider));

this.workspaceInfoProvider = new GscWorkspaceTreeDataProvider();
context.subscriptions.push(vscode.window.registerTreeDataProvider("gsc-view-workspace-info", GscSidePanel.workspaceInfoProvider));

this.otherViewProvider = new OtherViewProvider();
context.subscriptions.push(vscode.window.registerWebviewViewProvider("gsc-view-other", GscSidePanel.otherViewProvider));
}

}
88 changes: 88 additions & 0 deletions src/GscSidePanelFileTreeDataProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import * as vscode from 'vscode';
import { GscFiles } from './GscFiles';


interface GscTreeItemData {
label: string;
originalLabel?: string;
children?: GscTreeItemData[];
command?: vscode.Command;

icon?: vscode.ThemeIcon;
}

enum GscTreeItem {
ReferenceableGameRootFolders = 'Referenceable Game Root Folders',
IgnoredFilePaths = 'Ignored File Paths',
IgnoredFunctionNames = 'Ignored Function Names',
CurrentGame = 'Current Game',
ErrorDiagnostics = 'Error Diagnostics'
}


export class GscFileTreeDataProvider implements vscode.TreeDataProvider<GscTreeItemData> {
private _onDidChangeTreeData: vscode.EventEmitter<GscTreeItemData | undefined | void> = new vscode.EventEmitter<GscTreeItemData | undefined | void>();
readonly onDidChangeTreeData: vscode.Event<GscTreeItemData | undefined | void> = this._onDidChangeTreeData.event;

constructor() {
}

getTreeItem(element: GscTreeItemData): vscode.TreeItem {
const treeItem = new vscode.TreeItem(
element.label,
element.children ? this.getCollapsibleState(element.originalLabel || element.label) : vscode.TreeItemCollapsibleState.None
);

return treeItem;
}

getChildren(element?: GscTreeItemData): GscTreeItemData[] {

// Its a root element
if (!element) {

const editor = vscode.window.activeTextEditor;
const gscFile = editor ? GscFiles.getCachedFile(editor.document.uri) : undefined;

if (editor && gscFile) {

const referenceableGameRootFolders = gscFile.config.referenceableGameRootFolders.map((folder: any) => ({ label: vscode.workspace.asRelativePath(folder.uri, true) }));
const ignoredFilePaths = gscFile.config.ignoredFilePaths.map((path: string) => ({ label: path }));
const ignoredFunctionNames = gscFile.config.ignoredFunctionNames.map((name: string) => ({ label: name }));
const currentGame = [{ label: gscFile.config.currentGame }];
const errorDiagnostics = [{ label: gscFile.config.errorDiagnostics }];

return [
{ label: `${GscTreeItem.ReferenceableGameRootFolders} (${referenceableGameRootFolders.length})`, originalLabel: GscTreeItem.ReferenceableGameRootFolders, children: referenceableGameRootFolders },
{ label: `${GscTreeItem.IgnoredFilePaths} (${ignoredFilePaths.length})`, originalLabel: GscTreeItem.IgnoredFilePaths, children: ignoredFilePaths },
{ label: `${GscTreeItem.IgnoredFunctionNames} (${ignoredFunctionNames.length})`, originalLabel: GscTreeItem.IgnoredFunctionNames, children: ignoredFunctionNames },
{ label: `${GscTreeItem.CurrentGame} (${currentGame.length})`, originalLabel: GscTreeItem.CurrentGame, children: currentGame },
{ label: `${GscTreeItem.ErrorDiagnostics} (${errorDiagnostics.length})`, originalLabel: GscTreeItem.ErrorDiagnostics, children: errorDiagnostics }
];
}

return [
{ label: 'No active editor' }
];
}
return element.children || [];
}

refresh(): void {
this._onDidChangeTreeData.fire();
}

private getCollapsibleState(label: string): vscode.TreeItemCollapsibleState {
switch (label) {
case GscTreeItem.ReferenceableGameRootFolders:
case GscTreeItem.IgnoredFilePaths:
case GscTreeItem.IgnoredFunctionNames:
return vscode.TreeItemCollapsibleState.Expanded;
default:
return vscode.TreeItemCollapsibleState.Collapsed;
}
}
}



104 changes: 104 additions & 0 deletions src/GscSidePanelOtherViewProvider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import * as vscode from 'vscode';
import { GscFiles } from './GscFiles';
import { GscDiagnosticsCollection } from './GscDiagnosticsCollection';
import { Issues } from './Issues';
import { Updates } from './Updates';


export class OtherViewProvider implements vscode.WebviewViewProvider {

private _view?: vscode.WebviewView;

constructor() {
this.updateWebviewContent();
}

resolveWebviewView(webviewView: vscode.WebviewView) {
this._view = webviewView;
webviewView.webview.options = { enableScripts: true };
webviewView.webview.html = this.getHtmlContent();

webviewView.webview.onDidReceiveMessage(message => {
switch (message.command) {
case 'parseAllFiles':
void GscFiles.parseAllFiles();
break;
case 'reDiagnoseAllFiles':
void GscDiagnosticsCollection.updateDiagnosticsForAll("sidePanel");
break;
case 'reportIssue':
Issues.showIssueWindow(false);
break;
case 'showExtensionUpdates':
Updates.showUpdateWindow();
break;
}
});
}

// Update the webview content based on the current active editor
public updateWebviewContent() {
if (!this._view) {
return;
}
this._view.webview.html = this.getHtmlContent();

}

private getHtmlContent(): string {
return `<!DOCTYPE html>
<html lang="en">
<head>
<style>
button {
background-color: var(--vscode-button-background);
color: var(--vscode-button-foreground);
border: 1px solid var(--vscode-button-border, transparent);
border-radius: 2px;
padding: 4px;
cursor: pointer;
margin: 4px;
text-align: center;
line-height: 18px;
text-decoration: none;
width: 100%;
}
button:hover {
background-color: var(--vscode-button-hoverBackground);
}
p {
margin-bottom: 0;
}
</style>
</head>
<body>
<p>GSC Files:</p>
<button id="button1" class="codicon codicon-file">Parse all files</button><br>
<button id="button2">Re-diagnose all files</button><br>
<p>Issues:</p>
<button id="button3">Report an issue</button><br>
<p>Updates:</p>
<button id="button4">Show extension updates</button><br>
<script>
const vscode = acquireVsCodeApi();
document.getElementById('button1').addEventListener('click', () => {
vscode.postMessage({ command: 'parseAllFiles' });
});
document.getElementById('button2').addEventListener('click', () => {
vscode.postMessage({ command: 'reDiagnoseAllFiles' });
});
document.getElementById('button3').addEventListener('click', () => {
vscode.postMessage({ command: 'reportIssue' });
});
document.getElementById('button4').addEventListener('click', () => {
vscode.postMessage({ command: 'showExtensionUpdates' });
});
</script>
</body>
</html>`;
}

}
Loading

0 comments on commit 85f88de

Please sign in to comment.