static public bool FindCurrentToken(SnapshotPoint currentPosition, out SnapshotSpan span) { ITextSnapshotLine textSnapshotLine = currentPosition.GetContainingLine(); LineBuffer lineText = new LineBuffer(textSnapshotLine); int lineLength = textSnapshotLine.LengthIncludingLineBreak; int iCol = (currentPosition - textSnapshotLine.Start); // handle end of buffer case if (iCol >= lineLength) { span = new SnapshotSpan(currentPosition.Snapshot, textSnapshotLine.End, 0); return(true); } // scan left for base char while ((iCol > 0) && !IsGraphemeBreak(lineText, iCol)) { iCol--; } // if it's a word, return the word char ch = lineText[iCol]; if (IsWordChar(ch)) { return(FindCurrentWordCoords(new SnapshotPoint(currentPosition.Snapshot, textSnapshotLine.Start + iCol), out span)); } // contiguous whitespace int iBeg; if (Char.IsWhiteSpace(ch)) { for (iBeg = iCol - 1; iBeg >= 0; --iBeg) { if (!Char.IsWhiteSpace(lineText[iBeg])) { break; } } iBeg++; for (++iCol; iCol < lineLength; ++iCol) { if (!Char.IsWhiteSpace(lineText[iCol])) { break; } } } // contiguous punctuation and math symbols else if (Char.IsPunctuation(ch) || IsMathSymbol(ch)) { for (iBeg = iCol - 1; iBeg >= 0; --iBeg) { ch = lineText[iBeg]; if (!(Char.IsPunctuation(ch) || IsMathSymbol(ch))) { break; } } iBeg++; for (++iCol; iCol < lineLength; ++iCol) { ch = lineText[iCol]; if (!(Char.IsPunctuation(ch) || IsMathSymbol(ch))) { break; } } } //Let's get the whole surrogate pair. else if (Char.IsHighSurrogate(ch) && ((iCol + 1) < lineLength) && Char.IsLowSurrogate(lineText[iCol + 1])) { iBeg = iCol; iCol += 2; } // any other single char else { iBeg = iCol++; } if (iCol > lineLength) { iCol = lineLength; } // Done -- fill in the data span = new SnapshotSpan(currentPosition.Snapshot, (textSnapshotLine.Start + iBeg), (iCol - iBeg)); return(true); }
// Returns true if iChar is at a grapheme boundary public static bool IsGraphemeBreak(LineBuffer line, int iChar) { if (iChar <= 0) { return(true); } char cR = line[iChar]; if (cR == 0) { return(true); } char cL = line[(iChar - 1)]; if (cL == 0) { return(true); } // break around line breaks if (IsLineBreak(cL) || IsLineBreak(cR)) { return(true); } // don't separate a combining char from it's base if (IsCombining(cR)) { // A combining character after a quote or whitespace does not combine with the quote or whitespace if (cL != '\'' && cL != '\"' && !Char.IsWhiteSpace(cL) && Char.IsLetter(cL)) { return(false); } } // don't break surrogate pairs if (Char.IsHighSurrogate(cL)) { return(!Char.IsLowSurrogate(cR)); } HangulJamoType hjL = GetHangulJamoType(cL); HangulJamoType hjR = GetHangulJamoType(cR); if ((hjL != HangulJamoType.Other) && (hjR != HangulJamoType.Other)) { switch (hjL) { case HangulJamoType.Lead: return(false); case HangulJamoType.Vowel: return(HangulJamoType.Lead == hjR); case HangulJamoType.Trail: return(HangulJamoType.Trail != hjR); default: break; } } return(true); }