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

... 76  77  78  79  80  81  82  83  84  85  86  87  [88]  89  90  ...
NoWriterDateCnt.TitleFile(s)
11736정성태10/12/201818504오류 유형: 492. Visual Studio 로딩 시 오류 - The 'Scc Display Information' package did not load correctly.
11735정성태10/12/201824265VS.NET IDE: 129. Visual Studio - 특정 문자(열)를 개행 문자로 바꾸는 방법
11734정성태10/10/201818608Linux: 4. Synology NAS(DS216+II)에 FTDI 장치 연결 후 C#(.NET Core)으로 DTR 제어파일 다운로드1
11733정성태10/10/201821366Linux: 3. Synology NAS(DS216+II)에서 FTDI 장치를 C/C++로 제어
11732정성태10/10/201821131디버깅 기술: 119. windbg 분석 사례 - 종료자(Finalizer)에서 예외가 발생한 경우 비정상 종료(Crash) 발생파일 다운로드1
11731정성태10/9/201820549개발 환경 구성: 409. C# - REST API를 이용해 Azure Kudu 서비스 이용 - 웹 앱 확장 처리파일 다운로드1
11730정성태10/9/201819835개발 환경 구성: 408. C# - REST API를 이용해 Azure Kudu 서비스 이용 - 파일 처리파일 다운로드1
11729정성태10/9/201822323Windows: 150. 윈도우에서 ARP Cache 목록 확인 및 삭제하는 방법
11728정성태10/9/201820153사물인터넷: 50. Audio Jack 커넥터의 IR 적외선 송신기 [1]
11727정성태10/8/201821381오류 유형: 491. Visual Studio의 리눅스 SSH 원격 연결 - "Connectivity Failure. Please make sure host name and port number are correct."
11726정성태10/7/201824053사물인터넷: 49. 라즈베리 파이를 이용해 원격 컴퓨터의 전원 스위치 제어파일 다운로드1
11724정성태10/5/201823814개발 환경 구성: 407. 유니코드와 한글 - "Hangul Compatibility Jamo"파일 다운로드1
11723정성태10/4/201817542개발 환경 구성: 406. "Docker for Windows" 컨테이너 내의 .NET Core 응용 프로그램에서 직렬 포트(Serial Port, COM Port) 사용 방법
11722정성태10/4/201821255.NET Framework: 798. C# - Hyper-V 가상 머신의 직렬 포트와 연결된 Named Pipe 간의 통신파일 다운로드1
11721정성태10/4/201821576.NET Framework: 797. Linux 환경의 .NET Core 응용 프로그램에서 직렬 포트(Serial Port, COM Port) 사용 방법파일 다운로드1
11720정성태10/4/201823150개발 환경 구성: 405. Hyper-V 가상 머신에서 직렬 포트(Serial Port, COM Port) 사용
11719정성태10/4/201823730.NET Framework: 796. C# - 인증서를 윈도우에 설치하는 방법
11718정성태10/4/201818893개발 환경 구성: 404. (opkg가 설치된) Synology NAS(DS216+II)에 cmake 설치
11717정성태10/3/201821508사물인터넷: 48. 넷두이노의 C# 네트워크 프로그램 [1]
11716정성태10/3/201822097사물인터넷: 47. Raspberry PI Zero (W)에 FTDI 장치 연결 후 C/C++로 DTR 제어파일 다운로드1
11715정성태10/3/201820842사물인터넷: 46. Raspberry PI Zero (W)에 docker 설치
11714정성태10/2/201820114사물인터넷: 45. Raspberry PI에 ping을 hostname으로 하는 방법
11713정성태10/2/201822491개발 환경 구성: 403. Synology NAS(DS216+II)에 docker 설치 후 .NET Core 2.1 응용 프로그램 실행하는 방법
11712정성태10/2/201827694.NET Framework: 795. C# - 폰트 목록을 한글이 아닌 영문으로 구하는 방법 [3]
11711정성태10/2/201823106오류 유형: 490. 윈도우 라이선스 키 입력 오류 0xc004f050, 0xc004e028
11710정성태10/2/201822048.NET Framework: 794. C# - 같은 모양, 다른 값의 한글 자음을 비교하는 호환 분해 [5]
... 76  77  78  79  80  81  82  83  84  85  86  87  [88]  89  90  ...