mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-07-23 03:05:44 +00:00
Moving from maps of maps to a more sophisticated graph class for includes
This commit is contained in:
parent
18c0e2ef5c
commit
c95367739f
3 changed files with 49 additions and 31 deletions
|
@ -23,4 +23,9 @@ export class Graph {
|
||||||
}
|
}
|
||||||
this.nodes.set(parent, par)
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -2,7 +2,7 @@ import { Diagnostic, DiagnosticSeverity, Range } from 'vscode-languageserver'
|
||||||
import { connection, documents } from './server'
|
import { connection, documents } from './server'
|
||||||
import { execSync } from 'child_process'
|
import { execSync } from 'child_process'
|
||||||
import * as path from 'path'
|
import * as path from 'path'
|
||||||
import { readFileSync, existsSync } from 'fs'
|
import { readFileSync, existsSync, statSync, Stats } from 'fs'
|
||||||
import { conf } from './config'
|
import { conf } from './config'
|
||||||
import { postError, formatURI, getDocumentContents } from './utils'
|
import { postError, formatURI, getDocumentContents } from './utils'
|
||||||
import { platform } from 'os'
|
import { platform } from 'os'
|
||||||
|
@ -11,7 +11,7 @@ import { Comment } from './comment'
|
||||||
|
|
||||||
const reDiag = /^(ERROR|WARNING): ([^?<>*|"]+?):(\d+): (?:'.*?' : )?(.+)\r?/
|
const reDiag = /^(ERROR|WARNING): ([^?<>*|"]+?):(\d+): (?:'.*?' : )?(.+)\r?/
|
||||||
const reVersion = /#version [\d]{3}/
|
const reVersion = /#version [\d]{3}/
|
||||||
const reInclude = /^(?:\s)*?(?:#include) "((?:\/?[^?<>:*|"]+?)+?\.(?:[a-zA-Z]+?))"\r?/
|
const reInclude = /^(?:\s)*?(?:#include) "(.+)"\r?/
|
||||||
const reIncludeExt = /#extension GL_GOOGLE_include_directive ?: ?require/
|
const reIncludeExt = /#extension GL_GOOGLE_include_directive ?: ?require/
|
||||||
const include = '#extension GL_GOOGLE_include_directive : require'
|
const include = '#extension GL_GOOGLE_include_directive : require'
|
||||||
const win = platform() === 'win32'
|
const win = platform() === 'win32'
|
||||||
|
@ -25,7 +25,6 @@ const filters = [
|
||||||
|
|
||||||
export const includeGraph = new Graph()
|
export const includeGraph = new Graph()
|
||||||
|
|
||||||
export const includeToParent = new Map<string, Set<string>>()
|
|
||||||
export const allFiles = new Set<string>()
|
export const allFiles = new Set<string>()
|
||||||
|
|
||||||
type IncludeObj = {
|
type IncludeObj = {
|
||||||
|
@ -99,17 +98,14 @@ export function preprocess(lines: string[], docURI: string) {
|
||||||
lint(docURI, lines, includeMap, diagnostics)
|
lint(docURI, lines, includeMap, diagnostics)
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildIncludeTree(inc: IncludeObj) {
|
const buildIncludeGraph = (inc: IncludeObj) => includeGraph.setParent(inc.path, inc.parent)
|
||||||
if (!includeToParent.has(inc.path)) includeToParent.set(inc.path, new Set([inc.parent]))
|
|
||||||
else includeToParent.get(inc.path).add(inc.parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
function processIncludes(lines: string[], incStack: string[], allIncludes: IncludeObj[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
|
function processIncludes(lines: string[], incStack: string[], allIncludes: IncludeObj[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
|
||||||
const includes = getIncludes(incStack[0], lines)
|
const includes = getIncludes(incStack[0], lines)
|
||||||
allIncludes.push(...includes)
|
allIncludes.push(...includes)
|
||||||
if (includes.length > 0) {
|
if (includes.length > 0) {
|
||||||
includes.reverse().forEach(inc => {
|
includes.reverse().forEach(inc => {
|
||||||
buildIncludeTree(inc)
|
buildIncludeGraph(inc)
|
||||||
mergeInclude(inc, lines, incStack, diagnostics, hasDirective)
|
mergeInclude(inc, lines, incStack, diagnostics, hasDirective)
|
||||||
})
|
})
|
||||||
// recursively check for more includes to be merged
|
// recursively check for more includes to be merged
|
||||||
|
@ -162,24 +158,40 @@ export function getIncludes(uri: string, lines: string[]) {
|
||||||
}, [])
|
}, [])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function ifInvalidFile(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>) {
|
||||||
|
const range = calcRange(inc.lineNumTopLevel - (win ? 1 : 0), incStack[0])
|
||||||
|
diagnostics.set(
|
||||||
|
inc.parent,
|
||||||
|
[
|
||||||
|
...(diagnostics.get(inc.parent) || []),
|
||||||
|
{
|
||||||
|
severity: DiagnosticSeverity.Error,
|
||||||
|
range,
|
||||||
|
message: `${inc.path.replace(conf.shaderpacksPath, '')} is missing or an invalid file.`,
|
||||||
|
source: 'mc-glsl'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
)
|
||||||
|
lines[inc.lineNumTopLevel] = ''
|
||||||
|
}
|
||||||
|
|
||||||
function mergeInclude(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
|
function mergeInclude(inc: IncludeObj, lines: string[], incStack: string[], diagnostics: Map<string, Diagnostic[]>, hasDirective: boolean) {
|
||||||
if (!existsSync(inc.path)) {
|
let stats: Stats
|
||||||
const range = calcRange(inc.lineNumTopLevel - (win ? 1 : 0), incStack[0])
|
try {
|
||||||
diagnostics.set(
|
stats = statSync(inc.path)
|
||||||
inc.parent,
|
} catch (e) {
|
||||||
[
|
if (e.code === 'ENOENT') {
|
||||||
...(diagnostics.get(inc.parent) || []),
|
ifInvalidFile(inc, lines, incStack, diagnostics)
|
||||||
{
|
return
|
||||||
severity: DiagnosticSeverity.Error,
|
}
|
||||||
range,
|
throw e
|
||||||
message: `${inc.path.replace(conf.shaderpacksPath, '')} is missing.`,
|
}
|
||||||
source: 'mc-glsl'
|
|
||||||
}
|
if (!stats.isFile()) {
|
||||||
]
|
ifInvalidFile(inc, lines, incStack, diagnostics)
|
||||||
)
|
|
||||||
lines[inc.lineNumTopLevel] = ''
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const dataLines = readFileSync(inc.path).toString().split('\n')
|
const dataLines = readFileSync(inc.path).toString().split('\n')
|
||||||
|
|
||||||
// if the includes parent is the top level (aka where the include directive is placed)
|
// if the includes parent is the top level (aka where the include directive is placed)
|
||||||
|
@ -230,7 +242,6 @@ function lint(uri: string, lines: string[], includes: Map<string, IncludeObj>, d
|
||||||
// TODO what if we dont know the top level parent? Feel like thats a non-issue given that we have uri
|
// TODO what if we dont know the top level parent? Feel like thats a non-issue given that we have uri
|
||||||
diag = {
|
diag = {
|
||||||
severity: errorType(type),
|
severity: errorType(type),
|
||||||
// TODO put -1 back when #11 is sorted
|
|
||||||
range: calcRange(includes.get(nextFile).lineNum, includes.get(nextFile).parent),
|
range: calcRange(includes.get(nextFile).lineNum, includes.get(nextFile).parent),
|
||||||
message: `Line ${line} ${includes.get(file).path.replace(conf.shaderpacksPath, '')} ${replaceWords(msg)}`,
|
message: `Line ${line} ${includes.get(file).path.replace(conf.shaderpacksPath, '')} ${replaceWords(msg)}`,
|
||||||
source: 'mc-glsl'
|
source: 'mc-glsl'
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import * as vsclang from 'vscode-languageserver'
|
import * as vsclang from 'vscode-languageserver'
|
||||||
import * as vsclangproto from 'vscode-languageserver-protocol'
|
import * as vsclangproto from 'vscode-languageserver-protocol'
|
||||||
import { completions } from './completionProvider'
|
import { completions } from './completionProvider'
|
||||||
import { preprocess, ext, includeToParent } from './linter'
|
import { preprocess, ext, includeToParent, includeGraph } from './linter'
|
||||||
import { extname } from 'path'
|
import { extname } from 'path'
|
||||||
|
|
||||||
const reVersion = /#version [\d]{3}/
|
const reVersion = /#version [\d]{3}/
|
||||||
|
@ -39,7 +39,7 @@ documents.onDidClose((event) => connection.sendDiagnostics({uri: event.document.
|
||||||
|
|
||||||
export function onEvent(document: vsclangproto.TextDocument) {
|
export function onEvent(document: vsclangproto.TextDocument) {
|
||||||
const uri = formatURI(document.uri)
|
const uri = formatURI(document.uri)
|
||||||
if (includeToParent.has(uri)) {
|
if (includeGraph.get(uri).parents.size > 0) {
|
||||||
lintBubbleDown(uri, document)
|
lintBubbleDown(uri, document)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -54,13 +54,15 @@ export function onEvent(document: vsclangproto.TextDocument) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function lintBubbleDown(uri: string, document: vsclangproto.TextDocument) {
|
function lintBubbleDown(uri: string, document: vsclangproto.TextDocument) {
|
||||||
includeToParent.get(uri).forEach(parent => {
|
includeGraph.get(uri).parents.forEach((parent, parentURI) => {
|
||||||
if (includeToParent.has(parent)) {
|
console.log(parentURI)
|
||||||
lintBubbleDown(parent, document)
|
console.log(parent.parents)
|
||||||
|
if (parent.parents.size > 0) {
|
||||||
|
lintBubbleDown(parentURI, document)
|
||||||
} else {
|
} else {
|
||||||
const lines = getDocumentContents(parent).split('\n')
|
const lines = getDocumentContents(parentURI).split('\n')
|
||||||
if (lines.filter(l => reVersion.test(l)).length > 0) {
|
if (lines.filter(l => reVersion.test(l)).length > 0) {
|
||||||
preprocess(lines, parent)
|
preprocess(lines, parentURI)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue