Vim: Avoid having to press ENTER after successful make? - vim

$ ls
Makefile html-page/ page-generator.m4
Run includes/
Alongside the Makefile, I have a script Run that is executed only when make completes without errors. This I've managed to implement with the following in my .vimrc file, which also looks for the Makefile in parent directories if needed.
" Before the 'make' quickfix command, run my quickfix pre-commands
autocmd QuickfixCmdPre make call MyQuickfixCmdPre()
" After the 'make' quickfix command, run my quickfix post-commands
autocmd QuickfixCmdPost make call MyQuickfixCmdPost()
and
function! MyQuickfixCmdPre()
" Save current buffer, but only if it's been modified
update
" (h)ead of (p)ath of % (current buffer), i.e. path of current file
let l:dir = expand('%:p:h')
" Remove final / and smack a /Makefile on the end, glob gives empty if file doesn't exist
while empty(glob(substitute(l:dir, '/$', '', '') . '/Makefile'))
" There's no Makefile here. Are we at the root dir?
if l:dir ==# "/"
" Just use dir of current file then
let l:dir = '.'
break
else
" Try the parent dir. Get (h)ead of dir, i.e. remove rightmost dir name from it
let l:dir = fnamemodify(l:dir, ':h')
endif
endwhile
" Makefile is in this dir, so local-cd (only this window) to the dir
execute "lcd " . l:dir
endfunction
function! MyQuickfixCmdPost()
" Get number of valid quickfix entries, i.e. number of errors reported,
" using filter to check the 'valid' flag
let l:err_count = len(filter(getqflist(), 'v:val.valid'))
if l:err_count ==# 0
" The make succeeded. Execute the Run script expected in the same dir as Makefile
call system('./Run')
redraw!
endif
endfunction
With this in place, after typing :mak in vim, the code is made and run... There are two possible results:
If there are errors during make, vim will present these errors with a Press ENTER or type command to continue afterwards, which is all good.
If make succeeds without errors, however, my Run script is executed, for testing my code (in this case an html file shown in a browser), but then when I switch back to vim, I have to press enter to get rid of a message from vim that I don't need to read because it doesn't tell me about errors. This message used to look like this:
"includes/m4includes/subs.m4" 34L, 759B written
:!make 2>&1| tee /var/folders/zk/0bsgbxne3pe5c86jsbgdt27f3333yd/T/vkbxFyd/255
m4 -I includes/m4includes page-generator.m4 >html-page/mypage.html
(1 of 1): m4 -I includes/m4includes page-generator.m4 >html-page/mypage.html
Press ENTER or type command to continue
but after introducing the redraw! in MyQuickfixCmdPost() is now reduced to:
(1 of 1): m4 -I includes/m4includes page-generator.m4 >html-page/mypage.html
Press ENTER or type command to continue
yet still with the need to press enter.
How do we avoid having to press enter every single time we return to vim after a successful compilation? Any ideas?
Note: vim has a -silent command-line option, but as far as I can see this would silence all the Press ENTERs, and the goal here is to only avoid them after a successful make.

Just add call feedkeys("\<CR>") afterwards. There are not many places you need feedkeys() (often normal! or similar commands will do), and there are subtle effects (look at the flags it takes carefully). Fortunately this is one place it is useful.

Related

call from command line, show file also if the search does not match

I use a msdos-script to search with vim for patterns and show me the result
Script: tel.bat
rem script is called: tel.bat <pattern>
gvim -R %WORKSPACE%\telliste.csv "+set ignorecase" "+set ft=javascript" -c /%1
This works fine if the pattern exist in the file. If the pattern is not matched, I get an error message and I am stuck. No keystroke or mouse action changes the state. Like:
Enter key - has no effect
Esc key - has no effect
Ctrl + C - the error-messages disappears, but the editor is frozen. No action possible
Mouse click in editor - has no effect
I can only close vim and try again. That's what I get as error, when I call the script tel.bat konez on the command line:
Error message translated:
Error during execution of "command line":
E486: Pattern not found: konez
Confirm with the ENTER Key or place a command
How can I work further on the file, even if the pattern is not found? In other words how can I avoid that I am stuck in vim.
I tried already with -c ":execute 'silent !'" in the batch file, but this was not recognized. Perhaps I did it in the wrong way...
This should work, and I cannot reproduce this on Linux with Vim version 8.0.1358; I can accept the error message with <Enter> and continue.
This could be a plugin / configuration issue; try launching with gvim --clean.
The multi-line error message is ugly. You could avoid it by moving to the lower-level search() function:
gvim ... -c "call search('%1')"
By evaluating its return value; you could also craft your own error message: if search(...) == 0 | echomsg 'No matches' | endif

Vim: cannot see :echomsg messages in message history list

I'm working on a vim script and want to see the value of a variable that is generated in the script for debugging purposes.
I use something like:
echomsg 'My variable = ' . b:variable
reload the source with
:source %
and then look the message history list with
:messages
But there's nothing there and I'm pretty sure that the command would be executed.
What am I doing wrong here?
EDIT:
I'm trying to make a change to vim-cucumber and so I wanted to see the value of a variable. In the ftplugin/cucumber.vim file, I have the following:
let b:cucumber_root = expand('%:p:h:s?.*[\/]\%(features\|stories\)/step_definitions/mobile_website\zs[\/].*??')
echomsg 'cucumber_root = ' . b:cucumber_root
If you look at the top of file you will find
if (exists("b:did_ftplugin"))
finish
endif
Which stops the file from being sourced again after the first time. You need to unlet b:did_ftplugin before sourcing the file again.
Other options would be to use another tpope plugin to do this for you called scripttease with the :Runtime command.

