mirror of
https://github.com/Strum355/mcshader-lsp.git
synced 2025-08-31 05:47:22 +00:00
v0.9.7: the real 0.9.6
This commit is contained in:
parent
d43bfec582
commit
f45e1a4b87
15 changed files with 84 additions and 68 deletions
|
@ -56,7 +56,7 @@ export function virtualMergedDocument(e: Extension): Command {
|
|||
+ vscode.window.activeTextEditor.document.uri.path
|
||||
.slice(vscode.window.activeTextEditor.document.uri.path.lastIndexOf('.') + 1)
|
||||
const path = vscode.Uri.parse(`mcglsl:${uri}`)
|
||||
|
||||
|
||||
const doc = await vscode.workspace.openTextDocument(path)
|
||||
docProvider.onDidChangeEmitter.fire(path)
|
||||
await vscode.window.showTextDocument(doc, {
|
||||
|
@ -83,7 +83,7 @@ export function parseTree(e: Extension): Command {
|
|||
onDidChangeEmitter = new vscode.EventEmitter<vscode.Uri>()
|
||||
onDidChange = this.onDidChangeEmitter.event
|
||||
|
||||
provideTextDocumentContent(uri: vscode.Uri, __: vscode.CancellationToken): vscode.ProviderResult<string> {
|
||||
provideTextDocumentContent(uri: vscode.Uri, _: vscode.CancellationToken): vscode.ProviderResult<string> {
|
||||
if (uri.path.includes('.flattened.')) return ''
|
||||
return getVirtualDocument(uri.path.substring(0, uri.path.lastIndexOf('.')))
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ export function parseTree(e: Extension): Command {
|
|||
|
||||
const uri = vscode.window.activeTextEditor.document.uri
|
||||
const path = vscode.Uri.parse(`mcglsl:${uri.path}.ast`)
|
||||
|
||||
|
||||
const doc = await vscode.workspace.openTextDocument(path)
|
||||
docProvider.onDidChangeEmitter.fire(path)
|
||||
await vscode.window.showTextDocument(doc, {
|
||||
|
|
|
@ -6,7 +6,7 @@ import { log } from './log'
|
|||
import { LanguageClient } from './lspClient'
|
||||
import { download, getReleaseInfo } from './net'
|
||||
import { PersistentState } from './persistent_state'
|
||||
import * as path from 'path'
|
||||
import * as path from 'path'
|
||||
|
||||
const platforms: { [key: string]: string } = {
|
||||
'x64 win32': 'x86_64-windows-msvc',
|
||||
|
@ -26,7 +26,7 @@ export class Extension {
|
|||
readonly package: {
|
||||
version: string
|
||||
} = vscode.extensions.getExtension(this.extensionID)!.packageJSON;
|
||||
|
||||
|
||||
public get context(): vscode.ExtensionContext {
|
||||
return this.extensionContext
|
||||
}
|
||||
|
@ -34,13 +34,13 @@ export class Extension {
|
|||
public get lspClient(): lsp.LanguageClient {
|
||||
return this.client
|
||||
}
|
||||
|
||||
|
||||
public activate = async (context: vscode.ExtensionContext) => {
|
||||
this.extensionContext = context
|
||||
this.state = new PersistentState(context.globalState)
|
||||
|
||||
if(!process.env['MCSHADER_DEBUG'] && !(vscode.workspace.getConfiguration('mcglsl').get('skipBootstrap') as boolean)) {
|
||||
await this.bootstrap()
|
||||
if (!process.env['MCSHADER_DEBUG'] && !(vscode.workspace.getConfiguration('mcglsl').get('skipBootstrap') as boolean)) {
|
||||
await this.bootstrap()
|
||||
} else {
|
||||
log.info('skipping language server bootstrap')
|
||||
}
|
||||
|
@ -52,31 +52,31 @@ export class Extension {
|
|||
|
||||
log.info('starting language server...')
|
||||
|
||||
const lspBinary = process.env['MCSHADER_DEBUG'] ?
|
||||
this.context.asAbsolutePath(path.join('server', 'target', 'debug', 'mcshader-lsp')) +
|
||||
(process.platform === 'win32' ? '.exe' : '') :
|
||||
path.join(this.context.globalStorageUri.fsPath, 'mcshader-lsp')
|
||||
const lspBinary = process.env['MCSHADER_DEBUG'] ?
|
||||
this.context.asAbsolutePath(path.join('server', 'target', 'debug', 'mcshader-lsp')) +
|
||||
(process.platform === 'win32' ? '.exe' : '') :
|
||||
path.join(this.context.globalStorageUri.fsPath, 'mcshader-lsp')
|
||||
|
||||
const filewatcherGlob = this.fileAssociationsToGlob(this.getGLSLFileAssociations())
|
||||
|
||||
|
||||
this.client = await new LanguageClient(this, lspBinary, filewatcherGlob).startServer()
|
||||
|
||||
|
||||
log.info('language server started!')
|
||||
}
|
||||
|
||||
fileAssociationsToGlob = (associations: string[]): string => {
|
||||
return '**/*.{'.concat(
|
||||
associations.map(s => s.substring(s.indexOf('.'))).join(',')
|
||||
) + '}'
|
||||
) + '}'
|
||||
}
|
||||
|
||||
getGLSLFileAssociations = (): string[] => {
|
||||
const exts = ['.fsh', '.vsh', '.gsh', '.glsl']
|
||||
const associations = vscode.workspace.getConfiguration('files').get('associations') as {[key: string]: string}
|
||||
|
||||
const associations = vscode.workspace.getConfiguration('files').get('associations') as { [key: string]: string }
|
||||
|
||||
Object.keys(associations).forEach((key) => {
|
||||
if(associations[key] === 'glsl') {
|
||||
exts.push(key.substring(key.indexOf('*')+1))
|
||||
if (associations[key] === 'glsl') {
|
||||
exts.push(key.substring(key.indexOf('*') + 1))
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -85,16 +85,16 @@ export class Extension {
|
|||
|
||||
registerCommand = (name: string, f: (e: Extension) => commands.Command) => {
|
||||
const cmd = f(this)
|
||||
this.context.subscriptions.push(vscode.commands.registerCommand('mcglsl.'+name, cmd))
|
||||
this.context.subscriptions.push(vscode.commands.registerCommand('mcglsl.' + name, cmd))
|
||||
}
|
||||
|
||||
deactivate = async () => {
|
||||
deactivate = async () => {
|
||||
await this.lspClient.stop()
|
||||
while(this.context.subscriptions.length > 0) {
|
||||
while (this.context.subscriptions.length > 0) {
|
||||
this.context.subscriptions.pop()?.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public updateStatus = (icon: string, text: string) => {
|
||||
this.statusBarItem?.dispose()
|
||||
this.statusBarItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left)
|
||||
|
@ -102,14 +102,14 @@ export class Extension {
|
|||
this.statusBarItem.show()
|
||||
this.context.subscriptions.push(this.statusBarItem)
|
||||
}
|
||||
|
||||
|
||||
public clearStatus = () => {
|
||||
this.statusBarItem?.dispose()
|
||||
}
|
||||
|
||||
private bootstrap = async () => {
|
||||
mkdirSync(this.extensionContext.globalStoragePath, { recursive: true })
|
||||
|
||||
|
||||
const dest = path.join(this.extensionContext.globalStoragePath, 'mcshader-lsp' + (process.platform === 'win32' ? '.exe' : ''))
|
||||
const exists = await fs.stat(dest).then(() => true, () => false)
|
||||
if (!exists) await this.state.updateServerVersion(undefined)
|
||||
|
@ -123,7 +123,7 @@ export class Extension {
|
|||
log.warn(`incompatible architecture/platform:\n\t${process.arch} ${process.platform}`)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
if (release.tag_name === this.state.serverVersion) {
|
||||
log.info('server version is same as extension:\n\t', this.state.serverVersion)
|
||||
return
|
||||
|
@ -135,8 +135,8 @@ export class Extension {
|
|||
|
||||
const userResponse = await vscode.window.showInformationMessage(
|
||||
this.state.serverVersion == undefined ?
|
||||
`Language server version ${this.package.version} is not installed.` :
|
||||
`An update is available. Upgrade from ${this.state.serverVersion} to ${release.tag_name}?`,
|
||||
`Language server version ${this.package.version} is not installed.` :
|
||||
`An update is available. Upgrade from ${this.state.serverVersion} to ${release.tag_name}?`,
|
||||
'Download now'
|
||||
)
|
||||
if (userResponse !== 'Download now') {
|
||||
|
@ -145,9 +145,16 @@ export class Extension {
|
|||
}
|
||||
|
||||
await download(artifact.browser_download_url, dest)
|
||||
|
||||
|
||||
this.state.updateServerVersion(release.tag_name)
|
||||
}
|
||||
}
|
||||
|
||||
export const activate = new Extension().activate
|
||||
export const activate = async (context: vscode.ExtensionContext) => {
|
||||
try {
|
||||
new Extension().activate(context)
|
||||
} catch (e) {
|
||||
log.error(`failed to activate extension: ${e}`)
|
||||
throw(e)
|
||||
}
|
||||
}
|
|
@ -9,33 +9,33 @@ export const log = new class {
|
|||
|
||||
// Hint: the type [T, ...T[]] means a non-empty array
|
||||
debug(...msg: [unknown, ...unknown[]]): void {
|
||||
log.write('DEBUG', ...msg)
|
||||
log.write('DEBUG', ...msg)
|
||||
}
|
||||
|
||||
info(...msg: [unknown, ...unknown[]]): void {
|
||||
log.write('INFO ', ...msg)
|
||||
log.write('INFO ', ...msg)
|
||||
}
|
||||
|
||||
warn(...msg: [unknown, ...unknown[]]): void {
|
||||
log.write('WARN ', ...msg)
|
||||
log.write('WARN ', ...msg)
|
||||
}
|
||||
|
||||
error(...msg: [unknown, ...unknown[]]): void {
|
||||
log.write('ERROR', ...msg)
|
||||
log.write('ERROR', ...msg)
|
||||
}
|
||||
|
||||
write(label: string, ...messageParts: unknown[]): void {
|
||||
const message = messageParts.map(log.stringify).join(' ')
|
||||
const dateTime = new Date().toLocaleString()
|
||||
log.output.appendLine(`${label} [${dateTime}]: ${message}`)
|
||||
const message = messageParts.map(log.stringify).join(' ')
|
||||
const dateTime = new Date().toLocaleString()
|
||||
log.output.appendLine(`${label} [${dateTime}]: ${message}`)
|
||||
}
|
||||
|
||||
private stringify(val: unknown): string {
|
||||
if (typeof val === 'string') return val
|
||||
if (typeof val === 'string') return val
|
||||
return inspect(val, {
|
||||
colors: false,
|
||||
depth: 6, // heuristic
|
||||
})
|
||||
colors: false,
|
||||
depth: 6, // heuristic
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ export class LanguageClient extends lsp.LanguageClient {
|
|||
super('vscode-mc-shader', 'VSCode MC Shader', {
|
||||
command: lspBinary
|
||||
}, {
|
||||
documentSelector: [{scheme: 'file', language: 'glsl'}],
|
||||
documentSelector: [{ scheme: 'file', language: 'glsl' }],
|
||||
outputChannel: lspOutputChannel,
|
||||
synchronize: {
|
||||
configurationSection: 'mcglsl',
|
||||
|
@ -28,10 +28,10 @@ export class LanguageClient extends lsp.LanguageClient {
|
|||
this.extension.context.subscriptions.push(this.start())
|
||||
|
||||
await this.onReady()
|
||||
|
||||
|
||||
this.onNotification(updateConfigMethod, this.onUpdateConfig)
|
||||
this.onNotification(statusMethod, this.onStatusChange)
|
||||
|
||||
|
||||
return this
|
||||
}
|
||||
|
||||
|
|
|
@ -12,5 +12,5 @@ export const status = new lsp.NotificationType<StatusParams>(statusMethod)
|
|||
export const updateConfigMethod = 'mc-glsl/updateConfig'
|
||||
|
||||
export type ConfigUpdateParams = {
|
||||
kv: {key: string, value: string}[]
|
||||
kv: { key: string, value: string }[]
|
||||
}
|
|
@ -16,20 +16,21 @@ interface GithubRelease {
|
|||
}
|
||||
|
||||
export async function getReleaseInfo(releaseTag: string): Promise<GithubRelease> {
|
||||
log.info('fetching release info for tag', releaseTag)
|
||||
const response = await fetch(`https://api.github.com/repos/strum355/mcshader-lsp/releases/tags/${releaseTag}`, {
|
||||
headers: {Accept: 'application/vnd.github.v3+json'}
|
||||
headers: { Accept: 'application/vnd.github.v3+json' }
|
||||
})
|
||||
|
||||
const isRelease = (obj: unknown): obj is GithubRelease => {
|
||||
return obj != null && typeof obj === 'object'
|
||||
return obj != null && typeof obj === 'object'
|
||||
&& typeof (obj as GithubRelease).tag_name === 'string'
|
||||
&& Array.isArray((obj as GithubRelease).assets)
|
||||
&& (obj as GithubRelease).assets.every((a) => typeof a.name === 'string' && typeof a.browser_download_url === 'string')
|
||||
}
|
||||
|
||||
const json = await response.json()
|
||||
if(!isRelease(json)) {
|
||||
throw new TypeError('Received malformed request from Github Release API ' + JSON.stringify(json))
|
||||
if (!isRelease(json)) {
|
||||
throw new TypeError(`Received malformed request from Github Release API ${JSON.stringify(json)}`)
|
||||
}
|
||||
return json
|
||||
}
|
||||
|
@ -50,14 +51,14 @@ export async function download(url: string, downloadDest: string) {
|
|||
message: `${newPercentage.toFixed(0)}%`,
|
||||
increment: newPercentage - lastPercentage
|
||||
})
|
||||
|
||||
|
||||
lastPercentage = newPercentage
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
async function downloadFile(
|
||||
url: string,
|
||||
destFilePath: fs.PathLike,
|
||||
|
@ -69,21 +70,21 @@ async function downloadFile(
|
|||
log.error({ body: await res.text(), headers: res.headers })
|
||||
throw new Error(`Got response ${res.status} when trying to download ${url}.`)
|
||||
}
|
||||
|
||||
|
||||
const totalBytes = Number(res.headers.get('content-length'))
|
||||
|
||||
|
||||
log.debug('downloading file with', totalBytes, 'bytes size from', url, 'to', destFilePath)
|
||||
|
||||
|
||||
let readBytes = 0
|
||||
res.body.on('data', (chunk: Buffer) => {
|
||||
readBytes += chunk.length
|
||||
onProgress(readBytes, totalBytes)
|
||||
})
|
||||
|
||||
|
||||
const destFileStream = fs.createWriteStream(destFilePath, { mode: 0o755 })
|
||||
|
||||
|
||||
await pipeline(res.body, destFileStream)
|
||||
|
||||
|
||||
// Don't apply the workaround in fixed versions of nodejs, since the process
|
||||
// freezes on them, the process waits for no-longer emitted `close` event.
|
||||
// The fix was applied in commit 7eed9d6bcc in v13.11.0
|
||||
|
@ -91,7 +92,7 @@ async function downloadFile(
|
|||
// https://github.com/nodejs/node/blob/master/doc/changelogs/CHANGELOG_V13.md
|
||||
const [, major, minor] = /v(\d+)\.(\d+)\.(\d+)/.exec(process.version)!
|
||||
if (+major > 13 || (+major === 13 && +minor >= 11)) return
|
||||
|
||||
|
||||
await new Promise<void>(resolve => {
|
||||
destFileStream.on('close', resolve)
|
||||
destFileStream.destroy()
|
||||
|
|
|
@ -12,6 +12,6 @@ export class PersistentState {
|
|||
}
|
||||
|
||||
async updateServerVersion(value: string | undefined) {
|
||||
await this.state.update('serverVersion', value)
|
||||
await this.state.update('serverVersion', value)
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue