4 enum FindInFilesMode { directory, workspace, project };
6 class FindInFilesDialog : Window
8 text = $"Find In Files";
9 background = formColor;
10 borderStyle = sizable;
11 minClientSize = { 440, 208 };
12 maxClientSize = { 640, 208 };
19 property const char * searchString { set { findContent.contents = value; } get { return findContent.contents; } };
20 property bool contentWholeWord { set { contentWholeWord.checked = value; } get { return contentWholeWord.checked; } };
21 property bool contentMatchCase { set { contentMatchCase.checked = value; } get { return contentMatchCase.checked; } };
22 property const char * currentDirectory
26 GetWorkingDir(currentDirectory, MAX_DIRECTORY);
27 PathCat(currentDirectory, value);
28 FileFixCase(currentDirectory);
29 findWhere.path = currentDirectory;
31 get { return (char *)currentDirectory; }
33 property FileFilter * filters { set { filters = value; } get { return filters; } };
34 // Replace with Array system
35 property int sizeFilters
39 int numFilters = value / sizeof(FileFilter);
44 // File Extension Filter
46 // filterDrop.AddField(null);
50 for(c = 0; c<numFilters; c++)
52 DataRow row = filterDrop.AddString(filters[c].name);
53 if(filters[c].extensions && !strcmp(filters[c].extensions, "ec, eh, c, cpp, cc, cxx, h, hpp, hh, hxx"))
59 filterDrop.AddString($"All files");
61 //if(fileFilter >= numFilters)
63 filterDrop.currentRow = filterDrop.FindRow(fileFilter);
65 get { return sizeFilters; }
67 property int filter { set { fileFilter = value; } get { return fileFilter; } };
69 property FindInFilesMode mode
76 findIn.SelectRow(inDirectoryRow);
79 findIn.SelectRow(inWorkspaceRow);
84 for(row = findIn.firstRow; row; row = row.next)
85 if(row != inDirectoryRow && row != inWorkspaceRow)
88 findIn.SelectRow(row);
92 lastSelectionMode = value;
96 if(findIn.currentRow == inDirectoryRow)
98 else if(findIn.currentRow == inWorkspaceRow)
105 property char * findDir
107 get { return searchThread.mode == directory ? (char *)searchThread.dir : null; }
109 /*if(searchThread.mode == directory)
110 ide.outputView.findDir = CopyString(searchThread.dir);
111 else if(searchThread.mode == project)
112 ide.outputView.findProject = searchThread.project;*/
113 property Project findProject
115 get { return searchThread.mode == project ? searchThread.project : null; }
118 property bool replaceMode
122 if(value != replaceMode)
124 int h = value ? 236 : 208;
125 find.text = value ? $"Replace" : $"Find";
126 find.hotKey = value ? altF : altR; // tocheck: the hotkey keeps getting lost
127 llreplaceWith.visible = value;
128 text = value ? $"Replace In Files" : $"Find In Files";
137 void AddProjectItem(Project project)
141 char label[MAX_FILENAME];
143 sprintf(label, $"%s Project", project.name);
144 row = findIn.AddString(label);
145 row.tag = (int64)(intptr)project;
149 void RemoveProjectItem(Project project)
154 for(row = inWorkspaceRow.next; row; row = row.next)
156 if((Project)(intptr)row.tag == project)
158 findIn.DeleteRow(row);
175 char currentDirectory[MAX_DIRECTORY];
176 FileFilter * filters;
179 DataRow inDirectoryRow;
180 DataRow inWorkspaceRow;
181 FindInFilesMode lastSelectionMode;
182 String lastSelectionProject;
183 String lastSelectionProjectNode;
185 SelectorButton starDir;
189 GetWorkingDir(currentDirectory, MAX_DIRECTORY);
190 FileFixCase(currentDirectory);
191 findWhere.path = currentDirectory;
192 findWherePrjNode.AddField(projectNodeField);
198 delete lastSelectionProject;
199 delete lastSelectionProjectNode;
204 this, anchor = { left = 20, top = 4, right = 8, bottom = 0 };
205 direction = horizontal;
216 anchor.top = 0, anchor.bottom = 0;
220 LayoutLine llfindIn { lpmain, this, size.h = 26 };
221 LayoutLine llfindWhere { lpmain, this, size.h = 26 };
222 LayoutLine llsubDirs { lpmain, this, size.h = 18 };
223 LayoutLine llfilter { lpmain, this, size.h = 26 };
224 LayoutLine llfileName { lpmain, this, size.h = 26 };
225 LayoutLine llfindWhat { lpmain, this, size.h = 26 };
226 LayoutLine llwholeWord { lpmain, this, size.h = 18 };
227 LayoutLine llmatchCase { lpmain, this, size.h = 18 };
228 LayoutLine llreplaceWith { lpmain, this, size.h = 26, visible = false };
230 Label lfindIn { llfindIn, this, size.w = 72, labeledWindow = findIn };
233 llfindIn, this, $"Find in:", altI, anchor.right = 0;
235 bool NotifySelect(DropBox control, DataRow row, Modifiers mods)
237 FindInFilesMode mode = this.mode;
238 bool inDir = mode == directory;
239 bool inWrk = mode == workspace;
240 bool inPrj = mode == project;
242 lfindWhere.labeledWindow = findWherePrjNode;
244 lfindWhere.labeledWindow = findWhere;
245 findWhere.visible = !inPrj;
246 findWhere.disabled = !inDir;
247 findWherePrjNode.visible = inPrj;
248 subDirs.disabled = inWrk;
249 llfindWhere.size = { llfindWhere.size.w, llfindWhere.size.h };
254 lastSelectionMode = mode;
255 prj = lastSelectionMode == project ? (Project)(intptr)row.tag : null;
256 delete lastSelectionProject;
260 ProjectNode node = prj.topNode;
261 char filePath[MAX_LOCATION];
262 prj.topNode.GetFullFilePath(filePath, true, true);
263 lastSelectionProject = CopyString(filePath);
264 findWherePrjNode.Clear();
265 ListProjectNodeFolders(node, null);
267 if(lastSelectionProjectNode && !(node = prj.topNode.FindByFullPath(lastSelectionProjectNode, false)))
270 delete lastSelectionProjectNode;
273 for(r = findWherePrjNode.firstRow; r; r = r.next)
274 if((ProjectNode)(intptr)r.tag == node)
277 findWherePrjNode.SelectRow(r);
284 void ListProjectNodeFolders(ProjectNode node, DataRow parentRow)
288 row = findWherePrjNode/*parentRow*/.AddRow();
290 row = findWherePrjNode.AddRow();
291 row.tag = (int64)(intptr)node;
292 row.SetData(null, node);
295 for(child : node.files; child.type == folder/* || child.type == file*//* || child.type == folderOpen*/)
296 ListProjectNodeFolders(child, row);
300 Label lfindWhere { llfindWhere, this, size.w = 72, labeledWindow = findWhere };
303 llfindWhere, this, $"Find where:", altH, size.h = 24, anchor.right = 0;
304 typeExpected = directory, browseDialog = fileDialog;
306 DropBox findWherePrjNode
308 llfindWhere, this, $"Find where:", altH, size.h = 24, anchor.right = 0;
310 //collapseControl = true, treeBranches = true;
312 bool NotifySelect(DropBox control, DataRow row, Modifiers mods)
316 ProjectNode node = (ProjectNode)(intptr)row.tag;
317 delete lastSelectionProjectNode;
320 char filePath[MAX_LOCATION];
321 node.GetFullFilePath(filePath, true, true);
322 lastSelectionProjectNode = CopyString(filePath);
328 DataField projectNodeField { dataType = "ProjectNode", freeData = false };
330 Window spacerA { llsubDirs, this, size = { 72, 10 }, clickThrough = true, background = formColor, inactive = true };
333 llsubDirs, this, $"Include Subdirectories", altU, isCheckbox = true, checked = true;
336 Label lfilter { llfilter, this, size.w = 72, labeledWindow = filterDrop };
339 llfilter, this, $"Filter:", altL, anchor.right = 0;
341 bool NotifySelect(DropBox control, DataRow row, Modifiers mods)
343 fileFilter = (int)(row ? row.tag : 0);
349 Label lfileName { llfileName, this, size.w = 72, labeledWindow = fileName };
352 llfileName, this, $"File name:", altN, size.h = 24, anchor.right = 0;
355 //Window spacerX { ll, this, size = { 72, 10 }, clickThrough = true, background = formColor, inactive = true };
356 //Button nameWholeWord { ll, this, "Whole word only", AltO, isCheckbox = true };
357 //Window spacerX { llwholeWord, this, size = { 72, 10 }, clickThrough = true, background = formColor, inactive = true };
358 //Button nameMatchCase { ll, this, "Match case", altA, isCheckbox = true };
360 Label lfindContent { llfindWhat, this, size.w = 72, labeledWindow = findContent };
363 llfindWhat, this, $"Find what:", altT, size.h = 24, anchor.right = 0;
366 Label lreplaceWith { llreplaceWith, this, size.w = 72, labeledWindow = replaceWith };
369 llreplaceWith, this, $"Replace with:", altE;
370 size.h = 24, anchor.right = 0;
373 Window spacerB { llwholeWord, this, size = { 72, 10 }, clickThrough = true, background = formColor, inactive = true };
374 Button contentWholeWord { llwholeWord, this, $"Whole word only", altW, isCheckbox = true };
376 Window spacerC { llmatchCase, this, size = { 72, 10 }, clickThrough = true, background = formColor, inactive = true };
377 Button contentMatchCase { llmatchCase, this, $"Match case", altC, isCheckbox = true };
384 anchor.top = 0, anchor.bottom = 0;
388 LayoutLine llspace { lpbuttons, this, size.h = 2 };
389 LayoutLine llfind { lpbuttons, this, size.h = 30 };
390 LayoutLine llcancel { lpbuttons, this, size.h = 30 };
394 llfind, this, $"Find", altF, isDefault = true, size = { 80, 24 }, anchor.horz = 0, anchor.vert = 0, keyRepeat = true;
396 bool NotifyClicked(Button control, int x, int y, Modifiers mods)
398 const String findPath = findWhere.path;
399 if(findIn.currentRow == inDirectoryRow && !findPath[0])
401 findWhere.Activate();
402 MessageBox { type = ok, master = parent,
403 text = text, contents = $"You must specify a search location." }.Modal();
405 else if(findIn.currentRow == inDirectoryRow && !FileExists(findPath))
407 findWhere.Activate();
408 MessageBox { type = ok, master = parent,
409 text = text, contents = $"Search location does not exist. Please provide a valid location." }.Modal();
411 else if(!fileName.contents[0] && !findContent.contents[0])
413 findContent.Activate();
414 MessageBox { type = ok, master = parent,
415 text = text, contents = $"Nothing to be found. Please specify at least one criteria." }.Modal();
419 findContent.Activate();
429 llcancel, this, $"Cancel", hotKey = { escape }, size = { 80, 24 }, anchor.horz = 0, anchor.vert = 0;
431 bool NotifyClicked(Button control, int x, int y, Modifiers mods)
433 findContent.Activate();
439 SearchThread searchThread { findDialog = this };
440 FileDialog fileDialog { master = this, type = selectDir, text = $"Select Search Location..." };
445 inDirectoryRow = null;
446 inWorkspaceRow = null;
451 bool withWorkspace = ide.workspace != null;
454 inDirectoryRow = findIn.AddString($"Directory");
458 inWorkspaceRow = findIn.AddString($"Workspace");
459 for(prj : ide.workspace.projects)
461 if(lastSelectionProject)
463 for(row = findIn.firstRow; row; row = row.next)
465 char filePath[MAX_LOCATION];
466 Project p = (Project)(intptr)row.tag;
469 p.topNode.GetFullFilePath(filePath, true, true);
470 if(!fstrcmp(filePath, lastSelectionProject))
475 findIn.SelectRow(row);
477 delete lastSelectionProject;
479 if(!lastSelectionProject)
481 if(lastSelectionMode == project)
483 Project prj = ide.workspace.projects.firstIterator.data;
484 for(row = findIn.firstRow; row; row = row.next)
485 if((Project)(intptr)row.tag == prj)
488 findIn.SelectRow(row);
491 property::mode = lastSelectionMode;
496 findIn.SelectRow(inDirectoryRow);
499 findIn.disabled = !withWorkspace;
500 /*disabled = findIn.currentRow != inDirectoryRow;
502 findWhere.disabled = disabled;
503 subDirs.disabled = disabled;*/
505 findContent.Activate();
511 searchThread.active = true;
512 searchThread.project = null;
513 searchThread.projectNode = null;
514 searchThread.subDirs = subDirs.checked;
516 if(findIn.currentRow == inDirectoryRow)
518 searchThread.mode = directory;
519 strcpy(searchThread.dir, findWhere.path);
521 else if(findIn.currentRow == inWorkspaceRow)
523 searchThread.mode = workspace;
524 searchThread.subDirs = true;
528 searchThread.mode = project;
529 searchThread.project = (Project)(intptr)findIn.currentRow.tag;
530 searchThread.projectNode = (ProjectNode)(findWherePrjNode.currentRow ? (void *)(intptr)findWherePrjNode.currentRow.tag : null);
532 //searchThread.nameMatchCase = nameMatchCase.checked;
533 //searchThread.nameWholeWord = nameWholeWord.checked;
534 searchThread.contentMatchCase = contentMatchCase.checked;
535 searchThread.contentWholeWord = contentWholeWord.checked;
537 searchThread.filter = filters[fileFilter];
539 strcpy(searchThread.nameCriteria, fileName.contents);
540 strcpy(searchThread.contentCriteria, findContent.contents);
542 strcpy(searchThread.contentReplace, replaceWith.contents);
543 searchThread.replaceMode = replaceMode;
545 //cancel.text = "Stop";
547 ide.outputView.ShowClearSelectTab(find);
551 searchThread.Create();
556 if(searchThread.active)
558 searchThread.Abort();
566 if(searchThread.active)
568 searchThread.Abort();
569 searchThread.Abort();
578 void SearchComplete()
580 //cancel.text = $"Cancel";
588 bool NotifyCharsAddedDeletedNameContent(EditBox editBox, BufferLocation before, BufferLocation after, bool pasteOperation)
590 find.disabled = (strlen(fileName.contents) == 0 && strlen(findContent.contents) == 0);
594 bool OnKeyHit(Key key, unichar ch)
596 if(ch && !key.alt && !key.ctrl && !key.shift && (contentMatchCase.active || contentWholeWord.active))
598 findContent.Activate();
599 return findContent.OnKeyHit(key, ch);
605 static define stackSize = 1024;
607 class SearchThread : Thread
610 bool active, subDirs/*, nameMatchCase, nameWholeWord*/, contentMatchCase, contentWholeWord;
611 char dir[MAX_DIRECTORY], contentCriteria[1024], contentReplace[1024], nameCriteria[1024];
613 FindInFilesDialog findDialog;
614 FindInFilesMode mode;
616 ProjectNode projectNode;
629 bool abort, abortNow;
638 int HowManyDigits(int num)
652 int globalFindCount = 0, filesSearchedCount = 0, filesMatchedCount = 0, dirsMatchedCount = 0;
653 //double lastTime = GetTime();
654 FindInFilesMode mode = this.mode;
656 EditBox replaceEdit = null;
664 char containing[512];
666 const char * filterName;
667 if(!strcmp(filter.name, "All files"))
668 filterName = "files";
670 filterName = filter.name;
672 sprintf(substring, $" with file name matching \"%s\"", nameCriteria);
675 if(contentCriteria && contentCriteria[0])
676 sprintf(containing, $" containing \"%s\"", contentCriteria);
678 containing[0] = '\0';
679 if(substring[0] && containing[0])
683 if(mode == directory)
686 ide.outputView.findBox.Logf(
687 $"Searching \"%s\"%s for %s%s%s%s\n\n",
688 (s = CopySystemPath(dir)), subDirs ? $" and its sub directories" : "",
689 filterName, substring, and, containing);
692 else if(mode == workspace)
693 ide.outputView.findBox.Logf(
694 $"Searching workspace files for %s%s%s%s\n\n",
695 filterName, substring, and, containing);
696 else if(mode == project)
697 ide.outputView.findBox.Logf(
698 $"Searching project %s files for %s%s%s%s\n\n",
699 project.name, filterName, substring, and, containing);
705 replaceEdit = EditBox
707 multiLine = true,textHorzScroll = true,textVertScroll = true,
708 text = $"Replacing Editbox", size = Size { 640,480 }/*,maxLineSize = 65536*/
712 if(mode == directory)
714 SearchStackFrame * stack = new0 SearchStackFrame[stackSize];
716 strcpy(stack[0].path, dir);
717 stack[0].fileList = FileListing { dir, extensions = filter.extensions }; // there should be a sorted = true/false
719 for(frame = 0; frame >= 0 && frame < stackSize && !abort; )
721 if(stack[frame].fileList.Find())
726 char name[MAX_LOCATION];
727 GetLastDirectory(stack[frame].fileList.path, name);
728 if(SearchString(name, 0, nameCriteria, false, false) == null)
731 if(!stack[frame].fileList.stats.attribs.isDirectory)
733 bool relative = false;
734 char fileRelative[MAX_LOCATION];
735 if(filter.ValidateFileName(stack[frame].fileList.name))
737 MakePathRelative(stack[frame].fileList.path, dir, fileRelative);
740 filesSearchedCount++;
741 if(match && contentCriteria[0])
746 ide.outputView.findBox.Tellf(
747 $"Searching %s for %s", relative ? fileRelative : stack[frame].fileList.path, contentCriteria);
751 ret = SearchFileContentAndReplace(stack[frame].fileList.path, relative, fileRelative, replaceEdit);
753 ret = SearchFileContent(stack[frame].fileList.path, relative, fileRelative);
756 globalFindCount += ret;
760 else if(match && nameCriteria[0])
764 ide.outputView.findBox.Logf(
766 relative ? fileRelative : stack[frame].fileList.path);
773 bool relative = false;
774 char fileRelative[MAX_LOCATION];
775 MakePathRelative(stack[frame].fileList.path, dir, fileRelative);
778 if(match && nameCriteria[0])
781 ide.outputView.findBox.Logf(
783 relative ? fileRelative : stack[frame].fileList.path);
785 ide.outputView.findBox.Tellf(
786 $"Searching %s", relative ? fileRelative : stack[frame].fileList.path);
790 if(subDirs && stack[frame].fileList.stats.attribs.isDirectory && strcmp(stack[frame].fileList.name, ".git"))
792 int lastFrame = frame;
793 /*double thisTime = GetTime();
795 if(thisTime - lastTime > 0.25)
797 findDialog.SearchUpdateLabel(stack[lastFrame].fileList.path);
801 if(frame < stackSize-1)
804 strcpy(stack[frame].path, stack[lastFrame].fileList.path);
805 stack[frame].fileList = FileListing { stack[frame].path, extensions = stack[lastFrame].fileList.extensions };
810 for( ; frame >= 0 ; frame--)
811 stack[frame].fileList.Stop();
813 ide.outputView.findBox.Logf($"Error: aborting search!\n");
824 for( ; frame >= 0 ; frame--)
825 if(frame < stackSize)
826 stack[frame].fileList.Stop();
829 else if(mode == workspace || mode == project)
831 bool firstIteration = true;
832 Project prj = project;
833 ProjectNode * stack = new0 ProjectNode[stackSize];
834 Iterator<Project> it { ide.workspace.projects };
838 if(mode == workspace)
840 if(!it.Next()) break;
843 stack[1] = projectNode ? projectNode : prj.topNode;
845 for(frame = 1; frame && !abort && frame < stackSize-1;)
847 bool relative = true; // would be option
848 char fileRelative[MAX_LOCATION];
849 char filePath[MAX_LOCATION];
851 fileRelative[0] = '\0';
852 if(stack[frame].type == file || stack[frame].type == folder || stack[frame].type == folderOpen)
854 stack[frame].GetFullFilePath(filePath, true, true);
855 //MakePathRelative(filePath, prj.topNode.path, fileRelative);
856 MakePathRelative(filePath, prj.topNode.path, fileRelative);
858 switch(stack[frame].type)
861 if((subDirs || firstIteration) && stack[frame].files && stack[frame].files.count)
863 int lastFrame = frame;
865 stack[frame] = stack[lastFrame].files.first;
866 firstIteration = false;
871 if(relative && mode == workspace && prj != ide.project)
873 char special[MAX_LOCATION];
874 sprintf(special, "(%s)%s", prj.name, fileRelative);
875 strcpy(fileRelative, special);
877 if(filter.ValidateFileName(stack[frame].name))
879 filesSearchedCount++;
880 if(!nameCriteria[0] || SearchString(stack[frame].name, 0, nameCriteria, false, false) != null)
882 if(contentCriteria[0])
887 ide.outputView.findBox.Tellf(
888 $"Searching %s for \"%s\"", relative ? fileRelative : filePath,
893 ret = SearchFileContentAndReplace(filePath, relative, fileRelative, replaceEdit);
895 ret = SearchFileContent(filePath, relative, fileRelative);
898 globalFindCount += ret;
902 else if(nameCriteria[0])
906 ide.outputView.findBox.Logf(
907 "%s\n", relative ? fileRelative : filePath);
912 stack[frame] = stack[frame].next;
917 if(relative && mode == workspace && prj != ide.project)
919 char special[MAX_LOCATION];
920 sprintf(special, "(%s)%s", prj.name, fileRelative);
921 strcpy(fileRelative, special);
923 if(nameCriteria[0] && SearchString(stack[frame].name, 0, nameCriteria, false, false) != null)
927 ide.outputView.findBox.Logf(
928 "%s\n", relative ? fileRelative : filePath);
931 if((subDirs || firstIteration) && stack[frame].files && stack[frame].files.count)
933 int lastFrame = frame;
935 stack[frame] = stack[lastFrame].files.first;
936 firstIteration = false;
939 stack[frame] = stack[frame].next;
943 stack[frame] = stack[frame].next;
946 while(frame && !stack[frame])
949 if(frame == 1 && projectNode && stack[frame] == projectNode)
952 stack[frame] = stack[frame].next;
955 if(mode == project) break;
959 for( ; frame >= 0; frame--)
960 if(frame < stackSize)
970 if(filesSearchedCount)
972 if(!contentCriteria[0] && (filesMatchedCount || dirsMatchedCount))
973 ide.outputView.findBox.Logf("\n");
975 ide.outputView.findBox.Logf(
976 $"%s search %s a total of %d match%s in %d out of the %d file%s searched\n",
977 abort ? $"Aborted" : $"Completed", replaceMode ? $"replaced" : $"found", globalFindCount, (globalFindCount > 1) ? $"es" : "",
978 filesMatchedCount, filesSearchedCount, (filesSearchedCount > 1) ? $"s" : "");
979 else if(filesMatchedCount)
980 ide.outputView.findBox.Logf(
981 $"%s search found a total of %d match%s in the %d file%s searched\n",
982 abort ? $"Aborted" : $"Completed", filesMatchedCount, (filesMatchedCount > 1) ? $"es" : "",
983 filesSearchedCount, (filesSearchedCount > 1) ? $"s" : "");
985 ide.outputView.findBox.Logf(
986 $"%s search did not find any match in the %d files searched\n",
987 abort ? $"Aborted" : $"Completed", filesSearchedCount);
990 ide.outputView.findBox.Logf(
991 $"%s search did not find any file\n", abort ? $"Aborted" : $"Completed");
992 findDialog.SearchComplete();
997 int SearchFileContent(const char *filePath, bool relative, const char *fileRelative)
1000 File f = FileOpen(filePath, read);
1006 while(f.GetLine(line, 65536/* should there be a - 1 here? */) && !abortNow)
1011 int inLineFindCount = 0;
1013 while((find = SearchString(line, start, contentCriteria, contentMatchCase, contentWholeWord)) && !abortNow)
1016 col = find - &line[start] + 1;
1017 start += (find - &line[start]) / sizeof(char) + strlen(contentCriteria);
1020 if(inLineFindCount && !abortNow)
1024 int len = strlen(line);
1025 s1[6 - HowManyDigits(lineNum)] = '\0';
1026 s2[4 - HowManyDigits(col)] = '\0';
1027 // Cut the line longer than 1024 because Logf prints to a buffer (and we don't want to output crazy long lines either)
1036 ide.outputView.findBox.Logf(
1037 " %s:%d:%d%s%s> %s\n", relative ? fileRelative : filePath,
1038 lineNum, col, s1, s2, line);
1040 findCount += inLineFindCount;
1044 f.Seek(-strlen(contentCriteria), current);*/
1050 ide.outputView.findBox.Logf(
1051 $"Found %d match%s in \"%s\"%s\n\n", findCount, (findCount > 1) ? "es" : "",
1052 relative ? fileRelative : filePath, abortNow ? $" before search was aborted" : "");
1059 ide.outputView.findBox.Logf($"Unable to open file %s\n\n", filePath);
1065 int SearchFileContentAndReplace(const char *filePath, bool relative, const char *fileRelative, EditBox edit)
1067 int replaceCount = -1;
1068 File f = FileOpen(filePath, read);
1073 while(f.GetLine(line, 65536/* should there be a - 1 here? */) && !abortNow)
1076 if(SearchString(line, 0, contentCriteria, contentMatchCase, contentWholeWord) && !abortNow)
1078 int lastLineNum = 0;
1083 for(; edit.Find(contentCriteria, contentWholeWord, contentMatchCase, true) == found; replaceCount++)
1085 int lineNum = edit.lineNumber + 1;
1086 edit.PutS(contentReplace);
1087 if(lineNum != lastLineNum)
1093 //int len = strlen(line);
1094 s1[6 - HowManyDigits(lineNum)] = '\0';
1095 s2[4 - HowManyDigits(col)] = '\0';
1096 strncpy(line, edit.line.text, 1023);
1099 // Cut the line longer than 1024 because Logf prints
1100 // to a buffer (and we don't want to output crazy long lines either)
1108 ide.outputView.findBox.Logf(
1109 " %s:%d:%d%s%s> %s\n", relative ? fileRelative : filePath,
1110 lineNum, col, s1, s2, line);
1116 if((f = FileOpen(filePath, write)))
1118 edit.Save(f, false);
1127 f.Seek(-strlen(contentCriteria), current);*/
1134 ide.outputView.findBox.Logf(
1135 $"Replaced %d match%s in \"%s\"%s\n\n", replaceCount, (replaceCount > 1) ? $"es" : "",
1136 relative ? fileRelative : filePath, abortNow ? $" before search was aborted" : "");
1143 ide.outputView.findBox.Logf($"Unable to open file %s\n\n", filePath);
1146 return replaceCount;
1150 static struct SearchStackFrame
1153 char path[MAX_LOCATION];
1154 FileListing fileList;