How to make vim indicate the file has changed since last save? - vim

I used to work with netbeans and it always put an asterisk and changed the tab color when the file had changed since last save. Is there any way to make vim do something similar, that is, remind me that I haven't saved the file?
I know that there is a way to have it save automatically once in a while, but I don't want to do that.

You can use the m flag in the 'statusline' option to add a [+] if file is modified. Note that in order to see the statusline, you'll need to set 'laststatus' to be greater than 0 (1-Only shows status line if there are two or more windows, 2-Always).
If you're using a GUI-version, such as MacVim, you may prefer to set 'titlestring', which uses the same syntax but will alter the name of the window in your window-manager.
Example:
:set laststatus=2
:set statusline=[%n]\ %<%f%h%m
This will display:
[: literal
%n: buffer number
]: literal
\<Space>: a space
%<: Truncate the field at the beginning if too long
%f: Path to the file in the buffer, as typed or relative to current
directory.
%h: Help buffer flag, text is "[help]".
%m: Modified flag, text is "[+]"; "[-]" if 'modifiable' is off.
For more information see:
:help status-line

Call :ls and you will see a + before unsaved buffers

If the terminal displays its title somewhere, it's possible to use
:set title
to display whether the file is modified: a + is displayed after the file name if it's modified.
However, a file can have + at the end of its file name. For most files this should work fine.
Source: https://stackoverflow.com/a/13244715/5267751

Pressing Ctrl+g (or equivalently :f) in normal mode will show the file status, which indicates whether the file is modified.
The status looks like this
"file_name" 100 lines --20%--
if the file is not modified, or
"file_name" [Modified] 100 lines --20%--
if the file is modified.
For more info see :help ^g.

Related

Vim gF should open file and jump to line

I tried out gF and it seems to not behave like mentioned in :help gF
If cursor is positioned on an entry x.c and I type gf the file is opened.
If cursor is positioned on an entry x.c:3 and I type gF I get E447: Can't find file "x.c:3" in path. Whereby :3 should tell vim to jump to line 3.
What do I miss?
Enter :set isfname
It'll show an OS dependent list of all characters considered being possibly part of a file name. On my system (Windows), the column : appears in the list.
isfname=#,48-57,/,\,.,-,_,+,,,#,$,%,{,},[,],:,#-#,!,~,=
Hence it won't be considered by gF as a separator between file name and line number. However if I add a space between them, the behaviour goes as documented.
Given how no sane person uses : in a file name, if you want to use gF on some compiler's output that says file.c:120, you can add this to your vimrc :
set isfname-=:
(mind the - before the =)
If ever one day you need to open a file that has a : in its name, you can always enter :set isfname+=: to restore the column as a valid file name character for the duration of that session.

VIM open c++ header file in vertical split by combining three commands

