Rogue ๋Œ€์‹  Codemirror!

#codemirror
#jekyll
Suggest Edit

์‹ ํƒ์Šค ํ•˜์ด๋ผ์ดํŠธ์— JSX๊ฐ€ ์ œ๋Œ€๋กœ ์ž‘๋™ํ•˜์ง€ ์•Š๋Š” ๋“ฏํ•ด์„œ jneen/rouge์˜ ์ด์ŠˆํŠธ๋ž˜์ปค๋ฅผ ๋ณด๋‹ˆ ์ด๋Ÿฐ ์ฝ”๋ฉ˜ํŠธ๊ฐ€ ์žˆ์–ด์„œ ๋†€๋žฌ์Šต๋‹ˆ๋‹ค.

zackify: Any status update on this?

jneen: No

๋ฌผ๋ก  ์ง€๊ธˆ์€ ๋Œ€์‘ํ•˜๋Š” ๊ฒƒ ๊ฐ™์€๋ฐ ์ง€ํ‚ฌ์—์„œ ์–ด๋–ป๊ฒŒ ์“ฐ๋Š”์ง€ ์ž˜ ๋ชจ๋ฅด๊ฒ ๋„ค์š”. ํฌ๋žจ๋‹ค์šด๋„ ๋„ํ๋ฉ˜ํŠธ๊ฐ€ ์˜ค๋ž˜๋˜์–ด๋ณด์ด๊ณ ... ์—ญ์‹œ ๊ทธ๋ƒฅ ์ต์ˆ™ํ•œ ๋ฐฉ์‹๋Œ€๋กœ ํ•˜๋Š”๊ฒŒ ๋งž๋Š” ๊ฒƒ ๊ฐ™์•„์„œ ์ต์ˆ™ํ•œ CodeMirror๋กœ Rogue๋Œ€์‹ ์— ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ์‹ ํƒ์Šค ํ•˜์ด๋ผ์ดํŠธ๋ฅผ ์ฒ˜๋ฆฌํ•ด ๋ณด์•˜์Šต๋‹ˆ๋‹ค.

Disable Rogue

๋จผ์ € ๋กœ๊ทธ๋ฅผ ๊บผ์•ผ๊ฒ ์ฃ ...

_config.yml์—์„œ ํฌ๋žจ๋‹ค์šด์˜ ํ•˜์ด๋ผ์ดํŠธ ์˜ต์…˜์„ ์ˆ˜์ •ํ•ฉ๋‹ˆ๋‹ค.

markdown: kramdown
kramdown:
  syntax_highlighter_opts:
    disable: true

Apply Codemirror

์ข€ ๋งŽ์€ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ๋™์‹œ์— ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

  • Lodash : forEach์™€ unescape๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์”๋‹ˆ๋‹ค.
  • Runmode : ์—๋””ํ„ฐ๊ฐ€ ์•„๋‹ˆ๋ผ ๋ Œ๋”๋ง๋งŒ ํ•˜๋Š” ๋ชจ๋“œ์ž…๋‹ˆ๋‹ค. ์ฝ”๋“œ๋ฏธ๋Ÿฌ ๋ณธ์ฒด๋ฅผ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š๊ณ ๋„ ์“ธ ์ˆ˜ ์žˆ๋Š” ์Šคํƒ ๋“œ์–ผ๋ก ๋„ ์žˆ์ง€๋งŒ ๋ชจ๋“œ๊ฒ€์ƒ‰๋“ฑ์˜ ๋‹ค๋ฅธ ๋ชจ๋“ˆ์„ ์ด์šฉํ•˜๊ธฐ์œ„ํ•ด ์• ๋“œ์˜จ์œผ๋กœ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • Meta : ์ฝ”๋“œ๋ฏธ๋Ÿฌ์—์„œ ์‚ฌ์šฉ๊ฐ€๋Šฅํ•œ ์‹ ํƒ์Šค ๋ชจ๋“œ ๋ฆฌ์ŠคํŠธ์™€ ์ด๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ์œ„ํ•œ ๋ฉ”์†Œ๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์ค๋‹ˆ๋‹ค.
  • Load Mode : ์ง์ ‘ ์‹ ํƒ์Šค๋ชจ๋“œ๋ฅผ ๋ถ€๋ฅผ ํ•„์š”์—†์ด ํ•„์š”ํ•  ๊ฒฝ์šฐ์—๋งŒ ๋ถ€๋ฅผ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.(์ˆ˜์‹ญ๊ฐœ์˜ ๋ชจ๋“œ๋ฅผ ์ง์ ‘ ๋ถˆ๋Ÿฌ์˜ค๋Š”๊ฑด ๊ทธ๋‹ค์ง€ ์œ ์พŒํ•˜์ง€ ์•Š์„๊ฒ๋‹ˆ๋‹ค.)
  • Overlay : HTML์˜ <script>์— ์“ฐ์ด๋Š” Javascript๋‚˜ Markdown์˜ Code Fence์— ์“ฐ์ด๋Š” ๊ฐ์ข… ์ฝ”๋“œ๋ฅผ ์œ„ํ•ด ๋ณต์ˆ˜์˜ ์‹ ํƒ์Šค๋ชจ๋“œ๋ฅผ ๊ฒน์ณ์“ฐ๊ฒŒ ํ•ด์ค๋‹ˆ๋‹ค.
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.22.2/codemirror.min.css">
<!-- ์ €๋Š” Dracula ํ…Œ๋งˆ๋ฅผ ์“ธ ๊ฒ๋‹ˆ๋‹ค -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.22.2/theme/dracula.min.css">

