How to execute a normal mode command in a vim function? - function

I am writing a vim function to insert some text in a c++ file, please see the following function:
function! InsertDebugInfo()
let i = line('.')
call append(i+1, '#ifdef DEBUG')
call append(i+2, 'std::cout << "" << std::endl;')
call append(i+3, '#endif')
call append(i+4, '')
call cursor(i+3, 0)
endfunction
In normal mode, I use == to re-indent one code line. My question is
how to call == in the above function. Furthermore, how to execute the
command such as 2f" which move the cursor to the second ".

To indent, you can just use
normal ==
To find also you can use
normal 2f"
or even shorter
norm <whatever you do in normal mode>
Now you might be getting what I'm trying to say.
If not, read documentation :h normal.

Try this in your function:
execute 'normal 2f"'

Related

Not able to get entire text of current buffer in vim

I am trying to get entire text of current buffer. I believe it is represented by '%' (see answer by SnoringFrog at https://vi.stackexchange.com/questions/2319/is-there-a-text-object-for-the-entire-buffer). However, following function gives an error:
function Check ()
echo %
endfunction
I call it with following command:
:call Check()
The error is:
Error detected while processing function Check:
line 1:
E15: Invalid expression: %
E15: Invalid expression: %
Where is the problem and how can it be solved?
Depending on the context, % can be a shortcut for the 1,$ range or a placeholder for the filename associated with the current buffer.
In the first case (the one in your link), it's not meant to be echoed at all which would be completely pointless.
In the second case, it needs to be expanded with expand('%') if you want to use it in a function.
Anyway, none of that matters because % is not what you want at all. What you want is :help getline():
function Check ()
echo getline(1,'$')
endfunction

printing the output of shell command from python subprocess

I am running a shell script which emits lots of line while executing...they are just status output rather than the actual output....
I want them to be displayed on a JTextArea. I am working on jython. The piece of my code looks like:
self.console=JTextArea(20,80)
cmd = "/Users/name/galaxy-dist/run.sh"
p = subprocess.Popen(cmd, stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True)
self.console.append(p.stdout.read())
This will wait until the command finishes and prints the output. But I want to show the realtime out put to mimic the console. Anybody have the idea ?
You're making things more complicated than they need to be. The Popen docs state the following about the stream arguments:
With the default settings of None, no redirection will occur; the child’s file handles will be inherited from the parent. [my emphasis]
Therefore, if you want the subprocess' output to go to your stdout, simply leave those arguments blank:
subprocess.Popen(cmd, shell=True)
In fact, you aren't using any of the more advanced features of the Popen constructor, and this particular example doesn't need any parsing by the shell, so you can simplify it further with the subprocess.call() function:
subprocess.call(cmd)
If you still want the return code, simply set a variable equal to this call:
return_code = subprocess.call(cmd)

How to concatenate several lines in vim

I am using a the vim-screen plugin that enable me to write scripts , start an interpreter in the same window and send lines the the interpreter. Problem is that the interpreter do not accept statements written on several lines.
exemple:
This will work f:{[x] y:y+1; Z:y+1; :Z; };
But this won't
f:{[x] y:y+1;
Z:y+1;
:Z;
};
How can I write a vim function that I could call to reshape the lines in order to be sent to the interpreter?
EDIT:
I had no success in making this function, I would like to create a function that would, from a input like this (that would be visually selected)
F:{[a;b;r]
//ccc1
aaa1;
aaa2;
//ccc2
aaa3;
};
output something like this F:{[a;b;r] aaa1; aaa2; aaa3; };
So I created a bounty
If you want to actually modify the buffer, J / :join do that. If you just want to join the lines that are sent to the interpreter (but keep them split in the buffer), you can retrieve the selected lines with getline(), and then join() them. Here's an example command:
:command! -range Invoke echomsg join(getline(<line1>,<line2>), '')
Edit
Based on that, you can "massage" the List of lines returned by getline(). E.g. to ignore the commented lines:
:command! -range Invoke echomsg join(filter(getline(<line1>,<line2>), 'v:val !~# "^\\s*//"'), '')
Additionally strip leading whitespace (this becomes unwieldy in a single line; better use a function now):
:command! -range Invoke echomsg join(map(filter(getline(<line1>,<line2>), 'v:val !~# "^\\s*//"'), 'substitute(v:val, "^\\s\\+", " ", "g")'), '')
Standard continuation character in vimscript scripts is backslash in the beginning of the next line. So, this
f:{[x] y:y+1;
\ Z:y+1;
\ :Z;
\ };
should work.

Vim function to copy a code function to clipboard

I want to have keyboard shortcut in Vim to copy a whole function from a Powershell file to the Windows clipboard. Here is the command for it:
1) va{Vok"*y - visual mode, select {} block, visual line mode, go to selection top, include header line, yank to Windows clipboard.
But it would work only for functions without an inner {} block. Here is a valid workaround for it:
2) va{a{a{a{a{a{a{Vok"*y - the same as (1), but selecting {} block is done multiple times - would work for code blocks that have 7 inner {} braces.
But the thing is - the (1) command works fine when called from a vim function, but (2) misbehaves and selects wrong code block when called from a vim function:
function! CopyCodeBlockToClipboard ()
let cursor_pos = getpos('.')
execute "normal" 'va{a{a{a{a{a{a{Vok"*y'
call setpos('.', cursor_pos)
endfunction
" Copy code block to clipboard
map <C-q> :call CopyCodeBlockToClipboard()<CR>
What am I doing wrong here in the CopyCodeBlockToClipboard?
The (2) command works as expected when executed directly in vim.
UPDATE:
I've noticed that:
if there are more a{ then the included blocks in the function
then vim wouldn't execute V
Looks like vim handles errors differently here. Extra a{ produces some error and regular command execution just ignores it. But execution from withing a function via :normal fails and wouldn't call V (or probably any command that follows the error).
Any workaround for this?
Try this function
function! CopyCodeBlockToClipboard()
let cursor_pos = getpos('.')
let i = 1
let done = 0
while !done
call setpos('.', cursor_pos)
execute "normal" 'v' . i . 'aBVok"*y'
if mode() =~ "^[vV]"
let done = 1
else
let i = i + 1
endif
endwhile
execute "normal \<ESC>"
call setpos('.', cursor_pos)
endfunction
This preforms a execute command to select blocks until it fails to select a block larger block. ([count]aB selects [count] blocks) It seems when the selection fails we end up in visual mode. So we can use mode() to check this.
When this function exits you should be in normal mode and the cursor should be restored to where you started. And the function will be in the * register.
This macro should come close to what you want to achieve:
?Function<CR> jump to first Function before the cursor position
v enter visual mode
/{<CR> extend it to next {
% extend it to the closing }
"*y yank into the system clipboard

Using an argument of a function in normal mode in Vim?

I have a Vimscript function defined like this:
function Cs(a, b)
normal a:a|"cylr a:b|x"cP
endfunction
However, the intended action (do some crazy stuff with the arguments a and b in normal mode) doesn't work, instead it takes the first "a" as "append" and writes the rest of the line to the file.
How can I use arguments on a "normal" statement in Vimscript? I found no way to do this.
You need to build up a string with the parameters in and execute it with the :exec statement.
e.g. something like this:
function Cs(a, b)
exec "normal " a ":" a "|\"cylr " a ":" b "|x\"cP"
endfunction