将 Visual Studio 的代码片段导出到 VS Code
導(dǎo)語
和原文作者一樣,水弟我現(xiàn)在也是使用 VS Code 和 Rider 作為主力開發(fā)工具,尤其是 VS Code 可以跨平臺,又有豐富的插件支持和多種編程語言支持。當我從 VS 轉(zhuǎn)移到以 VS Code 的開發(fā)過程中,遇到的最大問題就是代碼提示的不完善(被 VS 和 R# 調(diào)教壞了,總想按 tab 鍵)。當我看到原文作者通過從 VS 中導(dǎo)出代碼片段到 VS Code 時,瞬間被吸引到了。 雖然在不知不覺中用了 VS 自帶的代碼片段,但我從來沒有想過要自定義專屬的代碼片段,最多也是制作用于項目的模板(方便創(chuàng)建特定的類型文件)。雖然導(dǎo)出到 Rider 不是很完美,但 Rider 自帶了 R#,對這方面的需求還是很少的。
譯文:
Visual Studio 內(nèi)置了非常好用的代碼片段工具,多年來我一直在使用它來創(chuàng)建大量有用的擴展片段,使我的日常開發(fā)更容易。我有很多 C# 代碼片段,但更多的是用于 HTML 、自定義的 Bootstrap 代碼片段,乃至復(fù)雜的 HTML 控件代碼段。偶爾也會用到 JavaScript 、XAML 甚至Powershell 。
在過去的幾年里,我越來越多地使用其他工具與 Visual Studio 結(jié)合使用。特別是Visual Studio Code和JetBrains Rider。
在多年的使用 Visual Studio 中,我已經(jīng)累積了 130 多個代碼片段。每當我在其他開發(fā)環(huán)境中工作時 ( VS Code 或者 Rider),我真的很需要他們,特別是要寫一大段 HTML的時候,總是要去痛苦地去對應(yīng)的文檔站點查找。使用代碼片段功能,只需幾次擊鍵就會自動填充我自定義的特定代碼,每天可節(jié)省大量時間。
所以我很需要代碼片段功能,有時我打開 Visual Studio 只是為了找到需要的 HTML 的代碼片段,然后將它們粘貼回 VS Code 或 Rider。雖然繁瑣,但是仍然從文檔網(wǎng)站中復(fù)制代碼,然后手動修改代碼來得便捷。如果能在每個對應(yīng)的開發(fā)環(huán)境中直接執(zhí)行代碼片段的功能,那就太好了!
因此,在過去的幾個周末,我做了一個將 Visual Studio 中的代碼片段導(dǎo)出到 VS Code 中的小工具,同時盡量能導(dǎo)出到 JetBrains Rider 。
如果你感興趣,可以在GitHub上找到代碼:
GitHub上的VisualStudioSnippetConverter
另外說一句,這還只是一個菜鳥項目,并不能保證它支持所有類型的的代碼片段。只是我自己擁有的 137 個代碼片段都完美地移植到 VS Code,并且能夠運行。同時我還可以重新導(dǎo)出, 輕松地導(dǎo)出新創(chuàng)建的代碼片段,這樣就可以對比和更新了。
對于 Rider 而言,操作起來更為復(fù)雜,因為 Rider 有一種瘋狂的機制,可以將模板存儲在內(nèi)部的單個配置文件中。它還為 .NET相關(guān)的片段 (C#、VB、F#、Razor、ASP.NET )和 基于 Web ( html、css、js 等)的代碼片段使用了多個完全不同的存儲引擎。所以工具目前僅支持一次性導(dǎo)出 .NET 相關(guān)代碼段,因為 Rider 中基于 GUID 的密鑰系統(tǒng)不允許在沒有 GUID 的情況下查找現(xiàn)有代碼段。后面我們再詳細介紹。
代碼片段轉(zhuǎn)換器
你可以通過借助 .NET 全局工具 (.NET Global SDK Tool ),使用 Nuget 下載和運行代碼片段轉(zhuǎn)換器:
dotnet tool install --global dotnet-snippetconverter如果您不想安裝并只運行該工具,您可以克隆或下載Github倉庫,然后:
cd .\SnippetConverter\ dotnet run安裝后, 可以通過指向文件夾或單個文件將 Visual Studio 中的代碼片段批量或單獨轉(zhuǎn)換為 VS Code 支持的代碼片段。
snippetconverter ~2017 -r -d或者,您可以像下面這張屏幕截圖那樣指定輸出文件:
有幾個選項可用于轉(zhuǎn)換單個片段和文件夾,使用前綴,遞歸文件夾,輸出生成文件的路徑等:
Syntax:-------SnippetConverter <sourceFileOrDirectory> -o <outputFile> --mode --prefix --recurse --displayCommands:---------HELP || /? ? ? ? ? ?This help display ? ? ? ? ? Options:--------sourceFileOrDirectory ?Either an individual snippet file, or a source folderOptional special start syntax using `~` to point at User Code Snippets folder:~ ? ? ?- ?Visual Studio User Code Snippets folder (latest version installed)~2017 ?- ?Visual Studio User Code Snippets folder (specific VS version 2019-2012) ? ? ? ? ? ? ? ? ? ? ? -o <outputFile> ? ? ? ?Output file where VS Code snippets are generated into (ignored by Rider) ? Optional special start syntax using `~` to point at User Code Snippets folder:%APPDATA%\Code\User\snippets\ww-my-codesnippets.code-snippets~\ww-my-codesnippets.code-snippets ? ? ? ? ? ? ? ? ? ? ? if omitted generates `~\exported-visualstudio.code-snippets`-m,--mode ? ? ? ? ? ? ?vs-vscode ?(default)vs-rider ? experimental - (C#,VB.NET,html only) -d ? ? ? ? ? ? ? ? ? ? display the target file in Explorer -r ? ? ? ? ? ? ? ? ? ? if specifying a source folder recurses into child folders -p,--prefix ? ? ? ? ? ?snippet prefix generate for all snippets exportedExample: `ww-` on a snippet called `ifempty` produces `ww-ifempty`Examples:---------# vs-vscode: Individual Visual Studio Snippet SnippetConverter "~2017\Visual C#\My Code Snippets\proIPC.snippet" -o "~\ww-csharp.code-snippets" -d# vs-vscode: All snippets in a folder user VS Snippets and in recursive child folers SnippetConverter "~2017\Visual C#\My Code Snippets" -o "~\ww-csharp.code-snippets" -r -d# vs-vscode: All the user VS Snippets and in recursive child folders SnippetConverter ~2017\ -o "~\ww-all.code-snippets" -r -d# vs-vscode: All defaults: Latest version of VS, all snippets export to ?~\visualstudio-export.code-snippets SnippetConverter ~ -r -d --prefix ww-# vs-rider: Individual VS Snippet SnippetConverter "~2017\proIPC.snippet" -m vs-rider -d# vs-rider: All VS Snippets in a folder SnippetConverter "~2017\Visual C#\My Code Snippets" -m vs-rider -d上面的用例應(yīng)該足夠說明用途了。如果還想要了解更多信息,請接著往下看......
什么是 VS Code 的代碼片段
如果您不熟悉或不使用代碼片段,那您并不是少數(shù)人。它們在 Visual Studio 中幾乎是一個隱藏的功能,這是一個恥辱,因為它們是非常有用的生產(chǎn)力工具。不幸的是,Visual Studio 沒有任何有用的內(nèi)置UI來創(chuàng)建這些片段,因此大多數(shù)開發(fā)人員都沒有充分利用此功能。Visual Studio 只能蹩腳地點擊 ** 工具 - > 代碼片段管理器 ** 菜單 ,除了一個查看器之外,它沒有其他管理功能,僅僅是查看哪些片段是可用的,沒有內(nèi)置的方法來創(chuàng)建或編輯片段,甚至跳轉(zhuǎn)到并查看代碼片段。
但是,代碼片段僅僅只是位于用戶目錄的 Documents 文件夾下的 XML 文件。它們非常容易創(chuàng)建和更新,僅僅是原始的 XML 文件,用 VS Code 等文本編輯器去做代碼片段和高亮實在是非常簡單。盡管在 Visual Studio 中有一些提供 UI 操作的劣質(zhì)插件,但它們往往比原始的代碼片段文件更麻煩。
創(chuàng)建新代碼段的最佳方法是復(fù)制現(xiàn)有代碼段并對其進行修改以滿足您的需求。
一般來說,代碼片段位于 (水弟我是直接用 Everything搜索的):
<Documents>\Visual Studio 2017\Code Snippets每種語言技術(shù)都有自己的子文件夾進行分組,但僅僅是文件夾上的區(qū)分而已。代碼片段實際上通過 XML中的?Language?屬性確定它們適用的語言。
Visual Studio在此位置附帶了許多代碼段,您可以使用這些代碼段作為新代碼段的模板進行學習。
xml version="1.0" encoding="utf-8"<CodeSnippets xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet"><CodeSnippet Format="1.0.0"><Header><Title>Property with INotifyPropertyChange raised</Title><Description>Control Property with Attributes</Description><SnippetTypes><SnippetType>Expansion</SnippetType></SnippetTypes><Shortcut>proIPC</Shortcut></Header><Snippet><References /><Imports /><Declarations><Literal Editable="true"><ID>name</ID><Type></Type><ToolTip>Property Name</ToolTip><Default>MyProperty</Default><Function></Function></Literal> ? ? ? ?<Literal Editable="true"><ID>type</ID><Type></Type><ToolTip>Property Type</ToolTip><Default>string</Default><Function></Function></Literal></Declarations><Code Language="csharp" Kind="method decl" Delimiter="$"><![CDATA[public $type$ $name$ {get { return _$name$; }set{if (value == _$name$) return;_$name$ = value;OnPropertyChanged(nameof($name$));} } ? ? ? ? private $type$ _$name$; ]]></Code></Snippet></CodeSnippet></CodeSnippets>一旦文件存在或更新了,Visual Studio 無需重啟,就能立即發(fā)現(xiàn)并使用。在相關(guān)的 (如 C#) 編輯器中,立馬就能看到智能提示中的代碼段:
它插入對應(yīng)的模板并允許您編輯在模板中聲明的?$expr$?占位符:
這個 C# 代碼片段示例, 是 VS 中最常見的語言。如您所見, XML文件中的?<Code>?節(jié)點定義模板文本,Shortcut?節(jié)點定義觸發(fā)提示的按鍵,你可以使用在?<Declaration>?節(jié)點中使用類似?$txt$?占位符來定義參數(shù),同樣的占位符在多個地方出現(xiàn)也能同步更改。
對于我來說,最有用和最常用的代碼片段時用于插入 HTML 代碼,特別是在定義 Bootstrap 結(jié)構(gòu)或其他很難記住語法的自定義控件。我喜歡在瀏覽文檔網(wǎng)站后創(chuàng)建一個對應(yīng)的片段,這樣就很方便使用。用多幾次,省下來的時間就賺翻了。花費幾分鐘設(shè)置模板可以節(jié)省大量時間去輸入重復(fù)代碼,尤其是您每次都要浪費時間查找相同的 Bootstrap 代碼時。?
前綴以及代碼片段包
Visual Studio Marketplace中還有許多可用的代碼片段,您可以安裝使用一整套預(yù)設(shè)的代碼片段。例如,Bootstrap Snippet 包就內(nèi)置了一堆以?bs-?為前綴的代碼片段。
即使您自己有專屬的代碼片段,最好為您的代碼片段創(chuàng)建一個前綴,以便您可以在智能提示的海洋中輕松地找到它們。我一般使用?ww-?作為大多數(shù)代碼片段的前綴。不幸的是,我自己沒有很好得遵循這個建議,還是有不少代碼片段沒有這么做。
構(gòu)建轉(zhuǎn)換器
因為我在 Visual Studio 大量使用了代碼片段,所以我做了一個將 Visual Studio 中的代碼片段遷移到 VS Code 中的小工具,同時盡量能遷移到 JetBrains Rider 。
我想可能還有其他人需要用到,所以我把它作為 .NET Global Tool 控制臺應(yīng)用程序發(fā)布,以便快速安裝:
dotnet tool install dotnet-snippetconverter您需要.NET Core 2.1 SDK或更高版本才能運行它。
以下示例命令將代碼片段從 Visual Studio 遷移到 VS Code,稍后再討論遷移到 Rider 的事
安裝后,您可以使用以下命令快速將所有 Visual Studio 代碼片段轉(zhuǎn)換為 VS Code 可以接受的格式。
snippetconverter ~ -r -d這將轉(zhuǎn)換最新安裝的 Visual Studio 版本(2017,2019等)中的所有代碼片段,并在位于%appdata%\Code\User\snippets?路徑的 VS Code 的代碼文件夾中創(chuàng)建單獨的?visualstudio-exported.code-snippets?文件夾。
您還可以導(dǎo)出特定 VS 版本的代碼片段:
snippetconverter ~2017 -r -d或特定文件夾:
snippetconverter "~2017\Visual C#\My Code Snippets" -r -d -o "~\ww-csharp.code-snippets"其中輸入和輸出文件夾選項中的路徑都是可選的,示例中的~?是物理片段路徑的占位符,會指向 Visual Studio(%Documents%\Visual Studio <year>\Code Snippets)和 VS Code(%appdata%\Code\User\Snippets\)中存放代碼片段的基本位置,因此您不必每次都指定完整路徑。您高興的話,也可以使用合格的全路徑。
最后,您還可以導(dǎo)出單個文件:
snippetconverter "~2017\Visual C#\My Code Snippets\proIPC.snippet" -d -o "~\ww-csharp.code-snippets"如果 VS Code 中已存在該代碼片段,則會覆蓋更新,所以每次重新運行都會更新對應(yīng)的代碼片段。
運行遷移工具后,在VS Code 中通過前綴或者快捷方式就可以立即使用:
在 Visual Studio 中多個占位符輸入也是支持的:
同步代碼片段
目前只支持從Visual Studio?單向?遷移到到 VS Code。這意味著如果要保持 Visual Studio 和 VS Code 之間的代碼段同步,最好是在 Visual Studio 中創(chuàng)建代碼片段,然后通過此工具將它們遷移到 VS Code。
VS Code 中的代碼片段
我之前討論過 Visual Studio Snippets 的代碼片段格式,現(xiàn)在讓我們看看 VS Code 中又是什么樣的。
存放在?%AppData\Code\User\snippets
使用 JSON 格式化
命名為?lang.json
或者是?<name>.code-snippet?的命名格式
可以包含一個或者多個代碼片段
轉(zhuǎn)換器之所以導(dǎo)出為?.code-snippet?文件格式,是因為使用?lang.json?很容易造成命名沖突。如果默認的?visualstudio-export.code-snippets?不能使用,則使用?-o?來指定輸出文件。
VS Code 代碼片段文件是 JSON,它們看起來像:
{ ?"proipc": { ? ?"prefix": "proipc", ? ?"scope": "csharp", ? ?"body": [ ? ? ?"public ${2:string} ${1:MyProperty}", ? ? ?"{", ? ? ?" ? ?get { return _${1:MyProperty}; }", ? ? ?" ? ?set", ? ? ?" ? ?{", ? ? ?" ? ? ? ?if (value == _${1:MyProperty}) return;", ? ? ?" ? ? ? ?_${1:MyProperty} = value;", ? ? ?" ? ? ? ?OnPropertyChanged(nameof(${1:MyProperty}));", ? ? ?" ? ?}", ? ? ?"} ? ? ? ?", ? ? ?"private ${2:string} _${1:MyProperty};", ? ? ?""], ? ?"description": "Control Property with Attributes"}, ?"commandbase-object-declaration": { ? ?"prefix": "commandbase", ? ?"scope": "csharp", ? ?"body": [ ? ? ?" ? ? ? ?public CommandBase ${1:CommandName}Command { get; set; ?}", ? ? ?"", ? ? ?" ? ? ? ?void Command_${1:CommandName}()", ? ? ?" ? ? ? ?{", ? ? ?" ? ? ? ? ? ?${1:CommandName}Command = new CommandBase((parameter, command) =>", ? ? ?" ? ? ? ? ? ?{", ? ? ?" ? ? ? ? ? ? ?$0", ? ? ?" ? ? ? ? ? ?}, (p, c) => true);", ? ? ?" ? ? ? ?}", ? ? ?""], ? ?"description": "Create a CommandBase implementation and declaration"} }VS Code 的代碼模板在概念上更簡單,只有模板,前綴和范圍,以及使用字符串插值和約定來確定如何定義占位符。當然還有其他字段可以填充,但大多數(shù)值是可選的,對于從 Visual Studio 轉(zhuǎn)換過來的代碼片段用不到。
您可以在此處找到Visual Studio代碼段模板文檔:
VS Code 代碼段模板文檔
但是實際上,自己手動創(chuàng)建模板,定義 JSON中的?body?屬性還是有難度的,因為字符串可能只是一個字符串數(shù)組(yuk),也可能是一個可以輸入的類型。好在只是從 Visual Studio 代碼片段轉(zhuǎn)換,還是很容易生成對應(yīng)的模板...
咦?導(dǎo)出到 Rider
轉(zhuǎn)換器某種程度上可以適配到 Rider,但功能有限。因為Rider 使用令人抓狂的模式來存儲代碼片段,使用 GUID 來標識的 XML 文件。
%USERPROFILE%\.Rider2018.2\config\resharper-host\GlobalSettingsStorage.DotSettings讓我們看看幾個導(dǎo)出的模板效果:
<root><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Reformat/@EntryValue">True</s:Boolean><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Shortcut/@EntryValue">proipc</s:String><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/ShortenQualifiedReferences/@EntryValue">True</s:Boolean><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Scope/=C3001E7C0DA78E4487072B7E050D86C5/@KeyIndexDefined">True</s:Boolean><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Scope/=C3001E7C0DA78E4487072B7E050D86C5/Type/@EntryValue">InCSharpFile</s:String><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Text/@EntryValue">public $type$ $name$ {get { return _$name$; }set{if (value == _$name$) return;_$name$ = value;OnPropertyChanged(nameof($name$));} } ? ? ? ? private $type$ _$name$; ? ?</s:String><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Field/=name/@KeyIndexDefined">True</s:Boolean><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Field/=name/Expression/@EntryValue">complete()</s:String><s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Field/=name/Order/@EntryValue">0</s:Int64><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Field/=type/@KeyIndexDefined">True</s:Boolean><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Field/=type/Expression/@EntryValue">complete()</s:String><s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=720E28E0ECFD4CA0B80F10DC82149BD4/Field/=type/Order/@EntryValue">1</s:Int64><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/@KeyIndexDefined">True</s:Boolean><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Applicability/=Live/@EntryIndexedValue">True</s:Boolean><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Reformat/@EntryValue">True</s:Boolean><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Shortcut/@EntryValue">seterror</s:String><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/ShortenQualifiedReferences/@EntryValue">True</s:Boolean><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Scope/=C3001E7C0DA78E4487072B7E050D86C5/@KeyIndexDefined">True</s:Boolean><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Scope/=C3001E7C0DA78E4487072B7E050D86C5/Type/@EntryValue">InCSharpFile</s:String><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Text/@EntryValue"> ? ? ?public string ErrorMessage {get; set; }protected void SetError(){this.SetError("CLEAR");}protected void SetError(string message){if (message == null || message=="CLEAR"){this.ErrorMessage = string.Empty;return;}this.ErrorMessage += message;}protected void SetError(Exception ex, bool checkInner = false){if (ex == null)this.ErrorMessage = string.Empty;Exception e = ex;if (checkInner)e = e.GetBaseException();ErrorMessage = e.Message;} ? ?</s:String><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Field/=busObject/@KeyIndexDefined">True</s:Boolean><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Field/=busObject/Expression/@EntryValue">complete()</s:String><s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Field/=busObject/Order/@EntryValue">0</s:Int64><s:Boolean x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Field/=NewLiteral/@KeyIndexDefined">True</s:Boolean><s:String x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Field/=NewLiteral/Expression/@EntryValue">complete()</s:String><s:Int64 x:Key="/Default/PatternsAndTemplates/LiveTemplates/Template/=E88A906D39C741C0A3B8095C5063DADE/Field/=NewLiteral/Order/@EntryValue">1</s:Int64></root> ? ?使用這種瘋狂的格式,無法分辨一組代碼片段的開始和結(jié)束的位置。每個代碼片段都有多個 Key,加上 GUID 標識,這使得匹配現(xiàn)有的代碼段來判斷是否存在的目的幾乎不可能實現(xiàn)。
據(jù)我所知,沒有找到任何相關(guān)鍵值配置的文檔,也沒有如何存儲的文檔。很有可能存在其他存儲選項,但看起來 Rider 并沒有為代碼片段設(shè)置編輯功能。如果您有更好的開發(fā)人員文檔,請發(fā)表評論。
出于這個原因,Rider 導(dǎo)入是一次性的,如果您導(dǎo)出兩次相同的片段,它們就會翻倍。
為了測試,我在 Rider 的導(dǎo)出文件中添加了一個標記鍵。然后,在我導(dǎo)入相同的代碼片段時,我會刪除了之前添加的代碼片段。很簡陋,也只是測試階段。如果相關(guān)的配置發(fā)生了變化,則可能會失效。
此格式僅適用于 Rider 支持的 .NET 特定代碼類型:.NET Languages,Razor 和包含 HTML 模板的 WebForms。其他格式( JavaScript、HTML 、CSS)則使用完全獨立的格式,我沒有精力在實現(xiàn)相關(guān)的功能。對于 Rider,我主要關(guān)心的是 C# 和 HTML 模板,能正常運行就好了。
只需導(dǎo)出特定文件夾,如 C# 文件夾或 HTML 代碼段,而不是批量導(dǎo)出整個代碼片段文件夾。
SnippetConverter "~2017\Visual C#\My Code Snippets" -m vs-rider -d SnippetConverter "~2017\Code Snippets\Visual Web Developer\My HTML Snippets" -m vs-rider -d摘要
正如我前面提到的,所有這些都是非常簡陋,但對于將我全部的代碼片段從 Visual Studio 導(dǎo)出到 Visual Studio Code 是完全夠用的。對于 Rider, C# 和 HTML 代碼片段導(dǎo)出也可以做到,但是其他類型(如 JavaScript、CSS)會出現(xiàn)異常。我只是當作個人工具,如果哪天有足夠的興趣的話,我會接著完善,但是很大程度是需要另外搞一個完全獨立的轉(zhuǎn)換器。
我沒有測試所有的 Visual Studio 支持的文件類型,即使是VS 內(nèi)置的代碼片段也可能存在某些問題。保險一點,請不要批量導(dǎo)出所有代碼段,而是單獨導(dǎo)出每種類型的代碼片段。
我還是強烈建議使用前綴,因為可以更容易地找到你的代碼片段,并保持它們不受影響。
現(xiàn)在這個工具對于我來說已經(jīng)足夠了,但是我很想知道我是否是少數(shù)幾個投身到代碼片段轉(zhuǎn)換的人之一?
相關(guān)資源
Visual Studio SnippetConverter on GitHub
dotnet-snippetconverter .NET Global Tool
原文地址:https://www.cnblogs.com/chenug/p/10289866.html
.NET社區(qū)新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結(jié)
以上是生活随笔為你收集整理的将 Visual Studio 的代码片段导出到 VS Code的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET Core 3.0:System
- 下一篇: 如何基于 Kubernetes 构建完整