Create a custom mode

Hello :slight_smile:

I’m trying to create a custom mode and I started by using Simple Mode addon. Although, I’ve already noticed some of its limitation and I’d like to know if you could help me.

CodeMirror.defineSimpleMode('simplemode', {
 // The start state contains the rules that are intially used
 start: [
   {regex: /* .*/, token: 'ul', sol: true},
   {regex: /### .*/, token: 'header-3', sol: true},
   {regex: /## .*/, token: 'header-2', sol: true},
   {regex: /# .*/, token: 'header-1', sol: true},
   {regex: /\[.*]\(.*\)/, token: 'link'},
   {regex: /(#.*#)/, token: 'tag'},
   {regex: /(#[\w/]+)/, token: 'tag'},
   {regex: /(#\w+)/, token: 'tag'},
   {regex: /::.*?(::)/, token: 'marker'},
   {regex: /\*.*?(\*)/, token: 'bold'},
   {regex: /\/.*?(\/)/, token: 'italic'},
   {regex: /_.*?(_)/, token: 'underline'},
   {regex: /-.*?-/, token: 'strikethrough'}
 ]
})

The first thing is that {regex: /\[.*]\(.*\)/, token: 'link'} is not being highlighted in the following case (and some others): /test [link](https://go.com). I get /test [link](https:/ highlighted as an italic. How do I make the link thing to be prioritized?

The second thing: I want to nest some of the tokens, like:

*bold /this italic but still bold/*

Which is not working now.

Another thing is with the first rule: {regex: /* .*/, token: 'ul', sol: true},. If it matches, nothing else in that sentence is going to be matched…

How should I create a Mode that accomplishes this?

Thanks :slight_smile:

I tried with:

CodeMirror.defineMode('polar', function () {
  return {
    token: function (stream, state) {
      if (stream.match('### ')) {
        stream.skipToEnd()
        return 'header-3'
      }

      if (stream.match('## ')) {
        stream.skipToEnd()
        return 'header-2'
      }

      if (stream.match('# ')) {
        stream.skipToEnd()
        return 'header-1'
      }

      if (stream.match('#')) {
        if (stream.skipTo('#')) {
          stream.next()
          return 'tag'
        }

        if (!stream.eatWhile(/[\w/]/)) {
          return null
        }

        return 'tag'
      }

      if (stream.match('*')) {
        if (!stream.skipTo('*')) {
          return null
        }

        stream.next()
        return 'bold'
      }

      if (stream.match('/')) {
        if (!stream.skipTo('/')) {
          return null
        }

        stream.next()
        return 'italic'
      }

      if (stream.match('_')) {
        if (!stream.skipTo('_')) {
          return null
        }

        stream.next()
        return 'underline'
      }

      if (stream.match('-')) {
        if (!stream.skipTo('-')) {
          return null
        }

        stream.next()
        return 'strikethrough'
      }

      if (stream.match('::')) {
        if (!stream.skipTo('::')) {
          return null
        }

        stream.next()
        stream.next()
        return 'marker'
      }

      stream.skipToEnd()
      return null
    }
  }
})

But this way it only matches if we’re in the beginning of a line.

For a markdown-ish language with nesting markup, I’m not sure the simple mode framework will be very useful. You might have more luck writing a mode directly using the mode interface, or wrapping the Markdown mode somehow.

1 Like

Thanks :slight_smile: Already found out how to do this!