How to create a command in vim that accesses the current filename? - vim

I would like to create an individual vim command that does the following:
save the current file
run the current file with python
Currently I have to do it like this:
:w
:! python3 {filename}
Instead, I would like to do this:
:pyRun
or something similar

You can chain commands with |. So
:w | ! python3 %
will save the buffer and run it with python3.
See :help :bar and :help c_% for more information.
You can create a command for this like:
:command PyRun execute 'w <bar> ! python3 %'
Note that custom commands in vim have to start with an uppercase letter.

Related

Vim Running Terminal Command Automatically

I am trying to write a command (in vim rc) that automatically creates a new split and starts a terminal (i.e by executing :Term) and then automatically executing some bash commands on that terminal (specifically 'conda activate')
This is how far I got:
command CustomTerminal execute "vsplit ." <bar> execute "Term"
How to I extended this command such that, it pipes and executes some bash commands on this terminal?
I see the following issues with your command definition:
you don't need :execute here; also <Bar> is only needed in mappings
the vsplit . creates a directory listing; is that intended?
have you defined a custom :Term command? The build-in command to open a terminal is :terminal
:term performs a (horizontal) split on its own; its :help :terminal mentions
If you want to split the window vertically, use:
:vertical terminal
The :terminal command accepts optional shell commands already. If that's what you need, you can easily extend your custom command to take and pass this argument:
:command -nargs=? CustomTerminal vertical terminal <args>
See :help :command-nargs and :help <args>.
Additionally, you can add :help :command-completion via -complete=shellcmd.
Keeping the terminal and feeding commands to it
If you want to run more than one command and then close the terminal, so to reuse a single terminal session, you have to follow :help terminal-to-job to send commands from Vim to the terminal (received by the interactive shell or whatever application currently is running). It looks like this:
call term_sendkeys(buf, "ls *.java\<CR>")

Execute selection from script in Vim

I'm trying to incorporate vim into my main workflow. A major sticking point for me has been interactively editing and running programs/scripts.
For example given that I'm currently vimmed into test.py
print('hello')
x = 5
y = x+2
print(y)
Without leaving vim how would I:
a) run the whole script without leaving vim
b) run just "print('hello')"
Commenters and the other answer have pointed out how to run a file from vim. But they glossed over some really powerful possibilities. I'd like to explain how some of those work in more detail.
The simplest possible way of running a python script in vim, is to just call the python interpreter on the file, e.g.
:!python %
or, as I prefer to do to make sure there are no unsaved changes,
:w | !python %
But it is not even necessary to have a file to run a python script in vim. The reason why is because :w != save! :w means write, and if no argument is provided, it happens to write to the file you are editing. However, you can write to STDOUT, to another file, or even to another program. So if you'd like to run your buffer as python code without having a file to save and run, you may simply do:
:w !python
This meanse write the current buffer into the external program "python". This literally just sends the contents of your buffer directly to python.
Now here's where it gets really cool. In vim, :w is an "ex command", e.g. a command that you run from the vim command line that originally came from ex, a very old line based unix text editor. The awesome thing about ex commands is that since they are all line based, you can directly state which lines you would like the command to apply to. For example:
:2w myfile.txt
will write only line two to the file "myfile.txt". You can even supply a range, e.g.
:2,7w myfile.txt
will write lines 2-7 to "myfile.txt". This means that using your example, we can run
:1w !python
to run just
print('hello')
To make this more convenient, you can use visual mode to select every line you would like to run, which will automatically fill in the right range for you. This will look like
:'<,'>w !python
To make this more convenient, I would recommend adding something like
xnoremap <leader>p :w !python<cr>
to your .vimrc. Then you can visually select whatever you want and run it as python code by typing
\p
(replace \ with whatever you have set up as your leader). You could also do
nnoremap <leader>p :w !python<cr>
or
nnoremap <leader>p :w | !python %<cr>
depending on whether you want to save to a file or not.
Create a function for a range as discussed in this question:
fu PyRun() range
echo system('python -c ' . shellescape(join(getline(a:firstline, a:lastline), "\n")))
endf
Create a mapping for visual mode:
vmap <C-F6> :call PyRun()<CR>
Then you can select a range and press Control-F6. The range of lines will be executed by python. The result will be displayed in the command area.
You can run a program from vim using :!, i.e. :!python3 % to run your current script.
If you want to bind a key to it, another easy way would be to set makeprg to your python executable: :set makeprg=python3 and then bind a key to :make<cr>. In that case I would set up autocmds that switch the makeprg depending on the file type.
If you want to run a simple statement, you could either use Python's -c switch:
:!python3 -c 'print("Hello world")', or you could just run :!python3 without arguments to be dropped into a REPL without leaving Vim.

redirecting vim :make output to file

Rather than having vim print the output of the :make command, I want to read the output in a file (which gets updated automatically in vim); so that my compiled file can run right away without having to see the output of the :make command.
I'm using the following makefile
all: compile run
compile: file.cc
g++ -o file file.cc
run: file
./file
How does one redirect the output of the :make command in a way that it isn't also printed to the screen by vim?
First of all we have https://vi.stackexchange.com/ , you can get better answers about Vim in there.
Second, I'll argue that a Makefile is no place to run a program, the idea behind make is to catch compilation errors. But assuming you have your reasons (e.g. ./file opens a graphical display) there are a couple of ways to perform this in Vim:
For a start you can set makeprg to perform the redirection:
:set makeprg=make\ >/dev/null\ 2>&1
(You can change /dev/null to an actual file)
But that still leaves the line:
Press ENTER or type command to continue
And asks for confirmation, which may be annoying when you know that there is no output.
To get rid of the confirmation line you can use silent as follows:
set makeprg=make\ >/dev/null\ 2>&1
function! MyMake()
silent make
redraw!
endfunction
command Mm call MyMake()
And now you can do:
:Mm
To perform the make and go back to straight to Vim. (the redraw! is needed only in some terminals)
You can execute this command:
:silent exec "!make >Output" | :redraw!
The file Output contains the last output of the executed make command.
Use :silent to remove the output and "press enter" prompt. I suggest a nice mapping or command:
command! -nargs=* Smake silent make <args>
nnoremap <f5> :silent make<cr>
:make will populate the quickfix list with the results from :make. Use :copen to open the quickfix window.
For more help see:
:h :command
:h silent
:h :make
:h 'makeprg'
:h quickfix

vim shell output with less

I have python a code in vim, run it in vim command line, like this:
:!python %
Output is big enough for screen need scrolling to read it all, but vim only display the output with more command to page output, can I change this? use less command to page output.
I can run command with the less using pipe,
:!python % | less
but it seems not handy, have to quit twice to leave.
Try adding this to your .vimrc:
command! -nargs=* -complete=shellcmd R new | setlocal buftype=nofile bufhidden=hide noswapfile | r !<args>
Example usage:
:R python #
Explanation:
:R opens a new buffer and reads the output of the shell command into it. Because the shell command will be executed for THAT buffer and not the current buffer, we need to use # to refer to the current buffer.

Execute a script directly within vim/mvim/gvim

