1. Is this readable?

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...

new topic     » topic index » view message » categorize

2. Re: Is this readable?

At 01:56 AM 8/7/05 +0100, Pete Lomax wrote:

>
>
>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.

Not in the least.  Though I wish I had also included the bracket match code 
which also "jumps" using Ctrl+].
Although some of my code is multi-purpose, your elegant solution makes it 
appear that I created a jackhammer to drive a finishing nail.  I really 
just wanted to get your reaction to the feature.

>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.

I installed your code in place of mine to see how it felt to use.  While I 
still prefer my way, I attribute that to the natural preference for one's 
own children. ;->  In combination with my HOME key mod plus a slight change 
to your code I think it works just fine.

>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.

This change, below, looks on both sides of the cursor for a bracket character,
enabling the user to use the CTRL + arrow keys to land on one if there's no 
intervening white space.

>}}}
<eucode>
>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,"(){}[]")
     ----------------------------------------
     if k > 1 then
         ch = oneline[k - 1]
         bracketmatch = find(ch,"(){}[]")
         if not bracketmatch then
             ch = oneline[k]
             bracketmatch = find(ch,"(){}[]")
         else
             k -= 1
         end if
     elsif 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 
<snip>


control words are not balanced, though mine  does catch one error.  I think 
that this should be addressed.

         Thanks for your interest,

                 Bob

new topic     » goto parent     » topic index » view message » categorize

3. Re: Is this readable?

A line was clipped from my last post (not by me).  Should have read:

BTW, both of our algorithms will jump to a wrong word if, for example, the 
control words are not balanced, though mine  does catch one error.  I think 
that this should be addressed.

         Thanks for your interest,

                 Bob

new topic     » goto parent     » topic index » view message » categorize

Search



Quick Links

User menu

Not signed in.

Misc Menu