vim9script import autoload "kg8m/plugin/fzf/qf.vim" as fzfQf import autoload "kg8m/util/cursor.vim" as cursorUtil import autoload "kg8m/util/input.vim" as inputUtil import autoload "kg8m/util/logger.vim" export const DIRPATH = $"{$XDG_DATA_HOME}/vim/qf" export const EXTENSION = "json" mkdir(DIRPATH, "p") export def List(options: dict = {}): list const colorize = get(options, "colorize", true) const command = [ "fd", $FD_DEFAULT_OPTIONS, $FD_EXTRA_OPTIONS, "--strip-cwd-prefix", "--type", "f", "--base-directory", shellescape(DIRPATH), "--extension", EXTENSION, "--color", colorize ? "always" : "never", "| sort_without_escape_sequences", ]->join(" ") return system(command) ->split("\n") ->map((_, filepath) => fnamemodify(filepath, ":t:r")) enddef export def Complete(arglead: string, _cmdline: string, _curpos: number): list const all = List({ colorize: false }) if empty(arglead) return all else return all ->copy() ->filter((_, name) => name =~# $"^{arglead}") endif enddef export def Save(name: string = ""): void const raw_list = getqflist() if empty(raw_list) logger.Error("Quickfix list is empty. Do nothing.") return endif const filepath = NameToFilepath( empty(name) ? strftime("%Y%m%dT%H%M%S") : name ) if filereadable(filepath) const prompt = $"`{filepath}` exists. Overwrite it?" if inputUtil.Confirm(prompt) redraw else redraw echo "Canceled." return endif endif const encoded_list = EncodeList(raw_list) writefile(encoded_list, filepath) logger.Info($"Quickfix list is saved to `{filepath}`.") enddef export def Load(name: string = ""): void if empty(name) fzfQf.Load() else Process(name, (filepath) => { const encoded_list = readfile(filepath) const decoded_list = DecodeList(encoded_list) execute "edit" fnameescape(decoded_list[0].filename) cursorUtil.MoveIntoFolding(decoded_list[0].lnum, decoded_list[0].col) setqflist(decoded_list) copen wincmd p }) endif enddef export def Edit(name: string = ""): void if empty(name) fzfQf.Edit() else Process(name, (filepath) => { execute "edit" fnameescape(filepath) }) endif enddef export def Delete(name: string = ""): void if empty(name) fzfQf.Delete() else Process(name, (filepath) => { const prompt = $"Sure to delete `{filepath}`?" if inputUtil.Confirm(prompt) delete(filepath) logger.Info($"`{filepath}` has been deleted.") else logger.Info($"`{filepath}` remains.") endif }) endif enddef def Process(name: string, Callback: func(string)): void const filepath = NameToFilepath(name) if filereadable(filepath) Callback(filepath) else logger.Error($"`{filepath}` doesn't exist.") endif enddef def NameToFilepath(name: string): string return $"{DIRPATH}/{name}.{EXTENSION}" enddef def EncodeList(raw_list: list>): list return mapnew(raw_list, (_, original_item) => { final item = copy(original_item) item.filename = bufname(item.bufnr)->fnamemodify(":p") remove(item, "bufnr") return json_encode(item) }) enddef def DecodeList(encoded_list: list): list> return mapnew(encoded_list, (_, item) => json_decode(item)) enddef