Sublime Forum

Syntax Highlighting for Plain Text [noobie asking]

#1

Ok, I don’t even know if I’m asking this in the right place, and pardon me if I appear out-of-space dumb by asking this –

But how the hell do I create a Syntax Highlight for good ol’ Plain Text (.txt) format?

All I want are for lines starting in ALL CAPS to be a certain color, (necessary)
lines starting with ** to be another, (necessary)
and ideally have words between asterisks bold. (optional)

To clear it up, I’m not a coder, but a copywriter, and I bought Sublime because I love its feel and editing powers, and I’ve setup everything literally the way I want to, except this piece…

Help appreciated with head held down for my aversion of technical documentation.

Cheers,
nws

0 Likes

#2

There is two things:

  • First a syntax file to indicate to sublime what you want to highlight, using regular expression. This is described at http://www.sublimetext.com/docs/3/syntax.html
  • To each regular expression you associate a scope (a kind of identifier) that will then be used by the color scheme to decide how the text will be shown (character color, line color, bold, italic, …) For this you can either try to find existing scope supported by your current color scheme, or just create a new one (typically starting from an existing one and adding your new scopes).

I just created very quickly a syntax that might be a good starting point for you, using the markdown scope usually supported by many color scheme:

%YAML 1.2
---
# http://www.sublimetext.com/docs/3/syntax.html
name: My Plain Text
file_extensions: [txt]
scope: source.txt
contexts:
  main:
    # Line starting in all caps
    - match: '^[A-Z_]+\b.*'
      push:
        - meta_scope: markup.heading
        - match: '$\n?'
          pop: true
    # Line starting with **
    - match: '^\*\*.*'
      push:
        - meta_scope: meta.separator
        - match: '$\n?'
          pop: true
    # Words surrounded by *
    - match: '(\*)(\w+)(\*)'
      captures:
        1: punctuation.definition.bold.begin
        2: markup.bold
        3: punctuation.definition.bold.end

Just Copy/paste that and save it like myplaintest.sublime-syntax in your user package directory (Preferences->Browse package, then you should see a user directory).
And then just open a text file, use the menu in bottom-right and select “open all with current extensions”->user->My Plain Text

5 Likes

Modify Markdown.sublime-syntax file to add hashtag
#3

Yeeep! That’s exactly what I wanted.

Massive thanks, mr Clams, you’ve made my day :slight_smile:

0 Likes

#4

It may be good to change the base scope to text.txt, i.e. scope: text.plain.txt instead of scope: source.txt, because some keybindings, completions, etc. behaves different on source and text scopes.

1 Like

#5

Done. Not really seeing any changes, but if it’s a good idea, let it stay. Thanks.

0 Likes

#6

Thank you for the info, I was looking for exact same thing.

I’m not a programmer, I just like to customize the tools I use.

I managed to modify a bit your example, apply some scopes and put my matches.

However, I’d like to understand better how to apply highlighting and how to customize it.
I found the page where Monokai theme scopes are shown (but not in detail) but I can’t
find the explanation how punctuation.definition.bold.begin type of command works and the syntax.
Also, Is there a way to change background color of matched text?

Thanks

0 Likes

#7

There are two main bits that tie together for how the contents of the buffer are colored (as @Clams mentioned):

  1. A syntax definition is created that applies scopes to the text based on matching patterns

  2. A Color Scheme (e.g. Monokai) is used to say what colors and text styles each scope should visually look like

As outlined above, Clams used well known scopes so that things would highlight without having to go to any more steps. Basically the idea is that the two parts interact with each other and require some common conventions to ensure that everything looks good for people regardless of what language they’re working with or what color scheme they’re using.

Using the example syntax provided above, there is this match for finding words that are contained within literal * characters:

    # Words surrounded by *
    - match: '(\*)(\w+)(\*)'
      captures:
        1: punctuation.definition.bold.begin
        2: markup.bold
        3: punctuation.definition.bold.end

The first literal * has the scope punctuation.definition.bold.begin, the word itself has the scope markup.bold, and the last literal * has the scope punctuation.definition.bold.end.

Now, if we look inside of the Monokai.tmTheme file (you can view using PackageResourceViewer to open Color Scheme - Default/Monokai.tmTheme), we will see (among a couple of other settings) a series of sections that define the colors for specific scopes.

Doing a search for markup.bold turns up this as the first of two hits:

<dict>
    <key>name</key>
    <string>markup bold</string>
    <key>scope</key>
    <string>markup.bold</string>
    <key>settings</key>
    <dict>
        <key>fontStyle</key>
        <string>bold</string>
    </dict>
</dict>

The data is in an alternating key-value ordering (the file format is an uncompressed XML PList file with a different extension). This is telling us that this section is named markup bold, that it affects the scope markup.bold, and that the settings for this scope specify that anything that has this scope should have a bold font style.

The second hit on this search term is this one:

<dict>
    <key>name</key>
    <string>markup bold/italic</string>
    <key>scope</key>
    <string>markup.italic markup.bold | markup.bold markup.italic</string>
    <key>settings</key>
    <dict>
        <key>fontStyle</key>
        <string>bold italic</string>
    </dict>
</dict>

This one has a slightly different looking scope definition, which we will talk about in a moment. However for now it’s enough to notice that it includes bold and italic in what looks like two different orders, and specifies a font style that includes both styles.

Now, if we search for punctuation.definition.bold.begin or punctuation.definition.bold.end, there are no hits. However if you’re using this sample you can clearly see that the * characters with these scopes are being colored.

The “trick” here is that scopes can be made more or less specific by appending more suffixes to them, which is part of the real power of the system. There are no matches for these two specific scopes, but if you drop the first suffix off of one of them and search for punctuation.definition.bold instead, you find this:

<dict>
    <key>name</key>
    <string>markup punctuation</string>
    <key>scope</key>
    <string>text &amp; (punctuation.definition.italic | punctuation.definition.bold | punctuation.definition.raw | punctuation.definition.link | punctuation.definition.metadata | punctuation.definition.image | punctuation.separator.table-cell | punctuation.section.table-header | punctuation.definition.constant)</string>
    <key>settings</key>
    <dict>
        <key>foreground</key>
        <string>#F8F8F8AA</string>
    </dict>
</dict>

This is another one of those more complicated looking scope definitions (made more complicated by having to use &amp instead of & to be valid XML), but it looks like it has a bunch of different punctuation styles in it, and that the rule that matches it specifies a particular color.

A little experimentation will show that modifying the value of that color will change the color that the literal * marks are rendered with in the buffer.

To get back around to that whole scope issue thing, scopes in Sublime work somewhat like CSS selectors, allowing you to specify a particular hierarchy and specificity to dial in what you want.

In the case of the second hit for markup.bold, we saw this scope:

markup.italic markup.bold | markup.bold markup.italic

This is saying that any text that has the scopes “markup.italic and markup.bold” OR “markup.bold and markup.italic” should be highlighted this way. The distinction is important because scopes are applied in matched order (i.e. in a hierarchy), and so we want to make sure that this rule matches and works regardless of whether you started italic and went bold or started bold and went italic.

The more complicated scope we found for punctuation.definition.bold is saying that the scope has to start out being text and then be one of the following punctuation definitions, and if so that particular color should be used to highlight the text.

As you can probably guess, the addition of the .begin and .end on the scopes in the example match provide a higher level of specificity to those tokens; if you wanted to, you could make each specific * in this case a different color depending on whether they are the begin or end of the bold section, for example.

This extra specificity comes in handy because these scopes are used in places other than syntax highlighting, such as in snippets to indicate where they should trigger, in build systems to say when they’re available based on the language, in key bindings that want to only activate in certain situations, and so on.

There is a guide on scope naming that outlines best practices for both authors of syntax definitions as well as color scheme designers. There is also a guide on color schemes which explains the various options you have in more detail. There you’ll find how to also change the background color, for example.

While you’re working, you can use the Tools > Developer > Show Scope Name menu item (or it’s associated key binding, which you can see in the menu) to show you the exact scope that is present at the current cursor location.

I also wrote the following forum post a ways back that has more information on scopes and how you can apply them, which may come in handy for dialing in your new color scheme to catch the parts that you want (or as a potentially more in depth explanation for how scopes work in general).

4 Likes

#8

Dear Odat,

Thank you very much for your reply.

I must admit that all that information is overwhelming.

Maybe you can be so kind to give me just a few examples of how to
specify different foreground and background color for the matched regex?

Thanks.

0 Likes