Is it possible to display grid in Vim? - vim

I am using DrawIt plugin in Vim 7 to draw some ASCII diagrams.
This might be too much, but still—
Is there any plugin which can display a grid in background, to make the drawing easier?

I can't add anything to #David and #romainl's thoughts (I think #romainl's suggestion of using a semi-transparent window with a grid behind it is inspired!).
However, you might find it easier to visualise the cursor position by using:
set cursorline
set cursorcolumn
Of course it's not a substitute for a true grid, but it will at least let you see at a glance the alignment of the cursor.

Let me propose an implementation emulating the guiding grid using Vim
highlighting features. The following function creates the necessary
highlighting taking two mandatory arguments and another two optional ones.
The former two are distances between horizontal and vertical lines,
correspondingly. The latter arguments are the height and the width of the
area covered with grid (in lines and characters, correspondingly). When these
arguments are not specified the number of lines in the buffer and the length
of the longest line in it are used.
function! ToggleGrid(...)
if exists('b:grid_row_grp') || exists('b:grid_prev_cc')
call matchdelete(b:grid_row_grp)
let &colorcolumn = b:grid_prev_cc
unlet b:grid_row_grp b:grid_prev_cc
return
endif
let [dr, dc] = [a:1, a:2]
if a:0 < 4
let [i, nr, nc] = [1, line('$'), 0]
while i <= nr
let k = virtcol('$')
let nc = nc < k ? k : nc
let i += 1
endwhile
else
let [nr, nc] = [a:3, a:4]
endif
let rows = range(dr, nr, dr)
let cols = range(dc, nc, dc)
let pat = '\V' . join(map(rows, '"\\%" . v:val . "l"'), '\|')
let b:grid_row_grp = matchadd('ColorColumn', pat)
let b:grid_prev_cc = &colorcolumn
let &colorcolumn = join(cols, ',')
endfunction

I'm inclined to agree with #romainl; I can't think of any way to do this truly in Vim without mucking around with the source. However, I can think of a few workarounds.
In many terminal emulators, you can set a background image. (xfce4-terminal has this feature, for example). You could design a background where the dimensions of each cell correspond to the space occupied by your monospace font.
Nate Kane's vim-indent-guide might be helpful- it displays vertical lines you could use to align characters. See the screenshots page for some examples.
You could abuse Vim's highlighting to simulate a grid of sorts.

Related

Persistent (sticky) first line or column in VIM

This may be a stretch, but is there a chance to script a vim command such that the first (any?) row is constantly displayed at the top? The first (any) column (defined by a unique delimiter) be constantly displayed in the left?
The best I can manage is to split the screen and maximize the bottom one, so something like
split %
wincmd w
wincmd _
would be good for an upper row, but of course if the row is wider than the screen it doesn't work that well - unless there is a way to start a mode where two windows have their columns aligned.
For a persistent column I'm less sure. Need to somehow get the column of first delimiter (f command I thought, but I couldn't get it to work), vsplit % and vertical resize, then switch, wincmd l. Again this will only work if there are less rows then entire screen.
Doing both is even trickier, but possible using the above. I would also split the title row to make an empty cell at the corner. As far as synchronization, the title has to keep the row but sync on column, and vice-versa for the persistent column.
Is there a way to create such a persistent row+column setup that is synchronized with the main window? Also getting rid of the file names would be useful in this setup.
This is the best I could do, thanks to #DoktorOSwaldo's comment above. F2 and F3 toggle between a bound first column (according to given delimiter) and a bound first row. F4 destroys both:
hi cursorcolumn ctermbg=red
function Title_destroy()
if( winnr() == 1 )
return 0
endif
let oldpos = getpos('.')
wincmd k
wincmd j
hide
call setpos('.',oldpos)
set nocul
set nocuc
endfunction
function Title_bar()
if( winnr() > 1 )
call Title_destroy()
endif
set nowrap
split %
set scb
wincmd j
set scb
wincmd _
set scrollopt=hor
set cuc
endfunction
function Col_bar(delim)
if( winnr() > 1 )
call Title_destroy()
endif
set nowrap
let oldpos = getpos('.')
call setpos('.',[oldpos[0],oldpos[1],0,oldpos[3]])
let width = searchpos(a:delim)[1]+3
call setpos('.',oldpos)
vsplit %
exe 'vertical resize' width
set scb
wincmd l
set scb
set scrollopt=ver
set cul
endfunction
nnoremap <F2> :call Title_bar()<CR>
nnoremap <F3> :call Col_bar(nr2char(getchar()))<CR>
nnoremap <F4> :call Title_destroy()<CR>
I couldn't figure out a way to do both at the same time, since scrollopt is a global thing. If anyone figures it out please leave a comment or answer. Maybe somehow overloading window scrolling to change the scrollopt according to the scroll direction. For now this is good enough for handling large tables (for me).
Upgrades
It's fairly easy to accept a number optional argument - to change the row/column from just first.
Having both a sticky row and a sticky column.

