Created
November 4, 2017 12:54
-
-
Save Levertion/8180150d01eea7ba505fe896c0cb706b to your computer and use it in GitHub Desktop.
An attempted refactor of https://github.com/Levertion/vscode-mcfunction, until I realised it was going to end up being the exact same code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* -------------------------------------------------------------------------------------------- | |
* Licensed under the MIT License. See LICENSE and ThirdPartyNotices.txt in the project root for license information. | |
* ------------------------------------------------------------------------------------------ */ | |
'use strict'; | |
import { | |
IPCMessageReader, IPCMessageWriter, createConnection, IConnection, InitializeResult, | |
TextDocuments, Diagnostic, TextDocument | |
} from 'vscode-languageserver'; | |
import { readFileSync, lstatSync } from 'fs'; | |
import * as path from 'path'; | |
// Create a connection for the server. The connection uses Node's IPC as a transport | |
let connection: IConnection = createConnection(new IPCMessageReader(process), new IPCMessageWriter(process)); | |
var documents = new TextDocuments(); | |
documents.listen(connection) | |
interface singleLineRange { | |
start: number | |
end: number | |
} | |
interface functionInformation { | |
commands: FunctionLine[] | |
} | |
interface interpretedCommand { | |
parts: part[] | |
equivalent?: part | |
} | |
var availableCommands: interpretedCommand[] = []; | |
var computedDocuments: { [uri: string]: functionInformation } = {}; | |
interface FunctionLine { | |
diagnostics: Diagnostic[] | |
text: string | |
command: commandSection[] | |
} | |
interface commandSection { | |
part: part | |
subSections: commandSection[] | |
range: singleLineRange | |
valid: boolean | |
} | |
type partType = "literal" | "entities" | "entity" | "players" | "string" | "id" | "x y z" | "x y" | "x z" | "nbt" | "item" | "int" | "bool" | "block" | "x y" | "float" | "json" | "player"; | |
interface part { | |
type: partType | |
value: string //The name or, in the case of "literal", the literal value. This name is only for hover support if provided | |
additionalInfo?: { | |
noFollowSpace?: boolean //Whether a space after this argument is to not be assumed. | |
final?: boolean | |
} | |
} | |
interface functionDiagnostic { | |
} | |
interface subValidatorReturn { | |
subSections: commandSection[] | |
diagnostics: functionDiagnostic[] | |
} | |
let workspaceRoot: string; | |
connection.onInitialize((params): InitializeResult => { | |
workspaceRoot = params.rootUri; //Replaced as rootPath is deprecated | |
return { | |
capabilities: { | |
// Tell the client that the server works in incremental text document sync mode | |
textDocumentSync: documents.syncKind, | |
} | |
} | |
}); | |
// hold the maxNumberOfProblems setting | |
let maxNumberOfProblems: number; | |
//Hold the available commands (in the format as at https://gist.github.com/Dinnerbone/943fbcd763c19be188ed6b72a12d7e65/a7ecc4cfb1d12b66aeb6d4e7f643bec227f0d4f7) | |
let commands: string[]; | |
connection.onDidChangeConfiguration((change) => { | |
function pathValid(uri: string): boolean { | |
try { | |
return !lstatSync(uri).isDirectory(); | |
} catch (error) { | |
return false; | |
} | |
} | |
interface mcfunctionSettings { | |
maxNumberOfProblems?: number, | |
commandsFilePath?: string | |
} | |
interface Settings { | |
mcfunction: mcfunctionSettings; | |
} | |
let settings = <Settings>change.settings; | |
maxNumberOfProblems = settings.mcfunction.maxNumberOfProblems || 100; | |
let fallbackURI = path.join(__dirname, "..", "commands", "minecraft_commands.txt"); | |
let commandsURI: string; | |
if (settings.mcfunction.commandsFilePath) { //If the setting is set | |
let normalizedPath = path.normalize(settings.mcfunction.commandsFilePath); | |
if (pathValid(normalizedPath)) { //If it is a resolving filepath | |
commandsURI = normalizedPath; //URI is the value of the setting | |
} else { | |
if (workspaceRoot !== null) { //If a folder is open | |
let joinedPath = path.join(workspaceRoot, settings.mcfunction.commandsFilePath); | |
if (pathValid(joinedPath)) { //If it is a relative URI from the workspaceRoot and not a directory | |
commandsURI = joinedPath; //Set the URI to this value | |
} else { | |
commandsURI = fallbackURI; //In all other cases, use the fallback URI | |
} | |
} else { | |
commandsURI = fallbackURI; | |
} | |
} | |
} else { | |
commandsURI = fallbackURI; | |
} | |
try { | |
commands = readFileSync(commandsURI).toString().split(/\r?\n/g); | |
} | |
catch (e) { | |
throw "No command set could be found. This is most likely to be caused by your extension folder not containing a command set. If you see this error, please report it at https://github.com/Levertion/vscode-mcfunction/issues. This could also have occured if you moved your command set during the "; | |
} | |
for (var s = 0; s < commands.length; s++) { | |
availableCommands[s] = interpret(commands[s]); | |
} | |
// Revalidate any open text documents | |
documents.all().forEach(calculateFunction); | |
}); | |
function isValidPartType(type: string): partType { | |
if (["literal", "entities", "entity", "players", "string", "id", "x y z", "x y", "x z", "nbt", "item", "int", "bool", "block", "x y", "float", "json", "player"].includes(type)) { | |
return <partType>type; | |
} | |
else { | |
throw `|${type}| is not available as a type`; | |
} | |
}; | |
function interpret(command: string): interpretedCommand { | |
let intParts: part[] = []; | |
let equiv: RegExpExecArray = /-> (.+)/.exec(command); | |
if (equiv) { //Work out the equivalent sections | |
command = command.substring(0, command.length - equiv[0].length); | |
var equivalent: part = { type: "literal", value: equiv[1] }; | |
} | |
while (command.length > 0) { | |
let lenChange: number; | |
let sections: RegExpExecArray, section: string; | |
switch (/[ <]|$/.exec(command)[0]) { | |
case "<": //Argument calculation | |
sections = /(.+?)>(?: |(.)|$)/.exec(command); | |
section = sections[1]; | |
lenChange = sections[0].length; | |
let split = section.split(/: ?/); | |
try { | |
let type: partType = isValidPartType(split[1]); | |
intParts.push({ value: split[0].substring(1), type: type, additionalInfo: { noFollowSpace: sections.length == 3 } }); | |
} catch (e) { | |
connection.console.error(e); | |
} | |
break; | |
default: //Anything else (space or command end) | |
sections = /(.+?)(?: |$)/.exec(command); | |
intParts.push({ type: "literal", value: (sections[1]) }); | |
lenChange = sections[0].length; | |
break; | |
} | |
command = command.substring(lenChange); | |
} | |
return { equivalent, parts: intParts }; | |
} | |
function validateCommand(command: string): subValidatorReturn { return {} } | |
function calculateFunction(document: TextDocument): void { | |
let lines = document.getText().split(/\r?\n/); | |
for (var i = 0; i < lines.length; i++) { | |
let line = lines[i]; | |
let lineReturn = validateCommand(line); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment