vimrc tab behavior when noexpandtab and softtabstop is less than tabstop - vim

Questions
In the following example:
Why in the first line, a \t is inserted but only 4-col blank is displayed? Shouldn't it be 8 according to tabstop?
Why the two <TAB> hits in the first line and fifth lines have different results? (one is 09 and the other is 20202020)
.vimrc
set noexpandtab
set tabstop=8
set shiftwidth=4
set softtabstop=4
Text
I created the following text by first inserting 8 empty lines and then typing at the beginning of each line, so that there is no shiftwidth generated. (each 4-col blank below is inserted by hitting <TAB>):
1tab done
2tabs done
3tabs done
4tabs done
1tab
2tabs
3tabs
4tabs
hex representation
Then I did :%!xxd, this is what I got (with some trailing newlines):
0000000: 3174 6162 0964 6f6e 650a 3274 6162 7309 1tab.done.2tabs.
0000010: 2020 2020 646f 6e65 0a33 7461 6273 0909 done.3tabs..
0000020: 646f 6e65 0a34 7461 6273 0909 2020 2020 done.4tabs..
0000030: 646f 6e65 0a20 2020 2031 7461 620a 0932 done. 1tab..2
0000040: 7461 6273 0a09 2020 2020 3374 6162 730a tabs.. 3tabs.
0000050: 0909 3474 6162 730a 0a0a 0a0a 0a0a 0a0a ..4tabs.........
Related discussion
There are some pretty good answers here but I still don't understand what is going on in this particular case.

softtabstop is meant to be used that way, it will make your tabs appear a certain length even though they really are the length of tabstop
'softtabstop' 'sts' number (default 0)
...
This is useful to keep the 'ts' setting at its standard value
of 8, while being able to edit like it is set to 'sts'. However,
commands like "x" still work on the actual characters.
As for the weird behaviour of inserting spaces at the beginning, I'm convinced it has to do with smarttab which is on by default and shifts instead of inserting a tab at the beginning of a line.
'smarttab' 'sta' boolean (default on) global
When on, a < Tab> in front of a line inserts blanks according to
'shiftwidth'. 'tabstop' or 'softtabstop' is used in other places. A
will delete a 'shiftwidth' worth of space at the start of the
line.

IGI-111 answered your first question correctly, albeit maybe not clearly enough.
Why in the first line, a \t is inserted but only 4-col blank is displayed? Shouldn't it be 8 according to tabstop?
Keep in mind that TAB doesn't insert a fixed number of blanks, but advances the position to the next multiple of a certain number (if numbered from zero).
What do you mean by "even though they really are the length of
tabstop"?
He must mean that TAB characters, when printed to your terminal, would cause the cursor position to advance to the next multiple of tabstop (8), while pressing Tab in vim advances to the next multiple of softtabstop (4). If this next multiple of softtabstop isn't a multiple of tabstop, vim has to use spaces (0x20).
Why the two <TAB> hits in the first line and fifth lines have different results? (one is 09 and the other is 20202020)
That's because in the first line you hit Tab after you typed 1tab, i. e. you were at position 4 and to advance to position 8, which is a multiple of tabstop, a TAB (0x09) did the job, while in the fifth line you hit Tab at the beginning position 0 and to advance to position 4, which is not a multiple of tabstop, spaces are needed.

Related

vim: replace n strings with another strings

