Example #1
0
        private void ExpandToWordBreakAndContext(ITextPointer position, LogicalDirection direction, XmlLanguage language,
            out ITextPointer contentPosition, out ITextPointer contextPosition) 
        {
            ITextPointer start; 
            ITextPointer end; 
            ITextPointer outwardPosition;
            ITextPointer inwardPosition; 
            TextMap textMap;
            ArrayList segments;
            SpellerInterop.STextRange sTextRange;
            LogicalDirection inwardDirection; 
            int i;
 
            contentPosition = position; 
            contextPosition = position;
 
            if (position.GetPointerContext(direction) == TextPointerContext.None)
            {
                // There is no following context, we're at document start/end.
                return; 
            }
 
            // Disable spell checking functionality since we're only 
            // interested in word breaks here.  This greatly cuts down
            // the engine's workload. 
            _spellerInterop.SetContextOption("IsSpellChecking", false);

            //
            // Build an array of wordbreak offsets surrounding the position. 
            //
 
            // 1. Search outward, into surrounding text.  We need MinWordBreaksForContext 
            // word breaks to handle multi-word errors.
            outwardPosition = SearchForWordBreaks(position, direction, language, MinWordBreaksForContext, true /* stopOnError */); 

            // 2. Search inward, towards content.  We just need one word break inward.
            inwardDirection = direction == LogicalDirection.Forward ? LogicalDirection.Backward : LogicalDirection.Forward;
            inwardPosition = SearchForWordBreaks(position, inwardDirection, language, 1, false /* stopOnError */); 

            // Get combined word breaks.  This may not be the same as we calculated 
            // in two parts above, since we don't know yet whether or not position is 
            // on a word break.
            if (direction == LogicalDirection.Backward) 
            {
                start = outwardPosition;
                end = inwardPosition;
            } 
            else
            { 
                start = inwardPosition; 
                end = outwardPosition;
            } 
            textMap = new TextMap(start, end, position, position);
            segments = new ArrayList(MinWordBreaksForContext + 1);
            _spellerInterop.EnumTextSegments(textMap.Text, textMap.TextLength, null,
                new SpellerInterop.EnumTextSegmentsCallback(ExpandToWordBreakCallback), segments); 

            // 
            // Use our table of word breaks to calculate context and content positions. 
            //
            if (segments.Count == 0) 
            {
                // No segments.  This can happen if position is surrounded by
                // nothing but white space.  We've already initialized contentPosition
                // and contextPosition so there's nothing to do. 
            }
            else 
            { 
                int leftWordBreak;
                int rightWordBreak; 
                int contentOffset;
                int contextOffset;

                // Figure out where position lives in the segment list. 
                i = FindPositionInSegmentList(textMap, direction, segments, out leftWordBreak, out rightWordBreak);
 
                // contentPosition should be an edge on the segment we found. 
                if (direction == LogicalDirection.Backward)
                { 
                    contentOffset = textMap.ContentStartOffset == rightWordBreak ? rightWordBreak : leftWordBreak;
                }
                else
                { 
                    contentOffset = textMap.ContentStartOffset == leftWordBreak ? leftWordBreak : rightWordBreak;
                } 
                contentPosition = textMap.MapOffsetToPosition(contentOffset); 

                // contextPosition should be MinWordBreaksForContext - 1 words away. 
                if (direction == LogicalDirection.Backward)
                {
                    i -= (MinWordBreaksForContext - 1);
                    sTextRange = (SpellerInterop.STextRange)segments[Math.Max(i, 0)]; 
                    // We might actually follow contentOffset if we're at the document edge.
                    // Don't let that happen. 
                    contextOffset = Math.Min(sTextRange.Start, contentOffset); 
                }
                else 
                {
                    i += MinWordBreaksForContext;
                    sTextRange = (SpellerInterop.STextRange)segments[Math.Min(i, segments.Count-1)];
                    // We might actually preceed contentOffset if we're at the document edge. 
                    // Don't let that happen.
                    contextOffset = Math.Max(sTextRange.Start + sTextRange.Length, contentOffset); 
                } 
                contextPosition = textMap.MapOffsetToPosition(contextOffset);
            } 

            // Final fixup: if the dirty range covers only formatting (which is not passed
            // to the speller engine) then we might actually "expand" in the wrong
            // direction, since the TextMap will jump over formatting. 
            // Backup if necessary.
            if (direction == LogicalDirection.Backward) 
            { 
                if (position.CompareTo(contentPosition) < 0)
                { 
                    contentPosition = position;
                }
                if (position.CompareTo(contextPosition) < 0)
                { 
                    contextPosition = position;
                } 
            } 
            else
            { 
                if (position.CompareTo(contentPosition) > 0)
                {
                    contentPosition = position;
                } 
                if (position.CompareTo(contextPosition) > 0)
                { 
                    contextPosition = position; 
                }
            } 
        }
