diff --git a/README.md b/README.md index 218e9ca..158bd1f 100644 --- a/README.md +++ b/README.md @@ -150,6 +150,17 @@ end ## Configuration +### Only use plugin in specific workspaces + +The plugin can be configured to only run inside specific workspaces, instead of globally. + +To do this, go to `settings` > `extienstions` and find the SL Scipting settings, +and uncheck the `Enabled` setting. + +Then in any workspace you want to use the plugin in, you can either manually set the +`Enabled` setting at the workspace level, or open the command pallete and run the +`Second Life: Enable Extension for Workspace` command. + ### Preprocessor Settings Configure preprocessing behavior in VS Code settings: diff --git a/src/interfaces/hostinterface.ts b/src/interfaces/hostinterface.ts index 82cf198..2245c86 100644 --- a/src/interfaces/hostinterface.ts +++ b/src/interfaces/hostinterface.ts @@ -44,6 +44,9 @@ export function splitFilename(filename: NormalizedPath): { basepath: string; fil export interface HostInterface { /** Central configuration provider (framework-agnostic). */ config: FullConfigInterface; + + existsInSameWorkspace(knownPath:string, desiredPath:string): Promise; + exists(p: NormalizedPath, unsafe?: boolean): Promise; resolveFile( filename: string, // raw filename from directive diff --git a/src/pluginsupport.ts b/src/pluginsupport.ts index 99e7ccf..e50eb25 100644 --- a/src/pluginsupport.ts +++ b/src/pluginsupport.ts @@ -186,7 +186,7 @@ export class LuaLSPPlugin extends BasePlugin { await luaulsp.update("types.documentationFiles", [docsFile]); await luaulsp.update("platform.type", "standard"); await luaulsp.update("sourcemap.enabled", false); - await new Promise((resolve) => setTimeout(resolve, 100)); + await new Promise((resolve) => setTimeout(resolve, 1000)); // Execute luau-lsp's command to realod the language sever await vscode.commands.executeCommand("luau-lsp.reloadServer") } diff --git a/src/scriptsync.ts b/src/scriptsync.ts index 240edf3..fe3de22 100644 --- a/src/scriptsync.ts +++ b/src/scriptsync.ts @@ -25,7 +25,7 @@ import { } from "./utils"; import { ScriptLanguage } from "./shared/languageservice"; import { CompilationResult, RuntimeDebug, RuntimeError } from "./viewereditwsclient"; -import { normalizePath } from "./interfaces/hostinterface"; +import { HostInterface, normalizePath } from "./interfaces/hostinterface"; import { SynchService } from "./synchservice"; import { IncludeInfo } from "./shared/parser"; import { sha256 } from "js-sha256"; @@ -51,6 +51,7 @@ export class ScriptSync implements vscode.Disposable { private diagnosticSources: Set = new Set(); private lineMappings?: LineMapping[]; private config: ConfigService; + private host: HostInterface; private includedFiles : IncludeInfo[] = []; @@ -61,6 +62,7 @@ export class ScriptSync implements vscode.Disposable { config: ConfigService, scriptId?: string, viewerDocument?: vscode.TextDocument, + host?: HostInterface, ) { this.config = config; @@ -69,10 +71,12 @@ export class ScriptSync implements vscode.Disposable { this.macros = new MacroProcessor(this.language); this.initializeSystemMacros(language); + this.host = host ?? new VSCodeHost(); + // Initialize preprocessor with macro processor const enabled = config.getConfig(ConfigKey.PreprocessorEnable) ?? true; if (enabled) { - this.preprocessor = new LexingPreprocessor(new VSCodeHost(), config, this.macros); + this.preprocessor = new LexingPreprocessor(this.host, config, this.macros); } this.masterDocument = masterDocument; diff --git a/src/server/nodehost.ts b/src/server/nodehost.ts index 3b3fdde..378bd4d 100644 --- a/src/server/nodehost.ts +++ b/src/server/nodehost.ts @@ -57,6 +57,10 @@ export class NodeHost implements HostInterface { }; } + existsInSameWorkspace(_knownPath: string, _desiredPath: string): Promise { + throw new Error('Method not implemented.'); + } + // --------------------------------------------------------------------- async exists(p: NormalizedPath, _unsafe?: boolean): Promise { try { diff --git a/src/synchservice.ts b/src/synchservice.ts index 68a7698..c251b8c 100644 --- a/src/synchservice.ts +++ b/src/synchservice.ts @@ -27,11 +27,13 @@ import { showWarningMessage, closeEditor, logInfo, + VSCodeHost, } from "./utils"; import { maybe } from "./shared/sharedutils"; // TODO: migrate needed utilities from sharedutils if required import { ScriptLanguage, LanguageService } from "./shared/languageservice"; import { ScriptSync } from "./scriptsync"; import { LANGUAGE_CONFIGS } from "./shared/lexer"; +import { HostInterface } from "./interfaces/hostinterface"; type ParsedTempFile = { scriptName: string; scriptId: string; extension: string, language: ScriptLanguage}; @@ -45,6 +47,8 @@ export class SynchService implements vscode.Disposable { private handshakePromise?: Promise<{ success: boolean; message: string }>; private lastActiveChange: number = 0; private activeSync: ScriptSync | undefined; + private host: HostInterface; + private initialGenerationDone: boolean = false; public viewerName?: string; public viewerVersion?: string; @@ -58,6 +62,7 @@ export class SynchService implements vscode.Disposable { private constructor(context: vscode.ExtensionContext) { this.context = context; + this.host = new VSCodeHost(); } public static getInstance(context?: vscode.ExtensionContext): SynchService { @@ -116,8 +121,6 @@ export class SynchService implements vscode.Disposable { this.onChangeActiveTextEditor(editor), ); - this.initializeSyntax(); - // TODO: Figure out why restart isn't working on the luau-lsp server // TODO: Bug when prepping language syntax on download // const syntaxInit = this.initializeSyntax(); @@ -217,6 +220,7 @@ export class SynchService implements vscode.Disposable { config, parsed.scriptId, viewerDocument, + this.host, ); this.activeSyncs.set(masterPath, sync); } @@ -662,9 +666,17 @@ export class SynchService implements vscode.Disposable { //#region Event handlers private async onOpenTextDocument(document: vscode.TextDocument): Promise { this.lastActiveChange = 0; + this.initialDefinitionGeneration(document); await this.setupSync(document); } + private async initialDefinitionGeneration(document: vscode.TextDocument) : Promise { + if(this.initialGenerationDone) return; + if(!document.uri.fsPath.endsWith(".luau")) return; + this.initialGenerationDone = true; + this.initializeSyntax(); + } + private onCloseTextDocument(document: vscode.TextDocument): void { const filePath = path.normalize(document.fileName); this.removeSync(filePath, false); diff --git a/src/test/suite/diagnostic-integration.test.ts b/src/test/suite/diagnostic-integration.test.ts index 0b3c1d8..b4d3e09 100644 --- a/src/test/suite/diagnostic-integration.test.ts +++ b/src/test/suite/diagnostic-integration.test.ts @@ -152,6 +152,9 @@ function createMockHostWithFiles(files: Map, options?: Preproces async writeTOML(p: NormalizedPath, data: Record): Promise { return false; }, + async existsInSameWorkspace(knownPath: string, desiredPath: string): Promise { + return false; + }, fileNameToUri(fileName: NormalizedPath): string { // Strip path to only include directories/filename after "test" directory const testIndex = fileName.indexOf('test'); diff --git a/src/test/suite/include-disk-integration.test.ts b/src/test/suite/include-disk-integration.test.ts index f5febb5..1deebe0 100644 --- a/src/test/suite/include-disk-integration.test.ts +++ b/src/test/suite/include-disk-integration.test.ts @@ -136,6 +136,10 @@ class DiskTestHost implements HostInterface { return null; } + async existsInSameWorkspace(knownPath: string, desiredPath: string): Promise { + return false; + } + async readYAML(p: NormalizedPath): Promise { return null; } diff --git a/src/test/suite/lexingpreprocessor.test.ts b/src/test/suite/lexingpreprocessor.test.ts index 0871258..3ef77ee 100644 --- a/src/test/suite/lexingpreprocessor.test.ts +++ b/src/test/suite/lexingpreprocessor.test.ts @@ -120,6 +120,9 @@ suite("Lexing Preprocessor Test Suite", () => { async writeTOML(p: NormalizedPath, data: Record): Promise { return false; } + async existsInSameWorkspace(knownPath: string, desiredPath: string): Promise { + return false; + } fileNameToUri(fileName: NormalizedPath): string { // Strip path to only include directories/filename after "test" directory const testIndex = fileName.indexOf('test'); @@ -183,6 +186,9 @@ suite("Lexing Preprocessor Test Suite", () => { async writeTOML(p: NormalizedPath, data: Record): Promise { return false; } + async existsInSameWorkspace(knownPath: string, desiredPath: string): Promise { + return false; + } fileNameToUri(fileName: NormalizedPath): string { // Strip path to only include directories/filename after "test" directory const testIndex = fileName.indexOf('test'); diff --git a/src/test/suite/parse-line-mappings.test.ts b/src/test/suite/parse-line-mappings.test.ts index 99e2b09..73b6777 100644 --- a/src/test/suite/parse-line-mappings.test.ts +++ b/src/test/suite/parse-line-mappings.test.ts @@ -53,6 +53,9 @@ suite('Parse Line Mappings Tests', () => { async writeTOML(p: NormalizedPath, data: Record): Promise { return false; } + async existsInSameWorkspace(knownPath: string, desiredPath: string): Promise { + return false; + } fileNameToUri(fileName: NormalizedPath): string { // Strip path to only include directories/filename after "test" directory const testIndex = fileName.indexOf('test'); diff --git a/src/test/suite/parser.test.ts b/src/test/suite/parser.test.ts index e4ee52b..e2d640a 100644 --- a/src/test/suite/parser.test.ts +++ b/src/test/suite/parser.test.ts @@ -52,6 +52,9 @@ suite('Parser Tests', () => { async writeTOML(p: NormalizedPath, data: Record): Promise { return false; } + async existsInSameWorkspace(knownPath: string, desiredPath: string): Promise { + return false; + } fileNameToUri(fileName: NormalizedPath): string { // Strip path to only include directories/filename after "test" directory const testIndex = fileName.indexOf('test'); diff --git a/src/test/suite/require-table.test.ts b/src/test/suite/require-table.test.ts index 6a5a0e6..b7a450c 100644 --- a/src/test/suite/require-table.test.ts +++ b/src/test/suite/require-table.test.ts @@ -14,7 +14,7 @@ import * as assert from 'assert'; import * as path from 'path'; import { Parser } from '../../shared/parser'; import { Lexer } from '../../shared/lexer'; -import { NormalizedPath, normalizePath } from '../../interfaces/hostinterface'; +import { HostInterface, NormalizedPath, normalizePath } from '../../interfaces/hostinterface'; suite('Require Table Tests', () => { const testFile = normalizePath('/test/main.luau'); @@ -375,7 +375,7 @@ suite('Require Table Tests', () => { const fileD = normalizePath(path.join(workspaceRoot, 'complex_d.luau')); // Create a hybrid host that uses in-memory files - const memoryHost = { + const memoryHost : HostInterface = { config: {} as any, readFile: async (p: NormalizedPath): Promise => { return files.get(p) || null; @@ -400,6 +400,7 @@ suite('Require Table Tests', () => { readTOML: async (): Promise => null, writeYAML: async (): Promise => true, writeTOML: async (): Promise => true, + existsInSameWorkspace: async (knownPath: string, desiredPath: string): Promise => false, fileNameToUri: (fileName: NormalizedPath): string => { // Strip path to only include directories/filename after "test" directory const testIndex = fileName.indexOf('test'); diff --git a/src/utils.ts b/src/utils.ts index bd7d26f..be84a53 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -250,6 +250,16 @@ export class VSCodeHost implements HostInterface { return (await readTOMLFile(p)) as T | null; } + async existsInSameWorkspace(knownPath: string, desiredPath: string): Promise { + const knownUri = vscode.Uri.file(normalizePath(knownPath)); + const workspaceDir = vscode.workspace.getWorkspaceFolder(knownUri); + if(!workspaceDir) return false; + const desiredUri = vscode.Uri.file(normalizePath(workspaceDir.uri.fsPath + path.sep + desiredPath)); + const dWorkspaceDir = vscode.workspace.getWorkspaceFolder(desiredUri); + if(!dWorkspaceDir) return false; + return dWorkspaceDir.uri.fsPath == workspaceDir.uri.fsPath; + } + async exists(filename: NormalizedPath, unsafe?: boolean): Promise { if (unsafe) { return await fileExists(filename);