📄 highlight.c
字号:
/*** Callback wrapper around the above function.*/static void handleUnparsedRegionCB(textDisp *textD, int pos, void *cbArg){ handleUnparsedRegion((WindowInfo*)cbArg, textD->styleBuffer, pos);}/*** Re-parse the smallest region possible around a modification to buffer "buf"** to gurantee that the promised context lines and characters have** been presented to the patterns. Changes the style buffer in "highlightData"** with the parsing result.*/static void incrementalReparse(windowHighlightData *highlightData, textBuffer *buf, int pos, int nInserted, const char *delimiters){ int beginParse, endParse, endAt, lastMod, parseInStyle, nPasses; textBuffer *styleBuf = highlightData->styleBuffer; highlightDataRec *pass1Patterns = highlightData->pass1Patterns; highlightDataRec *pass2Patterns = highlightData->pass2Patterns; highlightDataRec *startPattern; reparseContext *context = &highlightData->contextRequirements; char *parentStyles = highlightData->parentStyles; /* Find the position "beginParse" at which to begin reparsing. This is far enough back in the buffer such that the guranteed number of lines and characters of context are examined. */ beginParse = pos; parseInStyle = findSafeParseRestartPos(buf, highlightData, &beginParse); /* Find the position "endParse" at which point it is safe to stop parsing, unless styles are getting changed beyond the last modification */ lastMod = pos + nInserted; endParse = forwardOneContext(buf, context, lastMod); /* ** Parse the buffer from beginParse, until styles compare ** with originals for one full context distance. Distance increases ** by powers of two until nothing changes from previous step. If ** parsing ends before endParse, start again one level up in the ** pattern hierarchy */ for (nPasses=0; ; nPasses++) { /* Parse forward from beginParse to one context beyond the end of the last modification */ startPattern = patternOfStyle(pass1Patterns, parseInStyle); /* If there is no pattern matching the style, it must be a pass-2 style. It that case, it is (probably) safe to start parsing with the root pass-1 pattern again. Anyway, passing a NULL-pointer to the parse routine would result in a crash; restarting with pass-1 patterns is certainly preferable, even if there is a slight chance of a faulty coloring. */ if (!startPattern) { startPattern = pass1Patterns; } endAt = parseBufferRange(startPattern, pass2Patterns, buf, styleBuf, context, beginParse, endParse, delimiters); /* If parse completed at this level, move one style up in the hierarchy and start again from where the previous parse left off. */ if (endAt < endParse) { beginParse = endAt; endParse = forwardOneContext(buf, context, max(endAt, max(lastModified(styleBuf), lastMod))); if (IS_PLAIN(parseInStyle)) { fprintf(stderr, "NEdit internal error: incr. reparse fell short\n"); return; } parseInStyle = parentStyleOf(parentStyles, parseInStyle); /* One context distance beyond last style changed means we're done */ } else if (lastModified(styleBuf) <= lastMod) { return; /* Styles are changing beyond the modification, continue extending the end of the parse range by powers of 2 * REPARSE_CHUNK_SIZE and reparse until nothing changes */ } else { lastMod = lastModified(styleBuf); endParse = min(buf->length, forwardOneContext(buf, context, lastMod) + (REPARSE_CHUNK_SIZE << nPasses)); } } }/*** Parse text in buffer "buf" between positions "beginParse" and "endParse"** using pass 1 patterns over the entire range and pass 2 patterns where needed** to determine whether re-parsed areas have changed and need to be redrawn.** Deposits style information in "styleBuf" and expands the selection in** styleBuf to show the additional areas which have changed and need** redrawing. beginParse must be a position from which pass 1 parsing may** safely be started using the pass1Patterns given. Internally, adds a** "takeoff" safety region before beginParse, so that pass 2 patterns will be** allowed to match properly if they begin before beginParse, and a "landing"** safety region beyond endparse so that endParse is guranteed to be parsed** correctly in both passes. Returns the buffer position at which parsing** finished (this will normally be endParse, unless the pass1Patterns is a** pattern which does end and the end is reached).*/static int parseBufferRange(highlightDataRec *pass1Patterns, highlightDataRec *pass2Patterns, textBuffer *buf, textBuffer *styleBuf, reparseContext *contextRequirements, int beginParse, int endParse, const char *delimiters){ char *string, *styleString, *stringPtr, *stylePtr, *temp, prevChar; int endSafety, endPass2Safety, startPass2Safety, tempLen; int modStart, modEnd, beginSafety, beginStyle, p, style; int firstPass2Style = pass2Patterns == NULL ? INT_MAX : (unsigned char)pass2Patterns[1].style; /* Begin parsing one context distance back (or to the last style change) */ beginStyle = pass1Patterns->style; if (CAN_CROSS_LINE_BOUNDARIES(contextRequirements)) { beginSafety = backwardOneContext(buf, contextRequirements, beginParse); for (p=beginParse; p>=beginSafety; p--) { style = BufGetCharacter(styleBuf, p-1); if (!EQUIVALENT_STYLE(style, beginStyle, firstPass2Style)) { beginSafety = p; break; } } } else { for (beginSafety=max(0,beginParse-1); beginSafety>0; beginSafety--) { style = BufGetCharacter(styleBuf, beginSafety); if (!EQUIVALENT_STYLE(style, beginStyle, firstPass2Style) || BufGetCharacter(buf, beginSafety) == '\n') { beginSafety++; break; } } } /* Parse one parse context beyond requested end to gurantee that parsing at endParse is complete, unless patterns can't cross line boundaries, in which case the end of the line is fine */ if (endParse == 0) return 0; if (CAN_CROSS_LINE_BOUNDARIES(contextRequirements)) endSafety = forwardOneContext(buf, contextRequirements, endParse); else if (endParse>=buf->length || (BufGetCharacter(buf,endParse-1)=='\n')) endSafety = endParse; else endSafety = min(buf->length, BufEndOfLine(buf, endParse) + 1); /* copy the buffer range into a string */ string = BufGetRange(buf, beginSafety, endSafety); styleString = BufGetRange(styleBuf, beginSafety, endSafety); /* Parse it with pass 1 patterns */ /* printf("parsing from %d thru %d\n", beginSafety, endSafety); */ prevChar = getPrevChar(buf, beginParse); stringPtr = &string[beginParse-beginSafety]; stylePtr = &styleString[beginParse-beginSafety]; parseString(pass1Patterns, &stringPtr, &stylePtr, endParse-beginParse, &prevChar, False, delimiters, string); /* On non top-level patterns, parsing can end early */ endParse = min(endParse, stringPtr-string + beginSafety); /* If there are no pass 2 patterns, we're done */ if (pass2Patterns == NULL) goto parseDone; /* Parsing of pass 2 patterns is done only as necessary for determining where styles have changed. Find the area to avoid, which is already marked as changed (all inserted text and previously modified areas) */ if (styleBuf->primary.selected) { modStart = styleBuf->primary.start; modEnd = styleBuf->primary.end; } else modStart = modEnd = 0; /* Re-parse the areas before the modification with pass 2 patterns, from beginSafety to far enough beyond modStart to gurantee that parsing at modStart is correct (pass 2 patterns must match entirely within one context distance, and only on the top level). If the parse region ends entirely before the modification or at or beyond modEnd, parse the whole thing and take advantage of the safety region which will be thrown away below. Otherwise save the contents of the safety region temporarily, and restore it after the parse. */ if (beginSafety < modStart) { if (endSafety > modStart) { endPass2Safety = forwardOneContext(buf, contextRequirements, modStart); if (endPass2Safety + PASS_2_REPARSE_CHUNK_SIZE >= modEnd) endPass2Safety = endSafety; } else endPass2Safety = endSafety; prevChar = getPrevChar(buf, beginSafety); if (endPass2Safety == endSafety) { passTwoParseString(pass2Patterns, string, styleString, endParse - beginSafety, &prevChar, False, delimiters, string); goto parseDone; } else { tempLen = endPass2Safety - modStart; temp = XtMalloc(tempLen); strncpy(temp, &styleString[modStart-beginSafety], tempLen); passTwoParseString(pass2Patterns, string, styleString, modStart - beginSafety, &prevChar, False, delimiters, string); strncpy(&styleString[modStart-beginSafety], temp, tempLen); XtFree(temp); } } /* Re-parse the areas after the modification with pass 2 patterns, from modEnd to endSafety, with an additional safety region before modEnd to ensure that parsing at modEnd is correct. */ if (endParse > modEnd) { if (beginSafety > modEnd) { prevChar = getPrevChar(buf, beginSafety); passTwoParseString(pass2Patterns, string, styleString, endParse - beginSafety, &prevChar, False, delimiters, string); } else { startPass2Safety = max(beginSafety, backwardOneContext(buf, contextRequirements, modEnd)); tempLen = modEnd - startPass2Safety; temp = XtMalloc(tempLen); strncpy(temp, &styleString[startPass2Safety-beginSafety], tempLen); prevChar = getPrevChar(buf, startPass2Safety); passTwoParseString(pass2Patterns, &string[startPass2Safety-beginSafety], &styleString[startPass2Safety-beginSafety], endParse-startPass2Safety, &prevChar, False, delimiters, string); strncpy(&styleString[startPass2Safety-beginSafety], temp, tempLen); XtFree(temp); } } parseDone: /* Update the style buffer with the new style information, but only through endParse. Skip the safety region at the end */ styleString[endParse-beginSafety] = '\0'; modifyStyleBuf(styleBuf, &styleString[beginParse-beginSafety], beginParse, endParse, firstPass2Style); XtFree(styleString); XtFree(string); return endParse;}/*** Parses "string" according to compiled regular expressions in "pattern"** until endRE is or errorRE are matched, or end of string is reached.** Advances "string", "styleString" pointers to the next character past** the end of the parsed section, and updates "prevChar" to reflect** the new character before "string".** If "anchored" is true, just scan the sub-pattern starting at the beginning** of the string. "length" is how much of the string must be parsed, but** "string" must still be null terminated, the termination indicating how** far the string should be searched, and "length" the part which is actually** required (the string may or may not be parsed beyond "length").**** Returns True if parsing was done and the parse succeeded. Returns False if** the error pattern matched, if the end of the string was reached without** matching the end expression, or in the unlikely event of an internal error.*/static int parseString(highlightDataRec *pattern, char **string, char **styleString, int length, char *prevChar, int anchored, const char *delimiters, const char* lookBehindTo){ int i, subExecuted, subIndex; char *stringPtr, *stylePtr, *startingStringPtr, *savedStartPtr; signed char *subExpr; char savedPrevChar; highlightDataRec *subPat = NULL, *subSubPat; if (length <= 0) return False; stringPtr = *string; stylePtr = *styleString; while(ExecRE(pattern->subPatternRE, NULL, stringPtr, anchored ? *string+1 : *string+length+1, False, *prevChar, '\0', delimiters, lookBehindTo)) { /* Beware of the case where only one real branch exists, but that branch has sub-branches itself. In that case the top_branch refers to the matching sub-branch and must be ignored. */ subIndex = (pattern->nSubBranches > 1) ? pattern->subPatternRE->top_branch : 0; /* Combination of all sub-patterns and end pattern matched */ /* printf("combined patterns RE matched at %d\n", pattern->subPatternRE->startp[0] - *string); */ startingStringPtr = stringPtr; /* Fill in the pattern style for the text that was skipped over before the match, and advance the pointers to the start of the pattern */ fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->startp[0], pattern->style, prevChar); /* If the combined pattern matched this pattern's end pattern, we're done. Fill in the style string, update the pointers, color the end expression if there were coloring sub-patterns, and return */ savedStartPtr = stringPtr; savedPrevChar = *prevChar; if (pattern->endRE != NULL) { if (subIndex == 0) { fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->endp[0], pattern->style, prevChar); subExecuted = False; for (i=0;i<pattern->nSubPatterns; i++) { subPat = pattern->subPatterns[i]; if (subPat->colorOnly) { if (!subExecuted) { if (!ExecRE(pattern->endRE, NULL, savedStartPtr, savedStartPtr+1, False, savedPrevChar, '\0', delimiters, lookBehindTo)) { fprintf(stderr, "Internal error, failed to " "recover end match in parseString\n"); return False; } subExecuted = True; } for (subExpr=subPat->endSubexprs; *subExpr!=-1; subExpr++) recolorSubexpr(pattern->endRE, *subExpr, subPat->style, *string, *styleString); } } *string = stringPtr; *styleString = stylePtr; return True; } --subIndex; } /* If the combined pattern matched this pattern's error pattern, we're done. Fill in the style string, update the pointers, and return */ if (pattern->errorRE != NULL) { if (subIndex == 0) { fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->startp[0], pattern->style, prevChar);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -