implementation module EdTextWindow;

//	Aux. operations for changing text in edit windows.

import StdClass;
import StdString, StdBool, StdInt, StdChar, deltaFont;

import	EdTypes, EdTextConstants, EdConstants, EdLists, EdProgramState, EdSupport, EdText, EdTextFind,
		EdPath;
		
// Text Insert and Delete functions
				
// InsertText :: !Bool !EditWindow !Int !Int !Clipboard -> (!Editor, !WindowUpdate);
InsertText select wd linenr charnr clip
	:== ReplaceText select wd {l1=linenr,c1=charnr,l2=linenr,c2=charnr} clip;
	
// RemoveText :: !EditWindow !PartTSel -> (!Editor, !WindowUpdate);
RemoveText wd tsel
	:== ReplaceText False wd tsel Nil;

// Sets current line and char pos in current line.

// SetCurLine :: !EditWindow !Int !Int -> (!EditWindow, !WindowUpdate);
SetCurLine wd lnr cnr
	:== DoSelectText wd lnr cnr lnr cnr;
	
// Selects the indicated line
	
// SelectLine :: !EditWindow !Int -> (!EditWindow, !WindowUpdate);
SelectLine wd lnr
	:== DoSelectText wd lnr 0 (inc lnr) 0;

//	Selects the entire text

SelectAllText :: !EditWindow -> (!EditWindow, !WindowUpdate);
SelectAllText wd=:{wtext={nrlines}}
	= DoSelectText wd 0 0 nrlines 0;

// AddClipboardWindow :: !EditOptions !NrLines !Text !EditWindows !EditWdIds
//						-> (!EditWindows !EditWdIds,!EditWindow,!EditWdId,!Int,!EditWdId);
AddClipboardWindow eoptions nrlines text editwindows editwdids
	:== AddTextWindow ClpbrdWd eoptions DefaultCompilerOptions EmptyTSel nrlines text
			EmptyPathname EmptyPathname editwindows editwdids;
	
// AddProjectWindow	::	EditOptions !NrLines !Text !Pathname !EditWindows !EditWdIds
//						-> (!EditWindows, !EditWdIds,!EditWindow,!EditWdId,!Int,!EditWdId);
AddProjectWindow eoptions nrlines text path editwindows editwdids
	:== AddTextWindow ProjectWd eoptions DefaultCompilerOptions EmptyTSel nrlines text path
			(RemovePath path) editwindows editwdids;
	
// AddInfoWindow ::	!WdType !EditOptions !NrLines !Text !Editor
//					-> (!EditWindows, !EditWdIds,!EditWindow,!EditWdId,!Int,!EditWdId);
AddInfoWindow wdtype eoptions nrlines text editwindows editwdids
	:== AddTextWindow wdtype eoptions DefaultCompilerOptions EmptyTSel nrlines text EmptyPathname
			(if (wdtype == ErrorWd) ErrorPathname TypePathname) editwindows editwdids;

// AddEditWindow ::	!EditOptions !CompilerOptions !PartTSel !NrLines !Text !Path !Editor
//					-> (!EditWindows, !EditWdIds,!EditWindow,!EditWdId,!Int,!EditWdId);
AddEditWindow eoptions coptions tsel nrlines text path editwindows editwdids
	:== AddTextWindow EditWd eoptions coptions tsel nrlines text path (RemovePath path)
			editwindows editwdids;

//			
// The arrow key function.
//
			
