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);
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);
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);
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 SearchStackFrame stack[stackSize];
655 FindInFilesMode mode = this.mode;
657 EditBox replaceEdit = null;
665 char containing[512];
667 const char * filterName;
668 if(!strcmp(filter.name, "All files"))
669 filterName = "files";
671 filterName = filter.name;
673 sprintf(substring, $" with file name matching \"%s\"", nameCriteria);
676 if(contentCriteria && contentCriteria[0])
677 sprintf(containing, $" containing \"%s\"", contentCriteria);
679 containing[0] = '\0';
680 if(substring[0] && containing[0])
684 if(mode == directory)
687 ide.outputView.findBox.Logf(
688 $"Searching \"%s\"%s for %s%s%s%s\n\n",
689 (s = CopySystemPath(dir)), subDirs ? $" and its sub directories" : "",
690 filterName, substring, and, containing);
693 else if(mode == workspace)
694 ide.outputView.findBox.Logf(
695 $"Searching workspace files for %s%s%s%s\n\n",
696 filterName, substring, and, containing);
697 else if(mode == project)
698 ide.outputView.findBox.Logf(
699 $"Searching project %s files for %s%s%s%s\n\n",
700 project.name, filterName, substring, and, containing);
706 replaceEdit = EditBox
708 multiLine = true,textHorzScroll = true,textVertScroll = true,
709 text = $"Replacing Editbox", size = Size { 640,480 }/*,maxLineSize = 65536*/
713 if(mode == directory)
715 strcpy(stack[0].path, dir);
716 stack[0].fileList = FileListing { dir, extensions = filter.extensions }; // there should be a sorted = true/false
718 for(frame = 0; frame >= 0 && frame < stackSize && !abort; )
720 if(stack[frame].fileList.Find())
725 char name[MAX_LOCATION];
726 GetLastDirectory(stack[frame].fileList.path, name);
727 if(SearchString(name, 0, nameCriteria, false, false) == null)
730 if(!stack[frame].fileList.stats.attribs.isDirectory)
732 bool relative = false;
733 char fileRelative[MAX_LOCATION];
734 if(filter.ValidateFileName(stack[frame].fileList.name))
736 MakePathRelative(stack[frame].fileList.path, dir, fileRelative);
739 filesSearchedCount++;
740 if(match && contentCriteria[0])
745 ide.outputView.findBox.Tellf(
746 $"Searching %s for %s", relative ? fileRelative : stack[frame].fileList.path, contentCriteria);
750 ret = SearchFileContentAndReplace(stack[frame].fileList.path, relative, fileRelative, replaceEdit);
752 ret = SearchFileContent(stack[frame].fileList.path, relative, fileRelative);
755 globalFindCount += ret;
759 else if(match && nameCriteria[0])
763 ide.outputView.findBox.Logf(
765 relative ? fileRelative : stack[frame].fileList.path);
772 bool relative = false;
773 char fileRelative[MAX_LOCATION];
774 MakePathRelative(stack[frame].fileList.path, dir, fileRelative);
777 if(match && nameCriteria[0])
780 ide.outputView.findBox.Logf(
782 relative ? fileRelative : stack[frame].fileList.path);
784 ide.outputView.findBox.Tellf(
785 $"Searching %s", relative ? fileRelative : stack[frame].fileList.path);
789 if(subDirs && stack[frame].fileList.stats.attribs.isDirectory && strcmp(stack[frame].fileList.name, ".git"))
791 int lastFrame = frame;
792 /*double thisTime = GetTime();
794 if(thisTime - lastTime > 0.25)
796 findDialog.SearchUpdateLabel(stack[lastFrame].fileList.path);
800 if(frame < stackSize-1)
803 strcpy(stack[frame].path, stack[lastFrame].fileList.path);
804 stack[frame].fileList = FileListing { stack[frame].path, extensions = stack[lastFrame].fileList.extensions };
809 for( ; frame >= 0 ; frame--)
810 stack[frame].fileList.Stop();
812 ide.outputView.findBox.Logf($"Error: aborting search!\n");
823 for( ; frame >= 0 ; frame--)
824 stack[frame].fileList.Stop();
826 else if(mode == workspace || mode == project)
828 bool firtIteration = true;
829 Project prj = project;
830 ProjectNode stack[1024];
831 Iterator<Project> it { ide.workspace.projects };
835 if(mode == workspace)
837 if(!it.Next()) break;
840 stack[1] = projectNode ? projectNode : prj.topNode;
842 for(frame = 1; frame && !abort;)
844 switch(stack[frame].type)
847 if((subDirs || firtIteration) && stack[frame].files && stack[frame].files.count)
849 int lastFrame = frame;
851 stack[frame] = stack[lastFrame].files.first;
852 firtIteration = false;
857 bool relative = true;
858 char fileRelative[MAX_LOCATION];
859 char filePath[MAX_LOCATION];
861 PathCat(filePath, prj.topNode.path);
862 PathCat(filePath, stack[frame].path);
863 PathCat(filePath, stack[frame].name);
864 fileRelative[0] = '\0';
865 PathCat(fileRelative, stack[frame].path);
866 PathCat(fileRelative, stack[frame].name);
867 if(relative && mode == workspace && prj != ide.project)
869 char special[MAX_LOCATION];
870 sprintf(special, "(%s)%s", prj.name, fileRelative);
871 strcpy(fileRelative, special);
873 if(filter.ValidateFileName(stack[frame].name))
875 filesSearchedCount++;
876 if(!nameCriteria[0] || SearchString(stack[frame].name, 0, nameCriteria, false, false) != null)
878 if(contentCriteria[0])
883 ide.outputView.findBox.Tellf(
884 $"Searching %s for \"%s\"", relative ? fileRelative : filePath,
889 ret = SearchFileContentAndReplace(filePath, relative, fileRelative, replaceEdit);
891 ret = SearchFileContent(filePath, relative, fileRelative);
894 globalFindCount += ret;
898 else if(nameCriteria[0])
902 ide.outputView.findBox.Logf(
903 "%s\n", relative ? fileRelative : filePath);
908 stack[frame] = stack[frame].next;
913 bool relative = true;
914 char fileRelative[MAX_LOCATION];
915 char filePath[MAX_LOCATION];
917 PathCat(filePath, prj.topNode.path);
918 PathCat(filePath, stack[frame].path);
919 fileRelative[0] = '\0';
920 PathCat(fileRelative, stack[frame].path);
921 if(relative && mode == workspace && prj != ide.project)
923 char special[MAX_LOCATION];
924 sprintf(special, "(%s)%s", prj.name, fileRelative);
925 strcpy(fileRelative, special);
927 if(nameCriteria[0] && SearchString(stack[frame].name, 0, nameCriteria, false, false) != null)
931 ide.outputView.findBox.Logf(
932 "%s\n", relative ? fileRelative : filePath);
935 if((subDirs || firtIteration) && stack[frame].files && stack[frame].files.count)
937 int lastFrame = frame;
939 stack[frame] = stack[lastFrame].files.first;
940 firtIteration = false;
943 stack[frame] = stack[frame].next;
947 stack[frame] = stack[frame].next;
950 while(frame && !stack[frame])
953 if(frame == 1 && projectNode && stack[frame] == projectNode)
956 stack[frame] = stack[frame].next;
959 if(mode == project) break;
963 for( ; frame ; frame--)
972 if(filesSearchedCount)
974 if(!contentCriteria[0] && (filesMatchedCount || dirsMatchedCount))
975 ide.outputView.findBox.Logf("\n");
977 ide.outputView.findBox.Logf(
978 $"%s search %s a total of %d match%s in %d out of the %d file%s searched\n",
979 abort ? $"Aborted" : $"Completed", replaceMode ? $"replaced" : $"found", globalFindCount, (globalFindCount > 1) ? $"es" : "",
980 filesMatchedCount, filesSearchedCount, (filesSearchedCount > 1) ? $"s" : "");
981 else if(filesMatchedCount)
982 ide.outputView.findBox.Logf(
983 $"%s search found a total of %d match%s in the %d file%s searched\n",
984 abort ? $"Aborted" : $"Completed", filesMatchedCount, (filesMatchedCount > 1) ? $"es" : "",
985 filesSearchedCount, (filesSearchedCount > 1) ? $"s" : "");
987 ide.outputView.findBox.Logf(
988 $"%s search did not find any match in the %d files searched\n",
989 abort ? $"Aborted" : $"Completed", filesSearchedCount);
992 ide.outputView.findBox.Logf(
993 $"%s search did not find any file\n", abort ? $"Aborted" : $"Completed");
994 findDialog.SearchComplete();
999 int SearchFileContent(const char *filePath, bool relative, const char *fileRelative)
1002 File f = FileOpen(filePath, read);
1008 while(f.GetLine(line, 65536/* should there be a - 1 here? */) && !abortNow)
1013 int inLineFindCount = 0;
1015 while((find = SearchString(line, start, contentCriteria, contentMatchCase, contentWholeWord)) && !abortNow)
1018 col = find - &line[start] + 1;
1019 start += (find - &line[start]) / sizeof(char) + strlen(contentCriteria);
1022 if(inLineFindCount && !abortNow)
1026 int len = strlen(line);
1027 s1[6 - HowManyDigits(lineNum)] = '\0';
1028 s2[4 - HowManyDigits(col)] = '\0';
1029 // Cut the line longer than 1024 because Logf prints to a buffer (and we don't want to output crazy long lines either)
1038 ide.outputView.findBox.Logf(
1039 " %s:%d:%d%s%s> %s\n", relative ? fileRelative : filePath,
1040 lineNum, col, s1, s2, line);
1042 findCount += inLineFindCount;
1046 f.Seek(-strlen(contentCriteria), current);*/
1052 ide.outputView.findBox.Logf(
1053 $"Found %d match%s in \"%s\"%s\n\n", findCount, (findCount > 1) ? "es" : "",
1054 relative ? fileRelative : filePath, abortNow ? $" before search was aborted" : "");
1061 ide.outputView.findBox.Logf($"Unable to open file %s\n\n", filePath);
1067 int SearchFileContentAndReplace(const char *filePath, bool relative, const char *fileRelative, EditBox edit)
1069 int replaceCount = -1;
1070 File f = FileOpen(filePath, read);
1075 while(f.GetLine(line, 65536/* should there be a - 1 here? */) && !abortNow)
1078 if(SearchString(line, 0, contentCriteria, contentMatchCase, contentWholeWord) && !abortNow)
1080 int lastLineNum = 0;
1085 for(; edit.Find(contentCriteria, contentWholeWord, contentMatchCase, true) == found; replaceCount++)
1087 int lineNum = edit.lineNumber + 1;
1088 edit.PutS(contentReplace);
1089 if(lineNum != lastLineNum)
1095 //int len = strlen(line);
1096 s1[6 - HowManyDigits(lineNum)] = '\0';
1097 s2[4 - HowManyDigits(col)] = '\0';
1098 strncpy(line, edit.line.text, 1023);
1101 // Cut the line longer than 1024 because Logf prints
1102 // to a buffer (and we don't want to output crazy long lines either)
1110 ide.outputView.findBox.Logf(
1111 " %s:%d:%d%s%s> %s\n", relative ? fileRelative : filePath,
1112 lineNum, col, s1, s2, line);
1118 if((f = FileOpen(filePath, write)))
1120 edit.Save(f, false);
1129 f.Seek(-strlen(contentCriteria), current);*/
1136 ide.outputView.findBox.Logf(
1137 $"Replaced %d match%s in \"%s\"%s\n\n", replaceCount, (replaceCount > 1) ? $"es" : "",
1138 relative ? fileRelative : filePath, abortNow ? $" before search was aborted" : "");
1145 ide.outputView.findBox.Logf($"Unable to open file %s\n\n", filePath);
1148 return replaceCount;
1152 static struct SearchStackFrame
1155 char path[MAX_LOCATION];
1156 FileListing fileList;