1 prototypes ensureNamespace: #text &delegate: True.
3 text define: #BufferPointer &parents: {Comparable}.
4 text define: #TextBuffer &parents: {Cloneable} &slots: {#lines. #view}. "call view update when changed"
6 TextBuffer traits define: #Pointer &parents: {BufferPointer}
7 &slots: {#lineNo. #columnNo. #partner}.
9 p@(TextBuffer Pointer traits) newAtLine: lineNo column: columnNo &partner: partner
10 [p clone `setting: #{#lineNo. #columnNo. #partner} to: {lineNo. columnNo. partner}].
12 p1@(TextBuffer Pointer traits) < p2@(BufferPointer traits)
14 p1 lineNo < p2 lineNo \/
15 [p1 lineNo = p2 lineNo /\ [p1 columnNo < p2 columnNo]]
18 "the following doesn't work.. doesn't specialize on traits:
20 ( #= findOn: {TextBuffer Pointer traits. TextBuffer Pointer traits}) disassemble.
24 ( #= findOn: {TextBuffer Pointer. TextBuffer Pointer}) disassemble.
26 (slot per slot comparison)
29 TextBuffer Pointer compareAndHashUsingSlots: #{#lineNo. #columnNo}.
33 p1@(TextBuffer Pointer traits) = p2@(TextBuffer Pointer traits)
35 p1 lineNo = p2 lineNo /\ [p1 columnNo = p2 columnNo]
38 " -- some primitive commands I'm making to help with fundamental mode -- "
40 text define: #TextBufferCommand &parents: {Command} &slots: {#buffer -> Nil.}.
42 text define: #TextBufferBlockCommand &parents: {BlockCommand. TextBufferCommand} &slots: {}.
43 text define: #TextBufferCommandGroup &parents: {CommandGroup. TextBufferCommand} &slots: {}.
45 "define slots for undo information, other stuff is passed in the #arguments"
46 text define: #TextBufferPointManipulationCommand &parents: {TextBufferCommand} &slots: {#oldPoint -> Nil.}.
48 text define: #MovePointCommand &parents: {TextBufferPointManipulationCommand}.
49 text define: #MovePointBeginningOfLineCommand &parents: {MovePointCommand}.
50 text define: #MovePointEndOfLineCommand &parents: {MovePointCommand}.
51 text define: #DropMarkCommand &parents: {TextBufferPointManipulationCommand}.
53 text define: #InsertTextCommand &parents: {TextBufferCommand} &slots: {#numCharacters -> 0}.
55 text define: #CopyRegionCommand &parents: {TextBufferCommand} &slots: {#oldPasteRing -> Nil.}.
56 text define: #DeleteRegionCommand &parents: {TextBufferPointManipulationCommand} &slots:
62 "The following deletes (sucks) from the right like the delete key, the
63 first argument is the point, the second is the number of times the
64 user would hit delete to accomplish the action. This behaves just like
65 InsertText and of course the user defined actions would include
66 actions later to move the point after the text is inserted."
68 text define: #DeleteFromPointCommand &parents: {TextBufferPointManipulationCommand} &slots: {#oldText -> ''.}.
70 tbc@(TextBufferCommand traits) name: name arguments: arguments buffer: buffer
72 tbc clone `setting: #{#name. #arguments. #buffer} to: {name. arguments. buffer}
75 " -- required functions by every buffer implementation -- "
77 "negative distance is towards the origin -- this should wrap also and is DESTRUCTIVE to p"
78 p@(TextBuffer Pointer traits) moveOn: tb@(TextBuffer traits) distance: i@(Integer traits)
81 p1@(TextBuffer Pointer traits) isConnectedTo: p2@(TextBuffer Pointer traits)
82 [p1 partner == p2 /\ [p2 partner == p1]].
84 p1@(TextBuffer Pointer traits) connectTo: p2@(TextBuffer Pointer traits)
91 p1@(TextBuffer Pointer traits) setTo: p2@(TextBuffer Pointer traits)
93 p1 partner := p2 partner.
94 p1 lineNo := p2 lineNo.
95 p1 columnNo := p2 columnNo.
99 p1@(TextBuffer Pointer traits) disconnect
101 p1 partner ifNotNil: [p1 partner partner := Nil.].
106 tb@(TextBuffer traits) makePointActive: p1@(TextBuffer Pointer traits)
107 [tb view update. p1].
109 tb@(TextBuffer traits) ensurePointActive: p1@(TextBuffer Pointer traits)
110 "delete the current point if it's not it"
111 [tb view update. p1].
113 tb@(TextBuffer traits) addPoint: p1@(TextBuffer Pointer traits)
114 [tb view update. p1].
116 tb@(TextBuffer traits) deletePoint: p1@(TextBuffer Pointer traits)
117 [tb view update. p1].
119 tb@(TextBuffer traits) allPoints
122 tb@(TextBuffer traits) activePoint
125 tb@(TextBuffer traits) at: p1@(TextBuffer Pointer traits) insert: text
126 [tb view update. tb].
128 tb@(TextBuffer traits) at: p1@(TextBuffer Pointer traits) delete: characters@(Integer traits)
129 [tb view update. tb].
131 tb@(TextBuffer traits) getContentsFrom: p1@(TextBuffer Pointer traits) to: p2@(TextBuffer Pointer traits)
134 tb@(TextBuffer traits) at: p1@(TextBuffer Pointer traits)
137 tb@(TextBuffer traits) at: p1@(TextBuffer Pointer traits) ifAbsent: block
140 tb@(TextBuffer traits) beginningOfBuffer
144 tb@(TextBuffer traits) endOfBuffer
148 tb@(TextBuffer traits) endOfLine: lineNo
152 " -- some given command interface commands using base functionality
153 that need to be overridden per-buffer impl. --"
155 "FIXME unoverride this and make it install the command into a undo/recording place"
157 action@(TextBufferCommand traits) execute
160 action@(TextBufferCommand traits) undo
164 action@(TextBufferCommand traits) pointArgument
166 ((action arguments at: 0) ifNil: [action buffer activePoint])
169 action@(MovePointCommand traits) execute
171 action buffer view update.
172 lobby inform: ('execute: ' ; action printString ; ' args: ' ; action arguments printString).
173 point := action pointArgument.
174 distance := (action arguments at: 1).
176 action oldPoint := point copy.
178 " the second argument can be an integer or another point's location "
180 (distance is: TextBuffer Pointer)
181 ifTrue: [point setTo: distance]
182 ifFalse: [point moveOn: action buffer distance: distance].
186 action@(MovePointCommand traits) undo
188 action buffer view update.
189 action pointArgument setTo: (action oldPoint).
192 action@(MovePointBeginningOfLineCommand traits) execute
194 action buffer view update.
195 point := action pointArgument.
197 action oldPoint := point copy.
199 " the second argument can be an integer or another point's location "
205 action@(MovePointEndOfLineCommand traits) execute
207 action buffer view update.
209 point := action pointArgument.
211 action oldPoint := point copy.
213 " the second argument can be an integer or another point's location "
215 point columnNo := (action buffer lines at: point lineNo) size.
219 action@(DropMarkCommand traits) execute
221 action oldPoint := action buffer activePoint partner.
222 action buffer activePoint partner := Nil.
224 newPartner := action buffer activePoint copy.
225 action buffer addPoint: newPartner.
227 action buffer activePoint connectTo: newPartner.
229 lobby inform: action buffer activePoint printString.
234 action@(DropMarkCommand traits) undo
236 action buffer deletePoint: action buffer activePoint partner.
237 action buffer activePoint partner := action oldPoint.
239 lobby inform: action buffer activePoint printString.
243 action@(InsertTextCommand traits) execute
246 point := action pointArgument.
247 action buffer at: point insert: (action arguments at: 1).
248 action numCharacters := (action arguments at: 1) size.
252 action@(InsertTextCommand traits) undo
254 action buffer at: action pointArgument delete: action numCharacters.
257 action@(CopyRegionCommand traits) execute
259 "FIXME figure out the pastering thingy #oldPasteRing"
260 action oldPasteRing := action buffer getContentsFrom: action buffer activePoint
261 to: (action buffer activePoint partner ifNil: [action buffer activePoint]).
265 action@(CopyRegionCommand traits) undo
270 action@(DeleteRegionCommand traits) execute
272 (action buffer activePoint partner)
273 ifNil: [action deletedText := ''.
274 action oldPoint := action buffer activePoint.
275 action oldMark := Nil]
276 ifNotNil: [action oldPoint := action buffer activePoint copy.
277 action oldMark := action buffer activePoint partner copy.
278 action deletedText := (action buffer getContentsFrom: action buffer activePoint
279 to: action buffer activePoint partner).
280 action buffer at: (action buffer activePoint min: action buffer activePoint partner)
281 delete: action deletedText size.
282 action buffer activePoint setTo: (action buffer activePoint min: action buffer activePoint partner).
283 action buffer deletePoint: action oldPoint.
284 action buffer activePoint disconnect]
287 action@(DeleteRegionCommand traits) undo
289 action oldMark ifNotNilDo:
291 action buffer activePoint setTo: oldPoint.
292 action buffer activePoint partner setTo: action oldMark.
293 action buffer at: (action buffer activePoint min: action buffer activePoint partner)
294 insert: action deletedText]
297 action@(DeleteFromPointCommand traits) execute
299 point := action pointArgument.
300 distance := (action arguments at: 1).
301 action oldText := (action buffer getContentsFrom: point to: (point copy moveOn: action buffer distance: distance)).
302 action buffer at: point delete: distance.
305 action@(DeleteFromPointCommand traits) undo
307 action buffer at: action pointArgument insert: action oldText.
310 " -- simple buffer and support functions, override the functions that need overriding -- "
312 text define: #ArrayTextBuffer &parents: {TextBuffer}.
314 tb@(ArrayTextBuffer traits) pointerToLine: lineNo column: columnNo
315 [tb Pointer newAtLine: lineNo column: columnNo].
317 tb@(ArrayTextBuffer traits) beginningOfBuffer
318 [tb pointerToLine: 0 column: 0].
320 tb@(ArrayTextBuffer traits) endOfLine: lineNo
322 [(tb lines at: lineNo) length].
324 tb@(ArrayTextBuffer traits) endOfBuffer
326 lastLineNo := tb lines indexLast.
327 tb pointerToLine: lastLineNo column: (tb endOfLine: lastLineNo)
330 ArrayTextBuffer addSlot: #cursors valued:
331 (ExtensibleArray new*, ArrayTextBuffer beginningOfBuffer).
333 atb@(ArrayTextBuffer traits) new
335 resend `>> [lines := ExtensibleArray new*, (ExtensibleArray new). ]
338 "negative distance is towards the origin -- this should wrap also and is DESTRUCTIVE to p"
339 p@(TextBuffer Pointer traits) moveOn: tb@(TextBuffer traits) distance: i@(Integer traits)
345 lobby inform: ('move from: ' ; (p printString) ; ' dist: ' ; i printString).
349 [[tb beginningOfBuffer = p \/ [i = 0]] whileFalse:
351 ifTrue: [p lineNo := p lineNo - 1. p columnNo := (tb endOfLine: p lineNo)]
352 ifFalse: [p columnNo := p columnNo - 1].
354 ifFalse: "move forward"
355 [[p = tb endOfBuffer \/ [i isZero]] whileFalse:
356 [(p columnNo = (tb endOfLine: p lineNo))
357 ifTrue: [p lineNo := p lineNo + 1. p columnNo := 0]
358 ifFalse: [p columnNo := p columnNo + 1].
361 lobby inform: 'move to: ' ; p printString ; ' dist: ' ; i printString.
365 tb@(ArrayTextBuffer traits) makePointActive: p1@(TextBuffer Pointer traits)
368 tb cursors remove: p1 ifAbsent: [].
369 tb cursors addFirst: p1.
373 tb@(ArrayTextBuffer traits) ensurePointActive: p1@(TextBuffer Pointer traits)
376 tb activePoint == p1 ifFalse:
377 [tb cursors remove: tb activePoint.
378 tb cursors remove: p1 ifAbsent: [].
379 tb cursors addFirst: p1].
383 tb@(ArrayTextBuffer traits) addPoint: p1@(TextBuffer Pointer traits)
386 tb cursors addLast: p1.
389 tb@(ArrayTextBuffer traits) deletePoint: p1@(TextBuffer Pointer traits)
392 tb cursors remove: p1.
395 tb@(ArrayTextBuffer traits) allPoints
400 tb@(ArrayTextBuffer traits) activePoint
405 p1@(TextBuffer Pointer traits) assureOn: tb@(ArrayTextBuffer traits)
407 "if it's off the end of the line, put it on the last character"
408 p1 columnNo <= (tb lines at: p1 lineNo) size ifFalse:
409 [p1 columnNo := (tb lines at: p1 lineNo) size].
412 tb@(ArrayTextBuffer traits) at: p1@(TextBuffer Pointer traits) insert: text
416 " if you want to insert text but the cursor is off the end of the
417 line (from a previous-line, etc instr), then move the cursor back
423 ifTrue: [text reverse do: [| :char | tb at: p1 insert: char]]
424 ifFalse: " insert the character "
425 [text = $\n \/ [text = $\r]
428 chars := (tb lines at: p1 lineNo) removeLast:
429 (tb lines at: p1 lineNo) size - p1 columnNo.
430 tb lines at: p1 lineNo + 1 insert: (chars as: tb lines first)]
431 ifFalse: [(tb lines at: p1 lineNo) at: p1 columnNo insert: text]]
434 tb@(ArrayTextBuffer traits) at: p1@(TextBuffer Pointer traits) delete: characters@(Integer traits)
438 lobby inform: ('delete at: ' ; (p1 printString)).
439 characters timesRepeat:
440 [(p1 = tb endOfBuffer) ifFalse:
441 [p1 columnNo = (tb endOfLine: p1 lineNo)
443 ["cursor at end of line, suck up the next one"
444 (tb lines at: p1 lineNo) addAll: (tb lines at: p1 lineNo + 1).
445 tb lines removeAt: p1 lineNo + 1]
447 ["delete a character"
448 (tb lines at: p1 lineNo) removeAt: p1 columnNo]]]
451 tb@(ArrayTextBuffer traits) getContentsFrom: p1@(TextBuffer Pointer traits) to: p2@(TextBuffer Pointer traits)
454 ifTrue: [min := p1 copy. max := p2 copy]
455 ifFalse: [min := p2 copy. max := p1 copy].
457 "FIXME: handle newlines"
458 [min < max] whileTrue:
459 [result ; ((tb at: min ifAbsent: ['\n']) as: String).
460 min moveOn: tb distance: 1].
461 result ; ((tb at: min ifAbsent: ['\n']) as: String) "capture last character"
465 tb@(ArrayTextBuffer traits) at: p1@(TextBuffer Pointer traits)
467 tb at: p1 ifAbsent: [break]
470 tb@(ArrayTextBuffer traits) at: p1@(TextBuffer Pointer traits) ifAbsent: block
473 p1 lineNo >= tb lines size
474 /\ [p1 columnNo >= (tb lines at: p1 lineNo) size]
476 ifFalse: [(tb lines at: p1 lineNo) at: p1 columnNo ifAbsent: [block do]]