diff --git a/README.md b/README.md index 2297e0c..bcecfa2 100644 --- a/README.md +++ b/README.md @@ -12,9 +12,9 @@ VSCode-MC-Shader is a [Visual Studio Code](https://code.visualstudio.com/) exten ## Features -- Linting (unpolished) +- Linting - Syntax highlighting (by extension dependency) -- Support for `#includes` directives +- Support for `#include` directives - Auto-complete prompts (incomplete) ## Planned @@ -37,7 +37,6 @@ Got a feature request? Chuck it into an Issue! | Option Name | Data Type | Description | Default Value | | ----------- | --------- | ----------- | ------------- | | `mcglsl.glslangValidatorPath` | string | The path to the glslangValidator executable. | In your `PATH`.| -| `mcglsl.lintOnType` | bool | Whether or not to lint while typing. Can decrease performance. | `false` | | `mcglsl.shaderpacksPath` | string | The path to the shaderpacks folder in your Minecraft installation folder. | None | ## Contributing diff --git a/package.json b/package.json index 1b9d5f6..c4ff5a6 100644 --- a/package.json +++ b/package.json @@ -1,9 +1,9 @@ { "name": "vscode-mc-shader", - "displayName": "vscode-mc-shader", + "displayName": "Minecraft GLSL Shader", "description": "A Visual Studio Code extension for linting/etc Minecraft GLSL Shaders", - "version": "0.0.1", - "publisher": "Noah Santschi-Cooney (Strum355)", + "version": "0.9.0", + "publisher": "Strum355", "author": "Noah Santschi-Cooney (Strum355)", "license": "MIT", "repository": { @@ -50,11 +50,6 @@ "default": "glslangValidator", "description": "The path to the glslangValidator executable. Default value assumes its in your PATH." }, - "mcglsl.lintOnType": { - "type": "boolean", - "default": false, - "description": "Whether or not to lint while typing. May decrease performance." - }, "mcglsl.shaderpacksPath": { "type": "string", "default": "", diff --git a/server/src/config.ts b/server/src/config.ts index c8dc5d4..1154e2c 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -1,10 +1,12 @@ import { connection, documents, onEvent } from './server' import fetch from 'node-fetch' import { platform } from 'os' -import { createWriteStream, chmodSync, createReadStream, unlinkSync } from 'fs' +import { createWriteStream, chmodSync, createReadStream, unlinkSync, read } from 'fs' import * as unzip from 'unzip' import { postError } from './utils' import { execSync } from 'child_process' +import { serverLog } from './logging' +import { dirname } from 'path' const url = { 'win32': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-windows-x64-Release.zip', @@ -12,6 +14,8 @@ const url = { 'darwin': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-osx-Release.zip' } +export let glslangReady = false + export interface Config { readonly shaderpacksPath: string readonly glslangPath: string @@ -21,17 +25,28 @@ export let conf: Config = {shaderpacksPath: '', glslangPath: ''} export const onConfigChange = async (change) => { const temp = change.settings.mcglsl as Config + if (temp.shaderpacksPath === conf.shaderpacksPath && temp.glslangPath === conf.glslangPath) return conf = {shaderpacksPath: temp['shaderpacksPath'].replace(/\\/g, '/'), glslangPath: temp['glslangValidatorPath'].replace(/\\/g, '/')} + serverLog.debug(() => 'new config: ' + JSON.stringify(temp)) + serverLog.debug(() => 'old config: ' + JSON.stringify(conf)) + + if (conf.shaderpacksPath === '' || conf.shaderpacksPath.replace(dirname(conf.shaderpacksPath), '') !== '/shaderpacks') { + serverLog.error(() => 'shaderpack path not set or doesn\'t end in \'shaderpacks\'', null) + connection.window.showErrorMessage('mcglsl.shaderpacksPath is not set or doesn\'t end in \'shaderpacks\'. Please set it in your settings.') + return + } try { if (!execSync(conf.glslangPath).toString().startsWith('Usage')) { documents.all().forEach(onEvent) + glslangReady = true } else { promptDownloadGlslang() } } catch (e) { if ((e.stdout.toString() as string).startsWith('Usage')) { documents.all().forEach(onEvent) + glslangReady = true } else { promptDownloadGlslang() } @@ -47,11 +62,6 @@ async function promptDownloadGlslang() { if (!chosen || chosen.title !== 'Download') return - if (conf.shaderpacksPath === '') { - connection.window.showErrorMessage('Please set mcglsl.shaderpacksPath as this is where glslangValidator will be saved to.') - return - } - downloadGlslang() } @@ -76,7 +86,8 @@ async function downloadGlslang() { chmodSync(conf.shaderpacksPath + '/glslangValidator', 0o775) unlinkSync(conf.shaderpacksPath + '/glslangValidator.zip') connection.sendNotification('update-config', conf.shaderpacksPath + '/glslangValidator') - connection.window.showInformationMessage('glslangValidator has been downloaded to ' + conf.shaderpacksPath + '/glslangValidator') + connection.window.showInformationMessage('glslangValidator has been downloaded to ' + conf.shaderpacksPath + '/glslangValidator. Your config should be updated automatically.') + glslangReady = true }) }) } catch (e) { diff --git a/server/src/graph.ts b/server/src/graph.ts index d741254..83c2b58 100644 --- a/server/src/graph.ts +++ b/server/src/graph.ts @@ -1,3 +1,9 @@ +// can you imagine that some people out there would import a whole library just for this? +export type Pair = { + first: T, + second: S +} + type Node = { parents: Map> children: Map @@ -10,6 +16,11 @@ export class Graph { return this.nodes.has(uri) ? this.nodes.get(uri).parents.size > 0 : false } + public get(uri: string): Node { + if (!this.nodes.has(uri)) this.nodes.set(uri, {parents: new Map(), children: new Map()}) + return this.nodes.get(uri) + } + public setParent(uri: string, parent: string, lineNum: number) { const par: Node = this.nodes.has(parent) ? this.nodes.get(parent) : {parents: new Map(), children: new Map()} if (this.nodes.has(uri)) { @@ -17,21 +28,14 @@ export class Graph { node.parents.set(parent, {first: lineNum, second: par}) par.children.set(uri, node) } else { - const node: Node = {parents: new Map([par].map(p => [parent, {first: lineNum, second: p}]) as [string, Pair][]), children: new Map()} + const node: Node = { + parents: new Map([par].map(p => [parent, {first: lineNum, second: p}]) as [string, Pair][]), + children: new Map() + } + par.children.set(uri, node) this.nodes.set(uri, node) } this.nodes.set(parent, par) } - - public get(uri: string): Node { - if (!this.nodes.has(uri)) this.nodes.set(uri, {parents: new Map(), children: new Map()}) - return this.nodes.get(uri) - } -} - -// can you imagine that some people out there would import a whole library just for this? -export type Pair = { - first: T, - second: S } \ No newline at end of file diff --git a/server/src/linter.ts b/server/src/linter.ts index e0cb61f..ebddef8 100644 --- a/server/src/linter.ts +++ b/server/src/linter.ts @@ -136,7 +136,7 @@ function processIncludes(lines: string[], incStack: string[], allIncludes: Set Array.from(tokens.entries()).reduce((acc, [key, value]) => acc.replace(key, value), msg) +const replaceWords = (msg: string) => Array.from(tokens.entries()).reduce((acc, [key, value]) => acc.replace(key, value), msg) const errorType = (error: string) => error === 'ERROR' ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning @@ -333,7 +333,7 @@ function calcRange(lineNum: number, uri: string): Range { return Range.create(lineNum, startOfLine, lineNum, endOfLine) } -export function absPath(currFile: string, includeFile: string): string { +function absPath(currFile: string, includeFile: string): string { if (!currFile.startsWith(conf.shaderpacksPath) || conf.shaderpacksPath === '') { connection.window.showErrorMessage(`Shaderpacks path may not be correct. Current file is in '${currFile}' but the path is set to '${conf.shaderpacksPath}'`) return '' diff --git a/server/src/logging.ts b/server/src/logging.ts index 93971a8..4674012 100644 --- a/server/src/logging.ts +++ b/server/src/logging.ts @@ -3,4 +3,5 @@ import { CategoryServiceFactory, CategoryConfiguration, LogLevel, Category } fro CategoryServiceFactory.setDefaultConfiguration(new CategoryConfiguration(LogLevel.Debug)) export const linterLog = new Category('linter') -export const completionLog = new Category('completion') \ No newline at end of file +export const completionLog = new Category('completion') +export const serverLog = new Category('server') \ No newline at end of file diff --git a/server/src/server.ts b/server/src/server.ts index d159511..cb5ecc7 100644 --- a/server/src/server.ts +++ b/server/src/server.ts @@ -2,14 +2,14 @@ import * as vsclang from 'vscode-languageserver' import * as vsclangproto from 'vscode-languageserver-protocol' import { completions } from './completionProvider' import { preprocess, ext, includeGraph } from './linter' -import { extname } from 'path' +import { extname, dirname } from 'path' const reVersion = /#version [\d]{3}/ export let connection: vsclang.IConnection connection = vsclang.createConnection(new vsclang.IPCMessageReader(process), new vsclang.IPCMessageWriter(process)) -import { onConfigChange } from './config' +import { onConfigChange, conf, glslangReady } from './config' import { formatURI, postError, getDocumentContents } from './utils' export const documents = new vsclang.TextDocuments() @@ -39,6 +39,8 @@ documents.onDidClose((event) => connection.sendDiagnostics({uri: event.document. //documents.onDidChangeContent(onEvent) export function onEvent(document: vsclangproto.TextDocument) { + if (conf.shaderpacksPath.replace(dirname(conf.shaderpacksPath), '') !== '/shaderpacks' || !glslangReady) return + const uri = formatURI(document.uri) if (includeGraph.get(uri).parents.size > 0) { lintBubbleDown(uri, document) diff --git a/server/src/utils.ts b/server/src/utils.ts index 0180f05..a7e8766 100644 --- a/server/src/utils.ts +++ b/server/src/utils.ts @@ -1,10 +1,11 @@ import { connection, documents } from './server' import { readFileSync } from 'fs' import { conf } from './config' +import { serverLog } from './logging' export function postError(e: Error) { connection.window.showErrorMessage(e.message) - console.log(e) + serverLog.error(e.message, new Error()) } export const formatURI = (uri: string) => uri.replace(/^file:\/\//, '').replace(/^(?:\/)c%3A/, 'C:').replace(/\\/g, '/')