1

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.

Mahmoud Al-Qudsi
  • 296
  • 1
  • 10

4 Answers4

5

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.

Mahmoud Al-Qudsi
  • 296
  • 1
  • 10
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.
Rich
  • 31,891
  • 3
  • 72
  • 139
  • Thanks, Rich. As you can tell, I'm out of my depths in vimland :) – Mahmoud Al-Qudsi Aug 07 '17 at 16:32
  • @MahmoudAl-Qudsi Don't worry, you'll pick it up quick. Just keep reading through the :help! – Rich Aug 07 '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 07 '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 07 '17 at 20:16
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.

Luc Hermitte
  • 17,351
  • 1
  • 33
  • 49
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()
SergioAraujo
  • 1,165
  • 11
  • 12
  • 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