How to determine horizontal scroll position in vim - vim

In the below vim window represented by visible area, how do I get the horizontal position of X, relative to Y, from a function?
Y------------------------+
1 File contents |
| |
| +-X--------------+ |
| |4| | |
| |5| Visible area | |
| |6| | |
| +-+--------------+ |
$ ^ |
+----|-------------------+
\
line numbers
For example, the vertical position of X relative to Y is four, as in the window is scrolled four rows down. I can get this as a zero-based index with line("w0") - 1.
I how do I determine how many columns rightwards the window is scrolled at a given moment? I've tried virtcol(".") - wincol() but that alone is slightly off if the cursor is over a double-width character.

Here is a solution without modifying the cursor position:
winsaveview().leftcol

If you want to have number column width use max([len(line('$')), &numberwidth])+1.
What does “horizontal position” mean? wincol() is horizontal position in the window, col(".") is byte offset from the start of the line, strchars(getline('.')[:(col('.')-1)]) is the number of unicode codepoints from the start of the line, len(split(getline('.')[:(col('.')-1)], '.\#=')) is the number of characters from the start of the line.

It's unfortunate that vim doesn't have a more direct way to get this, but the following will work
let cursor_pos = getpos('.')
normal g0
let scroll_x = col('.')
setpos('.', cursor_pos)
The trick is the g0 motion, which moves the cursor the left of the window, and from there we can get the current cursor column.

Related

Word Wrap in Vim (preserving indentation) in Latex document

I was just looking at this post which describes how to wrap entire words in vim. I am looking for a way to key the indentation, or in my case, the lack of it.
I usually select a couple lines with V and press gq to reformat it and re-wrap the lines.
Let say, I have the following document
*Inside of window *Outside of window
|---------------------------------------|
|This is a bla like of text that will wr|ap here
|can you see the wrap |
| |
|---------------------------------------|
The result will be:
*Inside of window *Outside of window
|---------------------------------------|
|This is a bla like of text that will |
|wrap here can you see the wrap |
| |
|---------------------------------------|
So far so good.
Now Let say, I have the following document with some latex tags
*Inside of window *Outside of window
|---------------------------------------|
|\begin{abstract} |
|This is a bla like of text that will wr|ap here
|can you see the wrap |
|\end{abstract} |
| |
|---------------------------------------|
The result is the following, which contains an undesirable \t in the next line
*Inside of window *Outside of window
|---------------------------------------|
|\begin{abstract} |
|This is a bla like of text that will |
| wrap here can you see the wrap |
|\end{abstract} |
| |
|---------------------------------------|
But, my goal is to have the result like the following, without the undesirable \t in the next line.
*Inside of window *Outside of window
|---------------------------------------|
|\begin{abstract} |
|This is a bla like of text that will |
|wrap here can you see the wrap |
|\end{abstract} |
| |
|---------------------------------------|
I tried adding set breakindent to my .vimrc but it didn't work. Currently these are the lines I use regarding wrapping.
set wrap " Wrap
set textwidth=79 " Default Text Width
The indentation for Latex is determined by the GetTeXIndent() function (which can be found out via :setlocal indentexpr?). The corresponding script in $VIMRUNTIME/indent/tex.vim has documentation in its header. It mentions (among others) a config setting that affects the indentation of environments.
" * g:tex_noindent_env
"
" A list of environment names. separated with '\|', where no indentation is
" required. The default is 'document\|verbatim'.
If you add the \begin{...} item there (by putting the configuration into your ~/.vimrc), no additional indent will happen:
let g:tex_noindent_env .= '\|begin'
Caveat: I know very little about Latex syntax; this may have unwanted side effects to formatting elsewhere. Read the entire indent documentation to understand your options for tweaking it.

Vim - swap columns with visual mode

