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.