Example #2
0
        private void AdjustScanRangeAroundComposition(ITextPointer rawStart, ITextPointer rawEnd,
            out ITextPointer start, out ITextPointer end) 
        {
            start = rawStart;
            end = rawEnd;
 
            if (!_textEditor.Selection.IsEmpty)
            { 
                // No caret to adjust around. 
                return;
            } 

            if (!_textEditor.UiScope.IsKeyboardFocused)
            {
                // Document isn't focused, no caret rendered. 
                return;
            } 
 
            // Get the word surrounding the caret.
 
            ITextPointer wordBreakLeft;
            ITextPointer wordBreakRight;
            ITextPointer caretPosition;
            TextMap textMap; 
            ArrayList segments;
 
            caretPosition = _textEditor.Selection.Start; 

            // Disable spell checking functionality since we're only 
            // interested in word breaks here.  This greatly cuts down
            // the engine's workload.
            _spellerInterop.SetContextOption("IsSpellChecking", false);
 
            XmlLanguage language = GetCurrentLanguage(caretPosition);
            wordBreakLeft = SearchForWordBreaks(caretPosition, LogicalDirection.Backward, language, 1, false /* stopOnError */); 
            wordBreakRight = SearchForWordBreaks(caretPosition, LogicalDirection.Forward, language, 1, false /* stopOnError */); 

            textMap = new TextMap(wordBreakLeft, wordBreakRight, caretPosition, caretPosition); 
            segments = new ArrayList(2);
            _spellerInterop.EnumTextSegments(textMap.Text, textMap.TextLength, null,
                new SpellerInterop.EnumTextSegmentsCallback(ExpandToWordBreakCallback), segments);
 
            // We will have no segments when position is surrounded by
            // nothing but white space. 
            if (segments.Count != 0) 
            {
                int leftBreakOffset; 
                int rightBreakOffset;

                // Figure out where caretPosition lives in the segment list.
                FindPositionInSegmentList(textMap, LogicalDirection.Backward, segments, out leftBreakOffset, out rightBreakOffset); 

                wordBreakLeft = textMap.MapOffsetToPosition(leftBreakOffset); 
                wordBreakRight = textMap.MapOffsetToPosition(rightBreakOffset); 
            }
 
            // Overlap?
            if (wordBreakLeft.CompareTo(rawEnd) < 0 &&
                wordBreakRight.CompareTo(rawStart) > 0)
            { 
                if (wordBreakLeft.CompareTo(rawStart) > 0)
                { 
                    // Truncate the right half of the input range. 
                    end = wordBreakLeft;
                } 
                else if (wordBreakRight.CompareTo(rawEnd) < 0)
                {
                    // Truncate the left half of the input range.
                    start = wordBreakRight; 
                }
                else 
                { 
                    // The entire dirty range is covered by the caret word.
                    // Try to find a following dirty range. 
                    GetNextScanRangeRaw(wordBreakRight, out start, out end);
                }

                // Schedule a future callback to deal with the skipped 
                // overlapping section.
                ScheduleCaretMovedCallback(); 
            } 
        }
Example #3
0
        // Flags a run of text with an error.
        // In two exceptional circumstances we schedule an idle-time callback
        // to re-analyze the run instead of marking it:
        // - when the caret is within the error text. 
        // - when an IME composition covers the text.
        private void MarkErrorRange(TextMap textMap, SpellerInterop.STextRange sTextRange) 
        { 
            ITextPointer errorStart;
            ITextPointer errorEnd; 

            if (sTextRange.Start + sTextRange.Length > textMap.ContentEndOffset)
            {
                // We found an error that starts in the content but extends into 
                // the context.  This must be a multi-word error.
                // For now, ignore it. 
                // 
                return;
            } 

            errorStart = textMap.MapOffsetToPosition(sTextRange.Start);
            errorEnd = textMap.MapOffsetToPosition(sTextRange.Start + sTextRange.Length);
 
            if (sTextRange.Start < textMap.ContentStartOffset)
            { 
                Invariant.Assert(sTextRange.Start + sTextRange.Length > textMap.ContentStartOffset); 

                // We've found an error that start in the context and extends into 
                // the content.  This can happen as more text is revealed to the
                // speller engine as the caret moves forward.
                // E.g., while scanning "avalon's" we flag an error over "avalon",
                // ignoring the "'s" because the caret is positioned within that segment. 
                // Then, the user hits space and now we analyze "'s" along with its
                // preceding context "avalon".  In this final scan, "avalon's" as a while 
                // is flagged as an error and we enter this if statement. 

                // We must mark the range clean before we can mark it dirty. 
                // _statusTable.MarkErrorRange can only handle clean runs.
                _statusTable.MarkCleanRange(errorStart, errorEnd);
            }
 
            _statusTable.MarkErrorRange(errorStart, errorEnd);
        }