[refactor]

This commit is contained in:
2025-07-19 14:39:44 +01:00
parent 7e5b68116a
commit e549845d70
7 changed files with 152 additions and 43 deletions

View File

@@ -1,4 +1,4 @@
export default interface InputStrategy { export default interface InputStrategy {
getInput(): Promise<number>; getInput(): Promise<number>;
} };

View File

@@ -8,21 +8,26 @@ export class VSCodePromptInputStrategy implements InputStrategy {
promptOptions?: InputBoxOptions, promptOptions?: InputBoxOptions,
cancelToken?: CancellationToken cancelToken?: CancellationToken
) => Thenable<string> ) => Thenable<string>
) {} ) { }
async getInput(): Promise<number> { async getInput(): Promise<number> {
while (this.inputQueue.length == 0) { while (this.inputQueue.length === 0) {
await this.requestInputFromPrompt(); await this.requestInputFromPrompt();
} }
const character = this.inputQueue.charCodeAt(0); const character = this.popInputFromQueue();
this.inputQueue = this.inputQueue.substring(1);
return character; return character;
} }
private popInputFromQueue() {
const character = this.inputQueue.charCodeAt(0);
this.inputQueue = this.inputQueue.substring(1);
return character;
}
private async requestInputFromPrompt() { private async requestInputFromPrompt() {
const inputPrompt = await this.requestor({ const inputPrompt = await this.requestor({
prompt: 'More input is required. Please provide input:', prompt: 'More input is required. Please provide input:',
}); });
this.inputQueue += inputPrompt; this.inputQueue += inputPrompt;
} }
} }

View File

@@ -0,0 +1,74 @@
import path = require('node:path');
import * as vscode from 'vscode';
export class CustomExecutionTaskProvider implements vscode.TaskProvider{
provideTasks(token?: vscode.CancellationToken): vscode.ProviderResult<vscode.Task[]> {
throw new Error('Method not implemented.');
}
resolveTask(task: vscode.Task, token?: vscode.CancellationToken): vscode.ProviderResult<vscode.Task> {
const taskDefinition = {};
throw new Error('5');
// return new vscode.Task()
}
}
class CustomBuildTaskTerminal implements vscode.Pseudoterminal {
private writeEmitter = new vscode.EventEmitter<string>();
onDidWrite: vscode.Event<string> = this.writeEmitter.event;
private closeEmitter = new vscode.EventEmitter<number>();
onDidClose?: vscode.Event<number> = this.closeEmitter.event;
private fileWatcher: vscode.FileSystemWatcher | undefined;
constructor(private workspaceRoot: string, private flavor: string, private flags: string[], private getSharedState: () => string | undefined, private setSharedState: (state: string) => void) {
}
open(initialDimensions: vscode.TerminalDimensions | undefined): void {
// At this point we can start using the terminal.
if (this.flags.indexOf('watch') > -1) {
const pattern = path.join(this.workspaceRoot, 'customBuildFile');
this.fileWatcher = vscode.workspace.createFileSystemWatcher(pattern);
this.fileWatcher.onDidChange(() => this.doBuild());
this.fileWatcher.onDidCreate(() => this.doBuild());
this.fileWatcher.onDidDelete(() => this.doBuild());
}
this.doBuild();
}
close(): void {
// The terminal has been closed. Shutdown the build.
if (this.fileWatcher) {
this.fileWatcher.dispose();
}
}
private async doBuild(): Promise<void> {
return new Promise<void>((resolve) => {
this.writeEmitter.fire('Starting build...\r\n');
let isIncremental = this.flags.indexOf('incremental') > -1;
if (isIncremental) {
if (this.getSharedState()) {
this.writeEmitter.fire('Using last build results: ' + this.getSharedState() + '\r\n');
} else {
isIncremental = false;
this.writeEmitter.fire('No result from last build. Doing full build.\r\n');
}
}
// Since we don't actually build anything in this example set a timeout instead.
setTimeout(() => {
const date = new Date();
this.setSharedState(date.toTimeString() + ' ' + date.toDateString());
this.writeEmitter.fire('Build complete.\r\n\r\n');
if (this.flags.indexOf('watch') === -1) {
this.closeEmitter.fire(0);
resolve();
}
}, isIncremental ? 1000 : 4000);
});
}
}

