<commit_before>package com.jetbrains.python.edu;

import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.daemon.LineMarkerInfo;
import com.intellij.codeInsight.daemon.LineMarkerProvider;
import com.intellij.execution.actions.RunContextAction;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.util.Function;
import com.jetbrains.python.psi.PyFile;
import com.jetbrains.python.psi.PyImportStatement;
import com.jetbrains.python.psi.PyStatement;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.List;

/**
 * @author traff
 */
public class PyExecuteFileLineMarkerProvider implements LineMarkerProvider {
  @Nullable
  @Override
  public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
    return null;
  }

  @Override
  public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {
    for (PsiElement element : elements) {
      if (isFirstCodeLine(element)) {
        final RunContextAction runAction = new RunContextAction(DefaultRunExecutor.getRunExecutorInstance());
        final LineMarkerInfo<PsiElement> markerInfo = new LineMarkerInfo<PsiElement>(
          element, element.getTextRange(), AllIcons.Actions.Execute, Pass.UPDATE_OVERRIDEN_MARKERS,
          new Function<PsiElement, String>() {
            @Override
            public String fun(PsiElement e) {
              return "Execute '" + e.getContainingFile().getName() + "'";
            }
          }, null,
          GutterIconRenderer.Alignment.RIGHT) {
          @Nullable
          @Override
          public GutterIconRenderer createGutterRenderer() {
            return new LineMarkerGutterIconRenderer<PsiElement>(this){
              @Override
              public AnAction getClickAction() {
                return runAction;
              }

              @Nullable
              @Override
              public ActionGroup getPopupMenuActions() {
                final DefaultActionGroup group = new DefaultActionGroup();
                group.add(runAction);
                final PyExecuteFileExtensionPoint[] extensions =
                  ApplicationManager.getApplication().getExtensions(PyExecuteFileExtensionPoint.EP_NAME);
                for (PyExecuteFileExtensionPoint extension : extensions) {
                  final AnAction action = extension.getRunAction();
                  if (action == null) {
                    continue;
                  }
                  group.add(action);
                }
                return group;
              }
            };
          }
        };
        result.add(markerInfo);
      }
    }
  }

  private static boolean isFirstCodeLine(PsiElement element) {
    return element instanceof PyStatement &&
           element.getParent() instanceof PyFile &&
           !isNothing(element) &&
           nothingBefore(element);
  }

  private static boolean nothingBefore(PsiElement element) {
    element = element.getPrevSibling();
    while (element != null) {
      if (!isNothing(element)) {
        return false;
      }
      element = element.getPrevSibling();
    }

    return true;
  }

  private static boolean isNothing(PsiElement element) {
    return (element instanceof PsiComment) || (element instanceof PyImportStatement) || (element instanceof PsiWhiteSpace);
  }
}
<commit_msg>EDU-384 Always show "execute file" icon on the first line<commit_after>package com.jetbrains.python.edu;

import com.intellij.codeHighlighting.Pass;
import com.intellij.codeInsight.daemon.LineMarkerInfo;
import com.intellij.codeInsight.daemon.LineMarkerProvider;
import com.intellij.execution.actions.RunContextAction;
import com.intellij.execution.executors.DefaultRunExecutor;
import com.intellij.icons.AllIcons;
import com.intellij.openapi.actionSystem.ActionGroup;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DefaultActionGroup;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.markup.GutterIconRenderer;
import com.intellij.psi.PsiElement;
import com.intellij.util.Function;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Collection;
import java.util.List;

/**
 * @author traff
 */
public class PyExecuteFileLineMarkerProvider implements LineMarkerProvider {
  @Nullable
  @Override
  public LineMarkerInfo getLineMarkerInfo(@NotNull PsiElement element) {
    return null;
  }

  @Override
  public void collectSlowLineMarkers(@NotNull List<PsiElement> elements, @NotNull Collection<LineMarkerInfo> result) {
    if (elements.isEmpty()) {
      return;
    }
    PsiElement element = elements.get(0);
    final RunContextAction runAction = new RunContextAction(DefaultRunExecutor.getRunExecutorInstance());
    final LineMarkerInfo<PsiElement> markerInfo = new LineMarkerInfo<PsiElement>(
      element, element.getTextRange(), AllIcons.Actions.Execute, Pass.UPDATE_OVERRIDEN_MARKERS,
      new Function<PsiElement, String>() {
        @Override
        public String fun(PsiElement e) {
          return "Execute '" + e.getContainingFile().getName() + "'";
        }
      }, null,
      GutterIconRenderer.Alignment.RIGHT) {
      @Nullable
      @Override
      public GutterIconRenderer createGutterRenderer() {
        return new LineMarkerGutterIconRenderer<PsiElement>(this) {
          @Override
          public AnAction getClickAction() {
            return runAction;
          }

          @Nullable
          @Override
          public ActionGroup getPopupMenuActions() {
            final DefaultActionGroup group = new DefaultActionGroup();
            group.add(runAction);
            final PyExecuteFileExtensionPoint[] extensions =
              ApplicationManager.getApplication().getExtensions(PyExecuteFileExtensionPoint.EP_NAME);
            for (PyExecuteFileExtensionPoint extension : extensions) {
              final AnAction action = extension.getRunAction();
              if (action == null) {
                continue;
              }
              group.add(action);
            }
            return group;
          }
        };
      }
    };
    result.add(markerInfo);
  }
}

{'fraction_non_alphanumeric': 0.08799525152099719, 'fraction_numerical': 0.0005935598753524262, 'mean_word_length': 3.019081693500298, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 15, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3023175', 'n_tokens_mistral': 1794, 'n_tokens_neox': 1753, 'n_words': 344}