TextMate has a nice feature that allows you to execute a script from within the current context and shows you the output in a separate window. This lets you write and test code on the go. I'm almost certain there is a similar feature with MacVim/gVIM, but I'm not sure what it is. Currently I save my buffers to disk, then go to the command line and execute the script in that respect. How do I improve that workflow with vim?
You can do this in vim using the ! command. For instance to count the number of words in the current file you can do:
:! wc %
The % is replaced by the current filename. To run a script you could call the interpreter on the file - for instance if you are writing a perl script:
:! perl %
vim tutorial: Mapping keys in Vim
You can map keys so perl executes current script as suggested by jts above.
map <C-p> :w<CR>:!perl %<CR>
will map Ctrl+P to write file and run it by perl
imap <C-p> <Esc>:w<CR>:!perl %<CR>
lets you call the same in insert mode.
You should have .vimrc (_vimrc for Windows) file in your vim/home folder. It has instructions on how vim should behave.
map <C-p> :w<CR>:!perl %<CR> is just instruction to map Ctrl+p to:
a) write current the file :w
b) run command (perl) using % (currently open file) as parameter :!perl %
<CR> after each command stands for "carriage return": an instruction to execute specific command. imap does the same as map but listens Ctrl+p while in insert mode.
You could run it right from vim:
:!./script.sh
All suggestions here merely showcased :!{cmd} %, which passes current buffer to the shell cmd.
But there is another option :write !{cmd}
For example, the effect of the :write !sh command is that each line of the current buffer is executed in the shell.It is often useful, when for instance you've added a couple of lines to you buffer, and want to see execution result immediately without saving the buffer first.Also it is possible to execute some range, rather than whole content of the buffer::[range]write !{cmd}
save the file and call the script using an interpreter
eg.:
:!python %
It sounds like you're looking for !:
:!{cmd} Execute {cmd} with the shell.
You can use % to denote the current filename, if you need to pass it to the script:
!proofread-script %
You can also use ! with a range, to use the command as a filter:
!{motion}{filter} " from normal mode
:{range}!{filter} " from command mode
(In the first case, as with many other commands, when you type the motion, it'll pass you into command mode, converting the motion into a range, e.g. :.,.+2!)
And finally, if you don't actually need to pass input from your file, but want the output in your file, that's essentially a trivial filter, and the fastest way to do it is !!{cmd}. This will replace the current line with the output of the command.
To execute the current executable script, use
:!./%
! executes a shell command, % is the current filename and ./ adds the current dir in front.
Put this small snippet in your .vimrc to execute the current file with one keystroke (like F5) and display the result in a new split-pane buffer.
:! is okay but you need to switch to your terminal to see the result.
While you can do that with ctrl-z and bring vim back with fg it still means you need to switch context a lot.
The way this snippet works is by first guessing the executable based on the filetype and then running it with the current file as its argument.
Next a handy utility method takes the output and dumps it into a new buffer.
It's not perfect, but really fast for common workflows.
Here's the snippet copied below:
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
"""""""""""""""""""""""""" RUN CURRENT FILE """""""""""""""""""""""""""""
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
" Execute current file
nnoremap <F5> :call ExecuteFile()<CR>
" Will attempt to execute the current file based on the `&filetype`
" You need to manually map the filetypes you use most commonly to the
" correct shell command.
function! ExecuteFile()
let filetype_to_command = {
\ 'javascript': 'node',
\ 'coffee': 'coffee',
\ 'python': 'python',
\ 'html': 'open',
\ 'sh': 'sh'
\ }
let cmd = get(filetype_to_command, &filetype, &filetype)
call RunShellCommand(cmd." %s")
endfunction
" Enter any shell command and have the output appear in a new buffer
" For example, to word count the current file:
"
" :Shell wc %s
"
" Thanks to: http://vim.wikia.com/wiki/Display_output_of_shell_commands_in_new_window
command! -complete=shellcmd -nargs=+ Shell call RunShellCommand(<q-args>)
function! RunShellCommand(cmdline)
echo a:cmdline
let expanded_cmdline = a:cmdline
for part in split(a:cmdline, ' ')
if part[0] =~ '\v[%#<]'
let expanded_part = fnameescape(expand(part))
let expanded_cmdline = substitute(expanded_cmdline, part, expanded_part, '')
endif
endfor
botright new
setlocal buftype=nofile bufhidden=wipe nobuflisted noswapfile nowrap
call setline(1, 'You entered: ' . a:cmdline)
call setline(2, 'Expanded Form: ' .expanded_cmdline)
call setline(3,substitute(getline(2),'.','=','g'))
execute '$read !'. expanded_cmdline
setlocal nomodifiable
1
endfunction
Well it depends on your OS - actually I did not test it on M$ Window$ - but Conque is one of the best plugins around there: http://code.google.com/p/conque/
Actually, it can be better, but works. You can embed a shell window in a vim "window".

Resources