#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif
#include "highlight.h"
#include "textBuf.h"
#include "textDisp.h"
#include "text.h"
#include "textP.h"
#include "nedit.h"
#include "regularExp.h"
#include "highlightData.h"
#include "preferences.h"
#include "window.h"
#include "../util/misc.h"
#include "../util/DialogF.h"
#include "../util/nedit_malloc.h"
#include <stdio.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#ifndef __MVS__
#include <sys/param.h>
#endif
#include <inttypes.h>
#include <Xm/Xm.h>
#include <Xm/XmP.h>
#if XmVersion >=
1002
#include <Xm/PrimitiveP.h>
#endif
#ifdef HAVE_DEBUG_H
#include "../debug.h"
#endif
#define PASS_2_REPARSE_CHUNK_SIZE 1000
#define REPARSE_CHUNK_SIZE 80
#define UNFINISHED_STYLE ASCII_A
#define PLAIN_STYLE (
ASCII_A+
1)
#define IS_PLAIN(style) (style ==
PLAIN_STYLE || style ==
UNFINISHED_STYLE)
#define IS_STYLED(style) (style !=
PLAIN_STYLE && style !=
UNFINISHED_STYLE)
#define EQUIVALENT_STYLE(style1, style2, firstPass2Style) (style1 == style2 || \
(style1 ==
UNFINISHED_STYLE && \
(style2 ==
PLAIN_STYLE || (
unsigned char)style2 >= firstPass2Style)) || \
(style2 ==
UNFINISHED_STYLE && \
(style1 ==
PLAIN_STYLE || (
unsigned char)style1 >= firstPass2Style)))
#define CAN_CROSS_LINE_BOUNDARIES(contextRequirements) \
(contextRequirements->nLines !=
1 || contextRequirements->nChars !=
0)
typedef struct _highlightDataRec {
regexp *startRE;
regexp *endRE;
regexp *errorRE;
regexp *subPatternRE;
char style;
int colorOnly;
signed char startSubexprs[
NSUBEXP+
1];
signed char endSubexprs[
NSUBEXP+
1];
int flags;
int nSubPatterns;
int nSubBranches;
int userStyleIndex;
struct _highlightDataRec **subPatterns;
} highlightDataRec;
typedef struct {
int nLines;
int nChars;
} reparseContext;
typedef struct {
highlightDataRec *pass1Patterns;
highlightDataRec *pass2Patterns;
char *parentStyles;
reparseContext contextRequirements;
styleTableEntry *styleTable;
int nStyles;
textBuffer *styleBuffer;
patternSet *patternSetForWindow;
} windowHighlightData;
static windowHighlightData *createHighlightData(WindowInfo *window,
patternSet *patSet);
static void freeHighlightData(windowHighlightData *hd);
static patternSet *findPatternsForWindow(WindowInfo *window,
int warn);
static highlightDataRec *compilePatterns(ColorProfile *colorProfile, Widget dialogParent,
highlightPattern *patternSrc,
int nPatterns);
static void freePatterns(highlightDataRec *patterns);
static void handleUnparsedRegion(
const WindowInfo* win, textBuffer* styleBuf,
int pos);
static void handleUnparsedRegionCB(
const textDisp* textD,
int pos,
const void* cbArg);
static void incrementalReparse(windowHighlightData *highlightData,
textBuffer *buf,
int pos,
int nInserted,
const char *delimiters);
static int parseBufferRange(highlightDataRec *pass1Patterns,
highlightDataRec *pass2Patterns, textBuffer *buf, textBuffer *styleBuf,
reparseContext *contextRequirements,
int beginParse,
int endParse,
const char *delimiters);
static int parseString(highlightDataRec *pattern,
const char **string,
char **styleString,
int length,
char *prevChar,
int anchored,
const char *delimiters,
const char* lookBehindTo,
const char* match_till);
static void passTwoParseString(highlightDataRec *pattern,
char *string,
char *styleString,
int length,
char *prevChar,
const char *delimiters,
const char* lookBehindTo,
const char* match_till);
static void fillStyleString(
const char **stringPtr,
char **stylePtr,
const char *toPtr,
char style,
char *prevChar);
static void modifyStyleBuf(textBuffer *styleBuf,
char *styleString,
int startPos,
int endPos,
int firstPass2Style);
static int lastModified(textBuffer *styleBuf);
static int max(
int i1,
int i2);
static int min(
int i1,
int i2);
static char getPrevChar(textBuffer *buf,
int pos);
static regexp *compileREAndWarn(Widget parent,
const char *re);
static int parentStyleOf(
const char *parentStyles,
int style);
static int isParentStyle(
const char *parentStyles,
int style1,
int style2);
static int findSafeParseRestartPos(textBuffer *buf,
windowHighlightData *highlightData,
int *pos);
static int backwardOneContext(textBuffer *buf, reparseContext *context,
int fromPos);
static int forwardOneContext(textBuffer *buf, reparseContext *context,
int fromPos);
static void recolorSubexpr(regexp *re,
int subexpr,
int style,
const char *string,
char *styleString);
static int indexOfNamedPattern(highlightPattern *patList,
int nPats,
const char *patName);
static int findTopLevelParentIndex(highlightPattern *patList,
int nPats,
int index);
static highlightDataRec *patternOfStyle(highlightDataRec *patterns,
int style);
static void updateWindowHeight(WindowInfo *window,
int oldFontHeight);
static int getFontHeight(WindowInfo *window);
static styleTableEntry *styleTableEntryOfCode(WindowInfo *window,
int hCode);
void SyntaxHighlightModifyCB(
int pos,
int nInserted,
int nDeleted,
int nRestyled,
const char *deletedText,
void *cbArg)
{
WindowInfo *window = (WindowInfo *)cbArg;
windowHighlightData
*highlightData = (windowHighlightData *)window->highlightData;
if(window->ansiColors) {
BufParseEscSeq(window->buffer, pos, nInserted, nDeleted);
}
if (highlightData ==
NULL)
return;
if (nInserted ==
0 && nDeleted ==
0) {
BufUnselect(highlightData->styleBuffer);
return;
}
if (nInserted >
0) {
char *insStyle;
int i;
insStyle = (
char*)NEditMalloc(nInserted +
1);
for (i=
0; i<nInserted; i++)
insStyle[i] =
UNFINISHED_STYLE;
insStyle[i] =
'\0';
BufReplace(highlightData->styleBuffer, pos, pos+nDeleted, insStyle);
NEditFree(insStyle);
}
else {
BufRemove(highlightData->styleBuffer, pos, pos+nDeleted);
}
BufSelect(highlightData->styleBuffer, pos, pos+nInserted);
if (highlightData->pass1Patterns)
incrementalReparse(highlightData, window->buffer, pos, nInserted,
GetWindowDelimiters(window));
}
void StartHighlighting(WindowInfo *window,
int warn)
{
patternSet *patterns;
windowHighlightData *highlightData;
char *stylePtr, *styleString;
const char *stringPtr, *bufString;
char prevChar =
'\0';
int i, oldFontHeight;
patterns = findPatternsForWindow(window, warn);
if (patterns ==
NULL)
return;
highlightData = createHighlightData(window, patterns);
if (highlightData ==
NULL)
return;
BeginWait(window->shell);
XmUpdateDisplay(window->shell);
stylePtr = styleString = (
char*)NEditMalloc(window->buffer->length +
1);
if (highlightData->pass1Patterns ==
NULL) {
for (i=
0; i<window->buffer->length; i++)
*stylePtr++ =
UNFINISHED_STYLE;
}
else {
stringPtr = bufString = BufAsString(window->buffer);
parseString(highlightData->pass1Patterns, &stringPtr, &stylePtr,
window->buffer->length, &prevChar, False,
GetWindowDelimiters(window), bufString,
NULL);
}
*stylePtr =
'\0';
BufSetAll(highlightData->styleBuffer, styleString);
NEditFree(styleString);
window->highlightData = highlightData;
oldFontHeight = getFontHeight(window);
AttachHighlightToWidget(window->textArea, window);
for (i=
0; i<window->nPanes; i++)
AttachHighlightToWidget(window->textPanes[i], window);
updateWindowHeight(window, oldFontHeight);
UpdateWMSizeHints(window);
UpdateMinPaneHeights(window);
XmUpdateDisplay(window->shell);
EndWait(window->shell);
}
void StopHighlighting(WindowInfo *window)
{
int i, oldFontHeight;
if (window->highlightData==
NULL)
return;
oldFontHeight = getFontHeight(window);
freeHighlightData((windowHighlightData *)window->highlightData);
window->highlightData =
NULL;
RemoveWidgetHighlight(window->textArea);
for (i=
0; i<window->nPanes; i++)
RemoveWidgetHighlight(window->textPanes[i]);
updateWindowHeight(window, oldFontHeight);
UpdateWMSizeHints(window);
UpdateMinPaneHeights(window);
}
void FreeHighlightingData(WindowInfo *window)
{
int i;
if (window->highlightData ==
NULL)
return;
freeHighlightData((windowHighlightData *)window->highlightData);
window->highlightData =
NULL;
((TextWidget)window->textArea)->text.textD->styleBuffer =
NULL;
for (i=
0; i<window->nPanes; i++)
((TextWidget)window->textPanes[i])->text.textD->styleBuffer =
NULL;
}
void AttachHighlightToWidget(Widget widget, WindowInfo *window)
{
windowHighlightData *highlightData =
(windowHighlightData *)window->highlightData;
TextDAttachHighlightData(((TextWidget)widget)->text.textD,
highlightData->styleBuffer, highlightData->styleTable,
highlightData->nStyles,
UNFINISHED_STYLE, handleUnparsedRegionCB,
window);
}
void RemoveWidgetHighlight(Widget widget)
{
TextDAttachHighlightData(((TextWidget)widget)->text.textD,
NULL,
NULL,
0,
UNFINISHED_STYLE,
NULL,
NULL);
}
void UpdateHighlightStyles(WindowInfo *window, Boolean redisplay)
{
patternSet *patterns;
windowHighlightData *highlightData;
windowHighlightData *oldHighlightData =
(windowHighlightData *)window->highlightData;
textBuffer *styleBuffer;
int i;
if (window->highlightData ==
NULL)
return;
patterns = findPatternsForWindow(window, False);
if (patterns ==
NULL) {
StopHighlighting(window);
return;
}
highlightData = createHighlightData(window, patterns);
if (highlightData ==
NULL) {
StopHighlighting(window);
return;
}
styleBuffer = oldHighlightData->styleBuffer;
oldHighlightData->styleBuffer = highlightData->styleBuffer;
freeHighlightData(oldHighlightData);
highlightData->styleBuffer = styleBuffer;
window->highlightData = highlightData;
((TextWidget)window->textArea)->text.textD->disableRedisplay = !redisplay;
AttachHighlightToWidget(window->textArea, window);
((TextWidget)window->textArea)->text.textD->disableRedisplay =
0;
for (i=
0; i<window->nPanes; i++) {
((TextWidget)window->textPanes[i])->text.textD->disableRedisplay = !redisplay;
AttachHighlightToWidget(window->textPanes[i], window);
((TextWidget)window->textPanes[i])->text.textD->disableRedisplay =
0;
}
}
int TestHighlightPatterns(patternSet *patSet)
{
windowHighlightData *highlightData;
highlightData = createHighlightData(WindowList, patSet);
if (highlightData ==
NULL)
return False;
freeHighlightData(highlightData);
return True;
}
void* GetHighlightInfo(WindowInfo *window,
int pos)
{
int style;
highlightDataRec *pattern =
NULL;
windowHighlightData *highlightData =
(windowHighlightData *)window->highlightData;
if (!highlightData)
return NULL;
style = (
int)BufGetCharacter(highlightData->styleBuffer, pos);
if (style ==
UNFINISHED_STYLE) {
handleUnparsedRegion(window, highlightData->styleBuffer, pos);
style = (
int)BufGetCharacter(highlightData->styleBuffer, pos);
}
if (highlightData->pass1Patterns) {
pattern = patternOfStyle(highlightData->pass1Patterns, style);
}
if (!pattern && highlightData->pass2Patterns) {
pattern = patternOfStyle(highlightData->pass2Patterns, style);
}
if (!pattern) {
return NULL;
}
return (
void*)(
intptr_t)pattern->userStyleIndex;
}
static void freeHighlightData(windowHighlightData *hd)
{
if (hd ==
NULL)
return;
if (hd->pass1Patterns !=
NULL)
freePatterns(hd->pass1Patterns);
if (hd->pass2Patterns !=
NULL)
freePatterns(hd->pass2Patterns);
NEditFree(hd->parentStyles);
BufFree(hd->styleBuffer);
NEditFree(hd->styleTable);
NEditFree(hd);
}
static patternSet *findPatternsForWindow(WindowInfo *window,
int warn)
{
patternSet *patterns;
char *modeName;
modeName = LanguageModeName(window->languageMode);
if (modeName ==
NULL) {
if (warn)
DialogF(
DF_WARN, window->shell,
1,
"Language Mode",
"No language-specific mode has been set for this file.\n\n"
"To use syntax highlighting in this window, please select a\n"
"language from the Preferences -> Language Modes menu.\n\n"
"New language modes and syntax highlighting patterns can be\n"
"added via Preferences -> Default Settings -> Language Modes,\n"
"and Preferences -> Default Settings -> Syntax Highlighting.",
"OK");
return NULL;
}
patterns = FindPatternSet(modeName);
if (patterns ==
NULL)
{
if (warn)
{
DialogF(
DF_WARN, window->shell,
1,
"Language Mode",
"Syntax highlighting is not available in language\n"
"mode %s.\n\n"
"You can create new syntax highlight patterns in the\n"
"Preferences -> Default Settings -> Syntax Highlighting\n"
"dialog, or choose a different language mode from:\n"
"Preferences -> Language Mode.",
"OK", modeName);
return NULL;
}
}
return patterns;
}
static windowHighlightData *createHighlightData(WindowInfo *window,
patternSet *patSet)
{
highlightPattern *patternSrc = patSet->patterns;
int nPatterns = patSet->nPatterns;
int contextLines = patSet->lineContext;
int contextChars = patSet->charContext;
int i, nPass1Patterns, nPass2Patterns;
int noPass1, noPass2;
char *parentStyles, *parentStylesPtr, *parentName;
highlightPattern *pass1PatternSrc, *pass2PatternSrc, *p1Ptr, *p2Ptr;
styleTableEntry *styleTable, *styleTablePtr;
textBuffer *styleBuf;
highlightDataRec *pass1Pats, *pass2Pats;
windowHighlightData *highlightData;
ColorProfile *colorprofile = window->colorProfile;
if (nPatterns ==
0)
{
return NULL;
}
if (!NamedStyleExists(colorprofile,
"Plain"))
{
DialogF(
DF_WARN, window->shell,
1,
"Highlight Style",
"Highlight style \"Plain\" is missing",
"OK");
return NULL;
}
for (i=
0; i<nPatterns; i++)
{
if (patternSrc[i].subPatternOf !=
NULL
&& indexOfNamedPattern(patternSrc, nPatterns,
patternSrc[i].subPatternOf) == -
1)
{
DialogF(
DF_WARN, window->shell,
1,
"Parent Pattern",
"Parent field \"%s\" in pattern \"%s\"\n"
"does not match any highlight patterns in this set",
"OK", patternSrc[i].subPatternOf, patternSrc[i].name);
return NULL;
}
}
for (i=
0; i<nPatterns; i++)
{
if (!NamedStyleExists(colorprofile, patternSrc[i].style))
{
DialogF(
DF_WARN, window->shell,
1,
"Highlight Style",
"Style \"%s\" named in pattern \"%s\"\n"
"does not match any existing style",
"OK",
patternSrc[i].style, patternSrc[i].name);
return NULL;
}
}
for (i =
0; i < nPatterns; i++)
{
if (patternSrc[i].subPatternOf !=
NULL)
{
int parentindex;
parentindex=findTopLevelParentIndex(patternSrc, nPatterns, i);
if (parentindex==-
1)
{
DialogF(
DF_WARN, window->shell,
1,
"Parent Pattern",
"Pattern \"%s\" does not have valid parent",
"OK",
patternSrc[i].name);
return NULL;
}
if (patternSrc[parentindex].flags &
DEFER_PARSING)
{
patternSrc[i].flags |=
DEFER_PARSING;
}
else
{
patternSrc[i].flags &= ~
DEFER_PARSING;
}
}
}
nPass1Patterns =
1;
nPass2Patterns =
1;
for (i=
0; i<nPatterns; i++)
if (patternSrc[i].flags &
DEFER_PARSING)
nPass2Patterns++;
else
nPass1Patterns++;
p1Ptr = pass1PatternSrc = (highlightPattern *)NEditMalloc(
sizeof(highlightPattern) * nPass1Patterns);
p2Ptr = pass2PatternSrc = (highlightPattern *)NEditMalloc(
sizeof(highlightPattern) * nPass2Patterns);
p1Ptr->name = p2Ptr->name =
"";
p1Ptr->startRE = p2Ptr->startRE =
NULL;
p1Ptr->endRE = p2Ptr->endRE =
NULL;
p1Ptr->errorRE = p2Ptr->errorRE =
NULL;
p1Ptr->style = p2Ptr->style =
"Plain";
p1Ptr->subPatternOf = p2Ptr->subPatternOf =
NULL;
p1Ptr->flags = p2Ptr->flags =
0;
p1Ptr++; p2Ptr++;
for (i=
0; i<nPatterns; i++) {
if (patternSrc[i].flags &
DEFER_PARSING)
*p2Ptr++ = patternSrc[i];
else
*p1Ptr++ = patternSrc[i];
}
if (nPass1Patterns ==
1)
nPass1Patterns =
0;
if (nPass2Patterns ==
1)
nPass2Patterns =
0;
if (nPass1Patterns ==
0)
pass1Pats =
NULL;
else {
pass1Pats = compilePatterns(window->colorProfile, window->shell, pass1PatternSrc,
nPass1Patterns);
if (pass1Pats ==
NULL)
return NULL;
}
if (nPass2Patterns ==
0)
pass2Pats =
NULL;
else {
pass2Pats = compilePatterns(window->colorProfile, window->shell, pass2PatternSrc,
nPass2Patterns);
if (pass2Pats ==
NULL)
return NULL;
}
noPass1 = nPass1Patterns ==
0;
noPass2 = nPass2Patterns ==
0;
if (noPass2)
pass1Pats[
0].style =
PLAIN_STYLE;
else if (noPass1)
pass2Pats[
0].style =
PLAIN_STYLE;
else {
pass1Pats[
0].style =
UNFINISHED_STYLE;
pass2Pats[
0].style =
PLAIN_STYLE;
}
for (i=
1; i<nPass1Patterns; i++)
pass1Pats[i].style =
PLAIN_STYLE + i;
for (i=
1; i<nPass2Patterns; i++)
pass2Pats[i].style =
PLAIN_STYLE + (noPass1 ?
0 : nPass1Patterns-
1) + i;
parentStylesPtr = parentStyles = (
char*)NEditMalloc(nPass1Patterns+nPass2Patterns+
2);
*parentStylesPtr++ =
'\0';
*parentStylesPtr++ =
'\0';
for (i=
1; i<nPass1Patterns; i++) {
parentName = pass1PatternSrc[i].subPatternOf;
*parentStylesPtr++ = parentName ==
NULL ?
PLAIN_STYLE :
pass1Pats[indexOfNamedPattern(pass1PatternSrc,
nPass1Patterns, parentName)].style;
}
for (i=
1; i<nPass2Patterns; i++) {
parentName = pass2PatternSrc[i].subPatternOf;
*parentStylesPtr++ = parentName ==
NULL ?
PLAIN_STYLE :
pass2Pats[indexOfNamedPattern(pass2PatternSrc,
nPass2Patterns, parentName)].style;
}
styleTablePtr = styleTable = (styleTableEntry *)NEditMalloc(
sizeof(styleTableEntry) * (nPass1Patterns + nPass2Patterns +
1));
#define setStyleTablePtr(colorProfile, styleTablePtr, patternSrc) \
do { \
styleTableEntry *p = styleTablePtr; \
highlightPattern *pat = patternSrc; \
int r, g, b; \
\
p->highlightName = pat->name; \
p->styleName = pat->style; \
p->colorName = ColorOfNamedStyle(colorProfile, pat->style); \
p->bgColorName = BgColorOfNamedStyle(colorProfile, pat->style); \
p->isBold = FontOfNamedStyleIsBold(colorProfile, pat->style); \
p->isItalic = FontOfNamedStyleIsItalic(colorProfile, pat->style); \
\
p->color.pixel = AllocColor(window->textArea, p->colorName, &r, &g, &b); \
p->color.color.red = r; \
p->color.color.green = g; \
p->color.color.blue = b; \
p->color.color.alpha = 0xFFFF; \
\
if (p->bgColorName) { \
p->bgColor = PixelToColor(window->textArea, AllocColor(window->textArea, p->bgColorName, &r, &g, &b)); \
p->bgColor.pixel = AllocColor(window->textArea, p->colorName, &r, &g, &b); \
p->bgColor.color.red = r; \
p->bgColor.color.green = g; \
p->bgColor.color.blue = b; \
p->bgColor.color.alpha = 0xFFFF; \
} \
else { \
p->bgColor = p->color; \
if(colorProfile->styleType ==
1) \
p->color = LightenColor(p->color); \
} \
p->font = FontOfNamedStyle(colorProfile, window, pat->style); \
}
while (
0)
styleTablePtr->underline =
FALSE;
setStyleTablePtr(colorprofile, styleTablePtr++,
noPass1 ? &pass2PatternSrc[
0] : &pass1PatternSrc[
0]);
styleTablePtr->underline =
FALSE;
setStyleTablePtr(colorprofile, styleTablePtr++,
noPass2 ? &pass1PatternSrc[
0] : &pass2PatternSrc[
0]);
for (i=
1; i<nPass1Patterns; i++) {
styleTablePtr->underline =
FALSE;
setStyleTablePtr(colorprofile, styleTablePtr++, &pass1PatternSrc[i]);
}
for (i=
1; i<nPass2Patterns; i++) {
styleTablePtr->underline =
FALSE;
setStyleTablePtr(colorprofile, styleTablePtr++, &pass2PatternSrc[i]);
}
NEditFree(pass1PatternSrc);
NEditFree(pass2PatternSrc);
styleBuf = BufCreate();
highlightData =(windowHighlightData *)NEditMalloc(
sizeof(windowHighlightData));
highlightData->pass1Patterns = pass1Pats;
highlightData->pass2Patterns = pass2Pats;
highlightData->parentStyles = parentStyles;
highlightData->styleTable = styleTable;
highlightData->nStyles = styleTablePtr - styleTable;
highlightData->styleBuffer = styleBuf;
highlightData->contextRequirements.nLines = contextLines;
highlightData->contextRequirements.nChars = contextChars;
highlightData->patternSetForWindow = patSet;
return highlightData;
}
static highlightDataRec *compilePatterns(ColorProfile *colorProfile, Widget dialogParent,
highlightPattern *patternSrc,
int nPatterns)
{
int i, nSubExprs, patternNum, length, subPatIndex, subExprNum, charsRead;
int parentIndex;
char *ptr, *bigPattern, *compileMsg;
highlightDataRec *compiledPats;
compiledPats = (highlightDataRec *)NEditMalloc(
sizeof(highlightDataRec) *
(nPatterns +
1));
compiledPats[nPatterns].style =
0;
for (i=
0; i<nPatterns; i++) {
compiledPats[i].nSubPatterns =
0;
compiledPats[i].nSubBranches =
0;
}
for (i=
1; i<nPatterns; i++)
if (patternSrc[i].subPatternOf ==
NULL)
compiledPats[
0].nSubPatterns++;
else
compiledPats[indexOfNamedPattern(patternSrc, nPatterns,
patternSrc[i].subPatternOf)].nSubPatterns++;
for (i=
0; i<nPatterns; i++)
compiledPats[i].subPatterns = compiledPats[i].nSubPatterns ==
0 ?
NULL : (highlightDataRec **)NEditMalloc(
sizeof(highlightDataRec *) * compiledPats[i].nSubPatterns);
for (i=
0; i<nPatterns; i++)
compiledPats[i].nSubPatterns =
0;
for (i=
1; i<nPatterns; i++) {
if (patternSrc[i].subPatternOf ==
NULL) {
compiledPats[
0].subPatterns[compiledPats[
0].nSubPatterns++] =
&compiledPats[i];
}
else {
parentIndex = indexOfNamedPattern(patternSrc,
nPatterns, patternSrc[i].subPatternOf);
compiledPats[parentIndex].subPatterns[compiledPats[parentIndex].
nSubPatterns++] = &compiledPats[i];
}
}
for (i=
0; i<nPatterns; i++) {
compiledPats[i].colorOnly = patternSrc[i].flags &
COLOR_ONLY;
compiledPats[i].userStyleIndex = IndexOfNamedStyle(colorProfile, patternSrc[i].style);
if (compiledPats[i].colorOnly && compiledPats[i].nSubPatterns !=
0)
{
DialogF(
DF_WARN, dialogParent,
1,
"Color-only Pattern",
"Color-only pattern \"%s\" may not have subpatterns",
"OK", patternSrc[i].name);
return NULL;
}
nSubExprs =
0;
if (patternSrc[i].startRE !=
NULL) {
ptr = patternSrc[i].startRE;
while(
TRUE) {
if (*ptr ==
'&') {
compiledPats[i].startSubexprs[nSubExprs++] =
0;
ptr++;
}
else if (sscanf(ptr,
"\\%d%n", &subExprNum, &charsRead)==
1) {
compiledPats[i].startSubexprs[nSubExprs++] = subExprNum;
ptr += charsRead;
}
else
break;
}
}
compiledPats[i].startSubexprs[nSubExprs] = -
1;
nSubExprs =
0;
if (patternSrc[i].endRE !=
NULL) {
ptr = patternSrc[i].endRE;
while(
TRUE) {
if (*ptr ==
'&') {
compiledPats[i].endSubexprs[nSubExprs++] =
0;
ptr++;
}
else if (sscanf(ptr,
"\\%d%n", &subExprNum, &charsRead)==
1) {
compiledPats[i].endSubexprs[nSubExprs++] = subExprNum;
ptr += charsRead;
}
else
break;
}
}
compiledPats[i].endSubexprs[nSubExprs] = -
1;
}
for (i=
0; i<nPatterns; i++) {
if (patternSrc[i].startRE ==
NULL || compiledPats[i].colorOnly)
compiledPats[i].startRE =
NULL;
else {
if ((compiledPats[i].startRE = compileREAndWarn(dialogParent,
patternSrc[i].startRE)) ==
NULL)
return NULL;
}
if (patternSrc[i].endRE ==
NULL || compiledPats[i].colorOnly)
compiledPats[i].endRE =
NULL;
else {
if ((compiledPats[i].endRE = compileREAndWarn(dialogParent,
patternSrc[i].endRE)) ==
NULL)
return NULL;
}
if (patternSrc[i].errorRE ==
NULL)
compiledPats[i].errorRE =
NULL;
else {
if ((compiledPats[i].errorRE = compileREAndWarn(dialogParent,
patternSrc[i].errorRE)) ==
NULL)
return NULL;
}
}
for (patternNum=
0; patternNum<nPatterns; patternNum++) {
if (patternSrc[patternNum].endRE ==
NULL &&
patternSrc[patternNum].errorRE ==
NULL &&
compiledPats[patternNum].nSubPatterns ==
0) {
compiledPats[patternNum].subPatternRE =
NULL;
continue;
}
length = (compiledPats[patternNum].colorOnly ||
patternSrc[patternNum].endRE ==
NULL) ?
0 :
strlen(patternSrc[patternNum].endRE) +
5;
length += (compiledPats[patternNum].colorOnly ||
patternSrc[patternNum].errorRE ==
NULL) ?
0 :
strlen(patternSrc[patternNum].errorRE) +
5;
for (i=
0; i<compiledPats[patternNum].nSubPatterns; i++) {
subPatIndex = compiledPats[patternNum].subPatterns[i]-compiledPats;
length += compiledPats[subPatIndex].colorOnly ?
0 :
strlen(patternSrc[subPatIndex].startRE) +
5;
}
if (length ==
0) {
compiledPats[patternNum].subPatternRE =
NULL;
continue;
}
bigPattern = (
char*)NEditMalloc(length+
1);
ptr=bigPattern;
if (patternSrc[patternNum].endRE !=
NULL) {
*ptr++ =
'('; *ptr++ =
'?'; *ptr++ =
':';
strcpy(ptr, patternSrc[patternNum].endRE);
ptr += strlen(patternSrc[patternNum].endRE);
*ptr++ =
')';
*ptr++ =
'|';
compiledPats[patternNum].nSubBranches++;
}
if (patternSrc[patternNum].errorRE !=
NULL) {
*ptr++ =
'('; *ptr++ =
'?'; *ptr++ =
':';
strcpy(ptr, patternSrc[patternNum].errorRE);
ptr += strlen(patternSrc[patternNum].errorRE);
*ptr++ =
')';
*ptr++ =
'|';
compiledPats[patternNum].nSubBranches++;
}
for (i=
0; i<compiledPats[patternNum].nSubPatterns; i++) {
subPatIndex = compiledPats[patternNum].subPatterns[i]-compiledPats;
if (compiledPats[subPatIndex].colorOnly)
continue;
*ptr++ =
'('; *ptr++ =
'?'; *ptr++ =
':';
strcpy(ptr, patternSrc[subPatIndex].startRE);
ptr += strlen(patternSrc[subPatIndex].startRE);
*ptr++ =
')';
*ptr++ =
'|';
compiledPats[patternNum].nSubBranches++;
}
*(ptr-
1) =
'\0';
compiledPats[patternNum].subPatternRE = CompileRE(bigPattern,
&compileMsg,
REDFLT_STANDARD);
if (compiledPats[patternNum].subPatternRE ==
NULL) {
fprintf(stderr,
"Error compiling syntax highlight patterns:\n%s",
compileMsg);
return NULL;
}
NEditFree(bigPattern);
}
for (i=
0; i<nPatterns; i++)
compiledPats[i].flags = patternSrc[i].flags;
return compiledPats;
}
static void freePatterns(highlightDataRec *patterns)
{
int i;
for (i=
0; patterns[i].style!=
0; i++) {
if (patterns[i].startRE !=
NULL)
free((
char *)patterns[i].startRE);
if (patterns[i].endRE !=
NULL)
free((
char *)patterns[i].endRE);
if (patterns[i].errorRE !=
NULL)
free((
char *)patterns[i].errorRE);
if (patterns[i].subPatternRE !=
NULL)
free((
char *)patterns[i].subPatternRE);
}
for (i=
0; patterns[i].style!=
0; i++) {
NEditFree(patterns[i].subPatterns);
}
NEditFree(patterns);
}
highlightPattern *FindPatternOfWindow(WindowInfo *window,
char *name)
{
windowHighlightData *hData = (windowHighlightData *)window->highlightData;
patternSet *set;
int i;
if (hData && (set = hData->patternSetForWindow)) {
for (i =
0; i < set->nPatterns; i++)
if (strcmp(set->patterns[i].name, name) ==
0)
return &set->patterns[i];
}
return NULL;
}
int HighlightCodeOfPos(WindowInfo *window,
int pos)
{
windowHighlightData *highlightData =
(windowHighlightData *)window->highlightData;
textBuffer *styleBuf =
highlightData ? highlightData->styleBuffer :
NULL;
int hCode =
0;
if (styleBuf !=
NULL) {
hCode = (
unsigned char)BufGetCharacter(styleBuf, pos);
if (hCode ==
UNFINISHED_STYLE) {
handleUnparsedRegion(window, highlightData->styleBuffer, pos);
hCode = (
unsigned char)BufGetCharacter(styleBuf, pos);
}
}
return hCode;
}
int HighlightLengthOfCodeFromPos(WindowInfo *window,
int pos,
int *checkCode)
{
windowHighlightData *highlightData =
(windowHighlightData *)window->highlightData;
textBuffer *styleBuf =
highlightData ? highlightData->styleBuffer :
NULL;
int hCode;
int oldPos = pos;
if (styleBuf !=
NULL) {
hCode = (
unsigned char)BufGetCharacter(styleBuf, pos);
if (!hCode)
return 0;
if (hCode ==
UNFINISHED_STYLE) {
handleUnparsedRegion(window, highlightData->styleBuffer, pos);
hCode = (
unsigned char)BufGetCharacter(styleBuf, pos);
}
if (*checkCode ==
0)
*checkCode = hCode;
while (hCode == *checkCode || hCode ==
UNFINISHED_STYLE) {
if (hCode ==
UNFINISHED_STYLE) {
handleUnparsedRegion(window, highlightData->styleBuffer, pos);
hCode = (
unsigned char)BufGetCharacter(styleBuf, pos);
}
else {
hCode = (
unsigned char)BufGetCharacter(styleBuf, ++pos);
}
}
}
return pos - oldPos;
}
int StyleLengthOfCodeFromPos(WindowInfo *window,
int pos,
const char **checkStyleName)
{
windowHighlightData *highlightData =
(windowHighlightData *)window->highlightData;
textBuffer *styleBuf =
highlightData ? highlightData->styleBuffer :
NULL;
int hCode;
int oldPos = pos;
styleTableEntry *entry;
if (styleBuf !=
NULL) {
hCode = (
unsigned char)BufGetCharacter(styleBuf, pos);
if (!hCode)
return 0;
if (hCode ==
UNFINISHED_STYLE) {
handleUnparsedRegion(window, highlightData->styleBuffer, pos);
hCode = (
unsigned char)BufGetCharacter(styleBuf, pos);
}
entry = styleTableEntryOfCode(window, hCode);
if (entry ==
NULL)
return 0;
if ((*checkStyleName) ==
NULL)
(*checkStyleName) = entry->styleName;
while (hCode ==
UNFINISHED_STYLE ||
((entry = styleTableEntryOfCode(window, hCode)) &&
strcmp(entry->styleName, (*checkStyleName)) ==
0)) {
if (hCode ==
UNFINISHED_STYLE) {
handleUnparsedRegion(window, highlightData->styleBuffer, pos);
hCode = (
unsigned char)BufGetCharacter(styleBuf, pos);
}
else {
hCode = (
unsigned char)BufGetCharacter(styleBuf, ++pos);
}
}
}
return pos - oldPos;
}
static styleTableEntry *styleTableEntryOfCode(WindowInfo *window,
int hCode)
{
windowHighlightData *highlightData =
(windowHighlightData *)window->highlightData;
hCode -=
UNFINISHED_STYLE;
if (!highlightData || hCode <
0 || hCode >= highlightData->nStyles)
return NULL;
return &highlightData->styleTable[hCode];
}
char *HighlightNameOfCode(WindowInfo *window,
int hCode)
{
styleTableEntry *entry = styleTableEntryOfCode(window, hCode);
return entry ? entry->highlightName :
"";
}
char *HighlightStyleOfCode(WindowInfo *window,
int hCode)
{
styleTableEntry *entry = styleTableEntryOfCode(window, hCode);
return entry ? entry->styleName :
"";
}
XftColor HighlightColorValueOfCode(WindowInfo *window,
int hCode,
int *r,
int *g,
int *b)
{
styleTableEntry *entry = styleTableEntryOfCode(window, hCode);
if (entry) {
*r = entry->color.color.red;
*g = entry->color.color.green;
*b = entry->color.color.blue;
return entry->color;
}
else
{
XftColor color = TextGetFGColor(window->textArea);
*r = color.color.red;
*g = color.color.green;
*b = color.color.blue;
return color;
}
}
XftColor GetHighlightBGColorOfCode(WindowInfo *window,
int hCode,
int *r,
int *g,
int *b)
{
styleTableEntry *entry = styleTableEntryOfCode(window, hCode);
if (entry && entry->bgColorName) {
*r = entry->bgColor.color.red;
*g = entry->bgColor.color.green;
*b = entry->bgColor.color.blue;
return entry->bgColor;
}
else
{
XftColor color = TextGetBGColor(window->textArea);
*r = color.color.red;
*g = color.color.green;
*b = color.color.blue;
return color;
}
}
static void handleUnparsedRegion(
const WindowInfo* window, textBuffer* styleBuf,
int pos)
{
textBuffer *buf = window->buffer;
int beginParse, endParse, beginSafety, endSafety, p;
windowHighlightData *highlightData =
(windowHighlightData *)window->highlightData;
reparseContext *context = &highlightData->contextRequirements;
highlightDataRec *pass2Patterns = highlightData->pass2Patterns;
char *string, *styleString, *stylePtr, c, prevChar;
const char *stringPtr;
if (pass2Patterns ==
NULL)
return;
int firstPass2Style = (
unsigned char)pass2Patterns[
1].style;
beginParse = pos;
beginSafety = backwardOneContext(buf, context, beginParse);
for (p=beginParse; p>=beginSafety; p--) {
c = BufGetCharacter(styleBuf, p);
if (c !=
UNFINISHED_STYLE && c !=
PLAIN_STYLE &&
(
unsigned char)c < firstPass2Style) {
beginSafety = p +
1;
break;
}
}
endParse = min(buf->length, pos +
PASS_2_REPARSE_CHUNK_SIZE);
endSafety = forwardOneContext(buf, context, endParse);
for (p=pos; p<endSafety; p++) {
c = BufGetCharacter(styleBuf, p);
if (c !=
UNFINISHED_STYLE && c !=
PLAIN_STYLE &&
(
unsigned char)c < firstPass2Style) {
endParse = min(endParse, p);
endSafety = p;
break;
}
else if (c !=
UNFINISHED_STYLE && p < endParse) {
endParse = p;
if ((
unsigned char)c < firstPass2Style)
endSafety = p;
else
endSafety = forwardOneContext(buf, context, endParse);
break;
}
}
stringPtr = string = BufGetRange(buf, beginSafety, endSafety);
styleString = stylePtr = BufGetRange(styleBuf, beginSafety, endSafety);
prevChar = getPrevChar(buf, beginSafety);
parseString(pass2Patterns, &stringPtr, &stylePtr, endParse - beginSafety,
&prevChar, False, GetWindowDelimiters(window), string,
NULL);
styleString[endParse-beginSafety] =
'\0';
BufReplace(styleBuf, beginParse, endParse,
&styleString[beginParse-beginSafety]);
NEditFree(styleString);
NEditFree(string);
}
static void handleUnparsedRegionCB(
const textDisp* textD,
int pos,
const void* cbArg)
{
handleUnparsedRegion((WindowInfo*) cbArg, textD->styleBuffer, pos);
}
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;
beginParse = pos;
parseInStyle = findSafeParseRestartPos(buf, highlightData, &beginParse);
lastMod = pos + nInserted;
endParse = forwardOneContext(buf, context, lastMod);
for (nPasses=
0; ; nPasses++) {
startPattern = patternOfStyle(pass1Patterns, parseInStyle);
if (!startPattern) {
startPattern = pass1Patterns;
}
endAt = parseBufferRange(startPattern,
pass2Patterns, buf, styleBuf, context, beginParse, endParse,
delimiters);
if (endAt < endParse) {
beginParse = endAt;
endParse = forwardOneContext(buf, context,
max(endAt, max(lastModified(styleBuf), lastMod)));
if (
IS_PLAIN(parseInStyle)) {
fprintf(stderr,
"XNEdit internal error: incr. reparse fell short\n");
return;
}
parseInStyle = parentStyleOf(parentStyles, parseInStyle);
}
else if (lastModified(styleBuf) <= lastMod) {
return;
}
else {
lastMod = lastModified(styleBuf);
endParse = min(buf->length, forwardOneContext(buf, context, lastMod)
+ (
REPARSE_CHUNK_SIZE << nPasses));
}
}
}
static int parseBufferRange(highlightDataRec *pass1Patterns,
highlightDataRec *pass2Patterns, textBuffer *buf, textBuffer *styleBuf,
reparseContext *contextRequirements,
int beginParse,
int endParse,
const char *delimiters)
{
char *string, *styleString, *stylePtr, *temp, prevChar;
const char *stringPtr;
int endSafety, endPass2Safety, startPass2Safety, tempLen;
int modStart, modEnd, beginSafety, beginStyle, p, style;
int firstPass2Style = pass2Patterns ==
NULL ?
INT_MAX :
(
unsigned char)pass2Patterns[
1].style;
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;
}
}
}
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);
string = BufGetRange(buf, beginSafety, endSafety);
styleString = BufGetRange(styleBuf, beginSafety, endSafety);
prevChar = getPrevChar(buf, beginParse);
stringPtr = &string[beginParse-beginSafety];
stylePtr = &styleString[beginParse-beginSafety];
parseString(pass1Patterns, &stringPtr, &stylePtr, endParse-beginParse,
&prevChar, False, delimiters, string,
NULL);
endParse = min(endParse, stringPtr-string + beginSafety);
if (pass2Patterns ==
NULL)
goto parseDone;
if (styleBuf->primary.selected) {
modStart = styleBuf->primary.start;
modEnd = styleBuf->primary.end;
}
else
modStart = modEnd =
0;
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, delimiters, string,
NULL);
goto parseDone;
}
else {
tempLen = endPass2Safety - modStart;
temp = (
char*)NEditMalloc(tempLen);
strncpy(temp, &styleString[modStart-beginSafety], tempLen);
passTwoParseString(pass2Patterns, string, styleString,
modStart - beginSafety, &prevChar, delimiters, string,
NULL);
strncpy(&styleString[modStart-beginSafety], temp, tempLen);
NEditFree(temp);
}
}
if (endParse > modEnd) {
if (beginSafety > modEnd) {
prevChar = getPrevChar(buf, beginSafety);
passTwoParseString(pass2Patterns, string, styleString,
endParse - beginSafety, &prevChar, delimiters, string,
NULL);
}
else {
startPass2Safety = max(beginSafety,
backwardOneContext(buf, contextRequirements, modEnd));
tempLen = modEnd - startPass2Safety;
temp = (
char*)NEditMalloc(tempLen);
strncpy(temp, &styleString[startPass2Safety-beginSafety], tempLen);
prevChar = getPrevChar(buf, startPass2Safety);
passTwoParseString(pass2Patterns,
&string[startPass2Safety-beginSafety],
&styleString[startPass2Safety-beginSafety],
endParse-startPass2Safety, &prevChar, delimiters, string,
NULL);
strncpy(&styleString[startPass2Safety-beginSafety], temp, tempLen);
NEditFree(temp);
}
}
parseDone:
styleString[endParse-beginSafety] =
'\0';
modifyStyleBuf(styleBuf, &styleString[beginParse-beginSafety],
beginParse, endParse, firstPass2Style);
NEditFree(styleString);
NEditFree(string);
return endParse;
}
static int parseString(highlightDataRec *pattern,
const char **string,
char **styleString,
int length,
char *prevChar,
int anchored,
const char *delimiters,
const char* lookBehindTo,
const char* match_till)
{
int i, subExecuted, subIndex;
char *stylePtr;
const char *stringPtr, *savedStartPtr, *startingStringPtr;
signed char *subExpr;
char savedPrevChar;
char succChar = match_till ? (*match_till) :
'\0';
highlightDataRec *subPat =
NULL, *subSubPat;
if (length <=
0)
return False;
stringPtr = *string;
stylePtr = *styleString;
while (ExecRE(pattern->subPatternRE, stringPtr, anchored ? *string+
1 :
*string+length+
1, False, *prevChar, succChar, delimiters,
lookBehindTo, match_till)) {
subIndex = (pattern->nSubBranches >
1) ?
pattern->subPatternRE->top_branch :
0;
startingStringPtr = stringPtr;
fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->startp[
0],
pattern->style, prevChar);
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, savedStartPtr,
savedStartPtr+
1, False, savedPrevChar,
succChar, delimiters, lookBehindTo, match_till)) {
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 (pattern->errorRE !=
NULL) {
if (subIndex ==
0) {
fillStyleString(&stringPtr, &stylePtr,
pattern->subPatternRE->startp[
0], pattern->style, prevChar);
*string = stringPtr;
*styleString = stylePtr;
return False;
}
--subIndex;
}
for (i=
0; i<pattern->nSubPatterns; i++) {
subPat = pattern->subPatterns[i];
if (subPat->colorOnly) ++subIndex;
else if (i == subIndex)
break;
}
if (i == pattern->nSubPatterns) {
fprintf(stderr,
"Internal error, failed to match in parseString\n");
return False;
}
if (subPat->subPatternRE ==
NULL) {
fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->endp[
0],
subPat->style, prevChar);
}
else if (subPat->endRE !=
NULL) {
if (!(subPat->flags &
PARSE_SUBPATS_FROM_START))
fillStyleString(&stringPtr, &stylePtr, pattern->subPatternRE->endp[
0],
subPat->style, prevChar);
parseString(subPat, &stringPtr, &stylePtr, length -
(stringPtr - *string), prevChar, False, delimiters,
lookBehindTo, match_till);
}
else {
parseString(subPat, &stringPtr, &stylePtr,
pattern->subPatternRE->endp[
0]-stringPtr, prevChar, False,
delimiters, lookBehindTo, pattern->subPatternRE->endp[
0]);
}
subExecuted = False;
for (i=
0; i<subPat->nSubPatterns; i++) {
subSubPat = subPat->subPatterns[i];
if (subSubPat->colorOnly) {
if (!subExecuted) {
if (!ExecRE(subPat->startRE, savedStartPtr,
savedStartPtr+
1, False, savedPrevChar, succChar,
delimiters, lookBehindTo, match_till)) {
fprintf(stderr,
"Internal error, failed to recover "
"start match in parseString\n");
return False;
}
subExecuted = True;
}
for (subExpr=subSubPat->startSubexprs; *subExpr!=-
1; subExpr++)
recolorSubexpr(subPat->startRE, *subExpr, subSubPat->style,
*string, *styleString);
}
}
if (stringPtr == startingStringPtr) {
if (*stringPtr ==
'\0')
break;
fillStyleString(&stringPtr, &stylePtr, stringPtr+
1,
pattern->style, prevChar);
}
}
if (anchored && stringPtr == *string)
return False;
if (!anchored)
fillStyleString(&stringPtr, &stylePtr, *string+length, pattern->style,
prevChar);
*string = stringPtr;
*styleString = stylePtr;
return pattern->endRE ==
NULL;
}
static void passTwoParseString(highlightDataRec *pattern,
char *string,
char *styleString,
int length,
char *prevChar,
const char *delimiters,
const char *lookBehindTo,
const char *match_till)
{
int inParseRegion = False;
char *stylePtr, temp, *parseStart =
NULL, *parseEnd, *s, *c;
const char *stringPtr;
int firstPass2Style = (
unsigned char)pattern[
1].style;
for (c = string, s = styleString; ; c++, s++) {
if (!inParseRegion && *c !=
'\0' && (*s ==
UNFINISHED_STYLE ||
*s ==
PLAIN_STYLE || (
unsigned char)*s >= firstPass2Style)) {
parseStart = c;
inParseRegion = True;
}
if (inParseRegion && (*c ==
'\0' || !(*s ==
UNFINISHED_STYLE ||
*s ==
PLAIN_STYLE || (
unsigned char)*s >= firstPass2Style))) {
parseEnd = c;
if (parseStart != string)
*prevChar = *(parseStart-
1);
stringPtr = parseStart;
stylePtr = &styleString[parseStart - string];
temp = *parseEnd;
*parseEnd =
'\0';
parseString(pattern, &stringPtr, &stylePtr,
min(parseEnd - parseStart, length - (parseStart - string)),
prevChar, False, delimiters, lookBehindTo, match_till);
*parseEnd = temp;
inParseRegion = False;
}
if (*c ==
'\0' || (!inParseRegion && c - string >= length))
break;
}
}
static void fillStyleString(
const char **stringPtr,
char **stylePtr,
const char *toPtr,
char style,
char *prevChar)
{
int i, len = toPtr-*stringPtr;
if (*stringPtr >= toPtr)
return;
for (i=
0; i<len; i++)
*(*stylePtr)++ = style;
if (prevChar !=
NULL) *prevChar = *(toPtr-
1);
*stringPtr = toPtr;
}
static void modifyStyleBuf(textBuffer *styleBuf,
char *styleString,
int startPos,
int endPos,
int firstPass2Style)
{
char *c, bufChar;
int pos, modStart, modEnd, minPos =
INT_MAX, maxPos =
0;
selection *sel = &styleBuf->primary;
if (sel->selected) {
modStart = sel->start;
modEnd = sel->end;
}
else
modStart = modEnd = startPos;
for (c=styleString, pos=startPos; pos<modStart && pos<endPos; c++, pos++) {
bufChar = BufGetCharacter(styleBuf, pos);
if (*c != bufChar && !(bufChar ==
UNFINISHED_STYLE &&
(*c ==
PLAIN_STYLE || (
unsigned char)*c >= firstPass2Style))) {
if (pos < minPos) minPos = pos;
if (pos > maxPos) maxPos = pos;
}
}
for (c=&styleString[max(
0, modEnd-startPos)], pos=max(modEnd, startPos);
pos<endPos; c++, pos++) {
bufChar = BufGetCharacter(styleBuf, pos);
if (*c != bufChar && !(bufChar ==
UNFINISHED_STYLE &&
(*c ==
PLAIN_STYLE || (
unsigned char)*c >= firstPass2Style))) {
if (pos < minPos) minPos = pos;
if (pos+
1 > maxPos) maxPos = pos+
1;
}
}
BufReplace(styleBuf, startPos, endPos, styleString);
BufSelect(styleBuf, min(modStart, minPos), max(modEnd, maxPos));
}
static int lastModified(textBuffer *styleBuf)
{
if (styleBuf->primary.selected)
return max(
0, styleBuf->primary.end);
return 0;
}
static double colorDistance(
const XColor *c1,
const XColor *c2)
{
static const double scale =
65535;
double tred = c1->red / scale - c2->red / scale;
double tgreen = c1->green / scale - c2->green / scale;
double tblue = c1->blue / scale - c2->blue / scale;
return tred * tred + tgreen * tgreen + tblue * tblue;
}
Pixel AllocateColor(Widget w,
const char *colorName)
{
int dummy;
return AllocColor(w, colorName, &dummy, &dummy, &dummy);
}
static int printParseColorError =
1;
void SetParseColorError(
int value)
{
printParseColorError = value;
}
XftColor ParseXftColor(Display *display, Colormap colormap, Pixel foreground,
int depth,
const char *colorName)
{
XftColor xftColor;
memset(&xftColor,
0,
sizeof(XftColor));
xftColor.color.alpha = 0xFFFF;
XColor colorDef;
if (XParseColor(display, colormap, colorName, &colorDef)) {
xftColor.color.red = colorDef.red;
xftColor.color.green = colorDef.green;
xftColor.color.blue = colorDef.blue;
}
else if(printParseColorError) {
fprintf(stderr,
"XNEdit: Color name %s not in database\n", colorName);
}
return xftColor;
}
Pixel AllocColor(Widget w,
const char *colorName,
int *r,
int *g,
int *b)
{
XColor colorDef;
XColor *allColorDefs;
Display *display = XtDisplay(w);
Colormap cMap;
Pixel foreground, bestPixel;
double small =
1.0e9;
int depth;
unsigned int ncolors;
unsigned long i, best =
0;
XtVaGetValues(w,
XtNcolormap, &cMap,
XtNdepth, &depth,
XtNforeground, &foreground,
NULL);
bestPixel = foreground;
if (! XParseColor(display, cMap, colorName, &colorDef)) {
if(printParseColorError) {
fprintf(stderr,
"NEdit: Color name %s not in database\n", colorName);
}
colorDef.pixel = foreground;
if (XQueryColor(display, cMap, &colorDef)) {
*r = colorDef.red;
*g = colorDef.green;
*b = colorDef.blue;
}
return foreground;
}
if (XAllocColor(display, cMap, &colorDef)) {
*r = colorDef.red;
*g = colorDef.green;
*b = colorDef.blue;
return colorDef.pixel;
}
#if 0
printf(
"Couldn''t allocate %d %d %d\n", colorDef.red, colorDef.green, colorDef.blue);
#endif
if (depth >
8) {
colorDef.pixel = foreground;
if (XQueryColor(display, cMap, &colorDef)) {
*r = colorDef.red;
*g = colorDef.green;
*b = colorDef.blue;
}
return foreground;
}
ncolors = (
1 << depth);
allColorDefs = malloc(ncolors *
sizeof(XColor));
memset(allColorDefs,
0, ncolors *
sizeof(XColor));
for (i =
0; i < ncolors; i++)
allColorDefs[i].pixel = i;
XQueryColors(display, cMap, allColorDefs, ncolors);
for (i =
0; i < ncolors; i++)
{
double dist = colorDistance(&allColorDefs[i], &colorDef);
if (dist < small)
{
best = i;
small = dist;
}
}
if (XAllocColor(display, cMap, &allColorDefs[best]))
bestPixel = allColorDefs[best].pixel;
#if 0
printf(
"Got %d %d %d, ", allColorDefs[best].red,
allColorDefs[best].green,
allColorDefs[best].blue);
printf(
"That''s %f off\n", small);
#endif
*r = allColorDefs[best].red;
*g = allColorDefs[best].green;
*b = allColorDefs[best].blue;
free(allColorDefs);
return bestPixel;
}
XftColor AllocXftColor(Widget w,
const char *colorName)
{
int r, g, b;
XftColor c;
c.pixel = AllocColor(w, colorName, &r, &g, &b);
c.color.red = r;
c.color.green = g;
c.color.blue = b;
c.color.alpha = 0xFFFF;
return c;
}
static char getPrevChar(textBuffer *buf,
int pos)
{
return pos ==
0 ?
'\0' : BufGetCharacter(buf, pos-
1);
}
static regexp *compileREAndWarn(Widget parent,
const char *re)
{
regexp *compiledRE;
char *compileMsg;
compiledRE = CompileRE(re, &compileMsg,
REDFLT_STANDARD);
if (compiledRE ==
NULL)
{
char *boundedRe = NEditStrdup(re);
size_t maxLength =
DF_MAX_MSG_LENGTH - strlen(compileMsg) -
60;
if (strlen(boundedRe) > maxLength)
{
strcpy(&boundedRe[maxLength-
3],
"...");
}
DialogF(
DF_WARN, parent,
1,
"Error in Regex",
"Error in syntax highlighting regular expression:\n%s\n%s",
"OK", boundedRe, compileMsg);
NEditFree(boundedRe);
return NULL;
}
return compiledRE;
}
static int parentStyleOf(
const char *parentStyles,
int style)
{
return parentStyles[(
unsigned char)style-
UNFINISHED_STYLE];
}
static int isParentStyle(
const char *parentStyles,
int style1,
int style2)
{
int p;
for (p = parentStyleOf(parentStyles, style2); p !=
'\0';
p = parentStyleOf(parentStyles, p))
if (style1 == p)
return TRUE;
return FALSE;
}
static int patternIsParsable(highlightDataRec *pattern)
{
return pattern !=
NULL && pattern->subPatternRE !=
NULL;
}
static int findSafeParseRestartPos(textBuffer *buf,
windowHighlightData *highlightData,
int *pos)
{
int style, startStyle, runningStyle, checkBackTo, safeParseStart, i;
char *parentStyles = highlightData->parentStyles;
highlightDataRec *pass1Patterns = highlightData->pass1Patterns;
reparseContext *context = &highlightData->contextRequirements;
*pos = backwardOneContext(buf, context, *pos);
if (*pos ==
0)
return PLAIN_STYLE;
startStyle = BufGetCharacter(highlightData->styleBuffer, *pos);
if (
IS_PLAIN(startStyle))
return PLAIN_STYLE;
if (patternIsParsable(patternOfStyle(pass1Patterns, startStyle))) {
safeParseStart = backwardOneContext(buf, context, *pos);
checkBackTo = backwardOneContext(buf, context, safeParseStart);
}
else {
safeParseStart =
0;
checkBackTo =
0;
}
runningStyle = startStyle;
for (i = *pos-
1; ; i--) {
if (i ==
0) {
*pos =
0;
return PLAIN_STYLE;
}
style = BufGetCharacter(highlightData->styleBuffer, i);
if (isParentStyle(parentStyles, style, runningStyle)) {
if (patternIsParsable(patternOfStyle(pass1Patterns, style))) {
*pos = i +
1;
return style;
}
else {
runningStyle = style;
}
}
else if (isParentStyle(parentStyles, runningStyle, style)) {
if (patternIsParsable
(patternOfStyle(pass1Patterns, runningStyle))) {
*pos = i +
1;
return runningStyle;
}
}
else if (runningStyle != style &&
isParentStyle(parentStyles,
parentStyleOf(parentStyles, runningStyle), style)) {
int parentStyle = parentStyleOf(parentStyles, runningStyle);
if (patternIsParsable(patternOfStyle(pass1Patterns, parentStyle))) {
*pos = i +
1;
return parentStyle;
}
else {
runningStyle = style;
}
}
else if (runningStyle != style) {
*pos = i +
1;
return PLAIN_STYLE;
}
if (i == checkBackTo) {
*pos = safeParseStart;
while (!patternIsParsable
(patternOfStyle(pass1Patterns, runningStyle)))
runningStyle = parentStyleOf(parentStyles, runningStyle);
return runningStyle;
}
}
}
static int backwardOneContext(textBuffer *buf, reparseContext *context,
int fromPos)
{
if (context->nLines ==
0)
return max(
0, fromPos - context->nChars);
else if (context->nChars ==
0)
return max(
0,
BufCountBackwardNLines(buf, fromPos, context->nLines-
1) -
1);
else
return max(
0, min(max(
0, BufCountBackwardNLines(buf, fromPos,
context->nLines-
1) -
1), fromPos - context->nChars));
}
static int forwardOneContext(textBuffer *buf, reparseContext *context,
int fromPos)
{
if (context->nLines ==
0)
return min(buf->length, fromPos + context->nChars);
else if (context->nChars ==
0)
return min(buf->length,
BufCountForwardNLines(buf, fromPos, context->nLines));
else
return min(buf->length, max(BufCountForwardNLines(buf, fromPos,
context->nLines), fromPos + context->nChars));
}
static void recolorSubexpr(regexp *re,
int subexpr,
int style,
const char *string,
char *styleString)
{
const char *stringPtr;
char *stylePtr;
stringPtr = re->startp[subexpr];
stylePtr = &styleString[stringPtr - string];
fillStyleString(&stringPtr, &stylePtr, re->endp[subexpr], style,
NULL);
}
static highlightDataRec *patternOfStyle(highlightDataRec *patterns,
int style)
{
int i;
for (i=
0; patterns[i].style!=
0; i++)
if (patterns[i].style == style)
return &patterns[i];
if (style ==
PLAIN_STYLE || style ==
UNFINISHED_STYLE)
return &patterns[
0];
return NULL;
}
static int max(
int i1,
int i2)
{
return i1 >= i2 ? i1 : i2;
}
static int min(
int i1,
int i2)
{
return i1 <= i2 ? i1 : i2;
}
static int indexOfNamedPattern(highlightPattern *patList,
int nPats,
const char *patName)
{
int i;
if (patName ==
NULL)
return -
1;
for (i=
0; i<nPats; i++)
if (!strcmp(patList[i].name, patName))
return i;
return -
1;
}
static int findTopLevelParentIndex(highlightPattern *patList,
int nPats,
int index)
{
int topIndex;
topIndex = index;
while (patList[topIndex].subPatternOf !=
NULL) {
topIndex = indexOfNamedPattern(patList, nPats,
patList[topIndex].subPatternOf);
if (index==topIndex)
return -
1;
}
return topIndex;
}
static void updateWindowHeight(WindowInfo *window,
int oldFontHeight)
{
int i, borderHeight, marginHeight;
Dimension windowHeight, textAreaHeight, textHeight, newWindowHeight;
if (NDocuments(window) >
1)
return;
XtVaGetValues(window->shell, XmNheight, &windowHeight,
NULL);
XtVaGetValues(window->textArea, XmNheight, &textAreaHeight,
textNmarginHeight, &marginHeight,
NULL);
textHeight = textAreaHeight -
2*marginHeight;
for (i=
0; i<window->nPanes; i++) {
XtVaGetValues(window->textPanes[i], XmNheight, &textAreaHeight,
NULL);
textHeight += textAreaHeight -
2*marginHeight;
}
borderHeight = windowHeight - textHeight;
newWindowHeight = (textHeight*getFontHeight(window)) / oldFontHeight +
borderHeight;
XtVaSetValues(window->shell, XmNheightInc, getFontHeight(window),
NULL);
XtVaSetValues(window->shell, XmNheight, newWindowHeight,
NULL);
}
static int getFontHeight(WindowInfo *window)
{
textDisp *textD = ((TextWidget)window->textArea)->text.textD;
return textD->ascent + textD->descent;
}
XftColor LightenColor(XftColor color)
{
int r = color.color.red;
int g = color.color.green;
int b = color.color.blue;
if(abs(r-g) <
5 && abs(g-b) <
5) {
r = 0xFFFF - r;
g = 0xFFFF - g;
b = 0xFFFF - b;
}
else {
r = r + 0x8000;
g = g + 0x8000;
b = b + 0x8000;
if(r > 0xFFFF) r = 0xFFFF;
if(g > 0xFFFF) g = 0xFFFF;
if(b > 0xFFFF) b = 0xFFFF;
}
color.color.red = r;
color.color.green = g;
color.color.blue = b;
return color;
}