using javascript folds in vim
I discovered a fantastic tool in vim recently – folding.
Now that I’ve learned to use it, I find that I’m addicted! I’ve installed Linux on a few machines in the last few weeks, and each time I do it, I don’t feel complete until I activate it.
To turn on folding for JavaScript, place the following line in your ~/.vimrc
.
let javaScript_fold=1
To show you an example of how it appears, I’m working on the following page: borders.
The JavaScript for that page is getting pretty massive, so folding lets me navigate the file easily. Here’s how the script looks upon opening it with folding inactive:
/* coded by Kae - kae@verens.com */ { /* I'd appreciate any feedback. You have the right to include this in your sites. Please retain this notice. This source has elements coded by Dean Edwards - please read his notices before copying */ } function getCss(){ var els,i; getCss_done=1; // get external stylesheets els=document.getElementsByTagName('link'); for(i=0;i<els.length;++i){ if(els[i].type=='text/css' && els[i].href){ getCss_done=0; getCss_leftToDo++; var x=new XMLHttpRequest(); x.open('GET',els[i].href,true); x.onreadystatechange=function(){ if(x.readyState==4 && (x.status==200 || x.status==304) ){ getCss_text+=x.responseText; getCss_leftToDo--; getCss_parseCssText(); if(!getCss_leftToDo)getCss_done=1; } } x.send(null); } } }
Reasonable, you probably think. But, what if you’re looking for a section of that file and it’s 970 lines long? That’s how long that particular script is so far. The default folding macros supplied by vim turn the above into this:
/* coded by Kae - kae@verens.com */ { /* I'd appreciate any feedback. You have the right to include this in your sites. Please retain this notice. This source has elements coded by Dean Edwards - please read his notices before copying */ } function getCss(){-------------------------------------------------------------------------------------------------------------------------------------------------------- function getCss_parseCssText(){------------------------------------------------------------------------------------------------------------------------------------------- function borderRadius(){-------------------------------------------------------------------------------------------------------------------------------------------------- function borderRadius_waitForCss(){--------------------------------------------------------------------------------------------------------------------------------------- function borderRadius_generateCurves(){----------------------------------------------------------------------------------------------------------------------------------- function sqrt(num){------------------------------------------------------------------------------------------------------------------------------------------------------- function drawRect(el,x,y,w,h,bc,bi,op){-----------------------------------------------------------------------------------------------------------------------------------
Isn’t that great!? Now, to view any particular function, I don’t need to go searching for it – I can just close the one I’m working on (zc
), use my arrow keys to go to the function I want, then open that with zo
.
But, that’s not good enough… The borderRadius_generateCurves()
function is 471 lines long, for example.
So, I took a look inside the vim macro file for JavaScript (/usr/share/vim/vim63/syntax/javascript.vim
).
The language used by the syntax manager is damned ugly looking, so it was a real trial trying to do what I wanted, without screwing everything up. Eventually, I found it. Here’s the code that does the default folding:
if exists("javaScript_fold") syn match javaScriptFunction "\<function\>" syn region javaScriptFunctionFold start="\<function\>.*[^};]$" end="^\z1}.*$" transparent fold keepend syn sync match javaScriptSync grouphere javaScriptFunctionFold "\<function\>" syn sync match javaScriptSync grouphere NONE "^}" setlocal foldmethod=syntax setlocal foldtext=getline(v:foldstart) else syn keyword javaScriptFunction function syn match javaScriptBraces "[{}]" endif syn sync fromstart syn sync maxlines=100
What I wanted, was to fold at every loop, comment, conditional, and function. It was actually quite simple in the end – just replace the above with this:
syn region myFold start="{" end="}" transparent fold syn sync fromstart set foldmethod=syntax set foldtext=getline(v:foldstart) syn sync maxlines=100
Now, the entire file was visible when I opened it:
/* coded by Kae - kae@verens.com */ {------------------------------------------------------------------------------------------------------------------------------------- function getCss(){-------------------------------------------------------------------------------------------------------------------------------------------------------- function getCss_parseCssText(){------------------------------------------------------------------------------------------------------------------------------------------- function borderRadius(){-------------------------------------------------------------------------------------------------------------------------------------------------- function borderRadius_waitForCss(){--------------------------------------------------------------------------------------------------------------------------------------- function borderRadius_generateCurves(){----------------------------------------------------------------------------------------------------------------------------------- function sqrt(num){------------------------------------------------------------------------------------------------------------------------------------------------------- function drawRect(el,x,y,w,h,bc,bi,op){----------------------------------------------------------------------------------------------------------------------------------- /* global variables */ {-------------------------------------------------------------------------------------------------------------------------------------------------- /* load xmlhttprequest compatibility layer, if required */ {-------------------------------------------------------------------------------------------------------------- /* attach the onload event */ {------------------------------------------------------------------------------------------------------------------------------------------- /* the following code was not written by Kae Verens. licenses have been kept */ {-----------------------------------------------------------------------------------------
When I open a function, it doesn’t automatically expand the whole thing now, making it a bit more readable. I can expand it out as I need, and keep the bits I’m not interested in hidden:
function borderRadius_generateCurves(){ /* common variables */ {------------------------------------------------------------------------------------------------------------------------------------------------- for(;i<getCss_rules.length;++i){ rules=getCss_rules[i][1]; /* fix undefined css */ {----------------------------------------------------------------------------------------------------------------------------------------------- /* common variables */ {------------------------------------------------------------------------------------------------------------------------------------------------ if(parseInt(tr[0]) || parseInt(br[0]) || parseInt(bl[0]) || parseInt(tl[0])){ /* common variables */ {----------------------------------------------------------------------------------------------------------------------------------------------- for(;j<els.length;++j){ /* draw border and background */ /* setup border array and common variables */ {----------------------------------------------------------------------------------------------------------------------- /* create background element */ {------------------------------------------------------------------------------------------------------------------------------------- /* generate curved borders */ { if(tr0){ // top right corner----------------------------------------------------------------------------------------------------------------------------------------- if(br0){ // bottom right corner var irx=tppBR0-tppWR,iry=tppBR1-tppWB; var irx2=irx*irx,tmp2=tppHeight-tppBR1; for(var cx=tppBR0-1;cx>-1;--cx){ var cx2=cx*cx,ind=tppWidth-tppBR0+cx; var h=(cx<irx)?sqrt(iry*iry*(1-cx2/irx2)):0; b_arr[ind][2]=tmp2+h; b_arr[ind][3]=tmp2+sqrt(tppBR1*tppBR1*(1-cx2/(tppBR0*tppBR0))); } } if(bl0){ // bottom left corner--------------------------------------------------------------------------------------------------------------------------------------- if(tl0){ // top left corner------------------------------------------------------------------------------------------------------------------------------------------ } /* fill in the background */ {---------------------------------------------------------------------------------------------------------------------------------------- /* draw borders */ {-------------------------------------------------------------------------------------------------------------------------------------------------- theEl.parentNode.insertBefore(bgw,theEl); } for(j=0;j<els.length;j++){ // remove the original border and adjust the padding accordingly --------------------------------------------------------------------------- } } /* show timer */ {------------------------------------------------------------------------------------------------------------------------------------------------------- }
Note that I’ve managed to contract comments as well. You do that by using the {
and }
symbols:
/* coded by Kae - kae@verens.com */ { /* I'd appreciate any feedback. You have the right to include this in your sites. Please retain this notice. This source has elements coded by Dean Edwards - please read his notices before copying */ }
That trick can also be used to close switch
es as well:
switch(parts2[0]){ case 'background': {-------------------------------------------------------------------------------------------------------------------------------------------------- case 'border': {------------------------------------------------------------------------------------------------------------------------------------------------------ case 'border-color': {------------------------------------------------------------------------------------------------------------------------------------------------ case 'border-radius': {----------------------------------------------------------------------------------------------------------------------------------------------- case 'border-top-right-radius': { m=(parts3L>1)?parts3[0]+' '+parts3[1]:parts3[0]+' '+parts3[0]; getCss_rules[a][1]['border-top-right-radius']=m; break; } case 'border-top-left-radius': {-------------------------------------------------------------------------------------------------------------------------------------- case 'border-bottom-right-radius': {---------------------------------------------------------------------------------------------------------------------------------- case 'border-bottom-left-radius': {----------------------------------------------------------------------------------------------------------------------------------- case 'border-style': {------------------------------------------------------------------------------------------------------------------------------------------------ case 'border-width': {------------------------------------------------------------------------------------------------------------------------------------------------ default: {------------------------------------------------------------------------------------------------------------------------------------------------------------ }
Well, that’s the longest thing I’ve written in a while… I hope it’s useful to someone!
Great post.
Don’t think I got all of it, but went running off to find out about folding. Isn’t that the smartest thing you ever saw! Gobsmacking.
I even got the “let php_folding=1” line (Note let not “set php_…”) added to my .vimrc file so all existing scripts fold up automatically without me doing a damn thing.
Thks for the heads up!
Pingback: » neatly indented folds in vim « klog
Pingback: Holy Shmoly! :: Vim folding redux
Pingback: quatroparedes » Blog Archive » Vim goodies
I created a VIM script called phpfolding.vim on vim.org and it folds php functions and classes. It supports PHPDoc API comments too, like the following function:
/**
* This does foo and bar
* @param bar some description
*/
function foo($bar)
{
// …
}
Is folded into this:
+– 9 lines function foo($bar)—————————————
As a PHP developer I use this alot and thought people might find this useful. You can find it here: http://www.vim.org/scripts/script.php?script_id=1623
Pingback: Confusion about vim folding - how to disable? - The Citrus Report