Microsoft MVP성태의 닷넷 이야기
VS.NET IDE: 95. Macros for Visual Studio 2013 [링크 복사], [링크+제목 복사],
조회: 19465
글쓴 사람
정성태 (techsharer at outlook.com)
홈페이지
첨부 파일
 
(연관된 글이 2개 있습니다.)

Macros for Visual Studio 2013

Visual Studio 2012부터 매크로 탐색기가 없어진 것을 그동안 Visual Commander로 겨우 만회할 수 있었는데요.

Visual Studio 2012/2013에서의 매크로 구현 - Visual Commander
; https://www.sysnet.pe.kr/2/0/1767

드디어 마이크로소프트의 "Visual Studio Platform Team"에서 직접 만든 (비록 정식 제품에 포함되는 유형은 아니지만) 매크로 확장이 배포가 되었습니다. ^^

Macros for Visual Studio 2013
; https://visualstudiogallery.msdn.microsoft.com/d3fbf133-e51b-41a2-b86f-9560a96ff62b

설치 후, Visual Studio 2010에서와 같이 "Alt + F8" 단축키로 "Macro Explorer"를 띄우기 위해 "Tools" / "Options" / "Keyboard"에 가서 할당(Assign)하면 끝!

vs2013_macro_explorer_1.png

마이크로소프트 측에서 2012부터 매크로를 없앴던 이유는, 매크로 사용자가 별로 많지 않은 반면 내부적으로 유지해야 하는 비용이 너무 커서였다고 했습니다. 따라서, 이렇게 확장 도구 유형으로 제공함으로써 '제품' 수준의 품질은 필요하지 않으면서 매크로를 요구하는 '일부 사용자'에게 해답은 줄 수 있게 된 것입니다.




하지만, 아쉬운 점이 좀 있습니다. 우선, 언어가 ".NET 언어"가 아닌 "Javascript"만 지원한다는 점입니다. 이 때문에 기존 매크로를 보유하고 있는 경우 마이그레이션하는데 시간이 걸릴 뿐만 아니라 일부 코드는 "Javascript"의 한계로 인해 변환 자체가 불가능한 경우도 있습니다. 일례로, 그동안은 .NET Framework의 BCL 클래스를 쉽게 이용할 수 있었지만 Javascript로 바뀐 이상 BCL 클래스를 활용하는 것은 물 건너 간 것입니다.

또 한가지 불편한 점은, 아직 초기라서 그런지 '공통 라이브러리'로써의 자바스크립트 관리가 없습니다. 따라서, A 매크로에서 SetText라는 함수를 정의했다면 B 매크로 파일에서 A 매크로 파일에 포함된 SetText를 재사용할 수는 없고 동일한 소스 코드를 복제해서 보유하고 있어야 합니다.

현재로써는... 그 정도! ^^




개인적으로 프로그래밍 이외에 Visual Studio 편집기를 지금의 이 블로그에 글을 쓰는 용도로 사용하고 있습니다. 정해진 포맷팅 몇 개를 Visual Studio의 매크로를 이용해 처리하고 있는데, 하필 2012부터 매크로가 사라져서 어쩔 수 없이 컴퓨터에 2010, 2013을 함께 설치해 두고 있었습니다. 물론, 지난번에 소개한 "Visual Studio 2012/2013에서의 매크로 구현 - Visual Commander" 확장이 있었는데 차일피일 마이그레이션을 미뤄오고 있었습니다. 어차피 2010에서 되기 때문에 크게 불편하지 않았던 것인데요.

이번에는 마이크로소프트가 공식적으로 확장을 내놓았으니 마음먹고 한번 마이그레이션을 해보았습니다. 다행히, 제가 작성한 매크로의 경우 javascript로 모두 변환이 가능했는데요. 그래도 일부 매크로 기능이 쉽게 되지는 않아서 이를 공유해 봅니다.


1. 파일 저장

기존의 VB.NET 매크로에서는 단순히 .NET BCL에서 제공되는 File.WriteAllText 메서드를 사용하면 되지만, javascript에서는 그럴 수가 없습니다. 이에 대한 우회 방법을 매크로 탐색기를 설치하면 제공되는 기본 예제 중에서 "Samples/Editor/Save Backup" 코드를 보고 찾아냈습니다.

간단히 정리하면, Visual Studio로 하여금 "New File" 메뉴를 실행하고 텍스트를 넣어둔 다음 "Save"를 시키고 문서를 닫는 것입니다.

