lean4-code-actions
Version:
Refactorings and snippets for Lean 4
81 lines (74 loc) • 3.35 kB
text/typescript
import { isDefined } from 'remeda'
import { exclude } from 'src/constants'
import { HieroName, toString } from 'src/models/Lean/HieroName'
import { HieroNameString } from 'src/models/Lean/HieroNameString'
import { getRangeFromOffsetAndLength } from 'src/utils/Range'
import { withWorkspaceEdit } from 'src/utils/WorkspaceEdit'
import { getLeanImportPathFromAbsoluteFilePath } from 'src/utils/path'
import { FileRename } from 'src/utils/vscode/FileRename'
import { escapeRegExp } from 'voca'
import { FileRenameEvent, ProgressLocation, window, workspace } from 'vscode'
interface HieroRename {
oldName: HieroName
newName: HieroName
}
interface HieroStringRename {
oldName: HieroNameString
newName: HieroNameString
}
export const onDidRenameFiles = async (event: FileRenameEvent) => {
const uris = await workspace.findFiles('**/*.lean', exclude)
const renames = event.files.map(toRename).filter(isDefined)
return window.withProgress({
cancellable: true,
location: ProgressLocation.Notification,
title: 'Updating imports',
}, (progress, cancellationToken) => {
return withWorkspaceEdit(async edit => {
const total = uris.length
const increment = 1 / total
for (let index = 0; index < uris.length; index++) {
const uri = uris[index]!
// opening a new document each time to keep the memory footprint low (otherwise we'll get OOM in large workspaces)
const document = await workspace.openTextDocument(uri)
const { getText, positionAt } = document
const getRange = getRangeFromOffsetAndLength(positionAt)
const text = getText()
for (const rename of renames) {
if (cancellationToken.isCancellationRequested) return
const { oldName, newName } = rename
const oldImport = `import ${oldName}`
const newImport = `import ${newName}`
const oldImportRegExp = new RegExp('^' + escapeRegExp(oldImport) + '$', 'gm')
const matches = text.matchAll(oldImportRegExp)
for (const match of matches) {
const { index } = match
if (index === undefined) continue
const range = getRange(index, oldImport.length)
edit.replace(uri, range, newImport)
}
}
progress.report({ message: `${index + 1} of ${total} files processed`, increment })
}
}, cancellationToken)
})
}
const toRename = ({ oldUri, newUri }: FileRename): HieroStringRename | undefined => {
const oldUriWorkspaceFolder = workspace.getWorkspaceFolder(oldUri)
const newUriWorkspaceFolder = workspace.getWorkspaceFolder(newUri)
if (!oldUriWorkspaceFolder) return
if (!newUriWorkspaceFolder) return
const oldUriWFS = oldUriWorkspaceFolder.uri.toString()
const newUriWFS = newUriWorkspaceFolder.uri.toString()
if (oldUriWFS !== newUriWFS) return
const oldUriS = oldUri.toString()
const newUriS = newUri.toString()
if (!oldUriS.endsWith('.lean')) return
if (!newUriS.endsWith('.lean')) return
const oldName = getLeanImportPathFromAbsoluteFilePath(oldUriWFS, oldUriS)
const newName = getLeanImportPathFromAbsoluteFilePath(newUriWFS, newUriS)
return { oldName, newName }
}
const toHieroStringRename = ({ oldName: prev, newName: next }: HieroRename): HieroStringRename => {
return { oldName: toString(prev), newName: toString(next) }
}