go back to 3 lines of context
[nedit-bw.git] / SmartCaseSearch.patch
blobfaa9b5082dacb02e8b34c13114a92ebadfa158ff
1 From: Thorsten Haude <yoo@vranx.de>
2 Subject: Smart Case Search
4 This adds the option 'Regular Expression, Smart Case' to Preferences ->
5 Default Settings -> Searching -> Default Search Style.
7 If this option is activated, the behavior of the iSearch bar changes as
8 follows: The search defaults to 'regex, no case' but changes to 'case
9 sensitive' as soon as an upper-case letter is entered in the iSearch line.
11 As seen on Mutt, other applications probably have similar things.
13 One problem I have with this is the lack of visual feedback. A separate
14 button is out of the question of course, so how should this be signaled to
15 the user? Color?
17 I added this only to the iSearch, I somehow don't see this in the
18 find/replace dialog boxes.
20 ---
22 doc/help.etx | 23 ++++++++++++------
23 source/menu.c | 36 +++++++++++++++++++++++++++++
24 source/nedit.h | 1
25 source/preferences.c | 17 +++++++------
26 source/search.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++-----
27 source/search.h | 1
28 source/window.c | 3 +-
29 7 files changed, 122 insertions(+), 22 deletions(-)
31 diff --quilt old/doc/help.etx new/doc/help.etx
32 --- old/doc/help.etx
33 +++ new/doc/help.etx
34 @@ -262,6 +262,11 @@ Finding and Replacing Text
35 content of any existing selection into the search text widget and triggers a new
36 search.
38 + All searches will default to the search mode selected in the preference menu.
39 + (Default Setting -> Searching -> Default Search Style). You can choose a smart
40 + case sensitivity here; this let all searches start insensitive, but changes to
41 + case sensitive as soon as you enter an upper-case letter.
43 3>Searching Backwards
45 Holding down the shift key while choosing any of the search or replace
46 @@ -2766,9 +2771,10 @@ Macro Subroutines
47 Optional arguments may include the strings: "wrap" to make the search wrap
48 around the beginning or end of the string, "backward" or "forward" to change
49 the search direction ("forward" is the default), "literal", "case", "word",
50 - "caseWord", "regex", or "regexNoCase" to change the search type (default is
51 - "literal"). Returns the starting position of the match, or -1 if nothing
52 - matched. Also returns the ending position of the match in $search_end.
53 + "caseWord", "regex", "regexNoCase", or "regexSmartCase" to change the search
54 + type (default is "literal"). Returns the starting position of the match, or
55 + -1 if nothing matched. Also returns the ending position of the match in
56 + $search_end.
58 **search_string( string, search_for, start [, search_type, direction] )**
59 Built-in macro subroutine for searching a string. Arguments are 1: string to
60 @@ -2776,9 +2782,9 @@ Macro Subroutines
61 may include the strings: "wrap" to make the search wrap around the beginning
62 or end of the string, "backward" or "forward" to change the search direction
63 ("forward" is the default), "literal", "case", "word", "caseWord", "regex",
64 - or "regexNoCase" to change the search type (default is "literal"). Returns
65 - the starting position of the match, or -1 if nothing matched. Also returns
66 - the ending position of the match in $search_end.
67 + "regexNoCase", or "regexSmartCase" to change the search type (default is
68 + "literal"). Returns the starting position of the match, or -1 if nothing
69 + matched. Also returns the ending position of the match in $search_end.
71 **select( start, end )**
72 Selects (with the primary selection) text in the current buffer between a
73 @@ -3321,8 +3327,9 @@ Action Routines
74 ~search-direction~
75 Either "forward" or "backward".
77 - ~search-type~ Either "literal", "case", "word",
78 - "caseWord", "regex", or "regexNoCase".
79 + ~search-type~ Either "literal", "case", "word",
80 + "caseWord", "regex", "regexNoCase",
81 + or "regexSmartCase".
83 ~search-wrap~ Either "wrap" or "nowrap".
85 diff --quilt old/source/menu.c new/source/menu.c
86 --- old/source/menu.c
87 +++ new/source/menu.c
88 @@ -193,6 +193,8 @@ static void searchCaseSenseCB(Widget w,
89 static void searchLiteralWordCB(Widget w, WindowInfo *window, caddr_t callData);
90 static void searchCaseSenseWordCB(Widget w, WindowInfo *window, caddr_t callData);
91 static void searchRegexNoCaseCB(Widget w, WindowInfo *window, caddr_t callData);
92 +static void searchRegexSmartCaseCB(Widget toggleButton, WindowInfo *windowInfo,
93 + caddr_t callData);
94 static void searchRegexCB(Widget w, WindowInfo *window, caddr_t callData);
95 #ifdef REPLACE_SCOPE
96 static void replaceScopeWindowCB(Widget w, WindowInfo *window, caddr_t callData);
97 @@ -935,6 +937,10 @@ Widget CreateMenuBar(Widget parent, Wind
98 window->searchRegexNoCaseDefItem = createMenuToggle(subSubSubPane,
99 "regularExpressionNoCase", "Regular Expression, Case Insensitive", 'I', searchRegexNoCaseCB, window,
100 GetPrefSearch() == SEARCH_REGEX_NOCASE, FULL);
101 + window->searchRegexSmartCaseDefItem = createMenuToggle(subSubSubPane,
102 + "regularExpressionSmartCase", "Regular Expression, Smart Case",
103 + 'S', searchRegexSmartCaseCB, window,
104 + GetPrefSearch() == SEARCH_REGEX_SMARTCASE, FULL);
105 #ifdef REPLACE_SCOPE
106 subSubSubPane = createMenu(subSubPane, "defaultReplaceScope",
107 "Default Replace Scope", 'R', NULL, FULL);
108 @@ -2568,6 +2574,36 @@ static void searchRegexNoCaseCB(Widget w
112 +static void searchRegexSmartCaseCB(Widget toggleButton, WindowInfo *window,
113 + caddr_t callData)
115 + WindowInfo *windowInfo;
117 + /* Set the preference and make the other windows' menus agree */
118 + if (XmToggleButtonGetState(toggleButton)) {
119 + SetPrefSearch(SEARCH_REGEX_SMARTCASE);
121 + for (windowInfo = WindowList;
122 + windowInfo != NULL;
123 + windowInfo = windowInfo->next) {
124 + XmToggleButtonSetState(windowInfo->searchLiteralDefItem,
125 + False, False);
126 + XmToggleButtonSetState(windowInfo->searchCaseSenseDefItem,
127 + False, False);
128 + XmToggleButtonSetState(windowInfo->searchLiteralWordDefItem,
129 + False, False);
130 + XmToggleButtonSetState(windowInfo->searchCaseSenseWordDefItem,
131 + False, False);
132 + XmToggleButtonSetState(windowInfo->searchRegexDefItem,
133 + False, False);
134 + XmToggleButtonSetState(windowInfo->searchRegexNoCaseDefItem,
135 + False, False);
136 + XmToggleButtonSetState(windowInfo->searchRegexSmartCaseDefItem,
137 + True, False);
142 #ifdef REPLACE_SCOPE
143 static void replaceScopeWindowCB(Widget w, WindowInfo *window, caddr_t callData)
145 diff --quilt old/source/nedit.h new/source/nedit.h
146 --- old/source/nedit.h
147 +++ new/source/nedit.h
148 @@ -425,6 +425,7 @@ typedef struct _WindowInfo {
149 Widget searchLiteralWordDefItem;
150 Widget searchCaseSenseWordDefItem;
151 Widget searchRegexNoCaseDefItem;
152 + Widget searchRegexSmartCaseDefItem;
153 Widget searchRegexDefItem;
154 #ifdef REPLACE_SCOPE
155 Widget replScopeWinDefItem;
156 diff --quilt old/source/preferences.c new/source/preferences.c
157 --- old/source/preferences.c
158 +++ new/source/preferences.c
159 @@ -119,6 +119,7 @@ enum fontStatus {GOOD_FONT, BAD_PRIMARY,
160 static char *SearchMethodStrings[] = {
161 "Literal", "CaseSense", "RegExp",
162 "LiteralWord", "CaseSenseWord", "RegExpNoCase",
163 + "RegExpSmartCase",
164 NULL
167 @@ -2219,14 +2220,6 @@ int GetPrefTruncSubstitution(void)
168 return PrefData.truncSubstitution;
172 -** If preferences don't get saved, ask the user on exit whether to save
174 -void MarkPrefsChanged(void)
176 - PrefsHaveChanged = True;
179 void SetPrefShowCursorline(Boolean value)
181 setIntPref(&PrefData.showCursorline, (int)value);
182 @@ -2238,6 +2231,14 @@ Boolean GetPrefShowCursorline(void)
186 +** If preferences don't get saved, ask the user on exit whether to save
188 +void MarkPrefsChanged(void)
190 + PrefsHaveChanged = True;
194 ** Check if preferences have changed, and if so, ask the user if he wants
195 ** to re-save. Returns False if user requests cancelation of Exit (or whatever
196 ** operation triggered this call to be made).
197 diff --quilt old/source/search.c new/source/search.c
198 --- old/source/search.c
199 +++ new/source/search.c
200 @@ -245,6 +245,7 @@ static void iSearchRecordLastBeginPos(Wi
201 int initPos);
202 static Boolean prefOrUserCancelsSubst(const Widget parent,
203 const Display* display);
204 +static void smartCaseToggle(const char *searchString, Widget toggleButton);
206 typedef struct _charMatchTable {
207 char c;
208 @@ -281,6 +282,7 @@ static char *searchTypeStrings[] = {
209 "word", /* SEARCH_LITERAL_WORD */
210 "caseWord", /* SEARCH_CASE_SENSE_WORD */
211 "regexNoCase", /* SEARCH_REGEX_NOCASE */
212 + "regexSmartCase", /* SEARCH_REGEX_SMARTCASE */
213 NULL
216 @@ -370,6 +372,8 @@ static void initToggleButtons(int search
218 break;
219 case SEARCH_REGEX_NOCASE:
220 + case SEARCH_REGEX_SMARTCASE:
221 + /* Smart case is no case for default setting */
222 *lastLiteralCase = False;
223 *lastRegexCase = False;
224 XmToggleButtonSetState(regexToggle, True, False);
225 @@ -2408,8 +2412,16 @@ static int textFieldNonEmpty(Widget w)
227 static void rFindTextValueChangedCB(Widget w, WindowInfo *window, XKeyEvent *event)
229 + char *searchString = XmTextGetString(w);
231 window = WidgetToWindow(w);
232 UpdateReplaceActionButtons(window);
234 + /* Switch to case-sensitive as soon as the user enters an upper-case
235 + letter. We have check the whole string each time to catch clipboard
236 + or selection inserts. */
237 + smartCaseToggle(searchString, window->replaceCaseToggle);
238 + XtFree(searchString);
241 static void rFindArrowKeyCB(Widget w, WindowInfo *window, XKeyEvent *event)
242 @@ -2503,8 +2515,16 @@ static void fUpdateActionButtons(WindowI
244 static void findTextValueChangedCB(Widget w, WindowInfo *window, XKeyEvent *event)
246 + char *searchString = XmTextGetString(w);
248 window = WidgetToWindow(w);
249 fUpdateActionButtons(window);
251 + /* Switch to case-sensitive as soon as the user enters an upper-case
252 + letter. We have check the whole string each time to catch clipboard
253 + or selection inserts. */
254 + smartCaseToggle(searchString, window->findCaseToggle);
255 + XtFree(searchString);
258 static void findArrowKeyCB(Widget w, WindowInfo *window, XKeyEvent *event)
259 @@ -2876,10 +2896,13 @@ static void selectedSearchCB(Widget w, X
260 /* Use the passed method for searching, unless it is regex, since this
261 kind of search is by definition a literal search */
262 searchType = callDataItems->searchType;
263 - if (searchType == SEARCH_REGEX )
264 - searchType = SEARCH_CASE_SENSE;
265 - else if (searchType == SEARCH_REGEX_NOCASE)
266 - searchType = SEARCH_LITERAL;
267 + if (searchType == SEARCH_REGEX || searchType == SEARCH_REGEX_SMARTCASE) {
268 + /* Here smart case must be sensitive, because the user
269 + cannot modify the string to search for. */
270 + searchType = SEARCH_CASE_SENSE;
271 + } else if (searchType == SEARCH_REGEX_NOCASE) {
272 + searchType = SEARCH_LITERAL;
275 /* search for it in the window */
276 SearchAndSelect(window, callDataItems->direction, searchString,
277 @@ -2902,6 +2925,11 @@ void BeginISearch(WindowInfo *window, in
278 choice. If not, an initToggleButtons() call should be inserted
279 here. But in that case, it might be appropriate to have different
280 default search modes for i-search and replace/find. */
282 + /* The 'Case' toggle button must be deactivated for smart cases. */
283 + if (GetPrefSearch() == SEARCH_REGEX_SMARTCASE) {
284 + XmToggleButtonSetState(window->iSearchCaseToggle, False, False);
286 TempShowISearch(window, TRUE);
287 XmProcessTraversal(window->iSearchText, XmTRAVERSE_CURRENT);
289 @@ -3195,6 +3223,12 @@ static void iSearchTextValueChangedCB(Wi
290 /* Fetch the string, search type and direction from the incremental
291 search bar widgets at the top of the window */
292 searchString = XmTextGetString(window->iSearchText);
294 + /* Switch to case-sensitive as soon as the user enters an upper-case
295 + letter. We have check the whole string each time to catch clipboard
296 + or selection inserts. */
297 + smartCaseToggle(searchString, window->iSearchCaseToggle);
299 if(XmToggleButtonGetState(window->iSearchCaseToggle)) {
300 if(XmToggleButtonGetState(window->iSearchRegexToggle))
301 searchType = SEARCH_REGEX;
302 @@ -4879,7 +4913,9 @@ static char *directionArg(int direction)
304 static int isRegexType(int searchType)
306 - return searchType == SEARCH_REGEX || searchType == SEARCH_REGEX_NOCASE;
307 + return searchType == SEARCH_REGEX
308 + || searchType == SEARCH_REGEX_NOCASE
309 + || searchType == SEARCH_REGEX_SMARTCASE;
313 @@ -5022,3 +5058,20 @@ static void iSearchCaseToggleCB(Widget w
314 else
315 window->iSearchLastLiteralCase = searchCaseSense;
319 +** Will search a string for uppercase characters. If there is one,
320 +** The toggleButton will be set to True.
322 +static void smartCaseToggle(const char *searchString, Widget toggleButton)
324 + if (GetPrefSearch() == SEARCH_REGEX_SMARTCASE) {
325 + int i;
326 + for (i = 0; i < strlen(searchString); i++) {
327 + if (isupper(*(searchString + i))) {
328 + XmToggleButtonSetState(toggleButton, True, False);
329 + break;
334 diff --quilt old/source/search.h new/source/search.h
335 --- old/source/search.h
336 +++ new/source/search.h
337 @@ -90,6 +90,7 @@ Boolean WindowCanBeClosed(WindowInfo *wi
338 enum SearchType {
339 SEARCH_LITERAL, SEARCH_CASE_SENSE, SEARCH_REGEX,
340 SEARCH_LITERAL_WORD, SEARCH_CASE_SENSE_WORD, SEARCH_REGEX_NOCASE,
341 + SEARCH_REGEX_SMARTCASE,
342 N_SEARCH_TYPES /* must be last in enum SearchType */ };
344 #ifdef REPLACE_SCOPE
345 diff --quilt old/source/window.c new/source/window.c
346 --- old/source/window.c
347 +++ new/source/window.c
348 @@ -490,7 +490,8 @@ WindowInfo *CreateWindow(const char *nam
349 xmToggleButtonWidgetClass, window->iSearchForm,
350 XmNlabelString, s1=XmStringCreateSimple("RegExp"),
351 XmNset, GetPrefSearch() == SEARCH_REGEX_NOCASE
352 - || GetPrefSearch() == SEARCH_REGEX,
353 + || GetPrefSearch() == SEARCH_REGEX
354 + || GetPrefSearch() == SEARCH_REGEX_SMARTCASE,
355 XmNtopAttachment, XmATTACH_FORM,
356 XmNbottomAttachment, XmATTACH_FORM,
357 XmNtopOffset, 1, /* see openmotif note above */