Remove White space in vim, keep indentation - vim

I am looking to remove all white space in vim, but keep the default indentation as is. Currently all out files use spaces instead of tabs so:
content
content inside[Sneeky white space of epicness]
content
Should be:
content
content inside
content
Note: [Sneeky white space of epicness] represents a block of white space.

Use substitute
%s/ *$//g
$ means end of line.
* means match zero or more instances of the previous element (as suggested by Jite)
Be aware that you could have tab... To represent any white space, use \s
%s/\s*$//g
EDIT:
As suggested by kojiro you could use + instead of *. With a *, vim does the replace on EVERY line. With a +, the replace is done only where it needs to be done in that case.
+ means match at least one instance of the previous element.
With vim you have to escape the +.
See :help pattern-overview for more details.
My final answer :
%s/\s\+$//g

There are several plugins that can detect and (on demand, or even automatically) delete trailing whitespace. My DeleteTrailingWhitespace plugin is one of them, and handles way more cornercases that the simple :%s command usually given. (The plugin page has links to alternative plugins.)

Related

Delete trailing whitespace, alternative to substitute command

To delete trailing whitespace on a line or across a file I can do:
:[range]s/\s\+$//
However, I was wondering for a single line in normal mode if there's an easier approach, for example if the line is:
Hi, I am a line |
And my cursor is past the e, is there a more generic command than doing dTe in normal mode? The next best I could find was dg_, but that goes one too far. And then, one more option might be gElD.
Generic way without :substitute
Use diw to delete multiple whitespace (including tabs) while the cursor is on one of the whitespaces (like in the example).
This works for any whitespace sequence: trailing, leading, etc.
Use dw to delete from the cursor to the end of the sequence. This is useful when you want to re-indent a line or fix alignment.
As this is independent of the first/last character of the previous/next word this is the most generic way.
Using a mapping with :substitute
Use nmap <leader>tr :%s/\s\+$// to remove all trailing whitespace in the whole buffer by pressing \tr (assuming the original mapleader)1.
Replace tr with what ever suits you best.
Omit the the % in the mapping to make it only work on the current line.
--
As a side note: Use set list listchars=trail:· to show trailing whitespace (replace · with any character you like).
--
1 Removing all whitespace may not be what you want, especially when using a version control system and the file contains whitespace not added by yourself.

Is it possible to make vim display leading spaces with a different amount of indentation?

It appears, surprisingly, that more self-selected SO devs prefer to indent via tabs rather than spaces. Some people brought up the argument that you can use tabs to indent, and spaces to align. In theory this sounds cool, but in practice I suspect it would be more of a pain than anything, seeing as you can't see which character you have (unless you like turning on that sort of thing).
So I had an idea - why not the editors? Why shouldn't editors let you configure the number of spaces you're going to use to indent, but also the appearance of those spaces. That is:
Normal:
class MyClass:
____def myfun():
________somevariable = 42
________volts = 40000000 # If you're into that sort of thing.
________________________________# Not well-formatted Python, though.
Leading indent set to appear as 2 spaces:
class MyClass:
__def myfun():
____somevariable = 42
____volts = 400000000
Is it possible to do something like this with vim? I know it's totally possible to write a post-open/pre-save command to replace the contents, which might work the same... but I'm more curious if it's possible, in vim, to make it appear as though the leading spaces are less (or more) than they actually are?
Yes, you can, using the conceal feature. Demonstration (using the markup from your example text and a different replacement character instead of spaces for effect):
:syntax match Indent "\%(^\%(__\)*\)\#<=__" conceal cchar=#
:set conceallevel=2 concealcursor=nvic
The pattern matches every pair of __ at the beginning of the line, and replaces (conceals) each with a single #, effectively reducing the visible indent.
As a purely visual feature, I don't find it very useful though, and would prefer the post-open / pre-save solution you seem to be aware of.

preventing trailing whitespace when using vim abbreviations

