Related
As part of learning Haskell, for fun I'm attempting to use Raspberry PI. Having encountered a myriad of issues installing ghci on the PI I've resolved to using just ghc.
So to create, compile & run a new Haskell file :
vi first.hs
i
main = putStrLn "First"
Esc
:w
:q
ghc -o first first.hs
./first
Output is : "First"
I would like to automate the commands :
Esc
:w
:q
ghc -o first first.hs
./first
Can these be added as new command from within vi / vim, something like :
:mycustomcommands
And run from within the vi / vim editor ?
Maybe you could try adding something like this to your vimrc:
function! ExecuteHS()
w
!ghc -o first %
!./first
endfunction
And to use this function you just have to call it like that :call ExecuteHS(). Vim will be put on background during the execution of your file and will then come back on foreground at the end of the execution.
As a bonus you can add the folowing line to your vimrc
nnoremap <key> :call ExecuteHS()<CR>
Replacing <key> with your prefered key combination <Leader>e for example. This way you'll simply have to hit ,e (if you didn't changed your leader key) in normal mode to call the function.
That's probably not the cleanest way to do it but it should work for what you want.
Absolutely in vim, though not necessarily in other vi flavors. See this tutorial on defining custom commands. Put the custom command in your vimrc and it will always be available as :Customcmd or whatever you call it. For one-button access, you can use :remap to assign a hotkey to your custom command or the sequence of built-in commands you want to run. This is a tutorial on keymappings that will give you more information.
I second #statox's referral to https://vi.stackexchange.com :)
I use vim-haskell, which includes a couple nice things. In particular, it includes a file for setting up cabal-install as the compiler, which is a very nice way of working. Dump this in ~/.vim/compiler/cabal-build.vim:
CompilerSet makeprg=cabal\ build
CompilerSet errorformat=
\%W%f:%l:%c:\ Warning:%m,
\%W%f:%l:%c:\ Warning:,
\%E%f:%l:%c:%m,
\%E%f:%l:%c:,
\%C\ \ %#%m,
\%-G%.%#,
\%-G%.%#
And this in ~/.vim/ftplugin/haskell.vim:
compiler cabal-build
(The argument to compiler should match the name of the file you put in ~/.vim/compiler.) Then you can run :make in vim and it will save any changed buffers (assuming autowrite is set) and build your project. When there are errors, it will populate the quick-fix list, which lets you jump to the specific file and line numbers of each error or warning with a key. Read more about this feature with :help quickfix. Once everything is working, you can :!cabal run to run it.
I have ~/.bash_history that contains lines such as sudo apt-get install, aplay foo.wav, etc. I thought it would be convenient if I could use these lines for completing whole lines while writing shell scripts.
:h compl-whole-line says:
CTRL-X CTRL-L
Search backwards for a line that starts with the
same characters as those in the current line before
the cursor. Indent is ignored. The matching line is
inserted in front of the cursor.
** The 'complete' option is used to decide which buffers
are searched for a match. Both loaded and unloaded
buffers are used.**
Note the asterisks I inserted. :h 'complete' says:
k k{dict} scan the file {dict}. Several "k" flags can be given,
patterns are valid too. For example: >
:set cpt=k/usr/dict/*,k~/spanish
So I thought :set complete+=k~/.bash_history would do the job. It didn't.
Start vim with
$ vim -u NONE -N
then
:set complete+=k~/.bash_history
:set complete?
" complete=.,w,b,u,t,i,k~/.bash_history
, I enter to the insert mode (i), and when I type
su<C-x><C-l>
, vim says Whole line completion (^L^N^P) Pattern not found. The completion is working for words, so when I type
su<C-p>
sudo is suggested.
What am I missing? How can I use my history for whole line completion without :sp ~/.bash_history?
set complete+=k[file] has nothing to do with line completion: whatever file you give to it will only be used as a source by dictionary completion (<C-x><C-k>) and keyword completion (<C-n>/<C-p>).
:help i_ctrl-x_ctrl-l is clear: line completion only works with lines found in loaded and unloaded buffers. Since ~/.bash_history is not loaded as a buffer, line completion will obviously never use it as a source.
So yes, the only practical solution is to load that file.
:sp ~/.bash_history is not really optimal, though, because a) it takes too much room, both physically and in your buffer list, and b) it requires way too many keystrokes.
The "too much room" part of the problem is easily solved with a more suited command:
:badd ~/.bash_history
The "too many keystrokes" part of the problem could be solved with an autocommand that runs the command above each time you edit a shell script:
augroup shell
autocmd!
autocmd BufNewFile,BufRead *.sh badd ~/.bash_history
augroup END
I've been trying to experiment with using :make recently but I don't like that vim has to switch to showing the shell output first and require one enter keypress, then it shows me what I think is a list of the collected errors based on 'errorformat' which I also need to confirm by pressing enter. I would prefer to just have a short "OK" message that does not require confirmation by a keypress, or that vim would open the :cwindow if there were any errors.
I'm using next line just for exact purpose you wrote:
nnoremap <leader>m :silent make\|redraw!\|cc<CR>
cc in the end shows first error or No errors message if this is the case.
You can map for example F9 to use gcc for small C snippets that don't require libraries, linking, etc:
map <F9> :!gcc -o %< % <enter><CR><C-w>
This will produce for the file foo.c the binary foo. I know that's not exactly what you want, but this doesn't show any shell and is useful for small c snippet.
Try:
:silent make
To automatically open the quickfix window after you run make, you can put this into your .vimrc:
autocmd QuickFixCmdPost * :copen
Say I'm editing my _vimrc file and I've just added a couple of lines, for instance a new key mapping. I don't want to reload the whole file (:so %) since that will reset a lot of temporary stuff I'm experimenting with. I just want to run the two lines that I'm currently working on.
I'm having no luck trying to copy/paste the lines into the command buffer, since I can't use the put command in there. Is there any way I could run the current line (or current selection) as EX commands?
Summary:
After Anton Kovalenko's answer and Peter Rincker's comment I ended up with these key maps, which either executes the current line, or the current selected lines if in visual mode:
" Execute current line or current selection as Vim EX commands.
nnoremap <F2> :exe getline(".")<CR>
vnoremap <F2> :<C-w>exe join(getline("'<","'>"),'<Bar>')<CR>
To execute the current line as an ex command, you may also use:
yy:#"
This will yank the current line to the "-register and execute it. I don't think it is too much typing.
Executing the line under cursor as an Ex command:
:execute getline(".")
Convenient enough for 2 lines. (I'd figure out something for doing it with regions, but I'm not a vim user). And for currently selected region, the following seems to do the job:
:execute getreg("*")
As commented by Peter Rincker, this mapping can be used for executing the currently selected lines:
:vnoremap <f2> :<c-u>exe join(getline("'<","'>"),'<bar>')<cr>
For that purpose, I have defined the following commands and mappings:
":[range]Execute Execute text lines as ex commands.
" Handles |line-continuation|.
" The same can be achieved via "zyy#z (or yy#" through the unnamed register);
" but there, the ex command must be preceded by a colon (i.e. :ex)
command! -bar -range Execute silent <line1>,<line2>yank z | let #z = substitute(#z, '\n\s*\\', '', 'g') | #z
" [count]<Leader>e Execute current [count] line(s) as ex commands, then
" {Visual}<Leader>e jump to the following line (to allow speedy sequential
" execution of multiple lines).
nnoremap <silent> <Leader>e :Execute<Bar>execute 'normal! ' . v:count1 . 'j'<CR>
xnoremap <silent> <Leader>e :Execute<Bar>execute 'normal! ' . v:count1 . 'j'<CR>
Just after posting this, I found a work-around. I can copy text into the clipboard using "*y, then put that text into the command buffer by using the middle mouse button. This works for me, but is hardly a convenient solution for people without clipboard support, mouse support or just an aversion to removing their hands from the Vim position.
The accepted answer doesn't handle continuation sections. Also, surprisingly, the bar isn't needed, newlines are fine. This will work, first yanking the text into register x:
vno <c-x> "xy:exe substitute(#x,"\n\\",'','g')<cr>
As someone has already mentioned, the only exception are commands that "eat up" newlines. Eg, executing the above mapping on:
:sign define piet text=>> texthl=Search
:exe ":sign place 2 line=23 name=piet file=" . expand("%:p")
will cause vim to to think that the user is trying to define textl as "Search\n:exe ":sign place... etc.
You could also try
:<C-R><C-L><CR>
Per the vim docs, the combination will plop the current line into the command line. From there, hitting enter should do the trick. I realize that this does not handle multiline cases, however it doesn't require a .vimrc and therefore works out of the box.
If you're doing a lot of experimenting (trying things out that you might want to add to your vimrc, I assume?) it might help to do so in a scratch file like experimental.vim so you aren't just relying on your history to know what you're trying out. Now that you have these great mappings, it will be easy to rerun things from experimental or vimrc without sourcing the whole file.
Also (sorry, I can't comment on answers yet, it seems), I tried this mapping of Peter's:
vnoremap <Leader>es :<c-u>exec join(getline("'<","'>"),'<BAR>')<CR>
This works in most cases, but it fails specifically on function definitions.
function! TestMe()
echo "Yay!"
endfunction
This mapping joins the lines into a single string, separated by <BAR> and then execs them.
I'm not entirely sure why, but if I try to do that with a function definition in normal mode:
:exec 'function! TestMe()| echo "Yay!"|endfunction'
-> E488: Trailing characters
After some testing, I've found that it will work with newline separators instead:
:exec "function! TestMe()\n echo 'Yay!'\nendfunction"
:call TestMe()
-> Yay!
So, I've changed my mapping to this:
vnoremap <Leader>es :<c-u>exec join(getline("'<","'>"),"\n")<CR>
I suppose there is a vim or ex reason why the <BAR> method doesn't work on functions (maybe even some setting I have on?), and I'm curious to hear what it is if someone knows.
I don't want to reload the whole file (:so %) since that will reset a lot of temporary stuff I'm experimenting. I just want to run the two lines that I'm currently working on.
If you want to execute a command because you want to refine it before committing it to _.vimrc, then you should launch a Command Line Window for Ex-mode commands with q:.
At launch the Command Line Window is buffered with the contents of the command line history. It is a normal Vim window the contents of which can be edited as any text buffer with the exception of pressing on any line which executes the command on that line. It is very useful when you want to slightly change a long, complex command you wrote earlier and re-run it.
To launch a 'Command Line Window' for search strings press q/.
!! (shorthand for :.!) executes the current line as input to a command, per POSIX ex & vi. You may need to append sh if it is a system command.
Executing !! on a blank line (and omitting sh) is a shortcut for reading a shell command straight into the buffer. By it's nature :.! overwrites the current line while :.r! inserts on the line below.
ls -A | head -n +4
~
~
!sh
Results:
.sh_history
.sh_logout
.kshrc
corelist.txt
~
~
4 lines added; 1 line deleted`
This means there is no need to redirect pipelines to a file and then examine the data to see if the contents are valid. Just execute commands in vi directly and undo if you make a mistake.
Alternately, yanking a line as a named buffer allows you to execute it as an ex command, almost like a macro. You can still edit and undo the line to get it correct instead of trying to edit the : line in command mode.
The functions recommended here are all POSIX and have been supported for over 40 years, so no special vim or other enhanced features are required.
:%s/meep/pEEp/ | g/foo/ s//BAR
foo
grok
meep
~
~
Yank the ex command (line 1, :%s...) into a named buffer / macro.
I just use the label m for "macro".
"myy
or
:1y m
Now execute the named buffer / macro, in command mode, using #:
#m
Results:
:%s/pEEp/pEEp/ | g/BAR / s//BAR
BAR
grok
pEEp
~
~
4 lines changed
But remember that "multiple undo" is not POSIX. undo is only a toggle between undo and redo in a "historically accurate & compliant" ex / vi implementation.
The work-around is to save to a temporary (or valid) file name before executing a questionable edit:
:w $$.tmp
Then just :e! to "reset and reload" if needed.
You can also use :pre (preserve) to make a special temporary backup file prior to making multiple changes.
Then use :reco! % (recover this!) to restore back to that point.
Realize that :preserve creates a snapshot-like file which is deleted as soon as it is rolled back to. It does not matter if you save the edit(s) or not.
Therefore writing your own file (:w ...) and restoring with :e! may still have value because the system will not automatically delete it.
:pre is perfect when you should have ran sudo vi ... or otherwise do not have the necessary permissions - but you only realized the mistake after making several changes. i.e. vi /etc/sudoers instead of sudo vi /etc/sudoers.
^^ NEVER DO THIS! ONLY AN EXAMPLE! USE sudo visudo INSTEAD!
You can get a list of existing recovery files with vi -r and recover one directly with vi -r filename as needed, optionally with something like sudo vi -r filename.
The distinction here is that even though the ":preserved file" has it's own "special" name and path internally, it will :write to the original, intended location when ":recovered ==> /etc/sudoers
Just be sure to use :wq! and not something like ZZ when done with your "recovery" or you will still lose the edits which you tried to save.
By the way, ^R is expected to redraw or repaint the display per POSIX; it is not "undo" in any compliant vi implementation.
When I run a shell command it asks to type ENTER at the end and once you do the output is hidden. Is there a way to see it again w/o running the command again?
Also some internal commands like make also run external commands, and those do not even stop for ENTER so if I have an error in my 'compiler' settings the command flashes on the screen too fast to see it. How do I see the command and its output? (quickfix is empty)
UPDATE
The output is DEFINITELY still there. at least on the terminal vim. if I type
:!cat
the output of the previous command is still there. the problem is a) it seems too much like a hack, I'm looking for a proper vim way b) it doesn't work in gui vim
just type :!
or you could try SingleCompile
Putting vim into the background normally works for me (hit Ctrl+Z).
This will show you the shell you started vim from and in my case I can see the output of all the commands that I ran in vim via ":!somecommand".
This is assuming that you ran vim from a shell, not the gui one (gvim).
Before executing a command, you can redirect output to a file, register, selection, clipboard or variable. For me, redirecting to a register is the most practical solution.
To start redirecting to register a, use
:redir #a
Then you run your commands, say
:!ls -l
And end redirecting with
:redir END
That's all, register a now contains the output from the redirected commands. You can view it with :reg a or put into a buffer with "ap, as you would do normally with a register.
Read the help for :redir to know more about the various ways of redirecting.
After months, I found a help file that you may be interested in taking a look: messages.txt.
Though incomplete, it helps a lot. There is a command (new to me) called g< that displays the last message given, but apparently only the Vim messages, like [No write since last change].
First, I suggest you to take a look in your settings for 'shm', and try to make your commands output more persistent (the "Hit ENTER" appearing more often). Then, check if this help file helps :-) I couldn't make it work 100%, but was a great advance.
Why I do not use :! anymore, and what is the alternative
I learn the :! from the currently chosen answer (and I upvoted it). It works, in a sense that it does show the previous screen.
However, the other day I learn another tip of using :!! to re-run the last command (which, by the way, is very useful when you are in a edit-test-edit-test-... cycle). And then I realize that, using :! somehow has a side effect of forgetting the last command, so that future :!! won't work. That is not cool.
I don't understand this, until I take a deep dive into vim's documentation.
:!{cmd} Execute {cmd} with the shell.
Any '!' in {cmd} is replaced with the previous
external command
Suddenly, everything starts to make sense. Let's examine it in this sequence:
Assuming you first run :!make foo bar baz tons of parameters and see its output, later come back to vim.
Now you can run :!!, the second ! will be replaced with the previous external command, so you will run make foo bar baz tons of parameters one more time.
Now if you run :!, vim will still treat it as "start a (new) external command", it is just that the command turns out to be EMPTY. So this is equivalent to you type an empty command (i.e. hitting ENTER once inside a normal shell). By switching the screen into shell, you happen to get a chance to see the previous screen output. That's it.
Now if you run :!!, vim will repeat the previous command, but this time, the previous command is an empty command. That's why your vim loses the memory for make foo bar baz tons of parameters so that next time you wanna make, you will have to type them again.
So, the next question will be, is there any other "pure vim command" to only show the previous shell output without messing up the last command memory? I don't know. But now I settle for using CTRL+Z to bring vim to background, therefore shows the shell console with the previous command output, and then I type fg and ENTER to switch back to vim. FWIW, the CTRL+Z solution actually needs one less key stroke than the :! solution (which requires shift+; shift+1 ENTER to show command screen, and a ENTER to come back).
I usually exit to the shell using :sh and that will show you the output from all commands that has been executed and did not have it's output redirected.
Simply close the shell and you will be back inside of vim.
Found this script -- which will open up a new tab
function! s:ExecuteInShell(command)
let command = join(map(split(a:command), 'expand(v:val)'))
let winnr = bufwinnr('^' . command . '$')
silent! execute winnr < 0 ? 'botright new ' . fnameescape(command) : winnr . 'wincmd w'
setlocal buftype=nowrite bufhidden=wipe nobuflisted noswapfile nowrap number
echo 'Execute ' . command . '...'
silent! execute 'silent %!'. command
silent! execute 'resize ' . line('$')
silent! redraw
silent! execute 'au BufUnload <buffer> execute bufwinnr(' . bufnr('#') . ') . ''wincmd w'''
silent! execute 'nnoremap <silent> <buffer> <LocalLeader>r :call <SID>ExecuteInShell(''' . command . ''')<CR>'
echo 'Shell command ' . command . ' executed.'
endfunction
command! -complete=shellcmd -nargs=+ Shell call s:ExecuteInShell(<q-args>)
Paste it in your .vimrc
It works on gui vim too..
Example Usage -- :Shell make
Scroll up (tested on iTerm 2). Note: this might not work depending on your vim configuration..
Example: I'm about to run !rspec --color % from my vim.
The buffer is filled with the output.
Now, after hitting ENTER, you can scroll up to see the previous output.
maybe the guys are forgetting about the :r
r !ls ~/
Put this where my cursor is:
bug_72440.html
bug_72440.vim
Desktop
dmtools
Docear
docear.sh
Documents
Downloads
examples.desktop
index.html
linux_home
Music
Pictures
Public
Templates
A simple u could get rid of the new text after I yank it or whatever;
Commands like make save their output to /tmp/vsoMething. The errorfile setting seems to be set to the file backing the quickfix/location list. If you want the output to be somewhere specific, see makeef. You can open the current errorfile like this:
:edit <C-r>=&errorfile<CR>
(Unfortunately, this doesn't seem to work for :grep.)
redir doesn't have to be tedious. See this plugin for simplifying it. (I have ftdetect and ftplugin scripts to make the output buffer not backed by a file.)
You see the output on the terminal when you type :!cat because of your terminal, not vim. You'd see the same thing if you used Ctrl-z which suspends vim so vim isn't actively doing anything.