Make sign use only one character width?

Sign is referring to the extra column on the left that is added when using e.g. the syntastic plugin.
I'd like to save on space by having it take up only one column of space, if possible. I can change the sign used to > from >> but it's still two char's wide!
Unfortunately there is no way to modify the width of the sign column. It's hard-coded in Vim at two characters wide.
It's defined in the Vim source in screen.c (line 2149 in vim-73):
# ifdef FEAT_SIGNS
if (draw_signcolumn(wp))
{
int nn = n + 2;
/* draw the sign column left of the fold column */
if (nn > W_WIDTH(wp))
nn = W_WIDTH(wp);
screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - n,
' ', ' ', hl_attr(HLF_SC));
n = nn;
}
# endif
The int nn = n + 2 line is the culprit. You could try to hack it in the source, but I don't know if the rest of the layout depends on a width of 2. Note that this is for the non-GUI implementation; the GUI width is also fixed, but defined elsewhere in the source.
A workaround that works for anyone using set number.
set signcolumn=number will draw signs over the number column:

Smooth color grading given start and end color

What is the best way to control color grading having a start and an end color? Using RGB or HSV ?
E.g
.
step = 1/nrColors;
currStep = 0;
for i = 1:nrColors
p = sigmoid(currStep);
R = start.R * p + end.R * (1-p)
G = ...
B = ...
currStep = currStep + step ;
end
or
H = start.H * p + end.R * (1-p)
S = ...
V = ...
With neither of the above, I could achieve a good transtion (either the colors are too tight to each other, or the colors are not smooth from humans point of view).
Where could I find a good reference on the subject ?
Best,
Theoretically, you will get the best match to human perception if you interpolate in the "Lab" color space:
http://en.wikipedia.org/wiki/CIELAB
Also, a sigmoid interpolation may be appropriate if you are animating a color transition, but if you are displaying a sequence of swatches that smoothly interpolate from one color to another (which is what it sounds like given that you talk about them being too tight to each other), then you might just want to interpolate linearly. Otherwise the start and end colors will be very similar, and the center ones more spaced out.

Smart window resizing with splits in MacVim

I'm using the latest MacVim. Is there any way to have it so if I open MacVim without a file or with only one file, it sets the window width to n characters? Then if I do a vertical split it will expand the window width to 2n characters? Same for 3 vertical splits but it will stop increasing the width after the window is 3n characters. Then if I close those splits it will resize down?
This appears to work. Whether or not a horizontal split has been done, any time a vsplit is created or deleted the window is resized.
let g:auto_resize_width = 40
function! s:AutoResize()
let win_width = winwidth(winnr())
if win_width < g:auto_resize_width
let &columns += g:auto_resize_width + 1
elseif win_width > g:auto_resize_width
let &columns -= g:auto_resize_width + 1
endif
wincmd =
endfunction
augroup AutoResize
autocmd!
autocmd WinEnter * call <sid>AutoResize()
augroup END
Configure the window width by changing the variable at the top. You probably want to do something like let g:auto_resize_width = &columns to set it to use the width of the original window as the width to resize by.
Things get a little wonky if you have so many vsplits that the window becomes maximized horizontally. I'm trying to find a fix and I'll post it if I find one.
I realized that my first post modified window height, not width. Here is what I meant:
Here's a quick solution I came up with, but it's not perfect. The function counts the number of open windows and then sets the window width to original_width * num_windows. The autocommands call the function when Vim starts, and whenever a new window is opened. You can change the default window width (80) to suit your needs.
function! SmartWidth( width )
let num_wins = 0
windo let num_wins+=1
sil exe "set columns=" . num_wins * a:width
sil exe "normal! \<c-w>="
endfunction
autocmd VimEnter * call SmartWidth(80)
autocmd WinEnter * call SmartWidth(80)
This works in the basic case, but does not distinguish between horizontal and vertical splits. I don't know how to do that!

