lean4-code-actions
Version:
Refactorings and snippets for Lean 4
72 lines (65 loc) • 3.39 kB
text/typescript
import { NonEmptyArray } from 'libs/utils/array/ensureNonEmptyArray'
import { last } from 'remeda'
import { toString } from 'src/models/Lean/HieroName'
import { Name } from 'src/models/Lean/Name'
import { withWorkspaceEdit } from 'src/utils/WorkspaceEdit'
import { getUriFromLeanNames } from 'src/utils/WorkspaceFolder'
import { ensureWorkspaceFolder } from 'src/utils/workspace'
import { WorkspaceEdit, WorkspaceFolder, commands } from 'vscode'
import { ensureEditor } from '../utils/TextEditor'
import { CreateNewFileConfig, getCreateNewFileConfig } from '../utils/WorkspaceConfiguration/CreateFileConfig'
import { askNamesFromEditor, getTypeFileContentsCV1, wrapFileContentsV1 } from './createNewFile'
export async function createNewFileSet() {
const config = getCreateNewFileConfig('lean4CodeActions.createNewFile')
const editor = ensureEditor()
const workspaceFolder = ensureWorkspaceFolder(editor.document.uri)
const names = await askNamesFromEditor(editor)
if (names === undefined) return
const mainUri = getUriFromLeanNames(workspaceFolder, names)
const result = await withWorkspaceEdit(async edit => {
createDataFile(workspaceFolder, config)(names)(edit)
createLawsFile(workspaceFolder, config)(names)(edit)
createMainFile(workspaceFolder, config)(names)(edit)
})
if (result === false) throw new Error('Edit could not be applied; maybe some files from the set already exist')
await commands.executeCommand('vscode.open', mainUri)
}
const createDataFile = (workspaceFolder: WorkspaceFolder, config: CreateNewFileConfig) => (parents: NonEmptyArray<Name>) => (edit: WorkspaceEdit) => {
const name = 'Data'
const contents = getTypeFileContentsCV1(config)('structure', parents, name)
createFileFromNames(workspaceFolder, edit, parents, name, contents)
}
const createLawsFile = (workspaceFolder: WorkspaceFolder, config: CreateNewFileConfig) => (parents: NonEmptyArray<Name>) => (edit: WorkspaceEdit) => {
const name = 'Laws'
const declarationLines = [
`structure ${name} (data : Data) : Prop where`,
' ',
'deriving Inhabited',
]
const imports = [...config.imports, toString([...parents, 'Data'])]
const opens = config.opens
const contents = wrapFileContentsV1(imports, opens)(parents, name)(declarationLines)
createFileFromNames(workspaceFolder, edit, parents, name, contents)
}
const createMainFile = (workspaceFolder: WorkspaceFolder, config: CreateNewFileConfig) => (names: NonEmptyArray<Name>) => (edit: WorkspaceEdit) => {
const name = last(names)
const parents = names.slice(0, -1)
const declarationLines = [
`abbrev ${name} := @Subtype ${name}.Data ${name}.Laws`,
' ',
`deriving instance Repr for ${name}`,
'',
`instance : Inhabited ${name} := ⟨{`,
' val := default,',
' property := by constructor',
'}⟩',
]
const imports = [...config.imports, toString([...names, 'Data']), toString([...names, 'Laws'])]
const opens = config.opens
const contents = wrapFileContentsV1(imports, opens)(parents, name)(declarationLines)
createFileFromNames(workspaceFolder, edit, parents, name, contents)
}
function createFileFromNames(workspaceFolder: WorkspaceFolder, edit: WorkspaceEdit, parents: Name[], name: Name, contents: string) {
const uri = getUriFromLeanNames(workspaceFolder, parents.concat([name]))
edit.createFile(uri, { contents: Buffer.from(contents) })
}