function findSelectorAtDocumentPos(editor, pos) {
        var cm = editor._codeMirror;
        var ctx = TokenUtils.getInitialContext(cm, $.extend({}, pos));
        var selector = "", foundChars = false;
        var isPreprocessorDoc = isCSSPreprocessorFile(editor.document.file.fullPath);
        var selectorArray = [];

        function _skipToOpeningBracket(ctx, startChar) {
            var unmatchedBraces = 0;
            if (!startChar) {
                startChar = "}";
            }
            while (true) {
                if (startChar === ctx.token.string) {
                    unmatchedBraces++;
                } else if (ctx.token.string.match(_invertedBracketPairs[startChar])) {
                    unmatchedBraces--;
                    if (unmatchedBraces <= 0) {
                        return;
                    }
                }

                if (!TokenUtils.movePrevToken(ctx)) {
                    return;
                }
            }
        }

        // Parse a selector. Assumes ctx is pointing at the opening
        // { that is after the selector name.
        function _parseSelector(ctx) {
            var selector = "";

            // Skip over {
            TokenUtils.movePrevToken(ctx);

            while (true) {
                if (ctx.token.type !== "comment") {
                    // Stop once we've reached a {, }, or ;
                    if (/[\{\}\;]/.test(ctx.token.string)) {
                        break;
                    }

                    // Stop once we've reached a <style ...> tag
                    if (ctx.token.string === "style" && ctx.token.type === "tag") {
                        // Remove everything up to end-of-tag from selector
                        var eotIndex = selector.indexOf(">");
                        if (eotIndex !== -1) {
                            selector = selector.substring(eotIndex + 1);
                        }
                        break;
                    }

                    selector = ctx.token.string + selector;
                }
                if (!TokenUtils.movePrevToken(ctx)) {
                    break;
                }
            }

            return selector;
        }

        var skipPrevSibling = false,
            state           = _getContextState(ctx);

        // If the cursor is inside a non-whitespace token with "block" or "top" state, then it is inside a
        // selector. The only exception is when it is immediately after the '{'.
        if (isPreprocessorDoc && _hasNonWhitespace(ctx.token.string) && ctx.token.string !== "{" &&
                (state.state === "block" || state.state === "top")) {
            foundChars = true;
        }

        // scan backwards to see if the cursor is in a rule
        do {
            if (ctx.token.type !== "comment") {
                if (ctx.token.string === "}") {
                    if (isPreprocessorDoc) {
                        if (state.state === "top") {
                            break;
                        }
                        skipPrevSibling = true;
                        // Skip past the entire preceding block until the matching "{"
                        _skipToOpeningBracket(ctx, "}");
                    } else {
                        break;
                    }
                } else if (ctx.token.string === "{") {
                    selector = _parseSelector(ctx);
                    if (isPreprocessorDoc) {
                        if (!skipPrevSibling && !/^\s*@/.test(selector)) {
                            selectorArray.unshift(selector);
                        }
                        if (skipPrevSibling) {
                            skipPrevSibling = false;
                        }
                    } else {
                        break;
                    }
                } else {
                    if (!isPreprocessorDoc && _hasNonWhitespace(ctx.token.string)) {
                        foundChars = true;
                    }
                    TokenUtils.movePrevToken(ctx);
                }
            } else {
                TokenUtils.movePrevToken(ctx);
            }
        } while (!TokenUtils.isAtStart(ctx));

        selector = _stripAtRules(selector);

        // Reset the context to original scan position
        ctx = TokenUtils.getInitialContext(cm, $.extend({}, pos));

        // special case - we aren't in a selector and haven't found any chars,
        // look at the next immediate token to see if it is non-whitespace.
        // For preprocessor documents we need to move the cursor to next non-whitespace
        // token so that we can collect the current selector if the cursor is inside it.
        if ((!selector && !foundChars && !isPreprocessorDoc) ||
                (isPreprocessorDoc && (ctx.token.string === "" || /\s+/.test(ctx.token.string)))) {
            if (TokenUtils.moveNextToken(ctx) && ctx.token.type !== "comment" && _hasNonWhitespace(ctx.token.string)) {
                foundChars = true;
                ctx = TokenUtils.getInitialContext(cm, $.extend({}, pos));
            }
        }

        // At this point if we haven't found a selector, but have seen chars when
        // scanning, assume we are in the middle of a selector. For a preprocessor
        // document we also need to collect the current selector if the cursor is
        // within the selector or whitespaces immediately before or after it.
        if ((!selector || isPreprocessorDoc) && foundChars) {
            // scan forward to see if the cursor is in a selector
            while (true) {
                if (ctx.token.type !== "comment") {
                    if (ctx.token.string === "{") {
                        selector = _parseSelector(ctx);
                        if (isPreprocessorDoc && !/^\s*@/.test(selector)) {
                            selectorArray.push(selector);
                        }
                        break;
                    } else if (ctx.token.string === "}" || ctx.token.string === ";") {
                        break;
                    }
                }
                if (!TokenUtils.moveNextToken(ctx)) {
                    break;
                }
            }
        }

        if (isPreprocessorDoc) {
            return _getSelectorInFinalCSSForm(selectorArray);
        }

        return _stripAtRules(selector);
    }
