Get length of current line - vim

I'm trying to add an indicator in my statusline for the total length of the line (not just the cursor column position, which can be shown with %c). How do I do this?

To get the contents of a line as a string, use getline(<line number>).
To get the contents of the current line as a string, you can use getline(".").
To get the length of a string, you can use strlen(<string>).
Putting it all together, we get strlen(getline(".")). To add it to your statusline, simply:
statusline += "%{strwidth(getline('.'))}"
or for vim-airline (what I use)
" can be any section; this is for section z (right hand side)
let g:airline_section_z = "%{strlen(getline('.'))}"

Related

How can I paste to next line and enter insert mode on current line?

I'm brand new to vim. A common pattern I am dealing with looks like this
myFunction :: some code
myFunction = some more code
how could I create a command where after executing I look like this
myFunction
myFunction
and am in insert mode with my cursor on the end of the first 'myFunction' ?
If you are copying the first line to the down then maybe try yy for yanking the whole (first) line, P for pasting the line before the cursor and A to go in insert mode at the end of first line.
And you can use :map to do whole thing at one. Like :map 'l yyPA
I have found an almost perfect solution "using ultisnips plugin", the only thing missing is the cursor position. I am considering an already typed text:
You must select the target lines (use vip in normal mode) and use your defined trigger on ultisnips
snippet trigger "Description" w
`!p
import re
snip.rv = re.sub("(^\w+).*", r"\1", snip.v.text, flags=re.MULTILINE)
`
endsnippet

In Vim/NeoVim, how to draw inside text buffer without modifying content

For example, suppose I want to implement a plugin that draws a margin line at 80 colums using custom characters (suppose I want the line to made from a column of * characters).
How can that be done in Vim or Neovim?
But more generically, is there a way to draw stuff over the text buffer without affecting the text content?
For example, how can I draw an inner rectangle inside a window which I can make bright colored in order to show the active window? The effect would be that the first line visible line of what is currently a text buffer would be filled with --- characters, the right-most column of the what is currently a text buffer would be filled with |. This would be inside the window, separate from the statuslines or vertical split lines.
Etc. How to do such things?
Some plugins that currently draw over the text buffer in different ways:
https://github.com/easymotion/vim-easymotion
https://github.com/Yggdroot/indentLine
EasyMotion does not draw over the text, i don't think this is possible.
What it does is defined in following function (sourcecode):
function! EasyMotion#helper#VarReset(var, ...) "{{{
if ! exists('s:var_reset')
let s:var_reset = {}
endif
if a:0 == 0 && has_key(s:var_reset, a:var)
" Reset var to original value
" setbufvar( or bufname): '' or '%' can be used for the current buffer
call setbufvar('%', a:var, s:var_reset[a:var])
elseif a:0 == 1
" Save original value and set new var value
let new_value = a:0 == 1 ? a:1 : ''
" Store original value
let s:var_reset[a:var] = getbufvar("", a:var)
" Set new var value
call setbufvar('%', a:var, new_value)
endif
endfunction "}}}
So it saves every replaced char and restores them afterwards.
I haven't looked at indentLine but it probably does intelligent listchars, as there is never text under the indentchar.
Anyway it isn't as if I am an expert on one of the plugin or vim in general. I just write this answer because i think there are easier way to achieve what you want. You could for example highlight the border lines with a certain color, or change the background for the active split. There is also a plugin for dimming inactive splits: https://github.com/blueyed/vim-diminactive

Append to top and bottom of selected text in vim

