0

This is perhaps a beginner question, but I'm unable to (intuitively) figure out how to redirect the output of an ex command to a variable for further processing.

Some background: I'm trying to create a list of file paths that I want to pass to fzf, and so I'm concatenating several sources into a list. In effect, what I want is something like this:

let list1 = split(system($FZF_DEFAULT_COMMAND), "\n")
let list2 = map(range(1, bufnr('$')),'bufname(v:val)')
let list3 = :oldfiles

call fzf#run({'source': list1 + list2,
            \ 'sink': 'e',
            \ })

My problem is with the :oldfiles list. I can't find the correct syntax to capture the output of that ex command int a local variable list3. I've tried the obvious (let list3 = :oldfiles) and some other options (&oldfiles, call oldfiles(), :oldfiles | list3, :oldfiles > list3, let list3 = :redir <CR> :oldfiles <CR> :redir END <CR>, etc. to no avail.

Thank you.

3

The correct syntax for doing this with redir (which works in earlier versions of vim than execute()) is this:

redir => list3
oldfiles
redir END

Or if you really want it to be a one liner:

redir => list3 | oldfiles | redir END

This is described about halfway down the documentation for :help :redir.

As for why the other ideas you tried didn't work:

  • &oldfiles: The & syntax allows you to access an option as a variable. :oldfiles is an Ex command, not an option.
  • call oldfiles() would call the oldfiles() function, if one existed. Again, :oldfiles is an Ex command, not a function.
  • :oldfiles | list would run the :oldfiles command, followed by the :list3 command (again, if one existed).
  • :oldfiles > list3 As far as I'm aware, this isn't really Vim syntax at all.
  • let list3 = :redir <cr> :oldfiles <CR> :redir END <CR> This definitely isn't Vim syntax.
  • Thanks, Rich. As you can tell, I'm out of my depths in vimland :) – Mahmoud Al-Qudsi Aug 7 '17 at 16:32
  • @MahmoudAl-Qudsi Don't worry, you'll pick it up quick. Just keep reading through the :help! – Rich Aug 7 '17 at 16:34
  • Thanks, Rich. How do I see the documentation for a function? E.g. :help split shows info on buffer splittinf and nothing about the string splitting function I guessed existed via trial and error. – Mahmoud Al-Qudsi Aug 7 '17 at 17:42
  • 1
    In the documentation, tags for functions end with a pair of empty parenthesis. Commands start with a colon. Options are surrounded by single quotes. Insert (/resp command, visual) mode mappings start with a i_ (/resp c_, v_). Search patterns start with / (-> :h /\s). Other tags (normal mode mappings, variables, concepts,...) aren't decorated -- I can't remember of any other exceptions. – Luc Hermitte Aug 7 '17 at 20:16
2

I managed to figure this one out. neovim and modern versions of vim provide an execute function that can be used to do just this.

let list3 = execute(":oldfiles") does the trick.

2

Prefer execute() over :redir if you can -- there are less side-effects.

In that particular case, it seems that v:oldfiles already contains the information you're looking for.

0

Personally I have created a function to get my last 20 commands, as it would be useful here it is:

" this function gets last 20 cmds to new buffer
fun! s:RedirHistoryCommands()
    set paste
    redir @r
    history : -20,
    redir End
    new
    put r
    set nopaste
    :%s/^\s\+//g
    :g/^$/d
endfun
command! -nargs=0 GetHistory call s:RedirHistoryCommands()
  • In my experience: we're better not using :redir when we can. In your particular case, you have: :echo map(range(1, 20), 'histget("cmd", "-".v:val)'). It's seems a bit convoluted at first, but at least there is no side effect. BTW: q: already opens a window where the history is dumped. – Luc Hermitte Aug 10 '17 at 16:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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