I have a markdown table like this.
I want to swap head3 column with head2.
| head1 | head3 | head2 |
|-------|-------|-------|
| foo | baa | none |
| some | text | here |
I can easily cut the column using visual mode (Ctrl-V), but how can I paste the column 'column-wisely'?
Also, which operating is easiert:
cut 'head 3' and paste behind 'head2'
cut 'head 2' and paste before 'head3'?
When you've selected and cut something with Ctrl+V, Vim will paste it as a column too. You can Ctrl+V select the column you want to swap into and paste, and the column you just replaced will now be in your paste register. Go back to the column you cut first and paste one more time to move the replaced column.
In steps:
Use Ctrl+V to select the entire head3 column
x to cut
Use Ctrl+V again to select the entire head2 column
p to paste
Move back to where head3 used to be
p to paste
Move to the first pip | : f+| then to the character right after it by l
Start selecting the column: Ctrl+v
Move to the end of the file: G
Move to the second pip, the one after the header3: 2f+|
Cut the selection: d
Move to the end of the line: $
And finally paste: p
Also, which operating is easiert:
cut 'head 3' and paste behind 'head2'
cut 'head 2' and paste before
'head3'?
For me, both work the same way.

Highlighting ascii tables

Some (ascii) reports I produce contain ascii tables, like this one:
+------+------+------+
| col1 | col2 | col3 |
+======+======+======+
| bla | bla | bla |
| bla | bla | bla |
| bla | bla | bla |
+------+------+------+
I am trying to find a way to highlight such tables using a vim syntax file. A simple highlighting should suffice - no need to distinguish between the |, the =, the + and the -. However, I do not want to highlight the words inside the table (only the skeleton), and I do not want to highlight -, = signs (etc.) outside of the table.
The problem with vim syntax files is that they have no way of determining what's "up" or "down" relatively to a given point. I would be OK with just highlighting per-line, for examples, lines like this:
+------+------+------+
even if they not create nice tables, but the problem is with lines like this:
| col1 | col2 | col3 |
which may be mixed with non-tabular code, like this Python code:
x = y\
| z | u | v # | is here for 'or'
Can you think of a more elegant way of doing so? I've seen ome highlighters (other than vim) which highlight tables quite well...
You can solve this with containmaint, cp. :help :syn contains. First, define a region that spans the entire range of lines that the table is comprised of. I'm using a simplistic pattern for the header / footer line here, and assert that there's no | immediately above / below (in the neighboring line); refine this as needed:
syn region tableRegion start="|\#<!\n+[-+]*+$" end="^+[-+]*+\n|\#!" contains=tableRow
Then, define the (again, simplistic here) pattern to match the table rows, and mark this contained, so it will only match inside other syntax regions that contains= it.
syn match tableRow "^|.*|$" contained

Delete a specific Column in VIM/gvim with out using Visual Block mode

