<commit_before>/*
 * Copyright 2000-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.intellij.codeInsight.highlighting;

import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.hint.EditorFragmentComponent;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.lang.Language;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.MarkupModelEx;
import com.intellij.openapi.editor.ex.util.HighlighterIteratorWrapper;
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.ILazyParseableElementType;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.LightweightHint;
import com.intellij.util.Alarm;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

public class BraceHighlightingHandler {
  private static final Key<List<RangeHighlighter>> BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY = Key.create("BraceHighlighter.BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY");
  private static final Key<RangeHighlighter> LINE_MARKER_IN_EDITOR_KEY = Key.create("BraceHighlighter.LINE_MARKER_IN_EDITOR_KEY");
  private static final Key<LightweightHint> HINT_IN_EDITOR_KEY = Key.create("BraceHighlighter.HINT_IN_EDITOR_KEY");

  /**
   * Holds weak references to the editors that are being processed at non-EDT.
   * <p/>
   * Is intended to be used to avoid submitting unnecessary new processing request from EDT, i.e. it's assumed that the collection
   * is accessed from the single thread (EDT).
   */
  private static final Set<Editor> PROCESSED_EDITORS = Collections.newSetFromMap(ContainerUtil.createWeakMap());

  @NotNull private final Project myProject;
  @NotNull private final Editor myEditor;
  private final Alarm myAlarm;

  private final DocumentEx myDocument;
  private final PsiFile myPsiFile;
  private final CodeInsightSettings myCodeInsightSettings;

  private BraceHighlightingHandler(@NotNull Project project, @NotNull Editor editor, @NotNull Alarm alarm, PsiFile psiFile) {
    myProject = project;

    myEditor = editor;
    myAlarm = alarm;
    myDocument = (DocumentEx)myEditor.getDocument();

    myPsiFile = psiFile;
    myCodeInsightSettings = CodeInsightSettings.getInstance();
  }

  static void lookForInjectedAndMatchBracesInOtherThread(@NotNull final Editor editor,
                                                         @NotNull final Alarm alarm,
                                                         @NotNull final Processor<BraceHighlightingHandler> processor) {
    ApplicationManagerEx.getApplicationEx().assertIsDispatchThread();
    if (!isValidEditor(editor)) return;
    if (!PROCESSED_EDITORS.add(editor)) {
      // Skip processing if that is not really necessary.
      // Assuming to be in EDT here.
      return;
    }
    final int offset = editor.getCaretModel().getOffset();

    // any request to the UI component need to be done from EDT
    final ModalityState modalityState = ModalityState.stateForComponent(editor.getComponent());
    final DumbAwareRunnable removeEditorFromProcessed = () -> PROCESSED_EDITORS.remove(editor);

    ApplicationManager.getApplication().executeOnPooledThread(() -> {
      if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(() -> {
        if (!isValidEditor(editor)) {
          ApplicationManager.getApplication().invokeLater(removeEditorFromProcessed);
          return;
        }
        @SuppressWarnings("ConstantConditions") // the `project` is valid after the `isValidEditor` call
        @NotNull final Project project = editor.getProject();

        final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project);
        final PsiFile injected;
        try {
          if (psiFile instanceof PsiBinaryFile || !isValidFile(psiFile)) {
            injected = null;
          }
          else {
            injected = getInjectedFileIfAny(editor, project, offset, psiFile, alarm);
          }
        }
        catch (RuntimeException e) {
          // Reset processing flag in case of unexpected exception.
          ApplicationManager.getApplication().invokeLater(removeEditorFromProcessed);
          throw e;
        }
        ApplicationManager.getApplication().invokeLater((DumbAwareRunnable)() -> {
          try {
            if (isValidEditor(editor) && isValidFile(injected)) {
              Editor newEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injected);
              BraceHighlightingHandler handler = new BraceHighlightingHandler(project, newEditor, alarm, injected);
              processor.process(handler);
            }
          }
          finally {
            removeEditorFromProcessed.run();
          }
        }, modalityState);
      })) {
        // write action is queued in AWT. restart after it's finished
        ApplicationManager.getApplication().invokeLater(() -> {
          removeEditorFromProcessed.run();
          lookForInjectedAndMatchBracesInOtherThread(editor, alarm, processor);
        }, modalityState);<commit_msg>interrupt injection calculation by write action as early as possible<commit_after>/*
 * Copyright 2000-2017 JetBrains s.r.o.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.intellij.codeInsight.highlighting;

import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.hint.EditorFragmentComponent;
import com.intellij.injected.editor.EditorWindow;
import com.intellij.lang.Language;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
import com.intellij.openapi.application.impl.ApplicationImpl;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.editor.colors.CodeInsightColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.MarkupModelEx;
import com.intellij.openapi.editor.ex.util.HighlighterIteratorWrapper;
import com.intellij.openapi.editor.ex.util.LexerEditorHighlighter;
import com.intellij.openapi.editor.highlighter.EditorHighlighter;
import com.intellij.openapi.editor.highlighter.HighlighterIterator;
import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.fileTypes.SyntaxHighlighter;
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory;
import com.intellij.openapi.progress.util.ProgressIndicatorUtils;
import com.intellij.openapi.project.DumbAwareRunnable;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Conditions;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.TextRange;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.tree.ILazyParseableElementType;
import com.intellij.psi.util.PsiUtilBase;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.ui.ColorUtil;
import com.intellij.ui.LightweightHint;
import com.intellij.util.Alarm;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.text.CharArrayUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

public class BraceHighlightingHandler {
  private static final Key<List<RangeHighlighter>> BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY = Key.create("BraceHighlighter.BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY");
  private static final Key<RangeHighlighter> LINE_MARKER_IN_EDITOR_KEY = Key.create("BraceHighlighter.LINE_MARKER_IN_EDITOR_KEY");
  private static final Key<LightweightHint> HINT_IN_EDITOR_KEY = Key.create("BraceHighlighter.HINT_IN_EDITOR_KEY");

  /**
   * Holds weak references to the editors that are being processed at non-EDT.
   * <p/>
   * Is intended to be used to avoid submitting unnecessary new processing request from EDT, i.e. it's assumed that the collection
   * is accessed from the single thread (EDT).
   */
  private static final Set<Editor> PROCESSED_EDITORS = Collections.newSetFromMap(ContainerUtil.createWeakMap());

  @NotNull private final Project myProject;
  @NotNull private final Editor myEditor;
  private final Alarm myAlarm;

  private final DocumentEx myDocument;
  private final PsiFile myPsiFile;
  private final CodeInsightSettings myCodeInsightSettings;

  private BraceHighlightingHandler(@NotNull Project project, @NotNull Editor editor, @NotNull Alarm alarm, PsiFile psiFile) {
    myProject = project;

    myEditor = editor;
    myAlarm = alarm;
    myDocument = (DocumentEx)myEditor.getDocument();

    myPsiFile = psiFile;
    myCodeInsightSettings = CodeInsightSettings.getInstance();
  }

  static void lookForInjectedAndMatchBracesInOtherThread(@NotNull final Editor editor,
                                                         @NotNull final Alarm alarm,
                                                         @NotNull final Processor<BraceHighlightingHandler> processor) {
    ApplicationManagerEx.getApplicationEx().assertIsDispatchThread();
    if (!isValidEditor(editor)) return;
    if (!PROCESSED_EDITORS.add(editor)) {
      // Skip processing if that is not really necessary.
      // Assuming to be in EDT here.
      return;
    }
    final int offset = editor.getCaretModel().getOffset();

    // any request to the UI component need to be done from EDT
    final ModalityState modalityState = ModalityState.stateForComponent(editor.getComponent());
    final DumbAwareRunnable removeEditorFromProcessed = () -> PROCESSED_EDITORS.remove(editor);

    ApplicationManager.getApplication().executeOnPooledThread(() -> {
      if (!ApplicationManagerEx.getApplicationEx().tryRunReadAction(() ->
        ((ApplicationImpl)ApplicationManager.getApplication()).executeByImpatientReader(()->
        ProgressIndicatorUtils.runInReadActionWithWriteActionPriority(()->{
          if (!isValidEditor(editor)) {
            ApplicationManager.getApplication().invokeLater(removeEditorFromProcessed);
            return;
          }
          @SuppressWarnings("ConstantConditions") // the `project` is valid after the `isValidEditor` call
          @NotNull final Project project = editor.getProject();

          final PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project);
          final PsiFile injected;
          try {
            if (psiFile instanceof PsiBinaryFile || !isValidFile(psiFile)) {
              injected = null;
            }
            else {
              injected = getInjectedFileIfAny(editor, project, offset, psiFile, alarm);
            }
          }
          catch (RuntimeException e) {
            // Reset processing flag in case of unexpected exception.
            ApplicationManager.getApplication().invokeLater(removeEditorFromProcessed);
            throw e;
          }
          ApplicationManager.getApplication().invokeLater((DumbAwareRunnable)() -> {
            try {
              if (isValidEditor(editor) && isValidFile(injected)) {
                Editor newEditor = InjectedLanguageUtil.getInjectedEditorForInjectedFile(editor, injected);
                BraceHighlightingHandler handler = new BraceHighlightingHandler(project, newEditor, alarm, injected);
                processor.process(handler);
              }
            }
            finally {
              removeEditorFromProcessed.run();
            }
          }, modalityState);
        })
      ))) {
        // write action is queued in AWT. restart after it's finished
        ApplicationManager.getApplication().invokeLater(() -> {
          removeEditorFromProcessed.run();
          lookForInjectedAndMatchBracesInOtherThread(editor, alarm, processor);
        }, modalityState);
{'fraction_non_alphanumeric': 0.08878100684977057, 'fraction_numerical': 0.0015960630444902574, 'mean_word_length': 3.9192018318613018, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 29, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '381096', 'n_tokens_mistral': 4284, 'n_tokens_neox': 4207, 'n_words': 924}