src/language/XMLUtils.js
function _getTagAttributeValue(editor, pos) {
        var ctx, tagName, attrName, exclusionList = [], offset, textBefore, textAfter;

        ctx = TokenUtils.getInitialContext(editor._codeMirror, pos);
        offset = TokenUtils.offsetInToken(ctx);

        // To support multiple options on the same attribute, we have
        // to break the value, these values will not be available then.
        if (ctx.token.type === "string" && /\s+/.test(ctx.token.string)) {
            textBefore = ctx.token.string.substr(1, offset);
            textAfter = ctx.token.string.substr(offset);

            // Remove quote from end of the string.
            if (/^['"]$/.test(ctx.token.string.substr(-1, 1))) {
                textAfter = textAfter.substr(0, textAfter.length - 1);
            }

            // Split the text before and after the offset, skipping the current query.
            exclusionList = exclusionList.concat(textBefore.split(/\s+/).slice(0, -1));
            exclusionList = exclusionList.concat(textAfter.split(/\s+/));

            // Filter through the list removing empty strings.
            exclusionList = exclusionList.filter(function (value) {
                if (value.length > 0) {
                    return true;
                }
            });
        }

        // Look-back and find tag and attributes.
        while (TokenUtils.movePrevToken(ctx)) {
            if (ctx.token.type === "tag bracket") {
                // Disallow hints in closing tags.
                if (ctx.token.string === "</") {
                    return null;
                }
                // Stop when closing bracket of another tag or opening bracket of its own in encountered.
                if (ctx.token.string.indexOf(">") >= 0 || ctx.token.string === "<") {
                    break;
                }
            }

            // Get the first previous attribute.
            if (ctx.token.type === "attribute" && !attrName) {
                attrName = ctx.token.string;
            }

            // Stop if we get a bracket after tag.
            if (ctx.token.type === "tag") {
                tagName = ctx.token.string;
                if (TokenUtils.movePrevToken(ctx)) {
                    if (ctx.token.type === "tag bracket" && ctx.token.string === "<") {
                        break;
                    }
                    return null;
                }
            }
        }

        return {
            tagName: tagName,
            attrName: attrName,
            exclusionList: exclusionList
        };
    }
function _getTagAttributeValue(editor, pos) {
        var ctx, tagName, attrName, exclusionList = [], offset, textBefore, textAfter;

        ctx = TokenUtils.getInitialContext(editor._codeMirror, pos);
        offset = TokenUtils.offsetInToken(ctx);

        // To support multiple options on the same attribute, we have
        // to break the value, these values will not be available then.
        if (ctx.token.type === "string" && /\s+/.test(ctx.token.string)) {
            textBefore = ctx.token.string.substr(1, offset);
            textAfter = ctx.token.string.substr(offset);

            // Remove quote from end of the string.
            if (/^['"]$/.test(ctx.token.string.substr(-1, 1))) {
                textAfter = textAfter.substr(0, textAfter.length - 1);
            }

            // Split the text before and after the offset, skipping the current query.
            exclusionList = exclusionList.concat(textBefore.split(/\s+/).slice(0, -1));
            exclusionList = exclusionList.concat(textAfter.split(/\s+/));

            // Filter through the list removing empty strings.
            exclusionList = exclusionList.filter(function (value) {
                if (value.length > 0) {
                    return true;
                }
            });
        }

        // Look-back and find tag and attributes.
        while (TokenUtils.movePrevToken(ctx)) {
            if (ctx.token.type === "tag bracket") {
                // Disallow hints in closing tags.
                if (ctx.token.string === "</") {
                    return null;
                }
                // Stop when closing bracket of another tag or opening bracket of its own in encountered.
                if (ctx.token.string.indexOf(">") >= 0 || ctx.token.string === "<") {
                    break;
                }
            }

            // Get the first previous attribute.
            if (ctx.token.type === "attribute" && !attrName) {
                attrName = ctx.token.string;
            }

            // Stop if we get a bracket after tag.
            if (ctx.token.type === "tag") {
                tagName = ctx.token.string;
                if (TokenUtils.movePrevToken(ctx)) {
                    if (ctx.token.type === "tag bracket" && ctx.token.string === "<") {
                        break;
                    }
                    return null;
                }
            }
        }

        return {
            tagName: tagName,
            attrName: attrName,
            exclusionList: exclusionList
        };
    }
function _getTagAttributeValue ( editor , pos ) { var ctx , tagName , attrName , exclusionList = [ ] , offset , textBefore , textAfter ; ctx = TokenUtils . getInitialContext ( editor . _codeMirror , pos ) ; offset = TokenUtils . offsetInToken ( ctx ) ; // To support multiple options on the same attribute, we have // to break the value, these values will not be available then. if ( ctx . token . type === "string" && / \s+ / . test ( ctx . token . string ) ) { textBefore = ctx . token . string . substr ( 1 , offset ) ; textAfter = ctx . token . string . substr ( offset ) ; // Remove quote from end of the string. if ( / ^['"]$ / . test ( ctx . token . string . substr ( - 1 , 1 ) ) ) { textAfter = textAfter . substr ( 0 , textAfter . length - 1 ) ; } // Split the text before and after the offset, skipping the current query. exclusionList = exclusionList . concat ( textBefore . split ( / \s+ / ) . slice ( 0 , - 1 ) ) ; exclusionList = exclusionList . concat ( textAfter . split ( / \s+ / ) ) ; // Filter through the list removing empty strings. exclusionList = exclusionList . filter ( function ( value ) { if ( value . length > 0 ) { return true ; } } ) ; } // Look-back and find tag and attributes. while ( TokenUtils . movePrevToken ( ctx ) ) { if ( ctx . token . type === "tag bracket" ) { // Disallow hints in closing tags. if ( ctx . token . string === "</" ) { return null ; } // Stop when closing bracket of another tag or opening bracket of its own in encountered. if ( ctx . token . string . indexOf ( ">" ) >= 0 || ctx . token . string === "<" ) { break ; } } // Get the first previous attribute. if ( ctx . token . type === "attribute" && ! attrName ) { attrName = ctx . token . string ; } // Stop if we get a bracket after tag. if ( ctx . token . type === "tag" ) { tagName = ctx . token . string ; if ( TokenUtils . movePrevToken ( ctx ) ) { if ( ctx . token . type === "tag bracket" && ctx . token . string === "<" ) { break ; } return null ; } } } return { tagName : tagName , attrName : attrName , exclusionList : exclusionList } ; }
Return the tag name, attribute name and a list of options used by the attribute

@param {!Editor} editor An instance of active editor
@param {!{line: number, ch: number}} pos Position of cursor in the editor
@return {!{tagName: string, attrName: string, exclusionList: Array.<string>}}
Return the tag name attribute name and a list of options used by the attribute