/// <summary> /// Do a synchronous text search/replace /// Use RepleaceAsync to run a background thread /// </summary> /// <param name="configuration">Replace operation parameters</param> /// <returns>Search results before replacement</returns> public FRResults ReplaceSync(FRConfiguration configuration) { try { FRResults results = new FRResults(); List <String> files = configuration.GetFiles(); FRSearch search = configuration.GetSearch(); string replacement = configuration.Replacement; if (replacement == null) { return(results); } string src; List <SearchMatch> matches; foreach (String file in files) { src = configuration.GetSource(file); search.SourceFile = file; results[file] = matches = search.Matches(src); foreach (SearchMatch match in matches) { src = search.ReplaceAll(src, replacement, matches); configuration.SetSource(file, src); } matches = null; } return(results); } catch (Exception ex) { MessageBox.Show("Exception " + ex.Message + "\n" + ex.StackTrace); return(null); } }
private void FindFinished(FRResults results) { UserInterfaceManager.ProgressDialog.Show(); UserInterfaceManager.ProgressDialog.SetTitle(TextHelper.GetString("Info.UpdatingReferences")); MessageBar.Locked = true; bool isNotHaxe = !PluginBase.CurrentProject.Language.StartsWith("haxe"); bool packageIsNotEmpty = !string.IsNullOrEmpty(currentTarget.OldFileModel.Package); string targetName = Path.GetFileNameWithoutExtension(currentTarget.OldFilePath); string oldType = (currentTarget.OldFileModel.Package + "." + targetName).Trim('.'); string newType = (currentTarget.NewPackage + "." + targetName).Trim('.'); foreach (KeyValuePair <string, List <SearchMatch> > entry in results) { List <SearchMatch> matches = entry.Value; if (matches.Count == 0) { continue; } string path = entry.Key; UserInterfaceManager.ProgressDialog.UpdateStatusMessage(TextHelper.GetString("Info.Updating") + " \"" + path + "\""); ScintillaControl sci = AssociatedDocumentHelper.LoadDocument(path); if (isNotHaxe && path != currentTarget.NewFilePath && ASContext.Context.CurrentModel.Imports.Search(targetName, FlagType.Class & FlagType.Function & FlagType.Namespace, 0) == null) { ASGenerator.InsertImport(new MemberModel(targetName, newType, FlagType.Import, 0), false); } if (packageIsNotEmpty) { RefactoringHelper.ReplaceMatches(matches, sci, newType, null); } else { foreach (SearchMatch sm in matches) { if (sm.LineText.TrimStart().StartsWith("import")) { RefactoringHelper.SelectMatch(sci, sm); sci.ReplaceSel(newType); } } } foreach (SearchMatch match in matches) { match.LineText = sci.GetLine(match.Line - 1); match.Value = newType; } if (!Results.ContainsKey(path)) { Results[path] = new List <SearchMatch>(); } Results[path].AddRange(matches.ToArray()); PluginBase.MainForm.CurrentDocument.Save(); if (sci.IsModify) { AssociatedDocumentHelper.MarkDocumentToKeep(path); } } UserInterfaceManager.ProgressDialog.Hide(); MessageBar.Locked = false; UpdateReferencesNextTarget(); }
/// <summary> /// Populates the m_SearchResults with any found matches /// </summary> public static IDictionary<String, List<SearchMatch>> GetInitialResultsList(FRResults results) { IDictionary<String, List<SearchMatch>> searchResults = new Dictionary<String, List<SearchMatch>>(); if (results == null) { // I suppose this should never happen -- // normally invoked when the user cancels the FindInFiles dialogue. // but since we're programmatically invoking the FRSearch, I don't think this should happen. // TODO: report this? } else if (results.Count == 0) { // no search results found. Again, an interesting issue if this comes up. // we should at least find the source entry the user is trying to change. // TODO: report this? } else { // found some matches! // I current separate the search listing from the FRResults. It's probably unnecessary but this is just the initial implementation. // TODO: test if this is necessary foreach (KeyValuePair<String, List<SearchMatch>> entry in results) { searchResults.Add(entry.Key, new List<SearchMatch>()); foreach (SearchMatch match in entry.Value) { searchResults[entry.Key].Add(match); } } } return searchResults; }
/// <summary> /// Filters the initial result set by determining which entries actually resolve back to our declaration target. /// </summary> private IDictionary <String, List <SearchMatch> > ResolveActualMatches(FRResults results, ASResult target) { // this will hold actual references back to the source member (some result hits could point to different members with the same name) IDictionary <String, List <SearchMatch> > actualMatches = new Dictionary <String, List <SearchMatch> >(); IDictionary <String, List <SearchMatch> > initialResultsList = RefactoringHelper.GetInitialResultsList(results); int matchesChecked = 0; int totalMatches = 0; foreach (KeyValuePair <String, List <SearchMatch> > entry in initialResultsList) { totalMatches += entry.Value.Count; } Boolean foundDeclarationSource = false; bool optionsEnabled = IncludeComments || IncludeStrings; foreach (KeyValuePair <String, List <SearchMatch> > entry in initialResultsList) { String currentFileName = entry.Key; UserInterfaceManager.ProgressDialog.UpdateStatusMessage(TextHelper.GetString("Info.ResolvingReferencesIn") + " \"" + currentFileName + "\""); foreach (SearchMatch match in entry.Value) { // we have to open/reopen the entry's file // there are issues with evaluating the declaration targets with non-open, non-current files // we have to do it each time as the process of checking the declaration source can change the currently open file! ScintillaControl sci = this.AssociatedDocumentHelper.LoadDocument(currentFileName).SciControl; // if the search result does point to the member source, store it bool add = false; if (RefactoringHelper.DoesMatchPointToTarget(sci, match, target, this.AssociatedDocumentHelper)) { if (ignoreDeclarationSource && !foundDeclarationSource && RefactoringHelper.IsMatchTheTarget(sci, match, target)) { //ignore the declaration source foundDeclarationSource = true; } else { add = true; } } else if (optionsEnabled) { add = RefactoringHelper.IsInsideCommentOrString(match, sci, IncludeComments, IncludeStrings); } if (add) { if (!actualMatches.ContainsKey(currentFileName)) { actualMatches.Add(currentFileName, new List <SearchMatch>()); } actualMatches[currentFileName].Add(match); } matchesChecked++; UserInterfaceManager.ProgressDialog.UpdateProgress((100 * matchesChecked) / totalMatches); } } this.AssociatedDocumentHelper.CloseTemporarilyOpenedDocuments(); return(actualMatches); }
/// <summary> /// Invoked when the FRSearch completes its search /// </summary> private void FindFinished(FRResults results) { UserInterfaceManager.ProgressDialog.Reset(); UserInterfaceManager.ProgressDialog.UpdateStatusMessage(TextHelper.GetString("Info.ResolvingReferences")); // First filter out any results that don't actually point to our source declaration this.Results = ResolveActualMatches(results, currentTarget); if (this.outputResults) { this.ReportResults(); } UserInterfaceManager.ProgressDialog.Hide(); // Select first match if (this.Results.Count > 0) { foreach (var fileEntries in this.Results) { if (fileEntries.Value.Count > 0 && System.IO.File.Exists(fileEntries.Key)) { SearchMatch entry = fileEntries.Value[0]; PluginBase.MainForm.OpenEditableDocument(fileEntries.Key, false); RefactoringHelper.SelectMatch(PluginBase.MainForm.CurrentDocument.SciControl, entry); break; } } } this.FireOnRefactorComplete(); }
/// <summary> /// Filters the initial result set by determining which entries actually resolve back to our declaration target. /// </summary> private void GotoNextMatch(FRResults results, ASResult target) { IDictionary <String, List <SearchMatch> > initialResultsList = RefactoringHelpera.GetInitialResultsList(results); Boolean foundDeclarationSource = false; foreach (KeyValuePair <String, List <SearchMatch> > entry in initialResultsList) { String currentFileName = entry.Key; ScintillaControl sci = (ScintillaControl)this.AssociatedDocumentHelper.LoadDocument(currentFileName); if (back) { entry.Value.Reverse(); } foreach (SearchMatch match in entry.Value) { // if the search result does point to the member source, store it if (RefactoringHelpera.DoesMatchPointToTarget(sci, match, target, this.AssociatedDocumentHelper)) { if (ignoreDeclarationSource && !foundDeclarationSource && RefactoringHelpera.IsMatchTheTarget(sci, match, target)) { //ignore the declaration source foundDeclarationSource = true; } else { int ws = sci.PositionFromLine(match.Line - 1) + match.Column; if (!back) { if (ws > curEndPos) { sci.SelectionStart = ws; sci.SelectionEnd = ws + match.Length; sci.ScrollCaret(); return; } } else { if (ws < curStartPos) { sci.SelectionStart = ws; sci.SelectionEnd = ws + match.Length; sci.ScrollCaret(); return; } } } } } } Globals.SciControl.SelectionStart = spos; Globals.SciControl.SelectionEnd = epos; string str = Globals.SciControl.GetWordFromPosition(spos); MessageBox.Show(LocaleHelper.GetString("MESSAGE_NOT_FOUND") + str, "", MessageBoxButtons.OK, MessageBoxIcon.Exclamation); }
/// <summary> /// Handles the results when find is ready /// </summary> private void FindFinished(FRResults results) { this.SetupResultsView(true); this.resultsView.Items.Clear(); if (results == null) { String message = TextHelper.GetString("Info.FindLookupCanceled"); this.infoLabel.Text = message; } else if (results.Count == 0) { String message = TextHelper.GetString("Info.NoMatchesFound"); this.infoLabel.Text = message; } else { if (!this.redirectCheckBox.Checked) { Int32 fileCount = 0; Int32 matchCount = 0; foreach (KeyValuePair <String, List <SearchMatch> > entry in results) { fileCount++; foreach (SearchMatch match in entry.Value) { matchCount++; ListViewItem item = new ListViewItem(); item.Text = match.Line.ToString(); item.SubItems.Add(match.LineText.Trim()); item.SubItems.Add(Path.GetFileName(entry.Key)); item.SubItems.Add(Path.GetDirectoryName(entry.Key)); item.Tag = new KeyValuePair <String, SearchMatch>(entry.Key, match); this.resultsView.Items.Add(item); this.AddToGroup(item, entry.Key); } } String message = TextHelper.GetString("Info.FoundInFiles"); String formatted = String.Format(message, matchCount, fileCount); this.infoLabel.Text = formatted; } else { Globals.MainForm.CallCommand("PluginCommand", "ResultsPanel.ClearResults"); foreach (KeyValuePair <String, List <SearchMatch> > entry in results) { foreach (SearchMatch match in entry.Value) { Int32 column = match.Column; TraceManager.Add(entry.Key + ":" + match.Line.ToString() + ": characters " + match.Column + "-" + (match.Column + match.Length) + " : " + match.LineText.Trim(), (Int32)TraceType.Info); } } Globals.MainForm.CallCommand("PluginCommand", "ResultsPanel.ShowResults"); this.Hide(); } } this.UpdateUIState(false); }
/// <summary> /// Invoked when the FRSearch completes its search /// </summary> private void FindFinished(FRResults results) { UserInterfaceManager.ProgressDialog.Reset(); UserInterfaceManager.ProgressDialog.UpdateStatusMessage(TextHelper.GetString("Info.ResolvingReferences")); // First filter out any results that don't actually point to our source declaration this.Results = ResolveActualMatches(results, currentTarget); if (this.outputResults) { this.ReportResults(); } UserInterfaceManager.ProgressDialog.Hide(); this.FireOnRefactorComplete(); }
/// <summary> /// Do a synchronous search /// Use SearchAsync to run a background thread /// </summary> /// <param name="configuration">Search operation parameters</param> /// <returns>Search results</returns> public FRResults SearchSync(FRConfiguration configuration) { try { FRResults results = new FRResults(); List <String> files = configuration.GetFiles(); FRSearch search = configuration.GetSearch(); foreach (String file in files) { String src = configuration.GetSource(file); List <SearchMatch> matches = search.Matches(src); FRSearch.ExtractResultsLineText(matches, src); results[file] = matches; } return(results); } catch (Exception ex) { MessageBox.Show("Exception " + ex.Message + "\n" + ex.StackTrace); return(null); } }
private void FindFinished(FRResults results) { UserInterfaceManager.ProgressDialog.Show(); UserInterfaceManager.ProgressDialog.SetTitle(TextHelper.GetString("Info.UpdatingReferences")); MessageBar.Locked = true; var currentTarget = targets[currentTargetIndex]; string targetName = Path.GetFileNameWithoutExtension(currentTarget.OldFilePath); string oldType = (currentTarget.OldFileModel.Package + "." + targetName).Trim('.'); string newType = (currentTarget.NewPackage + "." + targetName).Trim('.'); foreach (KeyValuePair <string, List <SearchMatch> > entry in results) { List <SearchMatch> matches = entry.Value; if (matches.Count == 0 || entry.Key == currentTarget.OldFilePath || entry.Key == currentTarget.NewFilePath) { continue; } string file = entry.Key; UserInterfaceManager.ProgressDialog.UpdateStatusMessage(TextHelper.GetString("Info.Updating") + " \"" + file + "\""); ITabbedDocument doc; ScintillaControl sci; var actualMatches = new List <SearchMatch>(); foreach (SearchMatch match in entry.Value) { // we have to open/reopen the entry's file // there are issues with evaluating the declaration targets with non-open, non-current files // we have to do it each time as the process of checking the declaration source can change the currently open file! sci = AssociatedDocumentHelper.LoadDocument(file).SciControl; // if the search result does point to the member source, store it if (RefactoringHelper.DoesMatchPointToTarget(sci, match, currentTargetResult, this.AssociatedDocumentHelper)) { actualMatches.Add(match); } } if (actualMatches.Count == 0) { continue; } int currLine = -1; doc = AssociatedDocumentHelper.LoadDocument(file); sci = doc.SciControl; string directory = Path.GetDirectoryName(file); // Let's check if we need to add the import. Check the considerations at the start of the file // directory != currentTarget.OwnerPath -> renamed owner directory, so both files in the same place bool needsImport = directory != Path.GetDirectoryName(currentTarget.NewFilePath) && directory != currentTarget.OwnerPath && ASContext.Context.CurrentModel.Imports.Search(targetName, FlagType.Class & FlagType.Function & FlagType.Namespace, 0) == null; // Replace matches int typeDiff = sci.MBSafeTextLength(oldType) - sci.MBSafeTextLength(targetName); int newTypeDiff = sci.MBSafeTextLength(newType) - sci.MBSafeTextLength(oldType); int accumulatedDiff = 0; int j = 0; for (int i = 0, count = actualMatches.Count; i < count; i++) { var sm = actualMatches[j]; if (currLine == -1) { currLine = sm.Line - 1; } if (sm.LineText.Contains(oldType)) { sm.Index -= typeDiff - accumulatedDiff; sm.Value = oldType; RefactoringHelper.SelectMatch(sci, sm); sm.Column -= typeDiff; sci.ReplaceSel(newType); sm.LineEnd = sci.SelectionEnd; sm.LineText = sm.LineText.Replace(oldType, newType); sm.Length = oldType.Length; sm.Value = newType; if (needsImport) { sm.Line++; } accumulatedDiff += newTypeDiff; j++; } else { actualMatches.RemoveAt(j); } } if (needsImport) { sci.GotoLine(currLine); ASGenerator.InsertImport(new MemberModel(targetName, newType, FlagType.Import, 0), false); int newLine = sci.LineFromPosition(sci.Text.IndexOfOrdinal(newType)); var sm = new SearchMatch(); sm.Line = newLine + 1; sm.LineText = sci.GetLine(newLine); sm.Column = 0; sm.Length = sci.MBSafeTextLength(sm.LineText); sm.Value = sm.LineText; actualMatches.Insert(0, sm); } if (actualMatches.Count == 0) { continue; } if (!Results.ContainsKey(file)) { Results[file] = new List <SearchMatch>(); } Results[file].AddRange(actualMatches); //Do we want to open modified files? //if (sci.IsModify) AssociatedDocumentHelper.MarkDocumentToKeep(file); doc.Save(); } currentTargetIndex++; UserInterfaceManager.ProgressDialog.Hide(); MessageBar.Locked = false; UpdateReferencesNextTarget(); }
/// <summary> /// Invoked when the FRSearch completes its search /// </summary> private void FindFinished(FRResults results) { GotoNextMatch(results, currentTarget); this.FireOnRefactorComplete(); }
/// <summary> /// Populates the m_SearchResults with any found matches /// </summary> public static IDictionary <String, List <SearchMatch> > GetInitialResultsList(FRResults results) { IDictionary <String, List <SearchMatch> > searchResults = new Dictionary <String, List <SearchMatch> >(); if (results == null) { // I suppose this should never happen -- // normally invoked when the user cancels the FindInFiles dialogue. // but since we're programmatically invoking the FRSearch, I don't think this should happen. // TODO: report this? } else if (results.Count == 0) { // no search results found. Again, an interesting issue if this comes up. // we should at least find the source entry the user is trying to change. // TODO: report this? } else { // found some matches! // I current separate the search listing from the FRResults. It's probably unnecessary but this is just the initial implementation. // TODO: test if this is necessary foreach (KeyValuePair <String, List <SearchMatch> > entry in results) { searchResults.Add(entry.Key, new List <SearchMatch>()); foreach (SearchMatch match in entry.Value) { searchResults[entry.Key].Add(match); } } } return(searchResults); }
void OnHaxeCompleteResultHandler(HaxeComplete hc, List <HaxePositionResult> result, HaxeCompleteStatus status) { var results = new FRResults(); switch (status) { case HaxeCompleteStatus.ERROR: TraceManager.AddAsync(hc.Errors, -3); break; case HaxeCompleteStatus.USAGE: if (!IgnoreDeclarationSource) { var sci = ASContext.CurSciControl; var path = sci.FileName; if (!results.ContainsKey(path)) { results.Add(path, new List <SearchMatch>()); } var index = hc.Expr.PositionExpression; var line = sci.LineFromPosition(index); var lineStart = sci.PositionFromLine(line); var lineEnd = sci.LineEndPosition(line); var lineText = sci.GetLine(line); var value = hc.Expr.Value; results[path].Add(new SearchMatch { Column = index - lineStart, Index = index, Length = value.Length, Line = line + 1, LineStart = lineStart, LineEnd = lineEnd, LineText = lineText, Value = value }); } foreach (var it in result) { var path = it.Path; if (!results.ContainsKey(path)) { results.Add(path, new List <SearchMatch>()); } var matches = results[path]; var sci = AssociatedDocumentHelper.LoadDocument(path).SciControl; var line = it.LineStart - 1; var lineStart = sci.PositionFromLine(line); var lineEnd = sci.LineEndPosition(line); var lineText = sci.GetLine(line); var value = lineText.Substring(it.CharacterStart, it.CharacterEnd - it.CharacterStart); matches.Add(new SearchMatch { Column = it.CharacterStart, Index = lineStart + it.CharacterStart, Length = value.Length, Line = line + 1, LineStart = lineStart, LineEnd = lineEnd, LineText = lineText, Value = value }); } break; } FindFinished(results); }
private static void ReplaceFinished(FRResults results) { RenameClassFile(); }
/// <summary> /// Handles the results when replace is ready /// </summary> private void ReplaceFinished(FRResults results) { this.SetupResultsView(false); this.resultsView.Items.Clear(); if (results == null) { String message = TextHelper.GetString("Info.ReplaceLookupCanceled"); this.infoLabel.Text = message; } else if (results.Count == 0) { String message = TextHelper.GetString("Info.NoMatchesFound"); this.infoLabel.Text = message; } else { if (!this.redirectCheckBox.Checked) { Int32 fileCount = 0; Int32 matchCount = 0; foreach (KeyValuePair<String, List<SearchMatch>> entry in results) { fileCount++; Int32 replaceCount = 0; ListViewItem item = new ListViewItem(); foreach (SearchMatch match in entry.Value) { replaceCount++; matchCount++; } if (replaceCount == 0) continue; item.Tag = new KeyValuePair<String, SearchMatch>(entry.Key, null); item.Text = replaceCount.ToString(); item.SubItems.Add(Path.GetFileName(entry.Key)); item.SubItems.Add(Path.GetDirectoryName(entry.Key)); this.resultsView.Items.Add(item); this.AddToGroup(item, entry.Key); } String message = TextHelper.GetString("Info.ReplacedInFiles"); String formatted = String.Format(message, matchCount, fileCount); this.infoLabel.Text = formatted; } else { Globals.MainForm.CallCommand("PluginCommand", "ResultsPanel.ClearResults"); foreach (KeyValuePair<String, List<SearchMatch>> entry in results) { foreach (SearchMatch match in entry.Value) { TraceManager.Add(entry.Key + ":" + match.Line.ToString() + ": chars " + match.Column + "-" + (match.Column + match.Length) + " : " + match.Value, (Int32)TraceType.Info); } } Globals.MainForm.CallCommand("PluginCommand", "ResultsPanel.ShowResults"); this.Hide(); } } this.UpdateUIState(false); }
/// <summary> /// Background work main loop /// </summary> private void BackgroundWork(Object sender, DoWorkEventArgs e) { try { FRConfiguration configuration = e.Argument as FRConfiguration; if (configuration == null) { e.Result = null; return; } // get files Int32 count = 0; List <string> files = configuration.GetFiles(); if (files == null || files.Count == 0) { e.Result = new FRResults(); // empty results return; } FRResults results = new FRResults(); FRSearch search = configuration.GetSearch(); string replacement = configuration.Replacement; if (this.backgroundWorker.CancellationPending) { e.Cancel = true; } else { // do search Int32 total = files.Count; Int32 lastPercent = 0; List <SearchMatch> matches; string src; foreach (String file in files) { if (this.backgroundWorker.CancellationPending) { e.Cancel = true; } else { // work src = configuration.GetSource(file); search.SourceFile = file; results[file] = matches = search.Matches(src); if (matches.Count > 0) { if (replacement != null) { // replace text src = search.ReplaceAll(src, replacement, matches); configuration.SetSource(file, src); } else { FRSearch.ExtractResultsLineText(matches, src); } } matches = null; // progress count++; Int32 percent = (100 * count) / total; if (lastPercent != percent) { this.backgroundWorker.ReportProgress(percent); lastPercent = percent; } } } } e.Result = results; } catch (Exception ex) { MessageBox.Show("Exception during background operation:\n" + ex.Message + "\n" + ex.StackTrace); e.Result = null; } }