Vimscript check if current buffer has unsaved changes - vim

I currently have my status line set up so that it's orange in insert mode and white otherwise. I'd like to make it go another color when I drop back to normal mode if the file has any unsaved changes, as I regularly take a little walk down a rabbit hole wondering why my changes have not taken effect. The little "[+]" doesn't smack me in the face enough ;)
I can't find any functions that start with "buf" and look like predicates for dirtiness though. I assume one exists, but is named something else. I expect there to be something like bufdirty() or bufchanged(). Any pointers? :)

I think that you are looking for
:echo &mod[ified]
which returns 1 if modified and 0 if not modified.

I like the idea of using the statusline color to indicate the buffer state. In fact, I've written the StatusLineHighlight plugin, which indicates the following attributes: modified, readonly, unmodifiable, special non-file "scratch" (but not the insert mode that you're using; for that, I find Vim's mode indication in the lower left corner enough).

Related

alter vim's mode indicator text to just the first letter in airline

I have vim with airline, that tells me which mode I am in. I would like to change it so that rather than the whole word it just displays the first letter. So N, I or V. Although I can find instructions for changing colours of the mode indicator, I can't find the command to add to my .vimrc that will change the text.
What do I add?
I don't use the plugin, but was able to locate the information in its help almost immediately.
You're looking for the g:airline_mode_map configuration; the example even does exactly what you're asking for (single mode letters), so just copy-and-paste the fragment into your ~/.vimrc!
Also, I would recommend to open an issue / ask the plugin author next time. It might take a bit longer until you get an answer, but it alerts the author about things that aren't yet documented or are hard to find in the documentation, so he can improve it.

How to automatically name a file when saving in vim

I'm trying to emulate in vim a behaviour similar to that of TextEdit.app.
As I work I often open a lot of files to take notes, and keep them there without saving them. When I restart the laptop, the TextEdit files will still be there and open thanks to AutoSave. If I do the same thing with vim (specifically MacVim) the files are (as expected) not saved and I lose their content.
My recipe for solving this problem has two bits. The first one is to automatically save the files when I'm not using them, so using a command like:
autocmd BufLeave,FocusLost * silent! wall
This works fine with files that have already been saved, but it ignores ones that have not yet been saved. This is where the second bit comes into play, I would like vim to automatically give these files a default name if it tries to save them and they don't already have a name. Possibly I would also like there to be a default save directory.
The ideal solution would be that when an unnamed file/buffer loses focus it gets saved as ~/Documents/notes/note_1.txt, the second one note_2.txt, etc etc.
I did look around for any pointers that could help in either direction (default name and default directory - the latter is not fundamental though), but couldn't find anything.
Can anybody help?
I don't like your idea, but it is doable.
You need a function:
function! SaveIt()
if bufname("%")==''
exec 'w /path/note_'.localtime()
else
w
endif
endfunction
and in your autocommand, just call the function. Some points you need to note:
the filename would be /path/note_( ms since 1970). your 1,2,3.. index will make vim check filesystem to find out the index. It could be a better name, e.g note_2013-09-11_11:11:11.233 You just change the localtime()
this may throw exception when you try to save a readonly buffer. (help, qf ...) You could check for them though.
Note that I didn't add the ! in w cmd.
it may not work for your autocmd wall. if you want to do it, you have to loop through all buffers, and for each buffer call the function.
after all the function shows the direction how it could be done, it (the quality) is still very far away from "production" level.

Vim Repeat dot (".") command buffer?

I really like the behavior of YankRing, which lets me access the last several things I've yanked or deleted or changed without thinking.
However a complementary feature like this is completely missing for the . repeat command, most often when I type something I really want to repeat, then accidentally overwriting that edit by pressing x to clean something up.
Often it's possible to get back some time still by visual-mode yanking what I just typed, but this is not ideal.
It should be really easy to remember the past few commands.
The question is how possible is it to extract from Vim the representation of the last command contained in whatever stores what . will do before it gets blown away?
If it is as I fear, the only way is to get a plugin to bind to every single command that could edit something, and instrument it in such a way as to store our own repeat-buffer. This is really not practical because I can already imagine how many other plugins that will break. But, I would still really really want this feature if it is possible in any way.
Unfortunately, there's no way to get and replay the command behind the . command. The only workaround is to be perpetually in macro recording mode, and use the macro register as a replacement for the . command.
This tactic is employed by the RepeatLast plugin, which might offer what you want.
Keyword completion and/or ctrl-a in insert mode should cover your needs.
A more yankring-like solution should be possible but, as you say, probably a little too intrusive. Did you look on vim.org by yourself before asking others to do it for you?

In Vim, how to keep characters concealed even when cursor enters that line

