[add] indirection
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
client/.antlr
|
||||
test.bf
|
||||
out
|
||||
dist
|
||||
|
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
@@ -4,6 +4,6 @@
|
||||
"typescript.tsc.autoDetect": "off",
|
||||
"typescript.preferences.quoteStyle": "single",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": true
|
||||
"source.fixAll.eslint": "explicit"
|
||||
}
|
||||
}
|
1159
package-lock.json
generated
1159
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
108
server/src/connection.ts
Normal file
108
server/src/connection.ts
Normal file
@@ -0,0 +1,108 @@
|
||||
import { CompletionItem, CompletionItemKind, Connection, DidChangeConfigurationNotification, DidChangeConfigurationParams, InitializeParams, InitializeResult, TextDocumentPositionParams, TextDocumentSyncKind } from 'vscode-languageserver';
|
||||
|
||||
export class BranFlakesConnectionManager {
|
||||
hasConfigurationCapability: boolean = false;
|
||||
hasWorkspaceFolderCapability: boolean = false;
|
||||
hasDiagnosticRelatedInformationCapability: boolean = false;
|
||||
|
||||
constructor(protected connection: Connection) {
|
||||
connection.onInitialize(this.initConnection);
|
||||
}
|
||||
|
||||
initConnection(params: InitializeParams) {
|
||||
let capabilities = params.capabilities;
|
||||
|
||||
// Does the client support the `workspace/configuration` request?
|
||||
// If not, we will fall back using global settings
|
||||
this.hasConfigurationCapability = !!(
|
||||
capabilities.workspace && !!capabilities.workspace.configuration
|
||||
);
|
||||
this.hasWorkspaceFolderCapability = !!(
|
||||
capabilities.workspace && !!capabilities.workspace.workspaceFolders
|
||||
);
|
||||
this.hasDiagnosticRelatedInformationCapability = !!(
|
||||
capabilities.textDocument &&
|
||||
capabilities.textDocument.publishDiagnostics &&
|
||||
capabilities.textDocument.publishDiagnostics.relatedInformation
|
||||
);
|
||||
|
||||
const result: InitializeResult = {
|
||||
capabilities: {
|
||||
textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
// Tell the client that the server supports code completion
|
||||
completionProvider: {
|
||||
resolveProvider: false,
|
||||
triggerCharacters: ['.'],
|
||||
},
|
||||
},
|
||||
};
|
||||
if (this.hasWorkspaceFolderCapability) {
|
||||
result.capabilities.workspace = {
|
||||
workspaceFolders: {
|
||||
supported: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
onInit() {
|
||||
if (this.hasConfigurationCapability) {
|
||||
// Register for all configuration changes.
|
||||
this.connection.client.register(
|
||||
DidChangeConfigurationNotification.type,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
if (this.hasWorkspaceFolderCapability) {
|
||||
this.connection.workspace.onDidChangeWorkspaceFolders(_event => {
|
||||
// connection.console.log('Workspace folder change event received.');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setOnCompletion() {
|
||||
this.connection.onCompletion((_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
|
||||
const completions: CompletionItem[] = [
|
||||
{
|
||||
label: '+',
|
||||
detail: 'Addition',
|
||||
documentation: 'Add one to cell',
|
||||
},
|
||||
{
|
||||
label: '-',
|
||||
detail: 'Subtraction',
|
||||
documentation: 'Subtract one from cell',
|
||||
},
|
||||
{
|
||||
label: ',',
|
||||
detail: 'Input',
|
||||
documentation: 'Ask for input (Stored in the ASCII format)',
|
||||
},
|
||||
{
|
||||
label: '.',
|
||||
detail: 'Output',
|
||||
documentation: 'Output the equivalent ASCII character',
|
||||
},
|
||||
{
|
||||
label: '>',
|
||||
detail: 'Right Shift',
|
||||
documentation: 'Shift the pointer one cell to the right',
|
||||
},
|
||||
{
|
||||
label: '<',
|
||||
detail: 'Left Shift',
|
||||
documentation: 'Shift the pointer one cell to the Left',
|
||||
},
|
||||
];
|
||||
return completions.map(e => {
|
||||
e.kind = CompletionItemKind.Operator;
|
||||
return e;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
listen() {
|
||||
this.connection.listen();
|
||||
}
|
||||
|
||||
}
|
@@ -3,240 +3,87 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
* ------------------------------------------------------------------------------------------ */
|
||||
import {
|
||||
createConnection,
|
||||
TextDocuments,
|
||||
Diagnostic,
|
||||
DiagnosticSeverity,
|
||||
ProposedFeatures,
|
||||
InitializeParams,
|
||||
DidChangeConfigurationNotification,
|
||||
CompletionItem,
|
||||
CompletionItemKind,
|
||||
TextDocumentPositionParams,
|
||||
TextDocumentSyncKind,
|
||||
InitializeResult,
|
||||
createConnection,
|
||||
TextDocuments,
|
||||
ProposedFeatures,
|
||||
} from 'vscode-languageserver';
|
||||
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import { BranFlakesSettings, defaultSettings } from './settings';
|
||||
import { BranFlakesConnectionManager } from './connection';
|
||||
import { validateTextDocument } from './validation';
|
||||
|
||||
// Create a connection for the server. The connection uses Node's IPC as a transport.
|
||||
// Also include all preview / proposed LSP features.
|
||||
let connection = createConnection(ProposedFeatures.all);
|
||||
export let connection = createConnection(ProposedFeatures.all);
|
||||
|
||||
// Create a simple text document manager. The text document manager
|
||||
// supports full document sync only
|
||||
let documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
|
||||
|
||||
let hasConfigurationCapability: boolean = false;
|
||||
let hasWorkspaceFolderCapability: boolean = false;
|
||||
let hasDiagnosticRelatedInformationCapability: boolean = false;
|
||||
|
||||
connection.onInitialize((params: InitializeParams) => {
|
||||
let capabilities = params.capabilities;
|
||||
let cm = new BranFlakesConnectionManager(connection);
|
||||
|
||||
// Does the client support the `workspace/configuration` request?
|
||||
// If not, we will fall back using global settings
|
||||
hasConfigurationCapability = !!(
|
||||
capabilities.workspace && !!capabilities.workspace.configuration
|
||||
);
|
||||
hasWorkspaceFolderCapability = !!(
|
||||
capabilities.workspace && !!capabilities.workspace.workspaceFolders
|
||||
);
|
||||
hasDiagnosticRelatedInformationCapability = !!(
|
||||
capabilities.textDocument &&
|
||||
capabilities.textDocument.publishDiagnostics &&
|
||||
capabilities.textDocument.publishDiagnostics.relatedInformation
|
||||
);
|
||||
|
||||
const result: InitializeResult = {
|
||||
capabilities: {
|
||||
textDocumentSync: TextDocumentSyncKind.Incremental,
|
||||
// Tell the client that the server supports code completion
|
||||
completionProvider: {
|
||||
resolveProvider: false,
|
||||
triggerCharacters: ['.'],
|
||||
},
|
||||
},
|
||||
};
|
||||
if (hasWorkspaceFolderCapability) {
|
||||
result.capabilities.workspace = {
|
||||
workspaceFolders: {
|
||||
supported: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
return result;
|
||||
});
|
||||
|
||||
connection.onInitialized(() => {
|
||||
if (hasConfigurationCapability) {
|
||||
// Register for all configuration changes.
|
||||
connection.client.register(
|
||||
DidChangeConfigurationNotification.type,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
if (hasWorkspaceFolderCapability) {
|
||||
connection.workspace.onDidChangeWorkspaceFolders(_event => {
|
||||
connection.console.log('Workspace folder change event received.');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// The example settings
|
||||
interface ExampleSettings {
|
||||
maxNumberOfProblems: number;
|
||||
}
|
||||
|
||||
// The global settings, used when the `workspace/configuration` request is not supported by the client.
|
||||
// Please note that this is not the case when using this server with the client provided in this example
|
||||
// but could happen with other clients.
|
||||
const defaultSettings: ExampleSettings = { maxNumberOfProblems: 5 };
|
||||
let globalSettings: ExampleSettings = defaultSettings;
|
||||
let globalSettings: BranFlakesSettings = defaultSettings;
|
||||
|
||||
// Cache the settings of all open documents
|
||||
let documentSettings: Map<string, Thenable<ExampleSettings>> = new Map();
|
||||
let documentSettings: Map<string, Thenable<BranFlakesSettings>> = new Map();
|
||||
|
||||
connection.onDidChangeConfiguration(change => {
|
||||
if (hasConfigurationCapability) {
|
||||
// Reset all cached document settings
|
||||
documentSettings.clear();
|
||||
} else {
|
||||
globalSettings = <ExampleSettings>(
|
||||
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');
|
||||
});
|
||||
// Revalidate all open text documents
|
||||
Promise.all(documents.all().map(validateTextDocument)).catch(e => {
|
||||
connection.console.log('Failed to validate text documents');
|
||||
});
|
||||
});
|
||||
|
||||
function getDocumentSettings(resource: string): Thenable<ExampleSettings> {
|
||||
if (!hasConfigurationCapability) {
|
||||
return Promise.resolve(globalSettings);
|
||||
}
|
||||
let result = documentSettings.get(resource);
|
||||
if (!result) {
|
||||
result = connection.workspace.getConfiguration({
|
||||
scopeUri: resource,
|
||||
section: 'languageServerExample',
|
||||
});
|
||||
documentSettings.set(resource, result);
|
||||
}
|
||||
return result;
|
||||
export function getDocumentSettings(resource: string): Thenable<BranFlakesSettings> {
|
||||
if (!hasConfigurationCapability) {
|
||||
return Promise.resolve(globalSettings);
|
||||
}
|
||||
let result = documentSettings.get(resource);
|
||||
if (!result) {
|
||||
result = connection.workspace.getConfiguration({
|
||||
scopeUri: resource,
|
||||
section: 'languageServerExample',
|
||||
});
|
||||
documentSettings.set(resource, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Only keep settings for open documents
|
||||
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
|
||||
// when the text document first opened or when its content has changed.
|
||||
documents.onDidChangeContent(change => {
|
||||
validateTextDocument(change.document);
|
||||
validateTextDocument(change.document);
|
||||
});
|
||||
|
||||
//Run when saved
|
||||
documents.onDidSave(change => {
|
||||
validateTextDocument(change.document);
|
||||
validateTextDocument(change.document);
|
||||
});
|
||||
|
||||
const validateBrackets = (text: string) => {
|
||||
let count = 0,
|
||||
lp: number[] = [],
|
||||
issues: number[] = [];
|
||||
const textsplit = text.split('');
|
||||
textsplit.forEach((x, i) => {
|
||||
if (x === '[' || x === ']') {
|
||||
if (x === '[') {
|
||||
lp.push(i);
|
||||
}
|
||||
if (x === ']') {
|
||||
if (lp.length === 0) {
|
||||
issues.push(i);
|
||||
}
|
||||
lp.pop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return [...lp, ...issues];
|
||||
};
|
||||
|
||||
async function validateTextDocument(textDocument: TextDocument): Promise<void> {
|
||||
// In this simple example we get the settings for every validate run.
|
||||
let settings = await getDocumentSettings(textDocument.uri);
|
||||
// The validator creates diagnostics for all uppercase words length 2 and more
|
||||
const text = textDocument.getText();
|
||||
|
||||
let problems = 0;
|
||||
let diagnostics: Diagnostic[] = [];
|
||||
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 ]',
|
||||
}))
|
||||
);
|
||||
|
||||
// Send the computed diagnostics to VSCode.
|
||||
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
|
||||
}
|
||||
|
||||
// This handler provides the initial list of the completion items.
|
||||
connection.onCompletion(
|
||||
(_textDocumentPosition: TextDocumentPositionParams): CompletionItem[] => {
|
||||
const completions: CompletionItem[] = [
|
||||
{
|
||||
label: '+',
|
||||
detail: 'Addition',
|
||||
documentation: 'Add one to cell',
|
||||
},
|
||||
{
|
||||
label: '-',
|
||||
detail: 'Subtraction',
|
||||
documentation: 'Subtract one from cell',
|
||||
},
|
||||
{
|
||||
label: ',',
|
||||
detail: 'Input',
|
||||
documentation: 'Ask for input (Stored in the ASCII format)',
|
||||
},
|
||||
{
|
||||
label: '.',
|
||||
detail: 'Output',
|
||||
documentation: 'Output the equivalent ASCII character',
|
||||
},
|
||||
{
|
||||
label: '>',
|
||||
detail: 'Right Shift',
|
||||
documentation: 'Shift the pointer one cell to the right',
|
||||
},
|
||||
{
|
||||
label: '<',
|
||||
detail: 'Left Shift',
|
||||
documentation: 'Shift the pointer one cell to the Left',
|
||||
},
|
||||
];
|
||||
return completions.map(e => {
|
||||
e.kind = CompletionItemKind.Operator;
|
||||
return e;
|
||||
});
|
||||
}
|
||||
);
|
||||
cm.setOnCompletion();
|
||||
|
||||
// Make the text document manager listen on the connection
|
||||
// for open, change and close text document events
|
||||
documents.listen(connection);
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
||||
cm.listen();
|
13
server/src/settings.ts
Normal file
13
server/src/settings.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
// The example settings
|
||||
export interface BranFlakesSettings {
|
||||
maxNumberOfProblems: number;
|
||||
}
|
||||
|
||||
|
||||
// The global settings, used when the `workspace/configuration` request is not supported by the client.
|
||||
// Please note that this is not the case when using this server with the client provided in this example
|
||||
// but could happen with other clients.
|
||||
export const defaultSettings: BranFlakesSettings = {
|
||||
maxNumberOfProblems: 5
|
||||
};
|
||||
|
52
server/src/validation.ts
Normal file
52
server/src/validation.ts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { Diagnostic, DiagnosticSeverity } from 'vscode-languageserver';
|
||||
import { TextDocument } from 'vscode-languageserver-textdocument';
|
||||
import { getDocumentSettings, connection } from './server';
|
||||
|
||||
|
||||
|
||||
export const validateBrackets = (text: string) => {
|
||||
let count = 0, lp: number[] = [], issues: number[] = [];
|
||||
const textsplit = text.split('');
|
||||
textsplit.forEach((x, i) => {
|
||||
if (x === '[' || x === ']') {
|
||||
if (x === '[') {
|
||||
lp.push(i);
|
||||
}
|
||||
if (x === ']') {
|
||||
if (lp.length === 0) {
|
||||
issues.push(i);
|
||||
}
|
||||
lp.pop();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return [...lp, ...issues];
|
||||
};
|
||||
|
||||
export async function validateTextDocument(textDocument: TextDocument): Promise<void> {
|
||||
// In this simple example we get the settings for every validate run.
|
||||
let settings = await getDocumentSettings(textDocument.uri);
|
||||
// The validator creates diagnostics for all uppercase words length 2 and more
|
||||
const text = textDocument.getText();
|
||||
|
||||
let problems = 0;
|
||||
let diagnostics: Diagnostic[] = [];
|
||||
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 ]',
|
||||
}))
|
||||
);
|
||||
|
||||
// Send the computed diagnostics to VSCode.
|
||||
connection.sendDiagnostics({ uri: textDocument.uri, diagnostics });
|
||||
}
|
||||
|
Reference in New Issue
Block a user