So far I have only found the :%! <cmd> way to pipe the current buffer through an external command.
But I am wondering if there is a way to have two or three viewports open and reference their respective buffers, for both input parameters and results of the external command.
Simple example:
I would like to have an open viewport with a file, a viewport with a awk (or jq or anything) script, and a third "result" viewport.
Then I would like to run awk (or jq, etc.) to use the script from the second viewport, running on the file in the first viewport and write the result to the third viewport.
Similar to what vim-jqplay does (unfortunately it is not compatible with nvim)
Thank you!
if there is a way to have two or three viewports open
In Vim slang it's called "windows". Please, don't use inappropriate terms anymore.
So far I have only found the :%! way to pipe the current buffer through an external command.
Actually, there are also :r !{cmd} (read from cmd, i.e. redirect command's stdout into the buffer) and :w !{cmd} (write to cmd, i.e. redirect command's stdin to read from the buffer).
Then I would like to run awk (or jq, etc.) to use the script from the second viewport, running on the file in the first viewport and write the result to the third viewport.
Well, you realize that you can't have two stdin redirections at the same time, do you? In principle, you can do something like
call appendbufline(3, '$', systemlist('gawk -f '..bufname(1), 2))
Here 1 is a script buffer number, 2 is datafile bufnr, and 3 is a target bufnr. But note that buffer 1 is passed simply as a filename (no redirection), so it must be saved before the command to run.
But I don't think it's so important to redirect stdin at all, as you can pass datafile name too. So, assuming the target buffer (3) is active, you can do this
:r !gawk -f #1 #2
Of course, both script (buffer 1) and data (buffer 2) must be saved to disk before running this.
Related
Often when I run a command that writes to stdout, and that command fails, I have to scroll up (using uncomfortable key-bindings) looking for the place where I pressed Enter, to see what the first error was (out of hundreds others, across many screens of text). This is both annoying and time-consuming. I wish there was a feature which allowed me to pin my current terminal to the place where I am now, then start the command, see only the first lines of the output (as many as fits below my cursor) and let the rest of the output be written but not displayed. In other words I would like a feature to allow me automatically scroll up to the place where I gave the command, to see the first lines of the output (where usually the origin of the failure is displayed).
I searched for it but I didn't find it. Do you know if such feature exists? Or have an idea how to implement it with some tricks or workarounds?
If you have a unique shell prompt you could bind a key to jump between shell prompts, for example something like this will make C-b S jump to the previous shell prompt then S subsequent ones:
bind S copy-mode \; send -X search-backward 'nicholas#myhost:'
bind -Tcopy-mode S send -X search-backward 'nicholas#myhost:'
Or similarly you could search for error strings if they have a recognisable prefix. If you install the tmux 3.1 release candidate, you can search for regular expressions.
Alternatively, you could use capture-pane to load the entire history into an editor with key bindings you prefer, for example:
$ tmux capturep -S- -E- -p|vim -
Or pipe to grep or whatever. Note you will need to use a temporary file for this to work with emacs.
Or try to get into the habit of teeing commands with lots of output to a file to start with.
I'd like to write a Vim command that does the following:
Make a new split.
Launch a terminal program.
Wait for the program to stop and close the split.
Read the output produced in the second step into the original buffer.
This seems like a very common work flow, but I'm having trouble getting it to work.
The problem is in steps 3 and 4. As a test I defined:
function MyExitFunction(a,b,c)
close
read blah
endfunction
Then did:
:new | call termopen('fzf>blah',{on_exit:MyExitFunction}
which does start the terminal and close the split after the program is done. The read command, however, seems to do nothing. Perhaps it reads the input into a wrong split?
What should I do to get the actual program output into my current buffer?
Note, fzf is not the actual program I'm running, but it works a bit like it.
If you have a command that cleanly outputs to stdout, then you simply need :read !<command>.
If you want interactivity, i.e. reading from stdin first, then you should probably run it inside a terminal with :vs | te and then yank the output over. Vim doesn't have a clean and easy way to interop with interactive scripts, so this is probably as good as it's gonna get.
i try to grep current file and then the results to be in separate buffer or split window , NOT in the current buffer im in
i need it to work with simple vim not using quickfix methods (vimgrep and such)
i did try this :
:r!grep foo %
VIM: How to store the grep results in a buffer
but it replaces the current buffer and only doing undo returns the previous file content
so my question is:
how to redirect the results or separate buffer or split window
Open a new buffer (here in a vertical window):
:vnew
Fill it with the output of a grep of the alternate file:
:0r!grep foo #
In one go:
:vnew | 0r!grep foo #
I'm not sure if this works perfectly in all scenarios, but give this a shot:
:execute "vnew" "tmp_buffer_" . winbufnr(winnr()) | execute "0r !grep foo" bufname(winbufnr(winnr()+1))
The first part should create a new buffer in a vertical split. I gave it a subscript with the buffer number it is associated with to avoid possible clashes with running this on multiple buffers. The second performs the read operation and figures which buffer to run the grep on by assuming the buffer to be grepped is in the next window over (which I believe should hold true since we've done a fresh split)
I am creating a NASM assembly code to read 2d array of numbers present in file from stdin
i am running the executable like this -> ./abc < input.txt .
and after that i will display the read 2d array on terminal then i want to get keys codes of arrow keys (which normal appear in terminal as special characters) i wrote code for it but its not working. ( I did echo off in termios setting for that)
Although it was working when i am taking file name as an argument & reading and not from stdin but using fopen with proper fd.
./abc abc.txt
in this case after displaying the read 2d array i am able to get arrow keys codes in program but not in earlier case.
Please help me in this matter.
By using input redirection you disconnect stdin from your terminal and instead connect it to a pipe that your shell is reading the file into.
You could use cat input.txt - | ./abc, but you would have to pres Enter to flush the line buffer and make cat pipe the current line into your program.
I would suggest not messing with stdin and just taking the input file as an argument, like you already did before.
Ok, I have rather simple question: How can one bind vim command/hotkey to execute some complicated shell-script?
E.g. I want to optimize base64-inlined images inside css files. I know, that in shell it would be something like:
echo `selection` > /tmp/img.png.b64
base64 -d /tmp/img.png.b64 > /tmp/img.png
optipng -o7 /tmp/img.png
base64 -w 0 /tmp/img.png > `selection`
I want to put selection into the script and then get result of script execution and replace selected content with that result.
I see the workflow as selecting base64 part in visual block mode and type e.g. :'<,'>optipng or press some hotkey.
The question is how to setup vim to do that.
Vim allows to filter line(s) through an external command with :[range]!{cmd}. If your optipng command can take input from stdin and print to stdout, you can use it directly; else, with the help of a small shell script wrapper. See :help :range! for details.
One limitation is that this only works for whole lines, not parts, even when visually selected. You can get around this with the vis plugin; it would then be something like:
:'<,'>B !optipng -o7