public static string GetVariableNameBeforeCaret(this ITextView textView) {
if (textView.Caret.InVirtualSpace) {
return string.Empty;
}
var position = textView.Caret.Position.BufferPosition;
var line = position.GetContainingLine();
// For performance reasons we won't be using AST here
// since during completion it is most probably damaged.
string lineText = line.GetText();
var tokenizer = new RTokenizer();
var tokens = tokenizer.Tokenize(lineText);
var tokenPosition = position - line.Start;
var index = tokens.GetFirstItemBeforePosition(tokenPosition);
// Preceding token must be right next to caret position
if (index < 0 || tokens[index].End < tokenPosition || !IsVariableNameToken(lineText, tokens[index])) {
return string.Empty;
}
if (index == 0) {
return IsVariableNameToken(lineText, tokens[0]) ? lineText.Substring(tokens[0].Start, tokens[0].Length) : string.Empty;
}
// Walk back through tokens allowing identifier and specific
// operator tokens. No whitespace is permitted between tokens.
// We have at least 2 tokens here.
int i = index;
for (; i > 0; i--) {
var precedingToken = tokens[i - 1];
var currentToken = tokens[i];
if (precedingToken.End < currentToken.Start || !IsVariableNameToken(lineText, precedingToken)) {
break;
}
}
return lineText.Substring(tokens[i].Start, tokens[index].End - tokens[i].Start);
}