Microsoft MVP성태의 닷넷 이야기
VS.NET IDE: 95. Macros for Visual Studio 2013 [링크 복사], [링크+제목 복사],
조회: 19464
글쓴 사람
정성태 (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)
13176정성태11/29/20224743오류 유형: 828. gunicorn - ModuleNotFoundError: No module named 'flask'
13175정성태11/29/20226592오류 유형: 827. Python - ImportError: cannot import name 'html5lib' from 'pip._vendor'
13174정성태11/28/20225002.NET Framework: 2073. C# - VMMap처럼 스택 메모리의 reserve/guard/commit 상태 출력파일 다운로드1
13173정성태11/27/20225786.NET Framework: 2072. 닷넷 응용 프로그램의 스레드 스택 크기 변경
13172정성태11/25/20225454.NET Framework: 2071. 닷넷에서 ESP/RSP 레지스터 값을 구하는 방법파일 다운로드1
13171정성태11/25/20225152Windows: 214. 윈도우 - 스레드 스택의 "red zone"
13170정성태11/24/20225396Windows: 213. 윈도우 - 싱글 스레드는 컨텍스트 스위칭이 없을까요?
13169정성태11/23/20225987Windows: 212. 윈도우의 Protected Process (Light) 보안 [1]파일 다운로드2
13168정성태11/22/20225318제니퍼 .NET: 31. 제니퍼 닷넷 적용 사례 (9) - DB 서비스에 부하가 걸렸다?!
13167정성태11/21/20225353.NET Framework: 2070. .NET 7 - Console.ReadKey와 리눅스의 터미널 타입
13166정성태11/20/20225077개발 환경 구성: 651. Windows 사용자 경험으로 WSL 환경에 dotnet 런타임/SDK 설치 방법
13165정성태11/18/20224907개발 환경 구성: 650. Azure - "scm" 프로세스와 엮인 서비스 모음
13164정성태11/18/20225905개발 환경 구성: 649. Azure - 비주얼 스튜디오를 이용한 AppService 원격 디버그 방법
13163정성태11/17/20225807개발 환경 구성: 648. 비주얼 스튜디오에서 안드로이드 기기 인식하는 방법
13162정성태11/15/20226862.NET Framework: 2069. .NET 7 - AOT(ahead-of-time) 컴파일
13161정성태11/14/20226189.NET Framework: 2068. C# - PublishSingleFile로 배포한 이미지의 역어셈블 가능 여부 (난독화 필요성) [4]
13160정성태11/11/20226072.NET Framework: 2067. C# - PublishSingleFile 적용 시 native/managed 모듈 통합 옵션
13159정성태11/10/20229355.NET Framework: 2066. C# - PublishSingleFile과 관련된 옵션 [3]
13158정성태11/9/20225473오류 유형: 826. Workload definition 'wasm-tools' in manifest 'microsoft.net.workload.mono.toolchain' [...] conflicts with manifest 'microsoft.net.workload.mono.toolchain.net7'
13157정성태11/8/20226130.NET Framework: 2065. C# - Mutex의 비동기 버전파일 다운로드1
13156정성태11/7/20227088.NET Framework: 2064. C# - Mutex와 Semaphore/SemaphoreSlim 차이점파일 다운로드1
13155정성태11/4/20226552디버깅 기술: 183. TCP 동시 접속 (연결이 아닌) 시도를 1개로 제한한 서버
13154정성태11/3/20226046.NET Framework: 2063. .NET 5+부터 지원되는 GC.GetGCMemoryInfo파일 다운로드1
13153정성태11/2/20227338.NET Framework: 2062. C# - 코드로 재현하는 소켓 상태(SYN_SENT, SYN_RECV)
13152정성태11/1/20225938.NET Framework: 2061. ASP.NET Core - DI로 추가한 클래스의 초기화 방법 [1]
13151정성태10/31/20226130C/C++: 161. Windows 11 환경에서 raw socket 테스트하는 방법파일 다운로드1
... 16  17  18  [19]  20  21  22  23  24  25  26  27  28  29  30  ...