This commit is contained in:
2024-01-02 22:32:24 +05:30
parent 0a2a6c4db6
commit fc7e3b431f
8 changed files with 178 additions and 192 deletions

View File

@@ -4,9 +4,9 @@ import { bfVisitor } from './generated/bfVisitor';
import { DiagnosticSeverity } from 'vscode-languageclient'; import { DiagnosticSeverity } from 'vscode-languageclient';
import { getTree } from './BranFlakesParseRunner'; import { getTree } from './BranFlakesParseRunner';
import { RuleNode } from 'antlr4ts/tree/RuleNode'; import { RuleNode } from 'antlr4ts/tree/RuleNode';
import InputStrategy from './input/InputStrategy'; import type InputStrategy from './input/InputStrategy';
export default class BranFlakesExecutorVisitor export class BranFlakesExecutorVisitor
extends AbstractParseTreeVisitor<Promise<void>> extends AbstractParseTreeVisitor<Promise<void>>
implements bfVisitor<Promise<void>> implements bfVisitor<Promise<void>>
{ {

View File

@@ -0,0 +1,4 @@
export interface BranFlakesCommand {
getCommandName(): string;
getCommandHandler(): (...args: any) => Promise<any>;
}

View File

@@ -1,5 +0,0 @@
export interface Command{
getCommandName():string;
getCommandHandler():(...args:any)=>Promise<any>;
}

View File

@@ -1,7 +1,6 @@
import { window } from 'vscode'; import { window } from 'vscode';
import { Command as BranFlakesCommand } from './Command'; import type { BranFlakesCommand } from './BranFlakesCommand';
import { VSCodePromptInputStrategy } from '../input/VSCodePromptInputStrategy'; import { VSCodePromptInputStrategy } from '../input/VSCodePromptInputStrategy';
import BranFlakesExecutorVisitor from '../BranFlakesExecutorVisitor';
export class CompileBranFlakesCommand implements BranFlakesCommand { export class CompileBranFlakesCommand implements BranFlakesCommand {
getCommandName() { getCommandName() {
@@ -14,6 +13,10 @@ export class CompileBranFlakesCommand implements BranFlakesCommand {
const inputStrategy = new VSCodePromptInputStrategy( const inputStrategy = new VSCodePromptInputStrategy(
window.showInputBox window.showInputBox
); );
const { BranFlakesExecutorVisitor } = await import(
'../BranFlakesExecutorVisitor'
);
const output = await BranFlakesExecutorVisitor.run( const output = await BranFlakesExecutorVisitor.run(
text, text,
fn, fn,

View File

@@ -4,14 +4,15 @@
* ------------------------------------------------------------------------------------------ */ * ------------------------------------------------------------------------------------------ */
import * as path from 'path'; import * as path from 'path';
import { ExtensionContext, commands, window } from 'vscode'; import { commands } from 'vscode';
import type { ExtensionContext } from 'vscode';
import { import {
LanguageClient, LanguageClient,
LanguageClientOptions, LanguageClientOptions,
ServerOptions, ServerOptions,
TransportKind, TransportKind,
} from 'vscode-languageclient'; } from 'vscode-languageclient';
import { CompileBranFlakesCommand } from './command/CompileCommand'; import { CompileBranFlakesCommand } from './command/CompileBranFlakesCommand';
let client: LanguageClient; let client: LanguageClient;

View File

@@ -1,5 +1,5 @@
import { CancellationToken, InputBoxOptions } from 'vscode'; import type { CancellationToken, InputBoxOptions } from 'vscode';
import InputStrategy from './InputStrategy'; import type InputStrategy from './InputStrategy';
export class VSCodePromptInputStrategy implements InputStrategy { export class VSCodePromptInputStrategy implements InputStrategy {
private inputQueue: string = ''; private inputQueue: string = '';

View File

@@ -5,9 +5,9 @@
"author": "Atreya Bain", "author": "Atreya Bain",
"license": "MIT", "license": "MIT",
"publisher": "atreyabain", "publisher": "atreyabain",
"version": "0.2.0", "version": "0.2.1",
"icon": "assets/128.png", "icon": "assets/128.png",
"categories": [], "categories": ["Programming Languages","Linters"],
"keywords": [ "keywords": [
"multi-root ready", "multi-root ready",
"brainfuck", "brainfuck",

View File

@@ -3,31 +3,26 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */ * ------------------------------------------------------------------------------------------ */
import { import {
createConnection, createConnection,
TextDocuments, TextDocuments,
Diagnostic, Diagnostic,
DiagnosticSeverity, DiagnosticSeverity,
ProposedFeatures, ProposedFeatures,
InitializeParams, InitializeParams,
DidChangeConfigurationNotification, DidChangeConfigurationNotification,
CompletionItem, CompletionItem,
CompletionItemKind, CompletionItemKind,
TextDocumentPositionParams, TextDocumentPositionParams,
TextDocumentSyncKind, TextDocumentSyncKind,
InitializeResult, InitializeResult,
Position,
} from 'vscode-languageserver'; } from 'vscode-languageserver';
import { TextDocument } from 'vscode-languageserver-textdocument'; import { TextDocument } from 'vscode-languageserver-textdocument';
// Create a connection for the server. The connection uses Node's IPC as a transport. // Create a connection for the server. The connection uses Node's IPC as a transport.
// Also include all preview / proposed LSP features. // Also include all preview / proposed LSP features.
let connection = createConnection(ProposedFeatures.all); let connection = createConnection(ProposedFeatures.all);
// Create a simple text document manager. The text document manager // Create a simple text document manager. The text document manager
// supports full document sync only // supports full document sync only
let documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument); let documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
@@ -37,60 +32,60 @@ let hasWorkspaceFolderCapability: boolean = false;
let hasDiagnosticRelatedInformationCapability: boolean = false; let hasDiagnosticRelatedInformationCapability: boolean = false;
connection.onInitialize((params: InitializeParams) => { connection.onInitialize((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
hasConfigurationCapability = !!( hasConfigurationCapability = !!(
capabilities.workspace && !!capabilities.workspace.configuration capabilities.workspace && !!capabilities.workspace.configuration
); );
hasWorkspaceFolderCapability = !!( hasWorkspaceFolderCapability = !!(
capabilities.workspace && !!capabilities.workspace.workspaceFolders capabilities.workspace && !!capabilities.workspace.workspaceFolders
); );
hasDiagnosticRelatedInformationCapability = !!( hasDiagnosticRelatedInformationCapability = !!(
capabilities.textDocument && capabilities.textDocument &&
capabilities.textDocument.publishDiagnostics && capabilities.textDocument.publishDiagnostics &&
capabilities.textDocument.publishDiagnostics.relatedInformation capabilities.textDocument.publishDiagnostics.relatedInformation
); );
const result: InitializeResult = { const result: InitializeResult = {
capabilities: { capabilities: {
textDocumentSync: TextDocumentSyncKind.Incremental, textDocumentSync: TextDocumentSyncKind.Incremental,
// Tell the client that the server supports code completion // Tell the client that the server supports code completion
completionProvider: { completionProvider: {
resolveProvider: false, resolveProvider: false,
triggerCharacters: ['.'], triggerCharacters: ['.'],
}, },
}, },
}; };
if (hasWorkspaceFolderCapability) { if (hasWorkspaceFolderCapability) {
result.capabilities.workspace = { result.capabilities.workspace = {
workspaceFolders: { workspaceFolders: {
supported: true, supported: true,
}, },
}; };
} }
return result; return result;
}); });
connection.onInitialized(() => { connection.onInitialized(() => {
if (hasConfigurationCapability) { if (hasConfigurationCapability) {
// Register for all configuration changes. // Register for all configuration changes.
connection.client.register( connection.client.register(
DidChangeConfigurationNotification.type, DidChangeConfigurationNotification.type,
undefined undefined
); );
} }
if (hasWorkspaceFolderCapability) { if (hasWorkspaceFolderCapability) {
connection.workspace.onDidChangeWorkspaceFolders(_event => { connection.workspace.onDidChangeWorkspaceFolders(_event => {
connection.console.log('Workspace folder change event received.'); connection.console.log('Workspace folder change event received.');
}); });
} }
}); });
// The example settings // The example settings
interface ExampleSettings { interface ExampleSettings {
maxNumberOfProblems: number; maxNumberOfProblems: number;
} }
// The global settings, used when the `workspace/configuration` request is not supported by the client. // The global settings, used when the `workspace/configuration` request is not supported by the client.
@@ -103,154 +98,142 @@ let globalSettings: ExampleSettings = defaultSettings;
let documentSettings: Map<string, Thenable<ExampleSettings>> = new Map(); let documentSettings: Map<string, Thenable<ExampleSettings>> = new Map();
connection.onDidChangeConfiguration(change => { connection.onDidChangeConfiguration(change => {
if (hasConfigurationCapability) { if (hasConfigurationCapability) {
// Reset all cached document settings // Reset all cached document settings
documentSettings.clear(); documentSettings.clear();
} else { } else {
globalSettings = <ExampleSettings>( globalSettings = <ExampleSettings>(
(change.settings.languageServerExample || defaultSettings) (change.settings.languageServerExample || defaultSettings)
); );
} }
// Revalidate all open text documents // Revalidate all open text documents
documents.all().forEach(validateTextDocument); Promise.all(documents.all().map(validateTextDocument)).catch(e => {
connection.console.log('Failed to validate text documents');
});
}); });
function getDocumentSettings(resource: string): Thenable<ExampleSettings> { function getDocumentSettings(resource: string): Thenable<ExampleSettings> {
if (!hasConfigurationCapability) { if (!hasConfigurationCapability) {
return Promise.resolve(globalSettings); return Promise.resolve(globalSettings);
} }
let result = documentSettings.get(resource); let result = documentSettings.get(resource);
if (!result) { if (!result) {
result = connection.workspace.getConfiguration({ result = connection.workspace.getConfiguration({
scopeUri: resource, scopeUri: resource,
section: 'languageServerExample', section: 'languageServerExample',
}); });
documentSettings.set(resource, result); documentSettings.set(resource, result);
} }
return result; return result;
} }
// Only keep settings for open documents // Only keep settings for open documents
documents.onDidClose(e => { documents.onDidClose(e => {
documentSettings.delete(e.document.uri); documentSettings.delete(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
// when the text document first opened or when its content has changed. // when the text document first opened or when its content has changed.
documents.onDidChangeContent(change => { documents.onDidChangeContent(change => {
//change.contentChanges; validateTextDocument(change.document);
validateTextDocument(change.document);
}); });
//Run when saved //Run when saved
documents.onDidSave(change => { documents.onDidSave(change => {
validateTextDocument(change.document); validateTextDocument(change.document);
}); });
const validateBrackets = (text: string) => { const validateBrackets = (text: string) => {
let count = 0, lp: number[] = [],issues:number[]=[]; let count = 0,
const textsplit = text.split(''); lp: number[] = [],
textsplit.forEach((x, i) => { issues: number[] = [];
if (x === '[' || x === ']') { const textsplit = text.split('');
textsplit.forEach((x, i) => {
if (x === '[') {lp.push(i);} if (x === '[' || x === ']') {
if (x === ']') {if(lp.length===0) {issues.push(i);}lp.pop();} if (x === '[') {
lp.push(i);
}
if (x === ']') {
if (lp.length === 0) {
issues.push(i);
}
lp.pop();
}
}
});
return [...lp, ...issues];
}
});
return [...lp,...issues];
}; };
async function validateTextDocument(textDocument: TextDocument): Promise<void> { 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);
// The validator creates diagnostics for all uppercase words length 2 and more // The validator creates diagnostics for all uppercase words length 2 and more
const text = textDocument.getText(); const text = textDocument.getText();
let problems = 0; let problems = 0;
let diagnostics: Diagnostic[] = []; let diagnostics: Diagnostic[] = [];
const issues = validateBrackets(text); const issues = validateBrackets(text);
diagnostics.push(...issues.map<Diagnostic>(e => ({
message: 'Brackets unmatched',
range:{
start: textDocument.positionAt(e),
end: textDocument.positionAt(e+1),
},
severity:DiagnosticSeverity.Error,
code:'[ and ]',
})));
// diagnostics.push({
// message: 'Brackets not matched',
// range: {
// start: { line: 0, character: 0 },
// end: { line: 0, character: 0 },
// },
// });
// diagnostics.push(<Diagnostic>{ diagnostics.push(
// severity: DiagnosticSeverity.Information, ...issues.map<Diagnostic>(e => ({
// range: { message: 'Brackets unmatched',
// start: textDocument.positionAt(0), range: {
// end: textDocument.positionAt(1), start: textDocument.positionAt(e),
// }, end: textDocument.positionAt(e + 1),
// // message:`HI:(${text})(${result.hasErrors()},${result.hasWarnings()})`, },
// message: `Parsing Failed`, severity: DiagnosticSeverity.Error,
// source: 'test', code: '[ and ]',
// }); }))
);
// Send the computed diagnostics to VSCode. // Send the computed diagnostics to VSCode.
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics }); connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
} }
// This handler provides the initial list of the completion items. // This handler provides the initial list of the completion items.
connection.onCompletion( connection.onCompletion(
(_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => { (_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
const completions: CompletionItem[] = [ const completions: CompletionItem[] = [
{ {
label: '+', label: '+',
detail: 'Addition', detail: 'Addition',
documentation: 'Add one to cell', documentation: 'Add one to cell',
}, },
{ {
label: '-', label: '-',
detail: 'Subtraction', detail: 'Subtraction',
documentation: 'Subtract one from cell', documentation: 'Subtract one from cell',
}, },
{ {
label: ',', label: ',',
detail: 'Input', detail: 'Input',
documentation: 'Ask for input (Stored in the ASCII format)', documentation: 'Ask for input (Stored in the ASCII format)',
}, },
{ {
label: '.', label: '.',
detail: 'Output', detail: 'Output',
documentation: 'Output the equivalent ASCII character', documentation: 'Output the equivalent ASCII character',
}, },
{ {
label: '>', label: '>',
detail: 'Right Shift', detail: 'Right Shift',
documentation: 'Shift the pointer one cell to the right', documentation: 'Shift the pointer one cell to the right',
}, },
{ {
label: '<', label: '<',
detail: 'Left Shift', detail: 'Left Shift',
documentation: 'Shift the pointer one cell to the Left', documentation: 'Shift the pointer one cell to the Left',
}, },
]; ];
return completions.map(e => { return completions.map(e => {
e.kind = CompletionItemKind.Operator; e.kind = CompletionItemKind.Operator;
return e; return e;
}); });
} }
); );
// Make the text document manager listen on the connection // Make the text document manager listen on the connection
// for open, change and close text document events // for open, change and close text document events
documents.listen(connection); documents.listen(connection);