📄 highlight.c
字号:
static const char CVSID[] = "$Id: highlight.c,v 1.42.2.1 2003/11/03 16:31:01 edg Exp $";/******************************************************************************** ** highlight.c -- Nirvana Editor syntax highlighting (text coloring and font ** selected by file content ** ** Copyright (C) 1999 Mark Edel ** ** This is free software; you can redistribute it and/or modify it under the ** terms of the GNU General Public License as published by the Free Software ** Foundation; either version 2 of the License, or (at your option) any later ** version. ** ** This software is distributed in the hope that it will be useful, but WITHOUT ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ** for more details. ** ** You should have received a copy of the GNU General Public License along with ** software; if not, write to the Free Software Foundation, Inc., 59 Temple ** Place, Suite 330, Boston, MA 02111-1307 USA ** ** Nirvana Text Editor ** June 24, 1996 ** ** Written by Mark Edel ** ********************************************************************************/#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 <stdio.h>#include <limits.h>#include <math.h>#include <stdlib.h>#include <string.h>#ifdef VMS#include "../util/VMSparam.h"#else#ifndef __MVS__#include <sys/param.h>#endif#endif /*VMS*/#include <Xm/Xm.h>#include <Xm/XmP.h>#if XmVersion >= 1002#include <Xm/PrimitiveP.h>#endif#ifdef HAVE_DEBUG_H#include "../debug.h"#endif/* How much re-parsing to do when an unfinished style is encountered */#define PASS_2_REPARSE_CHUNK_SIZE 1000/* Initial forward expansion of parsing region in incremental reparsing, when style changes propagate forward beyond the original modification. This distance is increased by a factor of two for each subsequent step. */#define REPARSE_CHUNK_SIZE 80/* Meanings of style buffer characters (styles). Don't use plain 'A' or 'B'; it causes problems with EBCDIC coding (possibly negative offsets when subtracting 'A'). */#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)/* Compare two styles where one of the styles may not yet have been processed with pass2 patterns */#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)))/* Scanning context can be reduced (with big efficiency gains) if we know that patterns can't cross line boundaries, which is implied by a context requirement of 1 line and 0 characters */#define CAN_CROSS_LINE_BOUNDARIES(contextRequirements) \ (contextRequirements->nLines != 1 || contextRequirements->nChars != 0)/* "Compiled" version of pattern specification */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; /* Number of top-level branches of subPatternRE */ int userStyleIndex; struct _highlightDataRec **subPatterns;} highlightDataRec;/* Context requirements for incremental reparsing of a pattern set */typedef struct { int nLines; int nChars;} reparseContext;/* Data structure attached to window to hold all syntax highlighting information (for both drawing and incremental reparsing) */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(Widget dialogParent, highlightPattern *patternSrc, int nPatterns);static void freePatterns(highlightDataRec *patterns);static void handleUnparsedRegion(WindowInfo* win, textBuffer *buf, int pos);static void handleUnparsedRegionCB(textDisp *textD, int pos, 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, char **string, char **styleString, int length, char *prevChar, int anchored, const char *delimiters, const char* lookBehindTo);static void passTwoParseString(highlightDataRec *pattern, char *string, char *styleString, int length, char *prevChar, int anchored, const char *delimiters, const char* lookBehindTo);static void fillStyleString(char **stringPtr, char **stylePtr, 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, 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);/*** Buffer modification callback for triggering re-parsing of modified** text and keeping the style buffer synchronized with the text buffer.** This must be attached to the the text buffer BEFORE any widget text** display callbacks, so it can get the style buffer ready to be used** by the text display routines.**** Update the style buffer for changes to the text, and mark any style** changes by selecting the region in the style buffer. This strange** protocol of informing the text display to redraw style changes by** making selections in the style buffer is used because this routine** is intended to be called BEFORE the text display callback paints the** text (to minimize redraws and, most importantly, to synchronize the** style buffer with the text buffer). If we redraw now, the text** display hasn't yet processed the modification, redrawing later is** not only complicated, it will double-draw almost everything typed.** ** Note: This routine must be kept efficient. It is called for every** character typed.*/void SyntaxHighlightModifyCB(int pos, int nInserted, int nDeleted, int nRestyled, char *deletedText, void *cbArg) { WindowInfo *window = (WindowInfo *)cbArg; windowHighlightData *highlightData = (windowHighlightData *)window->highlightData; if (highlightData == NULL) return; /* Restyling-only modifications (usually a primary or secondary selection) don't require any processing, but clear out the style buffer selection so the widget doesn't think it has to keep redrawing the old area */ if (nInserted == 0 && nDeleted == 0) { BufUnselect(highlightData->styleBuffer); return; } /* First and foremost, the style buffer must track the text buffer accurately and correctly */ if (nInserted > 0) { char *insStyle; int i; insStyle = XtMalloc(sizeof(char) * (nInserted + 1)); for (i=0; i<nInserted; i++) insStyle[i] = UNFINISHED_STYLE; insStyle[i] = '\0'; BufReplace(highlightData->styleBuffer, pos, pos+nDeleted, insStyle); XtFree(insStyle); } else { BufRemove(highlightData->styleBuffer, pos, pos+nDeleted); } /* Mark the changed region in the style buffer as requiring redraw. This is not necessary for getting it redrawn, it will be redrawn anyhow by the text display callback, but it clears the previous selection and saves the modifyStyleBuf routine from unnecessary work in tracking changes that are already scheduled for redraw */ BufSelect(highlightData->styleBuffer, pos, pos+nInserted); /* Re-parse around the changed region */ if (highlightData->pass1Patterns) incrementalReparse(highlightData, window->buffer, pos, nInserted, GetWindowDelimiters(window));}/*** Turn on syntax highlighting. If "warn" is true, warn the user when it** can't be done, otherwise, just return.*/void StartHighlighting(WindowInfo *window, int warn){ patternSet *patterns; windowHighlightData *highlightData; char *stylePtr, *styleString, *stringPtr, *bufString; char prevChar = '\0'; int i, oldFontHeight; /* Find the pattern set matching the window's current language mode, tell the user if it can't be done */ patterns = findPatternsForWindow(window, warn); if (patterns == NULL) return; /* Compile the patterns */ highlightData = createHighlightData(window, patterns); if (highlightData == NULL) return; /* Prepare for a long delay, refresh display and put up a watch cursor */ BeginWait(window->shell); XmUpdateDisplay(window->shell); /* Parse the buffer with pass 1 patterns. If there are none, initialize the style buffer to all UNFINISHED_STYLE to trigger parsing later */ stylePtr = styleString = XtMalloc(window->buffer->length + 1); if (highlightData->pass1Patterns == NULL) { for (i=0; i<window->buffer->length; i++) *stylePtr++ = UNFINISHED_STYLE; } else { stringPtr = bufString = BufGetAll(window->buffer); parseString(highlightData->pass1Patterns, &stringPtr, &stylePtr, window->buffer->length, &prevChar, False, GetWindowDelimiters(window), bufString); XtFree(bufString); } *stylePtr = '\0'; BufSetAll(highlightData->styleBuffer, styleString); XtFree(styleString); /* install highlight pattern data in the window data structure */ window->highlightData = highlightData; /* Get the height of the current font in the window, to be used after highlighting is turned on to resize the window to make room for additional highlight fonts which may be sized differently */ oldFontHeight = getFontHeight(window); /* Attach highlight information to text widgets in each pane */ AttachHighlightToWidget(window->textArea, window); for (i=0; i<window->nPanes; i++) AttachHighlightToWidget(window->textPanes[i], window); /* Re-size the window to fit the highlight fonts properly & tell the window manager about the potential line-height change as well */ updateWindowHeight(window, oldFontHeight); UpdateWMSizeHints(window); UpdateMinPaneHeights(window); /* Make sure that if the window has grown, the additional area gets repainted. Otherwise, it is possible that the area gets moved before a repaint event is received and the area doesn't get repainted at all (eg. because of a -line command line argument that moves the text). */ XmUpdateDisplay(window->shell); EndWait(window->shell);}/*** Turn off syntax highlighting and free style buffer, compiled patterns, and** related data.*/void StopHighlighting(WindowInfo *window){ int i, oldFontHeight; if (window->highlightData==NULL) return; /* Get the line height being used by the highlight fonts in the window, to be used after highlighting is turned off to resize the window back to the line height of the primary font */ oldFontHeight = getFontHeight(window); /* Free and remove the highlight data from the window */ freeHighlightData((windowHighlightData *)window->highlightData); window->highlightData = NULL; /* Remove and detach style buffer and style table from all text
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -