Microsoft MVP성태의 닷넷 이야기
VS.NET IDE: 95. Macros for Visual Studio 2013 [링크 복사], [링크+제목 복사],
조회: 26014
글쓴 사람
정성태 (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
정성태

... 46  47  48  49  50  51  [52]  53  54  55  56  57  58  59  60  ...
NoWriterDateCnt.TitleFile(s)
12640정성태5/13/202120940오류 유형: 716. RDP 연결 - Because of a protocol error (code: 0x112f), the remote session will be disconnected. [1]
12639정성태5/12/202117334오류 유형: 715. Arduino: Open Serial Monitor - The module '...\detection.node' was compiled against a different Node.js version using NODE_MODULE_VERSION
12638정성태5/12/202117576사물인터넷: 63. NodeMCU v1 ESP8266 - 펌웨어 내 파일 시스템(SPIFFS, LittleFS) 및 EEPROM 활용
12637정성태5/10/202117790사물인터넷: 62. NodeMCU v1 ESP8266 보드의 A0 핀에 다중 아날로그 센서 연결 [1]
12636정성태5/10/202118026사물인터넷: 61. NodeMCU v1 ESP8266 보드의 A0 핀 사용법 - FSR-402 아날로그 압력 센서 연동파일 다운로드1
12635정성태5/9/202116342기타: 81. OpenTabletDriver를 (관리자 권한으로 실행하지 않고도) 관리자 권한의 프로그램에서 동작하게 만드는 방법
12634정성태5/9/202114807개발 환경 구성: 572. .NET에서의 필수 무결성 제어 - 외부 Manifest 파일을 두는 방법파일 다운로드1
12633정성태5/7/202117801개발 환경 구성: 571. UAC - 관리자 권한 없이 UIPI 제약을 없애는 방법
12632정성태5/7/202119000기타: 80. (WACOM도 지원하는) Tablet 공통 디바이스 드라이버 - OpenTabletDriver
12631정성태5/5/202117827사물인터넷: 60. ThingSpeak 사물인터넷 플랫폼에 ESP8266 NodeMCU v1 + 조도 센서 장비 연동파일 다운로드1
12630정성태5/5/202118559사물인터넷: 59. NodeMCU v1 ESP8266 보드의 A0 핀 사용법 - CdS Cell(GL3526) 조도 센서 연동파일 다운로드1
12629정성태5/5/202120312.NET Framework: 1057. C# - CoAP 서버 및 클라이언트 제작 (UDP 소켓 통신) [1]파일 다운로드1
12628정성태5/4/202118225Linux: 39. Eclipse 원격 디버깅 - Cannot run program "gdb": Launching failed
12627정성태5/4/202118319Linux: 38. 라즈베리 파이 제로 용 프로그램 개발을 위한 Eclipse C/C++ 윈도우 환경 설정
12626정성태5/3/202118421.NET Framework: 1056. C# - Thread.Suspend 호출 시 응용 프로그램 hang 현상 (2)파일 다운로드1
12625정성태5/3/202116926오류 유형: 714. error CS5001: Program does not contain a static 'Main' method suitable for an entry point
12624정성태5/2/202121394.NET Framework: 1055. C# - struct/class가 스택/힙에 할당되는 사례 정리 [10]파일 다운로드1
12623정성태5/2/202117696.NET Framework: 1054. C# 9 최상위 문에 STAThread 사용 [1]파일 다운로드1
12622정성태5/2/202113537오류 유형: 713. XSD 파일을 포함한 프로젝트 - The type or namespace name 'TypedTableBase<>' does not exist in the namespace 'System.Data'
12621정성태5/1/202118427.NET Framework: 1053. C# - 특정 레지스트리 변경 시 알림을 받는 방법 [1]파일 다운로드1
12620정성태4/29/202121598.NET Framework: 1052. C# - 왜 구조체는 16 바이트의 크기가 적합한가? [1]파일 다운로드1
12619정성태4/28/202121561.NET Framework: 1051. C# - 구조체의 크기가 16바이트가 넘어가면 힙에 할당된다? [2]파일 다운로드1
12618정성태4/27/202119837사물인터넷: 58. NodeMCU v1 ESP8266 CP2102 Module을 이용한 WiFi UDP 통신 [1]파일 다운로드1
12617정성태4/26/202117091.NET Framework: 1050. C# - ETW EventListener의 Keywords별 EventId에 따른 필터링 방법파일 다운로드1
12616정성태4/26/202116794.NET Framework: 1049. C# - ETW EventListener를 상속받았을 때 초기화 순서파일 다운로드1
12615정성태4/26/202114045오류 유형: 712. Microsoft Live 로그인 - 계정을 선택하는(Pick an account) 화면에서 진행이 안 되는 문제
... 46  47  48  49  50  51  [52]  53  54  55  56  57  58  59  60  ...