Added support for ../ includes

This commit is contained in:
Noah Santschi-Cooney 2018-08-05 20:35:34 +01:00
parent 243eb671bc
commit 2421aeb32c
No known key found for this signature in database
GPG key ID: 3B22282472C8AE48
6 changed files with 48 additions and 47 deletions

View file

@ -1,11 +1,11 @@
# Minecraft GLSL Shaders
## vscode-mc-shader
[![CI](https://ci.netsoc.co/api/badges/Strum355/vscode-mc-shader/status.svg?branch=master)](https://ci.netsoc.co/Strum355/vscode-mc-shader)
<!-- [![CI](https://ci.netsoc.co/api/badges/Strum355/vscode-mc-shader/status.svg?branch=master)](https://ci.netsoc.co/Strum355/vscode-mc-shader)
[![Issues](https://img.shields.io/github/issues-raw/Strum355/vscode-mc-shader.svg)](https://github.com/Strum355/vscode-mc-shader/issues)
[![license](https://img.shields.io/github/license/Strum355/vscode-mc-shader.svg)](https://github.com/Strum355/vscode-mc-shader)
[![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)
[![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).
@ -31,7 +31,7 @@ Got a feature request? Chuck it into an Issue!
- Visual Studio Code (v1.17.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://cvs.khronos.org/svn/repos/ogl/trunk/ecosystem/public/sdk/tools/glslang/Install/) (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.
- 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?
## Extension Settings

View file

@ -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.9.0",
"version": "0.8.1",
"publisher": "Strum355",
"author": "Noah Santschi-Cooney (Strum355)",
"license": "MIT",

View file

@ -33,10 +33,7 @@ export namespace Comment {
function empty(i: number, line: string, twice: boolean): string {
line = line.substr(0, i) + ' ' + line.substr(i + 1)
if (twice) {
i++
line = line.substr(0, i) + ' ' + line.substr(i + 1)
}
if (twice) line = line.substr(0, i + 1) + ' ' + line.substr(i + 3)
return line
}
}

View file

@ -8,6 +8,7 @@ import { execSync } from 'child_process'
import { serverLog } from './logging'
import { dirname } from 'path'
import { DidChangeConfigurationParams } from 'vscode-languageserver/lib/main'
import { win } from './linter';
const url = {
'win32': 'https://github.com/KhronosGroup/glslang/releases/download/master-tot/glslang-master-windows-x64-Release.zip',
@ -87,16 +88,16 @@ async function downloadGlslang() {
createReadStream(conf.shaderpacksPath + '/glslangValidator.zip')
.pipe(unzip.Parse())
.on('entry', entry => {
if (entry.path === 'bin/glslangValidator') {
entry.pipe(createWriteStream(conf.shaderpacksPath + '/glslangValidator'))
if (entry.path === 'bin/glslangValidator' + win ? '.exe' : '') {
entry.pipe(createWriteStream(conf.shaderpacksPath + '/glslangValidator' + win ? '.exe' : ''))
return
}
entry.autodrain()
})
.on('close', () => {
chmodSync(conf.shaderpacksPath + '/glslangValidator', 0o775)
chmodSync(conf.shaderpacksPath + '/glslangValidator' + win ? '.exe' : '', 0o775)
unlinkSync(conf.shaderpacksPath + '/glslangValidator.zip')
connection.sendNotification('update-config', conf.shaderpacksPath + '/glslangValidator')
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
})

View file

@ -15,7 +15,7 @@ const reVersion = /#version [\d]{3}/
const reInclude = /^(?:\s)*?(?:#include) "(.+)"\r?/
const reIncludeExt = /#extension GL_GOOGLE_include_directive ?: ?require/
const include = '#extension GL_GOOGLE_include_directive : require'
const win = platform() === 'win32'
export const win = platform() === 'win32'
const filters = [
/stdin/,
@ -111,11 +111,11 @@ function includeDirective(lines: string[], docURI: string): boolean {
break
}
if (i === lines.length - 1) {
/* if (i === lines.length - 1) {
linterLog.warn(() => `no version found for ${docURI}. inserting at top`)
lines.splice(0, 0, include)
break
}
} */
}
return hasDirective
}
@ -123,11 +123,10 @@ function includeDirective(lines: string[], docURI: string): boolean {
const buildIncludeGraph = (inc: IncludeObj) => includeGraph.setParent(inc.path, inc.parent, inc.lineNum)
function processIncludes(lines: string[], incStack: string[], allIncludes: Set<IncludeObj>, diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
// todo figure out why incStack[0] here
const includes = getIncludes(incStack[0], lines)
const parent = incStack[incStack.length - 1]
const includes = getIncludes(parent, lines)
includes.forEach(i => allIncludes.add(i))
const parent = incStack[incStack.length - 1]
includeGraph.nodes.get(parent).children.forEach((node, uri) => {
if (!includes.has(uri)) {
includeGraph.nodes.get(parent).children.delete(uri)
@ -154,14 +153,14 @@ function getIncludes(uri: string, lines: string[]) {
total: -1,
comment: Comment.State.No,
parStack: [uri],
count: [0],
count: [-1],
}
return new Map(lines.reduce<IncludeObj[]>((out, line, i) => processLine(out, line, lines, i, lineInfo), []).map(inc => [inc.path, inc] as [string, IncludeObj]))
return lines.reduce<Map<string, IncludeObj>>((out, line, i) => processLine(out, line, lines, i, lineInfo), new Map())
}
// TODO can surely be reworked
function processLine(includes: IncludeObj[], line: string, lines: string[], i: number, linesInfo: LinesProcessingInfo): IncludeObj[] {
function processLine(includes: Map<string, IncludeObj>, line: string, lines: string[], i: number, linesInfo: LinesProcessingInfo): Map<string, IncludeObj> {
const updated = Comment.update(line, linesInfo.comment)
linesInfo.comment = updated[0]
@ -177,7 +176,6 @@ function processLine(includes: IncludeObj[], line: string, lines: string[], i: n
if (line.startsWith('#line')) {
const inc = line.slice(line.indexOf('"') + 1, line.lastIndexOf('"'))
if (inc === linesInfo.parStack[linesInfo.parStack.length - 2]) {
linesInfo.count.pop()
linesInfo.parStack.pop()
@ -191,13 +189,16 @@ function processLine(includes: IncludeObj[], line: string, lines: string[], i: n
const match = line.match(reInclude)
if (match) {
includes.push({
path: formatURI(absPath(linesInfo.parStack[linesInfo.parStack.length - 1], match[1])),
lineNum: linesInfo.count[linesInfo.count.length - 1],
lineNumTopLevel: linesInfo.total,
parent: formatURI(linesInfo.parStack[linesInfo.parStack.length - 1]),
match
})
includes.set(
formatURI(absPath(linesInfo.parStack[linesInfo.parStack.length - 1], match[1])),
{
path: formatURI(absPath(linesInfo.parStack[linesInfo.parStack.length - 1], match[1])),
lineNum: linesInfo.count[linesInfo.count.length - 1],
lineNumTopLevel: linesInfo.total,
parent: formatURI(linesInfo.parStack[linesInfo.parStack.length - 1]),
match
}
)
}
return includes
}
@ -210,7 +211,7 @@ function ifInvalidFile(inc: IncludeObj, lines: string[], incStack: string[], dia
const file = incStack[incStack.length - 1]
const diag: Diagnostic = {
severity: DiagnosticSeverity.Error,
range: calcRange(inc.lineNum, file),
range: calcRange(inc.lineNum - ((!hasDirective && includeGraph.get(file).parents.size === 0) ? 1 : 0), file),
message: msg,
source: 'mc-glsl'
}
@ -227,9 +228,13 @@ function ifInvalidFile(inc: IncludeObj, lines: string[], incStack: string[], dia
}
function mergeInclude(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
let stats: Stats
try {
stats = statSync(inc.path)
const stats = statSync(inc.path)
if (!stats.isFile()) {
const err = new Error()
err['code'] = 'ENOENT'
throw err
}
} catch (e) {
if (e.code === 'ENOENT') {
ifInvalidFile(inc, lines, incStack, diagnostics, hasDirective)
@ -238,11 +243,6 @@ function mergeInclude(inc: IncludeObj, lines: string[], incStack: string[], diag
throw e
}
if (!stats.isFile()) {
ifInvalidFile(inc, lines, incStack, diagnostics, hasDirective)
return
}
const dataLines = readFileSync(inc.path).toString().split('\n')
// if the includes parent is the top level (aka where the include directive is placed)
@ -293,9 +293,8 @@ function processErrors(out: string, docURI: string, diagnostics: Map<string, Dia
const diag: Diagnostic = {
severity: error.type,
// had to do - 2 here instead of - 1, windows only perhaps?
range: calcRange(error.line - ((!hasDirective && includeGraph.get(fileName).parents.size === 0) ? 2 : 1), fileName),
message: `Line ${error.line} ${replaceWords(error.msg)}`,
message: `Line ${error.line + 1} ${replaceWords(error.msg)}`,
source: 'mc-glsl'
}
@ -311,8 +310,8 @@ function propogateDiagnostic(error: ErrorMatch, diagnostics: Map<string, Diagnos
includeGraph.get(parentURI || error.file).parents.forEach((pair, parURI) => {
const diag: Diagnostic = {
severity: error.type,
range: calcRange(pair.first - (pair.second.parents.size > 0 ? 0 : (2 - (hasDirective ? 1 : 0))), parURI),
message: `Line ${error.line} ${trimPath(error.file)} ${replaceWords(error.msg)}`,
range: calcRange(pair.first - ((!hasDirective && pair.second.parents.size === 0) ? 1 : 0), parURI),
message: `Line ${error.line + 1} ${trimPath(error.file)} ${replaceWords(error.msg)}`,
source: 'mc-glsl'
}
@ -338,6 +337,8 @@ const filterMatches = (output: string) => output
.filter(match => match && match.length === 5)
function calcRange(lineNum: number, uri: string): Range {
linterLog.debug(() => `calculating range for ${trimPath(uri)} at L${lineNum}`)
const lines = getDocumentContents(uri).split('\n')
const line = lines[lineNum]
const startOfLine = line.length - line.trimLeft().length
@ -353,9 +354,11 @@ function absPath(currFile: string, includeFile: string): string {
}
// TODO add explanation comment
if (includeFile.charAt(0) === '/') {
if (includeFile.charAt(0) === '/' || (includeFile.charAt(0) === '.' && includeFile.charAt(1) === '.')) {
const shaderPath = trimPath(currFile).split('/').slice(0, 3).join('/')
return path.join(conf.shaderpacksPath, shaderPath, includeFile)
}
} /* else if (includeFile.charAt(0) === '.' && includeFile.charAt(1) === '.') {
} */
return path.join(path.dirname(currFile), includeFile)
}

View file

@ -45,14 +45,14 @@ export function onEvent(document: vsclangproto.TextDocument) {
const uri = formatURI(document.uri)
if (includeGraph.get(uri).parents.size > 0) {
lintBubbleDown(uri, document)
lintBubbleDown(uri)
return
}
// i think we still need to keep this in case we havent found the root of this files include tree
const lines = document.getText().split('\n')
const hasVersion = lines.filter(l => reVersion.test(l)).length > 0
if (!ext.has(extname(document.uri)) || !hasVersion) return
if (!hasVersion) return
try {
preprocess(document.getText().split('\n'), uri)
@ -61,10 +61,10 @@ export function onEvent(document: vsclangproto.TextDocument) {
}
}
function lintBubbleDown(uri: string, document: vsclangproto.TextDocument) {
function lintBubbleDown(uri: string) {
includeGraph.get(uri).parents.forEach((parent, parentURI) => {
if (parent.second.parents.size > 0) {
lintBubbleDown(parentURI, document)
lintBubbleDown(parentURI)
} else {
const lines = getDocumentContents(parentURI).split('\n')
// feel like we could perhaps do better? Hope no one puts #version at the top of their includes..