function SaveAsFile(fileText) {
    var fileName = dte.ActiveDocument.FullName + ".html";

    if (typeof (dte.ActiveDocument) != undefined) {
        var saveChangesNo = 2;

        // Create the temp document, save, then close
        dte.ItemOperations.NewFile("General\\Text File");
        dte.ActiveDocument.Object("TextDocument").Selection.Insert(fileText);
        dte.ActiveDocument.Save(fileName);
        dte.ActiveDocument.Close(saveChangesNo);
    }
}

작은 문제가 하나 있다면... 이 함수를 써 보니, Visual Studio를 실행해서 처음 실행하는 경우 다음과 같은 오류 창이 뜹니다.

An exception has been encountered. This may be caused by an extension.

You can get more information by examining the file 'c:\users\[계정]\AppData\Roaming\Microsoft\VisualStudio\12.0\ActivityLog.xml'

에러는 발생하지만, 다시 실행하면 이후부터는 아무런 문제없이 잘 동작하기 때문에 감수할 수 있습니다. 그 외에, 새로운 문서를 순간적으로 추가/삭제하기 때문에 화면이 잠시 깜빡이는 현상이 발생합니다. ^^;


2. 클립보드 복사

또 한가지 문제는 클립보드 사용입니다.

VS.NET - 매크로 함수내에서 클립보드 API 사용
; https://www.sysnet.pe.kr/2/1/628

VB.NET 매크로에서는 단순히 System.Windows.Forms 어셈블리의 Clipboard 타입을 사용하면 됐지만, javascript로 오면서 그게 안됩니다. 혹시나 싶어 "window.clipboardData.setData" 함수를 써봤지만 오류를 낼 뿐입니다.

이 역시 우회 방법을 위에서 설명한 "1. 파일 저장"과 비슷한 방식으로 해결했습니다. 즉, '빈 파일' 하나 생성하고 "Edit.SelectAll"을 실행해 전체 텍스트를 선택한 다음 "Edit.Cut"으로 클립 보드에 복사한 후 문서를 닫는 것입니다.

function SetClipboardData(iFileText)
{
    dte.UndoContext.Open("ToClipboard");

    if (typeof (dte.ActiveDocument) != undefined) {
        var saveChangesNo = 2;

        // Create the temp document, save, then close
        dte.ItemOperations.NewFile("General\\Text File");
        dte.ActiveDocument.Object("TextDocument").Selection.Insert(iFileText);

        dte.ExecuteCommand("Edit.SelectAll");
        dte.ExecuteCommand("Edit.Cut");

        dte.ActiveDocument.Close(saveChangesNo)     // Already saved with line above, don't need to save again.
    }

    dte.UndoContext.Close();  
}


3. 본문에 텍스트 삽입

이를 위해 매크로 확장에서 기본적으로 "Macro.InsertText" 함수를 제공합니다.

Macro.InsertText("TEST");

문제는, 이것의 효율이 그다지 좋지 않습니다. 긴 문장으로 테스트해보면 마치 사람이 빠르게 입력하듯 동작하기 때문에 느립니다. 그래서, 그냥 다음과 같은 함수를 만들어서 동작시키는 것이 권장됩니다.

var selection = dte.ActiveDocument.Selection;

var text = "// 주석: " + selection.Text;

SetText(selection, text);

function SetText(iSelection, iText) {
    var prop = dte.DTE.Properties("TextEditor", "PlainText").Item("IndentStyle");
    var oldIndent = prop.Value;
    prop.Value = 0;

    iSelection.Text = iText;

    prop.Value = oldIndent;
}

그런데, 여기서 만족할 수 없습니다. 이렇게 처리한 경우 텍스트 입력은 빠르게 되지만 'Ctrl + Z' 키를 눌러 Undo 작업을 하면 한줄씩 다시 undo 작업이 이뤄지면서 취소 작업에 시간이 걸립니다. 따라서, 단 한번의 'Ctrl + Z'키로 Undo를 할 수 있도록 UndoContext 처리를 해주면 됩니다.

function SetText(iSelection, iText) {
    dte.UndoContext.Open("SetTextContext");
    
    var prop = dte.DTE.Properties("TextEditor", "PlainText").Item("IndentStyle");
    var oldIndent = prop.Value;
    prop.Value = 0;

    iSelection.Text = iText;

    prop.Value = oldIndent;

    dte.UndoContext.Close();
}




[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]

[연관 글]






[최초 등록일: ]
[최종 수정일: 7/10/2021]

