@Override
  public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException {
    String selectedText = editor.getSelectionModel().getSelectedText();

    if (selectedText != null) {
      explain(selectedText.trim());
    }
    else {
      Caret caret = editor.getCaretModel().getPrimaryCaret();
      int offset = caret.getOffset();
      PsiElement at = file.findElementAt(offset);
      List<ShCompositeElement> parents =
          at == null
          ? Collections.emptyList()
          : PsiTreeUtil.collectParents(at, ShCompositeElement.class, true, psiElement -> psiElement.getText().contains("\n"));

      Set<String> strings = new HashSet<>(); // avoid duplicates by text in a bit weird manner
      List<ShCompositeElement> commands = ContainerUtil.filter(parents, e -> (e instanceof ShCommand || e instanceof ShCommandsList) && strings.add(e.getText()));

      if (commands.isEmpty()) {
        CommonRefactoringUtil.showErrorHint(project, editor, ShBundle.message("sh.explain.message.nothing.to.explain"),
                                            ShBundle.message("sh.explain.title.nothing.to.explain"), "");
      }
      else {
        IntroduceTargetChooser.showChooser(editor, commands, new Pass<PsiElement>() {
          @Override
          public void pass(@NotNull PsiElement psiElement) {
            explain(psiElement.getText());
          }
        }, PsiElement::getText, ShBundle.message("sh.explain.command.to.explain"));
      }
    }
  }
@Override
  public void invoke(@NotNull Project project, Editor editor, PsiFile file)