summaryrefslogtreecommitdiff
path: root/java/java-impl/src/com/intellij/codeInsight/highlighting/PairedBraceAndAnglesMatcher.java
blob: e85fec2ae52433b979d44f39175cd4ac28ebc5ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.codeInsight.highlighting;

import com.intellij.lang.BracePair;
import com.intellij.lang.Language;
import com.intellij.lang.PairedBraceMatcher;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.LanguageFileType;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.TokenSet;
import org.jetbrains.annotations.NotNull;

public abstract class PairedBraceAndAnglesMatcher extends PairedBraceMatcherAdapter {
  private final TokenSet myTokenSetAllowedInsideAngleBrackets;
  private final LanguageFileType myFileType;

  public PairedBraceAndAnglesMatcher(@NotNull PairedBraceMatcher matcher,
                                     @NotNull Language language,
                                     @NotNull LanguageFileType fileType,
                                     @NotNull TokenSet tokenSetAllowedInsideAngleBrackets) {
    super(matcher, language);
    myTokenSetAllowedInsideAngleBrackets = tokenSetAllowedInsideAngleBrackets;
    myFileType = fileType;
  }

  @Override
  public boolean isLBraceToken(@NotNull HighlighterIterator iterator, @NotNull CharSequence fileText, @NotNull FileType fileType) {
    return isBrace(iterator, fileText, fileType, true);
  }

  @Override
  public boolean isRBraceToken(@NotNull HighlighterIterator iterator, @NotNull CharSequence fileText, @NotNull FileType fileType) {
    return isBrace(iterator, fileText, fileType, false);
  }

  public abstract @NotNull IElementType lt();

  public abstract @NotNull IElementType gt();

  private boolean isBrace(HighlighterIterator iterator,
                          CharSequence fileText,
                          FileType fileType,
                          boolean left) {
    final BracePair pair = findPair(left, iterator, fileText, fileType);
    if (pair == null) return false;

    final IElementType opposite = left ? gt() : lt();
    if ((left ? pair.getRightBraceType() : pair.getLeftBraceType()) != opposite) return true;

    if (fileType != myFileType) return false;

    final IElementType braceElementType = left ? lt() : gt();
    int count = 0;
    try {
      int paired = 1;
      while (true) {
        count++;
        if (left) {
          iterator.advance();
        }
        else {
          iterator.retreat();
        }
        if (iterator.atEnd()) break;
        final IElementType tokenType = iterator.getTokenType();
        if (tokenType == opposite) {
          paired--;
          if (paired == 0) return true;
          continue;
        }

        if (tokenType == braceElementType) {
          paired++;
          continue;
        }

        if (!myTokenSetAllowedInsideAngleBrackets.contains(tokenType)) {
          return false;
        }
      }
      return false;
    }
    finally {
      while (count-- > 0) {
        if (left) {
          iterator.retreat();
        }
        else {
          iterator.advance();
        }
      }
    }
  }
}