How can I run a !<cmd> from a vim script when the path has a space in it on Windows? - vim

I'm attempting to use the :!<cmd> format in vim to execute an external command and put the results in the buffer. If I type :!, path completion is possible and I can complete the path right up to the command I want to execute. This automatically escapes spaces like so:
:!c:\Program\ Files\ (x86)\Microsoft\ Visual\ Studio\ 9.0\Common7\IDE\TF.exe
When I hit enter, I get:
'c:\Program\' is not recognized as an internal or external command
Which I suspect means that vim has not escaped the spaces properly when passing the command to cmd.exe. I've tried all sorts of escaping combinations to make this work but to no avail. The only way I've found to do this is to work out what the DOS8.3 filename is and use that instead of the long path name. However, I don't like this approach since it's going to make my script less portable. Does anyone know if this can be done, or is it a bug in vim?

If you have quoted arguments, not just the exe path, then you may need to do some fancy quoting, like below. The main problem is not the exe path itself, but the arguments. I found this webpage helpful for similar problems myself:
http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
Not sure offhand and don't have time to check, but if you have a quoted argument then sample below may be closer to what you need:
silent! exe 'r!"C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\TF.exe" history /followbranches \^"#\^"'
Also, I wonder whether the quotes around the path may need special treatment since they are around only a portion of the full command. In any case, the quotes \^" work for main quotes in command line and ^" for quotes embedded in other quotes. I have in the past found it useful to experiment with the command at a windows prompt, remembering to test it with the way Vim prepares it, which is with your command prepended by c:\windows\sys32\cmd.exe .
On second thought, I think when I was working with similar problem I never did get to point of solving command with both quoted arguments and quoted exe-path-with-spaces in same command. I expect there's way to do it, but I instead just created a soft link to the exe in path with no spaces. E.g.:
mklink c:\users\myname\myexe c:\program files(x86)\myapp\myexe.exe
After having done that there's no need to quote the exe command itself and quoting the argument with \^" worked fine. I am of course curious about how to quote an exe-with-spaces that also has quoted arguments.
EDIT: I think I found way around my problem with quoting, don't have VS to test with your exact command but here's what I think may work from command line:
cmd /k ""C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\TF.exe" history /followbranches ^"#^""
If that works for you from command line then I think only issue is getting Vim to include the /k switch. (Also, there could be issue with Windows command line "throwing away" the /followbranch switch, because of the forward slash, but maybe not.)
EDIT2: I think the trick for doing it from Vim is just to include the 'cmd /k' as part of the command you're running. You end up with several levels of shells opening, but I don't think that's a problem. For an example, here's on that runs from Vim, with (1) spaces in exe path, (2) quoted argument (the (message .. ) ) and even (3) a quote within a quoted argument (\^"hi\^"). This command opens an Emacs instance and has Emacs print message "hi":
!cmd /k ""c:\program files (x86)\emacs\emacs\bin\emacs.exe" --eval ^"(message \^"hi\^")^""
And yet one more EDIT: Including your own 'cmd /k' does create problems, I think, if you're trying not just to execute the external command, but to read its output back into the Vim buffer. In that case you could redirect the output to a file in the user's home directory and the use :read to insert into the buffer. If there's some way to get Vim's own cmd to use k switch then this would be unnecessary, but if not then at least this provides good workaround.

Enclose the full pathname of the executable in double quotation marks. Do not escape spaces in the pathname.
In your example, some of the backslashes were added to escape spaces, and others are a part of the pathname. You did not provide the original pathname, but I can guess at it. If I guessed right, the command that will work is:
:!"c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\TF.exe"
This works equally well in a script. The equivalent script command is:
silent execute '!"c:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\TF.exe"'
I have tested this in Vim 7.3.346 x86, installed on Windows 7 Pro SP1 x64.

%0 (batch name) %1 (1st parameter) %2 (2nd parameter)
example:
C:\CSW>MyBatchFile.bat "C:\Program files" "C:\CSW\My File.txt"
Not sure if this works with vim but it does work with bash in windows.

You just need to call by adding double quote in it.
I dont have enough idea about Vim script. but while running in command prompt if you will give the complete exe path having space then it will give error like
C:>c:\Program Files\Internet Explorer\iexplore.exe
'c:\Program' is not recognized as an internal or external command,
operable program or batch file.
But It will work if you will surrounded with double qoute.
C:>"c:\Program Files\Internet Explorer\iexplore.exe"
C:>

Related

Alacritty: run a startup script?

I'm on Windows 10 and trying to run a startup script (vcvars64.bat) to setup the MSVC compiler before using the Alacritty prompt.
I have tried the -e switch with the command and also with the alacritty.yml shell: option, but both options open Alacritty, run the command, then exit.
How do I run a script on startup as the first command then continue into Alacritty?
Thanks,
Matic
What I ended up with is:
Specify program: cmd.exe in Alacritty alacritty.yml:
shell:
program: cmd.exe
Create a shortcut to Alacritty.exe and place it eg. in C:\ProgramData\Microsoft\Windows\Start Menu\Programs\ (so that it shows up in Windows search).
In properties for the shortcut, under target, specify:
"C:\Program Files\Alacritty\alacritty.exe" --command "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat >/NUL" && bash.exe
Modify Visual Studio path to whatever you have, and which varsall.bat you want to use.
The tricky part was how sensitive cmd.exe is regarding quotes. Eg., it does not work for me to specify an absolute path to which bash.exe to use, it would fail on the first whitespace in the path no matter how I tried to quote it. So make sure the correct bash.exe is first in your PATH (open plain cmd.exe and run where bash.exe to see order). Another solution is of course to create a shortcut to the bash.exe of your liking to a place without spaces in its path then specify it's absolute path (tested to work).

Escaping characters in bash

I use thunar as a file manager
I want to use "custom actions" on certain files (Thunar --> Edit --> Configure Custom Actions...)
the command I use is: xfce4-terminal -e "md5sum '%F'" --hold
This works fine, except when the file path or file name contains a space. It just won't work as intended because the file can then not be found.
I think this is because the spaces in the file path are not automatically escaped
How do I solve this problem?
Thank you in advance
Seems like Thunar replaces %F with (potentially multiple) correctly quoted paths. Putting this inside quotes will ruin the already perfect quoting. From https://docs.xfce.org/xfce/thunar/custom-actions
Never quote field codes
You need a way to pass an argument list to a command running inside xfce4-terminal. Luckily man xfce4-terminal lists:
-x, --execute Execute the remainder of the command line inside the terminal
Therefore, try
xfce4-terminal --hold -x md5sum %F
You can easily escape a character with by placing a \ in front of it.

vim interpret argument with colon(s) as filename:line:column

Is it possible to configure VIM in a such way that if I type
vim filename:123:89
it opens file filename goes to line 123 and column 89?
If not through VIM maybe with a hack for the shell?
You can install the file-line plugin to open a file to the line and column specified after the filename. (github mirror)
From the Readme on github
When you open a file:line, for instance when coping and pasting from
an error from your compiler vim tries to open a file with a colon in
its name.
Examples:
vim index.html:20
vim app/models/user.rb:1337
With this little script in your plugins folder if the stuff after the colon is a number and a file exists with the name especified before the colon vim will open this file and take you to the line you wished in the first place.
I'm not sure how to skip to the column, but I've wanted the same feature for ages, so I just hacked up the "jump to line" functionality. In your .bashrc, set
VIM=$(which vim)
function vim {
local args
IFS=':' read -a args <<< "$1"
"$VIM" "${args[0]}" +0"${args[1]}"
}
This splits the argument to Vim by :, then constructs a command line of the form
vim <filename> +0<line>
The +0 is a hack to make sure the default line number is zero.
(If you're not using Bash, you can adapt this into a script and put it in your path, or translate it to your favorite shell language. To edit filename:with:colons, use $VIM.)
I've been using the file-line plugin, but it has a few open issues, and breaks some other vim plugins. So I went fishing for a better solution. Here it is:
function vim() {
local first="$1"
case $first in
*:*)
shift
command vim ${first%%:*} +0${first##*:} $#
;;
*)
command vim $#
;;
esac
}
Limitations:
bash only
Only parses first argument, whereas vim +X parses the first file argument. A more complex version could easily be made with proper command line parsing.
Advantages:
doesn't break other vim plugins
you could easily use $EDITOR and use this with emacs for instance.
compared to Fred's answer it doesn't use IFS/read to parse the argument but uses bash parameter expansion.
also sends in the remaining argument, which might occasionally be necessary.

