Is this readable?
- Posted by Pete Lomax <petelomax at blueyonder.co.uk> Aug 07, 2005
- 552 views
Bob Elia wrote: >Without knowing how you feel about other people working on your >program, I took the liberty of porting a few features from my never >released Euphoria Editor (originally by David Cuny and Carl White) to Edita. Bob: I welcome almost all requests and suggestions for improvements. Code which already works, which you supplied, even moreso. I have to admit I would probably never have thought it could be done without seeing your code. I saw an opportunity to write bracket match code, so I chose to rewrite rather than modify, which I hope does not bother you too much. I would appreciate comments (from you and and others on EUforum) re the following code. One thing which does not work is jumping to next(/prev) control structure when not on a cs word. I am hesitating, especially since I used the same keystroke for bracket matching, over whether it would be sensible anyway. BTW: For those on EUforum not particularly familiar with Edita source, I am assuming that globals filetext, currfile, CursorX, CursorY, wordChar, TokenChar, MapToByte(), paintCursorY(), forceCursorOnscreen(), and ExpLength(), are sufficiently self-evident.
global procedure ctrlBracket(integer direction) -- -- process ctrl [ and ctrl ]. -- jump to matching [end] procedure/function/type/for/while; -- cycle fwd/back through if/{elsif}/else/endif; -- jump to matching [,], (,), {,}. -- sequence oneline -- scratch var integer bX, -- CursorX of begin position, adjusted k, ch, bracketmatch, -- 0=go for if/while etc; else go for {} etc wordstart, wordend sequence onword sequence r -- local copy of routines[currfile], speedwise integer cS, -- scratch var chunkStart, -- 1..start of 1st routine-1, or: chunkEnd -- start..end of current routine, or: -- end prev rtn+1.. start nxt rtn-1, or: -- end last rtn+1.. end of file. integer len, -- length(oneline), speedwise level, -- stack pointer of saved stuff bracketTarget, -- want stuff at this level skipword, -- after "end" eWord -- scratch (1=end, 2/3=elsif/else) sequence oX,oY -- *The Stack*: examples: -- '{' found line 2 col 7, - trashed, or used, when we find '}', or: -- "if" found line 7 col 9; might be replaced by an elsif/else; -- - trashed, or used, when we find the "end". -- if isEu then --DEV currently checks for "test2.exw" -- if isEu and rtnList then --trace(1) -- -- First determine what we seek -- oneline=filetext[currfile][CursorY+1] k=MapToByte(oneline,CursorX) if k then ch=oneline[k] bracketmatch=find(ch,"(){}[]") else k=length(oneline)+1 bracketmatch=0 end if if not bracketmatch then -- process eg "else" on the e, l, s, or e, equally.. while k>1 and wordChar[oneline[k-1]] = TokenChar do k-=1 end while end if bX=k -- -- Calculate the smallest area to scan -- routines[currfile] contains {names,starts,ends}, -- eg {{"me","my"},{2,10},{8,18}} -- r=routines[currfile] chunkStart=1 chunkEnd=length(filetext[currfile]) for i=1 to length(r[rtnNAMES]) do cS=r[rtnSTART][i] if cS>CursorY+1 then chunkEnd = cS-1 exit end if chunkStart=cS cS = r[rtnEND][i] if cS>=CursorY+1 then chunkEnd = cS exit end if chunkStart=cS+1 end for --setText(Main,sprint({chunkStart,chunkEnd})) -- -- And scan! -- level=0 bracketTarget=-1 skipword=0 oX=repeat(0,32) oY=repeat(0,32) for i=chunkStart to chunkEnd do oneline=filetext[currfile][i] len=length(oneline) k=1 while k<=len do ch=oneline[k] if ch='-' and k<len and oneline[k+1]='-' then -- skip comments exit elsif ch='\"' then --- .. and strings while k<len do k+=1 ch=oneline[k] if ch='\"' then exit end if if ch='\\' and k<len then k+=1 end if end while elsif bracketmatch then -- count {} etc if find(ch,"({[") then level+=1 if level>length(oX) then oX&=repeat(0,32) oY&=repeat(0,32) end if oX[level]=k oY[level]=i -- remember open point if i=CursorY+1 and k=bX then bracketTarget=level -- find close for this end if elsif find(ch,")}]") then if i=CursorY+1 and k=bX and level then -- jump to saved open point paintCursorY() CursorY=oY[level]-1 CursorX=ExpLength(filetext[currfile][CursorY+1][1..oX[level]-1]) forceCursorOnscreen() paintCursorY() return elsif level=bracketTarget then -- we wanted this close point paintCursorY() CursorY=i-1 CursorX=ExpLength(oneline[1..k-1]) forceCursorOnscreen() paintCursorY() return end if level-=1 end if elsif k<=length(oneline) and wordChar[oneline[k]] = TokenChar then wordstart=k while k<length(oneline) and wordChar[oneline[k+1]] = TokenChar do k+=1 end while wordend=k if skipword then skipword=0 else onword = oneline[wordstart..wordend] if find(onword,{"if","for","while","procedure","function","type"}) then level+=1 if level>length(oX) then oX&=repeat(0,32) oY&=repeat(0,32) end if oX[level]=wordstart oY[level]=i -- remember cs start if i=CursorY+1 and wordstart=bX then bracketTarget=level -- find close (or elsif/else) for this end if else eWord=find(onword,{"end","elsif","else"}) if eWord then -- -- This code is significantly complicated by multiple -- elsif/else; basically if we are hunting forward, it is -- all rather easy: landing on the end means goto start; -- except landing on an elsif triggers "next". -- (where "landing" means finding word at {cY,cX}) -- OTOH, backward we must update last jump-back point... -- if i=CursorY+1 and wordstart=bX -- on current word and level>0 -- (sanity chk: structure found) and (direction=-1 or eWord=1) then -- going back or at end paintCursorY() CursorY=oY[level]-1 CursorX=ExpLength(filetext[currfile][CursorY+1][1..oX[level]-1]) forceCursorOnscreen() paintCursorY() return elsif level=bracketTarget -- this level we want and (eWord=1 -- "end"; goto start of control strucure... or (direction=1 -- fwd; *AND* elsif/else *AFTER* start pos. and compare({CursorY+1,bX},{i,wordstart})=-1)) then paintCursorY() CursorY=i-1 CursorX=ExpLength(oneline[1..wordstart-1]) forceCursorOnscreen() paintCursorY() return elsif eWord!=1 and direction=1 and i=CursorY+1 and wordstart=bX then -- fwd, on elsif: trigger "next". -- (nb: this will happen on "else" as well, no matter) bracketTarget=level end if if eWord=1 then skipword = 1 level-=1 elsif direction = -1 -- jumping backward: and level>0 then -- (sanity chk: structure found) -- keep track; replace "if" with "elsif"/"else": oX[level]=wordstart oY[level]=i end if end if end if end if end if k+=1 end while end for -- end if end procedure
Of course, it'll be extra-unreadable because of pigging linewrap... Otherwise, all comments welcome Regards, Pete PS bracketTarget should be renamed...