private void TokenFromPosition(ITextSnapshot snapshot, int position, out int itemIndex, out int offset) { // Normally token stream does not change after formatting so we can simply rely on the fact // that caret position is going to remain relative to the same token index itemIndex = -1; offset = 0; // Expand range to include the next line. This is needed when user introduces line break. var lineNumber = snapshot.GetLineNumberFromPosition(_changingRange.End); if (lineNumber < snapshot.LineCount - 1) { var end = snapshot.GetLineFromLineNumber(lineNumber + 1).End; _changingRange = TextRange.FromBounds(_changingRange.Start, end); } var tokenizer = new RTokenizer(); IReadOnlyTextRangeCollection <RToken> tokens = tokenizer.Tokenize(new TextProvider(snapshot), _changingRange.Start, _changingRange.Length, true); // Check if position is adjacent to previous token int prevItemIndex = tokens.GetFirstItemBeforePosition(position); if (prevItemIndex >= 0 && tokens[prevItemIndex].End == position) { itemIndex = prevItemIndex; offset = -tokens[itemIndex].Length; return; } int nextItemIndex = tokens.GetFirstItemAfterOrAtPosition(position); if (nextItemIndex >= 0) { // If two tokens are adjacent, gravity is negative, i.e. caret travels // with preceding token so it won't just to aniother line if, say, // formatter decides to insert a new line between tokens. if (nextItemIndex > 0 && tokens[nextItemIndex - 1].End == tokens[nextItemIndex].Start) { nextItemIndex--; } offset = tokens[nextItemIndex].Start - position; itemIndex = nextItemIndex; return; } // We are past last token if (tokens.Count > 0) { itemIndex = tokens.Count - 1; offset = tokens[itemIndex].Start - position; } else { itemIndex = -1; offset = position; } }
private static void TokenFromPosition(ITextSnapshot snapshot, int position, out int itemIndex, out int offset) { // Normally token stream does not change after formatting so we can simply rely on the fact // that caret position is going to remain relative to the same token index itemIndex = -1; offset = 0; var tokenizer = new RTokenizer(); IReadOnlyTextRangeCollection <RToken> tokens = tokenizer.Tokenize(new TextProvider(snapshot), 0, snapshot.Length, true); // Check if position is adjacent to previous token int prevItemIndex = tokens.GetFirstItemBeforePosition(position); if (prevItemIndex >= 0 && tokens[prevItemIndex].End == position) { itemIndex = prevItemIndex; offset = -tokens[itemIndex].Length; return; } int nextItemIndex = tokens.GetFirstItemAfterOrAtPosition(position); if (nextItemIndex >= 0) { // If two tokens are adjacent, gravity is negative, i.e. caret travels // with preceding token so it won't just to aniother line if, say, // formatter decides to insert a new line between tokens. if (nextItemIndex > 0 && tokens[nextItemIndex - 1].End == tokens[nextItemIndex].Start) { nextItemIndex--; } offset = tokens[nextItemIndex].Start - position; itemIndex = nextItemIndex; return; } // We are past last token if (tokens.Count > 0) { itemIndex = tokens.Count - 1; offset = tokens[itemIndex].Start - position; } else { itemIndex = -1; offset = position; } }