5

I renamed a big folder that contains a lot of files I recently edited. After changing the name, my neovim's v:oldfiles list contains the old names that is no longer accessible. How can I clean the list or fix the list to reflect the renaming.

I use fzf to access the mru files. I tried to set the variable directly but it doesn't work


I followed the selected answer to solve the problem for neovim. But when I write the file, even without any change and directly do :w, I encounter the following error and have no idea how to solve it.

Error detected while processing function 
shada#get_binstrings[1]..shada#strings_to_sd[9]..
<SNR>184_shada_convert_strings[87]..
<SNR>184_shada_eval[1]..msgpack#eval:
line   65: 
E716: Key not present in Dictionary: "py
E116: Invalid arguments for function add
Error detected while processing BufWriteCmd Auto commands for "*.shada": 
E686: Argument of writefile() must be a List

Update The error is reported to neovim.

A possible fix is to change line 609 of runtime/autoload/msgpack.vim from

elseif s =~# '-\?\%(inf\|nan\)'

to

elseif s =~# '^-\?\(inf\|nan\)$'

The code affects all versions of neovim.

2
  • Good Work! I am pretty sure others will thank you for this. You could add the neovim version affected by this.
    – Hotschke
    Commented Sep 4, 2018 at 14:11
  • @Hotschke thanks for your effect and time to help me. It is my pleasure to be able to contribute to the community.
    – doraemon
    Commented Sep 4, 2018 at 14:34

2 Answers 2

7

Fix entries in ShaDa File (neovim-specific)

Neovim does not use anymore the plaintext file viminfo (used by vim) to store this but uses a msgpack formatted file called ShaDa (short for shared data, :h shada). If you do not know where this file is, see :h shada-file-name and this tells you

The default name of the ShaDa file is "$XDG_DATA_HOME/nvim/shada/main.shada" for Unix. Default for $XDG_DATA_HOME is ~/.local/share.

Neovim provides special support to edit the binary Shada file (:h ft-shada). When you open this file in neovim with

:e ~/.local/share/nvim/shada/main.shada

the plugin file $VIMRUNTIME/plugin/shada.vim automatically converts the binary file to a human readable plaintext representation for convenient modification:

Global mark with timestamp 2018-09-02T11:32:44:
  % Key  Description  Value
  + n    name         '3'
  + f    file name    "/Users/Hotschke/oldpath/file.log"
  + l    line number  1
  + c    column       0
Jump with timestamp 2018-09-02T11:32:44:
  % Key  Description  Value
  + f    file name    "/Users/Hotschke/unaffected/doc.pdf"
  + l    line number  1
  + c    column       0
History entry with timestamp 2018-09-02T11:34:26:
  @ Description_  Value
  - history type  CMD
  - contents      "e /Users/Hotschke/oldpath/file.log"

For comparison, open the file in vim and you will see the content of a binary file.

Back in neovim: you can run :%s/oldpath/newpath/c to replace the oldpath with a newpath to adjust for the change on your drive. If you type :write, neovim runs a conversion of the buffer to msgpack and saves correctly the file. You do not have to worry about the details.

Remove entries

However, if you simply want to remove outdated entries, delete the complete entry.

The custom text object indent ai from github https://github.com/michaeljsmith/vim-indent-object can make this easier since the current representation uses indentation with a header line. To remove all entries which point to outdated files, e.g. in the above given snippet in global marks and in the cmd history, you can now run :g/oldpath/norm dai.

Finally, I would recommend to read :h shada-format to better understand the ShaDa file, in particular when you make changes to it.

4
  • @Hotshke Thanks very much. Will it get into problem if there exist duplicated file names after the substitution? Do I need to manually remove the duplications?
    – doraemon
    Commented Sep 3, 2018 at 1:15
  • The files listed by :oldfiles is generated by shada entries with the type mark (7, 8, 10, 11). There can always be several marks for a single file without your substitution command. :oldfiles lists each file once, presumably in the order of the most recent timestamp. Also the uniqueness of the marks is not changed by your substitution command. So no, you do not have to remove duplicates. In fact there are always duplicates. BTW you can create a backup of the file and/or activate persistent-undo to make sure you can undo your changes.
    – Hotschke
    Commented Sep 3, 2018 at 6:41
  • When I wrote the shada file (w, even without any change to the file), I got error as shown in the edited original post. Do you have any idea of what is going on there?
    – doraemon
    Commented Sep 4, 2018 at 9:04
  • I debugged a little the code for msgpack#eval and identified a possible bug over there
    – doraemon
    Commented Sep 4, 2018 at 9:59
1

I have written an article on dev.to about accessing v:oldfiles entries, here is the function to access oldfiles outside of vim:

function old(){
    [[ -f /tmp/oldfiles.txt ]] && \rm /tmp/oldfiles.txt
    vim -c 'redir >> /tmp/oldfiles.txt | silent oldfiles | redir end | q'

    local fname

    FILES=()
    for i in $(awk '!/man:/ {print $2}' /tmp/oldfiles.txt); do
        [[ -f $i ]] && FILES+=($i)
    done

    fname=$(printf "%s\n" "${FILES[@]}" | uniq | fzf) || return

    vim "$fname"
}

A "zsh" keybinding to trigger the function above with CtrlAlto

bindkey -s '^[^O' 'old^M'
2
  • Some tidbits: the for loop is going to break on filenames with spaces (let alone newlines); you could try readarray instead. Instead of awk '!a[$0]++', why not use uniq or sort -u? Heck, why not just pipe awk '!/man:/{ print $2 }' into sort -u and then into fzf?
    – D. Ben Knoble
    Commented Jan 21, 2022 at 1:43
  • Sorry D. Ben Knoble I forgot the windows users who use spaces in filename. I will exchange awk for uniq. Thanks! Commented Jan 21, 2022 at 15:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.