ftp.nice.ch/pub/next/text/etext/eText5-0.93.Source.NIHS.tar.gz#/eText5/eText.subproj/eText.XText.m

This is eText.XText.m in view mode; [Download] [Up]

{\rtf0\ansi{\fonttbl\f0\fmodern Courier;\f1\ftech Symbol;\f2\fmodern Ohlfs;}
\margl40
\margr40
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f0\b0\i0\ulnone\fs24\fc0\cf0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\
//
\i 	
\b FILENAME
\b0 :	
\b\i0 eText.XText.m\

\b0 //
\i 	
\b SUMMARY
\b0 :	
\b\i0 Implementation of the XText keybinding subsystem of eText
\b0 \
//	
\b\i CATEGORY
\b0 :
\i0 	
\b XText
\b0 \
//	
\b\i PROTOCOLS
\b0 :
\i0 	
\b Uses XTActions
\b0 \
//	
\b\i INTERFACE
\b0 :
\i0 	
\b None
\b0 \
//	
\b\i AUTHOR
\b0 :		
\b\i0 Rohit Khare, portions by Mike Dixon
\b0 \
//	
\b\i COPYRIGHT
\b0 :	
\f1\i0 Ó
\f0\b 1993,94 California Institure of Technology, eText Project\

\b0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\
//	
\b\i Description
\b0\i0 \
//		There is code related to XText initialization in eText.Class.m.\
//ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\
//	
\b\i History
\b0\i0 \
//	10/18/94:	
\b Cleaned up for eText5.
\b0 \
//	08/05/94:	
\b Completely Rearchitected for 5.0. RK
\b0 \
//ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\
//	
\b Imported Interfaces
\b0 \
//\
	#import "
\b eText.XText.h
\b0 "\
\
//	
\i A (not very elegant) table format for storing the initial emacs bindings.\

\i0 //
\i 	Unused args are indicated by the magic value 99.
\i0 \
typedef struct \{\
	const 
\b SEL
\b0  	*
\b sel
\b0 ;\
	
\b short
\b0  		
\b arg1
\b0 ;\
	
\b short
\b0  		
\b arg2
\b0 ;\
	
\b keyCode
\b0  	
\b key
\b0 ;\
\} 
\b tbl_entry
\b0 ;\
\
//	
\i For these and other key codes, refer to\

\i0 //	
\i /NextLibrary/Documentation/NextDev/Summaries/06_KeyInfo/KeyInfo.rtfd\

\b\i0 tbl_entry
\b0  
\b emacs_base
\b0 [] = \{\

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx6340\tx8000\fc0\cf0 \{&@selector(
\b moveChar:mode:
\b0 ), -1,  0, 0x351\},	// 
\i ctrl-b  	move back char
\i0 \
\{&@selector(
\b moveChar:mode:
\b0 ), -1,  1, 0x401\},	// 
\i ctrl-h  	delete back char
\i0 \
\{&@selector(
\b moveChar:mode:
\b0 ), -1,  3, 0x353\},	// 
\i ctrl-B  	select back char
\i0 \
\{&@selector(
\b moveChar:mode:
\b0 ),  1,  0, 0x3c1\},	// 
\i ctrl-f	move fwd char
\i0 \
\{&@selector(
\b moveChar:mode:
\b0 ),  1,  1, 0x3b1\},	// 
\i ctrl-d  	delete fwd char
\i0 \
\{&@selector(
\b moveChar:mode:
\b0 ),  1,  3, 0x3c3\},	// 
\i ctrl-f  	select fwd char
\i0 \
\{&@selector(
\b moveWord:mode:
\b0 ), -1,  0, 0x354\},	// 
\i alt-b   	move back word
\i0 \
\{&@selector(
\b moveWord:mode:
\b0 ), -1,  1, 0x1b4\},	// 
\i alt-del 	delete back word
\i0 \
\{0,							   0,  0, 0x404\}, 	// 
\i alt-h  	(ditto)
\i0 \
\{&@selector(
\b moveWord:mode:
\b0 ), -1,  3, 0x356\},	// 
\i alt-B   	select back word
\i0 \
\{&@selector(
\b moveWord:mode:
\b0 ),  1,  0, 0x3c4\},	// 
\i alt-f   	move fwd word
\i0 \
\{&@selector(
\b moveWord:mode:
\b0 ),  1,  1, 0x3b4\},	// 
\i alt-d   	delete fwd word
\i0 \
\{&@selector(
\b moveWord:mode:
\b0 ),  1,  3, 0x3c6\},	// 
\i alt-F  	select fwd word
\i0 \
\{&@selector(
\b moveLine:mode:
\b0 ), -1,  0, 0x081\},	// 
\i ctrl-p  	move back line
\i0 \
\{&@selector(
\b moveLine:mode:
\b0 ), -1,  3, 0x083\},	// 
\i ctrl-P  	select back line
\i0 \
\{&@selector(
\b moveLine:mode:
\b0 ),  1,  0, 0x371\},	// 
\i ctrl-n  	move fwd line
\i0 \
\{&@selector(
\b moveLine:mode:
\b0 ),  1,  3, 0x373\},	// 
\i ctrl-N  	select fwd line
\i0 \
\{&@selector(
\b lineBegin:
\b0 ),	   0, 99, 0x391\}, 	// 
\i ctrl-a  	move to line begin
\i0 \
\{&@selector(
\b lineBegin:
\b0 ),	   3, 99, 0x393\}, 	// 
\i ctrl-A  	select to line bgn
\i0 \
\{&@selector(
\b lineEnd:
\b0 ),		   0, 99, 0x441\},	// 
\i ctrl-e  	move to line end
\i0 \
\{&@selector(
\b lineEnd:
\b0 ),		   1, 99, 0x3e1\}, 	// 
\i ctrl-k  	delete to line end
\i0 \
\{&@selector(
\b lineEnd:
\b0 ),		   3, 99, 0x443\}, 	// 
\i ctrl-E  	select to line end
\i0 \
\{&@selector(
\b docBegin:
\b0 ),	   0, 99, 0x2e6\}, 	// 
\i alt-<   	move to doc begin
\i0 \
\{&@selector(
\b docEnd:
\b0 ),		   0, 99, 0x2f6\}, 	// 
\i alt->   	move to doc begin
\i0 \
\{&@selector(
\b collapseSel:
\b0 ),   0, 99, 0x381\}, 	// 
\i ctrl-spc	collapse selection
\i0 \
\{&@selector(
\b transChars
\b0 ),	  99, 99, 0x481\}, 	// 
\i ctrl-t  	transpose chars
\i0 \
\{&@selector(
\b setNextAction:
\b0 ), 0, 99, 0x421\},	// 
\i ctrl-q  	quote next key
\i0 \
\{&@selector(
\b insertNextChar
\b0 ), 99, 99, 0x425\},	// 
\i ctrl-alt-q really quote key
\i0 \
\{&@selector(
\b openLine
\b0 ),		 99, 99, 0x071\}, 	// 
\i ctrl-o  	open line
\i0 \
\{&@selector(
\b scroll::
\b0 ),		  1, -1, 0x341\}, 	// 
\i ctrl-v  	scroll fwd page
\i0 \
\{0,							  0,  0, 0x0f6\},  	// 
\i alt-shft-down (ditto)
\i0 \
\{&@selector(
\b scroll::
\b0 ),		 -1,  1, 0x344\}, 	// 
\i alt-v   	scroll back page
\i0 \
\{0,							  0,  0, 0x166\}, 	// 
\i alt-shft-up(ditto)
\i0 \
\{&@selector(
\b scroll::
\b0 ),		  0,  4, 0x343\},	// 
\i ctrl-V  	scroll fwd 4 lines
\i0 \
\{&@selector(
\b scroll::
\b0 ),		  0, -4, 0x346\}, 	// 
\i alt-V   	scroll back 4 lines
\i0 \
\{&@selector(
\b scroll::
\b0 ),	  -9999,  0, 0x165\}, 	// 
\i alt-ctrl-up scroll to start
\i0 \
\{&@selector(
\b scroll::
\b0 ),	   9999,  0, 0x0f5\}, 	// 
\i alt-ctrl-down  scroll to end
\i0 \
\{&@selector(
\b scrollIfRO::
\b0 ),   1, -1, 0x380\},	// 
\i space   	scroll fwd pg if RO
\i0 \
\{&@selector(
\b scrollIfRO::
\b0 ),  -1,  1, 0x1b0\},	// 
\i del     	scroll back pg if RO
\i0 \
\{&@selector(
\b scrollIfRO::
\b0 ),   0,  4, 0x382\},	// 
\i shift-sp	scroll fwd 4 lines
\i0 \
\{&@selector(
\b scrollIfRO::
\b0 ),   0, -4, 0x1b2\}, 	// 
\i shft-del	scroll back 4 lines
\i0 \
\{&@selector(
\b scrollSelToVisible
\b0 ),\
							 99, 99, 0x2d1\}, 	// 
\i ctrl-l  	scroll to selection
\i0 \

\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 \{0, 0, 0\}\
\};\
\
void 
\b initbase_emacs
\b0 (
\b actionTbl
\b0  actions, 
\b NXZone
\b0  *zone)\
\{\
	keyCode i;\
	
\b tbl_entry
\b0  *e;\
	
\b XTAction
\b0  *a = [XTAction 
\b undefinedAction
\b0 ];\
\
	// 
\i make all non-command control & alt combinations invoke "unboundKey"
\i0 \
	for (i=0; i<KEY_CODES; i+=16) \{\
		actions[i+1] = actions[i+3] = actions[i+4] = actions[i+5]\
			= actions[i+6] = actions[i+7] = a;\
	\}\
\
	// 
\i ... except for ctrl-i (a handy substitute for tab)
\i0 \
	actions[6*16 + 1] = nil;\
\
	// 
\i and then install the emacs key bindings
\i0 \
	for (e=
\b emacs_base
\b0 ; (e->key != 0); ++e) \{\
		if (e->sel == 0) \{\}\
			// 
\i same action as previous binding
\i0 \
		else if (e->arg1 == 99)\
			a = [[
\b XTMsg0Action
\b0  allocFromZone:zone] initSel:*(e->sel)];\
		else if (e->arg2 == 99)\
			a = [[
\b XTMsg1Action
\b0  allocFromZone:zone]\
					initSel:*(e->sel) arg:e->arg1];\
		else\
			a = [[
\b XTMsg2Action
\b0  allocFromZone:zone]\
					initSel:*(e->sel) arg:e->arg1 arg:e->arg2];\
		actions[e->key] = a;\
	\}\
\}\
\

\i @implementation eText(XText)\

\i0 //ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\
//	
\b XText0 Management
\b0 \
//\
- 
\b setErrorStream
\b0 :errs \{\
	// 
\i Egregious paranoia
\i0 \
	if ([errs 
\b respondsTo
\b0 : @selector(
\b report:
\b0 )]) errorStream = errs;\
	else [errorStream report:"
\b Invalid argument to setErrorStream:
\b0 "];\
	return self;\
\}\
- 
\b errorStream
\b0  \{\
	return 
\b errorStream
\b0 ;\}\
\
- 
\b setInitialAction
\b0 :action \{\
	
\b initialAction
\b0  = 
\b nextAction
\b0  = action; return self;\}\
- 
\b initialAction
\b0  \{\
	return 
\b initialAction
\b0 ;\}\
- 
\b setNextAction
\b0 :action \{\
	
\b nextAction
\b0  = action; return self;\}\
\
- 
\b unboundKey 
\b0 \{\
	
\b NXBeep
\b0 (); return self;\}\
- 
\b keyDown
\b0 :(
\b NXEvent
\b0  *)event \{\
	id temp;\
\
	
\b temp
\b0  = 
\b nextAction
\b0 ;\
	
\b nextAction
\b0  = 
\b initialAction
\b0 ;\
	if (
\b temp
\b0 ) \{\
		temp = [
\b temp
\b0  
\b applyTo
\b0 :
\b self
\b0  
\b event
\b0 :
\b event
\b0 ]; // 
\i this could turn autoD off...
\i0 \
		if (vFlags.
\i disableAutodisplay
\i0 ) \{		// 
\i this turns it back on...\

\i0 			[self 
\b setAutodisplay
\b0 :YES];\
			[[self superview] 
\b display
\b0 ];\
		\}\
		if (temp && (
\b sp0
\b0 .cp == 
\b spN
\b0 .cp))         \
		// 
\i RK: Added temp check to prevent setSel from lousing up the typingRun's font selection\

\i0 			[self 
\b setSel
\b0 :
\b sp0
\b0 .cp :
\b sp0
\b0 .cp];       // 
\i hack to make caret reappear
\i0 \
	\}\
	return 
\b temp
\b0  ? 
\b self
\b0  : [
\b super
\b0  
\b keyDown
\b0 :event];\
\}\
\
//ÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐ\
//	
\b XText Operations (emacs)
\b0 \
//\
- 
\b goto
\b0 :(int)pos 
\b end
\b0 :(int)end 
\b mode
\b0 :(int)mode \{\
	int start;\
	\
	
\b switch
\b0 (
\b mode
\b0 ) \{\
\
	case 
\b 0
\b0 :		// 
\i move
\i0 \
		[self 
\b setSel
\b0 :pos :pos];\
		[self 
\b scrollSelToVisible
\b0 ];\
		posHint = -1;\
		break;\
\
	case 
\b 1
\b0 :		// 
\i delete
\i0 \
	case 
\b 2
\b0 :		// 
\i cut
\i0 \
		if (pos != end) \{\
			start = pos;\
			if (start > end)\
				\{ start = end; end = pos; \}\
			[self 
\b setSel
\b0 :start :end];\
			if (mode == 1)\
				[self 
\b delete
\b0 :self];\
			else\
				[self 
\b cut
\b0 :self];\
		\}\
		posHint = -1;\
		break;\
\
	case 
\b 3
\b0 :		// 
\i select
\i0 \
		start = pos;\
		if (start > end)\
			\{ start = end; end = pos; \}\
		// 
\i The Text object can't even extend the selection without flashing,
\i0 \
		// 
\i unless we disable autodisplay
\i0 \
		//
\i if (sp0.cp != spN.cp)
\i0 \
		//	
\i [self disableAutodisplay];
\i0 \
		[self 
\b setSel
\b0 :
\b start
\b0  :
\b end
\b0 ];\
		posHint = pos;\
		break;\
	\}\
	
\b xHintPos
\b0  = 
\b -1
\b0 ;\
	return self;\
\}\
\
- 
\b moveChar
\b0 :(int)cnt 
\b mode
\b0 :(int)mode \{\
	int pos, end;\
	int 
\b max
\b0  = [self 
\b textLength
\b0 ];\
	\
	if (sp0.cp == 
\b posHint
\b0 ) \{\
		pos = sp0.cp + cnt;\
		end = spN.cp;\
	\} else \{\
		pos = spN.cp + cnt;\
		end = sp0.cp;\
	\}\
	if (pos < 0)\
		pos = 0;\
	else if (pos > max)\
		pos = max;\
	return [self 
\b goto
\b0 :pos 
\b end
\b0 :end 
\b mode
\b0 :mode];\
\}\
\
- 
\b moveWord
\b0 :(int)cnt 
\b mode
\b0 :(int)mode \{\
    NXStream *s = [self stream];\
	char c;\
	int i, pos, end;\
	unsigned char digit_cat = charCategoryTable['0'];\
	unsigned char alpha_cat = charCategoryTable['a'];\
	unsigned char c_cat;\
	BOOL inWord = NO;\
\
	if (cnt == 0)\
		return self;\
	if (sp0.cp == posHint) \{\
		pos = sp0.cp;\
		end = spN.cp;\
	\} else \{\
		pos = spN.cp;\
		end = sp0.cp;\
	\}\
	NXSeek(s, pos, NX_FROMSTART);\
	i = (cnt<0 ? -cnt : cnt);\
	while (1) \{\
		c = (cnt<0 ? NXBGetc(s) : NXGetc(s));\
		if (c == EOF) break;\
		c_cat = charCategoryTable[c];\
		if (c_cat==alpha_cat || c_cat==digit_cat)\
			inWord = YES;\
		else if (inWord) \{\
			--i;\
			if (i > 0)\
				inWord = NO;\
			else\
				break;\
		\}\
	\}\
	pos = NXTell(s);\
	if (c != EOF)\
		pos += (cnt<0 ? 1 : -1);\
	return [self 
\b goto
\b0 :pos 
\b end
\b0 :end 
\b mode
\b0 :mode];\
\}\
\
- 
\b moveLine
\b0 :(int)cnt 
\b mode
\b0 :(int)mode \{\
	int pos, end, x, dir;\
\
	if (sp0.cp == posHint) \{\
		pos = sp0.cp;\
		end = spN.cp;\
	\} else \{\
		pos = spN.cp;\
		end = sp0.cp;\
	\}\

\i 	//if (mode != 0)\
	//	[self disableAutodisplay];\
	// collapse and normalize the selection\

\i0 	[self 
\b setSel
\b0 :pos :pos];\
	x = (sp0.cp == xHintPos ? xHint : (sp0.cp - sp0.c1st));\
	\
	if (cnt < 0) \{\
		dir = NX_UP;\
		cnt = -cnt;\
	\} else \{\
		dir = NX_DOWN;\
	\}\
	for (; cnt > 0; --cnt)\
		[self moveCaret: dir];\
\
	pos = 
\b LINE_LENGTH
\b0 (sp0.line)-1;\
	if (x < pos)\
		pos = x;\
	pos += sp0.c1st;\
	[self 
\b goto
\b0 :pos 
\b end
\b0 :end 
\b mode
\b0 :mode];\
	xHintPos = pos;\
	xHint = x;\
	return self;\
\}\
\
- 
\b lineBegin
\b0 :(int)mode \{\
	int pos, end;\
\
	if (sp0.cp == posHint) \{\
		pos = sp0.c1st;\
		end = spN.cp;\
	\} else \{\
		pos = spN.c1st;\
		// 
\i Text is inconsistent about what line it thinks we're on
\i0 \
		if (spN.cp == (spN.c1st + LINE_LENGTH(spN.line)))\
			pos = spN.cp;\
		end = sp0.cp;\
	\}\
	return [self 
\b goto
\b0 :pos 
\b end
\b0 :end 
\b mode
\b0 :mode];\
\}\
\
- 
\b lineEnd
\b0 :(int)mode \{\
	NXSelPt *sp;\
	int pos, end;\
\
	if (sp0.cp == posHint) \{\
		sp = &sp0;\
		end = spN.cp;\
	\} else \{\
		// 
\i need to correct for TBD
\i0 \
		sp = &spN;\
		end = sp0.cp;\
	\}\
	pos = sp->c1st + LINE_LENGTH(sp->line) - 1;\
	if (pos < sp->cp) \{\
		// 
\i Text is being flakey again; we really want to be on the next line
\i0 \
		// 
\i this is pretty gross
\i0 \
		pos = sp->line;\
		if (theBreaks->breaks[pos/sizeof(
\b NXLineDesc
\b0 )] < 0)\
			pos += sizeof(
\b NXHeightChange
\b0 );\
		else\
			pos += sizeof(
\b NXLineDesc
\b0 );\
		pos = sp->cp + 
\b LINE_LENGTH
\b0 (pos) - 1;\
	\}\
	if ((pos == sp->cp) && (mode != 0))\
		++pos;\
	return [self 
\b goto
\b0 :pos 
\b end
\b0 :end 
\b mode
\b0 :mode];\
\}\
\
- 
\b docBegin
\b0 :(int)mode \{\
	return [self	
\b goto
\b0 :0\
				  	 
\b end
\b0 :(sp0.cp == posHint ? spN.cp : sp0.cp)\
				 	
\b mode
\b0 :mode];\
\}\
\
- 
\b docEnd
\b0 :(int)mode \{\
	return [self	
\b goto
\b0 :[self textLength]\
				 	 
\b end
\b0 :(sp0.cp == posHint ? spN.cp : sp0.cp)\
				 	
\b mode
\b0 :mode];\
\}\
\
- 
\b collapseSel
\b0 :(int)dir \{\
	int pos;\
\
	if ((dir < 0) || ((dir == 0) && (sp0.cp == posHint)))\
		pos = sp0.cp;\
	else\
		pos = spN.cp;\
	return [self 
\b goto
\b0 :pos 
\b end
\b0 :pos 
\b mode
\b0 :0];\
\}\
\
- 
\b transChars
\b0  \{\
	int pos = sp0.cp;\
	char buf[2], temp;\
\
	if (pos == spN.cp) \{\
		if (pos == (sp0.c1st + 
\b LINE_LENGTH
\b0 (sp0.line) - 1))\
			--pos;\
		if (pos > 0)\
			if ([self 
\b getSubstring
\b0 :
\b buf
\b0  start:pos-1 length:2] == 2) \{\
				temp = buf[1]; buf[1] = buf[0]; buf[0] = temp;\

\i 				//[self disableAutodisplay];\

\i0 				[self 
\b setSel
\b0 :pos-1 :pos+1];\
				[self 
\b replaceSel
\b0 :
\b buf
\b0  length:
\b 2
\b0 ];\
				return self;\
			\}\
	\}\
	
\b NXBeep
\b0 ();\
	return self;\
\}\
\
- 
\b openLine
\b0  \{\
	int pos = sp0.cp;\
\
	// 
\i don't do anything if there's a non-empty selection
\i0 \
	if (pos == spN.cp) \{\
		[self 
\b replaceSel
\b0 :"
\b \\n
\b0 "];\
		[self 
\b setSel
\b0 :pos :pos];\
	\} else\
		
\b NXBeep
\b0 ();\
	return self;\
\}\
\
- 
\b scroll
\b0 :(int)pages :(int)lines \{\
	NXRect r;\
\
	// 
\i if our superview isn't a ClipView, we can't scroll
\i0 \
	if ([superview 
\b respondsTo
\b0 :@selector(
\b _scrollTo:
\b0 )]) \{\
		[superview 
\b getBounds
\b0 :&r];\
		r.origin.y += pages*r.size.height + lines*[self lineHeight];\
		// 
\i Added by RK to keep one line of context on pgdowns.(insurance)
\i0 \
		if (
\b pages
\b0 ) r.origin.y -= [self 
\b lineHeight
\b0 ];\
		[superview 
\b _scrollTo
\b0 :&r.
\b origin
\b0 ];\
	\} else\
		
\b NXBeep
\b0 ();\
	return self;\
\}\
\
- 
\b scrollIfRO
\b0 :(int)pages :(int)lines \{\
	if (
\b !
\b0 [self 
\b isEditable
\b0 ])\
		return [self 
\b scroll
\b0 :pages :lines];\
	else\
		return nil;\
\}\
\
- 
\b insertChar
\b0 :(NXEvent *)event \{\
	char c;\
\
	c = 
\b event
\b0 ->data.key.
\b charCode
\b0 ;\
	[self 
\b replaceSel
\b0 :&c 
\b length
\b0 :1];\
	return self;\
\}\
\
- 
\b insertNextChar
\b0  \{\
	
\b static
\b0  id 
\b action
\b0  = 
\b nil
\b0 ;\
\
	if (!action)\
		action = [[
\b XTEventMsgAction
\b0  allocFromZone:[NXApp zone]]\
							
\b initSel
\b0 :@selector(insertChar:)];\
	
\b nextAction
\b0  = 
\b action
\b0 ;\
	return self;\
\}\
\

\i @end
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.