diff --git a/CHANGELOG.md b/CHANGELOG.md index aabf1ca..d71f710 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,23 @@ All notable changes to the "vscode-mc-shader" extension will be documented in th The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) -## [Unreleased] +## [0.8.4] + +### Fixed + +- Filtering out `global const initializers must be constant`. "Something something non-standard shader extensions that GPU developers implicitly enable" - Dethraid + +## [0.8.3] + +### Fixed + +- Filtering out gpu_shader4 in code + +## [0.8.2] ### Added -- Incomplete completion items - Support for #include directives -- Basic linting with highlighting. -- Support for .fsh, .vsh, .glsl and .gsh files. \ No newline at end of file +- Basic linting with highlighting with error propogation to all known parents of an include. +- Support for .fsh, .vsh, .glsl and .gsh files. +- Incomplete completion items \ No newline at end of file diff --git a/README.md b/README.md index 2b69a4e..42a7026 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ [![Maintainability](https://api.codeclimate.com/v1/badges/c2c813cb0a42a8aad483/maintainability)](https://codeclimate.com/github/Strum355/vscode-mc-shader/maintainability) [![Waffle.io - Columns and their card count](https://badge.waffle.io/Strum355/vscode-mc-shader.svg?columns=all)](https://waffle.io/Strum355/vscode-mc-shader) --> -VSCode-MC-Shader is a [Visual Studio Code](https://code.visualstudio.com/) extension for developing Minecraft GLSL Shaders for [Optifine](http://optifine.net). It currently provides linting and syntax highlighting (by stef-levesque/vscode-shader dependency). +VSCode-mc-shader is a [Visual Studio Code](https://code.visualstudio.com/) extension for developing Minecraft GLSL Shaders for [Optifine](http://optifine.net). It currently provides linting and syntax highlighting (by stef-levesque/vscode-shader dependency). @@ -16,23 +16,22 @@ VSCode-MC-Shader is a [Visual Studio Code](https://code.visualstudio.com/) exten - Linting - Syntax highlighting (by extension dependency) - Support for `#include` directives -- Auto-complete prompts (incomplete) +- Auto-complete prompts (incomplete and rough) -## Planned +## Installation (assumes installing from VSCode extension tab) -- Multi-workspaces (currently only one is supported and using multiple is very undefined behaviour) -- Warnings for unused uniforms/varyings -- Some cool `DRAWBUFFERS` stuff - -Got a feature request? Chuck it into an Issue! +- After reloading, open a shaderpack's folder. +- You should be prompted to set your shaderpacks folder e.g. `"mcglsl.shaderpacksPath": "C:/Users/Noah/AppData/Roaming/.minecraft/shaderpacks"` +- You should then be prompted saying `glslangValidator` isn't installed. Hit the download button and wait for a notification saying that it's been installed. +- You should now be good to go! ## Requirements -- Visual Studio Code (v1.17.0 or higher - minimum requirement untested) +- Visual Studio Code (v1.23.0 or higher - minimum requirement untested). - The [Shader languages support for VS Code](https://marketplace.visualstudio.com/items?itemName=slevesque.shader) extension. This should automatically install when you install this extension. - That the shader(s) you're editing are in the `shaderpacks` folder in `.minecraft`. -- The [OpenGL / OpenGL ES Reference Compiler](https://github.com/KhronosGroup/glslang) (for convenience, put it in your PATH, this is the assumed location if not specified). If, for some reason, you're using MacOS, there are no pre-compiled binaries of this. -- [MacOS] Not MacOS. Not that you're making MC Shaders on/for MacOS anyways...right? +- That you've only one shader folder open. Multiple workspaces aren't currently supported. +- The [OpenGL / OpenGL ES Reference Compiler](https://github.com/KhronosGroup/glslang). The extension will give you an option to download it and update your settings automatically. ## Extension Settings @@ -45,14 +44,22 @@ Got a feature request? Chuck it into an Issue! Please see [CONTRIBUTING.md](https://github.com/Strum355/vscode-mc-shader/blob/master/CONTRIBUTING.md). +## Planned + +- Multi-workspaces (currently only one is supported and using multiple is very undefined behaviour) +- Warnings for unused uniforms/varyings +- Some cool `DRAWBUFFERS` stuff + +Got a feature request? Chuck it into an Issue! + ## Known Issues -I'll fill this in once this actually gets released. +Check the issues on Github [here](https://github.com/Strum355/vscode-mc-shader/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Abug). ## Release Notes -None yet. +Check [CHANGELOG.md](https://github.com/Strum355/vscode-mc-shader/blob/master/CHANGELOG.md). ## License -This code is released under the MIT License. Copyright (c) 2018 Noah Santschi-Cooney +This code is released under the [MIT License](https://github.com/Strum355/vscode-mc-shader/blob/master/LICENSE). Copyright (c) 2018 Noah Santschi-Cooney diff --git a/package.json b/package.json index 18f0310..0c60624 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "vscode-mc-shader", "displayName": "Minecraft GLSL Shaders", "description": "A Visual Studio Code extension for linting/etc Minecraft GLSL Shaders", - "version": "0.8.1", + "version": "0.8.4", "publisher": "Strum355", "author": "Noah Santschi-Cooney (Strum355)", "license": "MIT", diff --git a/server/src/config.ts b/server/src/config.ts index 42cd085..2271d15 100644 --- a/server/src/config.ts +++ b/server/src/config.ts @@ -7,7 +7,7 @@ import { postError } from './utils' import { execSync } from 'child_process' import { serverLog } from './logging' import { dirname } from 'path' -import { DidChangeConfigurationParams } from 'vscode-languageserver/lib/main' +import { DidChangeConfigurationParams } from 'vscode-languageserver' import { win } from './linter' const url = { @@ -36,8 +36,10 @@ export async function onConfigChange(change: DidChangeConfigurationParams) { if (conf.shaderpacksPath === '' || conf.shaderpacksPath.replace(dirname(conf.shaderpacksPath), '') !== '/shaderpacks') { if (supress) return + serverLog.error(() => 'shaderpack path not set or doesn\'t end in \'shaderpacks\'', null) supress = true + const clicked = await connection.window.showErrorMessage( 'mcglsl.shaderpacksPath is not set or doesn\'t end in \'shaderpacks\'. Please set it in your settings.', {title: 'Supress'} @@ -78,29 +80,47 @@ async function promptDownloadGlslang() { async function downloadGlslang() { connection.window.showInformationMessage('Downloading. Your settings will be updated automatically and you\'ll be notified when its done.') + serverLog.info(() => 'downloading glslangValidator...') + const res = await fetch(url[platform()]) + serverLog.info(() => 'glslangValidator downloaded. Extracting...') + try { const zip = createWriteStream(conf.shaderpacksPath + '/glslangValidator.zip') res.body.pipe(zip) + const glslang = '/glslangValidator' + (win ? '.exe' : '') + zip.on('finish', () => { - createReadStream(conf.shaderpacksPath + '/glslangValidator.zip') - .pipe(unzip.Parse()) - .on('entry', entry => { - if (entry.path === 'bin/glslangValidator' + win ? '.exe' : '') { - entry.pipe(createWriteStream(conf.shaderpacksPath + '/glslangValidator' + win ? '.exe' : '')) - return - } - entry.autodrain() - }) - .on('close', () => { - chmodSync(conf.shaderpacksPath + '/glslangValidator' + win ? '.exe' : '', 0o775) - unlinkSync(conf.shaderpacksPath + '/glslangValidator.zip') - connection.sendNotification('update-config', conf.shaderpacksPath + '/glslangValidator' + win ? '.exe' : '') - connection.window.showInformationMessage('glslangValidator has been downloaded to ' + conf.shaderpacksPath + '/glslangValidator. Your config should be updated automatically.') - glslangReady = true - }) + try { + createReadStream(conf.shaderpacksPath + '/glslangValidator.zip') + .pipe(unzip.Parse()) + .on('entry', entry => { + try { + if (entry.path === 'bin' + glslang) { + entry.pipe(createWriteStream(conf.shaderpacksPath + glslang)) + return + } + entry.autodrain() + } catch (e) { + postError(e) + } + }) + .on('close', () => { + try { + chmodSync(conf.shaderpacksPath + glslang, 0o775) + unlinkSync(conf.shaderpacksPath + '/glslangValidator.zip') + connection.sendNotification('update-config', conf.shaderpacksPath + glslang) + connection.window.showInformationMessage('glslangValidator has been downloaded to ' + conf.shaderpacksPath + '/glslangValidator. Your config should be updated automatically.') + glslangReady = true + } catch (e) { + postError(e) + } + }) + } catch (e) { + postError(e) + } }) } catch (e) { postError(e) diff --git a/server/src/linter.ts b/server/src/linter.ts index c6cdda6..b0719e2 100644 --- a/server/src/linter.ts +++ b/server/src/linter.ts @@ -1,12 +1,12 @@ import { Diagnostic, DiagnosticSeverity, Range } from 'vscode-languageserver' -import { connection, documents } from './server' +import { connection } from './server' import { execSync } from 'child_process' import * as path from 'path' -import { readFileSync, existsSync, statSync, Stats } from 'fs' +import { readFileSync, statSync } from 'fs' import { conf } from './config' -import { postError, formatURI, getDocumentContents, trimPath } from './utils' +import { formatURI, getDocumentContents, trimPath } from './utils' import { platform } from 'os' -import { Graph, Node } from './graph' +import { Graph } from './graph' import { Comment } from './comment' import { linterLog } from './logging' @@ -17,11 +17,16 @@ const reIncludeExt = /#extension GL_GOOGLE_include_directive ?: ?require/ const include = '#extension GL_GOOGLE_include_directive : require' export const win = platform() === 'win32' -const filters = [ +const errorFilters = [ /stdin/, /(No code generated)/, /(compilation terminated)/, - /Could not process include directive for header name:/ + /Could not process include directive for header name:/, + /global const initializers must be constant/, +] + +const codeFilters = [ + /#extension GL_EXT_gpu_shader4 : require/, ] export const includeGraph = new Graph() @@ -82,19 +87,18 @@ const tokens = new Map([ ]) export function preprocess(lines: string[], docURI: string) { - const hasDirective = includeDirective(lines, docURI) + const hasDirective = includeDirective(lines) - const allIncludes = new Set() const diagnostics = new Map() - processIncludes(lines, [docURI], allIncludes, diagnostics, hasDirective) + processIncludes(lines, [docURI], new Set(), diagnostics, hasDirective) - const includeMap = new Map(Array.from(allIncludes).map(obj => [obj.path, obj]) as [string, IncludeObj][]) + //const includeMap = new Map(Array.from(allIncludes).map(obj => [obj.path, obj]) as [string, IncludeObj][]) - lint(docURI, lines, includeMap, diagnostics, hasDirective) + lint(docURI, lines, diagnostics, hasDirective) } -function includeDirective(lines: string[], docURI: string): boolean { +function includeDirective(lines: string[]): boolean { if (lines.findIndex(x => reIncludeExt.test(x)) > -1) { linterLog.info(() => 'include directive found') return true @@ -256,10 +260,12 @@ function mergeInclude(inc: IncludeObj, lines: string[], incStack: string[], diag // merge the lines of the file into the current document lines.splice(inc.lineNumTopLevel + 1, 0, ...dataLines) // add the closing #line indicating we're re-entering a block a level up - lines.splice(inc.lineNumTopLevel + 1 + dataLines.length, 0, `#line ${inc.lineNum + 1} "${inc.parent}"`) + lines.splice(inc.lineNumTopLevel + 1 + dataLines.length, 0, `#line ${inc.lineNum} "${inc.parent}"`) } -function lint(docURI: string, lines: string[], includes: Map, diagnostics: Map, hasDirective: boolean) { +function lint(docURI: string, lines: string[], diagnostics: Map, hasDirective: boolean) { + lines.forEach((l, i) => {if (codeFilters.some(r => r.test(l))) lines[i] = ''}) + let out: string = '' try { execSync(`${conf.glslangPath} --stdin -S ${ext.get(path.extname(docURI))}`, {input: lines.join('\n')}) @@ -274,7 +280,16 @@ function lint(docURI: string, lines: string[], includes: Map processErrors(out, docURI, diagnostics, hasDirective) - daigsArray(diagnostics).forEach(d => { + diagnostics.forEach((diags, uri) => { + if (diags.length === 0) return + linterLog.info(() => `found ${diags.length} error(s) for ${trimPath(uri)}`) + }) + + const diagsList = daigsArray(diagnostics) + + if (diagsList.filter(d => d.diag.length > 0).length === 0) linterLog.info(() => 'no errors found') + + diagsList.forEach(d => { if (win) d.uri = d.uri.replace('file://C:', 'file:///c%3A') connection.sendDiagnostics({uri: d.uri, diagnostics: d.diag}) }) @@ -293,7 +308,8 @@ function processErrors(out: string, docURI: string, diagnostics: Map) => Array.from(diags).map(k const filterMatches = (output: string) => output .split('\n') - .filter(s => s.length > 1 && !filters.some(reg => reg.test(s))) + .filter(s => s.length > 1 && !errorFilters.some(reg => reg.test(s))) .map(s => s.match(reDiag)) .filter(match => match && match.length === 5) function calcRange(lineNum: number, uri: string): Range { - linterLog.debug(() => `calculating range for ${trimPath(uri)} at L${lineNum}`) + linterLog.debug(() => `calculating range for ${trimPath(uri)} at L${lineNum + 1}`) const lines = getDocumentContents(uri).split('\n') - const line = lines[lineNum] + const line = lines[Math.min(Math.max(lineNum, 0), lines.length - 1)] const startOfLine = line.length - line.trimLeft().length const endOfLine = line.trimRight().length + 1 //const endOfLine = line.slice(0, line.indexOf('//')).trimRight().length + 2