in vsintegration/src/FSharp.LanguageService.Base/Source.cs [1035:1114]
public bool GetWordExtent(int line, int idx, WORDEXTFLAGS flags, out int startIdx, out int endIdx)
{
Debug.Assert(line >= 0 && idx >= 0);
startIdx = endIdx = idx;
int length;
NativeMethods.ThrowOnFailure(this.textLines.GetLengthOfLine(line, out length));
// pin to length of line just in case we return false and skip pinning at the end of this method.
startIdx = endIdx = Math.Min(idx, length);
if (length == 0)
{
return false;
}
//get the character classes
TokenInfo[] lineInfo = this.colorizer.GetLineInfo(this.textLines, line, this.colorState);
if (lineInfo == null || lineInfo.Length == 0) return false;
int count = lineInfo.Length;
TokenInfo info = new TokenInfo();
int index = this.GetTokenInfoAt(lineInfo, idx, ref info);
if (index < 0) return false;
// don't do anything in comment or text or literal space, unless we
// are doing intellisense in which case we want to match the entire value
// of quoted strings.
TokenType type = info.Type;
if ((flags != FSharpSourceBase_DEPRECATED.WholeToken || type != TokenType.String) && (type == TokenType.Comment || type == TokenType.LineComment || type == TokenType.Text || type == TokenType.String || type == TokenType.Literal))
return false;
//search for a token
switch (flags & WORDEXTFLAGS.WORDEXT_MOVETYPE_MASK)
{
case WORDEXTFLAGS.WORDEXT_PREVIOUS:
index--;
while (index >= 0 && !MatchToken(flags, lineInfo[index])) index--;
if (index < 0) return false;
break;
case WORDEXTFLAGS.WORDEXT_NEXT:
index++;
while (index < count && !MatchToken(flags, lineInfo[index])) index++;
if (index >= count) return false;
break;
case WORDEXTFLAGS.WORDEXT_NEAREST:
{
int prevIdx = index;
prevIdx--;
while (prevIdx >= 0 && !MatchToken(flags, lineInfo[prevIdx])) prevIdx--;
int nextIdx = index;
while (nextIdx < count && !MatchToken(flags, lineInfo[nextIdx])) nextIdx++;
if (prevIdx < 0 && nextIdx >= count) return false;
else if (nextIdx >= count) index = prevIdx;
else if (prevIdx < 0) index = nextIdx;
else if (index - prevIdx < nextIdx - index) index = prevIdx;
else
index = nextIdx;
break;
}
case WORDEXTFLAGS.WORDEXT_CURRENT:
default:
if (!MatchToken(flags, info))
return false;
break;
}
info = lineInfo[index];
// We found something, set the span, pinned to the valid coordinates for the
// current line.
startIdx = Math.Min(length, info.StartIndex);
endIdx = Math.Min(length, info.EndIndex);
// The scanner endIndex is the last char of the symbol, but
// GetWordExtent wants it to be the next char after that, so
// we increment the endIdx (if we can).
if (endIdx < length) endIdx++;
return true;
}