Editing the command line within a shell within vim - shell

There's some clunky behavior I'd like to resolve:
In vim I can use :terminal to bring up a shell window. But if I type something into it, I can't edit it like a normal shell: I'm stuck either in a useless normal mode, or I'm in an insert mode where I can only write new letters or delete them at the end of the line. I can't move the cursor to the middle and change, say,
cd ~/Picturs/MyLovelyHusbandAndChildren2017/VacationPhotos/Aruba
into
cd ~/Pictures/MyLovelyHusbandAndChildren2017/VacationPhotos/Aruba
without simply deleting everything from ~/Pictur to the end and rewriting it. Is there any way at all around this or is it a basic limitation of how vim works? This is frustrating to me because I'd like to use ghci in the shell window but this makes it much less responsive.

There are some specific configs you can do both on vim or neovim to tacle this issue, in my case, neovim, I have these lines on my init file:
augroup neovim_terminal
autocmd!
" Enter Terminal-mode (insert) automatically
autocmd TermOpen * startinsert
" Disables number lines on terminal buffers
autocmd TermOpen * :set nonumber norelativenumber
" allows you to use Ctrl-c on terminal window
autocmd TermOpen * nnoremap <buffer> <C-c> i<C-c>
augroup END
Note the autocmd TermOpen * startinsert, that line makes sure, as soon as I enter a new terminal on neovim it will be in inert mode.

Related

How to close cmd window from vim command after using latexmk?

I am new to vim and I'm using it to type up my latex documents. I work on Windows, and have defined this map in my vimrc file:
autocmd FileType tex inoremap ,lc <Esc>:w! \| !latexmk -pdf -pv %<CR>
When latexmk is ran, it opens up a cmd window and then the PDF viewer window. However, it doesn't close the cmd window, which I then have to close by pressing any key. Is there any way to define my map such that it closes the command line and opens up my PDF? I thought something like
autocmd FileType tex inoremap ,lc <Esc>:w! \| !latexmk -pdf %<CR> \| !latexmk -pv %<CR>
could work, but turns out it doesn't.
You can try:
autocmd FileType tex inoremap ,lc <Esc>:w! \| !latexmk -pdf -pv %<CR> \| call feedkeys(' ')<CR>
The feedkeys() simulates the press of the given key(s), in occurence the space key, which should close the command message for you.
Additional advices
As you are new to Vim, you may be interested by some additional advices I want to share to improve your above code:
You can add the <buffer> argument to your mapping:
autocmd FileType tex inoremap <buffer> ,lc ...
It will map your shortkey only for latex buffers. Without it, once a latex file is loaded, every buffer and window will interpret your mapping, which is not what you want I guess.
You can create a dedicated function in order to perform the job you want: it will improve readability and make it easier to modify. Indeed, your autocommand line is becoming quite long to read, and it might be still longer if you wanted to add more features.
So you could transform your code into something like this:
autocmd FileType tex inoremap <buffer> ,lc <Esc>:call MakeLatex()<CR>
function MakeLatex()
w!
!latexmk -pdf -pv %
call feedkeys(' ')
endf
Depending of what exact behaviour you want for your mapping, you could replace <esc> by <c-o> in your mapping.
This way, you can stay in Insert mode after having typed your shortcut:
autocmd FileType tex inoremap <buffer> ,lc <C-O>:call MakeLatex()<CR>
The last thing to improve (imho) would be to put all of this into a separate ftplugin file. This way you can separate features that you only want for Latex files, and make it easier to add even more filetype-based features.
In order to do this, go to your vim home directory (it should be something like ~/.vim or ~/vimfiles on Windows) and create the file <YOUR_VIM_DIR>/ftplugin/tex.vim; this file will be loaded each time you will want to edit a latex file, without the need of any autocmd FileType tex. Then put the following code into this file:
inoremap <buffer> ,lc <c-o>:MakeLatex<cr>
command! -buffer MakeLatex call s:make_latex()
function s:make_latex()
w!
!latexmk -pdf -pv %
call feedkeys(' ')
endf
It is a slightly improved version compared to the above one, because now, everything is local to the buffer or to the script. In the previous version, the MakeLatex() function scope was global to Vim, while it was not needed outside of Latex files. With this version, s:make_latex() is local to the script, and the MakeLatex command is local to the buffer, so the scope of commands/functions is really limited to Latex files only.
Hope this can be useful, happy vimming;

Paste bash command, but make sure it doesn't run

Sometimes when you ctrl-v with bash it will run the command even though you didn't intend to run it yet - is there a way to paste a command into the bash shell / terminal making sure you don't actually run any of the command(s)?
if you could set what was on the terminal prompt programmatically, you could do this with bash on MacOS:
export BASH_PROMPT="$(pbpaste)"
which ties into my other question that I just asked:
How to change the value that's in the prompt
There is a Readline variable:
enable-bracketed-paste
When set to On, Readline will configure the terminal in a way that will enable it to insert each paste into the editing buffer as a single string of characters, instead of treating each character as if it had been read from the keyboard. This can prevent pasted characters from being interpreted as editing commands. The default is off.
To turn this on, put something like
set enable-bracketed-paste on
into your ~/.inputrc.
This was introduced in Bash 4.4 / Readline 7.0.
Use ^X^E aka Ctrl+X Ctrl+E in bash to open your $EDITOR for command entry.
Paste and/or edit as much as you want, across as many lines as you want. When you're done, save and exit, and bash will run it.
(In vi mode, the shortcut is v)

VIM, setting directory to where you returned from shell

