wordpress에서 modelica code 표시하기(prism.js + Highlighting Code Block plug-in)

워드 프레스에서 Highlighting Code Block을 이용하여 modelica code를 보여주는데, 선택할 수 있는 Default Language set에 “modelica” 항목이 없다.
그래서 직접 만들어서 서버에 업로드 해서 사용하는데, prism.js를 잘 모르는 상태에서 만들어 쓰려니 힘들다.

사용한 방식은 prism.js 파일에 “modelica” 항목을 추가하는 방법.
다른 사람이 먼저 작업해 놓은 파일이 분명 있을 듯 한데(visual studio code, obsidian 등에서 이미 modelica를 지원함) 못 찾겠다.


prism js 관련 언어
웹사이트 링크

Modelica Prism.js 작성

아직 Prism을 정확히 이해하지 못해서, CPP를 기반으로 우선 키워드 부분만 반영함.

reference
keyword : 13page

[전체 소스 : Github](https://github.com/eraracom/ModelicaLanguage/tree/main/Prism.js)

Prism.languages.modelica=
Prism.languages.extend("cpp",
{
    keyword:
    /\b(?:algorithm|and|annotation|block|break|class|connect|connector|constant|constrainedby|der|discrete|each|elseif|elsewhen|encapsulated|end|enumeration|equation|expandable|extends|external|false|final|flow|for|function|if|import|impure|in|initial|inner|input|loop|model|not|operator|or|outer|output|package|parameter|partial|protected|public|pure|record|redeclare|replaceable|return|stream|then|true|type|when|while|within)\b/,

}),

;

기존 언어 분석

C 언어 분석

시작

Prism.languages.c=
Prism.languages.extend("clike",
{ 

extend 의 의미는 기존의 규칙을 따른다는 의미이다.
즉 C언어는 clike라는 언어의 규칙을 포함한다.

키워드

keyword:
/\b(?:
_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|asm|typeof|inline|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|union|unsigned|void|volatile|while
)\b

연산자

/,
operator:
/>>=?
|<<=?
|->
|([-+&|:])\1
|[?:~]
|[-+*\/%&|^!=<>]=?

숫자

/,
number:
/(?:
\b0x[\da-f]+
|(?:\b\d+\.?\d*
|\B\.\d+)(?:e[+-]?\d+)?)[ful]*/i}
),

instartBefore

(static) insertBefore(inside, before, insert, rootopt) → {Grammar}
다른 토큰 앞에 정의한 토큰을 삽입합니다.

Prism.languages.insertBefore
("c",

"string",

{
    macro:
    {
        pattern:/(^\s*)#\s*[a-z]+(?:[^\r\n\\]|\\(?:\r\n|[\s\S]))*/im,
        lookbehind:!0,
        alias:"property",
        inside:
        {
            string:
            {
                pattern:
                /(#\s*include\s*)(?:<.+?>|("|')(?:\\?.)+?\2)/,

                lookbehind:
                !0
            },

            directive:
            {
                pattern:/(#\s*)
                \b(?:define|defined|elif|else|endif|error|ifdef|ifndef|if|import|
                include|line|pragma|undef|using
                )\b/,

                lookbehind:
                !0,

                alias:
                "keyword"
            }
        }
    },

    constant:

    /\b(?:
    __FILE__|__LINE__|__DATE__|__TIME__|__TIMESTAMP__|__func__|EOF|NULL|
    SEEK_CUR|SEEK_END|SEEK_SET|stdin|stdout|stderr
    )\b

/}
)
,delete 

Prism.languages.c["class-name"]
,delete 

Prism.languages.c["boolean"];

C++ 분석

Prism.languages.cpp=
Prism.languages.extend("c",
{
    keyword:
    /\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|class|compl|const|constexpr|const_cast|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|float|for|friend|goto|if|inline|int|int8_t|int16_t|int32_t|int64_t|uint8_t|uint16_t|uint32_t|uint64_t|long|mutable|namespace|new|noexcept|nullptr|operator|private|protected|public|register|reinterpret_cast|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|union|unsigned|using|virtual|void|volatile|wchar_t|while)\b/,

    "boolean":
    /\b(?:true|false)\b/,

    operator:   
    />>=?|<<=?|->|([-+&|:])\1|[?:~]|[-+*\/%&|^!=<>]=?|\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\b/


}),

Prism.languages.insertBefore(
"cpp",
"keyword",

{
    "class-name":
    {
        pattern:
        /(class\s+)\w+/i,

        lookbehind:
        !0
    }
}),

Prism.languages.insertBefore(
"cpp",
"string",

{
    "raw-string":
    {
        pattern:
        /R"([^()\\ ]{0,16})\([\s\S]*?\)\1"/,
        alias:"string",
        greedy:!0
    }
});

CSS 분석

Prism.languages.css=
{
comment:
/\/\*[\s\S]*?\*\/

/,
atrule:
{
    pattern:
    /@[\w-]+?.*?(?:;|(?=\s*\{))/i,

    inside:
    {
        rule:
        /@[\w-]+/}},

        url:
        /url\((?:(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1|.*?)\)/i,

        selector:
        /[^{}\s][^{};]*?(?=\s*\{)/,

        string:
        {
            pattern:
            /("|')(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,

            greedy:
            !0
        },

        property:
        /[-_a-z\xA0-\uFFFF][-\w\xA0-\uFFFF]*(?=\s*:)/i,

        important:
        /!important\b/i,"function":/[-a-z0-9]+(?=\()/i,

        punctuation:/[(){};:,]
    /},

    Prism.languages.css.atrule.inside.rest=Prism.languages.css,
    Prism.languages.markup&&(
    Prism.languages.insertBefore
    ("markup",
    "tag",

    {
        style:
        {
            pattern:/(<style[\s\S]*?>)[\s\S]*?(?=<\/style>)/i,
            lookbehind:!0,inside:Prism.languages.css,
            alias:"language-css",
            greedy:!0
        }
    }),

    Prism.languages.insertBefore
    ("inside",
    "attr-value",

    {
        "style-attr":
        {
            pattern:/\s*style=("|')(?:\\[\s\S]|(?!\1)[^\\])*\1/i,
            inside:{"attr-name":
            {
                pattern:/^\s*style/i,
                inside:Prism.languages.markup.tag.inside
            },
        punctuation:/^\s*=\s*['"]|['"]\s*$/,"attr-value":
        {
            pattern:/.+/i,inside:Prism.languages.css
        }
    },
    alias:"language-css"}},Prism.languages.markup.tag));

Clike 분석

Prism.languages.clike=
{
    comment:[
    {
        pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,
        lookbehind:!0
    },
    {
        pattern:/(^|[^\\:])\/\/.*/,
        lookbehind:!0,
        greedy:!0
    }],

    string:
    {
        pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,
        greedy:!0
    },

    "class-name":
    {
        pattern:
        /((?:\b(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[\w.\\]+/i,

        lookbehind:
        !0,

        inside:
        {
            punctuation:
            /[.\\]/
        }
    },

    keyword:
                /\b(?:if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/,"boolean":/\b(?:true|false)\b/,"function":/\w+(?=\()/,

    number:
    /\b0x[\da-f]+\b|(?:\b\d+\.?\d*|\B\.\d+)(?:e[+-]?\d+)?/i,

    operator:
    /--?|\+\+?|!=?=?|<=?|>=?|==?=?|&&?|\|\|?|\?|\*|\/|~|\^|%/,

    punctuation:
    /[{}[\];(),.:]/
};

캡쳐한 이미지 Base64로 변환하는 프로그램 만들기 (C#)

첫번째 캡쳐 : 일반적인 붙여넣기(ctrl+v)
두번째 캡쳐 : Base64로 붙여넣기(ctrl+shift+B)

깃허브 경로

옵시디안 사용을 하려다 보니,
이미지가 따로 파일로 저장되는것이 단점 이였다.

*모든 파일마다 _files라는 폴더를 만들어 저장하는데, 생각보다 트리구조가 지저분해짐.

클립보드 내용을 Base64로 만들어 옵시디안에 추가해 주면 좋겠다고 생각하고 있었는데, 그렇게 하는 프로그램을 Python 기반으로 만든 사람이 있었다.

참고 사이트

그런데, PyQt를 해야 하고, 시간을 많이 투자하지 않기 위해
C#으로 자체적으로 만들기로 결정! (오랜만에 하려니 기억이 기억이 잘 안난다. ㅜ,.ㅜ)


1. 기본 프로젝트 생성

File – New – Project
C# 으로 설정하고, WPF App.(.NET Framework) 선택

버튼을 만들어서 시험해본다.

2. Clipboard 이미지를 Base64로 변환

클립 보드가 비어 있지 않고, 이미지 인 경우에만 동작

if ((System.Windows.Clipboard.GetDataObject() != null) && (System.Windows.Clipboard.ContainsImage()))

클립 보드 내용을 파일로 저장함

[참고사이트](Clipboard.GetImage Method (System.Windows) | Microsoft Learn)

 var image = System.Windows.Clipboard.GetImage();
  using (var fileStream = new FileStream(pngFile, FileMode.Create))
  {
   BitmapEncoder encoder = new PngBitmapEncoder();
   encoder.Frames.Add(BitmapFrame.Create(image));
   encoder.Save(fileStream);
  }

PNG 파일을 Base64로 변환

(참고한 사이트가 기억나지 않는다.)

StringBuilder sb = new StringBuilder("<img src=\"data: image / png; base64,");
byte[] imageBytes = File.ReadAllBytes(pngFile);
string base64String = Convert.ToBase64String(imageBytes);
sb.AppendFormat("{1}", filename, base64String);


sb.Remove(sb.Length - 2, 2); 
sb.Append("\" alt = \"\" > "); 

string Text = sb.ToString(); 

Base64 text를 다시 클립 보드에 업데이트

if (Text != null)
{
System.Windows.Clipboard.SetText(Text);
}

2. Hot Key 설정

MouseKeyHook 이라는 nuGet을 사용한다.

reference

초기화 부분에 아래 코드 작성

public MainWindow()
{
InitializeComponent();
HotkeyManager.Current.AddOrReplace("Increment", Key.B, ModifierKeys.Control | ModifierKeys.Shift, ClipboardToBase64);
}

3. ctrl + V

reference

아래 코드를 통해 keybd_event를 사용할 수 있도록 하고,

[DllImport("user32.dll")]
public static extern void keybd_event(byte vk, byte scan, int flags, ref int extrainfo);

Hotkey로 실행되었을 때는 해당 프로그램으로 포커스가 넘어 온상태이므로
ctrl + tab으로 붙여넣기 의도한 프로그램으로 바꾸고,
붙여넣기 함.

int info = 0;
keybd_event((byte)Keys.ControlKey, 0, 0, ref info); 
keybd_event((byte)Keys.Tab, 0, 0, ref info); 
keybd_event((byte)Keys.Tab, 0, 2, ref info); 
keybd_event((byte)Keys.ControlKey, 0, 2, ref info); 
keybd_event((byte)Keys.ControlKey, 0, 0, ref info); 
keybd_event((byte)Keys.V, 0, 0, ref info); 
keybd_event((byte)Keys.V, 0, 2, ref info); 
keybd_event((byte)Keys.ControlKey, 0, 2, ref info); 

keybd_event((byte)Keys.Down, 0, 0, ref info); 
keybd_event((byte)Keys.Down, 0, 2, ref info); 

keybd_event((byte)Keys.Enter, 0, 0, ref info);
keybd_event((byte)Keys.Enter, 0, 2, ref info); 

전체 코드

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using NHotkey.Wpf;
using System.Threading;

namespace ClipToBase64
{


    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public int Handle { get; private set; }

        public MainWindow()
        {
            InitializeComponent();
            HotkeyManager.Current.AddOrReplace("Increment", Key.B, ModifierKeys.Control | ModifierKeys.Shift, ClipboardToBase64);
        }

        [DllImport("user32.dll")]
        public static extern void keybd_event(byte vk, byte scan, int flags, ref int extrainfo);



        [STAThread]
        private void ClipboardToBase64(object sender, NHotkey.HotkeyEventArgs e)
        {

            string filename = "temp";
            string _001 = "d:\\00_Working_Temp\\" + filename + ".png";
            string pngFile = _001;


            if ((System.Windows.Clipboard.GetDataObject() != null) && (System.Windows.Clipboard.ContainsImage()))
            {
                var image = System.Windows.Clipboard.GetImage();
                using (var fileStream = new FileStream(pngFile, FileMode.Create))
                {
                    BitmapEncoder encoder = new PngBitmapEncoder();
                    encoder.Frames.Add(BitmapFrame.Create(image));
                    encoder.Save(fileStream);
                }

                StringBuilder sb = new StringBuilder("<img src=\"data: image / png; base64,");

                byte[] imageBytes = File.ReadAllBytes(pngFile);
                string base64String = Convert.ToBase64String(imageBytes);
                sb.AppendFormat("{1}", filename, base64String);


                sb.Remove(sb.Length - 2, 2);
                sb.Append("\" alt = \"\" > ");

                string Text = sb.ToString();
                if (Text != null)
                {
                    System.Windows.Clipboard.SetText(Text);
                }


                int info = 0;
                keybd_event((byte)Keys.ControlKey, 0, 0, ref info); // Ctrl key 다운
                keybd_event((byte)Keys.Tab, 0, 0, ref info); // Tab key 다운
                keybd_event((byte)Keys.Tab, 0, 2, ref info); // Tab key 업
                keybd_event((byte)Keys.ControlKey, 0, 2, ref info); // Ctrl key 업
                keybd_event((byte)Keys.ControlKey, 0, 0, ref info); // Ctrl key 다운
                keybd_event((byte)Keys.V, 0, 0, ref info); // V key 다운
                keybd_event((byte)Keys.V, 0, 2, ref info); // V key 업
                keybd_event((byte)Keys.ControlKey, 0, 2, ref info); // Ctrl key 업

                keybd_event((byte)Keys.Down, 0, 0, ref info); //  key 다운
                keybd_event((byte)Keys.Down, 0, 2, ref info); // Tab key 업

                keybd_event((byte)Keys.Enter, 0, 0, ref info); //  key 다운
                keybd_event((byte)Keys.Enter, 0, 2, ref info); // Tab key 업
            }
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            ClipboardToBase64(this,null);
        }
    }
} 

Obsidian_수식 폰트 사이즈 키우기(Increase formula font size)

최근 데이터 정리를 위해 옵시디안을 사용하고 있다.
논문 내용을 분석하기 위해 Latex 문법을 이용할 일이 있었다. 분수가 포함된 수식만 글씨 크기가 작아서 읽기 어려운 상황이엇고, 이를 해결할 방법을 찾았다.
참고 사이트

폰트 크기를 수정하기 위해서 css snippet를 사용한다.

  1. 메뉴의 settings -> Appearance -> CSS Snippets로 가서 snippets folder를 연다
  2. . css 파일을 만들어서 아래 문장을 추가한다.(알아보기 쉬운 파일이름).
.MathJax {font-size: 1.2em;}
  1. 옵시디안 화면에서 위에 만든 파일의 이름으로된 부분을 선택해서 활성화 한다.

파일을 업데이트 하면 바로 반영한다.

원본 문서는 1.3으로 숫자가 되어있으나, 한글 폰트와 크기를 봤을 때 1.2가 더 어울리는 것 같아서 변경함.
( $표시를 하나만 사용하는 문장에 수식이 포함된 경우는 1.2, 따로 수식만 보이는 경우는 1.4가 어울렸는데, 1.2로 선택했다. )