Window titles in screen and urxvt, from vim

I previously posted about generating title escapes for screen and rxvt-unicode from zsh. I’ve since worked on getting a consistent title from vim, too. It’s become complex enough that I’m spinning it out into a new post.

To set both titles from vim, use its termcap-title options to push the title to screen using the iconstring. When not running under screen, the right titlestring escapes will be inferred from terminfo.

set title
auto BufEnter * let &titlestring = s:MyTitle()

if &term =~ 'screen\(\.\(xterm\|rxvt\)\(-\(256\)\?color\)\?\)\?'
  " Set the screen title using the vim "iconstring"."
  set t_IS=^[k
  set t_IE=^[\
  set icon
  auto BufEnter * let &iconstring = &titlestring
  " Set the xterm title using the vim "titlestring"."
  set t_ts=^[]2;
  set t_fs=^G
endif

where the underlined characters are actual escapes input with ^V, not with literal carets.

As for generating a fancy title string like vim: there are some gotchas. The biggest is that vim does not preserve logical directory names, so getcwd() will resolve symlinks, leading to a different location string than generated by zsh’s %~. Rather than call pwd -L, we might as well unify the expansion syntax and call zsh. Of course, it’s nice to have a fallback, too:

" Perform zsh-like prompt expansion using the template {prompt}.  See
" "EXPANSION OF PROMPT SEQUENCES" in zshmisc(1).
function s:ZshPromptExpn(prompt)
  if &shell == "/bin/zsh"
    return system("print -Pn " . shellescape(a:prompt))
  else
    " Fallback to poor man's prompt expansion.
    " By no means equivalent to zsh.
    let idx = 0
    let result = ''
    let escapere = '%\([%)m]\|\(\(-\?[0-9]\+\)\?[~]\)\)'
    while idx < len(a:prompt)
      let nextesc = match(a:prompt, escapere, idx)
      if nextesc < 0
        let result .= a:prompt[idx :]
        break
      elseif idx < nextesc
        let result .= a:prompt[idx : (nextesc - 1)]
      endif

      let idx = matchend(a:prompt, escapere, nextesc)
      let esc = a:prompt[nextesc : (idx - 1)]
      if esc == '%m'
        let result .= substitute(hostname(), '^\([^.]*\).*', '\1', '')
      elseif esc =~ '%-\?[0-9]*[~]'
        let result .= fnamemodify(getcwd(), ':~')[:-2]
      elseif esc == '%%'
        let result .= '%'
      endif
    endwhile
    return result
endfunction

function s:MyTitle()
  return s:ZshPromptExpn("%m:%-3~ ") .
  \ v:progname . " " . fnamemodify(expand("%:f"), ":.")
endfunction

Leave a Reply

Your email address will not be published. Required fields are marked *