void SelectTreeViewNodes(DecompileTabState tabState, ILSpyTreeNode[] nodes) { if (!IsActiveTab(tabState)) return; // This isn't perfect, but let's assume the TE has focus if the treeview doesn't. // We should normally check for: // Keyboard.FocusedElement == tabState.TextView.TextEditor.TextArea // but a menu could be open in the text editor, and then the above expression fails. bool hasKeyboardFocus = !(Keyboard.FocusedElement is SharpTreeViewItem); var old = tabState.ignoreDecompilationRequests; try { tabState.ignoreDecompilationRequests = true; treeView.SelectedItems.Clear(); if (nodes.Length > 0) { treeView.FocusNode(nodes[0]); // This can happen when pressing Ctrl+Shift+Tab when the treeview has keyboard focus if (treeView.SelectedItems.Count != 0) treeView.SelectedItems.Clear(); treeView.SelectedItem = nodes[0]; // FocusNode() should already call ScrollIntoView() but for some reason, // the ScrollIntoView() does nothing so add another call. // Background priority won't work, we need ContextIdle prio this.Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(delegate { var item = treeView.SelectedItem as SharpTreeNode; if (item != null) treeView.ScrollIntoView(item); })); } foreach (var node in nodes) treeView.SelectedItems.Add(node); } finally { tabState.ignoreDecompilationRequests = old; } // The treeview stole the focus; get it back if (hasKeyboardFocus) DelaySetFocus(tabState); }
void RecordHistory(DecompileTabState tabState) { if (tabState == null) return; var dtState = tabState.TextView.GetState(tabState.DecompiledNodes); if (dtState != null) tabState.History.UpdateCurrent(new NavigationState(dtState, tabState.Language)); tabState.History.Record(new NavigationState(tabState.DecompiledNodes, tabState.Language)); }
void SaveCode(DecompileTabState tabState) { if (tabState == null) return; var textView = tabState.TextView; if (tabState.DecompiledNodes.Length == 1) { if (tabState.DecompiledNodes[0].Save(textView)) return; } textView.SaveToDisk(tabState.Language, tabState.DecompiledNodes, new DecompilationOptions() { FullDecompilation = true }); }
// Returns true if we could decompile the reference bool JumpToReferenceAsyncInternal(DecompileTabState tabState, bool canLoad, object reference, Func<bool, bool, bool> onDecompileFinished) { ILSpyTreeNode treeNode = FindTreeNode(reference); if (treeNode != null) { var nodes = new[] { treeNode }; DecompileNodes(tabState, nodes, false, onDecompileFinished); SelectTreeViewNodes(tabState, nodes); return true; } else if (reference is dnlib.DotNet.Emit.OpCode) { string link = "http://msdn.microsoft.com/library/system.reflection.emit.opcodes." + ((dnlib.DotNet.Emit.OpCode)reference).Code.ToString().ToLowerInvariant() + ".aspx"; try { Process.Start(link); } catch { } return true; } else if (canLoad && reference is IMemberDef) { // Here if the module was removed. It's possible that the user has re-added it. var member = (IMemberDef)reference; var module = member.Module; if (module == null) // Check if it has been deleted return false; var mainModule = module; if (module.Assembly != null) mainModule = module.Assembly.ManifestModule; if (!string.IsNullOrEmpty(mainModule.Location) && !string.IsNullOrEmpty(module.Location)) { // Check if the module was removed and then added again foreach (var m in assemblyList.GetAllModules()) { if (mainModule.Location.Equals(m.Location, StringComparison.OrdinalIgnoreCase)) { foreach (var asmMod in GetAssemblyModules(m)) { if (!module.Location.Equals(asmMod.Location, StringComparison.OrdinalIgnoreCase)) continue; // Found the module var modDef = asmMod as ModuleDefMD; if (modDef != null) { member = modDef.ResolveToken(member.MDToken) as IMemberDef; if (member != null) // should never fail return JumpToReferenceAsyncInternal(tabState, false, member, onDecompileFinished); } break; } return false; } } } // The module has been removed. Add it again var loadedAsm = new LoadedAssembly(assemblyList, mainModule); loadedAsm.IsAutoLoaded = true; assemblyList.AddAssembly(loadedAsm, true, false, false); return JumpToReferenceAsyncInternal(tabState, false, reference, onDecompileFinished); } else return false; }
void NavigateHistory(DecompileTabState tabState, bool forward) { var dtState = tabState.TextView.GetState(tabState.DecompiledNodes); if(dtState != null) tabState.History.UpdateCurrent(new NavigationState(dtState, tabState.Language)); var newState = forward ? tabState.History.GoForward() : tabState.History.GoBack(); var nodes = newState.TreeNodes.Cast<ILSpyTreeNode>().ToArray(); SelectTreeViewNodes(tabState, nodes); DecompileNodes(tabState, newState.ViewState, false, newState.Language, nodes); SetLanguage(newState.Language); }
static ITokenResolver GetResolver(out DecompileTabState tabState) { tabState = MainWindow.Instance.GetActiveDecompileTabState(); if (tabState == null) return null; return ILSpyTreeNode.GetModule(tabState.DecompiledNodes) as ITokenResolver; }
void ForceDecompile(DecompileTabState tabState) { DecompileRestoreLocation(tabState, tabState.DecompiledNodes, null, true); }
void DecompileNodes(DecompileTabState tabState, ILSpyTreeNode[] nodes, bool recordHistory, Language language, Func<bool, bool, bool> onDecompileFinished, bool forceDecompile = false) { var helper = new OnShowOutputHelper(tabState.TextView, onDecompileFinished, nodes); bool? decompiled = DecompileNodes(tabState, null, recordHistory, language, nodes, forceDecompile); if (decompiled == false) { helper.Abort(); onDecompileFinished(true, false); } }
bool? DecompileNodes(DecompileTabState tabState, DecompilerTextViewState state, bool recordHistory, Language language, ILSpyTreeNode[] nodes, bool forceDecompile = false) { if (tabState.ignoreDecompilationRequests) return null; // Ignore all nodes that have been deleted nodes = FilterOutDeletedNodes(nodes); if (tabState.HasDecompiled && !forceDecompile && tabState.Equals(nodes, language)) { if (state != null) tabState.TextView.EditorPositionState = state.EditorPositionState; return false; } if (tabState.HasDecompiled && recordHistory) RecordHistory(tabState); tabState.HasDecompiled = true; tabState.SetDecompileProps(language, nodes); if (nodes.Length == 1) { var node = nodes[0]; var viewObject = node.GetViewObject(tabState.TextView); if (viewObject != null) { tabState.TextView.CancelDecompileAsync(); tabState.Content = viewObject; return true; } if (node.View(tabState.TextView)) { tabState.Content = tabState.TextView; tabState.TextView.CancelDecompileAsync(); return true; } } tabState.Content = tabState.TextView; tabState.TextView.DecompileAsync(language, nodes, new DecompilationOptions() { TextViewState = state, DecompilerTextView = tabState.TextView }); return true; }
DecompileTabState CreateNewDecompileTabState(TabManager<TabState> tabManager, Language language = null) { var tabState = new DecompileTabState(language ?? sessionSettings.FilterSettings.Language); return (DecompileTabState)tabManager.AddNewTabState(tabState); }
void DecompileNodes(DecompileTabState tabState, ILSpyTreeNode[] nodes, bool recordHistory, Func<bool, bool, bool> onDecompileFinished) { DecompileNodes(tabState, nodes, recordHistory, tabState.Language, onDecompileFinished); }
DecompileTabState CreateDecompileTabState(DecompileTabState tabState, SavedDecompileTabState savedState, IList<ILSpyTreeNode> newNodes = null, bool decompile = true) { var nodes = new List<ILSpyTreeNode>(savedState.Paths.Count); if (newNodes != null) nodes.AddRange(newNodes); else { foreach (var asm in savedState.ActiveAutoLoadedAssemblies) this.assemblyList.OpenAssembly(asm, true); foreach (var path in savedState.Paths) { var node = assemblyListTreeNode.FindNodeByPath(path); if (node == null) { nodes = null; break; } nodes.Add(node); } } if (decompile) { if (nodes != null) { var tmpNodes = nodes.ToArray(); DecompileNodes(tabState, tmpNodes, false, (success, hasMovedCaret) => decompilerTextView_OnShowOutput(success, hasMovedCaret, tabState.TextView, savedState)); } else AboutPage.Display(tabState.TextView); } return tabState; }
bool BackCommand(DecompileTabState tabState) { if (tabState == null) return false; if (tabState.History.CanNavigateBack) { NavigateHistory(tabState, false); return true; } return false; }
static bool MustRefresh(DecompileTabState tabState, LoadedAssembly asm) { var asms = new HashSet<LoadedAssembly>(); asms.Add(asm); return DecompileCache.IsInModifiedAssembly(asms, tabState.DecompiledNodes) || DecompileCache.IsInModifiedAssembly(asms, tabState.TextView.References); }
static ModuleDefMD GetModule(out DecompileTabState tabState) { tabState = MainWindow.Instance.GetActiveDecompileTabState(); if (tabState == null) return null; return ILSpyTreeNode.GetModule(tabState.DecompiledNodes) as ModuleDefMD; }
void DecompileRestoreLocation(DecompileTabState tabState, ILSpyTreeNode[] nodes, Language language = null, bool forceDecompile = false) { var pos = tabState.TextView.GetRefPos(); DecompileNodes(tabState, nodes, false, language ?? tabState.Language, (a, b) => tabState.TextView.GoTo(pos), forceDecompile); }
static ModuleDefMD GetModule(ContextMenuEntryContext context, out DecompileTabState tabState) { tabState = null; if (context == null) return null; var textView = context.Element as DecompilerTextView; if (textView != null) { tabState = DecompileTabState.GetDecompileTabState(textView); if (tabState != null) return ILSpyTreeNode.GetModule(tabState.DecompiledNodes) as ModuleDefMD; } if (context.SelectedTreeNodes != null && context.SelectedTreeNodes.Length == 1) return ILSpyTreeNode.GetModule(context.SelectedTreeNodes[0]) as ModuleDefMD; return null; }
static bool MustRefresh(DecompileTabState tabState, DnSpyFile mod) { var asms = new HashSet<DnSpyFile>(); asms.Add(mod); return DecompileCache.IsInModifiedModule(asms, tabState.DecompiledNodes) || DecompileCache.IsInModifiedModule(asms, tabState.TextView.References); }