<commit_before>package org.jetbrains.plugins.scala
package lang
package refactoring
package introduceVariable


import org.jetbrains.plugins.scala.util.ScalaUtils
import com.intellij.openapi.editor.{Editor, VisualPosition}
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.wm.WindowManager
import com.intellij.psi.{xml => _, _}
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.ui.ConflictsDialog
import com.intellij.refactoring.util.RefactoringMessageDialog
import com.intellij.refactoring.{HelpID, RefactoringActionHandler}
import java.util.regex.{Pattern, Matcher}

import lexer.ScalaTokenTypes
import namesSuggester.NameSuggester
import psi.api.base.patterns.ScCaseClause
import psi.api.ScalaFile
import psi.api.statements._
import psi.api.toplevel.ScEarlyDefinitions
import psi.api.toplevel.templates.ScTemplateBody
import psi.ScalaPsiUtil
import psi.types.{ScType}
import psi.api.expr._
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.plugins.scala.lang.psi.impl.ScalaPsiElementFactory
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.project.Project
import psi.api.toplevel.typedef.ScMember
import refactoring.util.ScalaRefactoringUtil
import extractMethod.ScalaExtractMethodUtils
import collection.mutable.ArrayBuffer

/**
* User: <NAME>
* Date: 23.06.2008
*/

class ScalaIntroduceVariableHandler extends RefactoringActionHandler {
  val REFACTORING_NAME = ScalaBundle.message("introduce.variable.title")
  var deleteOccurrence = false;



  private def getLineText(editor: Editor): String = {
    val lineNumber = editor.getCaretModel.getLogicalPosition.line
    if (lineNumber >= editor.getDocument.getLineCount) return ""
    val caret = editor.getCaretModel.getVisualPosition
    val lineStart = editor.visualToLogicalPosition(new VisualPosition(caret.line, 0));
    val nextLineStart = editor.visualToLogicalPosition(new VisualPosition(caret.line + 1, 0))
    val start = editor.logicalPositionToOffset(lineStart)
    val end = editor.logicalPositionToOffset(nextLineStart)
    return editor.getDocument.getText.substring(start, end)
  }

