Dynamic vim font size based on file length - vim

I want vim (MacVim) to default to a large font for new/short files and dynamically scale down to a smaller font (to a set minimum) as the number of lines grows. Is this possible to do with a plugin? What vim concepts will I need to know to write that plugin?
My reason for wanting this is that I love writing code in a large font, but after files get longer I'd rather squint a little than scroll.

That's an interesting idea. Not sure if I'd use it :-) — but it's certainly an interesting idea.
You don't need to write a complete plugin, as all it needs to do is to perform some math. More specifically, a rough formula would be:
Where the desired size (S) depends on the current document number of lines (n), a constant determining what is considered a big file (k, in lines), the desired amplitude (a) — meaning how much will the size vary — and a minimum font size (m).
Now that we know that, it's just a matter of implementing it. Quick notes:
To get n we can call the line() function passing "$" as argument
To set the font size, after we have the number we can build a string and execute it with exec
With that in mind, a quick function quite descriptive could be written as:
function! DetermineFontSize()
let bigFile = 200
let nLines = line("$")
let rate = (nLines > bigFile) ? 0 : (1-nLines/(bigFile*1.0))
exec "set guifont=Menlo:h".float2nr(ceil((rate*5)+11))
endfunction
I'm sure that other Vim masters can improve this a lot. Anyway, a quick explanation:
Set up what we call big file. I've chossen 200 lines for debugging purposes, you probably want a bigger number.
Get the number of lines in the current file.
Do the parenthesis in the previous formula. Note that there is a conditional involved (if you noticed I missed that in the formula, congratulations!). If we have more lines than the maximum constant, 0 is returned. Otherwise, we'd have a negative number — plus calculating something that's obvious.
In the fourth line we build the string to be executed while completing the formula. I choose to hardcode the values for a and m here, since they are used only once and it's easy to modify them. Here a is 5 and m is 11, meaning the font will vary between 11 and 16. The syntax I used here to set the font is valid for Mac. If another reader uses another system you may want to change it accordingly.
Put that in your .vimrc or source it from other file and you'll be ready to test it. On a file with one line, the font is set to 16. If there are 39 lines, also size 16 but size 15 if there are 40. Size goes to 14 when there are 80 lines and so on.
You probably want to call this automatically, so create an auto command as well.
autocmd BufEnter * call DetermineFontSize()
This will work only when you enter a buffer, as the name says. You could change that to include InsertLeave or something like, but keep in mind this will generate more calls to the function. Should not be a performance problem though.
Check :h autocommand-events and build the autocmd as you like.
Update
As ZyX pointed out in the comments, the last line from the function could be written as:
let &guifont='Menlo:h'.float2nr(ceil((rate*5)+11))

vim executes in a terminal. Font size is terminal dependant, so what you ask may be impossible unless your vim ask directly the terminal to change font size... which may be difficult to do.

Related

Is there a way to have vim start line numbering at 0?