Sample Input File
+--------------------+---------+---------
| Name | S1 | S2
+--------------------+---------+---------
| A | -4.703 | -2.378
| B | -3283.2 | -3204.5
| C | 8779 | 7302
| D | 22078 | 18018
+--------------------+---------+---------
It is required to remove the S1 Column, i.e
Desired Output
+--------------------+---------
| Name | S2
+--------------------+---------
| A | -2.378
| B | -3205.5
| C | 7302
| D | 18018
+--------------------+---------
Can anyone help with this
thanks
Look, ma: no visual (block) mode !
My pragmatic approach wins would be: look for column anchors (-+-)
/-+-
Now, the column deletion is as simple as
d<C-v>N
(delete, block-wise, to the next occurrence of the column anchor from the end of the document).
Job done.
Fancy options
To account for multiple columns, you'd like to be precise about which column to match
This needs a little extra oomph
0f+
:exec '/\%' . col('.') . 'v\v[+|]'Enter
NC-vN
t+d
To see more about this \%22v way to select a virtual column, see
Support in vim for specific types of comments
In command mode:
:%s/^\([[+|][^+|]\+\)[+|][^+|]\+/\1/
This uses vim's built-in sed-like search and replace command. Here's the breakdown:
% - for the entire file
s - search for
/^ - the start of line
\([[+|][^+|]\+\) - followed by + or |, followed by any number (\+) of anything that is not + or |. This will get the first column, which we want to keep, so put it in a capture group by surrounding it with \( and \)
[+|][^+|]\+ - followed by + or |, followed by any number (\+) of anything that is not + or |. This will get the second column, which we don't want to keep, so no capture group.
/\1/ - replace everything we matched with the first capture group (which contains the first column). This effectively replaces the first and second column with the contents of the first column.
Like I said, vim's regex are pretty much identical to sed, so you if you look through this tutorial on sed you'll probably pick up a lot of useful stuff for vim as well.
Edit
In response to the OP's request to make this more generally capable of deleting any column:
:%s/^\(\([[+|][^+|]\+\)\{1\}\)[+|][^+|]\+/\1/
The index inside of the \{\}, now deletes the column indicated. Think of it like an array index (i.e. starts at zero). So \{0\} now deletes the first column, \{1\} deletes the second, and so on.
I would like to write Mathias Schwarz's comment into an answer because Visual Mode is the natural way for the task, although there is already an accepted answer.
Assuming cursor is in ¶
+--------------------+¶--------+---------
| Name | S1 | S2
+--------------------+---------+---------
| A | -4.703 | -2.378
| B | -3283.2 | -3204.5
| C | 8779 | 7302
| D | 22078 | 18018
+--------------------+---------+---------
Use normal command Ctrl-V8jf+d to select S1 column and delete it. Explanation:
Ctrl-V: Enter in Blockwise Visual Mode.
8j: Eigth is the number of rows of the table, it sets cursor at same column but last line.
f+: Move cursor until next + character.
d: delete visual selection.
And result is:
+--------------------+---------
| Name | S2
+--------------------+---------
| A | -2.378
| B | -3204.5
| C | 7302
| D | 18018
+--------------------+---------
If this is the only content of the file, the simplest way is to use this:
:%normal 22|d32|
IF there is more text in the file, specifies the line interval:
:X,Ynormal 22|d32|
Where X and Y is the line interval, for example: 10,17normal 22|d32|
If you're not familiar with the normal command and with the | "motion" there goes a quick explanation:
The normal command execute the following commands in the normal mode;
The | "motion" moves the cursor to a specified column, so 22| moves the cursor to the 22nd column;
Basically what :X,Ynormal 22|d32|does is to move the cursor to the 22nd column (22|) and deletes everything (d) until the 32nd column (32|) for every line specified by X and Y.
Based on patterns of your table, this can be achieved in two simple commands:
:%norm 2f+dF+
:%norm 2f|dF|
Where 2 is your column to remove (1 will remove 1st, 3 - 3rd).
This works as below (for each line at once):
Find second corresponding character of the column (2f+ or 2f|).
Delete backwards to the next found character of the column (dF+ or dF|).
Here is command line approach removing 2nd column in-place:
$ ex +'%norm 2f+dF+' +'%norm 2f|dF|' -scx cols2

Add lines to visual selection via Ex-Mode

Is it possible to add certain lines to a visual selection via an EX-mode command?
I have text in the following form:
+----------+-----------+
| Some text| other text|
+----------+-----------+
| More text||
| And even more ||
| - ...||
+----------+-----------+
And I want the text to be displayed like this:
+---------------+------------+
| Some text | other text |
+---------------+------------+
| More text | |
| And even more | |
| - ... | |
+---------------+------------+
Using the tabular plugin when I delete the lines with + via the following workflow works:
g!/+/d
// Visually select the remaining lines
Tab /|
// Manually insert the +----+----+ lines
I was wondering if there is a way to keep the delimiting lines and visual-select the lines not containing a + via EX-Mode like :g!/+/ add-line-to-visual-selection.
You could use:
:Tab /|\|+/l1
:<range>g/+/s/ /-/g
You can find help for \| in :help /\| or more globally :help pattern, it is the standard way to express alternation in Vim Regular Expressions. So /|\|+/ is a pattern with delimiters that matches either | or +. (Reading the whole :help pattern has excellent return on investment, FYI).
Concerning the /l1 in the Tabular plugin, you can read the help of the plugin more in depth, it will add space after separator and left-align text.

Resources