RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 841411
Accepted
Kir_Antipov
Kir_Antipov
Asked:2020-06-13 16:44:54 +0000 UTC2020-06-13 16:44:54 +0000 UTC 2020-06-13 16:44:54 +0000 UTC

构建 VS 扩展,按字符串长度排序

  • 772

同志们,问题如下:我习惯于在我的项目中排序using并且(不仅是)按字符串的长度排序。也就是说,这种代码:

using System.Collections.Generic;
using System;
using System.Linq;
using System.IO;

我一定会改成:

using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;

只有这样我才能冷静下来)

所以。我有点厌倦了手动执行此操作,所以我想问:是否有任何轻量级扩展(我怀疑ReSharper它可以,但我不考虑它)Visual Studio 2017可以按长度对所选行进行排序?

visual-studio-2017
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    Kir_Antipov
    2020-06-17T03:48:43Z2020-06-17T03:48:43Z

    实际上,没有人回答我,但我自己没有找到合适的扩展名。但是谁阻止我自己写呢?这就是我所做的。该扩展程序现在挂在Marketplace中,即此处。

    当然,我并没有开始强烈地将这一切正式化,因为我这样做只是为了我自己,但你永远不知道这样的小事会派上用场,并不是每个人都想安装令人印象深刻的扩展。

    好吧,让我们同时考虑一个为手头的任务创建这样一个简单扩展的示例。


    0) 首先,我们创建一个 VSIX 项目(Visual Studio 扩展可以用 Visual C++、Visual Basic、C# 编写。我用 C# 编写了这个案例)。如果此类项目的模板不在可用模板列表中,请使用 Visual Studio 安装程序安装相应的项目。


    1) 向项目中添加一个元素Custom Command并将其命名为“ CommandSort ”。
    在出现的类“ CommandSort.cs ”中添加以下代码:

    using System;
    using System.Linq;
    using Microsoft.VisualStudio.Shell;
    using System.ComponentModel.Design;
    
    namespace LineSorter
    {
        internal sealed class CommandSort
        {
            #region Var
            private AsyncPackage Package { get; }
            public int CommandId { get; } = 0x0100;
            public static CommandSort Instance { get; private set; }
            public static Guid CommandSet { get; } = new Guid("e9f69e2b-6313-4c2b-9765-1ddd6439d519");
            #endregion
    
            #region Init
            private CommandSort(AsyncPackage Package, OleMenuCommandService CommandService)
            {
                this.Package = Package ?? throw new ArgumentNullException(nameof(Package));
                CommandService = CommandService ?? throw new ArgumentNullException(nameof(CommandService));
                CommandID menuCommandID = new CommandID(CommandSet, CommandId);
                MenuCommand menuItem = new MenuCommand(Execute, menuCommandID);
                CommandService.AddCommand(menuItem);
            }
            public static async System.Threading.Tasks.Task InitializeAsync(AsyncPackage Package)
            {
                ThreadHelper.ThrowIfNotOnUIThread();
                Instance = new CommandSort(Package, await Package.GetServiceAsync((typeof(IMenuCommandService))) as OleMenuCommandService);
            }
            #endregion
    
            #region Functions
            private void Execute(object sender, EventArgs e)
            {
                ThreadHelper.ThrowIfNotOnUIThread();
                TextSelection.GetSelection(Package).OrderBy(x => x.Length).ThenBy(x => x).ReplaceSelection();
            }
            #endregion
        }
    }
    

    我们团队在项目中的初始化程序、ID 和 GUID 将由 VS 自动设置。其实我们只需要改变方法即可Execute。


    2) 为了更方便地使用选定的文本,让我们创建“ TextSelection ”类并将以下代码添加到“ TextSelection.cs ”:

    using EnvDTE;
    using System;
    using System.Linq;
    using System.Windows;
    using System.Collections.Generic;
    using Microsoft.VisualStudio.TextManager.Interop;
    
    namespace LineSorter
    {
        public static class TextSelection
        {
            #region Var
            public static IServiceProvider ServiceProvider { get; set; }
            #endregion
    
            #region Functions
            /// <summary>
            /// Получим выделенный текст и избавим его от пробелов и табуляции в начале/конце строк
            /// </summary>
            public static IEnumerable<string> GetSelection(IServiceProvider ServiceProvider)
            {
                TextSelection.ServiceProvider = ServiceProvider;
                IVsTextManager2 textManager = ServiceProvider.GetService(typeof(SVsTextManager)) as IVsTextManager2;
                int result = textManager.GetActiveView2(1, null, (uint)_VIEWFRAMETYPE.vftCodeWindow, out IVsTextView view);
                view.GetSelectedText(out string selectedText);
                return selectedText.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim(new char[] { ' ', '\t' }));
            }
    
            public static void ReplaceSelection(this IEnumerable<string> Selections)
            {
                ReplaceSelection(Selections, ServiceProvider);
            }
            /// <summary>
            /// Заменим выделенный текст на указанную коллекцию строк
            /// </summary>
            public static void ReplaceSelection(this IEnumerable<string> Selections, IServiceProvider ServiceProvider)
            {
                DTE dte = ServiceProvider?.GetService(typeof(DTE)) as DTE;
                if (dte is null) return;
                IDataObject obj = Clipboard.GetDataObject();
                Clipboard.SetText(string.Join("\r\n", Selections));
                dte.ExecuteCommand("Edit.Paste");
                Clipboard.SetDataObject(obj);
            }
            #endregion
        }
    }
    

    我认为代码的逻辑非常清楚。但是,我将重点介绍用新集合 ( ReplaceSelection) 替换所选文本的方法。最初的代码如下所示:

    DTE dte = ServiceProvider?.GetService(typeof(DTE)) as DTE;
    if (dte is null) return;
    EnvDTE.TextSelection selection = dte.ActiveDocument?.Selection as EnvDTE.TextSelection;
    if (selection is null) return;
    selection.Text = string.Join("\r\n", Selections);
    

    一切似乎都很合乎逻辑:只需将所选文本替换为新文本即可。在许多手册中,我只是看到了这种方法。但是,我警告不要使用这种处理选定文本的方法,因为它的工作速度非常慢。设置后,由于某种原因,该属性EnvDTE.TextSelection.Text会解析整个插入的文本,将其分解为语义单元。让我解释一下:例如,我们有 2 个这样using的 'a 需要排序:

    using Microsoft.VisualStudio.Shell.Interop;
    using Task = System.Threading.Tasks.Task;
    

    对于我们的算法,重要的是这些是2行。但是,指定的属性将整个事物分解为一个语义集:

    using, Microsoft, VisualStudio, Shell, Interop, using, Task, System, Threading, Tasks, Task
    

    而且我们不再有2行,而是11 个单独处理的元素。随着要排序的字符串数量的增加,处理的语义单元的数量急剧增加,因此使用这种方法的简单操作开始花费大量时间。
    这就是为什么我使用了一个小技巧:

    1. 我保存剪贴板的当前状态
    2. 之后,我将我们字符串的组合集合驱动到其中
    3. 现在我已经从 VS 本身运行插入函数(如Ctrl+ V)。所以文本会立即插入到选择的位置,然后由环境本身格式化
    4. 在这个动作之后,我将之前的状态返回到剪贴板

    老实说,我不知道这个解决方案有多好,但它肯定比标准方式快。如果有更正确实施的想法 - 我会很高兴听到!



    3)好吧。实际上,通过代码理解。它仍然清理配置(CommandSortPackage.vsct):

    <?xml version="1.0" encoding="utf-8"?>
    <CommandTable xmlns="http://schemas.microsoft.com/VisualStudio/2005-10-18/CommandTable" xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <Extern href="stdidcmd.h" />
      <Extern href="vsshlids.h" />
      <Commands package="guidCommandSortPackage">
        <Groups>
          <Group guid="guidCommandSortPackageCmdSet" id="MyMenuGroup" priority="0x0600">
            <!-- IDM_VS_CTXT_CODEWIN - контекстное меню VS -->
            <Parent guid="guidSHLMainMenu" id="IDM_VS_CTXT_CODEWIN" />
          </Group>
        </Groups>
        <Buttons>
          <Button guid="guidCommandSortPackageCmdSet" id="CommandSortId" priority="0x0100" type="Button">
            <Parent guid="guidCommandSortPackageCmdSet" id="MyMenuGroup" />
            <Icon guid="guidImages" id="bmpPicArrows" />
            <Strings>
              <ButtonText>Сортировать линии</ButtonText>
            </Strings>
          </Button>
        </Buttons>
        <Bitmaps>
          <Bitmap guid="guidImages" href="Resources\CommandSort.png" usedList="bmpPic1, bmpPic2, bmpPicSearch, bmpPicX, bmpPicArrows, bmpPicStrikethrough" />
        </Bitmaps>
      </Commands>
    
      <!-- Устанавливаем shortcut для нашей команды -->
      <KeyBindings>
        <KeyBinding guid="guidCommandSortPackageCmdSet" id="CommandSortId" editor="guidVSStd97" mod1="Control" mod2="Control" key1="E" key2="L" />
      </KeyBindings>
    
      <Symbols>
        <GuidSymbol name="guidCommandSortPackage" value="{7fb18e2a-1a51-4dbb-b676-a3514e44823d}" />
        <GuidSymbol name="guidCommandSortPackageCmdSet" value="{e9f69e2b-6313-4c2b-9765-1ddd6439d519}">
          <IDSymbol name="MyMenuGroup" value="0x1020" />
          <!-- Обратите внимание, что value равно значению, которое указано у нас в CommandSort.cs! -->
          <IDSymbol name="CommandSortId" value="0x0100" />
        </GuidSymbol>
        <GuidSymbol name="guidImages" value="{f2b4c3e0-a959-40c0-be9d-315e5ca1615c}">
          <IDSymbol name="bmpPic1" value="1" />
          <IDSymbol name="bmpPic2" value="2" />
          <IDSymbol name="bmpPicSearch" value="3" />
          <IDSymbol name="bmpPicX" value="4" />
          <IDSymbol name="bmpPicArrows" value="5" />
          <IDSymbol name="bmpPicStrikethrough" value="6" />
        </GuidSymbol>
      </Symbols>
    </CommandTable>
    

    因此,我们添加了一个带有指定文本的按钮,并在 VS上下文菜单中引用我们的操作,并将热键与之关联: ( Ctrl+ E) + ( Ctrl+ L)


    4) 就是这样,我们的简单扩展已经准备就绪。您可以使用 VS 的实验版本对其进行调试,或者直接构建它,之后在许多软件包中您会发现令人垂涎的带有 *.vsix 扩展名的文件,您可以使用它立即在您的工作室中安装该扩展,或者甚至发布它)


    关于这一点 - 仅此而已)感谢您的关注)

    • 7

相关问题

  • .Net 核心依赖项

  • 如何将数据库形式的源传递给reportViewer1.LocalReport.DataSources?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    是否可以在 C++ 中继承类 <---> 结构?

    • 2 个回答
  • Marko Smith

    这种神经网络架构适合文本分类吗?

    • 1 个回答
  • Marko Smith

    为什么分配的工作方式不同?

    • 3 个回答
  • Marko Smith

    控制台中的光标坐标

    • 1 个回答
  • Marko Smith

    如何在 C++ 中删除类的实例?

    • 4 个回答
  • Marko Smith

    点是否属于线段的问题

    • 2 个回答
  • Marko Smith

    json结构错误

    • 1 个回答
  • Marko Smith

    ServiceWorker 中的“获取”事件

    • 1 个回答
  • Marko Smith

    c ++控制台应用程序exe文件[重复]

    • 1 个回答
  • Marko Smith

    按多列从sql表中选择

    • 1 个回答
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Suvitruf - Andrei Apanasik 什么是空? 2020-08-21 01:48:09 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5