How to start Gvim from Command Prompt?

I tried to start gvim using start command like this
start gvim.exe
But it doesn't work for gvim, although it does work for firefox.exe. My questions are-
How can I start gvim from command prompt?
Why start command doesn't work for gvim.exe?
Are there any additional parameter that I can use when starting gvim from command prompt?
Completely different, so a separate answer:
Actually, -- I just remembered -- Vim isn't normally added to the path variable, it's run through .bat files in C:\Windows.
From another answer on StackOverflow:
When you install gVim: Please make sure Create .bat files for
command line use is checked. It'll create several .bat files in
C:\Windows\:
C:\>cd %windir%
C:\WINDOWS>dir /b *.bat
evim.bat
gview.bat
gvim.bat
gvimdiff.bat
view.bat
vim.bat
vimdiff.bat
vimtutor.bat
This is because gvim.exe is not in your PATH list. If you know which directory gvim.exe resides, add this directory to your PATH list. This can be done by typing the following in an Explorer address bar:
Control Panel\System and Security\System
Then press Advanced system setings, then Environment Variables. The PATH is a list of directories separated by a ;.
Try typing just "gvim" instead of "start gvim.exe". That works for me. Vim isn't in my path environment variable.

Vim: `cd` to path stored in variable

I'm pretty new to vim, and I'm having a hard time understanding some subtleties with vim scripting. Specifically, I'm having trouble working with commands that expect an unquoted-string (is there a name for this?). For example
cd some/unquoted/string/path
The problem is that I'd like to pass a variable, but calling
let pathname = 'some/path'
cd pathname
will try to change the current directory to 'pathname' instead of 'some/path'. One way around this is to use
let cmd = 'cd ' . pathname
execute cmd
but this seems a bit roundabout. This StackOverflow question actually uses cd with a variable, but it doesn't work on my system ("a:path" is treated as the path as described above).
I'm using cd as a specific example, but this behavior isn't unique to cd; for example, the edit command also behaves this way. (Is there a name for this type of command?)
TL;DR: use execute 'cd' fnameescape(pathname)
Explanation: Lots of basic commands that take filenames as an argument support backtick syntax:
command `shell command`
or
command `=vim_expression`
so your example may be written as
cd `=pathname`
if you are running this in a controlled environment. You must not use this variant in plugins because a) there is &wildignore setting that may step in your way: set wildignore=*|cd =pathname will make cd fail regardless of what is stored in the pathname and b) if pathname contains newlines it will be split into two or more directories. Thus what you should use for any piece of code you intend to share is
execute 'cd' fnameescape(pathname)
Note that you must not use execute "cd" pathname because it does not care about special characters in pathname (for example, space).
The basic commands in Vim never do any processing of variables (how would it know that you didn't mean to change to the pathname directory instead of the some/path one?). You don't have to be quite as roundabout as you suggested, you can just do:
exe 'cd' pathname
Note that exe concatenates arguments with a space automatically, so you don't have to do:
exe 'cd ' . pathname
A lot time ago I wrote this plugin (function FixPathName() in order to solve this kind of issues. Now vim has some new functions like shellescape() when the path need to be used with external commands.

Resources