15

I want to write a syntax definition file for Sublime Text 2 for the Find Results that respects the file extensions for each place it finds the searched for term. The documentation mentions that "Syntax definitions from separate files can be combined" but does not mention how.

Does anyone have any examples of how that works? An answer to this question: Sublime Text 2: Setting file syntax inside the file itself (as Vim modelines) would work also.

EDIT

Ok, so tip one from a friend: http://manual.macromates.com/en/language_grammars

That uses the 'include' tag with a name to reference another language. That would work for me, but unfortunately I'd need to write a plugin to re-compile the file every time Sublime Text opened and re-write it with the various language extensions...Any chance y'all have a better idea?

6

1 Answer 1

23
+250

Recently, I obsessively tricked out my ST2 CSS syntax highlighting. My understanding of these *.tmLanguage files is based on trial and error--mostly error. I mention this to note my grasp is spotty, at best.

I think the file you want to modify is ~/Library/Application Support/Sublime Text 2/Packages/Default/Find Results.hidden-tmLanguage

Long story short, I think you want to set it up like this gist (which has liberal commenting):

https://gist.github.com/4333623#file-find-results-hidden-tmlanguage

A typical Find in files results will look something like this:

Searching 11 files for "feedback-assistance-form" (regex)

/_projects/___/group_reg.js:
   60       });
   61  
   62:      $asstForm = $help.find('#feedback-assistance-form');
   63  
   64       if (!$asstForm.length) {
   65:          console.log('WARN: Feedback assistance: #feedback-assistance-form not found');
   66           return;
   67       }

/_projects/___/group_register_help_tmpl.html:
    6  <div id="group-reg-help">
    7  
    8:  <form id="feedback-assistance-form" class="js-popover help-content hide" action="{% url info.views.assistance_request %}" method="post">
    9       
   10       <legend>Need Assistance?</legend>

3 matches across 2 files

The Find Results.hidden-tmLanguage parses the results into 3 relevant parts:

  • The line with the filename
  • An excerpted line without a match
  • An excerpted line with a match

The rules for this are in the <patterns> section:

<key>patterns</key>
<array>
    <dict>
        <key>match</key>
        <string>^([^ ].*):$</string>
        <key>captures</key>
        <dict>
            <key>1</key>
            <dict>
                <key>name</key>
                <string>entity.name.filename.find-in-files</string>
            </dict>
        </dict>
    </dict>
    <dict>
        <key>match</key>
        <string>^ +([0-9]+) </string>
        <key>captures</key>
        <dict>
            <key>1</key>
            <dict>
                <key>name</key>
                <string>constant.numeric.line-number.find-in-files</string>
            </dict>
        </dict>
    </dict>
    <dict>
        <key>match</key>
        <string>^ +([0-9]+):</string>
        <key>captures</key>
        <dict>
            <key>1</key> <!-- capture group 1 -->
            <dict>
                <key>name</key>  <!-- name it so it can be colored -->
                <string>constant.numeric.line-number.match.find-in-files</string>
            </dict>
        </dict>
    </dict>
</array>

These just go through the file, line-by-line, and look for a match. If a match is found, one or more <key>name</key> definitions are applied to the capturing group(s) of the match, if there are any. These name definitions are referenced in the theme definition file (for instance, Monokai) and the color is applied to the characters matched by the named capturing group.

The patterns above are just matches with capturing groups. I think a limitation of this is the match (or it's capturing groups) can't be further processed.

What's applied in the gist are patterns of the format:

<key>patterns</key>
<array>
    <dict>
        <key>begin</key>

<!-- add the filetype extensions, here -->
<!-- these are XML formatted files: -->

        <string>^([^ ].*\.(?:xml|tmLanguage|hidden-tmLanguage|tmTheme):)$</string>
        <key>beginCaptures</key>
        <dict>
            <key>1</key>
            <dict>
                <key>name</key>
                <string>entity.name.filename.find-in-files</string>
            </dict>
        </dict>
        <key>end</key>
        <string>^[^ ]</string>
        <key>patterns</key>
        <array>
            <dict>
                <key>include</key>
                <string>#line-numbers</string>
            </dict>
            <dict>
                <key>include</key>


<!-- which syntax should match up to the filetype extensions listed above: -->
<!-- to find out what the "scopeName" is, refer to the corresponding *.tmLanguage file -->
<!-- for XML, this is ~/Library/Application Support/Sublime Text 2/Packages/XML/XSL.tmLanguage -->

                <string>text.xml</string>
            </dict>
        </array>
    </dict>
    <!-- ... can have many more -->
</array>

The main thing with this type of pattern is it has a <begin> and an <end>, then it has it's own <pattern> section. When the <begin> regex is matched, the contents of <patterns> are applied until (this is where I get really spotty) an unmatched token is encountered, at which point the <end> is tested. I think.

In any event, the gist defines several of these begin-end-patterns blocks, one for each XML, HTML, JavaScript and CSS file types and syntaxes. The <being> regex matches the line with the filename and a particular file extension. This is used to create the start of the "context" for a given syntax. The context ends when elements in the subsequent <patterns> block stop matching and the <end> regex matches. I think you will basically just want to flesh this out for whichever syntaxes you want to highlight in find results...

Here is a screenshot of the syntax-highlighted find results I am getting using that gist:

Blingwear

I should note, a big issue I encountered is when a block-comment starts in an excerpt but the excerpt doesn't include the characters that end the block-comment. The block-comment just continues until the terminating token is encountered somewhere else in the find results. This extends into subsequent searches, as well.

Update:

I meant to add that you shouldn't need to recompile anything on startup. Although, it's worth mentioning that you have to restart sublime for the changes in Find Results.hidden-tmLanguage to take effect. If you make this a plugin of some sort, seems like changes would primarily consist of adding new languages, which could just be an infrequent plugin-update.

2
  • 1
    @ChristopherPfohl Thanks! Yeah, im pretty stoked. And, if you find a way around the issue with block comments, please post an update.
    – tiffon
    Commented Dec 19, 2012 at 22:04
  • 1
    Thanks for this. I've added some instructions for ST3 users in the comments of the gist
    – Dogoku
    Commented Feb 11, 2014 at 13:11

Not the answer you're looking for? Browse other questions tagged or ask your own question.