Skip to content

Commit 547d216

Browse files
#41: Support for proto file renames
Rename refactoring for proto files: - When one renames proto file, all related import statements should be updated. - When one renames folder where proto files are located, all related import statements should be updated. - When one presses Ctrl+F6 and renames proto file from import statement (in-place), file should be renamed. Fixes #32
1 parent 13f0294 commit 547d216

File tree

8 files changed

+106
-1
lines changed

8 files changed

+106
-1
lines changed

src/main/java/io/protostuff/jetbrains/plugin/ProtoParserDefinition.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,12 @@ protected ParseTree parse(Parser parser, IElementType root) {
297297
if (root instanceof IFileElementType) {
298298
return ((ProtoParser) parser).proto();
299299
}
300+
if (root instanceof RuleIElementType) {
301+
RuleIElementType type = (RuleIElementType) root;
302+
if (ProtoParserDefinition.rule(ProtoParser.RULE_fileReference).equals(type)) {
303+
return ((ProtoParser) parser).fileReference();
304+
}
305+
}
300306
// let's hope it's an ID as needed by "rename function"
301307
throw new UnsupportedOperationException();
302308
// return ((ProtoParser) parser).name();

src/main/java/io/protostuff/jetbrains/plugin/psi/FileReferenceNode.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,5 @@ private String getFilename() {
112112
}
113113
return Util.removeFirstAndLastChar(text);
114114
}
115+
115116
}

src/main/java/io/protostuff/jetbrains/plugin/psi/ProtoPsiFileRoot.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.protostuff.jetbrains.plugin.psi;
22

3+
import com.google.common.annotations.VisibleForTesting;
34
import com.intellij.extapi.psi.PsiFileBase;
45
import com.intellij.openapi.fileTypes.FileType;
56
import com.intellij.openapi.vfs.VirtualFile;
@@ -76,7 +77,8 @@ public Collection<ProtoType> getAllTypes() {
7677
return Collections.emptyList();
7778
}
7879

79-
private ProtoRootNode getProtoRoot() {
80+
@VisibleForTesting
81+
public ProtoRootNode getProtoRoot() {
8082
return findChildByClass(ProtoRootNode.class);
8183
}
8284

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package io.protostuff.jetbrains.plugin.psi.manipulator;
2+
3+
import com.intellij.openapi.project.Project;
4+
import com.intellij.openapi.util.TextRange;
5+
import com.intellij.psi.AbstractElementManipulator;
6+
import com.intellij.psi.PsiElement;
7+
import com.intellij.psi.PsiFileFactory;
8+
import com.intellij.psi.impl.PsiFileFactoryImpl;
9+
import com.intellij.util.IncorrectOperationException;
10+
import io.protostuff.compiler.parser.ProtoParser;
11+
import io.protostuff.jetbrains.plugin.ProtoLanguage;
12+
import io.protostuff.jetbrains.plugin.ProtoParserDefinition;
13+
import io.protostuff.jetbrains.plugin.psi.FileReferenceNode;
14+
import org.antlr.jetbrains.adapter.lexer.RuleIElementType;
15+
import org.antlr.jetbrains.adapter.psi.ScopeNode;
16+
import org.jetbrains.annotations.NotNull;
17+
18+
/**
19+
* File reference node manipulator. Use for changing text of import nodes when
20+
* renaming proto files.
21+
*
22+
* @author Kostiantyn Shchepanovskyi
23+
*/
24+
public class FileReferenceNodeManipulator extends AbstractElementManipulator<FileReferenceNode> {
25+
26+
@Override
27+
public FileReferenceNode handleContentChange(@NotNull FileReferenceNode fileReferenceNode, @NotNull TextRange range, String newContent) throws IncorrectOperationException {
28+
String oldText = fileReferenceNode.getText();
29+
String newText = oldText.substring(0, range.getStartOffset()) + newContent + oldText.substring(range.getEndOffset());
30+
Project project = fileReferenceNode.getProject();
31+
PsiFileFactoryImpl factory = (PsiFileFactoryImpl) PsiFileFactory.getInstance(project);
32+
RuleIElementType type = ProtoParserDefinition.rule(ProtoParser.RULE_fileReference);
33+
ScopeNode context = fileReferenceNode.getContext();
34+
PsiElement newNode = factory.createElementFromText(newText, ProtoLanguage.INSTANCE, type, context);
35+
if (newNode == null) {
36+
throw new IncorrectOperationException();
37+
}
38+
return (FileReferenceNode) fileReferenceNode.replace(newNode);
39+
}
40+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,10 @@
139139
<gotoClassContributor
140140
implementation="io.protostuff.jetbrains.plugin.GoToClassContributor"/>
141141

142+
<lang.elementManipulator
143+
forClass="io.protostuff.jetbrains.plugin.psi.FileReferenceNode"
144+
implementationClass="io.protostuff.jetbrains.plugin.psi.manipulator.FileReferenceNodeManipulator"/>
145+
142146
</extensions>
143147

144148
<actions>
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package io.protostuff.jetbrains.plugin.rename;
2+
3+
import com.intellij.openapi.extensions.Extensions;
4+
import com.intellij.openapi.project.Project;
5+
import com.intellij.psi.PsiElement;
6+
import com.intellij.psi.PsiFile;
7+
import com.intellij.refactoring.rename.RenameProcessor;
8+
import com.intellij.refactoring.rename.naming.AutomaticRenamerFactory;
9+
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase;
10+
import io.protostuff.jetbrains.plugin.psi.ProtoPsiFileRoot;
11+
import org.junit.Assert;
12+
13+
/**
14+
* Tests for rename refactoring - proto file rename.
15+
*
16+
* @author Kostiantyn Shchepanovskyi
17+
*/
18+
public class RenameImportedProtoTest extends LightCodeInsightFixtureTestCase {
19+
20+
@Override
21+
protected String getTestDataPath() {
22+
return "src/test/resources/";
23+
}
24+
25+
public void testRenameImportedProtoAtCaretPosition() {
26+
PsiFile[] files = myFixture.configureByFiles(
27+
"rename/import/import.proto",
28+
"rename/import/source.proto"
29+
);
30+
31+
PsiElement elementAtCaret = myFixture.getElementAtCaret();
32+
Project project = myFixture.getProject();
33+
RenameProcessor processor = new RenameProcessor(project, elementAtCaret, "renamed.proto", false, false);
34+
for (AutomaticRenamerFactory factory : Extensions.getExtensions(AutomaticRenamerFactory.EP_NAME)) {
35+
processor.addRenamerFactory(factory);
36+
}
37+
processor.run();
38+
39+
Assert.assertEquals("renamed.proto", files[0].getName());
40+
Assert.assertEquals("import \"rename/import/renamed.proto\";",
41+
((ProtoPsiFileRoot) files[1]).getProtoRoot().getImports().get(0).getText());
42+
}
43+
44+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
syntax = "proto2";
2+
3+
package rename.import;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
syntax = "proto2";
2+
3+
package rename.import;
4+
5+
import "rename/import/impo<caret>rt.proto";

0 commit comments

Comments
 (0)