diff --git a/src/server/features/updatePathOnRename.ts b/src/server/features/updatePathOnRename.ts index d4347e4..ba453de 100644 --- a/src/server/features/updatePathOnRename.ts +++ b/src/server/features/updatePathOnRename.ts @@ -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 { 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!`) diff --git a/src/server/utils/mutex.ts b/src/server/utils/mutex.ts new file mode 100644 index 0000000..0133035 --- /dev/null +++ b/src/server/utils/mutex.ts @@ -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(f: () => Promise): Promise { + return this.acquire() + .then(release => { + return f() + .then(res => { + release() + return res + }) + .catch(err => { + release() + throw err + }) + }) + } +}