mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
RUBY-21937 Added YAML simple copy-paste pre-processor
IDEA-CR-34731
This commit is contained in:
@@ -13,6 +13,7 @@
|
||||
|
||||
<lang.formatter language="yaml" implementationClass="org.jetbrains.yaml.formatter.YAMLFormattingModelBuilder"/>
|
||||
<enterHandlerDelegate implementation="org.jetbrains.yaml.formatter.YAMLEnterAtIndentHandler" order="first"/>
|
||||
<copyPastePreProcessor implementation="org.jetbrains.yaml.formatter.YAMLCopyPasteProcessor"/>
|
||||
<lang.parserDefinition language="yaml" implementationClass="org.jetbrains.yaml.YAMLParserDefinition"/>
|
||||
<lang.commenter language="yaml" implementationClass="org.jetbrains.yaml.YAMLCommenter"/>
|
||||
<lang.syntaxHighlighterFactory language="yaml" implementationClass="org.jetbrains.yaml.YAMLSyntaxHighlighterFactory"/>
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
// 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 org.jetbrains.yaml.formatter;
|
||||
|
||||
import com.intellij.codeInsight.editorActions.CopyPastePreProcessor;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.*;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.LineTokenizer;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.yaml.YAMLLanguage;
|
||||
import org.jetbrains.yaml.YAMLTextUtil;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public class YAMLCopyPasteProcessor implements CopyPastePreProcessor {
|
||||
@Nullable
|
||||
@Override
|
||||
public String preprocessOnCopy(PsiFile file, int[] startOffsets, int[] endOffsets, String text) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public String preprocessOnPaste(Project project, PsiFile file, Editor editor, String text, RawText rawText) {
|
||||
if (file.getLanguage() != YAMLLanguage.INSTANCE) return text;
|
||||
CaretModel caretModel = editor.getCaretModel();
|
||||
SelectionModel selectionModel = editor.getSelectionModel();
|
||||
Document document = editor.getDocument();
|
||||
int caretOffset = selectionModel.getSelectionStart() != selectionModel.getSelectionEnd() ?
|
||||
selectionModel.getSelectionStart() : caretModel.getOffset();
|
||||
int lineNumber = document.getLineNumber(caretOffset);
|
||||
int lineStartOffset = YAMLTextUtil.getLineStartSafeOffset(document, lineNumber);
|
||||
int indent = caretOffset - lineStartOffset;
|
||||
if (indent == 0) {
|
||||
// It could be copy and paste of lines
|
||||
// User could fix indentation later if he wanted to copy some block into top-level block
|
||||
return text;
|
||||
}
|
||||
|
||||
return indentText(text, StringUtil.repeatSymbol(' ', indent));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String indentText(@NotNull String text, @NotNull String curLineIndent) {
|
||||
List<String> lines = LineTokenizer.tokenizeIntoList(text, false, false);
|
||||
if (lines.isEmpty()) {
|
||||
// Such situation should not be possible
|
||||
Logger.getInstance(YAMLCopyPasteProcessor.class).error(text.isEmpty()
|
||||
? "Pasted empty text"
|
||||
: "Text '" + text + "' was converted into empty line list");
|
||||
return text;
|
||||
}
|
||||
int minIndent = calculateMinBlockIndent(lines);
|
||||
String firstLine = lines.iterator().next();
|
||||
if (lines.size() == 1) {
|
||||
return firstLine;
|
||||
}
|
||||
return firstLine.substring(YAMLTextUtil.getStartIndentSize(firstLine)) + "\n" +
|
||||
lines.stream().skip(1).map(line -> {
|
||||
// remove common indent and add needed indent
|
||||
if (isEmptyLine(line)) {
|
||||
return curLineIndent + line.substring(minIndent);
|
||||
}
|
||||
else {
|
||||
// do not indent empty lines at all
|
||||
return "";
|
||||
}
|
||||
}).reduce((left, right) -> left + "\n" + right).orElse("");
|
||||
}
|
||||
|
||||
private static int calculateMinBlockIndent(@NotNull List<String> list) {
|
||||
Iterator<String> it = list.iterator();
|
||||
String str = "";
|
||||
while (it.hasNext()) {
|
||||
str = it.next();
|
||||
if (isEmptyLine(str)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!it.hasNext()) {
|
||||
return 0;
|
||||
}
|
||||
int minIndent = YAMLTextUtil.getStartIndentSize(str);
|
||||
while (it.hasNext()) {
|
||||
str = it.next();
|
||||
if (isEmptyLine(str)) {
|
||||
minIndent = Math.min(minIndent, YAMLTextUtil.getStartIndentSize(str));
|
||||
}
|
||||
}
|
||||
return minIndent;
|
||||
}
|
||||
|
||||
private static boolean isEmptyLine(@NotNull String str) {
|
||||
return YAMLTextUtil.getStartIndentSize(str) < str.length();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
// 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 org.jetbrains.yaml.paste;
|
||||
|
||||
import com.intellij.codeInsight.CodeInsightSettings;
|
||||
import com.intellij.openapi.actionSystem.IdeActions;
|
||||
import com.intellij.openapi.application.ex.PathManagerEx;
|
||||
import com.intellij.openapi.ide.CopyPasteManager;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.awt.datatransfer.StringSelection;
|
||||
|
||||
public abstract class YAMLPasteTest extends LightPlatformCodeInsightFixtureTestCase {
|
||||
private static final String ZERO_INDENT_SAMPLE = "key1:\n" +
|
||||
" subKey: val1\n" +
|
||||
"\n" +
|
||||
"key2: val2";
|
||||
|
||||
private static final String INDENTED_SAMPLE = " key1:\n" +
|
||||
" subKey: val1\n" +
|
||||
"\n" +
|
||||
" key2: val2";
|
||||
|
||||
private static final String EMPTY_LINES_SAMPLE = "\n" +
|
||||
"\n" +
|
||||
"\n";
|
||||
|
||||
private final int myReformatOnPaste;
|
||||
|
||||
private int myDefaultReformatOnPaste = CodeInsightSettings.INDENT_EACH_LINE;
|
||||
|
||||
@SuppressWarnings("JUnitTestCaseWithNonTrivialConstructors")
|
||||
YAMLPasteTest(int paste) {
|
||||
myReformatOnPaste = paste;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
myDefaultReformatOnPaste = CodeInsightSettings.getInstance().REFORMAT_ON_PASTE;
|
||||
CodeInsightSettings.getInstance().REFORMAT_ON_PASTE = myReformatOnPaste;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
try {
|
||||
CodeInsightSettings.getInstance().REFORMAT_ON_PASTE = myDefaultReformatOnPaste;
|
||||
}
|
||||
finally {
|
||||
super.tearDown();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTestDataPath() {
|
||||
return PathManagerEx.getCommunityHomePath() + "/plugins/yaml/testSrc/org/jetbrains/yaml/paste/data/";
|
||||
}
|
||||
|
||||
public void testOneLinePaste() {
|
||||
doTest(" middle");
|
||||
}
|
||||
|
||||
public void testPasteValue_zeroIndent() {
|
||||
doTest(ZERO_INDENT_SAMPLE);
|
||||
}
|
||||
|
||||
public void testPasteValue_indented() {
|
||||
doTest(INDENTED_SAMPLE);
|
||||
}
|
||||
|
||||
public void testPasteValue_empty() {
|
||||
doTest(EMPTY_LINES_SAMPLE, ".empty");
|
||||
}
|
||||
|
||||
public void testPasteLines() {
|
||||
doTest(INDENTED_SAMPLE);
|
||||
}
|
||||
|
||||
public void testPasteItem_zeroIndent() {
|
||||
doTest(ZERO_INDENT_SAMPLE);
|
||||
}
|
||||
|
||||
public void testPasteItem_indented() {
|
||||
doTest(INDENTED_SAMPLE);
|
||||
}
|
||||
|
||||
public void testPasteItem_empty() {
|
||||
doTest(EMPTY_LINES_SAMPLE, ".empty");
|
||||
}
|
||||
|
||||
public void testPasteWithReplace_zeroIndent() {
|
||||
doInsertTest(ZERO_INDENT_SAMPLE);
|
||||
}
|
||||
|
||||
public void testPasteWithReplace_indented() {
|
||||
doInsertTest(INDENTED_SAMPLE);
|
||||
}
|
||||
|
||||
private void doTest(@NotNull String insert) {
|
||||
doTest(insert, "");
|
||||
}
|
||||
|
||||
private void doInsertTest(@NotNull String insert) {
|
||||
doTest(insert, "", true);
|
||||
}
|
||||
|
||||
private void doTest(@NotNull String insert, @NotNull String resultSuffix) {
|
||||
doTest(insert, resultSuffix, false);
|
||||
}
|
||||
|
||||
private void doTest(@NotNull String insert, @NotNull String resultSuffix, boolean selectWord) {
|
||||
String testName = getTestName(true);
|
||||
String fileName = ObjectUtils.notNull(StringUtil.substringBefore(testName, "_"), testName);
|
||||
myFixture.configureByFile(fileName + ".yml");
|
||||
CopyPasteManager.getInstance().setContents(new StringSelection(insert));
|
||||
if (selectWord) {
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_SELECT_WORD_AT_CARET);
|
||||
}
|
||||
myFixture.performEditorAction(IdeActions.ACTION_EDITOR_PASTE);
|
||||
myFixture.checkResultByFile(fileName + resultSuffix + ".txt");
|
||||
}
|
||||
|
||||
public static class YAMLPasteNoReformatTest extends YAMLPasteTest {
|
||||
public YAMLPasteNoReformatTest() {
|
||||
super(CodeInsightSettings.NO_REFORMAT);
|
||||
}
|
||||
}
|
||||
|
||||
public static class YAMLPasteIndentBlockTest extends YAMLPasteTest {
|
||||
public YAMLPasteIndentBlockTest() {
|
||||
super(CodeInsightSettings.INDENT_BLOCK);
|
||||
}
|
||||
}
|
||||
|
||||
public static class YAMLPasteIndentEachLineTest extends YAMLPasteTest {
|
||||
public YAMLPasteIndentEachLineTest() {
|
||||
super(CodeInsightSettings.INDENT_EACH_LINE);
|
||||
}
|
||||
}
|
||||
|
||||
public static class YAMLPasteReformatBlockTest extends YAMLPasteTest {
|
||||
public YAMLPasteReformatBlockTest() {
|
||||
super(CodeInsightSettings.REFORMAT_BLOCK);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
top:
|
||||
someKey1: start middle end
|
||||
someKey2: value2
|
||||
@@ -0,0 +1,3 @@
|
||||
top:
|
||||
someKey1: start<caret> end
|
||||
someKey2: value2
|
||||
@@ -0,0 +1,6 @@
|
||||
top:
|
||||
someKey:
|
||||
# use double list for clear indent
|
||||
- -
|
||||
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
top:
|
||||
someKey:
|
||||
# use double list for clear indent
|
||||
- - key1:
|
||||
subKey: val1
|
||||
|
||||
key2: val2
|
||||
@@ -0,0 +1,4 @@
|
||||
top:
|
||||
someKey:
|
||||
# use double list for clear indent
|
||||
- - <caret>
|
||||
@@ -0,0 +1,6 @@
|
||||
top:
|
||||
someKey: value
|
||||
key1:
|
||||
subKey: val1
|
||||
|
||||
key2: val2
|
||||
@@ -0,0 +1,3 @@
|
||||
top:
|
||||
someKey: value
|
||||
<caret>
|
||||
@@ -0,0 +1,5 @@
|
||||
top:
|
||||
someKey:
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
top:
|
||||
someKey:
|
||||
key1:
|
||||
subKey: val1
|
||||
|
||||
key2: val2
|
||||
@@ -0,0 +1,3 @@
|
||||
top:
|
||||
someKey:
|
||||
<caret>
|
||||
@@ -0,0 +1,6 @@
|
||||
top:
|
||||
someKey:
|
||||
key1:
|
||||
subKey: val1
|
||||
|
||||
key2: val2
|
||||
@@ -0,0 +1,3 @@
|
||||
top:
|
||||
someKey:
|
||||
some<caret>Word
|
||||
Reference in New Issue
Block a user