I'm trying to open 3 files in vim from the command line. I'd like one file on the left with a vertical split between it and the other two files, the remaining two files would be horizontally split.
| 2
1 |---
| 3
I know I can use the command vim -O Notes.markdown -O Plan.markdown to open the first two files in a vertical split and once I'm in I can switch to the second file with ctl w and then use the command split History.markdown to achieve what I want, but I'd like to be able to do it all in one line from the command line.
I tried using the command vim -O Notes.markdown -O Plan.markdown -c split History.Markdown which gets close, but it splits the first and second file leaving the 3rd on the right side of the vertical split.
The thing I can't figure out is if I can tell vim to use the ctl key from the command line so I could run something like ... -c <switchwindowcommand> | split History.markdown. Is there a way to specify the control key?
There are many ways to do this; the key is :wincmd, which lets you execute arbitrary window commands.
Here, I first create three vertical splits, and then use <C-W>H to move the first window to a full-height vertical split on the left:
$ vim -o 1 2 3 -c "wincmd H"
I think this is what you're looking for.
:help windcmd
For example:
vim a.txt -c "vs b.txt | sp c.txt" -c "wincmd h"
Related
Adding a simple line to my .vimrc I managed to open an ePub archive with zip.vim on a vim buffer. This basically opens a numbered list of htm, css, jpg, xml files that one can access individually. I want to perform a search and replace through all these numbered files as it is too painful to edit each of them and do it - there's around 400 files. :args and :argdo did not really work or at least I could not make them. Any ideas?
I'm not sure it will work for you, and I'm going to assume that when you hit Enter on a filepath inside your Vim buffer, a new viewport is opened (by the ZipBrowseSelect() function defined in $VIMRUNTIME/autoload/zip.vim) to display the contents of the file.
If this is the case, you could try the following method.
:%argd
This command deletes all the paths in the current arglist.
Then, you would have to visually select all the lines containing a path to a file you want to modify. From normal mode, you could hit vip, for example, and adjust the visual selection to exclude some lines if needed.
:'<,'>g/^/exe "norm \r" | argadd % | close
This command should hit Enter on each line inside your visual selection, add the file which has been opened in a new viewport, and close the latter to get back to the original window.
:vim /pattern/ ##
This command should populate the quickfix list with all the lines containing the pattern you're looking for.
:cfdo %s/pattern/replacement/ge | update
This command should replace pattern with replacement in each file present in the quickfix list, and save the file if it has been changed.
The last step uses the :cfdo command which was introduced in Vim version 7.4.858. If your Vim version is not new enough to support :cfdo, you could bypass the last 2 steps, and directly execute:
:argdo %s/pattern/replacement/ge | update
The benefit of:
:vim /pattern/ ##
:cfdo %s/pattern/replacement/ge | update
... is to prune the arglist from the files which don't contain your pattern, so that the substitutions commands are only executed when needed.
If you don't have :cfdo but still want to prune the arglist, you could source this custom command:
com! -nargs=0 -bar Qargs exe 'args '.s:qfl_names()
fu! s:qfl_names() abort
let buffer_numbers = {}
for qf_item in getqflist()
let buffer_numbers[qf_item['bufnr']] = bufname(qf_item['bufnr'])
endfor
return join(map(values(buffer_numbers), 'fnameescape(v:val)'))
endfu
I've copied it from this video: Project-wide find and replace.
Most of the other commands are also taken from this video, so it might help you to have a look at it, if you don't have already.
Then, you would replace the :cfdo command, with:
:Qargs
:argdo %s/pattern/replacement/ge | update
To summarize, you could try one of these 3 methods:
:%argd
visually select the paths of the files
:'<,'>g/^/exe "norm \r" | argadd % | close
:argdo %s/pattern/replacement/ge | update
Or:
:%argd
visually select the paths of the files
:'<,'>g/^/exe "norm \r" | argadd % | close
:vim /pattern/ ##
:cfdo %s/pattern/replacement/ge | update
Or:
:%argd
visually select the paths of the files
:'<,'>g/^/exe "norm \r" | argadd % | close
:vim /pattern/ ##
:Qargs
:argdo %s/pattern/replacement/ge | update
Edit:
You could also try to visually select the paths of the files, then execute:
:'<,'>g/^/e `='zipfile:'.expand('%:p').'::'.getline(".")` | %s/pattern/replacement/ge | update | b#
This method relies on the fact that the path to a file in the archive seems to follow this scheme:
zipfile:/path/to/epub::path/to/file/in/archive
So, you can get the path to a file under the cursor with the Vim expression:
'zipfile:'.expand('%:p').'::'.getline(".")
And you can edit this file using backticks (see :h `=):
:e `=Vim expression`
→
:e `='zipfile:'.expand('%:p').'::'.getline(".")`
From there, you need the global command, to repeat the edition on each line inside the visual selection.
In the epub I tested, all the paths were below the line mimetype. If this is the case for you, then you could merge the 2 steps (visual selection + global command) in a single command:
1/mimetype/+,$g/^/e `='zipfile:'.expand('%:p').'::'.getline(".")` | %s/pattern/replacement/ge | update | b#
I'm not sure but this mìght help you
On esc mode try
:%s/word you want to search/word you want yo replace with/g
Background.
I am a frequent vim-user, I just love the way you can navigate the buffers without ever having to reach for the mouse. I'm especially fond of the relative line numbers that let's me jump to specific lines with perfect accurecy, it just makes navigating that much faster. I also use tmux quite a bit since I often have a lot of stuff going on in my terminal.
The thing that bugs me the most though is when I use tmux copy-mode, it just takes forever to navigate to the line(s) you want to copy if you are using the arrow-keys, ctrl+p or k.
Searching for a unique keyword in the buffer is also not ideal but it might be faster if you already know what to search for. A lot of the time you make a search only to discover that the keyword you searched wasn't so unique after all and you didn't end up on the line you wished for anyway.
My question is this:
Does tmux support relative line-numbers?
..or line-numbers at all for that matter?
I can't find any information about this on the web. Nobody seems to be mentioning anything about this anywhere. Is there a better way?
Any other tips for ultra-speedy navigation in tmux copy-mode using the keyboard would also be very much appreciated.
tmux has a linenumber system in copy mode. however the first line is very bottom line.
In copy mode you can press : to go to line but there is no option to show linenumber. You can use some vim motions (key-mode was set as vi) in copy-mode, e.g. j k 20j 20k f F t T gg G 20G H L M ^ $ / ? ctrl-u ctrl-d w b ....
I think for copy a block of text, it is enough.. If you think you still cannot "ultra-speedy navigation", make a scenario, let's see how could we copy faster.
check man-page of tmux for details.
I found this tip. It will take you to your line with less keystrokes.
# super fast way to reach copy-mode and search upwards
bind-key / copy-mode \; send-key ?
This is a total hack but it works:
tmux split-window -h -l 3 -b "printf '\e[38;5;0m\e[48;5;226m' \
&& seq 200 1 \
&& echo -n 0 \
&& read" \
&& tmux select-pane -l
(newlines added for readablitiy)
To break this down:
tmux split-window -h -l 3 "command..." splits the pane -h horizontally (that is places a new pane next to the current one rather than above or below) with a -l width of 3 (you're unlikely to need more than 3 digits of line number... 0-999) to the -b left of the current pane and runs the command in it:
printf ... just sets the background colour to yellow and the foreground colour to black... You can omit this bit if you're not feeling fancy :)
seq 200 1 prints line numbers from 200 to 1 - extend if you have a tall screen!
echo -n 0 prints the 0 on the last line, because seq will print a trailing newline and we don't want that
read waits for you to press enter - this is how we block it from closing after the echo has completed
tmux select-pane -l jumps you back to focus on the pane you were working on
Select the pane and press enter to close it.
I would imagine that you can do something add a name for the new pane and create a keybinding for both opening and closing it from the pane you're actually trying to count line numbers on, but for now I'm just using the binding:
bind N split-window -h -l 3 -b "printf '\e[38;5;0m\e[48;5;226m' && seq 200 1 && echo -n 0 && read" \; select-pane -l
Is there a way to limit :Ag output so it always takes one line and doesn't blow up the quickfix window?
At the moment it looks like this and it's awful. I can't see filenames, everything is super slow and just sucks:
Update For the record, I scrolled Quickfix window a bit to illustrate the point better. And while it is usable via :cn :cp, I would like to be able to quickly glance over the results with j k.
Looking over the man page, there does not seem to be any way to limit the output built into Ag itself.
Is there another way of limiting the line length? Actually, you do have the built in "cut" command in Linux, e.g. using it on the shell:
ag --column foo | cut -c 1-80
Limit all lines to 80.
Now we have to make ag.vim execute our specially crafted command, for which the g:agprg exists. So the first thing I thought of is this:
let g:agprg='ag --column \| cut -c 1-80' " doesn't work
The problem with this is that the ag.vim plugin just appends extra arguments to the end, and thus you end up executing something like ag --column | cut -c 1-80 something-i-searched-for. Is there a way to directly "insert" the arguments before the |?
One trick is to use a temporary shell function, like this:
f() { ag --column "$#" | cut -c 1-80 }; f something-i-search-for
Unfortunately, we still can't use this. ag.vim checks whether or not the first word is an actual command. So it complains that no executable by the name of "f()" exists. So my final solution:
let g:agprg='true ; f(){ ag --column "$#" \| cut -c 1-80 }; f'
As true always exists and doesn't do anything except return true, this works!
To your actual screenwidth instead of 80, you could use:
let g:agprg='true ; f(){ ag --column "$#" \| cut -c 1-'.(&columns - 6).' }; f'
I added the magic - 6 here to account for the extra characters Vim itself adds.
ag now supports a --width switch. rg has a similar --max-columns switch.
Assuming you are using this plugin. You should add this to your ~/.vimrc as specified by :h g:ag_qhandler
let g:ag_qhandler = 'copen 1'
However you can probably just do let :g:ag_qhandler = 'cc'. This will print the results at the in the bottom. When you move through the quickfix list via :cnext or :cprev it will print the current result as well.
For more help see:
:h g:ag_qhandler
:h :cope
Changing the geometry of the quickfix window won't help you fix your problem: the window is unusable not because of its size but because your search results are polluted by superfluous matches in minimized files.
Minimized JavaScript or CSS is the frontend development's equivalent of a binary and that kind of file should be ignored by search tools, indexing tools, file navigation tools and even version control tools, sometimes, because they are generally irrelevant.
Adding these lines to your ~/.agignore will make Ag search only in actual source files:
*.min*
*-min*
*_min*
*.min.*
bundle
min
vendor
tags
cscope.*
Adjust that list to your liking.
I know how to open all files each in one tab or each in one window, but is it possible to make them open in a combination of tabs/windows?
I am using gvim 7.3
I think you have the notion of tab pages backwards. From :h tabpage:
A tab page holds one or more windows.
I'm not sure if it's what you want, but you can create two tabs each with two windows through liberal use of -c on the command line:
gvim -p2 first.txt third.txt -c "sp second.txt" -c "tabn" -c "sp fourth.txt"
This leaves the focus on the 4th file. You can rearrange the arguments (or add more) if you want to do something different. Also note that gvim will confusingly tell you that it's only opening two files.
You can use :[count]tab {cmd} (tab-page-commands) in combination with :[n]sbnext [N] (buffer-list) as follows:
vim file1 file2 file3 file4 +sbn +"tab sbn" +sbn
Just add more +"tab sbn" +sbn for more files. If you want to split vertically, replace +sbn by +"vert sbn".
BACKGROUND:
In vim (Ex mode) it is possible to run an external command and have the output from that command automatically inserted into the current buffer.
In Example 001, we see how to cd to the current directory, get a listing of the files there and auto insert that into the current buffer
EXAMPLE 001:
:cd . | :r ! dir /w/s/b
QUESTIONS:
1) Is it possible to automatically specify or capture the Vim {range} to reflect the lines that were recently inserted into the file ?
2) Using the range obtained in question 1) is it possible to chain Ex mode commands to automatically process the lines that were inserted into the file ?
3) If it is not possible to do 1) or 2) above, is there an alternate way for Vim to recognize lines recently inserted into the buffer and run arbitrary commands on them ?
4) What is a relevant :help cross reference that can be used for this purpose ?
GOAL:
The goal is to be able to chain multiple Ex mode commands together to easily run process recently added lines to a file, without having to expressly identify the line number or manually select them using Visual mode or something similar.
The goal is do something similar to the (psuedo-code) in Example 002
Example 002:
:cd . | :r ! dir /w/s/b | :{auto-range}s/^/ /
Vim sets the change marks '[ and '] to the inserted range; you can use these to define a range for subsequent Ex commands:
:cd . | execute 'r ! dir /w/s/b' | '[,']s/^/ /
You need :execute because otherwise the | is interpreted to belong to the :r command.
What about processing those lines before inserting them in Vim?
:r!dir /w/s/b | sed -e "s/^/ /"