I am a new user of vim (gvim in windows), and have found abbreviations a nice time saver - however they would be even better if i could stop the trailing whitespace at times.
I have some directories that i use a lot, and so i added some abbreviation/path pairs to my _vimrc:
:ab diR1 C:/dirA/dira/dir1/
:ab diR2 C:/dirA/dirb/dir2/
etc ...
Now when i type diR1 <space> i get C:/dirA/dira/dir1/[]| where the whitespace is represented by [] and the cursor is the | character. I would like to get rid of the [] == whitespace.
This is a minor complaint: however you seem to be able to customise everthing else in Vim so i figured i'd ask -- is it possible to avoid the trailing whitespace when one uses abbreviations in vim?
An alternate tool used within Vim is a good answer - my objective is to save re-typing frequently used directory structures, but to have the cursor handy as i would almost always add something to the end, such as myFile.txt.
The trailing white space (doubtless due to the fact that the space triggered the abbreviation) which i backspace over before adding myFile.txt to the end is less annoying than typing the whole thing over and over, but it would be ideal if i could avoid doing so ...
pb2q answer is exactly what you want in your current scenario, but does not fully answer the question presented in the title. This exact problem is addressed in the vim help file. See :helpgrep Eatchar. The example it gives is this:
You can even do more complicated things. For example, to consume the space
typed after an abbreviation: >
func Eatchar(pat)
let c = nr2char(getchar(0))
return (c =~ a:pat) ? '' : c
endfunc
iabbr <silent> if if ()<Left><C-R>=Eatchar('\s')<CR>
You would put the Eatchar function in your ~/.vimrc file and then use like so in your abbreviations:
iabbr <silent> diR1 C:/dirA/dira/dir1/<c-r>=Eatchar('\m\s\<bar>/')<cr>
This would "eat" any trailing white space character or a slash. Note that I used iabbr instead of just abbr, because it is rare to actually want abbreviations to expand in command line mode. You must be careful with abbreviations in command line mode as they will expand in unexpected places such as searches and input() commands.
For more information see:
:h abbreviations
:helpgrep Eatchar
:h :helpgrep
This is possible, without more customization than just abbrev.
The abbreviation is being triggered by the space character, as you know. The space is a non-keyword character, and remains after the abbreviation is expanded.
But there are other ways to trigger the expansion, such as other non-keyword characters, including /. So if you instead define your abbreviations like this:
:ab diR1 C:/dirA/dira/dir1
That is, without the trailing path separator, then you can type diR1/, have the abbreviation expand for you because of the slash /, and continue typing, appending to your path with a file name.
Alternately, you can force abbreviation expansion using Ctrl-]. That is, type the abbreviation: diR1, with no following space or other non-keyword character, and then type Ctrl-]. The abbreviation will be expanded and you'll remain in insert mode, and can append your file name to the expanded path.
Check out :help abbreviations, there may be something else useful for you there, including more complicated constructions for always consuming e.g. the space character that triggered the abbreviation.
Instead of abbreviations, you could use mappings. They're expanded as soon as you have typed the last character of the mapping, so there won't be a trailing space:
:inoremap diR1 c:/dirA/dira/dir1
The downside for this approach is that the letters you type while a mapping could be expanded are not displayed until the mapping is finished. This takes some using used to.

How to repeat a substitution the number of times the search word occurs in a row in a substitution command in Vim?