I have indexed my c++ codebase with ctags, I can open a header file as follows:
:tag myfile.h
(It doesn't matter where myfile.h is located, as long as it is inside the indexed codebase it will open correctly in vim)
When I'm editing a c++ file, I can get the header filename as follows:
:e%<.h
e.g. when editing myfile.cpp, executing this command will display myfile.h on the command line.
A file can be opened in vertical split, by issuing:
:vs <myfile>
Now what I want to accomplish, is to have 1 command or function which I can use to open a header file of the corresponding c++ file that I'm currently editing in vertical split. Hence basically I want to combine the 3 above commands as if I would be doing a Unix pipe, e.g.:
:vs tag | e%<.h
" :vs to open file in vertical split
" :tag to find tag
" :e%<.h to get header filename
Obviously the Unix pipe doesn't work on vim, alternatively I've tried to write a function at which I assign the result of a command to a variable, e.g.
headerFileName = :e%<.h
Which apparently is not the correct way of doing this, I'm a bit lost here so I hope somebody can provide some help.
There exist several plugins that already do this (without needing a ctags database BTW).
For instance, with alternate (aka a.vim), you just have to type :VS from the header file or the source file to open the other one in a vertically split window.
Note that alternate have an option to tell where to find the other file (same directory, substitute on directory name, ...)
Otherwise, I suspect you are looking for expand() and :exe. If you write a function it may be
function! s:whatever() abort
let crt = expand('%:t:r')
vnew
exe 'tag '.crt.'.h'
endfunction
command! whatever call s:whatever()

How could I judge whether the file has been changed since last saving in vim

I am trying to quantify my vim action by logging timestamp when saving(:w) a file.
Is it possible to know whether the file had really been edited since the last saving?
for example, I saved the file by :w, then, did nothing and just type :w to save it again, is it possible to judge that the file wasn't actually modified?
You can check the value of the 'modified' option:
if &modified
" do something if the buffer is modified
else
" do something else if it is not
endif
Vim displays a '[+]' next to the file name when the file has been modified. However it displays it even if there is no diff between the file on disk and your buffer (for example if you add the letter 'a' then remove it it will consider that the file has been edited).
press :file and if changes have been made [Modified] will be displayed after your file name.
If you have set laststatus to 2 in Vim, it shows you a status line at the bottom of the window which has a [+] indicator next to the filename when the file has been modified since it was last written.
Relevant help pages: laststatus, statusline
Before reading your answer, I thought it was about knowing if the file had been updated from another vim instance / editor before saving it!
If so, vim usally tell me when I want to save it :
WARNING : the file has been updated since vim read it !
Do you want to write it anyway (y/n)?
If it's only about knowing if you change anything since last time, as explained before, Vim display a [+] after your filename.

Vim show and be able to delete 0x0a at end of file

This is driving me nuts. Similar SO questions don't contain the answer, though, so here it goes again in slightly different form:
Is there a way to:
Make vim show 0x0a at the end of file as a blank line?
Supposing #1 can't be done, how do I delete the eol? There is no line, so there is nothing to delete.
For example:
vim -b myfile (currently no eol)
Add blank line at the end of file, :w :q
vim -b myfile - the blank line is gone, but hexdump shows 0x0a is still there. This is inconsistent behaviour.
I don't know how to see the last blank line, but to remove just open your file, the run:
:set binary noendofline
This will remove the last (invisible) blank line from it.
Warning: because of binary some settings will be modified (for example textwidth)!
You can use set noeol in binary mode:
:help noeol
When writing a file and this option is off and the 'binary' option
is on, no <EOL> will be written for the last line in the file. This
option is automatically set when starting to edit a new file, unless
the file does not have an <EOL> for the last line in the file, in
which case it is reset.
see also: Vim show newline at the end of file
The way Vim shows 0x0a at the end of the file is that it opens the file without complaining about [noeol] when :editing the file (in a kind of "reverse logic" from what you expect). As you've probably read already, Vim's (and Unix) philosophy is that the trailing newline should be there.
Based on this philosophy, I wouldn't recommend intentionally creating files without a trailing newline. However, there are ways to make Vim respect and maintain such existing files. My PreserveNoEOL plugin provides a way to do this effortlessly.

vim Jump to the next non-identical line

I am looking at files that may have several consecutive identical lines.
Is there a easy way of jumping to the next non-identical line?
Alternatively I would like to be able to fold all the lines that are equal to the initial one showing just the number of linees that are folded.
You could define your own fold-expr:
first set fdm:
:set fdm=expr
then
:set foldexpr=getline(v:lnum)==#getline(v:lnum-1)?1:0
now you can test by typing zM, to close all fold, if you are lucky ^_^ all duplicated lines are folded.
you could type zR to open all folds.
if it works and you open those kind of file very often, you could put the above lines in your .vimrc.(au with ft) if only one time job, you can write mode line into that file.
Try this:
:nmap <F2> "1y$<CR>/^\(<C-R>1$\)\#!<CR>
It maps F2 to:
copy the current line into register 1
search for (and move to) the first line that does not match the contents of register 1
This seems to work well, unless the text of your copied line has escaped characters that will confuse the search regexp. This is because register 1 is just dropped into the search expression without escaping. This would be tricky to fix reliably, but for normal log files, it shouldn't be much of a problem.
Also: if you're not married to vim and just need to read the non-consecutively-duplicated lines of a file, the canonical UNIX way is:
uniq filename
If you want to be in vim but won't need to make changes to the file, try:
:%!uniq
(If you try the latter, be sure to exit without saving)

Resources