The Layout Engine

As in many other areas, TextMate 2's layout engine has received a bunch of improvements under the hood. It's sometimes hard to show these changes, at least until new features taking advantage of the changes begin to bubble up to the surface. Let's take a tour of some of those new features now, so I can show you just how dynamic what renders has become.

In this article will discuss:

  • The replacement of invisible characters
  • Per-line soft wrap and indented soft wrap
  • Dynamic font sizing
  • Folding pattern upgrades

Not So Invisible

When TextMate 2 renders content, certain invisible characters are now shown in a meaningful representation, to you as the user. By way of example, if I type the following line into a shell script file and run it (with ⌃R):

printf "foo\rbar"

TextMate 2 shows me this output:

invisibles

This can help you recognize as hard to detect content is making it's way into your files.

That's a Wrap

Soft wrap has multiple enhancements in TextMate 2. First, it can now be turned on and off by line. Also, you format the wrapped string, which allows for some custom indentation.

A great example of both of these are the new style settings for comments in the Source bundle. Here's a setting bound to the comment.line.number-sign scope (among others):

{   indentedSoftWrap = {
        format = '${0/\S/ /g}';
        match = '.*(##?)\s+';
    };
    softWrap = :true;
}

The softWrap = :true; kicks in soft wrapping for lines ending in this scope. That might be needed because a lot of users prefer not to wrap actual code content. Comments are prose though, so it is probably desirable to treat them differently.

The indentedSoftWrap details give a regular expression to match the line where indenting started, and a Format Strings that will be expanded in terms of that match and prepended to each line.

The effect of these settings is that a trailing comment can now be rendered as such:

Soft Wrapped Comment

It’s worth mentioning that, for the purposes of matching, a line now has a left and a right scope that we can explicitly match against via the new scope selector syntax for selecting on either side. The left scope is the line’s starting scope and the right scope (which is what’s used by default if the selector doesn’t explicitly select side) is the line’s ending scope. We will talk more about the new scope selector syntax in a future article.

Sensible Font Sizing

The first thing I absolutely have to say about font sizing is that proportional width fonts are now supported. You asked for it and Allan added it. Enough said about that.

Another nice new feature is that fonts and their sizing can be altered by scope. For example, Markdown heading now adjust their size depending on the level of the heading. This helps them standout. Here are the settings from the Themes bundle tied to the markup.heading.1 scope:

{   fontName = 'Baskerville';
    fontSize = '2.25em';
}

Now the rule bound to markup.heading.2 uses the same font at a smaller size:

{   fontName = 'Baskerville';
    fontSize = '2.1em';
}

There are rules set for the other headings as well, on down to level six.

Notice that these sizes are being set in em so they will be relative to the rest of the document content. You can also use pt (absolute) or % (relative).

Fold on the Dotted Line

The folding system has been extended with two new patterns to allow indent-based foldings. Let's look at some examples of how this works.

For example, we might want to install these folding pattern settings for C++ (scoped to source.c++):

{ foldingIndentedBlockStart  = '^\s*(public|protected|private):\s*(//.*)?$|^\s*/[*](?!.*[*]/)';
  foldingIndentedBlockIgnore = '^\s*#';
}

The first pattern (foldingIndentedBlockStart) decides what starts a foldable block. In this case it is either a visibility keyword (public/private) or /*.

The latter is to make a comment block like the following foldable:

/*
 *  t_foldings.cc
 *  TextMate 2
 *  
 *  Created by Allan Odgaard on 2011-09-30.
 *  Copyright 2011 MacroMates. All rights reserved.
 */

The second pattern (foldingIndentedBlockIgnore) represents lines to ignore. For C++ this would be preprocessor directives:

   class foldings_t
   {
   public:
      foldings_t (arguments);
#if 0
      virtual ~foldings_t ();
#endif

   private:
      /* data */
   };

This allows us to still fold from public and down to private despite the non-indented preprocessor directives.

For Markdown's folding settings (scoped to text.html.markdown), let's look at some more sneaky patterns:

{  foldingIndentedBlockStart  = '^#+\s+';
   foldingIndentedBlockIgnore = '^(?!#+\s+)';
}

We let a heading be a start marker and then we effectively ignore everything which is not a heading, causing those lines to be included in the foldable block despite not being indented. This allows you to collapse entire sections of a Markdown document down to just the headings.

These are just some of the ways TextMate 2 can now dynamically modify content as it is displayed for you. Expect to see more developments in this area in the future, as the new layout engine gives plenty of room for growth.