internal void RaiseParseInformationUpdated(ParseInformationEventArgs e) { // RaiseParseInformationUpdated is called inside a lock, but we don't want to raise the event inside that lock. // To ensure events are raised in the same order, we always invoke on the main thread. SD.MainThread.InvokeAsyncAndForget(delegate { if (!LoadSolutionProjectsThread.IsRunning) { string addition; if (e.OldUnresolvedFile == null) { addition = " (new)"; } else if (e.NewUnresolvedFile == null) { addition = " (removed)"; } else { addition = " (updated)"; } LoggingService.Debug("ParseInformationUpdated " + e.FileName + addition); } ParseInformationUpdated(null, e); }); }
public void RegisterUnresolvedFile(IProject project, IUnresolvedFile unresolvedFile) { if (project == null) { throw new ArgumentNullException("project"); } if (unresolvedFile == null) { throw new ArgumentNullException("unresolvedFile"); } FreezableHelper.Freeze(unresolvedFile); var newParseInfo = new ParseInformation(unresolvedFile, null, false); rwLock.EnterWriteLock(); try { int index = FindIndexForProject(project); if (index >= 0) { currentVersion = null; var args = new ParseInformationEventArgs(project, entries[index].UnresolvedFile, newParseInfo); entries[index] = new ProjectEntry(project, unresolvedFile, null); project.OnParseInformationUpdated(args); parserService.RaiseParseInformationUpdated(args); } } finally { rwLock.ExitWriteLock(); } }
async void UpdateTick(ParseInformationEventArgs e) { bool isActive = ctl.IsVisible && !SD.ParserService.LoadSolutionProjectsThread.IsRunning; timer.IsEnabled = isActive; if (!isActive) return; LoggingService.Debug("DefinitionViewPad.Update"); ResolveResult res = await ResolveAtCaretAsync(e); if (res == null) return; var pos = res.GetDefinitionRegion(); if (pos.IsEmpty) return; // TODO : try to decompile? OpenFile(pos); }
internal void RaiseParseInformationUpdated(ParseInformationEventArgs e) { // RaiseParseInformationUpdated is called inside a lock, but we don't want to raise the event inside that lock. // To ensure events are raised in the same order, we always invoke on the main thread. SD.MainThread.InvokeAsyncAndForget(delegate { if (!LoadSolutionProjectsThread.IsRunning) { string addition; if (e.OldUnresolvedFile == null) { addition = " (new)"; } else if (e.NewUnresolvedFile == null) { addition = " (removed)"; } else { addition = " (updated)"; } LoggingService.Debug("ParseInformationUpdated " + e.FileName + addition); } ParseInformationUpdated(null, e); }); }
public void RegisterUnresolvedFile(IProject project, IUnresolvedFile unresolvedFile) { if (project == null) throw new ArgumentNullException("project"); if (unresolvedFile == null) throw new ArgumentNullException("unresolvedFile"); FreezableHelper.Freeze(unresolvedFile); var newParseInfo = new ParseInformation(unresolvedFile, null, false); lock (this) { int index = FindIndexForProject(project); if (index >= 0) { currentVersion = null; var args = new ParseInformationEventArgs(project, entries[index].UnresolvedFile, newParseInfo); entries[index] = new ProjectEntry(project, unresolvedFile, null); project.OnParseInformationUpdated(args); parserService.RaiseParseInformationUpdated(args); } } }
ProjectEntry DoParse(ITextSource fileContent, IProject parentProject, bool fullParseInformationRequested, CancellationToken cancellationToken) { if (parser == null) return default(ProjectEntry); if (fileContent == null) { // No file content was specified. Because the callers of this method already check for currently open files, // we can assume that the file isn't open and simply read it from disk. try { fileContent = SD.FileService.GetFileContentFromDisk(fileName, cancellationToken); } catch (IOException) { // It is possible that the file gets deleted/becomes inaccessible while a background parse // operation is enqueued, so we have to handle IO exceptions. return default(ProjectEntry); } catch (UnauthorizedAccessException) { return default(ProjectEntry); } } ProjectEntry result; lock (this) { int index = FindIndexForProject(parentProject); int versionComparison = CompareVersions(fileContent.Version); if (versionComparison > 0 || index < 0) { // We're going backwards in time, or are requesting a project that is not an owner // for this entry. var parseInfo = ParseWithExceptionHandling(fileContent, fullParseInformationRequested, parentProject, cancellationToken); FreezableHelper.Freeze(parseInfo.UnresolvedFile); return new ProjectEntry(parentProject, parseInfo.UnresolvedFile, parseInfo); } else { if (versionComparison == 0 && index >= 0) { // Ensure we have parse info for the specified project (entry.UnresolvedFile is null for newly registered projects) // If full parse info is requested, ensure we have full parse info. if (entries[index].UnresolvedFile != null && !(fullParseInformationRequested && entries[index].CachedParseInformation == null)) { // We already have the requested version parsed, just return it: return entries[index]; } } } ParseInformationEventArgs[] results = new ParseInformationEventArgs[entries.Count]; for (int i = 0; i < entries.Count; i++) { var parseInfo = ParseWithExceptionHandling(fileContent, fullParseInformationRequested, entries[i].Project, cancellationToken); if (parseInfo == null) throw new NullReferenceException(parser.GetType().Name + ".Parse() returned null"); if (fullParseInformationRequested && !parseInfo.IsFullParseInformation) throw new InvalidOperationException(parser.GetType().Name + ".Parse() did not return full parse info as requested."); OnDiskTextSourceVersion onDiskVersion = fileContent.Version as OnDiskTextSourceVersion; if (onDiskVersion != null) parseInfo.UnresolvedFile.LastWriteTime = onDiskVersion.LastWriteTime; FreezableHelper.Freeze(parseInfo.UnresolvedFile); results[i] = new ParseInformationEventArgs(entries[i].Project, entries[i].UnresolvedFile, parseInfo); } // Only if all parse runs succeeded, register the parse information. currentVersion = fileContent.Version; for (int i = 0; i < entries.Count; i++) { if (fullParseInformationRequested || (entries[i].CachedParseInformation != null && results[i].NewParseInformation.IsFullParseInformation)) entries[i] = new ProjectEntry(entries[i].Project, results[i].NewUnresolvedFile, results[i].NewParseInformation); else entries[i] = new ProjectEntry(entries[i].Project, results[i].NewUnresolvedFile, null); if (entries[i].Project != null) entries[i].Project.OnParseInformationUpdated(results[i]); parserService.RaiseParseInformationUpdated(results[i]); } result = entries[index]; } // exit lock parserService.RegisterForCacheExpiry(this); return result; }
Task<ResolveResult> ResolveAtCaretAsync(ParseInformationEventArgs e) { IWorkbenchWindow window = SD.Workbench.ActiveWorkbenchWindow; if (window == null) return Task.FromResult<ResolveResult>(null); IViewContent viewContent = window.ActiveViewContent; if (viewContent == null) return Task.FromResult<ResolveResult>(null); ITextEditor editor = viewContent.GetService<ITextEditor>(); if (editor == null) return Task.FromResult<ResolveResult>(null); // e might be null when this is a manually triggered update // don't resolve when an unrelated file was changed if (e != null && editor.FileName != e.FileName) return Task.FromResult<ResolveResult>(null); return SD.ParserService.ResolveAsync(editor.FileName, editor.Caret.Location, editor.Document); }
void OnParserUpdateStep(object sender, ParseInformationEventArgs e) { UpdateTick(e); }
ProjectEntry DoParse(ITextSource fileContent, IProject parentProject, bool fullParseInformationRequested, CancellationToken cancellationToken) { if (parser == null) { return(default(ProjectEntry)); } if (fileContent == null) { // No file content was specified. Because the callers of this method already check for currently open files, // we can assume that the file isn't open and simply read it from disk. try { fileContent = SD.FileService.GetFileContentFromDisk(fileName, cancellationToken); } catch (IOException) { // It is possible that the file gets deleted/becomes inaccessible while a background parse // operation is enqueued, so we have to handle IO exceptions. return(default(ProjectEntry)); } catch (UnauthorizedAccessException) { return(default(ProjectEntry)); } } ProjectEntry result; rwLock.EnterUpgradeableReadLock(); try { int index = FindIndexForProject(parentProject); int versionComparison = CompareVersions(fileContent.Version); if (versionComparison > 0 || index < 0) { // We're going backwards in time, or are requesting a project that is not an owner // for this entry. var parseInfo = ParseWithExceptionHandling(fileContent, fullParseInformationRequested, parentProject, cancellationToken); FreezableHelper.Freeze(parseInfo.UnresolvedFile); return(new ProjectEntry(parentProject, parseInfo.UnresolvedFile, parseInfo)); } else { if (versionComparison == 0 && index >= 0) { // Ensure we have parse info for the specified project (entry.UnresolvedFile is null for newly registered projects) // If full parse info is requested, ensure we have full parse info. if (entries[index].UnresolvedFile != null && !(fullParseInformationRequested && entries[index].CachedParseInformation == null)) { // We already have the requested version parsed, just return it: return(entries[index]); } } } ParseInformationEventArgs[] results = new ParseInformationEventArgs[entries.Count]; for (int i = 0; i < entries.Count; i++) { var parseInfo = ParseWithExceptionHandling(fileContent, fullParseInformationRequested, entries[i].Project, cancellationToken); if (parseInfo == null) { throw new NullReferenceException(parser.GetType().Name + ".Parse() returned null"); } if (fullParseInformationRequested && !parseInfo.IsFullParseInformation) { throw new InvalidOperationException(parser.GetType().Name + ".Parse() did not return full parse info as requested."); } OnDiskTextSourceVersion onDiskVersion = fileContent.Version as OnDiskTextSourceVersion; if (onDiskVersion != null) { parseInfo.UnresolvedFile.LastWriteTime = onDiskVersion.LastWriteTime; } FreezableHelper.Freeze(parseInfo.UnresolvedFile); results[i] = new ParseInformationEventArgs(entries[i].Project, entries[i].UnresolvedFile, parseInfo); } // Only if all parse runs succeeded, register the parse information. rwLock.EnterWriteLock(); try { currentVersion = fileContent.Version; for (int i = 0; i < entries.Count; i++) { if (fullParseInformationRequested || (entries[i].CachedParseInformation != null && results[i].NewParseInformation.IsFullParseInformation)) { entries[i] = new ProjectEntry(entries[i].Project, results[i].NewUnresolvedFile, results[i].NewParseInformation); } else { entries[i] = new ProjectEntry(entries[i].Project, results[i].NewUnresolvedFile, null); } if (entries[i].Project != null) { entries[i].Project.OnParseInformationUpdated(results[i]); } parserService.RaiseParseInformationUpdated(results[i]); } result = entries[index]; } finally { rwLock.ExitWriteLock(); } } finally { rwLock.ExitUpgradeableReadLock(); } parserService.RegisterForCacheExpiry(this); return(result); }
public override void OnParseInformationUpdated(ParseInformationEventArgs args) { var c = projectContentContainer; if (c != null) c.ParseInformationUpdated(args.OldUnresolvedFile, args.NewUnresolvedFile); // OnParseInformationUpdated is called inside a lock, but we don't want to raise the event inside that lock. // To ensure events are raised in the same order, we always invoke on the main thread. SD.MainThread.InvokeAsyncAndForget(delegate { ParseInformationUpdated(null, args); }); }