What is a vimrc function to determine if a buffer has been modified?
Asked Answered
B

2

7

I have a tabline function that I stole/modified from somewhere, but I would like the filename to have an asterisk before it if it has been modified since the last time it was written to disk (ie if :up would perform an action).

For example this is my tabline when I open vim -p file*.txt

file1.txt file2.txt file3.txt

Then after I change file1.txt and don't save it:

*file1.txt file2.txt file3.txt

My tabline function:

if exists("+showtabline")
   function MyTabLine()
      let s = ''
      let t = tabpagenr()
      let i = 1
      while i <= tabpagenr('$')
         let buflist = tabpagebuflist(i)
         let winnr = tabpagewinnr(i)
         let s .= ' %*'
         let s .= (i == t ? '%#TabLineSel#' : '%#TabLine#')
         let file = bufname(buflist[winnr - 1])
         let file = fnamemodify(file, ':p:t')
         if file == ''
            let file = '[No Name]'
         endif
         let s .= file
         let i = i + 1
      endwhile
      let s .= '%T%#TabLineFill#%='
      let s .= (tabpagenr('$') > 1 ? '%999XX' : 'X')
      return s
   endfunction
   set stal=2
   set tabline=%!MyTabLine()
endif
Beggar answered 30/6, 2011 at 17:34 Comment(1)
possible duplicate of Vim Buffer has been modifiedNorthern
E
15

I was just looking for the same and found that %m and %M is not well suited, as it tells you whether the currently open buffer is modified. So you cannot see if other buffers are modified (especially for tabs, this is important).

The solution is the function getbufvar. Roughly from the help:

let s .= (getbufvar(buflist[winnr - 1], "&mod")?'*':'').file

instead of

let s .= file

should do the trick. This can be used nicely to show all buffers open in one tab (in case of multiple splits).

Eunuchize answered 3/9, 2011 at 1:18 Comment(0)
B
1

tabline uses similar flags as statusline (see :h statusline). So %m is what you need and modifying the lines just before the endwhile as

let s .= file
let s .= (i == t ? '%m' : '')
let i = i + 1

will automatically place the default [+] after the file name in the current tab if there are unsaved changes.

Barite answered 30/6, 2011 at 19:40 Comment(7)
Thanks! Woohoo my upvote pushed you over 10k ;) The only problem with your modification is that the [+] only appears if the focused tab is modified. If the tab you are currently viewing is not modified, none of the other tabs have the [+] even if they are modified.Beggar
@Philip: Thanks :) Yeah, that's how I normally use it and just copied from my vimrc. Could you try just leaving it as let s.= '%m' instead of the conditional statement? Let me know if that works. I don't have time to check if it works right now, but perhaps later in the day... (unless of course, it works)Barite
@yoda that makes all the tabs have [+] when you are focused on a tab that has been modified, and all the tabs have nothing when you are focused on an unmodified tab.Beggar
@Philip: Ah, yes of course. Hmmm... I'm not sure if there is a way to poll a buffer number and get its modified status. It guess it could be implemented by building upon this (I don't know how yet and I could be wrong too), but I really wouldn't recommend it. The reason is because the tabline is updated on every keystroke. So if you have a function that polls each buffer on every keystroke, you'll notice a hit in performance. I guess its one of those things where you got to weigh if its really necessary and if its worth the effort.Barite
Could you cache the other buffers' modified values somehow? Since if you aren't focused on that tab, it is unlikely they will be updated. That way you wouldn't have to poll the other buffers each keystroke, just read from an array. I know that's what I would do in a programming language I know, but I don't know the limitations of the vim scripting language. Also, isn't that (the behavior I'm looking for) the default in some vim installations?Beggar
@philip: I haven't tried that and my vimscript-fu doesn't extend that much to give you a definite answer either way. In any case, you can modify all buffers without having to switch tabs using bufdo and so there might be other corner cases involved if you take the cacheing route.Barite
I checked at home and this is the default behavior on my mac vim and my ubuntu vim installations. At work I have to develop in Windows, and the cygwin vim does not do this, so I was trying to duplicate the behavior in my vimrc. Do you know where the statusline code is in my vim installations at home?Beggar

© 2022 - 2024 — McMap. All rights reserved.