I have added the set nu to my vimrc file, and I like it, but I would like to have vim start with line number 0 (it's to match the samples from a book I am using to learn C++).
I saw a suggestion to change set nu to set rnu, and at first it looked good, until I moved downward, and the 0 moved with my cursor. I understand what's going on here - it's displaying a 0 for my current position, and the lines above and below are renumbered relative to where 0 is. While cool, this is not what I want.
Thanks in advance!
Shane
This is not possible without patching the source.
Note that, in Vim, line numbers can be used in many more ways than in "regular" editors so changing how the line numbers are displayed will have a non-negligible impact in other areas. This doesn't seem like a very good idea.

Is there a way to show line numbers at end of the line in Vim

I am using
set relativenumber
set number
which let's me move easily around. However, it is often hard to know the exact the line number of the object where I would like to jump to because I first need to look to the left. I feel it would be easier if I could see the line numbers also on the right hand side right because my eyes have less space to follow (maybe?). I think the ideal setting would be to show the relative/absolute line number where the $ appears when whitespace characters are shown and to the left/right of the buffer. I.e.
1 Random text.$1 1
159 This is the line where the cursor is.$159 159
1 Some random text.$1 1
2 More random text. Another sentence. Maybe a third one? And so on.$2 2
3 Another line which might be quite long and my eyes focus somewhere here.$3 3
4 More random text containing more text and more words and stuff.$4 4
(In this example, I would like to do 3k but I may type 2k or 4k because I did not follow the correct line to the left.)
Is it possible to achieve this somehow?
Any suggestion on how to change my workflow are welcome, too.
Note: Using cursorline does not help as I do not seek the number of the current line.
No, there is no built-in support to your requirement. also I don't think this is easy to be done by plugin.
Maybe you could consider to change your habit/workflow. E.g. enable the cursorline option, to highlight your "current" line, it may let you easier to identify which line are you on right now.
To move cursor, if you don't want to count lines, you may want to try the EasyMotion plugin. It is very handy plugin. However it won't replace the hjkl ... motions.
No, that's not possible, unless you modify Vim's source code in a non-trivial way, or work around with kludges like a vertically split small scratch buffer at the side that is updated via autocmds.
Do you have :set cursorline? That helps (me) a lot to follow the current line, even with large window widths. Reducing those might help, too, though you have to deal with wrapping / scrolling of long lines then.

Move over last editing positionS

I want to see complete list of editing positions, not just a last one like '.
Jumps (<c-o> & <c-i>) are not it, since you can edit few times without any jump.
Is something like that possible or plugin should be implemented ?
EDIT
Enter in the blank line some text<esc> then do 0i1<esc> after that $a2<esc> then o<esc>. I want to have a key to return first to 2 then 1. g;/g, do not do that, they see those 2 edits as single one.
SOLUTION
It appears that this works
set fo=
au InsertEnter * set tw=1
au InsertLeave * set tw=78
After that you can use g; / g,
So basically, you want the functionality of the built-in g; / g, commands without the special treatment described at their :help:
When two undo-able changes are in the same line and at a column position less
than 'textwidth' apart only the last one is remembered. This avoids that a
sequence of small changes in a line, for example "xxxxx", adds many positions
to the change list. When 'textwidth' is zero 'wrapmargin' is used. When that
also isn't set a fixed number of 79 is used. Detail: For the computations
bytes are used, not characters, to avoid a speed penalty (this only matters
for multi-byte encodings).
Unfortunately, you only have two options:
Write your own plugin that records the insert positions (e.g. via an :autocmd InsertLeave, but capturing changes from other modes will be harder), and provides mappings to jump to them.
Modify Vim's source code to adapt the mentioned special treatment to what you have in mind.
Edit: try http://lifehacker.com/202093/go-back-in-text-file-time-with-vim-70
it could be what you were looking for
You may want to try:
:ju (show all the "jumps", ie places where you went in the file. Not always places where you edited, though)
If you want to jump directly to the "position n-3" : 3 <c-o> will do that
Another way: g ; to go back and g , to go forward
Another way: You can "mark" positions, and refer to them later
ma mark the current position and labels it "a"
mb mark another position, and labels it "b"
then
'a goes back to position a, 'b goes to position b.
it also works in commands :
:.,'as/^/# / : add "# " in front of the lines from the current one (.) to the one where mark a is ('a)
(etc)
Another way: to quickly jump to the SAME word you are currently over (usefull to jump from function definition to function usage(s): * (until you reach the one you want)
I think what you want is g-. See also :help :undolist. For full details, read
:help undo-tree
:help usr_32.txt
Edit: As the comment pointed out, this is not what the question asked for. I was really thinking of g; and g,, as mentioned by #Olivier Dulac.

Context sensitive word wrap in vi/vim

How can I can specific word wrapping for specific tags. For example, in LaTex I want word wrapping for my paragraphs but not for my figure commands (they are always very long and run off the screen).
Or with Javascript, I want the right margin for code to be at, for example 50 columns, but for the comments to be at only 40 columns
This is not builtin
You could probably script something yourself using a devious combination of `formatexpr` and synID(). I suggest you look at the help of the latter first, because it contains inspirational samples:
for id in synstack(line("."), col("."))
echo synIDattr(id, "name")
endfor
taken from :he synstack
The formatexpr is usually set to something like
:set formatexpr=mylang#Format()
thus delegating to a filetype plugin. You could implement the function to use different margins for different syntax contexts.
Bear in mind
the default formatexpr (if absent, formatprg) are probably no good for a source file (in my experience it has the tendency to string together lines as if they were text paragraphs). But then again, you can implement it any which way you want
that syntax highlighting may become out of sync. I'm not sure what happens when the cursor is at, say, 70% of a large document and you issue ggVGgq. It might not update the syntax highlighting all the way (meaning that your formatexpr function would get the 'wrong' synID() values. You get around this by saying something like
:syntax sync fromstart
this again might impact the highlighting performance depending on the size/complexity of the source and highlighting scripts

How to get list of files which are currently being diffed in vim

I am writing a vim plugin in which i need to determine all those files which are currently being diffed. That is the ones for which diff is set. I have been going through the manual but could not find much.
Is it possible to do this.
This question is actually related to question how-to-detect-the-position-of-window-in-vim.
In that question i was trying to get the position of window, so as to detect which one of the diffs is the right one and which is left one. The solution i got was to use winnr()
That solution can work only if there are only 2 windows(the ones being diffed). I want to make it generic so that even if multiple windows are open in vim, i can determine which one is on left and which one is right.
This is what i was thinking to solve the problem
Get a list of all listed buffers
For each of this buffers determine if diff is 1 for that
If diff is 1 use bufwinnr() to gets it window number.
From the window numbers determine which one is left and which one is right. left one will have smaller window number
And then determine if current buffer(in which alt-left`alt-right` is pressed) is left or right using winnr of current buffer.
Now the pieces that are missing are 1 and 2. For 1 ls can be used but i need to parse its output. Is there a straightfwd way to get list of all listed buffers. And then is there a way to check if for that buffer diff is 1 or not.
Any suggestions for a simpler solution are also appreciated.
Cycle through all possible buffer numbers from 0 to bufnr('$') and check, whether this buffer exists using bufexists(nr).
Save current buffer number using let curbuf=bufnr('%').
For each existing buffer do execute "buffer ".bufnumber and check &diff variable. Remember two numbers, but do not check bufwinnr().
Do execute "buffer ".curbuf.
Finally call bufwinnr(nr) for two numbers found in step 3.
UPD: another solution
let g:wlist={"0": [], "1":[]}
windo call add(g:wlist[&diff], bufnr('%'))
let g:diffbuffers=g:wlist.1
" here you have list of buffers with &diff option set in g:diffbuffers

Resources