View File

@@ -1,26 +1,30 @@
import { CompletionItem, CompletionItemKind, Connection, DidChangeConfigurationNotification, DidChangeConfigurationParams, InitializeParams, InitializeResult, TextDocumentPositionParams, TextDocumentSyncKind } from 'vscode-languageserver'; import { CompletionItem, CompletionItemKind, Connection, DidChangeConfigurationNotification, DidChangeConfigurationParams, InitializeParams, InitializeResult, TextDocumentPositionParams, TextDocuments, TextDocumentSyncKind } from 'vscode-languageserver';
import { validateTextDocument } from './validation';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { BranFlakesSettings, defaultSettings, SettingsManager } from './settings';
export class BranFlakesConnectionManager { export class BranFlakesConnectionManager {
hasConfigurationCapability: boolean = false;
hasWorkspaceFolderCapability: boolean = false;
hasDiagnosticRelatedInformationCapability: boolean = false;
constructor(protected connection: Connection) {
constructor(protected connection: Connection, private validator:typeof validateTextDocument, private documents:TextDocuments<TextDocument>, private settingsManager:SettingsManager) {
connection.onInitialize(this.initConnection); connection.onInitialize(this.initConnection);
connection.onDidChangeConfiguration(this.onDidChangeConfiguration);
} }
initConnection(params: InitializeParams) { initConnection(params: InitializeParams) {
let capabilities = params.capabilities; let capabilities = params.capabilities;
// Does the client support the `workspace/configuration` request? // Does the client support the `workspace/configuration` request?
// If not, we will fall back using global settings // If not, we will fall back using global settings
this.hasConfigurationCapability = !!( this.settingsManager.hasConfigurationCapability = !!(
capabilities.workspace && !!capabilities.workspace.configuration capabilities.workspace && !!capabilities.workspace.configuration
); );
this.hasWorkspaceFolderCapability = !!( this.settingsManager.hasWorkspaceFolderCapability = !!(
capabilities.workspace && !!capabilities.workspace.workspaceFolders capabilities.workspace && !!capabilities.workspace.workspaceFolders
); );
this.hasDiagnosticRelatedInformationCapability = !!( this.settingsManager.hasDiagnosticRelatedInformationCapability = !!(
capabilities.textDocument && capabilities.textDocument &&
capabilities.textDocument.publishDiagnostics && capabilities.textDocument.publishDiagnostics &&
capabilities.textDocument.publishDiagnostics.relatedInformation capabilities.textDocument.publishDiagnostics.relatedInformation
@@ -36,7 +40,7 @@ export class BranFlakesConnectionManager {
}, },
}, },
}; };
if (this.hasWorkspaceFolderCapability) { if (this.settingsManager.hasWorkspaceFolderCapability) {
result.capabilities.workspace = { result.capabilities.workspace = {
workspaceFolders: { workspaceFolders: {
supported: true, supported: true,
@@ -45,15 +49,31 @@ export class BranFlakesConnectionManager {
} }
return result; return result;
} }
onDidChangeConfiguration(change:DidChangeConfigurationParams){
if (this.settingsManager.hasConfigurationCapability) {
// Reset all cached document settings
this.settingsManager.clearDocumentSettings();
} else {
this.settingsManager.updateSettings(
(change.settings.languageServerExample || defaultSettings)
);
}
// Revalidate all open text documents
Promise.all(this.documents.all().map(validateTextDocument)).catch(e => {
this.connection.console.log('Failed to validate text documents');
});
}
onInit() { onInit() {
if (this.hasConfigurationCapability) { if (this.settingsManager.hasConfigurationCapability) {
// Register for all configuration changes. // Register for all configuration changes.
this.connection.client.register( this.connection.client.register(
DidChangeConfigurationNotification.type, DidChangeConfigurationNotification.type,
undefined undefined
); );
} }
if (this.hasWorkspaceFolderCapability) { if (this.settingsManager.hasWorkspaceFolderCapability) {
this.connection.workspace.onDidChangeWorkspaceFolders(_event => { this.connection.workspace.onDidChangeWorkspaceFolders(_event => {
// connection.console.log('Workspace folder change event received.'); // connection.console.log('Workspace folder change event received.');
}); });

View File

@@ -9,7 +9,7 @@ import {
} from 'vscode-languageserver'; } from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument'; import { TextDocument } from 'vscode-languageserver-textdocument';
import { BranFlakesSettings, defaultSettings } from './settings'; import { BranFlakesSettings, defaultSettings, SettingsManager } from './settings';
import { BranFlakesConnectionManager } from './connection'; import { BranFlakesConnectionManager } from './connection';
import { validateTextDocument } from './validation'; import { validateTextDocument } from './validation';
@@ -23,29 +23,15 @@ let documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
let hasConfigurationCapability: boolean = false; let hasConfigurationCapability: boolean = false;
let cm = new BranFlakesConnectionManager(connection);
let globalSettings: BranFlakesSettings = defaultSettings; let globalSettings: BranFlakesSettings = defaultSettings;
// Cache the settings of all open documents // Cache the settings of all open documents
let documentSettings: Map<string, Thenable<BranFlakesSettings>> = new Map(); let documentSettings: Map<string, Thenable<BranFlakesSettings>> = new Map();
let settingsManager = new SettingsManager();
let cm = new BranFlakesConnectionManager(connection, validateTextDocument,documents,settingsManager);
connection.onDidChangeConfiguration(change => {
if (hasConfigurationCapability) {
// Reset all cached document settings
documentSettings.clear();
} else {
globalSettings = <BranFlakesSettings>(
(change.settings.languageServerExample || defaultSettings)
);
}
// Revalidate all open text documents
Promise.all(documents.all().map(validateTextDocument)).catch(e => {
connection.console.log('Failed to validate text documents');
});
});
export function getDocumentSettings(resource: string): Thenable<BranFlakesSettings> { export function getDocumentSettings(resource: string): Thenable<BranFlakesSettings> {
if (!hasConfigurationCapability) { if (!hasConfigurationCapability) {
@@ -64,7 +50,7 @@ export function getDocumentSettings(resource: string): Thenable<BranFlakesSettin
// Only keep settings for open documents // Only keep settings for open documents
documents.onDidClose(e => { documents.onDidClose(e => {
documentSettings.delete(e.document.uri); settingsManager.closeDocument(e.document.uri);
}); });
// The content of a text document has changed. This event is emitted // The content of a text document has changed. This event is emitted

View File

@@ -11,3 +11,25 @@ export const defaultSettings: BranFlakesSettings = {
maxNumberOfProblems: 5 maxNumberOfProblems: 5
}; };
export class SettingsManager {
hasConfigurationCapability: boolean = false;
hasWorkspaceFolderCapability: boolean = false;
hasDiagnosticRelatedInformationCapability: boolean = false;
documentSettings: Map<string, Thenable<BranFlakesSettings>> = new Map();
#settings = defaultSettings;
updateSettings(newSettings: BranFlakesSettings) {
this.#settings = newSettings;
}
closeDocument(doc: string) {
this.documentSettings.delete(doc);
}
clearDocumentSettings(){
this.documentSettings.clear();
}
}

View File

@@ -24,6 +24,8 @@ export const validateBrackets = (text: string) => {
return [...lp, ...issues]; return [...lp, ...issues];
}; };
export async function validateTextDocument(textDocument: TextDocument): Promise<void> { export async function validateTextDocument(textDocument: TextDocument): Promise<void> {
// In this simple example we get the settings for every validate run. // In this simple example we get the settings for every validate run.
let settings = await getDocumentSettings(textDocument.uri); let settings = await getDocumentSettings(textDocument.uri);