Linting of all currently discovered files that contain the edited include at some depth is pretty much working! Issue #11 highlights the blocking bug

This commit is contained in:
Noah Santschi-Cooney 2018-07-25 00:43:07 +01:00
parent 5e6a12c88b
commit 5a06d8ff1b
No known key found for this signature in database
GPG key ID: 3B22282472C8AE48
3 changed files with 58 additions and 30 deletions

View file

@ -4,7 +4,7 @@ import { execSync } from 'child_process'
import * as path from 'path' import * as path from 'path'
import { readFileSync, existsSync } from 'fs' import { readFileSync, existsSync } from 'fs'
import { conf } from './config' import { conf } from './config'
import { postError, formatURI } from './utils' import { postError, formatURI, getDocumentContents } from './utils'
import { platform } from 'os' import { platform } from 'os'
const reDiag = /^(ERROR|WARNING): ([^?<>*|"]+?):(\d+): (?:'.*?' : )?(.+)\r?/ const reDiag = /^(ERROR|WARNING): ([^?<>*|"]+?):(\d+): (?:'.*?' : )?(.+)\r?/
@ -21,7 +21,7 @@ const filters = [
/Could not process include directive for header name:/ /Could not process include directive for header name:/
] ]
const includeToParent = new Map<string, string[]>() export const includeToParent = new Map<string, Set<string>>()
type IncludeObj = { type IncludeObj = {
lineNum: number, lineNum: number,
@ -79,7 +79,8 @@ export function isInComment(line: string, state: Comment): Comment {
} }
export function preprocess(lines: string[], docURI: string) { export function preprocess(lines: string[], docURI: string) {
if (lines.find((value: string, i: number, obj: string[]): boolean => reIncludeExt.test(value)) == undefined) { // wish there was an ignore keyword like Go
if (lines.find((value: string, _, __): boolean => reIncludeExt.test(value)) == undefined) {
for (let i = 0; i < lines.length; i++) { for (let i = 0; i < lines.length; i++) {
const line = lines[i] const line = lines[i]
if (reVersion.test(line)) { if (reVersion.test(line)) {
@ -93,17 +94,19 @@ export function preprocess(lines: string[], docURI: string) {
} }
} }
const incStack = [docURI]
const allIncludes: IncludeObj[] = [] const allIncludes: IncludeObj[] = []
const diagnostics = new Map<string, Diagnostic[]>() const diagnostics = new Map<string, Diagnostic[]>()
processIncludes(lines, incStack, allIncludes, diagnostics)
processIncludes(lines, [docURI], allIncludes, diagnostics)
const includeMap = new Map<string, IncludeObj>(allIncludes.map(obj => [obj.path, obj]) as [string, IncludeObj][]) const includeMap = new Map<string, IncludeObj>(allIncludes.map(obj => [obj.path, obj]) as [string, IncludeObj][])
try {
lint(docURI, lines, includeMap, diagnostics) lint(docURI, lines, includeMap, diagnostics)
} catch (e) { }
postError(e)
} function buildIncludeTree(inc: IncludeObj) {
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[]>) { function processIncludes(lines: string[], incStack: string[], allIncludes: IncludeObj[], diagnostics: Map<string, Diagnostic[]>) {
@ -111,6 +114,7 @@ function processIncludes(lines: string[], incStack: string[], allIncludes: Inclu
allIncludes.push(...includes) allIncludes.push(...includes)
if (includes.length > 0) { if (includes.length > 0) {
includes.reverse().forEach(inc => { includes.reverse().forEach(inc => {
buildIncludeTree(inc)
mergeInclude(inc, lines, incStack, diagnostics) mergeInclude(inc, lines, incStack, diagnostics)
}) })
// recursively check for more includes to be merged // recursively check for more includes to be merged
@ -223,7 +227,8 @@ 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),
range: calcRange(includes.get(nextFile).lineNum - 1, includes.get(nextFile).parent), // TODO put -1 back when #11 is sorted
range: calcRange(includes.get(nextFile).lineNum, includes.get(nextFile).parent),
message: includes.get(file).path.replace(conf.shaderpacksPath, '') + replaceWords(msg), message: includes.get(file).path.replace(conf.shaderpacksPath, '') + replaceWords(msg),
source: 'mc-glsl' source: 'mc-glsl'
} }
@ -253,14 +258,10 @@ const filterMatches = (output: string) => output
.filter(match => match && match.length === 5) .filter(match => match && match.length === 5)
function calcRange(lineNum: number, uri: string): Range { function calcRange(lineNum: number, uri: string): Range {
let lines = []
// TODO better error handling maybe? // TODO better error handling maybe?
if (documents.keys().includes('file://' + uri)) { const lines = getDocumentContents(uri).split('\n')
lines = documents.get('file://' + uri).getText().split('\n') console.log(uri, lineNum, lines.length)
} else { console.log(lines.slice(Math.max(lineNum - 3, 0), lineNum + 3).join('\n'))
lines = readFileSync(uri).toString().split('\n')
}
const line = lines[lineNum] const line = lines[lineNum]
const startOfLine = line.length - line.trimLeft().length const startOfLine = line.length - line.trimLeft().length

View file

@ -1,14 +1,16 @@
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 } from './linter' import { preprocess, ext, includeToParent } from './linter'
import { extname } from 'path' import { extname } from 'path'
const reVersion = /#version [\d]{3}/
export let connection: vsclang.IConnection export let connection: vsclang.IConnection
connection = vsclang.createConnection(new vsclang.IPCMessageReader(process), new vsclang.IPCMessageWriter(process)) connection = vsclang.createConnection(new vsclang.IPCMessageReader(process), new vsclang.IPCMessageWriter(process))
import { onConfigChange } from './config' import { onConfigChange } from './config'
import { formatURI } from './utils' import { formatURI, postError, getDocumentContents } from './utils'
export const documents = new vsclang.TextDocuments() export const documents = new vsclang.TextDocuments()
documents.listen(connection) documents.listen(connection)
@ -36,15 +38,34 @@ documents.onDidClose((event) => connection.sendDiagnostics({uri: event.document.
//documents.onDidChangeContent(onEvent) //documents.onDidChangeContent(onEvent)
export function onEvent(document: vsclangproto.TextDocument) { export function onEvent(document: vsclangproto.TextDocument) {
if (!ext.has(extname(document.uri))) return const uri = formatURI(document.uri)
try { if (includeToParent.has(uri)) {
console.log(document.uri) lintBubbleDown(uri, document)
console.log(formatURI(document.uri)) return
preprocess(document.getText().split('\n'), formatURI(document.uri))
} catch (e) {
connection.window.showErrorMessage(`[mc-glsl] ${e.message}`)
throw(e)
} }
if (!ext.has(extname(document.uri))) return
try {
preprocess(document.getText().split('\n'), uri)
} catch (e) {
postError(e)
}
}
function lintBubbleDown(uri: string, document: vsclangproto.TextDocument) {
includeToParent.get(uri).forEach(parent => {
console.log(`${uri} has parent ${parent}`)
if (includeToParent.has(parent)) {
lintBubbleDown(parent, document)
} else {
const lines = getDocumentContents(parent).split('\n')
if (lines.filter(l => reVersion.test(l)).length > 0) {
console.log(`${parent} is at top, linting down`)
preprocess(lines, parent)
}
}
})
} }
connection.onDidChangeConfiguration(onConfigChange) connection.onDidChangeConfiguration(onConfigChange)

View file

@ -1,8 +1,14 @@
import { connection } from './server' import { connection, documents } from './server'
import { readFileSync } from 'fs'
export function postError(e: Error) { export function postError(e: Error) {
connection.window.showErrorMessage(e.message) connection.window.showErrorMessage(e.message)
console.log(e) console.log(e)
} }
export const formatURI = (uri: string) => uri.replace(/^file:\/\//, '').replace(/^(?:\/)c%3A/, 'C:').replace(/\\/g, '/') export const formatURI = (uri: string) => uri.replace(/^file:\/\//, '').replace(/^(?:\/)c%3A/, 'C:').replace(/\\/g, '/')
export function getDocumentContents(uri: string): string {
if (documents.keys().includes('file://' + uri)) return documents.get('file://' + uri).getText()
else return readFileSync(uri).toString()
}