function findSelectorAtDocumentPos(editor, pos) {
        var cm = editor._codeMirror;
        var ctx = TokenUtils.getInitialContext(cm, $.extend({}, pos));
        var selector = "", foundChars = false;
        var isPreprocessorDoc = isCSSPreprocessorFile(editor.document.file.fullPath);
        var selectorArray = [];

        function _skipToOpeningBracket(ctx, startChar) {
            var unmatchedBraces = 0;
            if (!startChar) {
                startChar = "}";
            }
            while (true) {
                if (startChar === ctx.token.string) {
                    unmatchedBraces++;
                } else if (ctx.token.string.match(_invertedBracketPairs[startChar])) {
                    unmatchedBraces--;
                    if (unmatchedBraces <= 0) {
                        return;
                    }
                }

                if (!TokenUtils.movePrevToken(ctx)) {
                    return;
                }
            }
        }

        // Parse a selector. Assumes ctx is pointing at the opening
        // { that is after the selector name.
        function _parseSelector(ctx) {
            var selector = "";

            // Skip over {
            TokenUtils.movePrevToken(ctx);

            while (true) {
                if (ctx.token.type !== "comment") {
                    // Stop once we've reached a {, }, or ;
                    if (/[\{\}\;]/.test(ctx.token.string)) {
                        break;
                    }

                    // Stop once we've reached a <style ...> tag
                    if (ctx.token.string === "style" && ctx.token.type === "tag") {
                        // Remove everything up to end-of-tag from selector
                        var eotIndex = selector.indexOf(">");
                        if (eotIndex !== -1) {
                            selector = selector.substring(eotIndex + 1);
                        }
                        break;
                    }

                    selector = ctx.token.string + selector;
                }
                if (!TokenUtils.movePrevToken(ctx)) {
                    break;
                }
            }

            return selector;
        }

        var skipPrevSibling = false,
            state           = _getContextState(ctx);

        // If the cursor is inside a non-whitespace token with "block" or "top" state, then it is inside a
        // selector. The only exception is when it is immediately after the '{'.
        if (isPreprocessorDoc && _hasNonWhitespace(ctx.token.string) && ctx.token.string !== "{" &&
                (state.state === "block" || state.state === "top")) {
            foundChars = true;
        }

        // scan backwards to see if the cursor is in a rule
        do {
            if (ctx.token.type !== "comment") {
                if (ctx.token.string === "}") {
                    if (isPreprocessorDoc) {
                        if (state.state === "top") {
                            break;
                        }
                        skipPrevSibling = true;
                        // Skip past the entire preceding block until the matching "{"
                        _skipToOpeningBracket(ctx, "}");
                    } else {
                        break;
                    }
                } else if (ctx.token.string === "{") {
                    selector = _parseSelector(ctx);
                    if (isPreprocessorDoc) {
                        if (!skipPrevSibling && !/^\s*@/.test(selector)) {
                            selectorArray.unshift(selector);
                        }
                        if (skipPrevSibling) {
                            skipPrevSibling = false;
                        }
                    } else {
                        break;
                    }
                } else {
                    if (!isPreprocessorDoc && _hasNonWhitespace(ctx.token.string)) {
                        foundChars = true;
                    }
                    TokenUtils.movePrevToken(ctx);
                }
            } else {
                TokenUtils.movePrevToken(ctx);
            }
        } while (!TokenUtils.isAtStart(ctx));

        selector = _stripAtRules(selector);

        // Reset the context to original scan position
        ctx = TokenUtils.getInitialContext(cm, $.extend({}, pos));

        // special case - we aren't in a selector and haven't found any chars,
        // look at the next immediate token to see if it is non-whitespace.
        // For preprocessor documents we need to move the cursor to next non-whitespace
        // token so that we can collect the current selector if the cursor is inside it.
        if ((!selector && !foundChars && !isPreprocessorDoc) ||
                (isPreprocessorDoc && (ctx.token.string === "" || /\s+/.test(ctx.token.string)))) {
            if (TokenUtils.moveNextToken(ctx) && ctx.token.type !== "comment" && _hasNonWhitespace(ctx.token.string)) {
                foundChars = true;
                ctx = TokenUtils.getInitialContext(cm, $.extend({}, pos));
            }
        }

        // At this point if we haven't found a selector, but have seen chars when
        // scanning, assume we are in the middle of a selector. For a preprocessor
        // document we also need to collect the current selector if the cursor is
        // within the selector or whitespaces immediately before or after it.
        if ((!selector || isPreprocessorDoc) && foundChars) {
            // scan forward to see if the cursor is in a selector
            while (true) {
                if (ctx.token.type !== "comment") {
                    if (ctx.token.string === "{") {
                        selector = _parseSelector(ctx);
                        if (isPreprocessorDoc && !/^\s*@/.test(selector)) {
                            selectorArray.push(selector);
                        }
                        break;
                    } else if (ctx.token.string === "}" || ctx.token.string === ";") {
                        break;
                    }
                }
                if (!TokenUtils.moveNextToken(ctx)) {
                    break;
                }
            }
        }

        if (isPreprocessorDoc) {
            return _getSelectorInFinalCSSForm(selectorArray);
        }

        return _stripAtRules(selector);
    }