I'm somewhat new to VIM and am playing with ways to open files (OS X).
Upon returning to VIM after temporarily exiting into shell (ctrl+z, followed by fg), I think it would be convenient if VIM set its current working directory to wherever I was when I returned.
Is this possible? I do know how to change the working directory manually from within VIM.
thank you,
Check if your version of Vim has support for client-server functionality: :echo has('clientserver')
If so, you can write an alias to tell Vim to change its cwd:
In your .bashrc:
alias fg="$VIM --remote-send ':cd $PWD<CR>'; fg"
Where $VIM is vim or gvim or macvim.
You need the colon and the <CR> because you're sending Vim keystrokes rather than commands (<CR> is a special notation for "Enter")
I'm not sure whether --remote-send works when Vim is suspended - this approach might be better if you use something like screen or tmux to run vim and your shell at the same time.
Otherwise, it's a bit trickier.
There's a :shell command that is similar to suspending and resuming, but I'm assuming it forks a child process instead of returning you to Vim's parent process. If you're ok with that, there's a ShellCmdPost autocmd you can attach to to load information. You can use that in association with an alias that writes the $CWD to a file to load the required directory and change to it.
In your .bashrc:
alias fgv="echo $PWD > ~/.cwd; exit"
In your .vimrc:
autocmd ShellCmdPost * call LoadCWD()
function! LoadCWD()
let lines = readfile('~/.cwd')
if len(lines) > 0
let cwd = lines[0]
execute 'cd' cwd
endif
endfunction
Looking through the list of autocommands, I was not able to find any that detect when Vim has been suspended and has just been resumed. You could remap ctrl-z to first set a flag variable then do an unmapped ctrl-z. Then write a shell script like before that writes its $CWD to a specific file. Then you can set up an autocmd to watch that file for modification and in the handler, check the flag variable, and if it's set, reset it, read the file, and change to that directory. A bit complex, but it would work.
That would look like this. You'll have to load the file when you start Vim so that it can monitor it for changes. You may want to set hidden so that you can keep the buffer open but hide it.
In your .bashrc:
alias fg="echo $PWD > ~/.cwd; fg"
In your .vimrc:
set hidden
edit ~/.cwd
enew
nnoremap <C-Z> :let g:load_cwd = 1<CR><C-Z>
autocmd FileChangedShell ~/.cwd call LoadCWD()
function! LoadCWD()
if g:load_cwd
let g:load_cwd = 0
let lines = readfile('~/.cwd')
if len(lines) > 0
let cwd = lines[0]
execute 'cd' cwd
endif
endif
endfunction

vim/gvim close nerdtree after start from shell

I would like to close NerdTree on vim startup using shell arguments. Something like this:
vim +NERDTreeClose file.txt
or
vim -c "NERDTreeClose" file.txt
should do the trick, but it doesn't. Automatic start of NERDTree is defined inside .vimrc (by autocmd vimenter * NERDTree) and it should stay there.
The point of all this is to configure vim as a mergetool so I don't need NERDTree opening on startup.

How can I invoke VIM with C-X e for long, complex, tricky commands?

I found an awesome tip here. You can "[r]apidly invoke an editor to write a long, complex, or tricky command". However, when I press the key combination above, I get Emacs open. I would like to switch it to Vim. How can I invoke Vim with C-X e?
[1. Problem SOLVED by Brian Cambell]
export EDITOR=vim
Add to your .bashrc or appropriate shell rc file
[2. Problem SOLVED thanks to Pax]
I was unable to get the tricky command back to Bash. The errors were:
> Error detected while processing BufRead Auto commands for "*":
> E117: Unknown function: JumpToLastPosition
Quotes in .vimrc solved the second problem. I am still unsure about the part in my .vimrc:
" augroup misc
" autocmd!
" autocmd BufReadPost * call JumpToLastPosition()
" autocmd FileChangedShell * call WarningMsg("File changed outside of vim")
" augroup end
[3. Problem]
What do the above part in .vimrc do?
On most Linux installs (all the ones I tested), bash recognizes both the Emacs and Vi command history keys (or you can use "set -o vi" to force it).
So, you can just use the vi-mode "<ESC>v" to to enter visual mode, this will start editing in a Vim session.
To run the command, you just save and exit from Vim ("ZZ" or ":wq"). To cancel the command, you need to delete the contents, save and exit ("1GdGZZ").
In addition to running it by exiting, you can also save it while in the editor to another location (":w /tmp/myscript").
Keep in mind that visual mode will work with the currently selected line so you don't have to start with a blank command ("<ESC>v"). You can use the normal vi-mode tools to select a line from the history first and then enter visual mode ("<ESC>kv" for last command, "<ESC>/grep<ENTER>nnv" for third-last grep command and so on).
Using this method has the advantage of not changing the "EDITOR" variable which may be used for other things (unless you want Vim for everything, which is a very sensible position to take IMNSHO).
Update:
Regarding your error, posted after the question:
JumpToLastPosition() is the function called by Vim for all files to put the cursor where it was when you last edited the file. I'm going to assume you're actually getting this error when the editing starts, not when you exit, since this is the auto function following a buffer read.
Can you start a "normal" vim session ("vim xx.txt" and then "vim xx") without this error occurring? You may find you get the same problem (and possibly only on the last one).
If you do have the same problem, you need to look at your startup files. It's possible the autocmd for BufRead is broken somehow. Have a look inside your vimrc and you filetype.vim files to see where that function is called and/or defined (I suspect it's called but not defined and that may be a mismatch between the two files or one of them has been damaged).
export EDITOR=vim
Add to your .bashrc or appropriate shell rc file
The link that you provided contains the answer:
Next time you are using your shell, try typing ctrl-x e (that is holding control key press x and then e). The shell will take what you've written on the command line thus far and paste it into the editor specified by $EDITOR.
You need to set the EDITOR environment variable (like #Brian Campbell)

Resources