vim line number does weird things on lines starting with an 8 - vim

I have some commands set up that run the test under my current cursor position. using the command rails test <filename>:<linenumber>. I execute this command through
exec '!rails test %:'.line('.') which works fine in most situations. However, for some reason when the line number starts with an 8 it behaves weirdly.
when testing with the command :exec '!echo "%:'.line('.').'"' i get the following outputs
line 7 -> test.txt:7
line 8 -> test.txt
line 9 -> test.txt:9
line 79 -> test.txt:79
line 80 -> test.txt0
line 89 -> test.txt9
line 90 -> test.txt:90
This pattern repeats for the 800s as well.
Am i missing something obvious?
EDIT: As someone in the comments suggested i posted my question on the vi-stackexchange.

This command:
:exec '!echo "%:'.line('.').'"'
is handled in several steps from the inside to the outside:
line('.') is evaluated to 8,
'!echo "%:'.'8'.'"' is evaluated to '!echo "%:8"'
'!echo "%:8"' is parsed by Vim before being sent to :execute, in order to expand various special characters as explained in :help cmdline-special. The "problem" (more like "powerful feature" if you ask me) is that the expansion takes into account :help filename-modifiers and :8 is a legit filename modifier:
:8 Converts the path to 8.3 short format (currently only on MS-Windows). Will act on as much of a path that is an existing path.
After expansion, '!echo "%:8"' looks like '!echo "test.txt"' because no conversion was performed. If the number is 80, you get test.txt0 because the file name is left as-is and then there's that trailing 0. And so on for test.txt00, etc.
!echo "test.txt" (or !echo "test.txt0", or !echo "test.txt00", etc.) is finally executed.
In order to avoid that unwanted expansion, you should evaluate the file name and the line number separately:
'!rails test '.expand('%').':'.line('.')

Related

VI read line not giving desired output

I have a file called test, I open it using vi as such:
vi test
Now I want to insert a line through a shell command, for simplicity I use a printf:
:r! printf %s hello
However the line that is entered is
tests
i.e. the name of the file with a s appended.
If I enter the same command in terminal directly, it works fine.
What I want to do is ultimately be able to encode a string in base64 and enter it on the same line as where my cursor is in vi, so that I won't have to copy the string in a separate terminal, encode it, and copy it back into vi. How can I do this? What am I doing wrong?
The first stage of processing a command line in vim is expanding it. % is expanded to the name of the current file — test in your case. %s is expanded to tests.
To avoid expanding protect the special character with a backslash:
:r! printf \%s hello

why is vim's delete command so slow

I have a file that contains about 5000 lines and I want to delete all lines that have 'some_string' so I first search for /some_string then I execute :g//d. This takes over 5 minutes to delete ~90% of the lines. What gives?
In comparison, if I run sed -i '/some_string/d' some_file it takes 46ms.
Add an underscore to your command.
I experienced a similar problem and it turned out to be each line being copied to my system clipboard. By adding a _, you tell vim to use the blackhole register.
:g//d_
The help gives the following syntax for :d
:[range]d[elete] [x] Delete [range] lines (default: current line) [into register x].

How to write a string in a file using vim editor from command line

I want to create a new file using vi editor from command line and add a string to it multiple times say 100. Using vi -S command.script file.txt is supposed to do the trick where a new file file.txt will be created and the commands given in command.script file can write to this file. My command.script contains
:%100a hello world
:wq
But its's not working, what I am doing wrong?
If you interactively execute :%100a hello world in a Vim session, you'll get E488: Trailing characters. Looking up :help :a:
:{range}a[ppend][!] Insert several lines of text below the specified
line. If the {range} is missing, the text will be
inserted after the current line. [...]
These two commands will keep on asking for lines, until you type a line
containing only a ".".
tells you that the text has to be put in following lines (and concluded by a line with only a . character).
Or did you mean to use the normal mode a command? (That one takes a [count] to multiply; your %100 range is wrong, too!)
You can also use the low-level function append(), repeating the string with repeat().
summary
$append
hello world
[...]
hello world
.
execute "$normal! 100ahello world\<CR>"
" Easier with o instead of a:
$normal! 100ohello world
call append('$', repeat(['hello world'], 100))
non-Vim alternatives
But honestly, if that is your real use case (and not just a simplified toy example), you don't need Vim at all for this. Here's one example for the Bash shell:
$ for i in $(seq 100); do echo "hello world" >> file.txt; done

