message: regex match
diff: import { Position, PositionDiff } from './../motion/position';
  +import { TextEditor } from "./../textEditor";
  import * as vscode from 'vscode';
  +function escapeRegExpCharacters(value: string): string {
  + return value.replace(/[\-\\\{\}\*\+\?\|\^\$\.\,\[\]\(\)\#\s]/g, '\\$&');
  +}
  +
  +let toReversedString = (function () {
  +
  + function reverse(str: string): string {
  + let reversedStr = '';
  + for (let i = str.length - 1; i >= 0; i--) {
  + reversedStr += str.charAt(i);
  + }
  + return reversedStr;
  + }
  +
  + let lastInput: string = '';
  + let lastOutput: string = '';
  + return function toReversedString(str: string): string {
  + if (lastInput !== str) {
  + lastInput = str;
  + lastOutput = reverse(lastInput);
  + }
  + return lastOutput;
  + };
  +})();
  +
  /**
  * PairMatcher finds the position matching the given character, respecting nested
  * instances of the pair.
  @@ -45,23 +71,80 @@ export class PairMatcher {
  return undefined;
  }
  + let regex = new RegExp('(' + escapeRegExpCharacters(charToMatch) + '|' + escapeRegExpCharacters(toFind.match) + ')', 'i');
  +
  let stackHeight = closed ? 0 : 1;
  let matchedPosition: Position | undefined = undefined;
  - for (const { char, pos } of Position.IterateDocument(position, toFind.nextMatchIsForward)) {
  - if (char === charToMatch) {
  + // find matched bracket up
  + if (!toFind.nextMatchIsForward) {
  + for (let lineNumber = position.line; lineNumber >= 0; lineNumber--) {
  + let lineText = TextEditor.getLineAt(new Position(lineNumber, 0)).text;
  + let startOffset = lineNumber === position.line ? lineText.length - position.character - 1 : 0;
  +
  + while (true) {
  + let queryText = toReversedString(lineText).substr(startOffset);
  + if (queryText === '') {
  + break;
  + }
  +
  + let m = queryText.match(regex);
  +
  + if (!m) {
  + break;
  + }
  +
  + let matchedChar = m[0];
  + if (matchedChar === charToMatch) {
  stackHeight++;
  }
  - if (char === toFind.match) {
  + if (matchedChar === toFind.match) {
  stackHeight--;
  }
  if (stackHeight === 0) {
  - matchedPosition = pos;
  + matchedPosition = new Position(lineNumber, lineText.length - startOffset - m.index! - 1);
  + return matchedPosition;
  + }
  + startOffset = startOffset + m.index! + 1;
  + }
  + }
  + } else {
  + for (let lineNumber = position.line, lineCount = TextEditor.getLineCount(); lineNumber < lineCount; lineNumber++) {
  + let lineText = TextEditor.getLineAt(new Position(lineNumber, 0)).text;
  + let startOffset = lineNumber === position.line ? position.character : 0;
  +
  + while (true) {
  + let queryText = lineText.substr(startOffset);
  + if (queryText === '') {
  + break;
  + }
  +
  + let m = queryText.match(regex);
  +
  + if (!m) {
  break;
  }
  +
  + let matchedChar = m[0];
  + if (matchedChar === charToMatch) {
  + stackHeight++;
  + }
  +
  + if (matchedChar === toFind.match) {
  + stackHeight--;
  + }
  +
  + if (stackHeight === 0) {
  + matchedPosition = new Position(lineNumber, startOffset + m.index!);
  + return matchedPosition;
  + }
  +
  + startOffset = startOffset + m.index! + 1;
  + }
  + }
  }
  if (matchedPosition) {
  