@Override
  protected void collectAdditionalElementsToRename(List<Pair<PsiElement, TextRange>> stringUsages) {
    if (isReplaceAllOccurrences()) {
      for (E expression : getOccurrences()) {
        LOG.assertTrue(expression.isValid(), expression.getText());
        stringUsages.add(
            Pair.<PsiElement, TextRange>create(
                expression, new TextRange(0, expression.getTextLength())));
      }
    } else if (getExpr() != null) {
      correctExpression();
      final E expr = getExpr();
      LOG.assertTrue(expr.isValid(), expr.getText());
      stringUsages.add(
          Pair.<PsiElement, TextRange>create(expr, new TextRange(0, expr.getTextLength())));
    }

    final V localVariable = getLocalVariable();
    if (localVariable != null) {
      final PsiElement nameIdentifier = localVariable.getNameIdentifier();
      if (nameIdentifier != null) {
        int length = nameIdentifier.getTextLength();
        stringUsages.add(
            Pair.<PsiElement, TextRange>create(nameIdentifier, new TextRange(0, length)));
      }
    }
  }
  public AbstractInplaceIntroducer(
      Project project,
      Editor editor,
      @Nullable E expr,
      @Nullable V localVariable,
      E[] occurrences,
      String title,
      final FileType languageFileType) {
    super(null, editor, project, title, occurrences, expr);
    myLocalVariable = localVariable;
    if (localVariable != null) {
      final PsiElement nameIdentifier = localVariable.getNameIdentifier();
      if (nameIdentifier != null) {
        myLocalMarker = createMarker(nameIdentifier);
      }
    } else {
      myLocalMarker = null;
    }
    myExprText = getExpressionText(expr);
    myLocalName = localVariable != null ? localVariable.getName() : null;

    myPreview = createPreviewComponent(project, languageFileType);
    myPreviewComponent = new JPanel(new BorderLayout());
    myPreviewComponent.add(myPreview.getComponent(), BorderLayout.CENTER);
    myPreviewComponent.setBorder(new EmptyBorder(2, 2, 6, 2));

    myWholePanel = new JPanel(new GridBagLayout());
    myWholePanel.setBorder(null);

    showDialogAdvertisement(getActionName());
  }
  protected void restoreState(@NotNull final V psiField) {
    if (!ReadonlyStatusHandler.ensureDocumentWritable(
        myProject, InjectedLanguageUtil.getTopLevelEditor(myEditor).getDocument())) return;
    ApplicationManager.getApplication()
        .runWriteAction(
            () -> {
              final PsiFile containingFile = psiField.getContainingFile();
              final RangeMarker exprMarker = getExprMarker();
              if (exprMarker != null) {
                myExpr = restoreExpression(containingFile, psiField, exprMarker, myExprText);
              }

              if (myLocalMarker != null) {
                final PsiElement refVariableElement =
                    containingFile.findElementAt(myLocalMarker.getStartOffset());
                if (refVariableElement != null) {
                  final PsiElement parent = refVariableElement.getParent();
                  if (parent instanceof PsiNamedElement) {
                    ((PsiNamedElement) parent).setName(myLocalName);
                  }
                }

                final V localVariable = getLocalVariable();
                if (localVariable != null && localVariable.isPhysical()) {
                  myLocalVariable = localVariable;
                  final PsiElement nameIdentifier = localVariable.getNameIdentifier();
                  if (nameIdentifier != null) {
                    myLocalMarker = createMarker(nameIdentifier);
                  }
                }
              }
              final List<RangeMarker> occurrenceMarkers = getOccurrenceMarkers();
              for (int i = 0, occurrenceMarkersSize = occurrenceMarkers.size();
                  i < occurrenceMarkersSize;
                  i++) {
                RangeMarker marker = occurrenceMarkers.get(i);
                if (getExprMarker() != null
                    && marker.getStartOffset() == getExprMarker().getStartOffset()
                    && myExpr != null) {
                  myOccurrences[i] = myExpr;
                  continue;
                }
                final E psiExpression =
                    restoreExpression(
                        containingFile,
                        psiField,
                        marker,
                        getLocalVariable() != null ? myLocalName : myExprText);
                if (psiExpression != null) {
                  myOccurrences[i] = psiExpression;
                }
              }

              if (myExpr != null && myExpr.isPhysical()) {
                myExprMarker = createMarker(myExpr);
              }
              myOccurrenceMarkers = null;
              deleteTemplateField(psiField);
            });
  }
  /**
   * Begins the in-place refactoring operation.
   *
   * @return true if the in-place refactoring was successfully started, false if it failed to start
   *     and a dialog should be shown instead.
   */
  public boolean startInplaceIntroduceTemplate() {
    final boolean replaceAllOccurrences = isReplaceAllOccurrences();
    final Ref<Boolean> result = new Ref<>();
    CommandProcessor.getInstance()
        .executeCommand(
            myProject,
            () -> {
              final String[] names = suggestNames(replaceAllOccurrences, getLocalVariable());
              final V variable = createFieldToStartTemplateOn(replaceAllOccurrences, names);
              boolean started = false;
              if (variable != null) {
                int caretOffset = getCaretOffset();
                myEditor.getCaretModel().moveToOffset(caretOffset);
                myEditor.getScrollingModel().scrollToCaret(ScrollType.MAKE_VISIBLE);

                final LinkedHashSet<String> nameSuggestions = new LinkedHashSet<>();
                nameSuggestions.add(variable.getName());
                nameSuggestions.addAll(Arrays.asList(names));
                initOccurrencesMarkers();
                setElementToRename(variable);
                updateTitle(getVariable());
                started = super.performInplaceRefactoring(nameSuggestions);
                if (started) {
                  onRenameTemplateStarted();
                  myDocumentAdapter =
                      new DocumentAdapter() {
                        @Override
                        public void documentChanged(DocumentEvent e) {
                          if (myPreview == null) return;
                          final TemplateState templateState =
                              TemplateManagerImpl.getTemplateState(myEditor);
                          if (templateState != null) {
                            final TextResult value =
                                templateState.getVariableValue(
                                    InplaceRefactoring.PRIMARY_VARIABLE_NAME);
                            if (value != null) {
                              updateTitle(getVariable(), value.getText());
                            }
                          }
                        }
                      };
                  myEditor.getDocument().addDocumentListener(myDocumentAdapter);
                  updateTitle(getVariable());
                  if (TemplateManagerImpl.getTemplateState(myEditor) != null) {
                    myEditor.putUserData(ACTIVE_INTRODUCE, this);
                  }
                }
              }
              result.set(started);
              if (!started) {
                finish(true);
              }
            },
            getCommandName(),
            getCommandName());
    return result.get();
  }
  protected void updateTitle(@Nullable V variable, String value) {
    if (variable == null) return;

    final String variableText = variable.getText();
    final PsiElement identifier = variable.getNameIdentifier();
    if (identifier != null) {
      final int startOffsetInParent = identifier.getStartOffsetInParent();
      setPreviewText(
          variableText.substring(0, startOffsetInParent)
              + value
              + variableText.substring(startOffsetInParent + identifier.getTextLength()));
    } else {
      setPreviewText(variableText.replaceFirst(variable.getName(), value));
    }
    revalidate();
  }
  @Override
  protected void addHighlights(
      @NotNull Map<TextRange, TextAttributes> ranges,
      @NotNull Editor editor,
      @NotNull Collection<RangeHighlighter> highlighters,
      @NotNull HighlightManager highlightManager) {
    final TextAttributes attributes =
        EditorColorsManager.getInstance()
            .getGlobalScheme()
            .getAttributes(EditorColors.SEARCH_RESULT_ATTRIBUTES);
    final V variable = getVariable();
    if (variable != null) {
      final String name = variable.getName();
      LOG.assertTrue(name != null, variable);
      final int variableNameLength = name.length();
      if (isReplaceAllOccurrences()) {
        for (RangeMarker marker : getOccurrenceMarkers()) {
          final int startOffset = marker.getStartOffset();
          highlightManager.addOccurrenceHighlight(
              editor,
              startOffset,
              startOffset + variableNameLength,
              attributes,
              0,
              highlighters,
              null);
        }
      } else if (getExpr() != null) {
        final int startOffset = getExprMarker().getStartOffset();
        highlightManager.addOccurrenceHighlight(
            editor,
            startOffset,
            startOffset + variableNameLength,
            attributes,
            0,
            highlighters,
            null);
      }
    }

    for (RangeHighlighter highlighter : highlighters) {
      highlighter.setGreedyToLeft(true);
      highlighter.setGreedyToRight(true);
    }
  }
 public void restartInplaceIntroduceTemplate() {
   Runnable restartTemplateRunnable =
       () -> {
         final TemplateState templateState = TemplateManagerImpl.getTemplateState(myEditor);
         if (templateState != null) {
           myEditor.putUserData(INTRODUCE_RESTART, true);
           try {
             final TextRange range = templateState.getCurrentVariableRange();
             if (range != null) {
               final TextResult inputText = templateState.getVariableValue(PRIMARY_VARIABLE_NAME);
               final String inputName = inputText != null ? inputText.getText() : null;
               final V variable = getVariable();
               if (inputName == null
                   || variable == null
                   || !isIdentifier(inputName, variable.getLanguage())) {
                 final String[] names =
                     suggestNames(isReplaceAllOccurrences(), getLocalVariable());
                 ApplicationManager.getApplication()
                     .runWriteAction(
                         () ->
                             myEditor
                                 .getDocument()
                                 .replaceString(
                                     range.getStartOffset(), range.getEndOffset(), names[0]));
               }
             }
             templateState.gotoEnd(true);
             try {
               myShouldSelect = false;
               startInplaceIntroduceTemplate();
             } finally {
               myShouldSelect = true;
             }
           } finally {
             myEditor.putUserData(INTRODUCE_RESTART, false);
           }
         }
         updateTitle(getVariable());
       };
   CommandProcessor.getInstance()
       .executeCommand(myProject, restartTemplateRunnable, getCommandName(), getCommandName());
 }
 public V getLocalVariable() {
   if (myLocalVariable != null && myLocalVariable.isValid()) {
     return myLocalVariable;
   }
   if (myLocalMarker != null) {
     V variable = getVariable();
     PsiFile containingFile;
     if (variable != null) {
       containingFile = variable.getContainingFile();
     } else {
       containingFile =
           PsiDocumentManager.getInstance(myProject).getPsiFile(myEditor.getDocument());
     }
     PsiNameIdentifierOwner identifierOwner =
         PsiTreeUtil.getParentOfType(
             containingFile.findElementAt(myLocalMarker.getStartOffset()),
             PsiNameIdentifierOwner.class,
             false);
     return identifierOwner != null && identifierOwner.getClass() == myLocalVariable.getClass()
         ? (V) identifierOwner
         : null;
   }
   return myLocalVariable;
 }
  public boolean startsOnTheSameElement(E expr, V localVariable) {
    if (myExprMarker != null
        && myExprMarker.isValid()
        && expr != null
        && myExprMarker.getStartOffset() == expr.getTextOffset()) {
      return true;
    }

    if (myLocalMarker != null
        && myLocalMarker.isValid()
        && localVariable != null
        && myLocalMarker.getStartOffset() == localVariable.getTextOffset()) {
      return true;
    }
    return isRestart();
  }
 protected void deleteTemplateField(V psiField) {
   if (psiField.isValid()) {
     psiField.delete();
   }
 }
 protected void updateTitle(@Nullable V variable) {
   if (variable == null) return;
   setPreviewText(variable.getText());
   revalidate();
 }