Creative Commons License
이 저작물은 크리에이티브 커먼즈 코리아 저작자표시-비영리-변경금지 2.0 대한민국 라이센스에 따라 이용하실 수 있습니다.
by SeongTae Jeong, mailto:techsharer at outlook.com

비밀번호

댓글 작성자
 



2016-08-19 12시57분
Visual Studio's most useful (and underused) tips
; http://www.hanselman.com/blog/VisualStudiosMostUsefulAndUnderusedTips.aspx
정성태

... 16  17  18  19  20  [21]  22  23  24  25  26  27  28  29  30  ...
NoWriterDateCnt.TitleFile(s)
13126정성태9/15/20227476.NET Framework: 2049. C# 11 - 정적 메서드에 대한 delegate 처리 시 cache 적용
13125정성태9/14/20227718.NET Framework: 2048. C# 11 - 구조체 필드의 자동 초기화(auto-default structs)
13124정성태9/13/20227507.NET Framework: 2047. Golang, Python, C#에서의 CRC32 사용
13123정성태9/8/20227861.NET Framework: 2046. C# 11 - 멤버(속성/필드)에 지정할 수 있는 required 예약어 추가
13122정성태8/26/20227831.NET Framework: 2045. C# 11 - 메서드 매개 변수에 대한 nameof 지원
13121정성태8/23/20225668C/C++: 157. Golang - 구조체의 slice 필드를 Reflection을 이용해 변경하는 방법
13120정성태8/19/20227314Windows: 209. Windows NT Service에서 UI를 다루는 방법 [3]
13119정성태8/18/20226879.NET Framework: 2044. .NET Core/5+ 프로젝트에서 참조 DLL이 보관된 공통 디렉터리를 지정하는 방법
13118정성태8/18/20225663.NET Framework: 2043. WPF Color의 기본 색 영역은 (sRGB가 아닌) scRGB [2]
13117정성태8/17/20227885.NET Framework: 2042. C# 11 - 파일 범위 내에서 유효한 타입 정의 (File-local types)파일 다운로드1
13116정성태8/4/20228335.NET Framework: 2041. C# - Socket.Close 시 Socket.Receive 메서드에서 예외가 발생하는 문제파일 다운로드1
13115정성태8/3/20228716.NET Framework: 2040. C# - ValueTask와 Task의 성능 비교 [1]파일 다운로드1
13114정성태8/2/20228883.NET Framework: 2039. C# - Task와 비교해 본 ValueTask 사용법파일 다운로드1
13113정성태7/31/20228206.NET Framework: 2038. C# 11 - Span 타입에 대한 패턴 매칭 (Pattern matching on ReadOnlySpan<char>)
13112정성태7/30/20228569.NET Framework: 2037. C# 11 - 목록 패턴(List patterns) [1]파일 다운로드1
13111정성태7/29/20228326.NET Framework: 2036. C# 11 - IntPtr/UIntPtr과 nint/nuint의 통합파일 다운로드1
13110정성태7/27/20228382.NET Framework: 2035. C# 11 - 새로운 연산자 ">>>" (Unsigned Right Shift)파일 다운로드1
13109정성태7/27/20229784VS.NET IDE: 177. 비주얼 스튜디오 2022를 이용한 (소스 코드가 없는) 닷넷 모듈 디버깅 - "외부 원본(External Sources)" [1]
13108정성태7/26/20227731Linux: 53. container에 실행 중인 Golang 프로세스를 디버깅하는 방법 [1]
13107정성태7/25/20226821Linux: 52. Debian/Ubuntu 계열의 docker container에서 자주 설치하게 되는 명령어
13106정성태7/24/20226616오류 유형: 819. 닷넷 6 프로젝트의 "Conditional compilation symbols" 기본값 오류
13105정성태7/23/20227924.NET Framework: 2034. .NET Core/5+ 환경에서 (프로젝트가 아닌) C# 코드 파일을 입력으로 컴파일하는 방법 - 두 번째 이야기 [1]
13104정성태7/23/202211002Linux: 51. WSL - init에서 systemd로 전환하는 방법
13103정성태7/22/20227493오류 유형: 818. WSL - systemd-genie와 관련한 2가지(systemd-remount-fs.service, multipathd.socket) 에러
13102정성태7/19/20226956.NET Framework: 2033. .NET Core/5+에서는 구할 수 없는 HttpRuntime.AppDomainAppId
13101정성태7/15/202215930도서: 시작하세요! C# 10 프로그래밍
... 16  17  18  19  20  [21]  22  23  24  25  26  27  28  29  30  ...