use Mutex for rename files in sequence

This commit is contained in:
Qiming Zhao 2020-04-18 19:18:00 +08:00
parent 8fb49605c7
commit 8fadbb20d7
2 changed files with 64 additions and 4 deletions

View file

@ -9,6 +9,7 @@ import * as Proto from '../protocol'
import { ITypeScriptServiceClient } from '../typescriptService'
import * as typeConverters from '../utils/typeConverters'
import FileConfigurationManager from './fileConfigurationManager'
import { Mutex } from '../utils/mutex'
function wait(ms: number): Promise<any> {
return new Promise(resolve => {
@ -29,10 +30,16 @@ export default class UpdateImportsOnFileRenameHandler {
let glob = languageId == 'typescript' ? '**/*.{ts,tsx}' : '**/*.{js,jsx}'
const watcher = workspace.createFileSystemWatcher(glob)
this.disposables.push(watcher)
watcher.onDidRename(e => {
this.doRename(e.oldUri, e.newUri).catch(e => {
client.logger.error(e.message)
})
let mutex = new Mutex()
watcher.onDidRename(async e => {
let release = await mutex.acquire()
try {
await this.doRename(e.oldUri, e.newUri)
release()
} catch (e) {
this.client.logger.error('Error on rename:', e)
release()
}
}, null, this.disposables)
}
@ -50,6 +57,10 @@ export default class UpdateImportsOnFileRenameHandler {
const targetFile = newResource.fsPath
const oldFile = oldResource.fsPath
const newUri = newResource.toString()
let oldDocument = workspace.getDocument(oldResource.toString())
if (oldDocument) {
await workspace.nvim.command(`silent ${oldDocument.bufnr}bwipeout!`)
}
let document = workspace.getDocument(newUri)
if (document) {
await workspace.nvim.command(`silent ${document.bufnr}bwipeout!`)

49
src/server/utils/mutex.ts Normal file
View file

@ -0,0 +1,49 @@
export class Mutex {
private tasks: (() => void)[] = []
private count = 1
private sched(): void {
if (this.count > 0 && this.tasks.length > 0) {
this.count--
let next = this.tasks.shift()
next()
}
}
public get busy(): boolean {
return this.count == 0
}
// tslint:disable-next-line: typedef
public acquire() {
return new Promise<() => void>(res => {
let task = () => {
let released = false
res(() => {
if (!released) {
released = true
this.count++
this.sched()
}
})
}
this.tasks.push(task)
process.nextTick(this.sched.bind(this))
})
}
public use<T>(f: () => Promise<T>): Promise<T> {
return this.acquire()
.then(release => {
return f()
.then(res => {
release()
return res
})
.catch(err => {
release()
throw err
})
})
}
}