vim expanded makeprg variable - vim

I use the :set makeprg functionality to set different make behaviour depending on files. One feature of this is that I can use % and %< in order to refer to the file in the active buffer, as well as $ for environment variables.
I'd like to echo the expanded makeprg variable, but I can't seem to achieve this.
For example, suppose I have :set makeprg=build\ %, and I'm working on file Foo.txt.
I would expect the output of echoing an expanded makeprg to be:
build Foo.txt
However, we have the following result when echoing the &makeprg variable:
:echo(&makeprg)
build\ %
The solution probably involves using expand(), except that this would involve parsing the &makeprg for escaped symbols and dealing with $ appropriately for environment variables. Is there a solution to this that I'm missing?

Why would you need this? For troubleshooting, I would probably just append echo to 'makeprg' (that's a trailing space after \):
:setl makeprg^=echo\
But the following should do what you had in mind. The trick is to split the 'makeprg' string on spaces, and process each word individually:
:echo join(map(split(&makeprg), 'expand(v:val)'))

A bit closer to the truth:
join(map(split(mystring, '\ze[<%#]'), 'expand(v:val)'), '').

Related

Make vim understand tcl script environment variables ('gf' command)

I often use gf in vim to open files under cursor. Often these file paths use environment variables but when in .tcl script files vim is unable to use the environment variable.
This works for gf:
$tcl_lib/myfile.tcl
These do NOT work for gf:
$env(tcl_lib)/myfile.tcl
$::env(tcl_lib)/myfile.tcl
These are some of the things I have tried:
:set isfname=#,48-57,/,.,-,_,+,,,#,$,%,~,=,{,},(,)
:set isfname=#,48-57,/,.,-,_,+,,,#,$,%,~,=,{,},40-41
:set includeexpr=substitute(v:fname,'\$env(\([^)]\+\))','\$\1','')
Is there a way to make vim understand the syntax for environment variables in tcl scripts (specifically for the 'gf' command)?
There are a few techniques:
Set 'path' & 'includeexpr'
In theory you can just add $tcl_lib to path. e.g. set path=.,$tcl_lib,,. However, any filename starting with / will fail. This can be remedied by removing the starting /.
Add to ~/.vim/after/ftplugin/tcl.vim:
set path=.,$tcl_lib,,
let &l:includeexpr="substitute(v:fname, '^/', '', 'g')"
Reading Environmental variables via 'includeexpr'
Can use a substitution to expand environment variables
let l:includeexpr = "substitute(v:fname, '$\\%(::\\)\\=env(\\([^)]*\\))', '\\=expand(\"$\".submatch(1))', 'g')"
This uses a sub-replace-expression (See :h sub-replace-expression) to use expand() to get the environmental variable.
This might require you to change 'isfname' to allow more characters tto be a part of a filename looking string.
Just map gf and friends
Make buffer-local mappings for gf, <c-w>f, etc which are specific to your language and check certain paths. This completely side-steps many of Vim's built in methods so it should be used as a last resort.
Finally got back to this and was able to solve it in a pretty good way. Add the following tcl.vim file to your ~/.vim/ftplugin and your "gf" should work!
https://github.com/stephenmm/dotfiles/blob/master/vim/ftplugin/tcl.vim
" Add charecters to possible filename types so vim will recognize:
" $::env(THIS)/as/a/file.tcl
set isfname+={,},(,),:
" Turn the string into something vim knows as a filename:
" $::env(THIS)/as/a/file.tcl => ${THIS}/as/a/file.tcl
function! TclGfIncludeExpr(fname)
if a:fname =~? '\$\(::\)\?env([^)]\+)'
return substitute(a:fname, '\$\(::\)\?env(\([^)]\+\))', '${\2}', 'g')
endif
return a:fname
endfunction
" Tie the function to includeexpr
set includeexpr=TclGfIncludeExpr(v:fname)
Adding below 2 lines in ~/.vimrc will work for me.
set isfname+={,},(,),:
let &l:includeexpr = "substitute(v:fname,'$\\%(::\\)\\=env(\\([^)]*\\))','\\=expand(\"$\".submatch(1))', 'g')"

vimrc how to invoke unix find?

i want to set the tags variable to the set of all gotags files i generated in specific folder(s) using exuberant Ctags. (gotags is nothing but the tags file renamed).
i put following lines in my .vimrc file.
set tags+=/usr/local/go/src/gotags
set tags+=`find /home/vimal/gowork/src -name gotags`
but it doesnt work and i get the following error
$ vi ~/.vimrc
Error detected while processing /home/vimal/.vimrc:
line 157:
E518: Unknown option: /home/vimal/gowork/src
Press ENTER or type command to continue
how can i fix the error and set the tags variable with the value: list of all the gotags files under one directory tree.
Inventing new syntax tends not to work that well in practice. Use system() to run external commands from Vim, not backticks. Also set in Vim is weird, it doesn't evaluate RHS the way you expect. Most of the time it's a lot simpler to use let &option = ... instead of set option=....
Anyway, to answer your question, you don't need to run find(1) for that, plain Vim functions are enough for what you want:
let &tags = join(extend([&tags, '/usr/local/go/src/gotags'],
\ findfile('gotags', '/home/vimal/gowork/src', -1)), ',')

Colorizing the output of :make, :grep, etc., in Vim

When building my application using the :make command in Vim, the output is not colorized. I have configured the makefile to use clang as the C compiler, and when running make outside of Vim or when running :!make, clang's output is colorized. :set makeprg returns makeprg=make, just for reference.
I have the same issue with grep: when running :grep, the output is not colorized; when running :!grep, it is. I have tried using the --color option with :grep, to no avail. :set grepprg returns grepprg=grep -n $* /dev/null.
I've read through VIM Unix commands printed in color and also How to color my vimgrep result patterns. The former seems to have the opposite problem (i.e. :!command output not colorized); the latter doesn't have any alternative to dropping down to the shell, which I don't feel is a "correct" fix for the issue.
The problem is that when Vim runs other commands via :make or :grep, those commands don't get a terminal for their standard output -- in the sense that for them isatty(STDOUT_FILENO) is false -- because Vim is capturing the output on its way to being displayed on the terminal. On the other hand, when you use :!make or :!grep, standard output is just going to the terminal.
Clang by default and grep --color=auto (which is probably how you have it aliased) use the terminalness of stdout to decide whether to colourise their output. This is convenient in that you get colourful output on your terminal but capture just the text when you redirect output to a file -- all without needing to add extra command line options.
So what you want to do is override these commands' usual smarts so that they always colourise their output.
For grep, you can use --color=always when it is run via :grep within Vim:
:set grepprg=grep\ --color=always\ -n\ $*\ /dev/null
and depending on your colour settings and version of grep this will work well enough.
For clang, you can change your Makefile to use clang -fcolor-diagnostics so as to force colourisation or more flexibly add an extra variable to $(CC) that will be overridden when run via :make within Vim:
:set makeprg=make\ EXTRA_CFLAGS=-fcolor-diagnostic
However (at least with clang 3.0 and vim 7.3) you will find that clang's style of colourisation prevents Vim from picking out filenames and line numbers from the diagnostics, so doing this wrecks the advantage of using :make rather than :!make.
You may be able to teach Vim to pick out the filenames etc from the surrounding ANSI escape sequences that do the colourisation by adding more entries to Vim's errorformat option to match the colourised clang-style diagnostics. (And similarly with grepformat if your grep colourisation colours the filenames or linenumbers.)
When you run :grep or :make (as opposed to :!grep or :!make),
the output is not only shown in the terminal,
but also sent to the quick-fix window, from which it is processed.
You can access the quick fix windo using the vim-command :copen.
The quick fix window is essentially a text file that is opened in read-only mode.
Like in any other text file, colors are not supported in the quick fix file.
Instead, they are represented with escape characters like [01;34m.
Therefore, producing colorized output from make (or grep) will
mess up the output as it is shown in the quick-fix window, even if you can get vim to process it,
and send the cursor to the selected error/warning/find message.
The question whether the output is colorized now becomes a little subtle: I suggest that the
terminal output should remain uncolored, but that the quick-fix output should be colorized.
The color scheme in the quick fix window is not defined by any color-indications in the file itself, but in the syntax highlighting
of the quick fix window, defined in the file qf.vim (/usr/share/vim/vim81/syntax/qf.vim on my computer).
The color scheme defined in qf.vim does not add much color to the quick fix window, but the syntax hightlighting
scheme may be extended by creating the file ~/.vim/syntax/after/qf.vim. I use cmake in combination with the
gnu and/or the intel compilers, and get nice-looking results with the following contents for ~/.vim/syntax/after/qf.vim:
syn match qBuilt "Built target *" nextgroup=qTarget
syn match qTarget ".*$" contained
syn match qEnteringLeaving ": \(Entering\|Leaving\) directory *" nextgroup=qdSeparator
syn match qdSeparator "'" nextgroup=qdName contained
syn match qdName "[^']*" contained
syn match qbProgress "\[ *[0-9]*%\]"
syn match qBuild "Building .* object"
syn match qWarn "warning\( *#[0-9]*\|\):"
syn match qError "error\( *#[0-9]*\|\):"
syn match qRemark "remark\( *#[0-9]*\|\):"
hi def link qTarget Constant
hi def link qError Error
hi def link qWarn Error
hi def link qRemark WarningMsg
hi def link qEnteringLeaving Keyword
hi def link qBuild Keyword
hi def link qBuilt Keyword
hi def link qdName Include
hi def link qbProgress Special

Why the -b(binary) option doesn't work in vim?

As vim doc said, I can use the -b option to open a binary file.
-b Binary mode. File I/O will only recognize <NL> to separate
lines. The 'expandtab' option will be reset. The 'textwidth'
option is set to 0. 'modeline' is reset. The 'binary' option
is set. This is done after reading the vimrc/exrc files but
before reading any file in the arglist. See also
|edit-binary|. {not in Vi}
I use this command to open vim:
$ vim --cmd 'set et' -u NONE -b
I type this command to view options:
:set et? bin?
expandtab
binary
The et(expandtab) option wasn't reset. Why?
Thanks for your help!
Well the issue is, simply, that --cmd -c or +cmd arguments are executed after processing the other flags. This makes sense, as it would not effectively do anything otherwise.
:verbose set et?
would tell you exactly that. In case you need a workaround for your particular sample vim +'set binary' (unlikely since et != binary)
You are right on the docs for --cmd. So it comes down to the order in which command line flags are interpreted, which is basically 'undefined'. Although
This is done after reading the vimrc/exrc files but before reading any file in the arglist
could be taken to imply 'before processing other command line arguments'.
Note The '+' commands essentially go with specific files and are (AFAICT) processed in the order in which they appear, even when intermixed with filename arguments.

Vim with Powershell

I'm using gvim on Windows.
In my _vimrc I've added:
set shell=powershell.exe
set shellcmdflag=-c
set shellpipe=>
set shellredir=>
function! Test()
echo system("dir -name")
endfunction
command! -nargs=0 Test :call Test()
If I execute this function (:Test) I see nonsense characters (non number/letter ASCII characters).
If I use cmd as the shell, it works (without the -name), so the problem seems to be with getting output from powershell into vim.
Interestingly, this works great:
:!dir -name
As does this:
:r !dir -name
UPDATE: confirming behavior mentioned by David
If you execute the set commands mentioned above in the _vimrc, :Test outputs nonsense. However, if you execute them directly in vim instead of in the _vimrc, :Test works as expected.
Also, I've tried using iconv in case it was an encoding problem:
:echo iconv( system("dir -name"), "unicode", &enc )
But this didn't make any difference. I could be using the wrong encoding types though.
Anyone know how to make this work?
It is a bit of a hack, but the following works in Vim 7.2. Notice, I am running Powershell within a CMD session.
if has("win32")
set shell=cmd.exe
set shellcmdflag=/c\ powershell.exe\ -NoLogo\ -NoProfile\ -NonInteractive\ -ExecutionPolicy\ RemoteSigned
set shellpipe=|
set shellredir=>
endif
function! Test()
echo system("dir -name")
endfunction
Tested with the following...
:!dir -name
:call Test()
I ran into a similar problem described by many here.
Specifically, calling
:set shell=powershell
manually from within vim would cause powershell to work fine, but as soon as I added:
set shell=powershell
to my vimrc file I would get the error "Unable to open temp file .... "
The problem is that by default when shell is modified, vim automatically sets shellxquote to " which means that shell commands will look like the following:
powershell -c "cmd > tmpfile"
Where as this command needs to look like this, in order for vim to read the temp file:
powershell -c "cmd" > tmpfile
Setting shellquote to " in my vimrc file and unsetting shellxquote (i.e. setting it to a blank space) seem to fix all my problems:
set shell=powershell
set shellcmdflag=-c
set shellquote=\"
set shellxquote=
I've also tried taking this further and scripting vim a bit using the system() call:
system() with powershell in vim
I suspect that the problem is that Powershell uses the native String encoding for .NET, which is UTF-16 plus a byte-order-mark.
When it's piping objects between commands it's not a problem. It's a total PITA for external programs though.
You can pipe the output through out-file, which does support changing the encoding, but still formats the output for the terminal that it's in by default (arrgh!), so things like "Get-Process" will truncate with ellipses, etc. You can specify the width of the virtual terminal that Out-File uses though.
Not sure how useful this information is, but it does illuminate the problem a bit more.
Try replacing
"dir \*vim\*"
with
" -command { dir \*vim\* }"
EDIT: Try using cmd.exe as the shell and put "powershell.exe" before "-command"
Interesting question - here is something else to add to the confusion. Without making any changes to my .vimrc file, if I then run the following commands in gvim:
:set shell=powershell.exe
:set shellcmdflag=-noprofile
:echo system("dir -name")
It behaves as expected!
If I make the same changes to my .vimrc file, though (the shell and shellcmdflag options), running :echo system("dir -name") returns the nonsense characters!
The initial example code works fine for me when I plop it in vimrc.
So now I'm trying to figure out what in my vimrc is making it function. Possibly:
set encoding=utf8
Edit: Yep, that appears to do it. You probably want to have VIM defaulting to unicode anyway, these days...
None of the answers on this page were working for me until I found this hint from https://github.com/dougireton/mirror_pond/blob/master/vimrc - set shellxquote= [space character] was the missing piece.
if has("win32") || has("gui_win32")
if executable("PowerShell")
" Set PowerShell as the shell for running external ! commands
" http://stackoverflow.com/questions/7605917/system-with-powershell-in-vim
set shell=PowerShell
set shellcmdflag=-ExecutionPolicy\ RemoteSigned\ -Command
set shellquote=\"
" shellxquote must be a literal space character.
set shellxquote=
endif
endif
Combining the answers in this and the related thread, add the following to your $profile assuming you installed diffutils from chocolatey:
Remove-Item Alias:diff -force
And add the following to your ~/.vimrc:
if (has('win32') || has('gui_win32')) && executable('pwsh')
set shell=pwsh
set shellcmdflag=\ -ExecutionPolicy\ RemoteSigned\ -NoProfile\ -Nologo\ -NonInteractive\ -Command
endif
make sure shellcmdflag is exactly as shown
All credit for these solutions to their respective contributors, this is merely an aggregation post.
I propose an hackish solution. It doesn't really solve the problem, but it get the job done somehow.
This Vim plugin automate the creation of a temporary script file, powershell call through cmd.exe and paste of the result. It's not as nice as a proper powershell handling by vim, but it works.
Try instead
set shellcmdflag=\ -c
Explanation:
Vim uses tempname() to generate a temp file path that system() reads.
If &shell contains 'sh' and &shellcmdflag starts with '-'
then tempname() generates a temp file path with forward slashes.
Thus, if
set shell=powershell
set shellcmdflag=-c
then Vim will try to read a temp file with forward slashes that
cannot be found.
A remedy is to set instead
set shellcmdflag=\ -c
that is, add a whitespace to &shellcmdflag so that the first character
is no longer '-' and tempname() produces a temp file path with backward
slashes that can be found by system().
I remarked on the vim_dev mailing list ( https://groups.google.com/forum/#!topic/vim_dev/vTR05EZyfE0 ) that this deserves better documentation.
actf answer works for me, but because of Powershell built in DIFF (which is different from the Linux one) you must add this line to your Powershell profile to have diff working again in VIM:
Remove-Item Alias:diff -force
I'm running GVim v8.2 (Windows).
Using the fullpath to the executable works for me:
set shell=C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe
I don't use VIM but Powershell's default output is Unicode. Notepad can read unicode, you could use it to see if you are getting the output you expect.

Resources