static bool IsTagWithoutClose( const VString &inTag ) { static const char *sList[] = { "!DOCTYPE", "AREA", "BASE", "BASEFONT", "BR", "COL", "FRAME", "HR" "IMG", "INPUT", "ISINDEX", "LINK", "META", "PARAM", }; for (sLONG i = 0; i < sizeof( sList ) / sizeof( const char * ); i++) { if (inTag.EqualTo( VString( sList[ i ] ), false )) return true; } return false; }
void VJSLanguageSyntaxTesterColorResults::_GetProperty( VJSParms_getProperty &ioParams, IJSLanguageSyntaxTesterColorResults *inResults ) { VString propName; if (ioParams.GetPropertyName( propName )) { sLONG result = -1; if (propName.EqualTo( CVSTR( "kColumnName" ), true )) result = eColumnName; else if (propName.EqualTo( CVSTR( "kTableName" ), true )) result = eTableName; else if (propName.EqualTo( CVSTR( "kComment" ), true )) result = eComment; else if (propName.EqualTo( CVSTR( "kKeyword" ), true )) result = eKeyword; else if (propName.EqualTo( CVSTR( "kNormal" ), true )) result = eNormal; else if (propName.EqualTo( CVSTR( "kNumber" ), true )) result = eNumber; else if (propName.EqualTo( CVSTR( "kString" ), true )) result = eString; else if (propName.EqualTo( CVSTR( "kName" ), true )) result = eName; else if (propName.EqualTo( CVSTR( "kComparison" ), true )) result = eComparison; else if (propName.EqualTo( CVSTR( "kFunctionKeyword" ), true )) result = eFunctionKeyword; else if (propName.EqualTo( CVSTR( "kDebug" ), true )) result = eDebug; if (-1 != result) ioParams.ReturnNumber( result ); } }
bool HTMLLexer::IsMultiLineCommentStart( UniChar inChar, sLONG &outType ) { // We are looking for <!--, which requires three more tokens of lookahead. if (CHAR_LESS_THAN_SIGN != inChar) return false; if (!fLexerInput->HasMoreChars()) return false; VString subStr; fLexerInput->GetSubString( fLexerInput->GetCurrentPosition(), 4, subStr ); if (subStr.EqualTo( CVSTR( "<!--" ), false )) { outType = kHTMLMultilineComment; return true; } return false; }
bool HTMLLexer::IsMultiLineCommentEnd( UniChar inChar, sLONG &outCharsToConsume, sLONG inType ) { // We have to check for newlines for no other reason than bookkeeping. This records when we // locate a newline so that the fLineNumber property remains properly in-sync. We will consume // the newline for the caller if that's what we've gotten. if (IsLineEnding( inChar )) ConsumeLineEnding( inChar ); // We are looking for --> if (inType != kCommentContinuationType && inType != kHTMLMultilineComment) return false; if (CHAR_HYPHEN_MINUS != inChar) return false; if (!fLexerInput->HasMoreChars()) return false; VString subStr; fLexerInput->GetSubString( fLexerInput->GetCurrentPosition() + 1, 2, subStr ); if (subStr.EqualTo( CVSTR( "->" ), false )) { // We're at the end of the comment, but the caller still needs to consume two characters outCharsToConsume = 2; return true; } return false; }
void VHTMLSyntax::GetSuggestions( ICodeEditorDocument* inDocument, sLONG inLineNumber, sLONG inPos, ITipInfoArray *outSuggestions, sLONG& outStartOffset, bool inAll ) { // Get the text for the line up to the point of insertion, and we'll lex that to see if we can come up // with some rational suggestions for the user. VString xstr; inDocument->GetLine( inLineNumber, xstr ); xstr.Truncate( inPos ); char *lexinput = CreateUTF8String( xstr ); struct htmlLexeme *list = parseHTML( lexinput ); // Gin up some line params for tracking state information VLineSyntaxParams *currentLineParams = currentLineParams = new VLineSyntaxParams(); if (inLineNumber > 0) { // We're starting where we left off on the previous line currentLineParams->CopyState( static_cast< VLineSyntaxParams * >( inDocument->GetLineSyntaxParams( inLineNumber - 1 ) ) ); } // Given the list of HTML tokens, let's walk over the list and try to make some sense // of them. Walk over the list one token at a time, and see if we can make sense of // what we've got. This is going to be awfully similar to the way we do things in the // SetLine method, except that we're not actually updating the line state for the current // line. Instead, we're working on a copy of the existing information. struct htmlLexeme *cur = list; int lastTokenProcessed = 0; while (cur) { if (kKeyword == cur->fStyle) { lastTokenProcessed = 3; // Keywords a bit trickier than you might think because we need to be sure they're actually part of a // tag. If the user types something like: <b>This table rocks</b>, we only want to highlight the b in the // begin and end tag, and not the "table" in the user's text. To deal with this, we have an "in tag" flag // that basically turns keyword highlighting on and off. if (currentLineParams->IsProcessingTag()) { // If we're processing an opening tag, then we want to push the keyword onto the tag stack. But if we're // processing a closing tag, then we want to pop the last keyword off the tag stack and try to match it up // to what we just processed. If they match, we're golden. If not, we just assume the user's mismatching // their tags because they're an idiot. VString tagName; xstr.GetSubString( cur->fOffset + 1, cur->fLength, tagName ); if (currentLineParams->IsProcessingStartTag()) { currentLineParams->PushTag( tagName ); // Note that we are no longer processing the start of a tag. This allows us to handle attributes // separately from the tag itself. currentLineParams->SetIsProcessingStartTag( false ); } else { VString lastTag; currentLineParams->PopTag( lastTag ); if (!lastTag.EqualTo( tagName, false )) { // The tags don't match, so we're just going to ignore the issue // TODO: do something more sensible here } } } } else if (kTagOpen == cur->fStyle || kEndTagOpen == cur->fStyle) { lastTokenProcessed = (kTagOpen == cur->fStyle) ? 1 : 2; currentLineParams->SetIsProcessingTag( true ); currentLineParams->SetIsProcessingStartTag( kTagOpen == cur->fStyle ); } else if (kTagClose == cur->fStyle || kTagSelfClose == cur->fStyle) { lastTokenProcessed = 0; currentLineParams->SetIsProcessingTag( false ); // If we just handled a self-closing tag (like <br />), then we want to pop it from the stack // TODO: some tags can't have matching pairs, like <br>, so even if it's not self-closing, we want // to pop it off the tag stack. Handle that here if (kTagSelfClose == cur->fStyle) { VString toss; currentLineParams->PopTag( toss ); } } else { lastTokenProcessed = 0; } cur = cur->fNext; } if (lastTokenProcessed == 1) { // We processed a tag opener, but no keyword for the tag. So let's make a bunch of suggestions! } else if (lastTokenProcessed == 2) { // We processed a tag closer, but no keyword for the tag. Grab the last opened tag from the list // and suggest it as the closer VString suggestion; currentLineParams->LastTag( suggestion ); outSuggestions->AddTip( new VCodeEditorTipInfo( inDocument, suggestion, htmlcolorShadow[ keyword_col ] ) ); } delete currentLineParams; FreeLexemeList( list ); }
void VHTMLSyntax::SetLine( ICodeEditorDocument *inDocument, sLONG inLineNumber, bool inLoading ) { #if 0 VString source; inDocument->GetLine( inLineNumber, source ); HTMLParser parser; HTMLParser::State *state = NULL; HTMLParser::State *prevLineState = NULL; if (inLineNumber > 0) prevLineState = GetStateForLine( inDocument, inLineNumber - 1 ); ParsingCookie *cookie = new ParsingCookie( inDocument, inLineNumber ); parser.Parse( source, prevLineState, &state, this, (const void *)cookie ); SetStateForLine( inDocument, inLineNumber, state ); cookie->Release(); #else // Get the params for the current line so that we can set them up properly VLineSyntaxParams *currentLineParams = static_cast< VLineSyntaxParams * >( inDocument->GetLineSyntaxParams( inLineNumber ) ); if (!currentLineParams) { currentLineParams = new VLineSyntaxParams(); inDocument->AssignLineSyntaxParams( inLineNumber, currentLineParams ); } bool previousOpenCommentState = currentLineParams->IsOpenComment(); // We also want the params for the preceeding line, in case we're the continuation of // a comment. VLineSyntaxParams *previousLineParams = NULL; if (inLineNumber > 0) { previousLineParams = static_cast< VLineSyntaxParams * >( inDocument->GetLineSyntaxParams( inLineNumber - 1 ) ); } VString xstr; inDocument->GetLine(inLineNumber,xstr); inDocument->SetLineStyle(inLineNumber,0,xstr.GetLength(),0); //initiate the line char *lexinput = CreateUTF8String( xstr ); struct htmlLexeme *list = parseHTML( lexinput ); // If we used to be in comment continuation mode, the assumption is that we're still in // comment continuation mode. We'll switch this off if the comment ends though currentLineParams->CopyState( previousLineParams ); // We are going to keep track of which open and close tags we've seen on the line. This allows // us to determine which unmatched open and close tags exist so we can associate that data with // the line. As we find open tags, we'll push them onto the open tag list. As we find close tags, // we will scan the open tag list and *remove* any that match. If there's no match, then we'll add // the tag to the close list. std::vector< VString > openList, closeList; // Given the list of HTML tokens, let's walk over the list and try to make some sense // of them. Walk over the list one token at a time, and see if we can make sense of // what we've got. struct htmlLexeme *cur = list; while (cur) { // There are only three types of comments we need to worry about. Full comments, // open comments and close comments. We'll get a token representing any one of the // three. However, we need to pay special attention to multi-line comments, since // they won't lex out entirely correct. If the previous line was part of an open // comment, then we want to keep walking over the tokens, marking them as part of // the comment, until we run out of tokens, or we find a kCommentClose token. if (currentLineParams->IsOpenComment()) { if (kCommentClose == cur->fStyle) { // We found the end of the comment, so we can highlight it appropriately, // and go back to our regularly scheduled lexing inDocument->SetLineStyle( inLineNumber, cur->fOffset, cur->fOffset + cur->fLength, htmlcolorShadow[ comment_col ] ); // We're also done being a part of the comment continuation train currentLineParams->SetIsOpenComment( false ); } else { // This is just another part of the comment inDocument->SetLineStyle( inLineNumber, cur->fOffset, cur->fOffset + cur->fLength, htmlcolorShadow[ comment_col ] ); } // Advance cur = cur->fNext; continue; } if (kCompleteComment == cur->fStyle) { // A complete comment is the easiest of the three cases. Just highlight it inDocument->SetLineStyle( inLineNumber, cur->fOffset, cur->fOffset + cur->fLength, htmlcolorShadow[ comment_col ] ); } else if (kCommentOpen == cur->fStyle) { // An open comment must be the last token in the list xbox_assert( !cur->fNext ); // We want to highlight from here to the end of the line inDocument->SetLineStyle( inLineNumber, cur->fOffset, cur->fOffset + cur->fLength, htmlcolorShadow[ comment_col ] ); // We also want to flag that this line ends with an open comment currentLineParams->SetIsOpenComment( true ); } else if (kCommentClose == cur->fStyle) { // If we got a close comment token, then something's off. That means the user put in a close comment // token, but they never opened it. We're going to ignore that state, and flag this as being normal inDocument->SetLineStyle( inLineNumber, cur->fOffset, cur->fOffset + cur->fLength, htmlcolorShadow[ scommentend_col ] ); } else if (kString == cur->fStyle) { inDocument->SetLineStyle( inLineNumber, cur->fOffset, cur->fOffset + cur->fLength, htmlcolorShadow[ string_col ] ); } else if (kKeyword == cur->fStyle) { // Keywords a bit trickier than you might think because we need to be sure they're actually part of a // tag. If the user types something like: <b>This table rocks</b>, we only want to highlight the b in the // begin and end tag, and not the "table" in the user's text. To deal with this, we have an "in tag" flag // that basically turns keyword highlighting on and off. if (currentLineParams->IsProcessingTag()) { inDocument->SetLineStyle( inLineNumber, cur->fOffset, cur->fOffset + cur->fLength, htmlcolorShadow[ keyword_col ] ); // If we're processing an opening tag, then we want to push the keyword onto the tag stack. But if we're // processing a closing tag, then we want to pop the last keyword off the tag stack and try to match it up // to what we just processed. If they match, we're golden. If not, we just assume the user's mismatching // their tags because they're an idiot. VString tagName; xstr.GetSubString( cur->fOffset + 1, cur->fLength, tagName ); if (currentLineParams->IsProcessingStartTag()) { if (!IsTagWithoutClose( tagName )) { openList.push_back( tagName ); } currentLineParams->PushTag( tagName ); // Note that we are no longer processing the start of a tag. This allows us to handle attributes // separately from the tag itself. currentLineParams->SetIsProcessingStartTag( false ); } else { // Check to see if this closed tag is on the open list. If it is, we want to remove it from the // list. Otherwise, we want to add it to the close list. bool bAddToClose = true; for (std::vector< VString >::iterator iter = openList.begin(); bAddToClose && iter != openList.end();) { if (tagName.EqualTo( *iter, false )) { iter = openList.erase( iter ); bAddToClose = false; } else { ++iter; } } if (bAddToClose) closeList.push_back( tagName ); VString lastTag; currentLineParams->PopTag( lastTag ); if (!lastTag.EqualTo( tagName, false )) { // The tags don't match, so we're just going to ignore the issue // TODO: do something more sensible here } } } } else if (kNumber == cur->fStyle) { inDocument->SetLineStyle( inLineNumber, cur->fOffset, cur->fOffset + cur->fLength, htmlcolorShadow[ allnum_col ] ); } else if (kTagOpen == cur->fStyle || kEndTagOpen == cur->fStyle) { currentLineParams->SetIsProcessingTag( true ); currentLineParams->SetIsProcessingStartTag( kTagOpen == cur->fStyle ); } else if (kTagClose == cur->fStyle || kTagSelfClose == cur->fStyle) { currentLineParams->SetIsProcessingTag( false ); // If we just handled a self-closing tag (like <br />), then we want to pop it from the stack VString lastTag; currentLineParams->LastTag( lastTag ); if (kTagSelfClose == cur->fStyle || IsTagWithoutClose( lastTag )) { VString toss; currentLineParams->PopTag( toss ); // We also do not want to add it to our list of open tags for the line, since it's self-closed for (std::vector< VString >::iterator iter = openList.begin(); iter != openList.end(); ++iter) { if (lastTag.EqualTo( *iter, false )) { iter = openList.erase( iter ); break; } } } } cur = cur->fNext; } FreeLexemeList( list ); // Now that we have an open and a close list, we want to associate them with the line. for (std::vector< VString >::iterator iter = openList.begin(); iter != openList.end(); ++iter) { currentLineParams->AddUnmatchedOpenTag( *iter ); } for (std::vector< VString >::iterator iter = closeList.begin(); iter != closeList.end(); ++iter) { currentLineParams->AddUnmatchedCloseTag( *iter ); } // There are two cases we really need to care about. If the line now ends in // an open comment (and didn't used to), we want to colorize down the document. // Also, if the line no longer ends in an open comment (but used to), we want to // colorize down the document. In either case, we want to keep colorizing subsequent // lines until the comment is ended or the end of the document is reached. if ((!previousOpenCommentState && currentLineParams->IsOpenComment() || // Now ends with open comment, didn't used to previousOpenCommentState && !currentLineParams->IsOpenComment()) && // Used to end with an open comment, but no longer does inLineNumber + 1 < inDocument->GetNbLines()) { SetLine( inDocument, inLineNumber + 1, inLoading ); } #endif // old code }
bool MatchesCloseTag( const VString &inTag ) { for (std::vector< VString >::iterator iter = fUnmatchedCloseTags.begin(); iter != fUnmatchedCloseTags.end(); ++iter) { if (inTag.EqualTo( *iter, false )) return true; } return false; }