Is there a succinct way to delete to the end of the word or the next punctuation mark in Vim? - vim

In Vim, I regularly use dw to delete from the cursor to the end of the word and daw to delete an entire word.
Now that I'm editing SQL all the time, I'd love to be able do something similar for all the table and field names, which use underscores as delimiters.
Is there a succinct hotkey in Vim to delete from the cursor to the end of the word, or to the next punctuation mark? I don't want to have to spend the mental energy to decide "is the end I'm trying to delete up to an underscore, or is it the line end? Or is it a period between the table and field names?"
I'm sure I could do something like df(_|>), but if I'm typing that many characters, I might as well just hit the delete key 8 times.

If another way to rephrase the question is "how do I make vim consider _ to be a word delimiter so that I can use dw and other word-related commands with it?", then you can use
:set iskeyword-=_
Vim will then consider _ to be a word separator, allowing you to use dw to delete the text before the underline.
Some other options are mentioned in the answers in this post: Customising word separators in vi

use dw to delete from the cursor to the end of the word
The actual meaning of dw is "delete from the cursor to the next word". It certainly can "delete from the cursor to the end of the word", but only in some cases. de, which actually means "delete from the cursor to the end of the word" seems more appropriate.
Now, Vim has the notion of :help word:
A word consists of a sequence of letters, digits and underscores, or a
sequence of other non-blank characters, separated with white space (spaces,
tabs, <EOL>).
and :help WORD:
A WORD consists of a sequence of non-blank characters, separated with white
space.
For example, in the sample below:
package main
import "fmt"
func main() {
fmt.Println("hello world")
}
all these would be considered as "words", covered by lowercase word motions:
fmt
.
Println
("
hello
world
")
while these would be "WORDS", covered by uppercase word motions:
fmt.Println("hello
world")
And then there is the way w and W handle leading/trailing whitespace to take into account.
See :help word-motions.
I don't want to have to spend the mental energy to decide "is the end I'm trying to delete up to an underscore, or is it the line end? Or is it a period between the table and field names?"
All that to say that Vim can't be expected to read your mind with regard to what you exactly want to delete. Instead, it comes with mildly opinionated defaults and :help 'iskeyword', that you can adjust as you wish.
You are the only one who can decipher the riddle above so yes, you have to spend that mental energy.
Alternatively, you could provide precise and exhaustive requirements so we can help you figure out a way out of this.

Related

Replace a word (or many words) with spaces of same length?

In a general sense, my question is how do I do something like "dw" or "dd", but instead of deleting characters, I want to over-write with spaces?
E.g. lets say I have text:
first second third
if the cursor is on the "s" in second, I can hit "dw" to get:
first third
but what if I want:
first third
Is there a simple way to do that? An ideal solution would be to use the "d" style syntax (e.g. dw, daw, d$, etc.) but with whitespace replacement instead of deletion.
From the start of the word,
Ctrl-v to enter visual block mode,
e to move to the end of the word (highlighting the word in the process),
r[SPACE] to replace the highlighted characters with spaces.
Because of their very nature (the next character must be consumed), r and R can't work like operators. If you want to replace a motion, visually select it first, and then do r<Space> or r_ or whatever.
In this very specific case:
ver<Space>
or:
viwr<Space>
NOTE: I used ve and viw because the semantics of w are inconsistent so I prefer to avoid it when possible.

Yank text between certain words or marks

Is there some vim-magic to yank between two strings?
As example:
#%%
some example
or
some other
#%%
I would like to yank everthing in between (#%%)? Like the "yi(" command.
y works with all motions, which includes /.
/#%% and then wyn would accomplish what you want, where
/#%%: search for the literal symbols #%%. As long as your cursor was above the section you want to yank, this will highlight the first instance.
wyn: move one word forward, to not include #%% in your yank (this assumes #%% is space separated from everything you want to yank). yn just means "yank all text until the next instance of the search".
If you don’t care that :yank is linewise, you could do
:/#%%/+,/#%%/- yank
Since patterns count as addresses, we can write a range that selects the inner text, and then yank it.

Vim: word vs WORD

I'm learning Vim and can't wrap my head around the difference between word and WORD.
I got the following from the Vim manual.
A word consists of a sequence of letters, digits and underscores, or a
sequence of other non-blank characters, separated with white space
(spaces, tabs, ). This can be changed with the 'iskeyword'
option. An empty line is also considered to be a word.
A WORD consists of a sequence of non-blank characters, separated with
white space. An empty line is also considered to be a WORD.
I feel word and WORD are just the same thing. They are both a sequence of non-blank chars separated with white spaces. An empty line can be considered as both word and WORD.
Question:
What's the difference between them?
And why/when would someone use WORD over word?
I've already done Google and SO search, but their search-engine interpret WORD as just word so it's like I'm searching for Vim word vs word and of course won't find anything useful.
A WORD is always delimited by whitespace.
A word is delimited by non-keyword characters, which are configurable. Whitespace characters aren't keywords, and usually other characters (like ()[],-) aren't, neither. Therefore, a word usually is smaller than a WORD; the word-navigation is more fine-grained.
Example
This "stuff" is not-so difficult!
wwww wwwww ww www ww wwwwwwwww " (key)words, delimiters are non-keywords: "-! and whitespace
WWWW WWWWWWW WW WWWWWW WWWWWWWWWW " WORDS, delimiters are whitespace only
To supplement the previous answers... I visualise it like this; WORD is bigger than word, it encompasses more...
If I do viw ("select inner word") while my cursor is on app in the following line, it selects app:
app/views/layouts/admin.blade.php
If I do viW (WORD) while my cursor is at the same place, it selects the whole sequence of characters. A WORD includes characters that words, which are like English words, do not, such as asterisks, slashes, parentheses, brackets, etc.
According to Vim documentation ( :h 03.1 )
A word ends at a non-word character, such as a ".", "-" or ")".
A WORD ends strictly with a white-space. This may not be a word in normal sense, hence the uppercase.
eg.
ge b w e
<- <- ---> --->
This is-a line, with special/separated/words (and some more). ~
<----- <----- --------------------> ----->
gE B W E
If your cursor is at m (of more above)
a word would mean 'more' (i.e delimited by ')' non-word character)
whereas a WORD would mean 'more).' (i.e. delimited by white-space only)
similarly, If your cursor is at p (of special)
a word would mean 'special'
whereas a WORD would mean 'special/separated/words'
That's a grammar problem while understanding the definition of "word".
I get stuck at first in Chinese version of this definition (could be miss-translation).
The definition is definitely correct, but it should be read like that:
A word consists of:
[(a sequence of letters,digits and underscores),
or (a sequence of other non-blank characters)],
separated with white space (spaces, tabs, <EOL>).
Whitespace characters were only needed when delimiting two same types of 'word'
More examples in brackets as follow:
(example^&$%^Example) three "word" :(example), (^&$%^) and (Example)
(^&^&^^ &&^&^) two "word" : (^&^&^^) and (&&^&^)
(we're in stackoverflow) five "word" :(we), ('), (re), (in) and (stackoverflow)
Another way to say it. If ur coding, and want to move thru the line stopping at delimiters and things line that "() . [] , :" use w.
if you want to bypass those and just jump to words lets say like a novel or short story has, use W.
For coding the small w is probably the one used most often. Depends where you are in the code.

In Vim, I'd like to go back a word. The opposite of `w`

When you're using vim, you can move forward word by word with w. How do I go backwards?
Use b to go back a word.
You may also want to check out W and B to advance/go back a WORD (which
consists of a sequence of non-blank characters separated with white space, according to :h WORD).
It helps for me to think of it as:
b to go to beginning of current or previous word
w to go the beginning of next word
e to go to the end of current or next word
ge to go the end of the previous word
Try :h word-motions for more details and how to combine them with operations.
use "b" to move back - just tested in vi - works fine.
Alternatively, if you use w, b, W, and B to navigate lines by hopping over words, consider the following alternatives which can be faster if used correctly.
f<char> # jump to next occurrence of <char> to right (inclusive)
or
F<char> # jump back to next occurrence of <char> to left (inclusive)
If your words are separated by spaces
If your words are separated by <space> you can hop over words by spaces:
f<space>;;;; where ; repeats the previous command, so you hop forward by spaces
F<space>;; to hop backwards by space
If your words are separated by punctuation and not spaces
just replace <char> with punctuation, for example .
The punctuation method is not efficient for scrolling through, but if you know where you want to jump, it can usually get there in a jump or two.

How to reformat "gq"ed text in one line per paragraph format in Vim

I have some text files previously formatted in vim using "gggqG". Now I need to convert them to one line per paragraph format. I saw a way(using :g command) to do that before, but I have forgot it. Anyone knows?
There are two approaches I know of:
Set textwidth to something big and reformat:
:set tw=1000000
gggqG
Use substitute (this is more appropriate if you want to do it in a mapping):
:%s/.\zs\n\ze./ /
Explanation of the latter:
:%s " Search and replace across the whole file
/ " Delimiter
.\zs\n\ze. " Look for a character either side of a new-line (so ignore blank lines).
" The \zs and \ze make the replacement only replace the new-line character.
/ / " Delimiters and replace the new-line with a space.
If your text paragraphs are separated by a blank line, this seems to work:
:g!/^\s*$/normal vipJ
:g global (multi-repeat)
!/^\s*$/ match all lines except blank lines and those containing only whitespace.
normal enters 'normal' mode
vip visually select inner paragraph
J join lines
Maybe you should set textwidth to very large value (like 99999999) (0 does not work for some reason) and use gggqG?
// I cannot tell you a way to reformat your paragraph with :g without knowing exactly what the paragraph is. Maybe somebody else can.

Resources