<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.22.2/codemirror.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.22.2/addon/runmode/runmode.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.22.2/mode/meta.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.22.2/addon/mode/loadmode.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.22.2/addon/mode/overlay.min.js"></script>
<script>

// ์–ด๋””์„œ ๋ชจ๋“œ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ์ง€๋ฅผ ์ ์–ด์ค๋‹ˆ๋‹ค.
CodeMirror.modeURL = 'https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.22.2/mode/%N/%N.js'
var codeBlocks = document.querySelectorAll('pre code')

// ์ €๋Š” JSX๋ฅผ ์ฃผ๋กœ ์“ฐ๋ฏ€๋กœ js๋‚˜ javascript ๋ชจ๋‘ JSX๋กœ ์ฒ˜๋ฆฌํ•˜๊ฒŒ ํ–ˆ์Šต๋‹ˆ๋‹ค.
function parseMode (mode) {
  switch (mode) {
    case 'js':
    case 'javascript':
      mode = 'jsx'
  }
  let syntax = CodeMirror.findModeByName(mode)
  if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
  return syntax
}

_.forEach(codeBlocks, block => {
  // ํด๋ž˜์Šค์˜ ํ”„๋ฆฌํ”ฝ์Šค `language-`๋ฅผ ์ง€์šฐ๊ณ  ๋ชจ๋“œ๋ฅผ ํŒŒ์Šคํ•ฉ๋‹ˆ๋‹ค.
  var syntax = parseMode(block.className.substring(9))

  CodeMirror.requireMode(syntax.mode, () => {
    // ์ด๋ฏธ ์ด์Šค์ผ€์ดํ”„๋œ `&gt;`๋“ฑ ์—”ํ‹ฐํ‹ฐ๋ฅผ `>`๋กœ ๋Œ๋ ค์ค๋‹ˆ๋‹ค
    var value = _.unescape(block.innerHTML)
    // ๋Ÿฐ๋ชจ๋“œ ์ „์— ๋‚ด์šฉ์„ ๋‹ค ์ •๋ฆฌํ•ด๋‘ก๋‹ˆ๋‹ค.
    block.innerHTML = ''
    // ํ…Œ๋งˆ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค
    block.parentNode.className = `cm-s-dracula CodeMirror`
    // ๋ Œ๋”๋ฅผ ์‹œ์ž‘ํ•ฉ๋‹ˆ๋‹ค
    CodeMirror.runMode(value, syntax.mime, block, {
      tabSize: 2
    })
  })
})
</script>

์ด์ƒ์ž…๋‹ˆ๋‹ค. ์ด์ œ ํŽ˜์ด์ง€๊ฐ€ ์—ด๋ฆฌ๋ฉด <pre><code>๋ฅผ ์ž๋™์œผ๋กœ ๊ฒ€์ƒ‰ํ•ด์„œ ์ฝ”๋“œ๋ฏธ๋Ÿฌ๋กœ ๋ Œ๋”๋ง ํ•˜๊ฒŒ ๋ ๊ฒ๋‹ˆ๋‹ค.