So I have the following text (==== delimiters denotes selected text):
This is some text
I'm not interested in.
This is indented text
not important.
=====================
This text portion is
selected.
=====================
Also not important
indented text
Other text i'm not
interested in.
Now I want to create a vim function so that when called, it appends at the top and at the bottom some default text. For example I would like to end with:
This is some text
I'm not interested in.
This is indented text
not important.
THIS TEXT WAS APPENDED
AFTER FUNCTION CALL
This text portion is
selected.
THIS OTHER TEXT WAS
APPENDED AFTER THE SAME
FUNCTION CALL
Also not important
indented text
Other text i'm not
interested in.
Please note that indentation should be preserved (thanks benjifisher)
How can I do this?
This is a little sloppy, but it works:
function! Frame() range
'<put!=\"THIS OTHER TEXT WAS\nAPPENDED AFTER\nFUNCTION CALL\"
'>put=\"THIS OTHER TEXT WAS\nAPPENDED AFTER THE SAME\nFUNCTION CALL\"
endfun
Select your lines in Visual mode, and type
:'<,'>call Frame()
(The range '<,'> is inserted automatically.) There are some advantages to using :execute with a:firstline and a:lastlineas in :help function-range-example, instead of the Visual marks '< and '>, but that gets a little complicated. You could also prefix each command with :silent if you do not care to be told that 3 lines have been added (twice).
Here is a version that copies the indentation from the first and last selected lines, as requested in the updated question. This version uses :call append() instead of :put, which makes it more convenient to use a:firstline and a:lastline; possibly, this will be useful if you ever want to call the function with a range other than the Visual one.
" Add lines at the bottom before adding at the top, since the line numbers
" will change when you add lines.
function! Frame() range
" Define a list of lines and prepend the desired indentation.
let botlines = ['THIS OTHER TEXT WAS', 'APPENDED AFTER THE SAME', 'FUNCTION CALL']
let botspaces = matchstr(getline(a:lastline), '\s*')
let lines = []
for line in botlines
call add(lines, botspaces . line)
endfor
" Now add those lines at the bottom.
call append(a:lastline, lines)
" Now do the same thing at the top.
let toplines = ['THIS OTHER TEXT WAS', 'APPENDED AFTER', 'FUNCTION CALL']
let topspaces = matchstr(getline(a:firstline), '\s*')
let lines = []
for line in toplines
call add(lines, topspaces . line)
endfor
call append(a:firstline - 1, lines)
endfun

Whenever I type colon in insert mode it moves my text to the very beginning of line

Whenever I type a : (colon) it moves all the text on the current line to the beginning of the line, ignoring spaces and tabs.
So if I type
var combo = new Ext.form.ComboBox({
typeAhead //I'm about to type a colon, but right now it looks fine
})
Then I type the colon it moves the text and it now looks like
var combo = new Ext.form.ComboBox({
typeAhead: //text is no longer indented
})
This is a javascript file, so that might be causing the problem?
How can I stop my text from being moved to the beginning of the line when I type a colon?
Adding a colon to the end of a token is causing vim to interpret it as a jump label for C-indenting purposes. :set cino+=L0 should cause it to stay in the current column.
Also, doesn't the JSON syntax allow you to quote the thing that precedes the colon? That should prevent vim from thinking it's a label too.
var combo = new Ext.form.ComboBox({
"typeAhead": "foo" // this isn't a jump label
});

How to improve this vim mapping to format/align similar lines

Recently I was in need of a faster way to format similar code lines according a common character (usually =). For example, I want to format this:
myVar = getMyVar();
myLongerVar = getMyLongerVar();
myYetLongerVar = getMyYetLongerVar();
into that:
myVar = getMyVar();
myLongerVar = getMyLongerVar();
myYetLongerVar = getMyYetLongerVar();
then I wrote the following mappings:
" query used to find the common character. In this case i'm setting it to "find the ="
let g:defformatquery = "f="
" set current line as having the longer size till the common character
nnoremap <Leader>gm 0
\:execute "normal " . g:defformatquery<CR>
\:let b:epos = getpos(".")[2]<CR>
" format current line according to the position acquired above
nnoremap <Leader>g= 0
\:execute "normal " . g:defformatquery<CR>hvgeld
\:execute "normal " . (b:epos - getpos(".")[2]) . "i "<CR>
To use them I have to perform these steps (assuming , is my <Leader>):
position the cursor in the line with the longer text before the = sign (the third line in the example provided, myYetLongerVar)
press: ,gm
for each line I want to format, position the cursor there and press ,g=
Although this works, the process is kinda slow.
I want to create a function that would format the entire selected area at once. Then I could just create one map for the function.
Any ideas?
You should try the Align plugin.
For example, to align some selected lines (selected with v or CTRL-v) according to the = sign, you just type:
:Align =
Or to align from line 34 to 39:
:34,39Align =

Resources