Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I open a terminal then I open Vim. Then I work on my source code, but unfortunately I click on the close button of the terminal title bar and my work is lost. Is it possible to configure Vim such that it will tell me when I am trying to close the terminal without saving my work?

Thanks!

share|improve this question
    
gnome-terminal will warn if there is any program running in the terminal windows including, of course, vim. – barraponto Feb 23 '12 at 20:50
2  
Which "Termimal"? There's a program called that on many different OSes, and they have different ways of being configured to cope with this problem. – Warren Young Feb 23 '12 at 20:53
    
@Warren Young: It is a xfce4-terminal. According to the answer of Chris Down below, I would like to change the way my terminal handles WM_DELETE_WINDOW, but I do not know how to do it yet. – Benjamin Feb 23 '12 at 20:56
up vote 15 down vote accepted

There is no way for vim to know in advance that it's grandparent process (the terminal) is killed so it too, is normally killed as a result of killing the parent processes.

However, on most default setups vim will create a .swp file named after the current file being edited; for instance MyPrecious.java.swp. This file should contain a snapshot of the file MyPrecious.java just before the vim process was killed. Unless you have set up vim to specifically put these .swp files in some other directory, they should reside in the same directory as the edited file and you can easily restore your editing work.

Note that some of these files starts with a dot . so they are invisible unless you use ls -a to list the files in a directory.

share|improve this answer
4  
+1 but you should add that the .swp filename starts with a . so it is by default 'invisible'. – Zenon Feb 24 '12 at 0:35

Looking at the problem from a different angle, screen or tmux will allow you to keep your shell going independently of your terminal. When you close the terminal you can open a new one and reconnect to the original shell. Vim will still be running.

share|improve this answer
    
I use tmux and have it hooked into .zlogin so it's always started up when I login to a shell. Never lost a window since. – Matthew Scharley Feb 24 '12 at 3:58
    
@MatthewScharley - if just takes return values -- you don't need to do your roundabout issuing of tmux followed by checking $?, just check tmux. – Chris Down Feb 25 '12 at 21:54

vim has no control over how your terminal's GUI handles WM_DELETE_WINDOW. Instead, look for a setting in your terminal that controls how the terminal acts when asked to close when it has a shell with children.

share|improve this answer
    
Thanks! But how can I change the way my terminal (xfce4-terminal) handles WM_DELETE_WINDOW? – Benjamin Feb 23 '12 at 20:53

There is a way for Vim to know that the terminal has been closed: the SIGHUP signal.

When you close a terminal, the SIGHUP signal is sent to the controlling process, which is usually your shell. Your shell should then exit, causing Vim to be sent the SIGHUP signal. By default, processes simply terminate when they receive the SIGHUP signal.

I'm not familiar with Vim, but maybe it can be configured to save all work before exiting when a SIGHUP signal is received. If not, maybe you can set a shell trap on SIGHUP, perhaps in combination with running Vim with nohup, to execute a special command that somehow causes Vim to exit more gracefully when the terminal is closed.

share|improve this answer

As others have stated, vim cannot react to such an event. But you might consider one of these work-arounds:

  • Using gvim instead of vim, which can be invoked from the command line, too. An alias might help adjusting to the switch (assuming bash-compatible shell): alias vim=gvim. Stating gvim as your preferred editor might help, too: export EDITOR=gvim. This works only on a local machine, though.
  • Using a terminal muxer (such as tmux or screen) was already mentioned.
  • Configuring your terminal (whichever that is) to confirm that you want to close it. This will catch you by surprise the first few times, which should force you to think before closing your terminal in the long term.
share|improve this answer

This came to me after I asked the question in another forum AskUbuntu: vim.desktop - changes lost when terminal exits and a lot of experimental *.desktop files demonstrating that gnome-terminal would allow vim to be killed without warning even if it was running in an shell & even if there were other commands before or after it for bash or gnome-terminal to run.

An "interactive" shell (bash -i) sounded sure to invoke the GNOME warning upon closing the window, based on the literal warning message:

Close this terminal? There is still a process running in this terminal. Closing the terminal will kill it.

but adding the -i option to bash, as run from the *.desktop file, stopped GNOME from opening a window in my testing (with Ubuntu 16.04 - gnome-terminal 3.18.3). So instead I tried invoking the interactive shell from a wrapper script, and that was a full solution:

/usr/local/bin/vim-gnome-wrap

#!/bin/bash -f
bash -ic 'vim "$@"' vim "$@"

... then edit /usr/share/applications/vim.desktop or copy it to a new *.desktop file, with these changes:

TryExec=vim-gnome-wrap
# It doesn't open window for interactive shell when GNOME arranges the terminal:
# Terminal=true
# Exec=vim-gnome-wrap %F
# ... yet it does so when gnome-terminal is run explicitly:
Terminal=false
Exec=gnome-terminal -e "vim-gnome-wrap %F"

This provides a warning upon closing the window whether the vim buffer has unsaved changes or not, and works on multiple files. Special thanks to @muru below for suggesting $@ syntax which preserves arguments exactly (spaces & metacharacters).

share|improve this answer
    
In a script, I'd use bash -ic 'vim "$@"' vim "$@". That should handle filenames with spaces, etc. well enough. (The second vim is just $0 for the command, it can be anything.) – muru Apr 24 at 18:10
    
thanks @muru, have edited as such, noticed problem this eve & hoped there would be a quick answer like that. – rphair Apr 24 at 21:30

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.