Vim write temporary info as :write does

I have a macro which calls a function I defined in my vimrc
:function! DoStuff()
:!mycommand
:end
map <C-p>i :call DoStuff()<CR>
When I press the macro keys I get right a shell with the output of mycommand and it works fine but I would like improve that.
I noticed that when I write a file (:w) a short message is displayed for short time in the command bar which says "File X written", I want to achieve the same result, when macro sequence is pressed I want check if the command went fine (checking the return code) and then display a message (such "Ok" or "Not Okay") as the :write command does.
Any ideas ?
Write external command output to a temporary file
via Vimscript functions
First, capture the output of the external command in a variable, whose contents can then be written to a (temporary) file via writefile().
:let output = system('mycommand')
:call writefile(output, 'path/to/tempfile')
via scratch buffer
If you need to apply arbitrary commands to the captured contents, or need Vim to handle different file encodings, you have to use a buffer:
:new path/to/tempfile
:0read !mycommand
:write
:bdelete
via file redirection
This is the simplest approach when you need the output as-is:
:!mycommand > path/to/tempfile
Check for command success and notify
After external command execution, the special variable v:shell_error contains exit status of the last shell command. You can test that to report a message to the user:
!mycommand
if v:shell_error != 0
echohl ErrorMsg
echomsg "The command failed"
echohl None
else
echomsg "The command succeeded"
endif
If you've used system() to execute the command, you also have the error message returned by it, and can include that in the notification.

Automatically append current date to file name when saving in Vim

I'm using vim to take notes while reading academic articles. I prefer to have a new text file for each note I've taken, but organizing them becomes tedious.
What I would like to do is set an autocommand to detect if I'm in a certain directory, writing to a newfile and then appened the current date and time to whatever filename I write.
So if I have:
:pwd
/path/to/projects
When I type
:w Notes
I would like vim instead to save the file as
"Notes - <CURRENT DATE - TIME >.txt"
I believe it involves declaring something like the following in my vimrc:
autocmd BufNewFile,BufWrite "/path/to/projects/*" <command involving strftime("%Y-%m-%d_%H-%M")>
But I can't figure out what. Any Ideas? I'm using Vim 7.3 on Debian Linux.
You're very close. I think it's best to rename the file as it is created; messing with the file name during writes makes this more difficult (e.g. what if you re-open an existing note, or just write the buffer again?)
The :file command can be used to rename the current file; the current filename is in the % special identifier. Triggered when a new file is created, this does the job:
autocmd BufNewFile /path/to/projects/* execute 'file' fnameescape(expand('%') . strftime(" - %Y-%m-%d_%H-%M.txt"))
If you don't want to consider the original filename, this becomes even easier:
autocmd BufNewFile /path/to/projects/* execute 'file' fnameescape(strftime("Notes - %Y-%m-%d_%H-%M.txt"))
You may be looking for something along the lines of:
function! SaveWithTS(filename) range
execute "save '" . a:filename . strftime(" - %Y-%m-%d_%H-%M.txt'")
endfunction
command! -nargs=1 SWT call SaveWithTS( <q-args> )
With the above in your .vimrc, executing :SWT Note will save your file as Note - YYYY-MM-DD_HH-MM.txt. This has the disadvantage of not happening automatically, so you have to remember to use :SWT instead of :w the first time your write your file, but it does let you wait until you are ready to save to decide what your filename should be (i.e. you aren't stuck with Note every time).
Edit: The above version of SaveWithTS actually saves to the filename with single quotes around it (bad testing on my part). Below is a version that should fix that and also lets you specify an extension to your file (but will default to .txt)
function! SaveWithTS(filename) range
let l:extension = '.' . fnamemodify( a:filename, ':e' )
if len(l:extension) == 1
let l:extension = '.txt'
endif
let l:filename = escape( fnamemodify(a:filename, ':r') . strftime(" - %Y-%m-%d_%H-%M") . l:extension, ' ' )
execute "write " . l:filename
endfunction

function failed when call it from a command in vim

When I find the word in the current file, I need to first type "/keyword", but I can't see all the matched rows, So I tried to use the following command to do a shortcut, but it doesn't work, could you please help check why it failed?
function! FindCurrentFile(pattern)
echo a:pattern
execute ":vimgrep" . a:pattern . " %"
execute ":cw"
endfunction
command! -nargs=1 Fi call FindCurrentFile(<args>)
By the way, if you just need a quick overview over the matches you can simply use
:g//print
or
:g//p
(You may even leave out the p completely, since :print is the default operation for the :global command.)
When the current buffer has line numbers turned off, the results produced by :g//p can be difficult to take in fast. In that case use :g//# to show the matches with the line numbers.
Another trick that works for keywords is the normal mode command [I. It shows a quick overview of all the instances of the keyword under the cursor in the current buffer. See :h [I.
try to change the line in your function into this:
execute ':vimgrep "' . a:pattern . '" ' . expand("%")
<args> is replace with the command argument as is - that means that if you write:
Fi keyword
the command will run:
call FindCurrentFile(keyword)
which is wrong - because you want to pass the string "keyword", not a variable named keyword.
What you need is <q-args>, which quotes the argument.
BTW, if you wanted more than one argument, you had to use <f-args>, which quotes multiple arguments and separates them with ,.

Resources