Merge branch 'master' of git.labs.intellij.net:idea/community
[idea/community.git] / platform / platform-tests / testSrc / com / intellij / openapi / editor / richcopy / SyntaxInfoConstructionTest.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.openapi.editor.richcopy;
17
18 import com.intellij.openapi.application.ApplicationManager;
19 import com.intellij.openapi.editor.*;
20 import com.intellij.openapi.editor.ex.EditorEx;
21 import com.intellij.openapi.editor.impl.DocumentImpl;
22 import com.intellij.openapi.editor.richcopy.model.ColorRegistry;
23 import com.intellij.openapi.editor.richcopy.model.MarkupHandler;
24 import com.intellij.openapi.editor.richcopy.model.SyntaxInfo;
25 import com.intellij.openapi.fileEditor.FileDocumentManager;
26 import com.intellij.openapi.fileTypes.FileType;
27 import com.intellij.openapi.fileTypes.FileTypeRegistry;
28 import com.intellij.openapi.util.text.StringUtil;
29 import com.intellij.openapi.vfs.VirtualFile;
30 import com.intellij.psi.PsiFile;
31 import com.intellij.psi.PsiFileFactory;
32 import com.intellij.testFramework.fixtures.LightPlatformCodeInsightFixtureTestCase;
33 import com.intellij.ui.JBColor;
34
35 /**
36  * @author Denis Zhdanov
37  * @since 3/27/13 11:11 AM
38  */
39 public class SyntaxInfoConstructionTest extends LightPlatformCodeInsightFixtureTestCase {
40   public void testBlockSelection() {
41     String text =
42       "package org;\n" +
43       "\n" +
44       "public class TestClass {\n" +
45       "\n" +
46       "    int field;\n" +
47       "\n" +
48       "    public int getField() {\n" +
49       "        return field;\n" +
50       "    }\n" +
51       "}";
52     init(text);
53
54     int blockSelectionStartOffset = text.indexOf("public int");
55     Editor editor = myFixture.getEditor();
56     LogicalPosition blockSelectionStartPosition = editor.offsetToLogicalPosition(blockSelectionStartOffset);
57     LogicalPosition blockSelectionEndPosition = new LogicalPosition(
58       blockSelectionStartPosition.line + 2,
59       editor.offsetToLogicalPosition(text.indexOf('{', blockSelectionStartOffset)).column + 1);
60     editor.getSelectionModel().setBlockSelection(blockSelectionStartPosition, blockSelectionEndPosition);
61
62     verifySyntaxInfo("foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=public int \n" +
63                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=getField() {\n" +
64                      "text=\n" +
65                      "\n" +
66                      "text=    \n" +
67                      "foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=return \n" +
68                      "foreground=java.awt.Color[r=102,g=14,b=122],text=field\n" +
69                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=;\n" +
70                      "text=\n" +
71                      "\n" +
72                      "text=}\n");
73   }
74
75   public void testColumnModeBlockSelection() {
76     String text =
77       "package org;\n" +
78       "\n" +
79       "public class TestClass {\n" +
80       "\n" +
81       "    int field;\n" +
82       "\n" +
83       "    public int getField() {\n" +
84       "        return field;\n" +
85       "    }\n" +
86       "}";
87     init(text);
88
89     int blockSelectionStartOffset = text.indexOf("public int");
90     Editor editor = myFixture.getEditor();
91     ((EditorEx) editor).setColumnMode(true);
92     LogicalPosition blockSelectionStartPosition = editor.offsetToLogicalPosition(blockSelectionStartOffset);
93     LogicalPosition blockSelectionEndPosition = new LogicalPosition(
94       blockSelectionStartPosition.line + 2,
95       editor.offsetToLogicalPosition(text.indexOf('{', blockSelectionStartOffset)).column + 1);
96     editor.getSelectionModel().setBlockSelection(blockSelectionStartPosition, blockSelectionEndPosition);
97
98     verifySyntaxInfo("foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=public int \n" +
99                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=getField() {\n" +
100                      "text=\n" +
101                      "\n" +
102                      "text=    \n" +
103                      "foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=return \n" +
104                      "foreground=java.awt.Color[r=102,g=14,b=122],text=field\n" +
105                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=;\n" +
106                      "text=\n" +
107                      "\n" +
108                      "text=}\n");
109   }
110
111   public void testColumnModeBlockSelectionWithGaps() {
112     String text =
113       "public class TestClass {\n" +
114       "\n" +
115       "    int field;\n" +
116       "\n" +
117       "    int otherField;\n" +
118       "}";
119     init(text);
120
121     int blockSelectionStartOffset = text.indexOf("int");
122     Editor editor = myFixture.getEditor();
123     ((EditorEx) editor).setColumnMode(true);
124     LogicalPosition blockSelectionStartPosition = editor.offsetToLogicalPosition(blockSelectionStartOffset);
125     LogicalPosition blockSelectionEndPosition = new LogicalPosition(blockSelectionStartPosition.line + 2, blockSelectionStartPosition.column + 16);
126     editor.getSelectionModel().setBlockSelection(blockSelectionStartPosition, blockSelectionEndPosition);
127
128     verifySyntaxInfo("foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=int \n" +
129                      "foreground=java.awt.Color[r=102,g=14,b=122],text=field\n" +
130                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=;\n" +
131                      "text=\n" +
132                      "\n" +
133                      "text=\n" +
134                      "\n" +
135                      "foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=int \n" +
136                      "foreground=java.awt.Color[r=102,g=14,b=122],text=otherField\n" +
137                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=;\n");
138   }
139
140   public void testRegularSelection() {
141     // We want to exclude unnecessary indents from the pasted results.
142     String text =
143       "package org;\n" +
144       "\n" +
145       "public class TestClass {\n" +
146       "\n" +
147       "    int field;\n" +
148       "\n" +
149       "    public int getField() {\n" +
150       "        return field;\n" +
151       "    }\n" +
152       "}";
153     init(text);
154
155     int selectionStart = text.indexOf("public int");
156     int selectionEnd = text.indexOf('}', selectionStart) + 1;
157     SelectionModel selectionModel = myFixture.getEditor().getSelectionModel();
158     selectionModel.setSelection(selectionStart, selectionEnd);
159
160     String expected = "foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=public int \n" +
161                       "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=getField() {\n" +
162                       "\n" +
163                       "text=    \n" +
164                       "foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=return \n" +
165                       "foreground=java.awt.Color[r=102,g=14,b=122],text=field\n" +
166                       "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=;\n" +
167                       "\n" +
168                       "text=}\n";
169
170     verifySyntaxInfo(expected);
171     
172     selectionModel.setSelection(selectionStart - 2, selectionEnd);
173     verifySyntaxInfo(expected);
174
175     selectionModel.setSelection(selectionStart - 4, selectionEnd);
176     verifySyntaxInfo(expected);
177   }
178
179   public void testIncorrectFirstLineCalculationOffset() {
180     init("\"tr\" #> <selection>template.statusList.sortBy</selection>(_.index).map(fromStatus =>");
181
182     verifySyntaxInfo("fontStyle=0,text=template.statusList.sortBy\n");
183   }
184
185   public void testJavadoc() {
186     init(
187       "package org;\n" +
188       "\n" +
189       "import java.io.Serializable;\n" +
190       "\n" +
191       "<selection>/**\n" +
192       " * Code in <code>here</code>\n" +
193       " * <strong>Hi</strong> man\n" +
194       " * @param <T>\n" +
195       " </selection>*/\n" +
196       "public interface SampleTest<T> extends Serializable {\n" +
197       "    boolean isNotNull();\n" +
198       "    T getValue();\n" +
199       "}"
200     );
201     verifySyntaxInfo("foreground=java.awt.Color[r=128,g=128,b=128],fontStyle=2,text=/**\n" +
202                      "\n" +
203                      "text= * Code in \n" +
204                      "background=java.awt.Color[r=226,g=255,b=226],text=<code>\n" +
205                      "background=java.awt.Color[r=255,g=255,b=255],text=here\n" +
206                      "background=java.awt.Color[r=226,g=255,b=226],text=</code>\n" +
207                      "background=java.awt.Color[r=255,g=255,b=255],text=\n" +
208                      "\n" +
209                      "text= * \n" +
210                      "background=java.awt.Color[r=226,g=255,b=226],text=<strong>\n" +
211                      "background=java.awt.Color[r=255,g=255,b=255],text=Hi\n" +
212                      "background=java.awt.Color[r=226,g=255,b=226],text=</strong>\n" +
213                      "background=java.awt.Color[r=255,g=255,b=255],text= man\n" +
214                      "\n" +
215                      "text= * \n" +
216                      "fontStyle=3,text=@param \n" +
217                      "foreground=java.awt.Color[r=61,g=61,b=61],text=<T>\n" +
218                      "\n" +
219                      "text= \n");
220   }
221
222   public void testIndentStrippingWhenFirstLineIsMostIndented() throws Exception {
223     init("public class Test {\n" +
224          "<selection>  int field;\n" +
225          "}</selection>");
226     verifySyntaxInfo("text=  \n" +
227                      "foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=int \n" +
228                      "foreground=java.awt.Color[r=102,g=14,b=122],text=field\n" +
229                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=;\n" +
230                      "\n" +
231                      "text=}\n");
232   }
233
234   public void testIndentStrippingWhenSelectionEndIsBeforeNonWsCharactersOnTheLine() throws Exception {
235     init("public class Test {\n" +
236          "<selection>  int field;\n" +
237          "</selection>}");
238     verifySyntaxInfo("foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=int \n" +
239                      "foreground=java.awt.Color[r=102,g=14,b=122],text=field\n" +
240                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=;\n" +
241                      "\n");
242   }
243
244   public void testSlashRSeparator() throws Exception {
245     String text = "package org;\r" +
246                   "\r" +
247                   "public class TestClass {\r" +
248                   "\r" +
249                   "    int field;\r" +
250                   "\r" +
251                   "    public int getField() {\r" +
252                   "        return field;\r" +
253                   "    }\r" +
254                   "}";
255     initWithCustomLineSeparators(text);
256     int selectionStart = text.indexOf("public int");
257     int selectionEnd = text.indexOf('}', selectionStart);
258     myFixture.getEditor().getSelectionModel().setSelection(selectionStart, selectionEnd);
259
260     verifySyntaxInfo("foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=public int \n" +
261                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=getField() {\n" +
262                      "\n" +
263                      "text=    \n" +
264                      "foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=return \n" +
265                      "foreground=java.awt.Color[r=102,g=14,b=122],text=field\n" +
266                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=;\n" +
267                      "\n" +
268                      "text=}\n");
269   }
270
271   public void testSlashRSlashNSeparator() throws Exception {
272     String text = "package org;\r\n" +
273                   "\r\n" +
274                   "public class TestClass {\r\n" +
275                   "\r\n" +
276                   "    int field;\r\n" +
277                   "\r\n" +
278                   "    public int getField() {\r\n" +
279                   "        return field;\r\n" +
280                   "    }\r\n" +
281                   "}";
282     initWithCustomLineSeparators(text);
283     int selectionStart = text.indexOf("public int");
284     int selectionEnd = text.indexOf('}', selectionStart);
285     myFixture.getEditor().getSelectionModel().setSelection(selectionStart, selectionEnd);
286
287     verifySyntaxInfo("foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=public int \n" +
288                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=getField() {\n" +
289                      "\n" +
290                      "text=    \n" +
291                      "foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=return \n" +
292                      "foreground=java.awt.Color[r=102,g=14,b=122],text=field\n" +
293                      "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=;\n" +
294                      "\n" +
295                      "text=}\n");
296   }
297   
298   public void testNonPhysicalFile() throws Exception {
299     String fileName = "Test.java";
300     FileType fileType = FileTypeRegistry.getInstance().getFileTypeByFileName(fileName);
301     PsiFile psiFile = PsiFileFactory.getInstance(getProject()).createFileFromText(fileName, fileType, "class Test {}", 0, false);
302     VirtualFile virtualFile = psiFile.getViewProvider().getVirtualFile();
303     Document document = FileDocumentManager.getInstance().getDocument(virtualFile);
304     assertNotNull(document);
305     EditorFactory editorFactory = EditorFactory.getInstance();
306     Editor editor = editorFactory.createViewer(document, getProject());
307     try {
308       editor.getSelectionModel().setSelection(0, document.getTextLength());
309       String syntaxInfo = getSyntaxInfo(editor, psiFile);
310       assertEquals("foreground=java.awt.Color[r=0,g=0,b=128],fontStyle=1,text=class \n" +
311                    "foreground=java.awt.Color[r=0,g=0,b=0],fontStyle=0,text=Test {}\n", syntaxInfo);
312     }
313     finally {
314       editorFactory.releaseEditor(editor);
315     }
316   }
317
318   private String getSyntaxInfo() {
319     return getSyntaxInfo(myFixture.getEditor(), myFixture.getFile());
320   }
321   
322   private static String getSyntaxInfo(Editor editor, PsiFile psiFile) {
323     final StringBuilder builder = new StringBuilder();
324     SelectionModel selectionModel = editor.getSelectionModel();
325     String selectedText = selectionModel.getSelectedText(true);
326     assertNotNull(selectedText);
327     final String text = StringUtil.convertLineSeparators(selectedText);
328
329     TextWithMarkupProcessor processor = new TextWithMarkupProcessor() {
330       @Override
331       void createResult(SyntaxInfo syntaxInfo, Editor editor) {
332         final ColorRegistry colorRegistry = syntaxInfo.getColorRegistry();
333         assertEquals(JBColor.BLACK, colorRegistry.dataById(syntaxInfo.getDefaultForeground()));
334         assertEquals(JBColor.WHITE, colorRegistry.dataById(syntaxInfo.getDefaultBackground()));
335         assertEquals((float)editor.getColorsScheme().getEditorFontSize(), syntaxInfo.getFontSize(), 0.01f);
336         syntaxInfo.processOutputInfo(new MarkupHandler() {
337           @Override
338           public void handleText(int startOffset, int endOffset) throws Exception {
339             builder.append("text=").append(text.substring(startOffset, endOffset)).append('\n');
340           }
341
342           @Override
343           public void handleForeground(int foregroundId) throws Exception {
344             builder.append("foreground=").append(colorRegistry.dataById(foregroundId)).append(',');
345           }
346
347           @Override
348           public void handleBackground(int backgroundId) throws Exception {
349             builder.append("background=").append(colorRegistry.dataById(backgroundId)).append(',');
350           }
351
352           @Override
353           public void handleFont(int fontNameId) throws Exception {
354             assertEquals(1, fontNameId);
355           }
356
357           @Override
358           public void handleStyle(int style) throws Exception {
359             builder.append("fontStyle=").append(style).append(',');
360           }
361
362           @Override
363           public boolean canHandleMore() {
364             return true;
365           }
366         });
367       }
368     };
369     processor.collectTransferableData(psiFile, editor, selectionModel.getBlockSelectionStarts(), selectionModel.getBlockSelectionEnds());
370
371     return builder.toString();
372   }
373
374   private void init(String text) {
375     myFixture.configureByText(getTestName(true) + ".java", text);
376     myFixture.doHighlighting();
377   }
378
379   private void initWithCustomLineSeparators(final String text) {
380     myFixture.configureByText(getTestName(true) + ".java", "");
381     final DocumentImpl document = (DocumentImpl)myFixture.getEditor().getDocument();
382     document.setAcceptSlashR(true);
383     ApplicationManager.getApplication().runWriteAction(new Runnable() {
384       @Override
385       public void run() {
386         document.setText(text);
387       }
388     });
389     myFixture.doHighlighting();
390   }
391
392   private void verifySyntaxInfo(String info) {
393     assertEquals(info, getSyntaxInfo());
394   }
395
396   @Override
397   protected boolean isWriteActionRequired() {
398     return false;
399   }
400 }