function getTagInfo(editor, constPos) {
        //we're going to changing pos a lot, but we don't want to mess up
        //the pos the caller passed in so we use extend to make a safe copy of it.	
        //This is what pass by value in c++ would do.	
        var pos = $.extend({}, constPos),
            ctx = _getInitialContext(editor._codeMirror, pos),
            offset = _offsetInToken(ctx),
            tagInfo,
            tokenType;
        
        // check if this is inside a style block.
        if (editor.getModeForSelection() !== "html") {
            return createTagInfo();
        }
        
        //check and see where we are in the tag
        if (ctx.token.string.length > 0 && ctx.token.string.trim().length === 0) {

            // token at (i.e. before) pos is whitespace, so test token at next pos
            //
            // note: getTokenAt() does range checking for ch. If it detects that ch is past
            // EOL, it uses EOL, same token is returned, and the following condition fails,
            // so we don't need to worry about testPos being valid.
            var testPos = {ch: ctx.pos.ch + 1, line: ctx.pos.line},
                testToken = editor._codeMirror.getTokenAt(testPos);

            if (testToken.string.length > 0 && testToken.string.trim().length > 0 &&
                    testToken.string.charAt(0) !== ">") {
                // pos has whitespace before it and non-whitespace after it, so use token after
                ctx.token = testToken;

                if (ctx.token.className === "tag") {
                    // check to see if the cursor is just before a "<" but not in any tag.
                    if (ctx.token.string.charAt(0) === "<") {
                        return createTagInfo();
                    }
                } else if (ctx.token.className === "attribute") {
                    // check to see if the user is going to add a new attr before an existing one
                    return _getTagInfoStartingFromAttrName(ctx, false);
                } else if (ctx.token.className === "string") {
                    // we're either before a "=" or an attribute value.
                    return createTagInfo();
                }

                ctx.pos = testPos;
                // Get the new offset from test token and subtract one for testPos adjustment
                offset = _offsetInToken(ctx) - 1;
            } else {
                // We get here if ">" or white spaces after testPos.
                // next, see what's before pos
                if (!_movePrevToken(ctx)) {
                    return createTagInfo();
                }
            
                if (ctx.token.className !== "tag") {
                    //if wasn't the tag name, assume it was an attr value
                    tagInfo = _getTagInfoStartingFromAttrValue(ctx);

                    //if it wasn't an attr value, assume it was an empty attr (ie. attr with no value)
                    if (!tagInfo.tagName) {
                        tagInfo = _getTagInfoStartingFromAttrName(ctx, true);
                    }

                    //We don't want to give context for the previous attr
                    //and we want it to look like the user is going to add a new attr
                    if (tagInfo.tagName) {
                        return createTagInfo(ATTR_NAME, 0, tagInfo.tagName);
                    }
                    return createTagInfo();
                }
                
                //we know the tag was here, so they user is adding an attr name
                tokenType = ATTR_NAME;
                offset = 0;
            }
        }
        
        if (ctx.token.className === "tag") {
            // Check if the user just typed a white space after "<" that made an existing tag invalid.
            if (ctx.token.string.indexOf("< ") === 0) {
                return createTagInfo();
            }
            
            //check to see if this is the closing of a tag (either the start or end)
            if (ctx.token.string === ">" ||
                    (ctx.token.string.charAt(0) === "<" && ctx.token.string.charAt(1) === "/")) {
                return createTagInfo();
            }
            
            if (!tokenType) {
                tokenType = TAG_NAME;
                offset--; //need to take off 1 for the leading "<"
            }
            
            //we're actually in the tag, just return that as we have no relevant 
            //info about what attr is selected
            return createTagInfo(tokenType, offset, _extractTagName(ctx));
        }
        
        if (ctx.token.string === "=") {
            // To discourage unquoted attribute value usage we intentionally return an invalid tag info here.
            // This will also spare us from handling the conversion between quoted and unquoted attribute values.
            return createTagInfo();
        }
        
        if (ctx.token.className === "attribute") {
            tagInfo = _getTagInfoStartingFromAttrName(ctx, false);
        } else {
            // if we're not at a tag, "=", or attribute name, assume we're in the value
            tagInfo = _getTagInfoStartingFromAttrValue(ctx);
        }
        
        if (tokenType && tagInfo.tagName) {
            tagInfo.position.tokenType = tokenType;
            tagInfo.position.offset = offset;
        }
        
        return tagInfo;
    }
Figure out if we're in a tag, and if we are return info about what to hint about it
An example token stream for this tag is <span id="open-files-disclosure-arrow"></span> : 
     className:tag       string:"<span"
     className:          string:" "
     className:attribute string:"id"
     className:          string:"="
     className:string    string:""open-files-disclosure-arrow""
     className:tag       string:"></span>"
@param {Editor} editor An instance of a Brackets editor
@param {{ch: number, line: number}} constPos  A CM pos (likely from editor.getCursor())
@return {{tagName:string, attr{name:string, value:string}, hint:{type:{string}, offset{number}}}}
             A tagInfo object with some context about the current tag hint.