1 // Selection list management functions
2 // Copyright (C) 2000 Core Technologies.
3
4 // This file is part of e93.
5 //
6 // e93 is free software; you can redistribute it and/or modify
7 // it under the terms of the e93 LICENSE AGREEMENT.
8 //
9 // e93 is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // e93 LICENSE AGREEMENT for more details.
13 //
14 // You should have received a copy of the e93 LICENSE AGREEMENT
15 // along with e93; see the file "LICENSE.TXT".
16
17 #include "includes.h"
18
19 typedef struct selectionElement
20 {
21 SPARSE_ARRAY_HEADER
22 saHeader; // only need the header
23 } SELECTION_ELEMENT;
24
25 typedef struct selectionUniverse
26 {
27 UINT32
28 cursorPosition; // if there is no selection, this is the cursor's position
29 SPARSE_ARRAY
30 selectionArray;
31 } SELECTION_UNIVERSE;
32
33 enum
34 {
35 DUPLICATE_NAME
36 };
37
38 static const char *errorDescriptions[]=
39 {
40 "Duplicate mark names are not allowed"
41 };
42
DeleteAllSelections(SELECTION_UNIVERSE * universe)43 void DeleteAllSelections(SELECTION_UNIVERSE *universe)
44 // Remove all selections from universe
45 {
46 DeleteSARange(&universe->selectionArray,0,universe->selectionArray.totalElements);
47 }
48
DeleteSelectionRange(SELECTION_UNIVERSE * universe,UINT32 startPosition,UINT32 numElements)49 void DeleteSelectionRange(SELECTION_UNIVERSE *universe,UINT32 startPosition,UINT32 numElements)
50 // Remove selection array elements from startPosition for numElements
51 // NOTE: this does not mind being called for positions outside of the current array
52 // This pulls the remaining array elements to the left.
53 {
54 DeleteSARange(&universe->selectionArray,startPosition,numElements);
55 }
56
InsertSelectionRange(SELECTION_UNIVERSE * universe,UINT32 startPosition,UINT32 numElements)57 bool InsertSelectionRange(SELECTION_UNIVERSE *universe,UINT32 startPosition,UINT32 numElements)
58 // insert numElements into the selection array at startPosition
59 // the elements inserted will be selected if the insertion was inside a current selection
60 // This pushes the existing array elements after startPosition to the right.
61 {
62 return(InsertSARange(&universe->selectionArray,startPosition,numElements));
63 }
64
ClearSelectionRange(SELECTION_UNIVERSE * universe,UINT32 startPosition,UINT32 numElements)65 bool ClearSelectionRange(SELECTION_UNIVERSE *universe,UINT32 startPosition,UINT32 numElements)
66 // clear selection at startPosition for numElements of universe
67 // if there is a problem, return false
68 {
69 return(ClearSARange(&universe->selectionArray,startPosition,numElements));
70 }
71
SetSelectionRange(SELECTION_UNIVERSE * universe,UINT32 startPosition,UINT32 numElements)72 bool SetSelectionRange(SELECTION_UNIVERSE *universe,UINT32 startPosition,UINT32 numElements)
73 // set selection at startPosition for numElements of universe
74 // if there is a problem, return false
75 // the selection will overwrite anything currently in the array at
76 // the given positions (no insertion (right shift) is performed)
77 {
78 SELECTION_ELEMENT
79 element;
80
81 return(SetSARange(&universe->selectionArray,startPosition,numElements,&element));
82 }
83
GetSelectionAtOrAfterPosition(SELECTION_UNIVERSE * universe,UINT32 position,UINT32 * startPosition,UINT32 * numElements)84 bool GetSelectionAtOrAfterPosition(SELECTION_UNIVERSE *universe,UINT32 position,UINT32 *startPosition,UINT32 *numElements)
85 // Return the index of the selection which occupies position,
86 // or the first one after the position if the position is not occupied.
87 // If the passed position is past the end of the array, return false
88 // NOTE: this uses a cache so it is efficient to call
89 // repeatedly for positions which are nearby each other
90 {
91 SELECTION_ELEMENT
92 *element;
93
94 if(GetSARecordAtOrAfterPosition(&universe->selectionArray,position,startPosition,numElements,(void **)&element))
95 {
96 return(true);
97 }
98 return(false);
99 }
100
GetSelectionAtOrBeforePosition(SELECTION_UNIVERSE * universe,UINT32 position,UINT32 * startPosition,UINT32 * numElements)101 bool GetSelectionAtOrBeforePosition(SELECTION_UNIVERSE *universe,UINT32 position,UINT32 *startPosition,UINT32 *numElements)
102 // Return the index of the selection which occupies position,
103 // or the first one before the position if the position is not occupied.
104 // If the passed position is before the first element of the array, return false.
105 // NOTE: this uses a cache so it is efficient to call
106 // repeatedly for positions which are nearby each other
107 {
108 SELECTION_ELEMENT
109 *element;
110
111 if(GetSARecordAtOrBeforePosition(&universe->selectionArray,position,startPosition,numElements,(void **)&element))
112 {
113 return(true);
114 }
115 return(false);
116 }
117
GetSelectionRange(SELECTION_UNIVERSE * universe,UINT32 position,UINT32 * startPosition,UINT32 * numElements,bool * isActive)118 bool GetSelectionRange(SELECTION_UNIVERSE *universe,UINT32 position,UINT32 *startPosition,UINT32 *numElements,bool *isActive)
119 // return the range of positions in the array which include position
120 // and are selected (or not selected) the same as position
121 // NOTE: this uses a cache so it is efficient to call
122 // repeatedly for positions which are nearby each other
123 // NOTE: if position is off the end of the array, isActive will be returned as false,
124 // startPosition will contain the position where the array ended and
125 // this will return false (numElements will not be set)
126 {
127 SELECTION_ELEMENT
128 *element;
129
130 *isActive=false;
131 if(GetSARecordForPosition(&universe->selectionArray,position,startPosition,numElements,(void **)&element))
132 {
133 if(element)
134 {
135 *isActive=true;
136 }
137 return(true);
138 }
139 return(false);
140 }
141
GetSelectionAtPosition(SELECTION_UNIVERSE * universe,UINT32 position)142 bool GetSelectionAtPosition(SELECTION_UNIVERSE *universe,UINT32 position)
143 // call this to return the selection at the given position of
144 // the given selection universe.
145 // NOTE: if position is off the end of the array, this will return false.
146 // NOTE: this uses a cache so it is efficient to call
147 // repeatedly for positions which are nearby each other
148 {
149 UINT32
150 startPosition,
151 numElements;
152 bool
153 selection;
154
155 GetSelectionRange(universe,position,&startPosition,&numElements,&selection);
156 return(selection);
157 }
158
IsSelectionEmpty(SELECTION_UNIVERSE * universe)159 bool IsSelectionEmpty(SELECTION_UNIVERSE *universe)
160 // return TRUE if universe contains no selection elements
161 {
162 return(IsSAEmpty(&universe->selectionArray));
163 }
164
GetSelectionEndPositions(SELECTION_UNIVERSE * universe,UINT32 * startPosition,UINT32 * endPosition)165 void GetSelectionEndPositions(SELECTION_UNIVERSE *universe,UINT32 *startPosition,UINT32 *endPosition)
166 // return the start and end absolute text positions of the passed selection universe
167 // if there are no selections, then the cursor position is returned as both the start and the end
168 {
169 if(!GetSAElementEnds(&universe->selectionArray,startPosition,endPosition))
170 {
171 (*startPosition)=(*endPosition)=universe->cursorPosition;
172 }
173 }
174
GetSelectionCursorPosition(SELECTION_UNIVERSE * universe)175 UINT32 GetSelectionCursorPosition(SELECTION_UNIVERSE *universe)
176 // Get the cursor position for the passed selection universe
177 {
178 return(universe->cursorPosition);
179 }
180
SetSelectionCursorPosition(SELECTION_UNIVERSE * universe,UINT32 position)181 void SetSelectionCursorPosition(SELECTION_UNIVERSE *universe,UINT32 position)
182 // Set the cursor position for the passed selection universe
183 {
184 universe->cursorPosition=position;
185 }
186
AdjustSelectionsForChange(SELECTION_UNIVERSE * universe,UINT32 startOffset,UINT32 oldEndOffset,UINT32 newEndOffset)187 void AdjustSelectionsForChange(SELECTION_UNIVERSE *universe,UINT32 startOffset,UINT32 oldEndOffset,UINT32 newEndOffset)
188 // given a change at startOffset, run through the given selection list, and fix it up
189 // NOTE: this can cause all the selections to disappear
190 // If it does, then the cursor will be left at the end of the change
191 {
192 UINT32
193 startPosition,
194 endPosition;
195
196 if(GetSAElementEnds(&universe->selectionArray,&startPosition,&endPosition)) // if there is some selection, then move the cursor to the start so if the selection goes away, the cursor is left in the correct spot
197 {
198 universe->cursorPosition=startPosition; // push to the start
199 }
200
201 DeleteSelectionRange(universe,startOffset,oldEndOffset-startOffset);
202 InsertSelectionRange(universe,startOffset,newEndOffset-startOffset);
203
204 if(universe->cursorPosition>=startOffset) // if cursor was before the change, then do not move it
205 {
206 if(universe->cursorPosition>oldEndOffset) // see if cursor was past changed area (move it relatively)
207 {
208 universe->cursorPosition=(universe->cursorPosition+newEndOffset)-oldEndOffset;
209 }
210 else
211 {
212 universe->cursorPosition=newEndOffset; // if cursor in middle of change, put it at the end
213 }
214 }
215 }
216
CopySelectionUniverse(SELECTION_UNIVERSE * sourceUniverse,SELECTION_UNIVERSE * destUniverse)217 bool CopySelectionUniverse(SELECTION_UNIVERSE *sourceUniverse,SELECTION_UNIVERSE *destUniverse)
218 // copy sourceUniverse to destUniverse
219 // if there is a problem, SetError, and return false
220 // This may be called with sourceUniverse==destUniverse
221 {
222 bool
223 fail;
224 UINT32
225 startPosition,
226 numElements;
227
228 fail=false;
229 DeleteAllSelections(destUniverse);
230 destUniverse->cursorPosition=sourceUniverse->cursorPosition; // copy the cursor position
231
232 startPosition=0;
233 while(!fail&&GetSelectionAtOrAfterPosition(sourceUniverse,startPosition,&startPosition,&numElements))
234 {
235 fail=!SetSelectionRange(destUniverse,startPosition,numElements);
236 startPosition+=numElements;
237 }
238 return(!fail);
239 }
240
OrSelectionUniverse(SELECTION_UNIVERSE * sourceUniverse,SELECTION_UNIVERSE * destUniverse)241 bool OrSelectionUniverse(SELECTION_UNIVERSE *sourceUniverse,SELECTION_UNIVERSE *destUniverse)
242 // Logical OR sourceUniverse to destUniverse
243 // if there is a problem, SetError, and return false
244 // NOTE: adjacent selection boundaries that are not shared
245 // will be coalesced in the result.
246 // This may be called with sourceUniverse==destUniverse
247 {
248 bool
249 fail;
250 UINT32
251 startPosition,
252 numElements;
253 UINT32
254 destPosition,
255 destElements;
256
257 fail=false;
258
259 startPosition=0;
260 while(!fail&&GetSelectionAtOrAfterPosition(sourceUniverse,startPosition,&startPosition,&numElements))
261 {
262 if(GetSelectionAtOrAfterPosition(destUniverse,startPosition,&destPosition,&destElements))
263 {
264 if(destPosition<startPosition) // if dest selection has a section that extends back from the start, coalesce it in
265 {
266 numElements+=startPosition-destPosition;
267 startPosition=destPosition;
268 }
269 if(GetSelectionAtOrAfterPosition(destUniverse,startPosition+numElements,&destPosition,&destElements))
270 {
271 if(destPosition<startPosition+numElements) // if dest selection has a section that extends beyond the end, coalesce it in
272 {
273 numElements=destPosition+destElements-startPosition;
274 }
275 }
276 }
277 fail=!SetSelectionRange(destUniverse,startPosition,numElements);
278 startPosition+=numElements;
279 }
280 return(!fail);
281 }
282
AndSelectionUniverse(SELECTION_UNIVERSE * sourceUniverse,SELECTION_UNIVERSE * destUniverse)283 bool AndSelectionUniverse(SELECTION_UNIVERSE *sourceUniverse,SELECTION_UNIVERSE *destUniverse)
284 // Logical AND sourceUniverse to destUniverse
285 // if there is a problem, SetError, and return false
286 // NOTE: all selections boundaries occuring in either selection will be
287 // present in the resulting selection.
288 // This may be called with sourceUniverse==destUniverse
289 {
290 bool
291 fail;
292 UINT32
293 clearPosition,
294 startPosition,
295 endPosition,
296 numElements;
297 UINT32
298 destPosition,
299 destElements;
300
301 fail=false;
302
303 clearPosition=startPosition=0;
304 while(!fail&&GetSelectionAtOrAfterPosition(sourceUniverse,startPosition,&startPosition,&numElements))
305 {
306 fail=!ClearSelectionRange(destUniverse,clearPosition,startPosition-clearPosition);
307 if(GetSelectionAtOrAfterPosition(destUniverse,startPosition+numElements,&destPosition,&destElements))
308 {
309 if(destPosition<startPosition+numElements) // make sure to break dest at end of start if needed
310 {
311 fail=!SetSelectionRange(destUniverse,destPosition,startPosition+numElements-destPosition);
312 }
313 }
314 startPosition+=numElements;
315 clearPosition=startPosition;
316 }
317
318 if(!fail&&GetSAElementEnds(&destUniverse->selectionArray,&startPosition,&endPosition))
319 {
320 if(endPosition>clearPosition)
321 {
322 fail=!ClearSelectionRange(destUniverse,clearPosition,endPosition-clearPosition);
323 }
324 }
325 return(!fail);
326 }
327
XorSelectionUniverse(SELECTION_UNIVERSE * sourceUniverse,SELECTION_UNIVERSE * destUniverse)328 bool XorSelectionUniverse(SELECTION_UNIVERSE *sourceUniverse,SELECTION_UNIVERSE *destUniverse)
329 // Logical XOR sourceUniverse to destUniverse
330 // if there is a problem, SetError, and return false
331 // NOTE: all selections boundaries occuring in either selection will be
332 // present in the resulting selection.
333 // This may be called with sourceUniverse==destUniverse
334 {
335 bool
336 fail;
337 UINT32
338 startPositionS,
339 numElementsS,
340 startPositionD,
341 numElementsD,
342 numToDo;
343
344 fail=false;
345
346 startPositionS=startPositionD=0;
347 while(!fail&&GetSelectionAtOrAfterPosition(sourceUniverse,startPositionS,&startPositionS,&numElementsS))
348 {
349 while(!fail&&numElementsS)
350 {
351 if(GetSelectionAtOrAfterPosition(destUniverse,startPositionS,&startPositionD,&numElementsD))
352 {
353 if(startPositionS<startPositionD)
354 {
355 numToDo=startPositionD-startPositionS;
356 if(numToDo>numElementsS)
357 {
358 numToDo=numElementsS;
359 }
360 fail=!SetSelectionRange(destUniverse,startPositionS,numToDo);
361 numElementsS-=numToDo;
362 startPositionS+=numToDo;
363 }
364 if(!fail&&numElementsS) // still some to do?
365 {
366 numToDo=startPositionD+numElementsD-startPositionS;
367 if(numToDo>numElementsS)
368 {
369 numToDo=numElementsS;
370 }
371 fail=!ClearSelectionRange(destUniverse,startPositionS,numToDo);
372 numElementsS-=numToDo;
373 startPositionS+=numToDo;
374 }
375 }
376 else // just copy S to D now
377 {
378 fail=!SetSelectionRange(destUniverse,startPositionS,numElementsS);
379 startPositionS+=numElementsS;
380 numElementsS=0;
381 }
382 }
383 }
384 return(!fail);
385 }
386
CloseSelectionUniverse(SELECTION_UNIVERSE * universe)387 void CloseSelectionUniverse(SELECTION_UNIVERSE *universe)
388 // dispose of a selection universe
389 {
390 UnInitSA(&(universe->selectionArray));
391 MDisposePtr(universe);
392 }
393
OpenSelectionUniverse()394 SELECTION_UNIVERSE *OpenSelectionUniverse()
395 // Open a selection universe (with no elements)
396 // If there is a problem, set the error, and return NULL
397 {
398 SELECTION_UNIVERSE
399 *universe;
400
401 if((universe=(SELECTION_UNIVERSE *)MNewPtr(sizeof(SELECTION_UNIVERSE))))
402 {
403 universe->cursorPosition=0; // no cursor position yet, so just set it to 0
404 if(InitSA(&(universe->selectionArray),sizeof(SELECTION_ELEMENT)))
405 {
406 return(universe);
407 }
408 MDisposePtr(universe);
409 }
410 return(NULL);
411 }
412
413 // --------------------------------------------------------------------------------------------------------------------------
414 // Mark management
415
UnlinkVisibilityFromMark(EDITOR_MARK * mark,MARK_VISIBILITY * visibility)416 static void UnlinkVisibilityFromMark(EDITOR_MARK *mark,MARK_VISIBILITY *visibility)
417 // unlink the visibility record from the mark's list
418 {
419 if(visibility->prevView)
420 {
421 visibility->prevView->nextView=visibility->nextView;
422 }
423 else
424 {
425 mark->headVisibility=visibility->nextView;
426 }
427 if(visibility->nextView)
428 {
429 visibility->nextView->prevView=visibility->prevView;
430 }
431 else
432 {
433 mark->tailVisibility=visibility->prevView;
434 }
435 }
436
LinkVisibilityToMark(EDITOR_MARK * mark,MARK_VISIBILITY * visibility)437 static void LinkVisibilityToMark(EDITOR_MARK *mark,MARK_VISIBILITY *visibility)
438 // Link the visibility record to the list of views that this mark is visible in
439 {
440 visibility->parentMark=mark;
441
442 visibility->nextView=NULL;
443 if((visibility->prevView=mark->tailVisibility))
444 {
445 mark->tailVisibility->nextView=visibility;
446 }
447 else
448 {
449 mark->headVisibility=visibility;
450 }
451 mark->tailVisibility=visibility;
452 }
453
UnlinkVisibilityFromView(EDITOR_VIEW * view,MARK_VISIBILITY * visibility)454 static void UnlinkVisibilityFromView(EDITOR_VIEW *view,MARK_VISIBILITY *visibility)
455 // unlink the visibility record from the view's list
456 {
457 if(visibility->prevMark)
458 {
459 visibility->prevMark->nextMark=visibility->nextMark;
460 }
461 else
462 {
463 view->headVisibility=visibility->nextMark;
464 }
465 if(visibility->nextMark)
466 {
467 visibility->nextMark->prevMark=visibility->prevMark;
468 }
469 else
470 {
471 view->tailVisibility=visibility->prevMark;
472 }
473 }
474
LinkVisibilityToView(EDITOR_VIEW * view,MARK_VISIBILITY * visibility)475 static void LinkVisibilityToView(EDITOR_VIEW *view,MARK_VISIBILITY *visibility)
476 // Link the visibility record to the list of marks visible on the
477 // passed view
478 {
479 visibility->parentView=view;
480
481 visibility->nextMark=NULL;
482 if((visibility->prevMark=view->tailVisibility))
483 {
484 view->tailVisibility->nextMark=visibility;
485 }
486 else
487 {
488 view->headVisibility=visibility;
489 }
490 view->tailVisibility=visibility;
491 }
492
LocateMarkVisibilityInView(EDITOR_VIEW * view,EDITOR_MARK * mark)493 MARK_VISIBILITY *LocateMarkVisibilityInView(EDITOR_VIEW *view,EDITOR_MARK *mark)
494 // hunt the passed view to see if mark is present in its visible
495 // mark list
496 {
497 MARK_VISIBILITY
498 *visibility;
499
500 visibility=view->headVisibility;
501 while(visibility)
502 {
503 if(visibility->parentMark==mark)
504 {
505 return(visibility);
506 }
507 visibility=visibility->nextMark;
508 }
509 return(NULL);
510 }
511
DisposeMarkVisible(MARK_VISIBILITY * visibility)512 static void DisposeMarkVisible(MARK_VISIBILITY *visibility)
513 // unlink and remove mark visibility record
514 {
515 UnlinkVisibilityFromView(visibility->parentView,visibility);
516 UnlinkVisibilityFromMark(visibility->parentMark,visibility);
517 MDisposePtr(visibility);
518 }
519
UnlinkVisibleMarksFromView(EDITOR_VIEW * view)520 void UnlinkVisibleMarksFromView(EDITOR_VIEW *view)
521 // Get rid of all visible marks attached to the passed view (usually done
522 // when closing the view)
523 {
524 while(view->headVisibility)
525 {
526 DisposeMarkVisible(view->headVisibility); // remove all visible marks
527 }
528 }
529
ClearEditorMarkVisible(EDITOR_MARK * mark,EDITOR_VIEW * view)530 void ClearEditorMarkVisible(EDITOR_MARK *mark,EDITOR_VIEW *view)
531 // Remove the mark from the list of those visible on the passed view
532 {
533 MARK_VISIBILITY
534 *visibility;
535
536 if((visibility=LocateMarkVisibilityInView(view,mark)))
537 {
538 ViewInvalidateMark(view,mark); // invalidate it in the view so that it will disappear
539 DisposeMarkVisible(visibility);
540 }
541 }
542
SetEditorMarkVisible(EDITOR_MARK * mark,EDITOR_VIEW * view,EDITOR_COLOR backgroundColor)543 bool SetEditorMarkVisible(EDITOR_MARK *mark,EDITOR_VIEW *view,EDITOR_COLOR backgroundColor)
544 // Make the passed mark visible in the passed view. If it is already visible, just
545 // update the colors
546 {
547 MARK_VISIBILITY
548 *visibility;
549
550 if(!(visibility=LocateMarkVisibilityInView(view,mark)))
551 {
552 if((visibility=(MARK_VISIBILITY *)MNewPtr(sizeof(MARK_VISIBILITY)))) // allocate a record, and link it to the view and mark
553 {
554 LinkVisibilityToMark(mark,visibility);
555 LinkVisibilityToView(view,visibility);
556 }
557 }
558 if(visibility) // found or allocated record?
559 {
560 visibility->backgroundColor=backgroundColor;
561 ViewInvalidateMark(view,mark); // invalidate it in the view it just became visible in
562 return(true);
563 }
564 return(false);
565 }
566
LocateEditorMark(EDITOR_BUFFER * buffer,char * markName)567 EDITOR_MARK *LocateEditorMark(EDITOR_BUFFER *buffer,char *markName)
568 // attempt to locate a mark with the given name on buffer
569 // if one is found, return it, else, return NULL
570 {
571 bool
572 found;
573 EDITOR_MARK
574 *currentMark;
575
576 currentMark=buffer->marks;
577 found=false;
578 while(currentMark&&!found)
579 {
580 if(currentMark->markName&&(strcmp(currentMark->markName,markName)==0))
581 {
582 found=true;
583 }
584 else
585 {
586 currentMark=currentMark->nextMark; // locate the mark to delete
587 }
588 }
589 return(currentMark);
590 }
591
UnlinkEditorMarkFromBuffer(EDITOR_BUFFER * buffer,EDITOR_MARK * mark)592 static void UnlinkEditorMarkFromBuffer(EDITOR_BUFFER *buffer,EDITOR_MARK *mark)
593 // unlink a mark from the buffer
594 {
595 EDITOR_MARK
596 *previousMark,
597 *currentMark;
598
599 previousMark=NULL;
600 currentMark=buffer->marks;
601 while(currentMark&&(currentMark!=mark))
602 {
603 previousMark=currentMark;
604 currentMark=currentMark->nextMark; // locate the mark to delete
605 }
606 if(currentMark) // make sure we located it
607 {
608 if(previousMark) // see if it was at the top
609 {
610 previousMark->nextMark=currentMark->nextMark; // link across
611 }
612 else
613 {
614 buffer->marks=currentMark->nextMark; // set new top of list
615 }
616 }
617 }
618
LinkEditorMarkToBuffer(EDITOR_BUFFER * buffer,EDITOR_MARK * mark)619 static void LinkEditorMarkToBuffer(EDITOR_BUFFER *buffer,EDITOR_MARK *mark)
620 // link a mark to the buffer
621 {
622 mark->nextMark=buffer->marks; // link onto start of list
623 buffer->marks=mark;
624 }
625
CloseEditorMark(EDITOR_BUFFER * buffer,EDITOR_MARK * mark)626 void CloseEditorMark(EDITOR_BUFFER *buffer,EDITOR_MARK *mark)
627 // Remove a mark from the buffer
628 {
629 ViewsInvalidateMark(mark); // invalidate it if it was visible in any view
630 while(mark->headVisibility)
631 {
632 DisposeMarkVisible(mark->headVisibility); // remove all visibility of this mark
633 }
634 UnlinkEditorMarkFromBuffer(buffer,mark);
635 MDisposePtr(mark->markName);
636 CloseSelectionUniverse(mark->selectionUniverse); // close the selections
637 MDisposePtr(mark); // get rid of the mark
638 }
639
NewEditorMark(EDITOR_BUFFER * buffer,char * markName)640 EDITOR_MARK *NewEditorMark(EDITOR_BUFFER *buffer,char *markName)
641 // Create a new empty mark on the buffer with markName
642 // If the name is already taken, return SetError, and return NULL
643 {
644 EDITOR_MARK
645 *mark;
646
647 if(!LocateEditorMark(buffer,markName))
648 {
649 if((mark=(EDITOR_MARK *)MNewPtr(sizeof(EDITOR_MARK))))
650 {
651 if((mark->selectionUniverse=OpenSelectionUniverse()))
652 {
653 if((mark->markName=(char *)MNewPtr(strlen(markName)+1)))
654 {
655 strcpy(mark->markName,markName); // copy the name
656 mark->headVisibility=NULL; // this mark is not yet visible in any view
657 mark->tailVisibility=NULL;
658 LinkEditorMarkToBuffer(buffer,mark); // link the mark to its buffer
659 return(mark);
660 }
661 CloseSelectionUniverse(mark->selectionUniverse);
662 }
663 MDisposePtr(mark);
664 }
665 }
666 else
667 {
668 SetError(errorDescriptions[DUPLICATE_NAME]);
669 }
670 return(NULL);
671 }
672