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.