function findSelectorAtDocumentPos ( editor , pos ) { var cm = editor . _codeMirror ; var ctx = TokenUtils . getInitialContext ( cm , $ . extend ( { } , pos ) ) ; var selector = "" , foundChars = false ; var isPreprocessorDoc = isCSSPreprocessorFile ( editor . document . file . fullPath ) ; var selectorArray = [ ] ; function _skipToOpeningBracket ( ctx , startChar ) { var unmatchedBraces = 0 ; if ( ! startChar ) { startChar = "}" ; } while ( true ) { if ( startChar === ctx . token . string ) { unmatchedBraces ++ ; } else if ( ctx . token . string . match ( _invertedBracketPairs [ startChar ] ) ) { unmatchedBraces -- ; if ( unmatchedBraces <= 0 ) { return ; } } if ( ! TokenUtils . movePrevToken ( ctx ) ) { return ; } } } // Parse a selector. Assumes ctx is pointing at the opening // { that is after the selector name. function _parseSelector ( ctx ) { var selector = "" ; // Skip over { TokenUtils . movePrevToken ( ctx ) ; while ( true ) { if ( ctx . token . type !== "comment" ) { // Stop once we've reached a {, }, or ; if ( / [\{\}\;] / . test ( ctx . token . string ) ) { break ; } // Stop once we've reached a <style ...> tag if ( ctx . token . string === "style" && ctx . token . type === "tag" ) { // Remove everything up to end-of-tag from selector var eotIndex = selector . indexOf ( ">" ) ; if ( eotIndex !== - 1 ) { selector = selector . substring ( eotIndex + 1 ) ; } break ; } selector = ctx . token . string + selector ; } if ( ! TokenUtils . movePrevToken ( ctx ) ) { break ; } } return selector ; } var skipPrevSibling = false , state = _getContextState ( ctx ) ; // If the cursor is inside a non-whitespace token with "block" or "top" state, then it is inside a // selector. The only exception is when it is immediately after the '{'. if ( isPreprocessorDoc && _hasNonWhitespace ( ctx . token . string ) && ctx . token . string !== "{" && ( state . state === "block" || state . state === "top" ) ) { foundChars = true ; } // scan backwards to see if the cursor is in a rule do { if ( ctx . token . type !== "comment" ) { if ( ctx . token . string === "}" ) { if ( isPreprocessorDoc ) { if ( state . state === "top" ) { break ; } skipPrevSibling = true ; // Skip past the entire preceding block until the matching "{" _skipToOpeningBracket ( ctx , "}" ) ; } else { break ; } } else if ( ctx . token . string === "{" ) { selector = _parseSelector ( ctx ) ; if ( isPreprocessorDoc ) { if ( ! skipPrevSibling && ! / ^\s*@ / . test ( selector ) ) { selectorArray . unshift ( selector ) ; } if ( skipPrevSibling ) { skipPrevSibling = false ; } } else { break ; } } else { if ( ! isPreprocessorDoc && _hasNonWhitespace ( ctx . token . string ) ) { foundChars = true ; } TokenUtils . movePrevToken ( ctx ) ; } } else { TokenUtils . movePrevToken ( ctx ) ; } } while ( ! TokenUtils . isAtStart ( ctx ) ) ; selector = _stripAtRules ( selector ) ; // Reset the context to original scan position ctx = TokenUtils . getInitialContext ( cm , $ . extend ( { } , pos ) ) ; // special case - we aren't in a selector and haven't found any chars, // look at the next immediate token to see if it is non-whitespace. // For preprocessor documents we need to move the cursor to next non-whitespace // token so that we can collect the current selector if the cursor is inside it. if ( ( ! selector && ! foundChars && ! isPreprocessorDoc ) || ( isPreprocessorDoc && ( ctx . token . string === "" || / \s+ / . test ( ctx . token . string ) ) ) ) { if ( TokenUtils . moveNextToken ( ctx ) && ctx . token . type !== "comment" && _hasNonWhitespace ( ctx . token . string ) ) { foundChars = true ; ctx = TokenUtils . getInitialContext ( cm , $ . extend ( { } , pos ) ) ; } } // At this point if we haven't found a selector, but have seen chars when // scanning, assume we are in the middle of a selector. For a preprocessor // document we also need to collect the current selector if the cursor is // within the selector or whitespaces immediately before or after it. if ( ( ! selector || isPreprocessorDoc ) && foundChars ) { // scan forward to see if the cursor is in a selector while ( true ) { if ( ctx . token . type !== "comment" ) { if ( ctx . token . string === "{" ) { selector = _parseSelector ( ctx ) ; if ( isPreprocessorDoc && ! / ^\s*@ / . test ( selector ) ) { selectorArray . push ( selector ) ; } break ; } else if ( ctx . token . string === "}" || ctx . token . string === ";" ) { break ; } } if ( ! TokenUtils . moveNextToken ( ctx ) ) { break ; } } } if ( isPreprocessorDoc ) { return _getSelectorInFinalCSSForm ( selectorArray ) ; } return _stripAtRules ( selector ) ; }
Returns the selector(s) of the rule at the specified document pos, or "" if the position is
is not within a style rule.

@param {!Editor} editor Editor to search
@param {!{line: number, ch: number}} pos Position to search
@return {string} Selector(s) for the rule at the specified position, or "" if the position
is not within a style rule. If the rule has multiple selectors, a comma-separated
selector string is returned.
Returns the selector ( s ) of the rule at the specified document pos or if the position is is not within a style rule .
Find a selector at the given position.