Share via


How to: Provide Automatic Brace Matching

When automatic brace matching is enabled, the language service highlights matching braces whenever the user types them. The code in the Babel service also handles brace matching when the user types CTRL+] in Visual Studio. Providing brace matching is done in the following three steps: 

  • Setting Matching Brace Properties

  • Adding Brace Match Rules

  • Adding Triggers

This topic is based on the Visual Studio Language Package solution, which provides a basic implementation of the Babel package. For more information about creating one of these solutions, see Walkthrough: Creating a Language Service Package.

Setting Matching Brace Properties

To enable automatic brace matching, set the following properties in the g_languageProperties global constant in stdservice_cpp:

  • MatchBraces: 1.

  • ShowMatchingBrace: 1. Causes Visual Studio to show the line of the matching brace in the status bar, which is useful when the matching brace is not visible in the view.

  • MatchBracesAtCaret: 1. Causes Visual Studio to highlight matching braces when the caret is positioned on a brace. Otherwise Visual Studio highlights braces only when they are added.

Adding Brace Match Rules

After you have set brace properties, you need to add brace matching rules to the parser specification file. The StdService class provides the matchPair and matchTriple methods to signal matching braces:

Call one of these from your grammar with the locations of the braces whenever a matching pair is found. The following example shows code that matches parenthesized expressions:

ParenExpr
    : '(' Expr ')'   { g_service->matchPair($1,$3); }
    | '(' Expr error 
          { g_service->expectError( "unmatched parenthesis", ")" ); }
    ;

The following example shows how braces are matched when parsing a parameter list:

ParenParams
    :  '(' ')'            { g_service->matchPair($1,$2); }
    |  '(' Params1 ')'    { g_service->matchPair($1,$3); }
    |  '(' Params1 error  { g_service->expectError( "unmatched parenthesis", ")" ); }
    |  '(' error ')'      { g_service->matchPair($1,$3); 
                            g_service->syntaxError( "parameters", &$2 ); }

Adding Triggers

The Babel service uses brace matching triggers, which are specified in the Service::getTokenInfo method.

In the tokenInfoTable array add the TriggerMatchBraces trigger to each token that is should be matched (see TriggerClass Enumeration for more details on triggers). The following example shows how to use triggers:

override const TokenInfo* Service::getTokenInfo() const
{
  static TokenInfo tokenInfoTable[] =
  {
    //TODO: Add your token information here.
    { IDENTIFIER, ClassIdentifier,  "identifier '%s'",  CharIdentifier },
    ...
    { KWVOID, ClassKeyword, "void", CharKeyword   },
    { '(',    ClassText,  "'('"   , CharDelimiter, TriggerMatchBraces }, 
    { ')',    ClassText,  "')'"   , CharDelimiter, TriggerMatchBraces },
    { '{',    ClassText,  "'{'"   , CharDelimiter, TriggerMatchBraces },
    { '}',    ClassText,  "'}'"   , CharDelimiter, TriggerMatchBraces },
    { '.',    ClassText,  "'.'"   , CharDelimiter },
    ...
    //Always end with the 'TokenEnd' token.
    { TokenEnd,     ClassText,      "<unknown>"   }
  };

  return tokenInfoTable;
};

Change History

Date

History

Reason

July 2008

Rewrote and refactored project.

Content bug fix.