public bool GetWordExtent()

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;
        }