diff -Nru a/source/menu.c b/source/menu.c --- a/source/menu.c 2005-01-10 21:12:12 +08:00 +++ b/source/menu.c 2005-01-10 21:12:12 +08:00 @@ -170,6 +170,7 @@ static void macroDefCB(Widget w, WindowInfo *window, caddr_t callData); static void bgMenuDefCB(Widget w, WindowInfo *window, caddr_t callData); static void searchDlogsDefCB(Widget w, WindowInfo *window, caddr_t callData); +static void highlightSearchDefCB(Widget w, WindowInfo *window, caddr_t callData); static void beepOnSearchWrapDefCB(Widget w, WindowInfo *window, caddr_t callData); static void keepSearchDlogsDefCB(Widget w, WindowInfo *window, caddr_t callData); @@ -358,6 +359,7 @@ static int searchWrap(int ignoreArgs, String *args, Cardinal *nArgs); static int searchKeepDialogs(int ignoreArgs, String *args, Cardinal *nArgs); static int searchType(int ignoreArgs, String *args, Cardinal *nArgs); +static int searchHighlight(int ignoreArgs, String *args, Cardinal *nArgs); static char **shiftKeyToDir(XtPointer callData); static void raiseCB(Widget w, WindowInfo *window, caddr_t callData); static void openPrevCB(Widget w, char *name, caddr_t callData); @@ -920,6 +922,9 @@ window->searchRegexNoCaseDefItem = createMenuToggle(subSubSubPane, "regularExpressionNoCase", "Regular Expression, Case Insensitive", 'I', searchRegexNoCaseCB, window, GetPrefSearch() == SEARCH_REGEX_NOCASE, FULL); + window->highlightSearchDefItem = createMenuToggle(subSubPane, "highlightSearch", + "Highlight Search", 'V', highlightSearchDefCB, window, + GetPrefSearchHighlight(), SHORT); #ifdef REPLACE_SCOPE subSubSubPane = createMenu(subSubPane, "defaultReplaceScope", "Default Replace Scope", 'R', NULL, FULL); @@ -2120,6 +2125,25 @@ } } +static void highlightSearchDefCB(Widget w, WindowInfo *window, caddr_t callData) +{ + WindowInfo *win; + int state = XmToggleButtonGetState(w); + + /* Set the preference and make the other windows' menus agree */ + SetPrefSearchHighlight(state); + for (win=WindowList; win!=NULL; win=win->next) { + if (!state) { + /* clear existing highlights */ + SearchAndHighlightDocument(win, NULL, 0); + } + + if (IsTopDocument(win)) { + XmToggleButtonSetState(win->highlightSearchDefItem, state, False); + } + } +} + static void beepOnSearchWrapDefCB(Widget w, WindowInfo *window, caddr_t callData) { WindowInfo *win; @@ -3175,20 +3199,21 @@ return; } SearchAndSelect(WidgetToWindow(w), searchDirection(1, args, nArgs), args[0], - searchType(1, args, nArgs), searchWrap(1, args, nArgs)); + searchType(1, args, nArgs), searchWrap(1, args, nArgs), + searchHighlight(0, args, nArgs)); } static void findSameAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { SearchAndSelectSame(WidgetToWindow(w), searchDirection(0, args, nArgs), - searchWrap(0, args, nArgs)); + searchWrap(0, args, nArgs), searchHighlight(0, args, nArgs)); } static void findSelAP(Widget w, XEvent *event, String *args, Cardinal *nArgs) { SearchForSelected(WidgetToWindow(w), searchDirection(0, args, nArgs), searchType(0, args, nArgs), searchWrap(0, args, nArgs), - event->xbutton.time); + searchHighlight(0, args, nArgs), event->xbutton.time); } static void startIncrFindAP(Widget w, XEvent *event, String *args, @@ -3209,7 +3234,8 @@ continued = TRUE; SearchAndSelectIncremental(WidgetToWindow(w), searchDirection(1, args, nArgs), args[0], - searchType(1, args, nArgs), searchWrap(1, args, nArgs), continued); + searchType(1, args, nArgs), searchWrap(1, args, nArgs), + searchHighlight(1, args, nArgs), continued); } static void replaceDialogAP(Widget w, XEvent *event, String *args, @@ -5047,6 +5073,18 @@ return GetPrefSearchWraps(); } +static int searchHighlight(int ignoreArgs, String *args, Cardinal *nArgs) +{ + int i; + + for (i=ignoreArgs; i<(int)*nArgs; i++) { + if (!strCaseCmp(args[i], "highlight")) + return(TRUE); + if (!strCaseCmp(args[i], "nohighlight")) + return(FALSE); + } + return GetPrefSearchHighlight(); +} /* ** Scans action argument list for arguments "literal", "case" or "regex" to ** determine search type for search and replace actions. "ignoreArgs" diff -Nru a/source/nedit.h b/source/nedit.h --- a/source/nedit.h 2005-01-10 21:12:12 +08:00 +++ b/source/nedit.h 2005-01-10 21:12:12 +08:00 @@ -310,6 +310,7 @@ Widget findRegexToggle; Widget findRevToggle; Widget findKeepBtn; + Widget findHighlightBtn; Widget findBtns; Widget findBtn; Widget findSearchTypeBox; @@ -385,6 +386,7 @@ Widget backlightCharsItem; Widget backlightCharsDefItem; Widget searchDlogsDefItem; + Widget highlightSearchDefItem; Widget beepOnSearchWrapDefItem; Widget keepSearchDlogsDefItem; Widget searchWrapsDefItem; @@ -536,6 +538,9 @@ Bool iSearchLastLiteralCase; /* idem, for literal mode */ Bool findLastRegexCase; /* idem, for regex mode in find dialog */ Bool findLastLiteralCase; /* idem, for literal mode */ + char *highlightSearchString; /* search string used in highlighting */ + int highlightSearchType; /* search type used in highlighting */ + int searchHighlightRSLabel; /* label for search hilite rangeset */ #ifdef REPLACE_SCOPE int replaceScope; /* Current scope for replace dialog */ diff -Nru a/source/preferences.c b/source/preferences.c --- a/source/preferences.c 2005-01-10 21:12:12 +08:00 +++ b/source/preferences.c 2005-01-10 21:12:12 +08:00 @@ -240,6 +240,7 @@ int autoSave; /* whether automatic backup feature is on */ int saveOldVersion; /* whether to preserve a copy of last version */ int searchDlogs; /* whether to show explanatory search dialogs */ + int searchHighlight; /* whether to hilite i-search matched strings */ int searchWrapBeep; /* 1=beep when search restarts at begin/end */ int keepSearchDlogs; /* whether to retain find and replace dialogs */ int searchWraps; /* whether to attempt search again if reach bof or eof */ @@ -312,6 +313,7 @@ char helpLinkColor[MAX_COLOR_LEN]; /* Color for hyperlinks in the help system */ char colorNames[NUM_COLORS][MAX_COLOR_LEN]; char tooltipBgColor[MAX_COLOR_LEN]; + char searchHiliteColor[MAX_COLOR_LEN]; /* color for highlighting search matches */ int undoModifiesSelection; int focusOnRaise; } PrefData; @@ -767,6 +769,8 @@ "0-8,10-31,127:red;9:#dedede;32,160-255:#f0f0f0;128-159:orange", /* gray87 gray94 */ &PrefData.backlightCharTypes, NULL, False}, + {"searchHighlight", "SearchHighlight", PREF_BOOLEAN, "True", + &PrefData.searchHighlight, NULL, True}, {"searchDialogs", "SearchDialogs", PREF_BOOLEAN, "False", &PrefData.searchDlogs, NULL, True}, {"beepOnSearchWrap", "BeepOnSearchWrap", PREF_BOOLEAN, "False", @@ -925,6 +929,9 @@ {"tooltipBgColor", "TooltipBgColor", PREF_STRING, "LemonChiffon1", PrefData.tooltipBgColor, (void *)sizeof(PrefData.tooltipBgColor), False}, + {"searchHiliteColor", "SearchHiliteColor", PREF_STRING, "Yellow", + PrefData.searchHiliteColor, + (void *)sizeof(PrefData.searchHiliteColor), False}, {"shell", "Shell", PREF_STRING, #if defined(__MVS__) || defined(__EMX__) @@ -1483,6 +1490,16 @@ return PrefData.searchDlogs; } +void SetPrefSearchHighlight(int state) +{ + setIntPref(&PrefData.searchHighlight, state); +} + +int GetPrefSearchHighlight(void) +{ + return PrefData.searchHighlight; +} + void SetPrefBeepOnSearchWrap(int state) { setIntPref(&PrefData.searchWrapBeep, state); @@ -1970,6 +1987,11 @@ char *GetPrefTooltipBgColor(void) { return PrefData.tooltipBgColor; +} + +char *GetPrefSearchHiliteColor(void) +{ + return PrefData.searchHiliteColor; } void SetPrefShell(const char *shell) diff -Nru a/source/preferences.h b/source/preferences.h --- a/source/preferences.h 2005-01-10 21:12:12 +08:00 +++ b/source/preferences.h 2005-01-10 21:12:12 +08:00 @@ -59,6 +59,8 @@ int GetPrefWrap(int langMode); void SetPrefWrapMargin(int margin); int GetPrefWrapMargin(void); +void SetPrefSearchHighlight(int state); +int GetPrefSearchHighlight(void); void SetPrefSearchDlogs(int state); int GetPrefSearchDlogs(void); void SetPrefKeepSearchDlogs(int state); @@ -144,6 +146,7 @@ XFontStruct *GetPrefItalicFont(void); XFontStruct *GetPrefBoldItalicFont(void); char *GetPrefTooltipBgColor(void); +char *GetPrefSearchHiliteColor(void); char *GetPrefHelpFontName(int index); char *GetPrefHelpLinkColor(void); char *GetPrefColorName(int colorIndex); diff -Nru a/source/rangeset.c b/source/rangeset.c --- a/source/rangeset.c 2005-01-10 21:12:12 +08:00 +++ b/source/rangeset.c 2005-01-10 21:12:12 +08:00 @@ -68,6 +68,8 @@ Pixel color; /* the value of a particular color */ textBuffer *buf; /* the text buffer of the rangeset */ char *name; /* name of rangeset */ + int refresh; /* refresh ranges if this is true */ + int priority; /* put this RS high on displaying */ }; struct _RangesetTable { @@ -158,8 +160,7 @@ int size; Range* newRanges; - if (n > 0) - { + if (n > 0) { /* see RangesNew() for comments */ n = (n >= 256) ? ((n + 64) & ~63) : ((n + 16) & ~15); size = n * sizeof (Range); @@ -167,8 +168,8 @@ ? XtRealloc((char *)ranges, size) : XtMalloc(size)); return newRanges; - } else if (ranges != NULL) - { + } + else if (ranges != NULL) { XtFree((char*) ranges); } @@ -190,10 +191,18 @@ /* ** Refresh the given range on the screen. If the range indicated is null, we ** refresh the screen for the whole file. +** +** Refreshing can be suspended by setting 'refresh' to False. This is +** useful if a large number of ranges is to be added in one burst. +** Remember to restore the flag and call RangesetRefreshRange() on the +** while file to after all work is done. */ void RangesetRefreshRange(Rangeset *rangeset, int start, int end) { + if (!rangeset->refresh) + return; + if (rangeset->buf != NULL) BufCheckDisplay(rangeset->buf, start, end); } @@ -202,6 +211,9 @@ { int i; + if (!rangeset->refresh) + return; + for (i = 0; i < rangeset->n_ranges; i++) RangesetRefreshRange(rangeset, rangeset->ranges[i].start, rangeset->ranges[i].end); } @@ -226,6 +238,7 @@ end = ranges[rangeset->n_ranges].end; RangesetRefreshRange(rangeset, start, end); } + rangeset->n_ranges = 0; } if (rangeset->color_name) @@ -240,6 +253,23 @@ rangeset->ranges = RangesFree(rangeset->ranges); } +/* +** suspend screen refreshing on ranges if 'flag' is set +** to False. +*/ +void RangesetSetRefresh(Rangeset *rangeset, int flag) +{ + rangeset->refresh = flag; +} + +/* +** query the screen refreshing status of the rangeset. +*/ +int RangesetGetRefresh(Rangeset *rangeset) +{ + return rangeset->refresh; +} + /* -------------------------------------------------------------------------- */ /* @@ -254,10 +284,12 @@ rangeset->n_ranges = 0; /* how many ranges in ranges */ rangeset->ranges = (Range *)0; /* the ranges table */ + rangeset->refresh = 1; rangeset->color_name = (char *)0; rangeset->name = (char *)0; rangeset->color_set = 0; rangeset->buf = buf; + rangeset->priority = 0; rangeset->maxpos = buf->gapEnd - buf->gapStart + buf->length; @@ -343,7 +375,8 @@ while (lo <= hi) { /* Beware of integer overflow when multiplying large numbers! */ - mid = lo + (int)((hi - lo) * (double)(max - val) / (max - min)); + mid = lo + (int)((hi - lo) * (double)(val - min) / (max - min)); + /* we won't worry about min == max - values should be unique */ if (val == table[mid]) @@ -700,20 +733,20 @@ int *count, char **color, char **name, char **mode) { if (rangeset == NULL) { - *defined = False; - *label = 0; - *count = 0; - *color = ""; - *name = ""; - *mode = ""; + if (defined) *defined = False; + if (label) *label = 0; + if (count) *count = 0; + if (color) *color = ""; + if (name) *name = ""; + if (mode) *mode = ""; } else { - *defined = True; - *label = (int)rangeset->label; - *count = rangeset->n_ranges; - *color = rangeset->color_name ? rangeset->color_name : ""; - *name = rangeset->name ? rangeset->name : ""; - *mode = rangeset->update_name; + if (defined) *defined = True; + if (label) *label = (int)rangeset->label; + if (count) *count = rangeset->n_ranges; + if (color) *color = rangeset->color_name ? rangeset->color_name : ""; + if (name) *name = rangeset->name ? rangeset->name : ""; + if (mode) *mode = rangeset->update_name; } } @@ -793,6 +826,8 @@ destRangeset->n_ranges = srcRangeset->n_ranges; destRangeset->color_set = srcRangeset->color_set; destRangeset->color = srcRangeset->color; + destRangeset->refresh = srcRangeset->refresh; + destRangeset->priority = srcRangeset->priority; if (srcRangeset->color_name) { destRangeset->color_name = XtMalloc(strlen(srcRangeset->color_name) +1); @@ -908,13 +943,13 @@ /* we want to make the "active" set the most recent (lowest depth value): shuffle table->order[0..depth-1] to table->order[1..depth] readjust the entries in table->depth[] accordingly */ - for (i = depth; i > 0; i--) { + for (i = depth; i > 0 && !table->set[(int)table->order[i-1]].priority; i--) { j = table->order[i] = table->order[i - 1]; table->depth[j] = i; } /* insert the new one: first in order, of depth 0 */ - table->order[0] = active; - table->depth[active] = 0; + table->order[i] = active; + table->depth[active] = i; /* and finally... */ table->active[active] = 1; @@ -955,6 +990,34 @@ return 1; } +/* +** set the priority of the rangeset so that it's ranges will be shown +** over other rangesets during highlighting. +*/ +void RangesetSetPriority(RangesetTable *table, int label, int level) +{ + int set_ind = RangesetFindIndex(table, label, 1); + int depth, i, j; + + if (set_ind < 0) + return; + + table->set[set_ind].priority = level; + depth = table->depth[set_ind]; + + /* we want to make the "active" set the most recent (lowest depth value): + shuffle table->order[0..depth-1] to table->order[1..depth] + readjust the entries in table->depth[] accordingly */ + for (i = depth; i > 0 && !table->set[(int)table->order[i-1]].priority; i--) { + j = table->order[i] = table->order[i - 1]; + table->depth[j] = i; + } + /* insert the new one: first in order, of depth 0 */ + table->order[i] = set_ind; + table->depth[set_ind] = i; + + RangesetTableListSet(table); +} /* ** Return the number of rangesets that are inactive @@ -1124,6 +1187,31 @@ rangesetRefreshAllRanges(rangeset); return 1; } + +Rangeset *GetRangesetByName(RangesetTable *rangesetTable, const char *name) +{ + Rangeset *rangeset; + unsigned char *rangesetList; + int nRangesets, i; + char *rangeset_name; + int label; + + rangesetList = RangesetGetList(rangesetTable); + nRangesets = strlen((char *)rangesetList); + for (i = 0; i < nRangesets; ++i) { + label = rangesetList[i]; + rangeset = RangesetFetch(rangesetTable, label); + if (rangeset) { + rangeset_name = RangesetGetName(rangeset); + if (strcmp(name, rangeset_name ? rangeset_name : "") == 0) { + return rangeset; + } + } + } + + return NULL; +} + /* ** Assign a name to a rangeset via the rangeset table. diff -Nru a/source/rangeset.h b/source/rangeset.h --- a/source/rangeset.h 2005-01-10 21:12:12 +08:00 +++ b/source/rangeset.h 2005-01-10 21:12:12 +08:00 @@ -39,6 +39,8 @@ typedef struct _Range Range; typedef struct _Rangeset Rangeset; +void RangesetSetRefresh(Rangeset *rangeset, int flag); +int RangesetGetRefresh(Rangeset *rangeset); void RangesetRefreshRange(Rangeset *rangeset, int start, int end); void RangesetEmpty(Rangeset *rangeset); void RangesetInit(Rangeset *rangeset, int label, textBuffer *buf); @@ -74,11 +76,13 @@ int RangesetAssignColorPixel(Rangeset *rangeset, Pixel color, int ok); char *RangesetGetColorName(Rangeset *rangeset); char *RangesetGetName(Rangeset *rangeset); +Rangeset *GetRangesetByName(RangesetTable *rangesetTable, const char *name); int RangesetAssignName(Rangeset *rangeset, char *name); int RangesetGetColorValid(Rangeset *rangeset, Pixel *color); char *RangesetTableGetColorName(RangesetTable *table, int index); int RangesetTableGetColorValid(RangesetTable *table, int index, Pixel *color); int RangesetTableAssignColorPixel(RangesetTable *table, int index, Pixel color, int ok); +void RangesetSetPriority(RangesetTable *table, int label, int level); #endif /* rangeset_h_DEFINED */ diff -Nru a/source/search.c b/source/search.c --- a/source/search.c 2005-01-10 21:12:12 +08:00 +++ b/source/search.c 2005-01-10 21:12:12 +08:00 @@ -32,12 +32,14 @@ #endif #include "search.h" +#include "rangeset.h" #include "regularExp.h" #include "textBuf.h" #include "text.h" #include "nedit.h" #include "server.h" #include "window.h" +#include "macro.h" #include "userCmds.h" #include "preferences.h" #include "file.h" @@ -85,6 +87,9 @@ #include "../debug.h" #endif +/* number of lines surrounding the modified range that are + to be included during progressive search highlighting */ +#define PROGRESSIVE_HIGHLIGHT_MARGIN 10 int NHist = 0; @@ -98,6 +103,7 @@ int direction; int searchType; int searchWrap; + int searchHighlight; } SearchSelectedCallData; /* History mechanism for search and replace strings */ @@ -114,6 +120,7 @@ static void rFocusCB(Widget w, WindowInfo *window, caddr_t *callData); static void rKeepCB(Widget w, WindowInfo *window, caddr_t *callData); static void fKeepCB(Widget w, WindowInfo *window, caddr_t *callData); +static void fHighlightCB(Widget w, WindowInfo *window, caddr_t *callData); static void replaceCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData); static void replaceAllCB(Widget w, WindowInfo *window, @@ -225,6 +232,7 @@ static char *searchTypeArg(int searchType); static char *searchWrapArg(int searchWrap); static char *directionArg(int direction); +static char *searchHighlightArg(int searchHighligh); static int isRegexType(int searchType); static int defaultRegexFlags(int searchType); static void findRegExpToggleCB(Widget w, XtPointer clientData, @@ -243,6 +251,7 @@ int beginPos, int startPos); static void iSearchRecordLastBeginPos(WindowInfo *window, int direction, int initPos); +static Rangeset *getSearchHighlightRangeset(WindowInfo *window); typedef struct _charMatchTable { char c; @@ -588,7 +597,6 @@ void DoFindDlog(WindowInfo *window, int direction, int keepDialogs, int searchType, Time time) { - /* Create the dialog if it doesn't already exist */ if (window->findDlog == NULL) CreateFindDlog(window->shell, window); @@ -614,6 +622,10 @@ /* Set the state of the Keep Dialog Up button */ XmToggleButtonSetState(window->findKeepBtn, keepDialogs, True); + /* Set the state of the Highlight All button */ + XmToggleButtonSetState(window->findHighlightBtn, + GetPrefSearchHighlight(), False); + /* Set the state of the Find button */ fUpdateActionButtons(window); @@ -699,7 +711,7 @@ Widget label2, label1, label, replaceText, findText; Widget findBtn, cancelBtn, replaceBtn; Widget replaceFindBtn; - Widget searchDirBox, reverseBtn, keepBtn; + Widget searchOptBox, reverseBtn, keepBtn; char title[MAXPATHLEN + 19]; Dimension shadowThickness; @@ -853,15 +865,15 @@ XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNradioBehavior, False); argcnt++; - searchDirBox = XmCreateRowColumn(form, "searchDirBox", args, argcnt); - XtManageChild(searchDirBox); - XmAddTabGroup(searchDirBox); + searchOptBox = XmCreateRowColumn(form, "searchOptBox", args, argcnt); + XtManageChild(searchOptBox); + XmAddTabGroup(searchOptBox); argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Search Backward")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'B'); argcnt++; - reverseBtn = XmCreateToggleButton(searchDirBox, "reverse", args, argcnt); + reverseBtn = XmCreateToggleButton(searchOptBox, "reverse", args, argcnt); XmStringFree(st1); XtManageChild(reverseBtn); @@ -890,7 +902,7 @@ XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_NONE); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; - XtSetArg(args[argcnt], XmNtopWidget, searchDirBox); argcnt++; + XtSetArg(args[argcnt], XmNtopWidget, searchOptBox); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNradioBehavior, True); argcnt++; @@ -954,7 +966,7 @@ XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; - XtSetArg(args[argcnt], XmNtopWidget, searchDirBox); argcnt++; + XtSetArg(args[argcnt], XmNtopWidget, searchOptBox); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 6); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 6); argcnt++; allForm = XmCreateForm(form, "all", args, argcnt); @@ -1188,8 +1200,8 @@ int argcnt, defaultBtnOffset; XmString st1; Widget form, btnForm, searchTypeBox; - Widget findText, label1, label2, cancelBtn, findBtn; - Widget searchDirBox, reverseBtn, keepBtn; + Widget findText, label1, label2, cancelBtn, findBtn, highlightBtn; + Widget searchOptBox, reverseBtn, keepBtn; char title[MAXPATHLEN + 11]; Dimension shadowThickness; @@ -1309,20 +1321,31 @@ XtSetArg(args[argcnt], XmNleftAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNradioBehavior, False); argcnt++; - searchDirBox = XmCreateRowColumn(form, "searchDirBox", args, argcnt); - XtManageChild(searchDirBox); - XmAddTabGroup(searchDirBox); + searchOptBox = XmCreateRowColumn(form, "searchOptBox", args, argcnt); + XtManageChild(searchOptBox); + XmAddTabGroup(searchOptBox); argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Search Backward")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'B'); argcnt++; - reverseBtn = XmCreateToggleButton(searchDirBox, "reverse", args, argcnt); + reverseBtn = XmCreateToggleButton(searchOptBox, "reverse", args, argcnt); XmStringFree(st1); XtManageChild(reverseBtn); argcnt = 0; XtSetArg(args[argcnt], XmNlabelString, + st1=MKSTRING("Highlight")); argcnt++; + XtSetArg(args[argcnt], XmNmnemonic, 'l'); argcnt++; + highlightBtn = XmCreateToggleButton(searchOptBox, "highlight", args, argcnt); + XtAddCallback(highlightBtn, XmNvalueChangedCallback, + (XtCallbackProc)fHighlightCB, window); + XmStringFree(st1); + XtManageChild(highlightBtn); + XmAddTabGroup(highlightBtn); + + argcnt = 0; + XtSetArg(args[argcnt], XmNlabelString, st1=MKSTRING("Keep Dialog")); argcnt++; XtSetArg(args[argcnt], XmNmnemonic, 'K'); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; @@ -1342,7 +1365,7 @@ XtSetArg(args[argcnt], XmNrightAttachment, XmATTACH_FORM); argcnt++; XtSetArg(args[argcnt], XmNtopAttachment, XmATTACH_WIDGET); argcnt++; XtSetArg(args[argcnt], XmNbottomAttachment, XmATTACH_NONE); argcnt++; - XtSetArg(args[argcnt], XmNtopWidget, searchDirBox); argcnt++; + XtSetArg(args[argcnt], XmNtopWidget, searchOptBox); argcnt++; XtSetArg(args[argcnt], XmNleftOffset, 2); argcnt++; XtSetArg(args[argcnt], XmNrightOffset, 4); argcnt++; btnForm = XmCreateForm(form, "buttons", args, argcnt); @@ -1389,6 +1412,7 @@ window->findText = findText; window->findRevToggle = reverseBtn; window->findKeepBtn = keepBtn; + window->findHighlightBtn = highlightBtn; window->findBtns = btnForm; window->findBtn = findBtn; window->findSearchTypeBox = searchTypeBox; @@ -1712,6 +1736,228 @@ XtVaSetValues(XtParent(window->findDlog), XmNtitle, "Find", NULL); } +/* +** return rangeset used for search highlighting +*/ +static Rangeset *getSearchHighlightRangeset(WindowInfo *window) +{ + return RangesetFetch(window->buffer->rangesetTable, + window->searchHighlightRSLabel); +} + +/* +** return True if window contains search highlights +*/ +static int hasSearchHighlight(WindowInfo *window) +{ + Rangeset *rs = getSearchHighlightRangeset(window); + int nRanges; + + if (!rs) + return False; + + RangesetGetInfo(rs, NULL, NULL, &nRanges, + NULL, NULL, NULL); + + return nRanges? True : False; +} + +typedef struct _SearchHiliteRefreshInfo { + Rangeset *rs; + int startPos, endPos; +} SearchHiliteRefreshInfo; + +/* +** Xt timer procedure for refreshing rangeset after doing +** progressive search highlighting. +*/ +static void searchHiliteRefreshProc(XtPointer clientData, XtIntervalId *id) +{ + SearchHiliteRefreshInfo *refreshInfo = + (SearchHiliteRefreshInfo*) clientData; + + RangesetRefreshRange(refreshInfo->rs, refreshInfo->startPos, + refreshInfo->endPos); + + XtFree((char*) refreshInfo); +} + +/* +** Callback to do progressive search highlight on modified buffer range. +*/ +void SearchHighlightModifyCB(int pos, int nInserted, int nDeleted, + int nRestyled, char *deletedText, void *cbArg) +{ + WindowInfo *window = (WindowInfo *)cbArg; + char *string; + int beginPos, found, foundStart, foundEnd; + Rangeset *hiliteRange; + int lineStart, lineEnd; + SearchHiliteRefreshInfo *refreshInfo; + + if (!nInserted && !nDeleted) + return; + + if (!window->highlightSearchString) + return; + + if ((hiliteRange = getSearchHighlightRangeset(window)) == NULL) + return; + + /* refresh highlight on modified buffer range */ + lineStart = BufCountBackwardNLines(window->buffer, pos, + PROGRESSIVE_HIGHLIGHT_MARGIN); + lineEnd = BufCountForwardNLines(window->buffer, pos + nInserted, + PROGRESSIVE_HIGHLIGHT_MARGIN); + + RangesetSetRefresh(hiliteRange, False); + RangesetRemoveBetween(hiliteRange, lineStart, lineEnd); + + string = BufGetRange(window->buffer, lineStart, lineEnd); + beginPos = 0; + do { + found = SearchString(string, window->highlightSearchString, + SEARCH_FORWARD, window->highlightSearchType, False, beginPos, + &foundStart, &foundEnd, NULL, NULL, + GetWindowDelimiters(window)); + + if (found) { + /* add match pos to rangeset and continue searching */ + RangesetAddBetween(hiliteRange, lineStart + foundStart, + lineStart + foundEnd); + beginPos = foundEnd; /* begin next search from here */ + } + } while (found); + + RangesetSetRefresh(hiliteRange, True); + + /* Refresh new search highlight ranges. + + FIXME: + We have to delay the refreshing of the new ranges until all the + modifiedCB are called, else the text panes may not get updated + properly, probably due to successive calls to the update callbacks + during the progressive search, as new ranges are removed and added. + */ + refreshInfo = (SearchHiliteRefreshInfo*) XtMalloc( + sizeof(SearchHiliteRefreshInfo)); + refreshInfo->startPos = lineStart; + refreshInfo->endPos = lineEnd; + refreshInfo->rs = hiliteRange; + XtAppAddTimeOut(XtWidgetToApplicationContext(window->shell), 0, + searchHiliteRefreshProc, refreshInfo); + + XtFree(string); +} + +/* +** search and highlight all matched strings in document if searchString is +** is not null. Else, clear the existing highlights. +*/ +void SearchAndHighlightDocument(WindowInfo *window, const char *searchString, + int searchType) +{ + char *hlColor = GetPrefSearchHiliteColor(); /* hilite color for matches */ + Rangeset *hiliteRange; + + if (!window->highlightSearchString && searchString == NULL) + return; + + /* save the current search string and type used for highlighting */ + XtFree(window->highlightSearchString); + window->highlightSearchString = NULL; + if (searchString) { + window->highlightSearchString = XtNewString(searchString); + window->highlightSearchType = searchType; + } + + if (searchString) { + /* search and highlight all match strings */ + int beginPos, found = False, foundStart, foundEnd; + char *string; + int label; + + if (window->buffer->rangesetTable == NULL) { + window->buffer->rangesetTable = RangesetTableAlloc(window->buffer); + } + + if ((label = window->searchHighlightRSLabel) == 0) { + if ((label = RangesetCreate(window->buffer->rangesetTable)) == 0) { + fprintf(stderr, "nedit: unable to create rangeset for search \ +highlighting\n"); + return; + } + + /* search highlight is always displayed over other rangesets */ + RangesetSetPriority(window->buffer->rangesetTable, label, 1); + window->searchHighlightRSLabel = label; + } + + /* create rangeset for highlighting matching strings */ + hiliteRange = RangesetFetch(window->buffer->rangesetTable, label); + + /* assign rangeset name and color */ + RangesetAssignColorName(hiliteRange, hlColor); + RangesetChangeModifyResponse(hiliteRange, "maintain"); + + /* defer rangeset refreshing until after we are done + searching, to improve the search-and-hilite speed. */ + RangesetSetRefresh(hiliteRange, False); + + /* put up the busy clock cursor, in case it take too long (?) */ + BeginWait(window->shell); + BusyWait(window->shell); + + /* search for matches and add to rangeset */ + string = BufGetAll(window->buffer); + beginPos = 0; + do { + found = SearchString(string, searchString, SEARCH_FORWARD, + searchType, False, beginPos, + &foundStart, &foundEnd, NULL, NULL, + GetWindowDelimiters(window)); + + if (found) { + /* add match pos to rangeset and continue searching */ + RangesetAddBetween(hiliteRange, foundStart, foundEnd); + beginPos = foundEnd; /* begin next search from here */ + } + } while (found); + + /* refresh the whole rangeset */ + RangesetSetRefresh(hiliteRange, True); + RangesetRefreshRange(hiliteRange, 0, window->buffer->length); + + EndWait(window->shell); + } + else { + /* remove highlight */ + hiliteRange = getSearchHighlightRangeset(window); + if (hiliteRange) { + /* delay refreshing the ranges till after we are done */ + RangesetSetRefresh(hiliteRange, False); + + /* remove the highlighted ranges */ + RangesetEmpty(hiliteRange); + + /* clear the highlight on display */ + RangesetSetRefresh(hiliteRange, True); + RangesetRefreshRange(hiliteRange, 0, window->buffer->length); + } + } +} + +/* +** Callback to clicks on Highlight button on the Find dialog +*/ +static void fHighlightCB(Widget w, WindowInfo *window, caddr_t *callData) +{ + if (!XmToggleButtonGetState(w)) { + /* clear previous highlights */ + SearchAndHighlightDocument(WidgetToWindow(w), NULL, 0); + } +} + static void replaceCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { @@ -2558,7 +2804,7 @@ { char searchString[SEARCHMAX]; int direction, searchType; - char *params[4]; + char *params[5]; window = WidgetToWindow(w); @@ -2574,8 +2820,9 @@ params[1] = directionArg(direction); params[2] = searchTypeArg(searchType); params[3] = searchWrapArg(GetPrefSearchWraps()); + params[4] = searchHighlightArg(XmToggleButtonGetState(window->findHighlightBtn)); windowNotToClose = window; - XtCallActionProc(window->lastFocus, "find", callData->event, params, 4); + XtCallActionProc(window->lastFocus, "find", callData->event, params, 5); windowNotToClose = NULL; /* pop down the dialog */ @@ -2730,7 +2977,8 @@ return TRUE; } -int SearchAndSelectSame(WindowInfo *window, int direction, int searchWrap) +int SearchAndSelectSame(WindowInfo *window, int direction, int searchWrap, + int searchHighlight) { if (NHist < 1) { XBell(TheDisplay, 0); @@ -2738,7 +2986,7 @@ } return SearchAndSelect(window, direction, SearchHistory[historyIndex(1)], - SearchTypeHistory[historyIndex(1)], searchWrap); + SearchTypeHistory[historyIndex(1)], searchWrap, searchHighlight); } /* @@ -2747,10 +2995,11 @@ ** adds the search string to the global search history. */ int SearchAndSelect(WindowInfo *window, int direction, const char *searchString, - int searchType, int searchWrap) + int searchType, int searchWrap, int searchHighlight) { int startPos, endPos; int beginPos, cursorPos, selStart, selEnd; + int doHilite; /* Save a copy of searchString in the search history */ saveSearchHistory(searchString, NULL, searchType, FALSE); @@ -2787,6 +3036,26 @@ incremental search wraps. */ iSearchRecordLastBeginPos(window, direction, beginPos); + /* check to see if we need to highlight matched strings */ + if (searchHighlight) { + int searchChanged = window->highlightSearchString && + (window->highlightSearchType != searchType || + strcmp(window->highlightSearchString, searchString)); + + /* do highlight if it wasn't done or, if search settings + has changed since last highlight. */ + doHilite = !hasSearchHighlight(window) || searchChanged; + if (doHilite) { + /* clear previous highlights */ + SearchAndHighlightDocument(window, NULL, 0); + } + } + else { + /* clear previous highlights */ + SearchAndHighlightDocument(window, NULL, 0); + doHilite = False; + } + /* do the search. SearchWindow does appropriate dialogs and beeps */ if (!SearchWindow(window, direction, searchString, searchType, searchWrap, beginPos, &startPos, &endPos, NULL, NULL)) @@ -2800,6 +3069,11 @@ beginPos+1, &startPos, &endPos, NULL, NULL)) return FALSE; + if (doHilite) { + /* refresh search highlight */ + SearchAndHighlightDocument(window, searchString, searchType); + } + /* if matched text is already selected, just beep */ if (selStart==startPos && selEnd==endPos) { XBell(TheDisplay, 0); @@ -2815,12 +3089,13 @@ } void SearchForSelected(WindowInfo *window, int direction, int searchType, - int searchWrap, Time time) + int searchWrap, int searchHighlight, Time time) { SearchSelectedCallData *callData = XtNew(SearchSelectedCallData); callData->direction = direction; callData->searchType = searchType; callData->searchWrap = searchWrap; + callData->searchHighlight = searchHighlight; XtGetSelectionValue(window->textArea, XA_PRIMARY, XA_STRING, (XtSelectionCallbackProc)selectedSearchCB, callData, time); } @@ -2884,7 +3159,8 @@ /* search for it in the window */ SearchAndSelect(window, callDataItems->direction, searchString, - searchType, callDataItems->searchWrap); + searchType, callDataItems->searchWrap, callDataItems->searchHighlight); + XtFree(callData); } @@ -2949,9 +3225,31 @@ ** current cursor position. */ int SearchAndSelectIncremental(WindowInfo *window, int direction, - const char *searchString, int searchType, int searchWrap, int continued) + const char *searchString, int searchType, int searchWrap, + int searchHighlight, int continued) { int beginPos, startPos, endPos; + int doHilite; + + /* check to see if we need to highlight matched strings */ + if (searchHighlight) { + int searchChanged = window->highlightSearchString && + (window->highlightSearchType != searchType || + strcmp(window->highlightSearchString, searchString)); + + /* do highlight if it wasn't done or, if search settings + has changed since last highlight. */ + doHilite = !hasSearchHighlight(window) || searchChanged; + if (doHilite) { + /* clear previous highlights */ + SearchAndHighlightDocument(window, NULL, 0); + } + } + else { + /* clear previous highlights */ + SearchAndHighlightDocument(window, NULL, 0); + doHilite = False; + } /* If there's a search in progress, start the search from the original starting position, otherwise search from the cursor position. */ @@ -3005,6 +3303,11 @@ window->iSearchLastBeginPos = startPos; + if (doHilite) { + /* refresh search highlight */ + SearchAndHighlightDocument(window, searchString, searchType); + } + /* select the text found string */ BufSelect(window->buffer, startPos, endPos); MakeSelectionVisible(window, window->lastFocus); @@ -3133,6 +3436,9 @@ window = WidgetToWindow(w); iSearchTextSetString(w, window, NULL); + + /* clear previous highlights */ + SearchAndHighlightDocument(window, NULL, 0); } /* @@ -3143,7 +3449,7 @@ static void iSearchTextActivateCB(Widget w, WindowInfo *window, XmAnyCallbackStruct *callData) { - char *params[4]; + char *params[5]; char *searchString; int searchType, direction; @@ -3176,7 +3482,9 @@ params[1] = directionArg(direction); params[2] = searchTypeArg(searchType); params[3] = searchWrapArg(GetPrefSearchWraps()); - XtCallActionProc(window->lastFocus, "find", callData->event, params, 4); + params[4] = searchHighlightArg(GetPrefSearchHighlight()); + XtCallActionProc(window->lastFocus, "find", callData->event, params, 5); + XtFree(searchString); } @@ -3236,10 +3544,12 @@ params[nParams++] = directionArg(direction); params[nParams++] = searchTypeArg(searchType); params[nParams++] = searchWrapArg(GetPrefSearchWraps()); + params[nParams++] = searchHighlightArg(GetPrefSearchHighlight()); if (window->iSearchStartPos != -1) params[nParams++] = "continued"; XtCallActionProc(window->lastFocus, "find_incremental", callData->event, params, nParams); + XtFree(searchString); } @@ -3604,7 +3914,7 @@ /* Replace the selected text only if it matches the search string */ if (searchMatchesSelection(window, searchString, searchType, &startPos, &endPos, &searchExtentBW, - &searchExtentFW)) { + &searchExtentFW)) { /* replace the text */ if (isRegexType(searchType)) { char replaceResult[SEARCHMAX+1], *foundString; @@ -3631,7 +3941,8 @@ } /* do the search; beeps/dialogs are taken care of */ - SearchAndSelect(window, direction, searchString, searchType, searchWrap); + SearchAndSelect(window, direction, searchString, searchType, searchWrap, + hasSearchHighlight(window)); return replaced; } @@ -3838,6 +4149,7 @@ /* replace the selected range in the real buffer */ fileString = BufGetAll(tempBuf); BufFree(tempBuf); + BufReplace(window->buffer, selStart, selEnd, fileString); XtFree(fileString); @@ -4759,17 +5071,28 @@ } /* +** Return a pointer to the string describing search highlight for search action +** routine parameters (see menu.c for processing of action routines) +*/ +static char *searchHighlightArg(int searchHighligh) +{ + if (searchHighligh) { + return "highlight"; + } + return "nohighlight"; +} + +/* ** Return a pointer to the string describing search wrap for search action ** routine parameters (see menu.c for processing of action routines) */ static char *searchWrapArg(int searchWrap) { if (searchWrap) { - return "wrap"; + return "wapr"; } return "nowrap"; } - /* ** Return a pointer to the string describing search direction for search action ** routine parameters (see menu.c for processing of action routines) diff -Nru a/source/search.h b/source/search.h --- a/source/search.h 2005-01-10 21:12:12 +08:00 +++ b/source/search.h 2005-01-10 21:12:12 +08:00 @@ -44,13 +44,17 @@ void UpdateReplaceActionButtons(WindowInfo* window); void DoFindDlog(WindowInfo *window, int direction, int keepDialogs, int searchType, Time time); +void SearchAndHighlightDocument(WindowInfo *window, const char *searchString, + int searchType); int SearchAndSelect(WindowInfo *window, int direction, const char *searchString, - int searchType, int searchWrap); -int SearchAndSelectSame(WindowInfo *window, int direction, int searchWrap); + int searchType, int searchWrap, int searchHighlight); +int SearchAndSelectSame(WindowInfo *window, int direction, int searchWrap, + int searchHighlight); int SearchAndSelectIncremental(WindowInfo *window, int direction, - const char *searchString, int searchType, int searchWrap, int continued); -void SearchForSelected(WindowInfo *window, int direction, int searchWrap, - int searchType, Time time); + const char *searchString, int searchType, int searchWrap, + int searchHighlight, int continued); +void SearchForSelected(WindowInfo *window, int direction, int searchType, + int searchWrap, int searchHighlight, Time time); int SearchAndReplace(WindowInfo *window, int direction, const char *searchString, const char *replaceString, int searchType, int searchWrap); int ReplaceAndSearch(WindowInfo *window, int direction, const char *searchString, diff -Nru a/source/window.c b/source/window.c --- a/source/window.c 2005-01-10 21:12:12 +08:00 +++ b/source/window.c 2005-01-10 21:12:12 +08:00 @@ -195,6 +195,9 @@ static WindowInfo *lastFocusDocument = NULL; /* where we came from */ static int DoneWithMoveDocumentDialog; +void SearchHighlightModifyCB(int pos, int nInserted, int nDeleted, + int nRestyled, char *deletedText, void *cbArg); + /* ** Create a new editor window */ @@ -304,6 +307,8 @@ window->macroCmdData = NULL; window->smartIndentData = NULL; window->languageMode = PLAIN_LANGUAGE_MODE; + window->highlightSearchString = NULL; + window->searchHighlightRSLabel = 0; window->iSearchHistIndex = 0; window->iSearchStartPos = -1; window->replaceLastRegexCase = TRUE; @@ -719,6 +724,7 @@ the text display's callback is called upon to display a modification */ window->buffer = BufCreate(); BufAddModifyCB(window->buffer, SyntaxHighlightModifyCB, window); + BufAddModifyCB(window->buffer, SearchHighlightModifyCB, window); /* Attach the buffer to the text widget, and add callbacks for modify */ TextSetBuffer(text, window->buffer); @@ -949,6 +955,9 @@ /* Destroy the file closed property for this file */ DeleteFileClosedProperty(window); + + /* release search highlighting rangeset and associated storage */ + SearchAndHighlightDocument(window, NULL, 0); /* if this is the last window, or must be kept alive temporarily because it's running the macro calling us, don't close it, make it Untitled */ @@ -992,6 +1001,7 @@ deallocated when the last text widget is destroyed */ BufRemoveModifyCB(window->buffer, modifiedCB, window); BufRemoveModifyCB(window->buffer, SyntaxHighlightModifyCB, window); + BufRemoveModifyCB(window->buffer, SearchHighlightModifyCB, window); #ifdef ROWCOLPATCH patchRowCol(window->menuBar); @@ -3257,6 +3267,8 @@ window->languageMode = PLAIN_LANGUAGE_MODE; window->iSearchHistIndex = 0; window->iSearchStartPos = -1; + window->searchHighlightRSLabel = 0; + window->highlightSearchString = NULL; window->replaceLastRegexCase = TRUE; window->replaceLastLiteralCase = FALSE; window->iSearchLastRegexCase = TRUE; @@ -3338,6 +3350,7 @@ the text display's callback is called upon to display a modification */ window->buffer = BufCreate(); BufAddModifyCB(window->buffer, SyntaxHighlightModifyCB, window); + BufAddModifyCB(window->buffer, SearchHighlightModifyCB, window); /* Attach the buffer to the text widget, and add callbacks for modify */ TextSetBuffer(text, window->buffer); @@ -3868,7 +3881,7 @@ void RaiseDocument(WindowInfo *window) { WindowInfo *win, *lastwin; - + if (!window || !WindowList) return; @@ -4265,6 +4278,13 @@ window->nMarks = orgWin->nMarks; memcpy(&window->markTable, &orgWin->markTable, sizeof(Bookmark)*window->nMarks); + + /* clone search highlighting stuff */ + if (orgWin->highlightSearchString) { + window->highlightSearchString = XtNewString(orgWin->highlightSearchString); + window->highlightSearchType = orgWin->highlightSearchType; + window->searchHighlightRSLabel = orgWin->searchHighlightRSLabel; + } /* kick start the auto-indent engine */ window->indentStyle = NO_AUTO_INDENT;