2021-12-25 18:33:00 +08:00
|
|
|
import { commands, Disposable, disposeAll, StatusBarItem, TaskOptions, Uri, window, workspace } from 'coc.nvim'
|
2018-09-07 20:40:51 +08:00
|
|
|
import path from 'path'
|
2020-04-17 15:47:45 +08:00
|
|
|
import TypeScriptServiceClient from '../typescriptServiceClient'
|
2018-09-07 20:40:51 +08:00
|
|
|
|
2019-02-06 21:53:55 +08:00
|
|
|
const countRegex = /Found\s+(\d+)\s+error/
|
|
|
|
const errorRegex = /^(.+)\((\d+),(\d+)\):\s(\w+)\sTS(\d+):\s*(.+)$/
|
2018-09-07 20:40:51 +08:00
|
|
|
|
2019-04-12 16:33:19 +08:00
|
|
|
export default class WatchProject implements Disposable {
|
|
|
|
private disposables: Disposable[] = []
|
|
|
|
public static readonly id: string = 'tsserver.watchBuild'
|
|
|
|
public static readonly startTexts: string[] = ['Starting compilation in watch mode', 'Starting incremental compilation']
|
2019-02-06 21:53:55 +08:00
|
|
|
private statusItem: StatusBarItem
|
2020-12-08 18:50:01 +08:00
|
|
|
private task: any
|
2019-04-12 16:33:19 +08:00
|
|
|
private options: TaskOptions
|
2018-09-07 20:40:51 +08:00
|
|
|
|
2019-04-12 16:33:19 +08:00
|
|
|
public constructor(
|
2020-04-17 15:47:45 +08:00
|
|
|
private client: TypeScriptServiceClient
|
2019-04-12 16:33:19 +08:00
|
|
|
) {
|
2020-12-17 20:28:49 +08:00
|
|
|
this.statusItem = window.createStatusBarItem(1, { progress: true })
|
2019-04-12 16:33:19 +08:00
|
|
|
let task = this.task = workspace.createTask('TSC')
|
2021-06-06 22:29:30 -05:00
|
|
|
|
2020-12-08 18:50:01 +08:00
|
|
|
this.disposables.push(commands.registerCommand(WatchProject.id, async () => {
|
2019-06-13 22:52:57 +08:00
|
|
|
let opts = this.options = await this.getOptions()
|
2019-04-12 19:23:36 +08:00
|
|
|
await this.start(opts)
|
2019-04-12 16:33:19 +08:00
|
|
|
}))
|
|
|
|
task.onExit(code => {
|
|
|
|
if (code != 0) {
|
2020-12-17 20:28:49 +08:00
|
|
|
window.showMessage(`TSC exit with code ${code}`, 'warning')
|
2019-04-12 16:33:19 +08:00
|
|
|
}
|
|
|
|
this.onStop()
|
|
|
|
})
|
|
|
|
task.onStdout(lines => {
|
|
|
|
for (let line of lines) {
|
|
|
|
this.onLine(line)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
task.onStderr(lines => {
|
2020-12-17 20:28:49 +08:00
|
|
|
window.showMessage(`TSC error: ` + lines.join('\n'), 'error')
|
2019-04-12 16:33:19 +08:00
|
|
|
})
|
|
|
|
this.disposables.push(Disposable.create(() => {
|
|
|
|
task.dispose()
|
|
|
|
}))
|
|
|
|
this.check().catch(_e => {
|
|
|
|
// noop
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
private async check(): Promise<void> {
|
|
|
|
let running = await this.task.running
|
|
|
|
if (running) {
|
2019-06-13 22:52:57 +08:00
|
|
|
this.options = await this.getOptions()
|
2019-04-12 16:33:19 +08:00
|
|
|
this.statusItem.isProgress = false
|
|
|
|
this.statusItem.text = '?'
|
|
|
|
this.statusItem.show()
|
|
|
|
} else {
|
|
|
|
this.onStop()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private async start(options: TaskOptions): Promise<void> {
|
|
|
|
await this.task.start(options)
|
2019-02-06 21:53:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private onStop(): void {
|
|
|
|
this.statusItem.hide()
|
|
|
|
}
|
|
|
|
|
|
|
|
private onStart(): void {
|
|
|
|
this.statusItem.text = 'compiling'
|
|
|
|
this.statusItem.isProgress = true
|
|
|
|
this.statusItem.show()
|
2019-06-09 22:03:27 +08:00
|
|
|
workspace.nvim.call('setqflist', [[]], true)
|
2019-02-06 21:53:55 +08:00
|
|
|
}
|
|
|
|
|
2019-04-12 16:33:19 +08:00
|
|
|
private onLine(line: string): void {
|
|
|
|
if (countRegex.test(line)) {
|
|
|
|
let ms = line.match(countRegex)
|
|
|
|
this.statusItem.text = ms[1] == '0' ? '✓' : '✗'
|
|
|
|
this.statusItem.isProgress = false
|
|
|
|
} else if (WatchProject.startTexts.findIndex(s => line.indexOf(s) !== -1) != -1) {
|
|
|
|
this.onStart()
|
|
|
|
} else {
|
|
|
|
let ms = line.match(errorRegex)
|
|
|
|
if (!ms) return
|
|
|
|
let fullpath = path.join(this.options.cwd, ms[1])
|
|
|
|
let uri = Uri.file(fullpath).toString()
|
|
|
|
let doc = workspace.getDocument(uri)
|
|
|
|
let bufnr = doc ? doc.bufnr : null
|
|
|
|
let item = {
|
|
|
|
filename: fullpath,
|
|
|
|
lnum: Number(ms[2]),
|
|
|
|
col: Number(ms[3]),
|
|
|
|
text: `[tsc ${ms[5]}] ${ms[6]}`,
|
|
|
|
type: /error/i.test(ms[4]) ? 'E' : 'W'
|
|
|
|
} as any
|
|
|
|
if (bufnr) item.bufnr = bufnr
|
|
|
|
workspace.nvim.call('setqflist', [[item], 'a'])
|
2019-02-06 21:53:55 +08:00
|
|
|
}
|
2018-09-07 20:40:51 +08:00
|
|
|
}
|
|
|
|
|
2019-06-13 22:52:57 +08:00
|
|
|
public async getOptions(): Promise<TaskOptions> {
|
2020-04-17 15:47:45 +08:00
|
|
|
let { tscPath } = this.client
|
|
|
|
if (!tscPath) {
|
2020-12-17 20:28:49 +08:00
|
|
|
window.showMessage(`Local & global tsc not found`, 'error')
|
2018-09-07 20:40:51 +08:00
|
|
|
return
|
|
|
|
}
|
2021-06-06 22:29:30 -05:00
|
|
|
|
2021-12-25 18:33:00 +08:00
|
|
|
const tsconfigPath = workspace.getConfiguration('tsserver').get<string>('tsconfigPath', 'tsconfig.json')
|
2021-06-06 22:29:30 -05:00
|
|
|
let find = await workspace.findUp([tsconfigPath])
|
2019-04-19 18:27:37 +08:00
|
|
|
if (!find) {
|
2021-06-06 22:29:30 -05:00
|
|
|
window.showMessage(`${tsconfigPath} not found!`, 'error')
|
2018-09-07 20:40:51 +08:00
|
|
|
return
|
|
|
|
}
|
2021-06-06 22:29:30 -05:00
|
|
|
|
2020-04-17 15:47:45 +08:00
|
|
|
let root = path.dirname(find)
|
2019-04-12 16:33:19 +08:00
|
|
|
return {
|
2020-04-17 16:02:42 +08:00
|
|
|
cmd: tscPath,
|
2021-06-06 22:29:30 -05:00
|
|
|
args: ['-p', tsconfigPath, '--watch', 'true', '--pretty', 'false'],
|
2019-04-12 16:33:19 +08:00
|
|
|
cwd: root
|
|
|
|
}
|
2018-09-07 20:40:51 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
public dispose(): void {
|
|
|
|
disposeAll(this.disposables)
|
|
|
|
}
|
|
|
|
}
|