I would like to use tabs in a code that doesn’t use them. What I did until now to implement tabs was pretty handcrafty:
:%s/^ /\t/g
:%s/^\t /\t\t/g
. . .
Question: Is there a way to replace two spaces ( ) by tab (\t) the number of times it was found at the beginning of a line?
There are (at least) three substitution techniques relevant to this case.
1. The first one takes advantage of the preceding-atom matching
syntax to naturally define a step of indentation. According to the
question statement, an indent step is a pair of adjacent space
characters preceded with nothing but spaces from the beginning
of line. Following this definition, one can construct the actual
substitution pattern, right to left:
:%s/\%(^ *\)\#<= /\t/g
Indeed, the pattern designates an occurrence of two literal space
characters, but only when they are preceded by a zero-width match
of the atom just before \#<=, which is the pattern ^ * wrapped in
grouping parentheses \%(, \). These non-capturing parentheses are
used instead of the usual capturing ones, \(, \), since there is no
need in further referring to the matched string of leading spaces. Due
to the g flag, the above :substitute command runs through the
leading spaces pair by pair, and replaces each of them by single tab
character.
2. The second technique takes a different approach. Instead of
matching separate indent levels, one can break each of the lines
starting with space characters down into two lines: one containing
the indenting spaces of the original line, and another holding the
rest of it. After that, it is straightforward to replace all of the pairs
of spaces on the first line, and concatenate the lines back together:
:g/^ /s/^ \+/&\r/|-s/ /\t/g|j!
3. The third idea is to process leading spaces by means of Vim
scripting language. A convenient way of doing that is to use the
substitute with an expression feature of the :substitute command
(see :help sub-replace-\=). When started with \=, the substitute
string of the command enables to substitute the matches of a pattern
with results of evaluation of the expression specified after \=:
:%s#^ \+#\=repeat("\t",len(submatch(0))/2)
If you specifically want to convert spaces into tabs (or vice-versa) at the start of a line, there's the useful :retab command which takes care of that. For example:
:retab! 2 will convert spaces in groups of two to tabs
:set expandtab and then :retab! 2 will convert tabstops (of width 2) back to spaces
See :h :retab (and :h 'ts') for the details.
This is not a general solution for the original problem, but I think it covers the most common use case.
There is no general way of doing this using :s regex's. You can't make the /g modifier look backwards otherwise it'd be unusable, and you can't reliably check that you're at the beginning of the line without looking backwards.
The only way of doing it generally is to loop, like so:
:for i in range(100)
: %s/^\t*\zs /\t/e
:endfor
Which is ugly, slow and highly unrecommended. Use :retab

Highlight positions of the marks in Vim?

I am practising '[ and '], and I cannot see the difference.
How can you highlight the positions of the marks?
Use the showmarks plugin for VIM. It does just that.
vim-signature worked well for showing marks.
showmarks didn't work for me. It also hasn't been updated in nearly a decade.
I find several marks related plugins on GitHub, which shows marks on the signcolumn and provide commands to manage your marks:
vim-signature
vim-markology
vim-markbar
Currently, I am using vim-signature and it works great. You may try these plugins and choose what suits you best.
Your problem may be that the previously changed or yanked text was all on one line. If you use ' with a mark it just takes you to the line, not to the exact character. Use ` instead to get the exact character.
One way to temporarily highlight the region would be to type this:
`[v`]
This will jump to the start change/yank mark, start a visual block and then jump to the end change/yank mark.
Normally you can "blink" the matching delimiter ([{}]) ... using the % (percent sign) command in vi.
(That's not even unique to vim ... it works in other versions of vi as well).
The '[ and '] (single quote, square brackets) are unique to vim as far as I know. They move to the first non-blank character on the first or last line where most recently modified or "put" any text. If your most recent change only only affected a single line then the commands would both move to the same place (as you described).
Note that the ' command (in normal vi as well as vim) is a movement. 'letter (single quote followed by any lower case letter) is a command to move to the locate where a mark was most recently set (using the m command, of course). '' (repeating the single quote command twice) moves to "most recent" cursor location (think of there being a implicit mark there). That's the most recent location from which you initiated a movement or made a change ('[ and '] are ONLY about where you made changes).
For example if I'm on line 100 and I use n to search for the next occurrence of my current search pattern, then '' will get me back to line 100. From there if I type '' again then it will toggle me back to whatever the search (n) command found.
Personally I never use '[ and '] ... I drop a mark using ma (or b, or c or whatever) and then make my changes or pastes before or after the mark I've set, as appropriate.
This command will show the marks:
:match Error /\%'[\|\%']/

Resources