How do I find the RGBA value of a color from two RGB values?

I have a hunch this has been done before but I am a total layman at this and don't know how to begin to ask the right question. So I will describe what I am trying to do...
I have an unknown ARGB color. I only know its absolute RGB value as displayed over two known opaque background colors, for example black 0x000000 and white 0xFFFFFF. So, to continue the example, if I know that the ARGB color is RGB 0x000080 equivalent when displayed over 0x000000 and I know that the same ARGB color is RGB 0x7F7FFF equivalent when displayed over 0xFFFFFF, is there a way to compute what the original ARGB color is?
Or is this even possible???
So, you know that putting (a,r,g,b) over (r1,g1,b1) gives you (R1,G1,B1) and that putting it over (r2,g2,b2) gives you (R2,G2,B2). In other words -- incidentally I'm going to work here in units where a ranges from 0 to 1 -- you know (1-a)r1+ar=R1, (1-a)r2+ar=R2, etc. Take those two and subtract: you get (1-a)(r1-r2)=R1-R2 and hence a=1-(R1-R2)/(r1-r2). Once you know a, you can work everything else out.
You should actually compute the values of a you get from doing that calculation on all three of {R,G,B} and average them or something, to reduce the effects of roundoff error. In fact I'd recommend that you take a = 1 - [(R1-R2)sign(r1-r2) + (G1-G2)sign(g1-g2) + (B1-B2)sign(b1-b2)] / (|r1-r2|+|g1-g2|+|b1-b2), which amounts to weighting the more reliable colours more highly.
Now you have, e.g., r = (R1-(1-a)r1)/a = (R2-(1-a)r2)/a. These two would be equal if you had infinite-precision values for a,r,g,b, but of course in practice they may differ slightly. Average them: r = [(R1+R2)-(1-a)(r1+r2)]/2a.
If your value of a happens to be very small then you'll get only rather unreliable information about r,g,b. (In the limit where a=0 you'll get no information at all, and there's obviously nothing you can do about that.) It's possible that you may get numbers outside the range 0..255, in which case I don't think you can do better than just clipping.
Here's how it works out for your particular example. (r1,g1,b1)=(0,0,0); (r2,g2,b2)=(255,255,255); (R1,G1,B1)=(0,0,128); (R2,G2,B2)=(127,127,255). So a = 1 - [127+127+127]/[255+255+255] = 128/255, which happens to be one of the 256 actually-possible values of a. (If it weren't, we should probably round it at this stage.)
Now r = (127-255*127/255)*255/256 = 0; likewise g = 0; and b = (383-255*127/255)*255/256 = 255.
So our ARGB colour was 80,00,00,FF.
Choosing black and white as the background colors is the best choice, both for ease of calculation and accuracy of result. With lots of abuse of notation....
a(RGB) + (1-a)0xFFFFFF = 0x7F7FFF
a(RGB) + (1-a)0x000000 = 0x000080
Subtracting the second from the first...
(1-a)0xFFFFFF = 0x7F7FFF-0x000080 = 0x7F7F7F
So
(1-a) = 0x7F/0xFF
a = (0xFF-0x7F)/0xFF = 0x80/0xFF
A = 0x80
and RGB = (a(RGB))/a = 0x000080/a = 0x0000FF
You can do something very similar with other choices of background color. The smaller a is and the closer the two background colors are the less accurately you will be able to determine the RGBA value. Consider the extreme cases where A=0 or where the two background colors are the same.

Resources