Пример #1
0
        private bool MergeSingle(SingleSelectionWithLocation inserted, LocationWithIndex existing)
        {
            if (existing.Selection.Start >= inserted.Start && existing.Selection.End <= inserted.End)
            {
                // The new selection is the same or a superset of the existing selection
                // so we can take that.
                this.items[existing.Index] = inserted.Selection;

                // The overall selection was only changed if the existing and new selections
                // exactly match.
                return(existing.Selection.Start != inserted.Start ||
                       existing.Selection.End != inserted.End);
            }

            if (existing.Selection.Start <= inserted.Start && existing.Selection.End >= inserted.End)
            {
                // The new location is completely covered by the existing one, we should ensure
                // that the caret is at the end specified by the insertion but this does not
                // change the overall selected text.
                this.items[existing.Index] = existing.Selection.Selection
                                             .WithDirection(inserted.Selection);

                return(false);
            }

            // Neither of the selections completely covers the other so create a new selection
            // the encompases both. This results in a change to the overall selection.
            this.items[existing.Index] = inserted.ExpandTo(
                existing.Selection.Start,
                existing.Selection.End);

            return(true);
        }
Пример #2
0
 private bool Merge(
     SingleSelectionWithLocation inserted,
     LocationWithIndex firstExisting,
     LocationWithIndex lastExisting)
 {
     return(firstExisting.Index == lastExisting.Index
         ? this.MergeSingle(inserted, firstExisting)
         : this.MergeRange(inserted, firstExisting, lastExisting));
 }
Пример #3
0
        private LocationWithIndex FindStart(
            LocationWithIndex minLocation,
            LocationWithIndex maxLocation,
            SingleSelectionWithLocation inserted)
        {
            if (!inserted.IsAfter(minLocation.Selection))
            {
                return(minLocation);
            }

            var minIndex = minLocation.Index;
            var gap      = maxLocation.Index - minIndex;

            while (true)
            {
                /* At this point we know that the inserted
                 * location is after the min location and
                 * that is is not after the max location */

                // If the gap is 1 or 0 then the start we want
                // must be the max location
                if (gap < 2)
                {
                    return(maxLocation);
                }

                // If the gap is more than 1 then we need to
                // reduce it, maintaining the fact that inserted
                // is after the min location and not after the
                // end location (i.e. before or overlapping the end)
                var centerIndex    = minIndex + (gap / 2);
                var centerLocation = this.items[centerIndex].GetDetails();
                if (inserted.IsAfter(centerLocation))
                {
                    minIndex = centerIndex;
                }
                else
                {
                    maxLocation = new LocationWithIndex(centerIndex, centerLocation);
                };

                gap = maxLocation.Index - minIndex;
            }
        }
Пример #4
0
        private bool MergeRange(
            SingleSelectionWithLocation inserted,
            LocationWithIndex firstExisting,
            LocationWithIndex lastExisting)
        {
            if (inserted.Start <= firstExisting.Selection.Start && inserted.End >= lastExisting.Selection.End)
            {
                // If the new selection completely overlaps the existing ones
                // we can simply use the new selection
                this.items[firstExisting.Index] = inserted.Selection;
            }
            else
            {
                // If the new selection does not completely overlap the old ones
                // then we need to create a new selection that is the union of
                // the old and new ones
                this.items[firstExisting.Index] = inserted.ExpandTo(
                    firstExisting.Selection.Start,
                    lastExisting.Selection.End);
            }

            // We need to move any selections after the last existing one
            // up in the list to fill the hole left by replacing multiple
            // selections with a single one and adjust the selection count
            // in the list
            var emptyGap = lastExisting.Index - firstExisting.Index;

            for (int i = lastExisting.Index + 1; i < this.Count; ++i)
            {
                this.items[i - emptyGap] = this.items[i];
            }

            this.Count -= emptyGap;

            // The overall selections will always have changed with a range merge
            return(true);
        }
Пример #5
0
 public LocationWithIndex(int index, SingleSelectionWithLocation selection)
 {
     this.Index     = index;
     this.Selection = selection;
 }
Пример #6
0
 public bool IsAfter(SingleSelectionWithLocation other)
 => this.IsZeroLength || other.IsZeroLength ? this.Start > other.End : this.Start >= other.End;
Пример #7
0
 public bool IsBefore(SingleSelectionWithLocation other)
 => this.IsZeroLength || other.IsZeroLength ? this.End < other.Start : this.End <= other.Start;