DirectionKey :: !PictureDomain !Bool !KeyMode !Char !EditWindow -> (!EditWindow, !WindowUpdate);
DirectionKey frame select mod_new key oldfr=:{wtext={curline,cursorpos,selection,nrlines}}
	| select
		= (frontb, updateb);
		{
			frontb				= {front & wtext={WinText | front.wtext & selection=selection`}};
			updateb				= {EmptyWindowUpdate &
									oldpos=cursorpos,oldsel=selection,curpos=curpos`,selection=selection`};
		}
		= (fronta, updatea);
		{
			fronta				= {front & wtext={WinText | front.wtext & selection=EmptySelection}};
			updatea				= {EmptyWindowUpdate &
									oldpos=cursorpos,oldsel=selection,curpos=curpos`,selection=EmptySelection};
		}
	where {
	front				= case key of
							{	LeftKey 
									->	(\(window,_,_) -> window) (GoLeftInText False mod_new curline oldfr);
								RightKey
									->	(\(window,_,_) -> window) (GoRightInText False mod_new curline oldfr);
								UpKey
									->	GoUpInText frame mod_new lnr cnr oldfr;
								DownKey
									->	GoDownInText frame mod_new lnr cnr oldfr;
							};
	selection`			= CalcSelection
							pas.ActPasPos.lnr pas.ActPasPos.cnr
								pas.ActPasPos.x pas.ActPasPos.y
									cline`.CurLine.lnr cline`.CurLine.cnr
										curpos`.CursorPos.x curpos`.CursorPos.y;
	cline`				= front.wtext.WinText.curline;
	curpos`				= front.wtext.cursorpos;
	pas					= EW_GetPassivePos curline cursorpos selection;
	nounselect			= IsEmptySelection selection || select;
	upkey				= key == UpKey;
	(lnr,cnr)			= lnr_cnr;
	lnr_cnr	| nounselect= (curline.CurLine.lnr,curline.CurLine.cnr);
			| upkey		= (selection.tsel.l1,selection.tsel.c1);
						= (selection.tsel.l2,selection.tsel.c2);
	};

//
// Removes the char/word just before/after the cursor
//
	
RemoveChars ::	!KeyMode !Bool !EditWindow -> (!EditWindow, !Bool, !Bool, !String, !LineUpdate);
RemoveChars mod_new before_cursor wd=:{wtext={curline,cursorpos,nrlines}}
	| unremoved	= (wd, False, False, "", {oldpos=cursorpos,newpos=cursorpos,width=0});
				= (wd`, True, line_removed, word, {oldpos=cursorpos,newpos=curpos`,width=width});
	where {
	(wd`,word,width)	= wd`_word_width;
	wd`_word_width
		| before_cursor	= GoLeftInText True mod_new curline wd;
						= GoRightInText True mod_new curline wd;
	unremoved			= ( before_cursor && curline.CurLine.lnr == 0 && curline.CurLine.cnr == 0 ) ||
							( not before_cursor && curline.CurLine.lnr == lastlinenr && eol);
							
	eol					= case curline.CurLine.after of
							{	NewlStr:!rest	-> True;
								_				-> False;
							};
								
	lastlinenr			= dec nrlines;
	curpos`				= wd`.wtext.cursorpos;
	
	line_removed
		| before_cursor	= IsEmptyList curline.CurLine.before;
						= case curline.CurLine.after of
							{	NewlStr:!rest	-> True;
								_				-> False;
							};
	};

// Inserts character after the cursor
	
InsertChar :: !Char !EditWindow -> (!EditWindow, !LineUpdate);
InsertChar key wd=:{wstate,wtext=wtext`=:{curline}}
	= (wd`, update);
	where {
	wd`		= {wd &	wstate={wstate & saved=False},
					wtext={wtext` & curline=cline`,cursorpos=update.newpos}};
	cline`	= InsertCharInLine key curline;
	update	= CursorPosInsertCharInLine key cline` wd;
	};
	
// Does the actual char insertion

InsertCharInLine :: !Char !CurLine -> CurLine;	
InsertCharInLine key cline=:{CurLine | before, cnr}
	| key == TabKey
		= {CurLine | cline & changed=True, before = TabStr:! before, cnr = inc cnr};
		= {CurLine | cline & changed=True, before = AddCharBefore key before, cnr = inc cnr};

// Determines the new cursor position after insertion

CursorPosInsertCharInLine :: !Char !CurLine !EditWindow -> LineUpdate;
CursorPosInsertCharInLine key cline` wd=:{wformat={tabw,winfont},wtext={cursorpos}}
	| key == TabKey
		= {width=widtha, oldpos=cursorpos, newpos=newposa};
		{
			newposa		= {cursorpos & vis=False,x=curposa_x,u_d=curposa_x};
			curposa_x	= tabw.ptabw * inc (cursorpos.CursorPos.x / tabw.ptabw);
			widtha		= curposa_x - cursorpos.CursorPos.x;
		}
		= {width=widthb, oldpos=cursorpos, newpos=newposb};
		{
			newposb		= {cursorpos & vis=False,x=curposb_x,u_d=curposb_x};
			curposb_x	= cursorpos.CursorPos.x + widthb;
			widthb		= FontCharWidth key winfont.font;
		};

// Inserts new line at current cursor position
	
InsertLine :: !Bool !EditWindow -> (!EditWindow, !LineUpdate);
InsertLine autoi wd=:{wtext=wtext`=:{nrlines,text,curline,cursorpos},wformat={metrics,tabw},wstate}
	= (wd`, {oldpos=cursorpos,newpos=curpos`,width=0});
	where {
	wd`				= {wd &	wstate={wstate & saved=False},
							wtext={wtext` & text=text`,nrlines=nrlines`,cursorpos=curpos`,curline=cline`}};
	cline`			= {CurLine | curline & changed=True,before=bef,lnr=linenr,cnr=charnr};
	curpos`			= {vis=False,x=cx,y=cy,u_d=cx};
	text`			= Text_InsertLine linenr EmptyLine text1;
	text1			= Text_SetLine curline.CurLine.lnr line text;
	(cx,charnr,bef)	= IndentCurrentLine (tabw.ptabw / tabw.ttabw) tabw.ptabw autoi line;
	cy				= cursorpos.CursorPos.y + metrics.height;
	linenr			= inc curline.CurLine.lnr;
	line			= BeforeToLine curline.CurLine.before;
	nrlines`		= inc nrlines;
	};

//
// Copies the selection in the text window
//
	
CopyText :: !EditWindow !PartTSel -> (!EditWindow, !Clipboard);
CopyText wd=:{wtext=wtext`=:{text,curline}} tsel=:{l1,c1,l2,c2}
	| one_line	= (wd, clipa);
				= (wd`, clipb);
	where {
	(clipa,_,_)				= CutFromCurLine tsel curline;
	clipb					= Text_CopySelection tsel text`;
	wd` | reset				= wd;
							= {wd & wtext={wtext` & text=text`,curline=cline`}};
	(reset,text`,cline`)	= EW_ResetCurLine one_line text curline;
	one_line				= l1 == l2 && l1 == curline.CurLine.lnr;
	};

// Replaces the indicated text by new text in the text window

ReplaceText ::	!Bool !EditWindow !PartTSel !Clipboard -> (!EditWindow, !WindowUpdate);
ReplaceText select wd tsel=:{l1,l2} clip
	=  SetCursorPos_and_Selection wd` select` added.l1 added.c1 added.l2 added.c2 insert;
	where {
	(wd`,insert)			= wd`_insert;
	wd`_insert | one_string	= InsertOneLine wd1 tsel last remove;
							= InsertLines wd1 tsel cliplen last clip remove;
	(wd1,remove)			= wd1_remove;
	wd1_remove | one_line	= RemoveOneLine wd tsel;
							= RemoveLines wd tsel;
	select`					= select && cliplen > 0;
	one_line				= l1 == l2;
	one_string				= cliplen == 1;
	(cliplen,last)			= Length_and_Last clip 0;
	added					= insert.WindowUpdate.added;
	};
	
// Appends the indicated text
	
AppendText :: !EditWindow !Text -> (!EditWindow, !WindowUpdate);
AppendText wd=:{wtext=wtext`=:{text,nrlines,curline},wstate} newtext
	= SetCursorPos_and_Selection wd` False lnr 0 lnr 0 update;
	where {
	wd`					= {wd &	wtext={wtext` & curline=cline`,text=text`,nrlines=nrlines`},wstate={wstate & saved=False}};
	(_,oldtext,_)		= EW_ResetCurLine False text curline;
	text`				= Text_AppendText oldtext newtext;
	nrlines`			= Text_NrLines text`;
	cline`				= {CurLine | changed=False,before=Nil,after=line,lnr=lnr,cnr=0};
	line				= Text_GetLine lnr text`;
	lnr					= dec nrlines`;
	oldlnr				= dec nrlines;
	oldline				= Text_GetLine oldlnr oldtext;
	nrremoved			= LLength removed;
	removed | is_nl		= NewlStr:!Nil;
						= Nil;
	added | is_nl		= {l1=oldlnr,c1=0,l2=lnr,c2=Line_NrChars line};
						= {l1=inc oldlnr,c1=0,l2=lnr,c2=Line_NrChars line};
	is_nl				= LLength oldline == 1 && Select oldline 0 == NewlStr;
	update				= {	WindowUpdate | EmptyWindowUpdate &
									nrremoved=nrremoved,
									removed=removed,
									added=added };
	};
	
//
// Selects the indicated text
//
	
SelectText :: !EditWindow !PartTSel -> (!EditWindow, !WindowUpdate);
SelectText wd tsel=:{l1,c1,l2,c2}
	= DoSelectText wd l1 c1 l2 c2;

/* Aux function: performs the actual selection */

DoSelectText :: !EditWindow !Int !Int !Int !Int -> (!EditWindow, !WindowUpdate); 
DoSelectText wd=:{wtext=wtext`=:{curline,text,nrlines}} l1 c1 l2 c2
	= SetCursorPos_and_Selection wd` select l1` c1` l2` c2` wu`;
	where {
	wu`			= {WindowUpdate | EmptyWindowUpdate & added = {l1=l2`,c1=c2`,l2=l2`,c2=c2`}};
	wd`			= {wd & wtext={wtext` & curline=cline`,text=text`}};
	(_,text`,_)	= EW_ResetCurLine False text curline;
	cline`		= {CurLine | changed=False,before=bef,after=aft,lnr=l2`,cnr=c2`};
	(bef,aft)	= Line_SplitLine c2` line;
	c2` | eot	= nrchars;
		| eol	= nrchars;
				= c2;
	l2` | eot	= dec nrlines;
				= l2;
// RWS ...
	l1`	=	min l1 l2`;
	c1`	=	min c1 c2`;
// ... RWS
	eot			= l2 >= nrlines;
	eol			= c2 >= nrchars;
	nrchars		= Line_NrChars line;
	line		= Text_GetLine l2` text`;
	select		= l1` <> l2` || c1` <> c2`;
	};

//
// Sets the active cursor position to the start or the end of a selection
//

SetActiveCursorPos :: !Bool !EditWindow -> EditWindow;
SetActiveCursorPos start wd=:{wtext=wtext`=:{text,curline,selection,cursorpos}}
	| at_pos	= wd;
				= wd`;
	where {
	at_pos				= IsEmptySelection selection || (curline.CurLine.lnr==ln && curline.CurLine.cnr==cn);
	wd`					= {wd & wtext={wtext` & text=text`,cursorpos=curpos`,curline=cline`}};
	(_,text`,cline1)	= EW_ResetCurLine at_curline text curline;
	cline`				= {CurLine | cline1 & before=bef,after=aft,lnr=ln,cnr=cn};
	curpos`				= {CursorPos | cursorpos & x=cx, y=cy};
	(bef,aft)			= Line_SplitLine cn line;
	line | at_curline	= Line_GlueLine cline1.CurLine.before cline1.CurLine.after;
						= Text_GetLine ln text`;
	(tsel,psel)			= (selection.tsel,selection.psel);
	(ln,cn,cx,cy)		= ln_cn_cx_cy;
	ln_cn_cx_cy | start	= (tsel.l1,tsel.c1,psel.bx,psel.by);
						= (tsel.l2,tsel.c2,psel.ex,psel.ey);
	at_curline			= curline.CurLine.lnr == ln;
	};

//
// Unselects text, sets cursorposition at start/end position of old selection depending on 1st arg.
//
	
UnselectText :: !Bool !EditWindow -> (!EditWindow, !WindowUpdate);
UnselectText up_left wd=:{wtext=wtext`=:{selection,cursorpos,curline,text}}
	= (wd`, update);
	where {
	update			= { EmptyWindowUpdate &
							oldsel		= selection,
							selection	= EmptySelection,
							oldpos		= cursorpos,
							curpos		= curpos` };
	wd`				= {wd & wtext={wtext` & curline=cline`,cursorpos=curpos`,selection=EmptySelection,text=text`}};
	cline` | at_pos	= cline1;
					= {changed=False,before=bef,after=aft,lnr=ln,cnr=cn};	
	(_,text`,cline1)= EW_ResetCurLine at_pos text curline;
	curpos`			= {vis=False,x=cx,y=cy,u_d=cx};
	(bef,aft)		= Line_SplitLine cn (Text_GetLine ln text`);
	(ln,cn)			= ln_cn;
	ln_cn | up_left	= (tsel.l1,tsel.c1);
					= (tsel.l2,tsel.c2);
	(cx,cy)			= cx_cy;
	cx_cy | up_left	= (psel.bx,psel.by);
					= (psel.ex,psel.ey);
	(tsel,psel)		= (selection.tsel,selection.psel);
	cline_left		= curline.CurLine.lnr==tsel.l1 && curline.CurLine.cnr==tsel.c1;
	at_pos			= cline_left == up_left;
	};
	
//
// Sets new text in the window
//
	
SetText :: !NrLines !Text !EditWindow -> EditWindow;
SetText nrlines text wd=:{wstate}
	= {wd &	wtext	= {	selection	= EmptySelection,
						cursorpos	= ZeroCursor,
						text		= text,
						nrlines		= nrlines,
						curline		= cline},
			wstate	= {	wstate & undoinfo = EmptyUndo}};
	where {
	cline	= {changed=False, before=Nil, after=Text_GetLine 0 text, lnr=0, cnr=0};
	};
	
//
// Sets newe tabwidth, font and fontsize in the text window
//

SetTab_and_Font_and_Size :: !Int !FontName !FontSize !EditWindow -> EditWindow;
SetTab_and_Font_and_Size	ttabw fontName size
							wd=:{wtext={curline={CurLine | lnr,cnr},selection=sel=:{tsel={l1,c1,l2,c2}}},wformat}
	= wd`
	where {
	(wd`,_)				= SetCursorPos_and_Selection
								wd1 has_selection l1` c1` l2` c2` EmptyWindowUpdate; 
	wd1					= {wd & wformat={wformat & metrics=metrics,tabw=tabwidth,winfont=wfont}};
	metrics				= {ascent=asct,descent=desc,lead=lead,height=hght};
	tabwidth			= {ttabw=ttabw, ptabw=ptabw};
	wfont				= {fontname=rfontName,fontsize=rfontSize,font=rfont};
	ptabw				= ttabw *  FontCharWidth ' ' rfont ;
	hght				= asct + (desc + lead);
	(asct,desc,_,lead)	= FontMetrics rfont;
	(rfontName, rfontSize,rfont)
		=	EditorGetFont fontName size;
	has_selection		= not (IsEmptySelection sel);
	(l1`,c1`,l2`,c2`)	= l1_c1_l2_c2`;
	l1_c1_l2_c2` | has_selection
						= (l1,c1,l2,c2);
						= (lnr,cnr,lnr,cnr);
	};

// Gets text from the text window
	
GetText	:: !EditWindow -> (!EditWindow, !NrLines, !Text);
GetText wd=:{wtext=wtext`=:{text,nrlines,curline}}
	| reset	= (wd`,nrlines,text`);
			= (wd,nrlines,text`);
	where {
	wd`						= {wd & wtext={wtext` & text=text`,curline=cline`}};
	(reset,text`,cline`)	= EW_ResetCurLine False text curline;
	};

// Adds a new text window

AddTextWindow ::	!WdType !EditOptions !CompilerOptions !PartTSel !NrLines !Text !Pathname !Pathname
					!EditWindows !EditWdIds
					-> (!EditWindows,!EditWdIds,!EditWindow,!EditWdId,!Int,!EditWdId);
AddTextWindow wdtype eo co {l1,c1,l2,c2} nrlines text pathname win_title editwindows editwdids
	= (editwindows`,editwdids`,editwd`,oldid,index,wdid);
	where {
	index							= GetWindowIndex win_title editwindows`;
	(oldid,_)						= GetFrontWindow editwindows;
	(editwindows`,editwdids`,wdid)	= AddWindow wdtype editwd` editwindows editwdids;
	(editwd`,_)						= DoSelectText editwd1 l1 c1 l2 c2;
	editwd1							= {editwd0 & wtext={editwd0.wtext & curline=cline`}};
	editwd0							= NewEditWindow wdtype eo co text pathname nrlines;
	cline`							= {CurLine | changed=False,before=Nil,after=aft,lnr=0,cnr=0};
	aft								= Text_GetLine 0 text;
	};

// Performs a find, replace & find or a find&replace operation depending on the 1st arg.

::	TextReplaceFunction	:==  PartTSel -> FindInfo -> NrLines -> Text -> (!Bool,!ReplacedAll,!PartTSel,!Text);

FindReplaceInText :: !EditWindow !FindInfo !TextReplaceFunction -> (!EditWindow,!Bool,!Bool,!PartTSel,!WindowUpdate);
FindReplaceInText wd=:{wstate,wtext=wtext`=:{text,nrlines,selection,curline}}
				finfo=:{backw,find,replace} find_replace
	| rpl
		= (wd`, fnd, rpl, textpos, {uw` & nrremoved=1, removed=removed, added=added});
	| fnd
		= (wd`, fnd, rpl, textpos, uw`);
		= (wd`, fnd, rpl, textpos, uw`);
	where {
		(wd`,uw`)				= SelectText wd2 sel;
		wd2	| rpl				= {wd &	wtext={wtext` & curline=cline`,text=text`},
										wstate={wstate & saved=False}};
							= {wd &	wtext={wtext` & curline=oldcline,text=oldtext}};
		(fnd,rplcd,sel,text`)	= find_replace textpos finfo nrlines oldtext;
		rpl						= not (IsEmptyList rplcd.ln_cns);
		(removed,added)			= case rplcd.ln_cns of
									{	Nil		-> (Nil,EmptyTSel);
										repl=:{Replaced | lnr,cnr}:!_
											-> (find:!Nil,{l1=lnr,c1=cnr,l2=lnr,c2=cnr+rplcd.len});
									};
		textpos					= EW_GetTextPosition curline selection;
		(_,oldtext,oldcline)	= EW_ResetCurLine False text curline;
		cline`					= {changed=False,before=Nil,after=Text_GetLine 0 text`,lnr=0,cnr=0};
	};

// Applies the replace function (2nd arg.) to the text.

::	TextReplaceAllFunction	:==  Text -> (!Bool,!ReplacedAll,!PartTSel,!Text);

ReplaceAllInText :: !EditWindow !TextReplaceAllFunction -> (!EditWindow, !Bool, !ReplacedAll, !WindowUpdate);
ReplaceAllInText wd=:{wtext=wtext`=:{text,curline},wstate} replace
	| fnd	= (wd`, fnd, replaced, {wu` & added = added, nrremoved = inc tsel.l2});
			= (wd`, fnd, replaced, wu`);
	where {
	(wd`,wu`)					= SelectText wd1 tsel;
	wd1							= {wd & wtext={wtext` & text=text`,curline=cline`},wstate={wstate & saved=False}};
	cline`						= {CurLine | changed=False, before=Nil,after=Text_GetLine 0 text`, lnr=0, cnr=0};
	(fnd,replaced,tsel,text`)	= replace text1;
	added						= {tsel & l1 = 0, c1 = 0};
	(_,text1,_)					= EW_ResetCurLine False text curline;
	};

//	
// Sets current line to the current mouse position. If 1st arg. is True the text between the
// old cursor position and the current one is selected.
//

GotoMousePosition :: !Bool !Int !Int !EditWindow -> (!EditWindow, !WindowUpdate);
GotoMousePosition	select mx my
					front=:{wtext=wtext`=:{curline,text,nrlines,selection,cursorpos},wformat={tabw,winfont,metrics}}
	= (front`,wu);
	where {
	wu					= { EmptyWindowUpdate &
								oldpos		= cursorpos,
								curpos		= curpos`,
								oldsel		= selection,
								selection	= selection` };
	front`				= {front & wtext={wtext` & cursorpos=curpos`,selection=selection`,curline=cline`,text=text`}};
	cline` | in_curline	= {CurLine | cline & before=bef, after=aft, cnr=charnr};
						= {CurLine | changed=False, before=bef, after=aft, lnr=linenr,cnr=charnr};
	curpos`				= {vis=False,x=sx,y=sy,u_d=sx};
	selection` | select	=  CalcSelection
							pas.ActPasPos.lnr pas.ActPasPos.cnr pas.ActPasPos.x pas.ActPasPos.y
								linenr charnr sx sy;
						= EmptySelection;
	(sx,charnr)			= CalcCharNumber mx` tabw.ptabw line winfont.font;
	sy					= PictureTop + linenr * metrics.height;
// RWS ...
	mx`
		| scaledY < 0			// above picture
			=	0;
		| scaledY >= nrlines	// below picture
			=	65535;
		| otherwise				// in picture
			=	mx;
	scaledY
		=	((my - PictureTop) / metrics.height);
	linenr
		=	Between 0 (dec nrlines) scaledY;
//	linenr				= Between 0 (dec nrlines) ((my - PictureTop) / metrics.height);
// ... RWS
	(bef,aft)			= Line_SplitLine charnr line;
	line | in_curline	= Line_GlueLine cline.CurLine.before cline.CurLine.after;
						= Text_GetLine linenr text`;
	pas					= EW_GetPassivePos curline cursorpos selection;
	(_,text`,cline)		= EW_ResetCurLine in_curline text curline;
	in_curline			= curline.CurLine.lnr == linenr;
	};		

// Misc.

Get_3_1	:: (s,t,u) -> s;
Get_3_1 (x,y,z) = x;