I may have a unique situation here. I want gVim (gui version, in Linux) to keep concealed characters concealed no matter what, even when the cursor is on that line or that character gets selected. (It should be as close to if the characters never existed as possible.) Currently the concealed characters show themselves when the cursor enters that line, which causes text to jump around when scrolling and when selecting text.
We are using gView (read-only gVim) to view logs, so as to take advantage of its robust syntax highlighting. Problem is, these logs contain lots of escape characters and TTY color codes, that make reading difficult. (^[33mSomeText^[0m)
I'm using this line to hide them:
syntax match Ignore /\%o33\[[0-9]\{0,5}m/ conceal
Since the files are viewed by non-vim-experts, it looks glitchy and broken when the text un-conceals itself. (And also looks glitchy and broken if the color codes are present, and also looks glitchy and broken if the color codes are blacked-out to become invisible, but still show when selected and appear after copy/paste.)
This should be fine because these files are opened read-only in gview, with an extra set nomodifiable making it even more difficult to save the file. While it's possible to edit and attempt to save the logs, doing so is considered both an invalid thing to do, and a harmless thing to do, and requires enough Vim skills that if someone manages to edit a file they know what they're doing. The problem with being able to edit a line with concealed text does not apply.
If 'conceal' can't be configured to keep hidden text hidden no matter what, an acceptable alternative would be to replace the TTY color codes with whitespace when the file gets opened. But, this has to be done in read-only mode, and we can't have gview throwing up a save dialog on closing the window because the file has been modified by its .vimrc.
Note: I am in full control of the .vim script file sourced when these are read, but cannot control the existence of the TTY color codes or the code that opens the log files in gview. (i.e. I can't pass it through sed or anything like that.) The ideal solution is anything that can transparently nuke the color codes from within a .vimrc, but I'll hear any suggestions. The 'conceal' feature is just my most promising lead.
So, any ideas how to permanently get rid of these on file view without dialogs popping up on close?
:help conceal
When the "conceal" argument is given, the item is marked as concealable.
Whether or not it is actually concealed depends on the value of the
'conceallevel' option. The 'concealcursor' option is used to decide whether
concealable items in the current line are displayed unconcealed to be able to
edit the line.
:help concealcursor
Sets the modes in which text in the cursor line can also be concealed.
When the current mode is listed then concealing happens just like in
other lines.
n Normal mode
v Visual mode
i Insert mode
c Command line editing, for 'incsearch'
'v' applies to all lines in the Visual area, not only the cursor.
A useful value is "nc". This is used in help files. So long as you
are moving around text is concealed, but when starting to insert text
or selecting a Visual area the concealed text is displayed, so that
you can see what you are doing.
Keep in mind that the cursor position is not always where it's
displayed. E.g., when moving vertically it may change column.
Also, :help conceallevel
Determine how text with the "conceal" syntax attribute |:syn-conceal|
is shown:
Value Effect ~
0 Text is shown normally
1 Each block of concealed text is replaced with one
character. If the syntax item does not have a custom
replacement character defined (see |:syn-cchar|) the
character defined in 'listchars' is used (default is a
space).
It is highlighted with the "Conceal" highlight group.
2 Concealed text is completely hidden unless it has a
custom replacement character defined (see
|:syn-cchar|).
3 Concealed text is completely hidden.
Only one command is needed: set concealcursor=n
I might have a better idea—you can pass it through sed (using %!sed) or really do a bunch of other :substitute commands—whatever edits you need to get rid of the color codes.
When you’re done, make sure to set nomodified—this forces vim to think there haven’t been any changes!

Undo all changes since opening buffer in vim

How can I undo all changes since opening a buffer? I imagine there may be some form of :earlier that does this.
UPDATE: Many are suggesting solutions for traversing to earlier file writes. This isn't what I asked for. I want to return to the original state the file was in when I originally loaded it into a buffer, no matter how many writes were made since then.
To revert the current buffer to the original state prior to the very
first change recorded in its undo list (see :help undo-tree), one
can use the following two consecutive invocations of the :undo
command:
:u1|u
The first command (:undo 1) reverts to the state of the buffer just
after the very first registered change, while the second command
(:undo) reverts that first change itself.
Starting with version 8.1 (see :helpg Patch 8.0.1441), Vim accepts
the change number 0 as a valid argument to the :undo command,
finally providing a way to refer to the state prior to any registered
changes. This makes it possible to achieve the same effect in
a single-command invocation:
:u0
You can use the
:edit!
command to get into the earliest saved state. See :help edit! for more information.
You can also check something like gundo.vim (can be found here), which displays the whole undo tree graphically, and you can easily jump between points. Then there is the histwin plugin which I did not used yet, but offers similar functionality.
In vim 8.1+ as well as in neovim, you can just use :u0
From the documentation
:u[ndo] {N} Jump to after change number {N}. See |undo-branches|
for the meaning of {N}. {not in Vi}
If you type
:u 1
it appears to go to after the first change; pressing u or typing :u will then go back to the change.
Otherwise, you can use a very large count to :earlier or g-
e.g.
:earlier 100000000 or 100000000g-
If you put this into a mapping/command, it could do any of these without too much trouble.
e.g.
:nnoremap <C-F12> :earlier 100000000<CR>
To access previously saved file status, I think the following work :
:earlier 1f
From the documentation :
:earlier {N}f Go to older text state {N} file writes before.
When changes were made since the last write
":earlier 1f" will revert the text to the state when
it was written. Otherwise it will go to the write
before that.
When at the state of the first file write, or when
the file was not written, ":earlier 1f" will go to
before the first change.
:earlier {N}m Go to older text state about {N} minutes before.
That should help... And even you have {N}h which is about {N} hours before.
A graphic solution:
The Gundo plugin allows visual comparison of changes in the undo history.
Open Gundo's "undo history pane", type G go to the last line, then we can back to the original file.

Resources