  def invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext) {
    def invokes() {
      val lineText = getLineText(editor)
      if (editor.getSelectionModel.getSelectedText != null &&
                lineText != null && editor.getSelectionModel.getSelectedText.trim == lineText.trim) deleteOccurrence = true
      ScalaRefactoringUtil.trimSpacesAndComments(editor, file)
      invoke(project, editor, file, editor.getSelectionModel.getSelectionStart, editor.getSelectionModel.getSelectionEnd)
    }
    if (!editor.getSelectionModel.hasSelection) {
      val offset = editor.getCaretModel.getOffset
      val element: PsiElement = file.findElementAt(offset)
      def getExpressions: Array[ScExpression] = {
        val res = new ArrayBuffer[ScExpression]
        var parent = element
        while (parent != null && !parent.getText.contains("\n")) {
          parent match {
            case expr: ScExpression => res += expr
            case _ =>
          }
          parent = parent.getParent
        }
        res.toArray
      }
      val expressions = getExpressions
      def chooseExpression(expr: ScExpression) {
        editor.getSelectionModel.setSelection(expr.getTextRange.getStartOffset,
          expr.getTextRange.getEndOffset)
        invokes
      }
      if (expressions.length == 0)
        editor.getSelectionModel.selectLineAtCaret
      else if (expressions.length == 1) {
        chooseExpression(expressions(0))
        return
      } else {
        ScalaRefactoringUtil.showChooser(editor, expressions, elem =>
          chooseExpression(elem.asInstanceOf[ScExpression]), "Choose Expression for Introduce Variable", (expr: ScExpression) => {
          ScalaRefactoringUtil.getShortText(expr)
        })
        return
      }
    }
    invokes
  }

  def invoke(project: Project, editor: Editor, file: PsiFile, startOffset: Int, endOffset: Int) {
    try {
      PsiDocumentManager.getInstance(project).commitAllDocuments
      if (!file.isInstanceOf[ScalaFile])
        showErrorMessage(ScalaBundle.message("only.for.scala"), project)

      if (!ScalaRefactoringUtil.ensureFileWritable(project, file))
        showErrorMessage(ScalaBundle.message("file.is.not.writable"), project)

      val (expr: ScExpression, typez: ScType) = ScalaRefactoringUtil.getExpression(project, editor, file, startOffset, endOffset).
              getOrElse(showErrorMessage(ScalaBundle.message("cannot.refactor.not.expression"), project))

      val typeText = ScType.presentableText(typez)

      expr.getParent match {
        case inf: ScInfixExpr if inf.operation == expr => showErrorMessage(ScalaBundle.message("cannot.refactor.not.expression"), project)
        case post: ScPostfixExpr if post.operation == expr => showErrorMessage(ScalaBundle.message("cannot.refactor.not.expression"), project)
        case _: ScGenericCall => showErrorMessage(ScalaBundle.message("connot.refactor.under.generic.call"), project)
        case _ if expr.isInstanceOf[ScConstrExpr] => showErrorMessage(ScalaBundle.message("cannot.refactor.constr.expression"), project)
        case _ =>
      }
      val guard: ScGuard = PsiTreeUtil.getParentOfType(expr, classOf[ScGuard])
      if (guard != null && guard.getParent.isInstanceOf[ScCaseClause]) showErrorMessage(ScalaBundle.message("cannot.refactor.guard"), project)

      val fileEncloser = if (file.asInstanceOf[ScalaFile].isScriptFile()) file
      else {
        var res: PsiElement = file.findElementAt(startOffset)
        while (!res.isInstanceOf[ScFunction] && res.getParent != null &&
                !res.getParent.isInstanceOf[ScTemplateBody]) res = res.getParent
        if (res == null) {
          for (child <- file.getChildren) {
            val textRange: TextRange = child.getTextRange
            if (textRange.contains(startOffset)) res = child
          }
        }
        res
      }
      val occurrences: Array[TextRange] = ScalaRefactoringUtil.getOccurrences(ScalaRefactoringUtil.unparExpr(expr), fileEncloser)
      // Getting settings
      val elemSeq = (for (occurence <- occurrences) yield file.findElementAt(occurence.getStartOffset)).toSeq ++
         (for (occurence <- occurrences) yield file.findElementAt(occurence.getEndOffset - 1)).toSeq
      val commonParent: PsiElement = PsiTreeUtil.findCommonParent(elemSeq: _*)
      val container: PsiElement = ScalaPsiUtil.getParentOfType(commonParent, occurrences.length == 1, classOf[ScalaFile], classOf[ScBlock],
        classOf[ScTemplateBody])
      val commonParentOne = PsiTreeUtil.findCommonParent(file.findElementAt(startOffset), file.findElementAt(endOffset - 1))
      val containerOne = ScalaPsiUtil.getParentOfType(commonParentOne, occurrences.length == 1, classOf[ScalaFile], classOf[ScBlock],
        classOf[ScTemplateBody])
      var validator = new ScalaVariableValidator(this, project, expr, occurrences, container, containerOne)
      var dialog = getDialog(project, editor, expr, typez, occurrences, false, validator)
      if (!dialog.isOK) return

      val varName: String = dialog.getEnteredName
      var varType: ScType = dialog.getSelectedType
      val isVariable: Boolean = dialog.isDeclareVariable
      val replaceAllOccurrences: Boolean = dialog.isReplaceAllOccurrences<commit_msg>SCL-2092: Introduce Variable in early definitions, fixed SOE.<commit_after>package org.jetbrains.plugins.scala
package lang
package refactoring
package introduceVariable


import org.jetbrains.plugins.scala.util.ScalaUtils
import com.intellij.openapi.editor.{Editor, VisualPosition}
import com.intellij.openapi.util.TextRange
import com.intellij.openapi.wm.WindowManager
import com.intellij.psi.{xml => _, _}
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.refactoring.ui.ConflictsDialog
import com.intellij.refactoring.util.RefactoringMessageDialog
import com.intellij.refactoring.{HelpID, RefactoringActionHandler}
import java.util.regex.{Pattern, Matcher}

import lexer.ScalaTokenTypes
import namesSuggester.NameSuggester
import psi.api.base.patterns.ScCaseClause
import psi.api.ScalaFile
import psi.api.statements._
import psi.api.toplevel.ScEarlyDefinitions
import psi.api.toplevel.templates.ScTemplateBody
import psi.ScalaPsiUtil
import psi.types.{ScType}
import psi.api.expr._
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.plugins.scala.lang.psi.impl.ScalaPsiElementFactory
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.project.Project
import psi.api.toplevel.typedef.ScMember
import refactoring.util.ScalaRefactoringUtil
import extractMethod.ScalaExtractMethodUtils
import collection.mutable.ArrayBuffer

/**
* User: <NAME>
* Date: 23.06.2008
*/

class ScalaIntroduceVariableHandler extends RefactoringActionHandler {
  val REFACTORING_NAME = ScalaBundle.message("introduce.variable.title")
  var deleteOccurrence = false;



  private def getLineText(editor: Editor): String = {
    val lineNumber = editor.getCaretModel.getLogicalPosition.line
    if (lineNumber >= editor.getDocument.getLineCount) return ""
    val caret = editor.getCaretModel.getVisualPosition
    val lineStart = editor.visualToLogicalPosition(new VisualPosition(caret.line, 0));
    val nextLineStart = editor.visualToLogicalPosition(new VisualPosition(caret.line + 1, 0))
    val start = editor.logicalPositionToOffset(lineStart)
    val end = editor.logicalPositionToOffset(nextLineStart)
    return editor.getDocument.getText.substring(start, end)
  }

  def invoke(project: Project, editor: Editor, file: PsiFile, dataContext: DataContext) {
    def invokes() {
      val lineText = getLineText(editor)
      if (editor.getSelectionModel.getSelectedText != null &&
                lineText != null && editor.getSelectionModel.getSelectedText.trim == lineText.trim) deleteOccurrence = true
      ScalaRefactoringUtil.trimSpacesAndComments(editor, file)
      invoke(project, editor, file, editor.getSelectionModel.getSelectionStart, editor.getSelectionModel.getSelectionEnd)
    }
    if (!editor.getSelectionModel.hasSelection) {
      val offset = editor.getCaretModel.getOffset
      val element: PsiElement = file.findElementAt(offset)
      def getExpressions: Array[ScExpression] = {
        val res = new ArrayBuffer[ScExpression]
        var parent = element
        while (parent != null && !parent.getText.contains("\n")) {
          parent match {
            case expr: ScExpression => res += expr
            case _ =>
          }
          parent = parent.getParent
        }
        res.toArray
      }
      val expressions = getExpressions
      def chooseExpression(expr: ScExpression) {
        editor.getSelectionModel.setSelection(expr.getTextRange.getStartOffset,
          expr.getTextRange.getEndOffset)
        invokes
      }
      if (expressions.length == 0)
        editor.getSelectionModel.selectLineAtCaret
      else if (expressions.length == 1) {
        chooseExpression(expressions(0))
        return
      } else {
        ScalaRefactoringUtil.showChooser(editor, expressions, elem =>
          chooseExpression(elem.asInstanceOf[ScExpression]), "Choose Expression for Introduce Variable", (expr: ScExpression) => {
          ScalaRefactoringUtil.getShortText(expr)
        })
        return
      }
    }
    invokes
  }

  def invoke(project: Project, editor: Editor, file: PsiFile, startOffset: Int, endOffset: Int) {
    try {
      PsiDocumentManager.getInstance(project).commitAllDocuments
      if (!file.isInstanceOf[ScalaFile])
        showErrorMessage(ScalaBundle.message("only.for.scala"), project)

      if (!ScalaRefactoringUtil.ensureFileWritable(project, file))
        showErrorMessage(ScalaBundle.message("file.is.not.writable"), project)

      val (expr: ScExpression, typez: ScType) = ScalaRefactoringUtil.getExpression(project, editor, file, startOffset, endOffset).
              getOrElse(showErrorMessage(ScalaBundle.message("cannot.refactor.not.expression"), project))

      val typeText = ScType.presentableText(typez)

      expr.getParent match {
        case inf: ScInfixExpr if inf.operation == expr => showErrorMessage(ScalaBundle.message("cannot.refactor.not.expression"), project)
        case post: ScPostfixExpr if post.operation == expr => showErrorMessage(ScalaBundle.message("cannot.refactor.not.expression"), project)
        case _: ScGenericCall => showErrorMessage(ScalaBundle.message("connot.refactor.under.generic.call"), project)
        case _ if expr.isInstanceOf[ScConstrExpr] => showErrorMessage(ScalaBundle.message("cannot.refactor.constr.expression"), project)
        case _ =>
      }
      val guard: ScGuard = PsiTreeUtil.getParentOfType(expr, classOf[ScGuard])
      if (guard != null && guard.getParent.isInstanceOf[ScCaseClause]) showErrorMessage(ScalaBundle.message("cannot.refactor.guard"), project)

      val fileEncloser = if (file.asInstanceOf[ScalaFile].isScriptFile()) file
      else {
        var res: PsiElement = file.findElementAt(startOffset)
        while (!res.isInstanceOf[ScFunction] && res.getParent != null &&
                !res.getParent.isInstanceOf[ScTemplateBody] &&
                !res.getParent.isInstanceOf[ScEarlyDefinitions]) res = res.getParent
        if (res == null) {
          for (child <- file.getChildren) {
            val textRange: TextRange = child.getTextRange
            if (textRange.contains(startOffset)) res = child
          }
        }
        res
      }
      val occurrences: Array[TextRange] = ScalaRefactoringUtil.getOccurrences(ScalaRefactoringUtil.unparExpr(expr), fileEncloser)
      // Getting settings
      val elemSeq = (for (occurence <- occurrences) yield file.findElementAt(occurence.getStartOffset)).toSeq ++
         (for (occurence <- occurrences) yield file.findElementAt(occurence.getEndOffset - 1)).toSeq
      val commonParent: PsiElement = PsiTreeUtil.findCommonParent(elemSeq: _*)
      val container: PsiElement = ScalaPsiUtil.getParentOfType(commonParent, occurrences.length == 1, classOf[ScalaFile], classOf[ScBlock],
        classOf[ScTemplateBody])
      val commonParentOne = PsiTreeUtil.findCommonParent(file.findElementAt(startOffset), file.findElementAt(endOffset - 1))
      val containerOne = ScalaPsiUtil.getParentOfType(commonParentOne, occurrences.length == 1, classOf[ScalaFile], classOf[ScBlock],
        classOf[ScTemplateBody])
      var validator = new ScalaVariableValidator(this, project, expr, occurrences, container, containerOne)
      var dialog = getDialog(project, editor, expr, typez, occurrences, false, validator)
      if (!dialog.isOK) return

      val varName: String = dialog.getEnteredName
      var varType: ScType = dialog.getSelectedType
      val isVariable: Boolean = dialog.isDeclareVariable
      val replaceAllOccurrences: Boolean = dialog.isReplaceAllOccurrences
{'fraction_non_alphanumeric': 0.09672251518590214, 'fraction_numerical': 0.0026700487283892933, 'mean_word_length': 3.9741035856573705, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 2}, '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': '1571600', 'n_tokens_mistral': 4434, 'n_tokens_neox': 4276, 'n_words': 817}