From 742ed5e435968e47886fe1fe519d897a0e4e1462 Mon Sep 17 00:00:00 2001 From: Bas Leijdekkers Date: Fri, 26 Jan 2018 15:24:07 +0100 Subject: [PATCH] SSR: help with creating variables --- .../source/META-INF/structuralsearch.xml | 2 + .../XmlStructuralSearchProfile.java | 10 ++- .../ui/StructuralSearchTypedHandler.java | 80 +++++++++++++++++++ 3 files changed, 88 insertions(+), 4 deletions(-) create mode 100644 platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/StructuralSearchTypedHandler.java diff --git a/platform/structuralsearch/source/META-INF/structuralsearch.xml b/platform/structuralsearch/source/META-INF/structuralsearch.xml index 49fa4d0261c0..030bc8674b5b 100644 --- a/platform/structuralsearch/source/META-INF/structuralsearch.xml +++ b/platform/structuralsearch/source/META-INF/structuralsearch.xml @@ -16,6 +16,8 @@ + + diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/XmlStructuralSearchProfile.java b/platform/structuralsearch/source/com/intellij/structuralsearch/XmlStructuralSearchProfile.java index 5d6cd596c964..d2e19b7c6628 100644 --- a/platform/structuralsearch/source/com/intellij/structuralsearch/XmlStructuralSearchProfile.java +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/XmlStructuralSearchProfile.java @@ -11,10 +11,7 @@ import com.intellij.openapi.fileTypes.FileType; import com.intellij.openapi.fileTypes.StdFileTypes; import com.intellij.openapi.project.Project; import com.intellij.psi.*; -import com.intellij.psi.xml.XmlDocument; -import com.intellij.psi.xml.XmlFile; -import com.intellij.psi.xml.XmlTag; -import com.intellij.psi.xml.XmlText; +import com.intellij.psi.xml.*; import com.intellij.structuralsearch.impl.matcher.*; import com.intellij.structuralsearch.impl.matcher.compiler.GlobalCompilingVisitor; import com.intellij.structuralsearch.impl.matcher.compiler.XmlCompilingVisitor; @@ -48,6 +45,11 @@ public class XmlStructuralSearchProfile extends StructuralSearchProfile { return new XmlMatchingVisitor(globalVisitor); } + @Override + public boolean isIdentifier(PsiElement element) { + return element instanceof XmlToken && ((XmlToken)element).getTokenType() == XmlTokenType.XML_NAME; + } + @NotNull @Override public NodeFilter getLexicalNodesFilter() { diff --git a/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/StructuralSearchTypedHandler.java b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/StructuralSearchTypedHandler.java new file mode 100644 index 000000000000..8c4bc92a9751 --- /dev/null +++ b/platform/structuralsearch/source/com/intellij/structuralsearch/plugin/ui/StructuralSearchTypedHandler.java @@ -0,0 +1,80 @@ +// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. +package com.intellij.structuralsearch.plugin.ui; + +import com.intellij.codeInsight.editorActions.TypedHandlerDelegate; +import com.intellij.openapi.editor.*; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.structuralsearch.StructuralSearchUtil; +import com.intellij.util.SmartList; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +/** + * @author Bas Leijdekkers + */ +public class StructuralSearchTypedHandler extends TypedHandlerDelegate { + + @NotNull + @Override + public Result beforeSelectionRemoved(char c, + @NotNull Project project, + @NotNull Editor editor, + @NotNull PsiFile file) { + if (editor.getUserData(SubstitutionShortInfoHandler.CURRENT_CONFIGURATION_KEY) == null) { + return Result.CONTINUE; + } + if (c == '$') { + final SelectionModel selectionModel = editor.getSelectionModel(); + final String selectedText = selectionModel.getSelectedText(); + if (!StringUtil.isEmpty(selectedText) && !selectedText.contains("$")) { + final Document document = editor.getDocument(); + final List rangeMarkers = new SmartList<>(); + rangeMarkers.add(document.createRangeMarker(selectionModel.getSelectionStart(), selectionModel.getSelectionEnd())); + + final CaretModel caretModel = editor.getCaretModel(); + final boolean multipleCarets = caretModel.getCaretCount() != 1; + if (!multipleCarets) { + PsiTreeUtil.processElements(file, element -> { + if (StructuralSearchUtil.isIdentifier(element) && element.getText().equals(selectedText)) { + rangeMarkers.add(document.createRangeMarker(element.getTextRange())); + } + return true; + }); + } + + final String newText = String.valueOf(c) + selectedText + c; + final boolean ltrSelection = selectionModel.getLeadSelectionOffset() != selectionModel.getSelectionEnd(); + for (RangeMarker marker : rangeMarkers) { + if (marker.isValid()) { + document.replaceString(marker.getStartOffset(), marker.getEndOffset(), newText); + if (multipleCarets) { + final int startOffset = marker.getStartOffset() + 1; + final int endOffset = startOffset + selectedText.length(); + selectionModel.setSelection(ltrSelection ? startOffset : endOffset, ltrSelection ? endOffset : startOffset); + caretModel.moveToOffset(ltrSelection ? endOffset : startOffset); + } + } + } + if (!multipleCarets) { + final List newCaretStates = new SmartList<>(); + for (RangeMarker marker : rangeMarkers) { + final int startOffset = marker.getStartOffset() + 1; + final int endOffset = startOffset + selectedText.length(); + final LogicalPosition selectionStart = editor.offsetToLogicalPosition(ltrSelection ? startOffset : endOffset); + final LogicalPosition selectionEnd = editor.offsetToLogicalPosition(ltrSelection ? endOffset : startOffset); + final LogicalPosition caretPosition = editor.offsetToLogicalPosition(ltrSelection ? endOffset : startOffset); + final CaretState state = new CaretState(caretPosition, selectionStart, selectionEnd); + newCaretStates.add(state); + } + caretModel.setCaretsAndSelections(newCaretStates); + } + return Result.STOP; + } + } + return super.beforeSelectionRemoved(c, project, editor, file); + } +}