private JComponent createActionLink(
     final String text, final String groupId, Icon icon, boolean focusListOnLeft) {
   final Ref<ActionLink> ref = new Ref<ActionLink>(null);
   AnAction action =
       new AnAction() {
         @Override
         public void actionPerformed(@NotNull AnActionEvent e) {
           ActionGroup configureGroup =
               (ActionGroup) ActionManager.getInstance().getAction(groupId);
           final PopupFactoryImpl.ActionGroupPopup popup =
               (PopupFactoryImpl.ActionGroupPopup)
                   JBPopupFactory.getInstance()
                       .createActionGroupPopup(
                           null,
                           new IconsFreeActionGroup(configureGroup),
                           e.getDataContext(),
                           JBPopupFactory.ActionSelectionAid.SPEEDSEARCH,
                           false,
                           ActionPlaces.WELCOME_SCREEN);
           popup.showUnderneathOfLabel(ref.get());
           UsageTrigger.trigger("welcome.screen." + groupId);
         }
       };
   ref.set(new ActionLink(text, icon, action));
   ref.get().setPaintUnderline(false);
   ref.get().setNormalColor(getLinkNormalColor());
   NonOpaquePanel panel = new NonOpaquePanel(new BorderLayout());
   panel.setBorder(JBUI.Borders.empty(4, 6, 4, 6));
   panel.add(ref.get());
   panel.add(createArrow(ref.get()), BorderLayout.EAST);
   installFocusable(panel, action, KeyEvent.VK_UP, KeyEvent.VK_DOWN, focusListOnLeft);
   return panel;
 }
  /**
   * remove highlights (bounded with <marker>...</marker>) from test case file
   *
   * @param document document to process
   */
  private void extractExpectedHighlightsSet(final Document document) {
    final String text = document.getText();

    final Set<String> markers = myHighlightingTypes.keySet();
    final String typesRx = "(?:" + StringUtil.join(markers, ")|(?:") + ")";
    final String openingTagRx =
        "<("
            + typesRx
            + ")"
            + "(?:\\s+descr=\"((?:[^\"]|\\\\\"|\\\\\\\\\"|\\\\\\[|\\\\\\])*)\")?"
            + "(?:\\s+type=\"([0-9A-Z_]+)\")?"
            + "(?:\\s+foreground=\"([0-9xa-f]+)\")?"
            + "(?:\\s+background=\"([0-9xa-f]+)\")?"
            + "(?:\\s+effectcolor=\"([0-9xa-f]+)\")?"
            + "(?:\\s+effecttype=\"([A-Z]+)\")?"
            + "(?:\\s+fonttype=\"([0-9]+)\")?"
            + "(?:\\s+textAttributesKey=\"((?:[^\"]|\\\\\"|\\\\\\\\\"|\\\\\\[|\\\\\\])*)\")?"
            + "(?:\\s+bundleMsg=\"((?:[^\"]|\\\\\"|\\\\\\\\\")*)\")?"
            + "(/)?>";

    final Matcher matcher = Pattern.compile(openingTagRx).matcher(text);
    int pos = 0;
    final Ref<Integer> textOffset = Ref.create(0);
    while (matcher.find(pos)) {
      textOffset.set(textOffset.get() + matcher.start() - pos);
      pos = extractExpectedHighlight(matcher, text, document, textOffset);
    }
  }
  private int extractExpectedHighlight(
      final Matcher matcher,
      final String text,
      final Document document,
      final Ref<Integer> textOffset) {
    document.deleteString(textOffset.get(), textOffset.get() + matcher.end() - matcher.start());

    int groupIdx = 1;
    final String marker = matcher.group(groupIdx++);
    String descr = matcher.group(groupIdx++);
    final String typeString = matcher.group(groupIdx++);
    final String foregroundColor = matcher.group(groupIdx++);
    final String backgroundColor = matcher.group(groupIdx++);
    final String effectColor = matcher.group(groupIdx++);
    final String effectType = matcher.group(groupIdx++);
    final String fontType = matcher.group(groupIdx++);
    final String attrKey = matcher.group(groupIdx++);
    final String bundleMessage = matcher.group(groupIdx++);
    final boolean closed = matcher.group(groupIdx) != null;

    if (descr == null) {
      descr = ANY_TEXT; // no descr means any string by default
    } else if (descr.equals("null")) {
      descr = null; // explicit "null" descr
    }
    if (descr != null) {
      descr =
          descr.replaceAll(
              "\\\\\\\\\"", "\""); // replace: \\" to ", doesn't check symbol before sequence \\"
      descr = descr.replaceAll("\\\\\"", "\"");
    }

    HighlightInfoType type = WHATEVER;
    if (typeString != null) {
      try {
        type = getTypeByName(typeString);
      } catch (Exception e) {
        LOG.error(e);
      }
      LOG.assertTrue(type != null, "Wrong highlight type: " + typeString);
    }

    TextAttributes forcedAttributes = null;
    if (foregroundColor != null) {
      //noinspection MagicConstant
      forcedAttributes =
          new TextAttributes(
              Color.decode(foregroundColor),
              Color.decode(backgroundColor),
              Color.decode(effectColor),
              EffectType.valueOf(effectType),
              Integer.parseInt(fontType));
    }

    final int rangeStart = textOffset.get();
    final int toContinueFrom;
    if (closed) {
      toContinueFrom = matcher.end();
    } else {
      int pos = matcher.end();
      final Matcher closingTagMatcher = Pattern.compile("</" + marker + ">").matcher(text);
      while (true) {
        if (!closingTagMatcher.find(pos)) {
          LOG.error("Cannot find closing </" + marker + "> in position " + pos);
        }

        final int nextTagStart = matcher.find(pos) ? matcher.start() : text.length();
        if (closingTagMatcher.start() < nextTagStart) {
          textOffset.set(textOffset.get() + closingTagMatcher.start() - pos);
          document.deleteString(
              textOffset.get(),
              textOffset.get() + closingTagMatcher.end() - closingTagMatcher.start());
          toContinueFrom = closingTagMatcher.end();
          break;
        }

        textOffset.set(textOffset.get() + nextTagStart - pos);
        pos = extractExpectedHighlight(matcher, text, document, textOffset);
      }
    }

    final ExpectedHighlightingSet expectedHighlightingSet = myHighlightingTypes.get(marker);
    if (expectedHighlightingSet.enabled) {
      TextAttributesKey forcedTextAttributesKey =
          attrKey == null ? null : TextAttributesKey.createTextAttributesKey(attrKey);
      HighlightInfo.Builder builder =
          HighlightInfo.newHighlightInfo(type)
              .range(rangeStart, textOffset.get())
              .severity(expectedHighlightingSet.severity);

      if (forcedAttributes != null) builder.textAttributes(forcedAttributes);
      if (forcedTextAttributesKey != null) builder.textAttributes(forcedTextAttributesKey);
      if (bundleMessage != null) {
        final List<String> split = StringUtil.split(bundleMessage, "|");
        final ResourceBundle bundle = ResourceBundle.getBundle(split.get(0));
        descr = CommonBundle.message(bundle, split.get(1), split.stream().skip(2).toArray());
      }
      if (descr != null) {
        builder.description(descr);
        builder.unescapedToolTip(descr);
      }
      if (expectedHighlightingSet.endOfLine) builder.endOfLine();
      HighlightInfo highlightInfo = builder.createUnconditionally();
      expectedHighlightingSet.infos.add(highlightInfo);
    }

    return toContinueFrom;
  }