156 lines
6.0 KiB
C#
156 lines
6.0 KiB
C#
using System;
|
|
using System.ComponentModel.Composition;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows;
|
|
using System.Windows.Input;
|
|
using dnlib.DotNet;
|
|
using dnSpy.Contracts.Controls;
|
|
using dnSpy.Contracts.Documents.Tabs.DocViewer;
|
|
using dnSpy.Contracts.Extension;
|
|
using dnSpy.Contracts.Menus;
|
|
using Microsoft.VisualStudio.Text;
|
|
|
|
// Adds menu items to the text editor context menu
|
|
// If you have many similar commands, it's better to create a base class and derive from
|
|
// MenuItemBase<TContext> instead of MenuItemBase, see TreeViewCtxMenus.cs for an example.
|
|
|
|
namespace Example1.Extension {
|
|
static class Constants {
|
|
//TODO: Use your own guids
|
|
// The first number is the order of the group, and the guid is the guid of the group,
|
|
// see eg. dnSpy.Contracts.Menus.MenuConstants.GROUP_CTX_CODE_HEX etc
|
|
public const string GROUP_TEXTEDITOR = "20000,3567EC95-E68E-44CE-932C-98A686FDCACF";
|
|
public const string GROUP_TREEVIEW = "20000,77ACC18E-D8EB-483B-8D93-3581574B8891";
|
|
}
|
|
|
|
// This gets loaded by dnSpy and is used to add the Ctrl+Alt+Q command
|
|
[ExportAutoLoaded]
|
|
sealed class CommandLoader : IAutoLoaded {
|
|
static readonly RoutedCommand Option1Command = new RoutedCommand("Option1Command", typeof(CommandLoader));
|
|
|
|
[ImportingConstructor]
|
|
CommandLoader(IWpfCommandService wpfCommandService, MySettings mySettings) {
|
|
var cmds = wpfCommandService.GetCommands(ControlConstants.GUID_DOCUMENTVIEWER_UICONTEXT);
|
|
// This command will be added to all text editors
|
|
cmds.Add(Option1Command,
|
|
(s, e) => mySettings.BoolOption1 = !mySettings.BoolOption1,
|
|
(s, e) => e.CanExecute = true,
|
|
ModifierKeys.Control | ModifierKeys.Alt, Key.Q);
|
|
}
|
|
}
|
|
|
|
[ExportMenuItem(Header = "Option 1", InputGestureText = "Ctrl+Alt+Q", Group = Constants.GROUP_TEXTEDITOR, Order = 0)]
|
|
sealed class TextEditorCommand1 : MenuItemBase {
|
|
readonly MySettings mySettings;
|
|
|
|
[ImportingConstructor]
|
|
TextEditorCommand1(MySettings mySettings) => this.mySettings = mySettings;
|
|
|
|
public override bool IsChecked(IMenuItemContext context) => mySettings.BoolOption1;
|
|
public override void Execute(IMenuItemContext context) => mySettings.BoolOption1 = !mySettings.BoolOption1;
|
|
|
|
// Only show this in the document viewer
|
|
public override bool IsVisible(IMenuItemContext context) => context.CreatorObject.Guid == new Guid(MenuConstants.GUIDOBJ_DOCUMENTVIEWERCONTROL_GUID);
|
|
}
|
|
|
|
[ExportMenuItem(Header = "Option 2", Group = Constants.GROUP_TEXTEDITOR, Order = 10)]
|
|
sealed class TextEditorCommand2 : MenuItemBase {
|
|
readonly MySettings mySettings;
|
|
|
|
[ImportingConstructor]
|
|
TextEditorCommand2(MySettings mySettings) => this.mySettings = mySettings;
|
|
|
|
public override bool IsChecked(IMenuItemContext context) => mySettings.BoolOption2;
|
|
public override void Execute(IMenuItemContext context) => mySettings.BoolOption2 = !mySettings.BoolOption2;
|
|
|
|
// Only show this in the document viewer
|
|
public override bool IsVisible(IMenuItemContext context) => context.CreatorObject.Guid == new Guid(MenuConstants.GUIDOBJ_DOCUMENTVIEWERCONTROL_GUID);
|
|
}
|
|
|
|
[ExportMenuItem(Group = Constants.GROUP_TEXTEDITOR, Order = 20)]
|
|
sealed class TextEditorCommand3 : MenuItemBase {
|
|
public override void Execute(IMenuItemContext context) {
|
|
var md = GetTokenObj(context);
|
|
if (md is not null) {
|
|
try {
|
|
Clipboard.SetText($"{md.MDToken.Raw:X8}");
|
|
}
|
|
catch (ExternalException) { }
|
|
}
|
|
}
|
|
|
|
public override string? GetHeader(IMenuItemContext context) {
|
|
var md = GetTokenObj(context);
|
|
if (md is null)
|
|
return "Copy token";
|
|
return $"Copy token {md.MDToken.Raw:X8}";
|
|
}
|
|
|
|
IMDTokenProvider? GetTokenObj(IMenuItemContext context) {
|
|
// Only show this in the document viewer
|
|
if (context.CreatorObject.Guid != new Guid(MenuConstants.GUIDOBJ_DOCUMENTVIEWERCONTROL_GUID))
|
|
return null;
|
|
|
|
// All references in the text editor are stored in TextReferences
|
|
var textRef = context.Find<TextReference>();
|
|
if (textRef is null)
|
|
return null;
|
|
|
|
return textRef.Reference as IMDTokenProvider;
|
|
}
|
|
|
|
// Only show this in the document viewer
|
|
public override bool IsVisible(IMenuItemContext context) => context.CreatorObject.Guid == new Guid(MenuConstants.GUIDOBJ_DOCUMENTVIEWERCONTROL_GUID);
|
|
public override bool IsEnabled(IMenuItemContext context) => GetTokenObj(context) is not null;
|
|
}
|
|
|
|
[ExportMenuItem(Group = Constants.GROUP_TEXTEDITOR, Order = 30)]
|
|
sealed class TextEditorCommand4 : MenuItemBase {
|
|
public override void Execute(IMenuItemContext context) {
|
|
var documentViewer = GetDocumentViewer(context);
|
|
if (documentViewer is not null) {
|
|
try {
|
|
var lineColumn = GetLineColumn(documentViewer.Caret.Position.VirtualBufferPosition);
|
|
Clipboard.SetText($"Line,col: {lineColumn.Line + 1},{lineColumn.Column + 1}");
|
|
}
|
|
catch (ExternalException) { }
|
|
}
|
|
}
|
|
|
|
public override string? GetHeader(IMenuItemContext context) {
|
|
var documentViewer = GetDocumentViewer(context);
|
|
if (documentViewer is null)
|
|
return "Copy line and column";
|
|
var lineColumn = GetLineColumn(documentViewer.Caret.Position.VirtualBufferPosition);
|
|
return $"Copy line,col {lineColumn.Line + 1},{lineColumn.Column + 1}";
|
|
}
|
|
|
|
LineColumn GetLineColumn(VirtualSnapshotPoint point) {
|
|
var line = point.Position.GetContainingLine();
|
|
int column = point.Position - line.Start + point.VirtualSpaces;
|
|
return new LineColumn(line.LineNumber, column);
|
|
}
|
|
|
|
struct LineColumn {
|
|
public int Line { get; }
|
|
public int Column { get; }
|
|
public LineColumn(int line, int column) {
|
|
Line = line;
|
|
Column = column;
|
|
}
|
|
}
|
|
|
|
IDocumentViewer? GetDocumentViewer(IMenuItemContext context) {
|
|
// Only show this in the document viewer
|
|
if (context.CreatorObject.Guid != new Guid(MenuConstants.GUIDOBJ_DOCUMENTVIEWERCONTROL_GUID))
|
|
return null;
|
|
|
|
return context.Find<IDocumentViewer>();
|
|
}
|
|
|
|
// Only show this in the document viewer
|
|
public override bool IsVisible(IMenuItemContext context) => context.CreatorObject.Guid == new Guid(MenuConstants.GUIDOBJ_DOCUMENTVIEWERCONTROL_GUID);
|
|
public override bool IsEnabled(IMenuItemContext context) => GetDocumentViewer(context) is not null;
|
|
}
|
|
}
|