WPF에서 Monaco Editor 사용하기

Monaco Editor란?

Monaco editor는 Microsoft에서 개발한 코드 에디터 엔진으로 MIT 라이선스를 가지는 open source입니다. Monaco editor는 웹 어플리케이션이며 대표적으로 VS Code에 사용된 엔진입니다. 기본적으로 다양한 코딩 언어에 대한 syntax를 제공할 뿐만 아니라 새로운 언어를 추가할 수 있습니다.

시작하기

WPF를 이용하여 개발중인 프로그램에 fortran 코드를 편집할 수 있는 에디터가 필요하게 되었고 손쉽게 WPF에 코드 에디터를 적용할 수 있는 방법을 찾던중 Manaco editor를 찾게 되었습니다. Monaco editor를 WPF에 적용하면서 진행했던 내용들을 정리하고자 글을 작성합니다. 테스트 환경은 Visual Studio 2022에서 .Net 6.0을 사용하였습니다.

WPF Application 구성

먼저 Visual Studio 2022를 실행하고 WPF 애플리케이션 프로젝트를 생성하고 .Net 6.0을 선택합니다. 생성된 프로젝트에 먼저 Monaco 폴더를 생성합니다. 이 후에 프로젝트에서 마우스 우 클릭을 하고 프로젝트 파일 편집을 선택합니다. 그러면 다음과 같은 xml 요소가 있을 것입니다.

Xml

<ItemGroup> <Folder Include="Moanco\" /> </ItemGroup>

위의 xml 요소를 다음과 같이 변경하고 저장합니다.

Xml

<ItemGroup> <Content Include="Monaco\**"> <CopyToOutputDirectory>Always</CopyToOutputDirectory> </Content> </ItemGroup>

Monaco editor 적용하기

https://microsoft.github.io/monaco-editor/에 가셔서 Monaco editor를 다운받고 압축을 해제 합니다. 압축을 해제 하시면 min 이라는 폴더가 있는데 이 폴더를 WPF 애플리케이션 구성에서 만들었던 Monaco 폴더안에 복사합니다. 복사 후에 Monaco 폴더에 index.html을 생성하고 다음과 같이 예제 코드를 작성하고 저장합니다.

Html

<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <link rel="stylesheet" data-name="vs/editor/editor.main" href="./min/vs/editor/editor.main.css" /> <style> html, body { height: 100%; margin: 0; } #container { height: 100%; } </style> </head> <body> <div id="container"></div> <script src="./min/vs/loader.js"></script> <script> require.config({ paths: { 'vs': './min/vs' } }); </script> <script src="./min/vs/editor/editor.main.nls.js"></script> <script src="./min/vs/editor/editor.main.js"></script> <script> var editor = monaco.editor.create(document.getElementById('container'), { language: 'cpp', value: `// Example class class Example { private: string title = "string variable"; double val; public: string getTitle(); double getValue(); };`, }); </script> </body> </html>

WebView2를 이용한 에디터 실행

Monaco editor는 웹 어플리케이션이기 때문에 WPF에서 사용할 수 있는 WebView2를 사용합니다. WebView2는 Visual Studio에서 Nuget 패키지 관리로 가셔서 WebView2를 검색 후 Microsoft.Web.WebView2를 설치합니다. 다음으로 MainWindow.xaml 파일을 다음과 같이 수정합니다.

그리고 MainWindow.xaml.cs의 내용도 다음과 같이 수정하고 저장합니다.

Csharp

public MainWindow() { InitializeComponent(); Loaded += Window_Loaded; } private void Window_Loaded(object sender, RoutedEventArgs e) { this.webView21.Source = new Uri(System.IO.Path.Combine( System.AppDomain.CurrentDomain.BaseDirectory, @"Monaco\index.html")); }

빌드 후 프로그램을 실행하게 되면 다음과 같은 결과를 얻을 수 있습니다.

새로운 language syntax 추가하기

기본적으로 제공하는 cpp 언어로 테스트를 진행하여 정상적으로 실행되는 것을 확인하였습니다. 하지만 저의 경우 fortran 코드에 대한 syntax를 필요하였고 기본적으로 제공되는 언어에는 fortran 코드 항목이 없어 새롭게 추가하게 되었습니다.

Language 추가하기

먼저 Monaco Editor가 우리가 사용하려는 새로운 language를 알게 하기 위해서 custom language identifier를 Monaco Editor에 등록해야 합니다. Monaco Editor에 새 language를 추가하는 방법은 다음의 코드를 index.html의 script 태그에 추가합니다. 저의 경우 fortran 언어를 추가할 것이기 때문에 id 값을 fortran으로 하였습니다.

Java

monaco.languages.register({ id: 'fortran' });

Keyword 및 tokenizer 추가하기

다음으로 등록한 fortran 언어에 highlighting 하기 위한 keyword들을 추가하고 코드 분석의 규칙을 정의하는 tokenizer를 설정합니다. 이러한 전반적인 syntax highlighting은 Monaco Editor의 setMonarchTokensProvider를 사용합니다. 제가 작성한 코드는 다음과 같습니다.

Java

monaco.languages.setMonarchTokensProvider('fortran', { keywords: [ 'subroutine', 'include', 'dimension', 'logical', 'character', 'integer', 'end', 'return'], tokenizer: { root: [ [/^c(\s.*)?$/, 'comment'], [/@?[a-zA-Z][\w$]*/, { cases: { '@keywords': 'keyword', '@default': 'variable', } }], [/".*?"/, 'string'], [/'.*?'/, 'string'], ] } });

위에서 keywords는 highlighting 하고자 하는 keyword들을 설정합니다. 주목할 사항은 tokenizer에 설정된 내용으로 본인의 경우 각 라인 첫 번째 글자가 'c' 라면 주석으로 처리 하기 위해서 /^c(\s.*)?/'comment' 로 설정하였습니다. 또한 ""와 '' 로 감싸진 문자의 경우 'string' 으로 처리 되도록 하였습니다.

결과 확인하기

위 내용과 같이 설정하고 코드를 에디터에 작성하게 되면 원하는 highliting된 코드를 확인할 수 있습니다. 저의 경우 다음과 같은 임의의 코드를 작성하였으며, 적용 전 후를 확인 해보면 다음과 같은 결과를 확인할 수 있습니다.

Custom language 적용 전

Custom language 적용 후

Custom theme

위에서 우리는 keywords로 설정한 단어들에 대해서 string, comment, keyowrd, variable 토큰에 따라 색상이 다르게 적용되는 것을 확인 할 수 있습니다. 이러한 색상은 Monaco Editor에 미리 정의된 색상이 적용되는 것으로 볼 수 있습니다. 여기서는 각 토큰에 따라 색상 및 폰트 스타일을 적용하는 방법을 알아 보겠습니다.

Theme 적용하기

Theme 적용은 Monaco에서 제공하는 API인 monaco.editor.defineTheme를 사용하여 적용할 수 있습니다. 테스트로 다음과 같이 theme를 적용해보았습니다.

Java

monaco.editor.defineTheme('fortranTheme', { colors: {}, base: 'vs', inherit: false, rules: [ { token: 'keyword', foreground: 'FF6600', fontStyle: 'bold' }, { token: 'comment', foreground: '999999' }, { token: 'string', foreground: '009966' }, { token: 'variable', foreground: '006699' }, ] });

적용하게 되면 다음과 같이 각 토큰에 대한 색상 및 스타일이 변경됩니다.

On this page