After reading Vim regex replace with n characters, I've known how to replace tabs by spaces:
:%s/^\v(\t)*/\=repeat(repeat(' ',4),strlen(submatch(0)))/g
The command above allows me to replace n tabs at the beginning of each line with n four-spaces.
Now I want to inverse it: replace n four-spaces with n tabs at the beginning of each line, I think the command should be :%s/^\v( )*/\=repeat("\t",strlen(submatch(0)))/g, but it doesn't work: if there is one four-space, it will be replaced by four tabs (but I want to make it only one tab) after executing the command.
Besides, is it possible to get the length of tab of vim so that I can make the command as below?
:%s/^\v(\t)*/\=repeat(repeat(' ',getSizeOfTab()),strlen(submatch(0)))/g
You can get the value of an option in Vimscript by prepending &. So, the size of tab is &tabstop, or &ts. There's also &softtabstop (&sts), pick which one you actually care about.
Whereas you needed to multiply the number of spaces with size of tab, you need to divide the number of tabs. Then there's the remainder to take care of. So, first set your tabstop:
:set ts=4
Then you can convert from tabs to spaces and from spaces to tabs like this:
:%s/^\v(\t)*/\=repeat(repeat(' ',&ts),strlen(submatch(0)))/g
:%s#^\v( )*#\=repeat("\t",strlen(submatch(0))/&ts).repeat(' ',strlen(submatch(0))%&ts)#g
(changed the separator from / to # because I needed / for division :P )
However... it seems you're reinventing the wheel here. :help :retab! and :help 'expandtab'. First set tabstop as above, then:
:set et | ret!
:set noet | ret!
The first one will change tabs to spaces; the second one, spaces to tabs, according to tabstop.

How can I tell Vim to fold GEDCOM files?

GEDCOM files start with a level number 0,1,2, etc., e.g. 2 DATE 10 SEP 1843. The GEDCOM syntax file does not support folding. It should take only a couple of colon commands to tell Vim that it should automatically assign the level number to the line's foldlevel so that zM displays only the level 0 lines, etc. Unfortunately my Vimscript skills are not up to it.
Put these lines inside gedcom.vim:
set foldmethod=expr
foldexpr=getline(v:lnum)

In Vim, there is one line with 10000 characters, how can I select / replace / delete the characters between 1234th to 5678th fast?

There is one line with 10000 characters, how can I select / replace / delete the characters between 1234th to 5678th fast?
Better in Vim, but if emacs can do, it's also good, thanks.
With :substitute:
You can skip the first 1233 characters, and then capture 5678 - 1234 + 1 = 4445 characters, using the :help /\{ multi, and :help /\zs to set the match start:
:substitute/^.\{1233}\zs.\{4445}/REPLACEMENT/
Normal mode
Go to the first character (0, 1233 right, then work on the next 4445 via the 4445l motion. For example, deletion: 01223ld4445l.
Direct addressing
The bad thing about both approaches is that you need to calculate the difference (4445 in your example). You can do that in the command-line via the expression register (<C-r>=5678-1234+1<CR>).
Alternatively, if there are no double-width or tab characters, the screen column can be directly addressed via the :help /\%v regular expression atom, or the | normal mode command:
:substitute/\%1234v.*\%5678v./REPLACEMENT/
or
1234|d5678|
In Emacs, navigate to the line and use move-to-column (bound to M-g TAB by default). Use set-mark-command (C-SPC) to activate the region. M-g TAB 1234 RET C-SPC M-g TAB 5678 RET will select the region of interest. Then you can use narrow-to-region (C-x n n) to narrow the buffer to just the selected region. Narrowing the buffer allows you to edit the narrowed region without affecting the rest. After editing, you can widen with widen (C-x n w).

Highlight specific column in VIM

I work a lot with files which contain data on fixed positions. Non-delimited "CSV" files if you will... Often, I'd like to highlight a specific column.
I tried
:match ErrorMsg /\%>30v.\+\%<40v/
but this runs extremely slow and only matches the first line. I suppose the file may be too large for this. Mind you, the files are very wide (around 40000 characters) but not very long (around 2000 lines). The data originates from old tools over which I have no control.
Example file:
63082
01089
75518 735301
53473 017146
37217
07
940376
762 2842
88331
40680 8928
645718
0131
03522
47210 27431
93837
8825072 49479415
52084 8940
0591705 205635
525429
65339 300
0397
1983
0
2605768
121991 648
3892
1260
Any ideas?
Are you using Vim 7.3?
Apparently they just recently added a colorcolumn option.
Try:
:set colorcolumn=31,32,33,34,35,36,37,38,39
Note that :help 'colorcolumn' says "Will make screen redrawing slower". I somewhat replicated your scenario, though, by using pure blocks of 1234567890 with the exact repetition count you specified.
The command you mentioned is very slow. colorcolumn isn't.
but this runs extremely slow and only matches the first line
By "first line" do you mean the first displayed line, when word wrapping is enabled? Unfortunately colorcolumn will exhibit the same behavior...
This is off the original topic, but Google leads people here. When trying to fix a horribly indented YAML or any other swiftwidth=2 file, I really struggle to visually recognize what is and isn't in a valid column. A comment by #ib to the accepted answer lead me to this gem.
:let &l:colorcolumn = join(range(3,15,2),',')
It basically says set colorcolumn to the comma delimited string value of 3 through 15 counted by 2. (In other words: :set colorcolumn=3,5,7,9,11,13,15) The result looks like this:
You can do a simple :set colorcolumn to see what value results.
To get rid of it do :set colorcolumn=

cindent, smartindent <esc>=% features in vim

I like cindent, smartindent and =% features in vim, which properly indents the code.
But, I have one problem with this, it indents everything with 8 spaces, and if I have few nested ifs, it can be very long line like here, though having so many nested ifs in first place is another question.
4 int main()
5 {
6 if(x)
7 {
8 if(u)
9 {
10 if(y)
11 {
12 }
13 }
14 }
15 }
I tried to set ts=1 and still it doesnt work.
Is there any way to make default indentation level to 4 spaces while using these features?
Edit
set sw=4 solved the problem. No wonder vim always surprises me :)
I believe you're looking for shiftwidth, abbreviated sw.
Edit: a couple quotes from documentation:
shiftwidth: Number of spaces to use for each step of (auto)indent. Used for |'cindent'|, |>>|, |<<|, etc.
tabstop: Number of spaces that a <Tab> in the file counts for.
expandtab: In Insert mode: Use the appropriate number of spaces to insert a <Tab>. Spaces are used in indents with the '>' and '<' commands and when 'autoindent' is on.
smarttab: When on, a <Tab> in front of a line inserts blanks according to 'shiftwidth'. 'tabstop' is used in other places.
Depending on your style, you may have to change more than one of these. Have a look at their help entries if you need more clarification!
Try setting shiftwidth (sw) to 4.
And, if you want to use spaces instead of tabs, set expandtab (et). Then you can change all those tabs to spaces with :retab.

Resources