mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-07-23 11:15:27 +00:00
OWO whats this? Includes kinda work? Thats right. Except *sometimes* it causes the entire extension to hang for some reason
This commit is contained in:
parent
daa9978eaf
commit
00c4cc487a
3 changed files with 85 additions and 61 deletions
|
@ -3,7 +3,7 @@ import './global'
|
||||||
import { TextDocument, Diagnostic, DiagnosticSeverity, Range } from 'vscode-languageserver'
|
import { TextDocument, Diagnostic, DiagnosticSeverity, Range } from 'vscode-languageserver'
|
||||||
import { exec } from 'child_process'
|
import { exec } from 'child_process'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import { open } from 'fs';
|
import { readFileSync } from 'fs';
|
||||||
|
|
||||||
const reDiag = /^(ERROR|WARNING): ([^?<>:*|"]+?):(\d+): (?:'.*?' : )?(.+)$/
|
const reDiag = /^(ERROR|WARNING): ([^?<>:*|"]+?):(\d+): (?:'.*?' : )?(.+)$/
|
||||||
const reVersion = /#version [\d]{3}/
|
const reVersion = /#version [\d]{3}/
|
||||||
|
@ -13,6 +13,7 @@ const include = '#extension GL_GOOGLE_include_directive : require'
|
||||||
const filters = [
|
const filters = [
|
||||||
/(No code generated)/,
|
/(No code generated)/,
|
||||||
/(compilation terminated)/,
|
/(compilation terminated)/,
|
||||||
|
/Could not process include directive for header name:/
|
||||||
]
|
]
|
||||||
|
|
||||||
const files: {[uri: string]: number} = {}
|
const files: {[uri: string]: number} = {}
|
||||||
|
@ -51,23 +52,9 @@ const tokens: {[key: string]: string} = {
|
||||||
'RIGHT_BRACE': '}'
|
'RIGHT_BRACE': '}'
|
||||||
}
|
}
|
||||||
|
|
||||||
const filterMatches = (output: string) => output
|
|
||||||
.split('\n')
|
|
||||||
.filter(s => s.length > 1 && !filters.some(reg => reg.test(s)))
|
|
||||||
.map(s => s.match(reDiag))
|
|
||||||
.filter(match => match && match.length === 4)
|
|
||||||
|
|
||||||
const replaceWord = (msg: string) => {
|
|
||||||
for (const token of Object.keys(tokens)) {
|
|
||||||
if (msg.includes(token)) {
|
|
||||||
msg = msg.replace(token, tokens[token])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return msg
|
|
||||||
}
|
|
||||||
|
|
||||||
export function preprocess(document: TextDocument, topLevel: boolean, incStack: string[]) {
|
export function preprocess(document: TextDocument, topLevel: boolean, incStack: string[]) {
|
||||||
const lines = document.getText().split('\n').map(s => s.replace(/^\s+|\s+$/g, ''))
|
const lines = document.getText().split('\n')
|
||||||
|
const docURI = formatURI(document.uri)
|
||||||
if (topLevel) {
|
if (topLevel) {
|
||||||
let inComment = false
|
let inComment = false
|
||||||
for (let i = 0; i < lines.length; i++) {
|
for (let i = 0; i < lines.length; i++) {
|
||||||
|
@ -84,62 +71,93 @@ export function preprocess(document: TextDocument, topLevel: boolean, incStack:
|
||||||
}
|
}
|
||||||
|
|
||||||
const includes = getIncludes(lines)
|
const includes = getIncludes(lines)
|
||||||
|
if (includes.length > 0) {
|
||||||
includes.forEach((inc) => {
|
includes.forEach((inc) => {
|
||||||
console.log(absPath(document.uri, inc.match[1]))
|
const incPath = absPath(docURI, inc.match[1])
|
||||||
|
const data = readFileSync(incPath)
|
||||||
|
lines[inc.lineNum] = `#line 0 "${incPath}"`
|
||||||
|
lines.splice(inc.lineNum + 1, 0, `#line ${inc.lineNum} "${docURI}"`)
|
||||||
|
const dataLines = data.toString().split('\n')
|
||||||
|
lines.splice(inc.lineNum + 1, 0, ...dataLines)
|
||||||
|
//console.log(lines.join('\n'))
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
const root = document.uri.replace(/^file:\/\//, '').replace(path.basename(document.uri), '')
|
lint(docURI, lines.join('\n'), includes)
|
||||||
//lint(path.extname(document.uri.replace(/^file:\/\//, '')), lines.join('\n'), document.uri)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function lint(extension: string, text: string, uri: string) {
|
const formatURI = (uri: string) => uri.replace(/^file:\/\//, '')
|
||||||
const child = exec(`${conf.glslangPath} --stdin -S ${ext[extension]}`, (error, out) => {
|
|
||||||
const diagnostics: Diagnostic[] = []
|
|
||||||
const matches = filterMatches(out) as RegExpMatchArray[]
|
|
||||||
matches.forEach((match) => {
|
|
||||||
const [type, line, msg] = match.slice(1)
|
|
||||||
diagnostics.push({
|
|
||||||
severity: type === 'ERROR' ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning,
|
|
||||||
range: calcRange(parseInt(line) - 1, uri),
|
|
||||||
message: replaceWord(msg),
|
|
||||||
source: 'mc-glsl'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
connection.sendDiagnostics({uri, diagnostics})
|
|
||||||
})
|
|
||||||
child.stdin.write(text)
|
|
||||||
child.stdin.end()
|
|
||||||
}
|
|
||||||
|
|
||||||
function calcRange(lineNum: number, uri: string): Range {
|
const getIncludes = (lines: string[]) => lines
|
||||||
const line = documents.get(uri).getText().split('\n')[lineNum - 1]
|
|
||||||
return Range.create(lineNum - 1, line.length - line.leftTrim().length, lineNum - 1, prepareLine(line).length + 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareLine(line: string): string {
|
|
||||||
return line.slice(0, line.indexOf('//')).rightTrim()
|
|
||||||
}
|
|
||||||
|
|
||||||
function getIncludes(lines: string[]): {lineNum: number, match: RegExpMatchArray}[] {
|
|
||||||
return lines
|
|
||||||
.map((line, i) => ({num: i, line}))
|
.map((line, i) => ({num: i, line}))
|
||||||
.filter((obj) => reInclude.test(obj.line))
|
.filter((obj) => reInclude.test(obj.line))
|
||||||
.map((obj) => ({lineNum: obj.num, match: obj.line.match(reInclude)}))
|
.map((obj) => ({lineNum: obj.num, match: obj.line.match(reInclude)}))
|
||||||
}
|
|
||||||
|
|
||||||
function absPath(currFile: string, includeFile: string): string {
|
function absPath(currFile: string, includeFile: string): string {
|
||||||
currFile = currFile.replace(/^file:\/\//, '')
|
|
||||||
if (!currFile.startsWith(conf.shaderpacksPath)) {
|
if (!currFile.startsWith(conf.shaderpacksPath)) {
|
||||||
connection.window.showErrorMessage(`Shaderpacks path may not be correct. Current file is in ${currFile} but the path is set to ${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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeFile.charAt(0) === '/') {
|
if (includeFile.charAt(0) === '/') {
|
||||||
console.log('no')
|
|
||||||
const shaderPath = currFile.replace(conf.shaderpacksPath, '').split('/').slice(0, 3).join('/')
|
const shaderPath = currFile.replace(conf.shaderpacksPath, '').split('/').slice(0, 3).join('/')
|
||||||
return path.join(conf.shaderpacksPath, shaderPath, includeFile)
|
return path.join(conf.shaderpacksPath, shaderPath, includeFile)
|
||||||
} else {
|
} else {
|
||||||
console.log('hi')
|
const shaderPath = path.dirname(currFile)
|
||||||
return path.join(currFile, includeFile)
|
return path.join(shaderPath, includeFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function lint(uri: string, text: string, includes: {lineNum: number, match: RegExpMatchArray}[]) {
|
||||||
|
const child = exec(`${conf.glslangPath} --stdin -S ${ext[path.extname(uri)]}`, (error, out) => {
|
||||||
|
const diagnostics: {[uri: string]: Diagnostic[]} = {}
|
||||||
|
diagnostics[uri] = []
|
||||||
|
includes.forEach(obj => {
|
||||||
|
diagnostics[absPath(uri, obj.match[1])] = []
|
||||||
|
})
|
||||||
|
const matches = filterMatches(out) as RegExpMatchArray[]
|
||||||
|
matches.forEach((match) => {
|
||||||
|
const [type, file, line, msg] = match.slice(1)
|
||||||
|
const diag = {
|
||||||
|
severity: type === 'ERROR' ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning,
|
||||||
|
range: calcRange(parseInt(line) - 1, uri),
|
||||||
|
message: replaceWord(msg),
|
||||||
|
source: 'mc-glsl'
|
||||||
|
}
|
||||||
|
diagnostics[file].push(diag)
|
||||||
|
})
|
||||||
|
console.log(JSON.stringify(daigsArray(diagnostics), null, 2))
|
||||||
|
daigsArray(diagnostics).forEach((d) => {
|
||||||
|
console.log(d.uri, d.diag.length)
|
||||||
|
connection.sendDiagnostics({uri: 'file://' + d.uri, diagnostics: d.diag})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
child.stdin.write(text)
|
||||||
|
child.stdin.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
const daigsArray = (diags: {[uri: string]: Diagnostic[]}) => Object.keys(diags).map(uri => ({uri, diag: diags[uri]}))
|
||||||
|
|
||||||
|
const filterMatches = (output: string) => output
|
||||||
|
.split('\n')
|
||||||
|
.filter(s => s.length > 1 && !filters.some(reg => reg.test(s)))
|
||||||
|
.map(s => s.match(reDiag))
|
||||||
|
.filter(match => match && match.length === 5)
|
||||||
|
|
||||||
|
const replaceWord = (msg: string) => {
|
||||||
|
for (const token of Object.keys(tokens)) {
|
||||||
|
if (msg.includes(token)) {
|
||||||
|
msg = msg.replace(token, tokens[token])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return msg
|
||||||
|
}
|
||||||
|
|
||||||
|
function calcRange(lineNum: number, uri: string): Range {
|
||||||
|
//TODO lineNum needs to be subtracted based off includes
|
||||||
|
const lines = documents.get('file://' + uri).getText().split('\n')
|
||||||
|
const line = lines[lineNum]
|
||||||
|
const startOfLine = line.length - line.leftTrim().length
|
||||||
|
const endOfLine = line.slice(0, line.indexOf('//')).rightTrim().length + 1
|
||||||
|
return Range.create(lineNum, startOfLine, lineNum, endOfLine)
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
import * as vsclang from 'vscode-languageserver'
|
import * as vsclang from 'vscode-languageserver'
|
||||||
|
import { TextDocumentChangeEvent } from 'vscode-languageserver-protocol';
|
||||||
import { Config } from './config'
|
import { Config } from './config'
|
||||||
import { completions } from './completionProvider';
|
import { completions } from './completionProvider';
|
||||||
import { preprocess } from './linter';
|
import { preprocess } from './linter';
|
||||||
|
@ -27,16 +28,20 @@ connection.onExit(() => {
|
||||||
})
|
})
|
||||||
|
|
||||||
documents.onDidOpen((event) => {
|
documents.onDidOpen((event) => {
|
||||||
preprocess(event.document, true, [event.document.uri.replace(/^file:\/\//, '')])
|
//onEvent(event)
|
||||||
})
|
})
|
||||||
|
|
||||||
documents.onDidSave((event) => {
|
documents.onDidSave((event) => {
|
||||||
preprocess(event.document, true, [event.document.uri.replace(/^file:\/\//, '')])
|
onEvent(event)
|
||||||
})
|
})
|
||||||
|
|
||||||
/* documents.onDidChangeContent((change) => {
|
documents.onDidChangeContent((event) => {
|
||||||
preprocess(change.document);
|
//onEvent(event)
|
||||||
});*/
|
})
|
||||||
|
|
||||||
|
function onEvent(event: TextDocumentChangeEvent) {
|
||||||
|
preprocess(event.document, true, [event.document.uri.replace(/^file:\/\//, '')])
|
||||||
|
}
|
||||||
|
|
||||||
connection.onDidChangeConfiguration((change) => {
|
connection.onDidChangeConfiguration((change) => {
|
||||||
const temp = change.settings.mcglsl as Config
|
const temp = change.settings.mcglsl as Config
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"array-type": false,
|
"array-type": false,
|
||||||
"interface-name": false,
|
"interface-name": false,
|
||||||
"indent": [true, "spaces", 2],
|
"indent": [true, "spaces", 2],
|
||||||
|
"triple-equals": false,
|
||||||
"arrow-parens": false,
|
"arrow-parens": false,
|
||||||
"max-classes-per-file": false,
|
"max-classes-per-file": false,
|
||||||
"no-console": false,
|
"no-console": false,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue