1

I am messing around with .vimrc and I had this idea to have function like follow:

function Fill_line ()
       execute "! printf '=%.0s' {1..10}"
endfunction

my output is:

Hello =test.cpp.0s

I want it to be:

==========

I have tried this as well:

function Fill_line ()
       execute "! printf '=\%.0s' {1..10}"
endfunction

My problem is how do I escape % character so it does not replace it with file name. keep in mind this is simplified example of otherwise complex function.

  • 1
    try with 2 backslashes – mosvy Jan 27 at 23:27
  • 1
    Well there is an entire Stack Exchange site devoted to vi, and it has had questions like vi.stackexchange.com/questions/9910 for some time. – JdeBP Jan 28 at 0:10
  • 1
    @JdeBP FWIW that vi.stackexchange.com link has no answer for this question. It's simply suggesting to use \%, which the OP already did in the 2nd example and which did not work for the reason I've explained in my answer. Find another one. – mosvy Jan 28 at 0:39
  • 1
    I didn't say that it was this exact question, just showed that it had questions in this very vein for some years. Note that vi.stackexchange.com/questions/10851 has better answers than yours. (-: – JdeBP Jan 28 at 2:04
  • 1
    @JdeBP: +1, using shellescape() is actually the officially recommended way to do it. – lcd047 Jan 28 at 8:28
2

You should either use two backslashes or use single quotes:

execute "! printf '=\\%.0s' {1..10}"

execute '! printf "=\%.0s" {1..10}'

You need that because, when parsing double quoted strings ("..."), vim will remove any backslashes that do not start an escape it knows about (eg. \n or \x0a), so the string being passed to the execute command will end up being ! printf '=%.0s' {1..10}, and the % will be replaced with the current file name.

1

As an alternative, consider maps. I have this map that underlines the current line:

map <Leader>= "ayy"ap:s/./=/g<CR>:nohlsearch<CR>

My mapleader is =, so I can underline the current line with == in normal mode.

1

As it is unclear what you are trying to do:

  1. Fill the current line with = up to column 80

    map _= :execute 'normal A' . repeat("=", (80-col("$")+1))<cr>
    
  2. Underline the current line:

    map _= :co.<cr>Vr=
    
  3. Add a separator (80 chars)

    map _= :call append(line('.'), repeat("=", 80))<cr>
    
  • My problem was escaping %, I do already have something like this in place. My code in original post is extremely simplified. – 0x476f72616e Jan 29 at 14:30
1

As others have already correctly answered, the % needs to be escaped so that Vim doesn't replace it with the current filename (as per :help cmdline-special), and inside a double-quoted string the backslash needs to be doubled.

However, Vim offers a :help shellescape() function that does the work for you (and considers all special characters!):

execute "! printf " . shellescape("=%.0s",1) . " {1..10}"

Here, you need to escape each argument separately; for the bare printf this isn't necessary, and the {1..10} must not be quoted in the shell to get expanded.

Note that there's no need to shell out solely for printf; Vim has printf() built-in.

  • % needs to be escaped so that Vim doesn't replace it I knew this, but I did not know how :). I wish I could select both of these answers. Since @mosvy works as well in given situation. – 0x476f72616e Jan 29 at 14:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.