3

From years of "finger memory" my hands know that F2 is save and F3 is quit (leftovers from years of IBM editors). Consequently my first vim key mappings were to get F2 and F3 doing what they're supposed to do. In particular for F3:

:map <F3> :q<CR>
:map! <ESC>:q<CR>

If I quit a file that has edits I still get the E37: No write since last change (add ! to override). What I'd prefer is more a function that would emit E37: No write since last change. Press F3 again to really quit.)

How would I code this?


Updated Solution Suggestion

It was pointed out to me that I could have used confirm to accomplist this task. I "knew" I'd seen some built-in solution before but i couldn't remember it. Note, however, confirm's sense is sense is inverted from the macro's, i.e. it offers "Yes, keep changes" while the macro offers "yes, discard changes." I'd have settled for confirm` if only it had been suggested earlier.


What I Actually Did

First, thanks @Jamie Schembri for the starting example. Always good to have an example when learning a new scripting language.

Here is the macro as I finally used it. Yes, it does not quite parallel the requirements. I replaced the second F3 with a Yes|No|Write choice which just felt better. I also had to add a nr2char() so the test for letters would work. I also had to delete one of the CR's from the :map.

UPDATE see this question for a solution using this macro with added functionality to handle tagstack files. If you quitfrom a file in the tagstack, vim closes all your files.

function! QuitF3()
  try
    quit
  catch /E37:/
    " Unwritten changes.
    echo "E37: Discard changes?  Y|y = Yes, N|n = No, W|w = Write"

    let ans = nr2char( getchar() )

    if      ans == "y" || ans == "Y"
      quit!
    elseif  ans == "w" || ans == "W"
      write
    else
      call feedkeys('\<ESC>')
    endif
  endtry
endfunction
Community
  • 1
  • 1
Wes Miller
  • 2,191
  • 2
  • 38
  • 64
  • "From years of "finger memory" my hands know that F2 is save and F3 is quit" damn. I think I could feel the memory-bump. ISPF/PDF could still teach a few things to the unix toolkit. A few. – jthill Nov 19 '13 at 13:44
  • Xedit, ZED, Redit, E, E/PM.... I wish there was a good linux clone of E/PM that used Rexx for macros. THE is a pretty gfood Xedit clone but it fights hard to be a pain on Linux. – Wes Miller Nov 19 '13 at 13:47
  • I'm trying to find how to do a next-key-only intercept that will let you ignore the message completely (so if you don't hit F3 whatever you do hit behaves normally). – jthill Nov 19 '13 at 13:58
  • I'll settle for discarding the next key unless it's F3. You know I'm going to hit ESC. ESC is to VI what reboot is to windows. – Wes Miller Nov 19 '13 at 14:07

2 Answers2

3

Referring to pandubear's answer, I wrote a quirky little function which seems to do what you want.

function! QuitF3()
  try
    quit
  catch /E37:/
    " Unwritten changes.
    echo "E37: No write since last change. Press F3 again to really quit."
    if getchar() == "\<F3>"
      quit!
    else
      " Close prompt.
      call feedkeys('\<ESC>')
    endif
  endtry
endfunction

map <F3> :call QuitF3()<CR><CR>
Community
  • 1
  • 1
Jamie Schembri
  • 6,047
  • 4
  • 25
  • 37
  • There it is. Will you explain what's causing the prompting you're skipping please? – jthill Nov 19 '13 at 17:20
  • Well, it doesn't quite work. It seems to get a 13, , from somewhere that is eaten by the getchar() and sees that is not an F3. Adding an `echo getchar()` before the`if getchar()` seems to fix the problem but produces gook on the screen. `echo getchar() > /dev/nill` did no good either. – Wes Miller Nov 19 '13 at 19:26
  • Oh, BTW, doesn't it need a `nr2char()` around the getdhar() to do ASCII to char translation? – Wes Miller Nov 19 '13 at 19:27
  • @jthill I'm honestly not sure, but I'd love if someone could shed light on that. That's the "quirky" bit. @WesMiller It shouldn't need `nr2char()` if I understand `:help getchar()` correctly. I only have OS X Terminal and iTerm2 to test with here, but both work, so could it be something to do with your terminal? – Jamie Schembri Nov 19 '13 at 20:30
  • Okay. I was about five minutes' frustration behind you, then :-) Wish I'd come up with just feeding it what it wanted as you did, I think my practical gear needs oiling. Hey, you could save the getchar result and append it to the feedkeys arg. – jthill Nov 19 '13 at 20:35
  • @jthill It certainly annoyed me that it required that extra ``, so I'd really like to figure out why it does! Anyway, I did try passing the `getchar()` result, but it resulted in weird behaviour — probably due to `expr-quote`. – Jamie Schembri Nov 19 '13 at 20:57
1

I think you could map F3 to a function that does this sort of thing: (pseudocode)

try:
    quit
catch error 37:
    intercept next keystroke
    if it's F3:
        force quit
    else:
        send key back to vim

I don't know all the details, but I'm pretty sure you can do all of those things with :try, :catch, getchar() (iffy on this one, not sure if it'll work for special keys like F3) and feedkeys(). See the :help for each of those things.

Seems a little bit much, though. Why not make a separate mapping for :q!?

Pandu
  • 1,606
  • 1
  • 12
  • 23
  • Similar to my thoughts. I have seen this behavior before so I know it can be done. And adding an extra mapping defeats the role of finger memory. – Wes Miller Nov 19 '13 at 14:55
  • Please see the "What I Actually Did" apended to the question. Sorry it won't fit here. Note, I had a problem with the second and had to remove it. – Wes Miller Nov 21 '13 at 15:00