what does the number 1 in the shellescape function mean in vim?

A vim command confuses me. I have read and re-read :help shellescape() several times. I still don't understand the meaning of the number 1 in shellescape(expand('%:p'), 1).
Here's the full command I'm trying to understand:
:nnoremap <F4> :exe ':silent !"c:\Program Files\Mozilla Firefox\firefox.exe"'shellescape(expand('%:p'), 1)<CR>
Let's break down this long command piece by piece.
the command is to map an exe command into F4 in the whole.
:exe is to execute some command.
:silent ! is to execute a shell command silently
"c:\Program Files\Mozilla Firefox\firefox.exe" can call my firefox program.
shellescape(), there are blanks to be escaped.
expand('%:p') can get current file name in full expression that is path + filename.
What does this excerpt from the help page mean?
With a |non-zero-arg| {special} and 'shell' containing "csh" in the tail it's
escaped a second time.
Is there some meaning such the same as 1 or 2 in s/(ha.*)(world)/\2\1/g?
please take a simple example in detail.
And i have two questions related to the topic.
1.In which way i can get how many type of shells in my gvim?
2.In which situation can i change 1 into 2 in shellescape()?
:nnoremap <F4> :exe ':silent !"c:\Program Files\Mozilla Firefox\firefox.exe"'shellescape(expand('%:p'), 2)<CR>
There are basically two different uses for shellescape(); one is the Vimscript system() function, the other the :! Ex command. While most escaping needs are identical in both uses (e.g. to deal with whitespace, arguments must be enclosed in quotes), the :! command requires some additional escaping, because on the command-line, Vim assigns special meaning to symbols like % (replacing it with the current file name). This does not happen for system().
Therefore, to tell shellescape() which escaping mode to use, it has the additional {special} argument; if you pass 1 (or any other value that evaluates to "true"), the additional characters are escaped, too.
TL;DR: Pass 1 for :! commands, 0 or omit the argument for use with system().
From the help for shellescape():
shellescape({string} [, {special}]) shellescape()
Escape {string} for use as a shell command argument.
On MS-Windows and MS-DOS, when 'shellslash' is not set, it
will enclose {string} in double quotes and double all double
quotes within {string}.
For other systems, it will enclose {string} in single quotes
and replace all "'" with "'\''".
When the {special} argument is present and it's a non-zero
Number or a non-empty String (non-zero-arg), then special
items such as "!", "%", "#" and "<cword>" will be preceded by
a backslash. This backslash will be removed again by the :!
command.
The 1 in your example simply tells shellescape() to escape special characters with a backslash. If you were to have (say) a ! in the path returned by expand(), it’d be replaced with \!.
shell is an option:
'shell' 'sh' E91
'shell' 'sh' string (default $SHELL or "sh",
MS-DOS and Win32: "command.com" or
"cmd.exe", OS/2: "cmd")
global
Name of the shell to use for ! and :! commands.
— :help 'shell'
“With a non-zero-arg {special} and 'shell' containing "csh" in the tail it's escaped a second time” means that if, as in your example, shellescape() is given a non-zero argument for special (your example has a 1), it will check shell for that "csh", and if it finds it (if your shell is set to something containing csh) it will double-escape it.
EDIT to specifically answer two questions added to (edited) original post:
You can get your shell setting (referred to in the shellescape() help quote) using :echo &shell.
2 is a Number and is non-zero. You should therefore be able to substitute 2 for the 1 in your example and get the same result.

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