Skip to content

Commit

Permalink
Merge branch 'master' into feature/antlrGH-433
Browse files Browse the repository at this point in the history
  • Loading branch information
kjarrio authored Aug 13, 2022
2 parents f26f2cb + f9753ad commit 1700b68
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
Expand All @@ -20,6 +21,8 @@
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileEditor.FileEditorManagerListener;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
Expand All @@ -35,6 +38,7 @@
import com.intellij.openapi.wm.ToolWindow;
import com.intellij.openapi.wm.ToolWindowAnchor;
import com.intellij.openapi.wm.ToolWindowManager;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.ui.content.Content;
import com.intellij.ui.content.ContentFactory;
import com.intellij.util.messages.MessageBusConnection;
Expand All @@ -53,7 +57,6 @@
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/** This object is the controller for the ANTLR plug-in. It receives
* events and can send them on to its contained components. For example,
Expand Down Expand Up @@ -92,6 +95,8 @@ public class ANTLRv4PluginController implements ProjectComponent {

private ProgressIndicator parsingProgressIndicator;

private final Map<String, Long> grammarFileMods = new HashMap<>();

public ANTLRv4PluginController(Project project) {
this.project = project;
}
Expand All @@ -110,6 +115,16 @@ public static ANTLRv4PluginController getInstance(Project project) {

@Override
public void initComponent() {

final FileTypeManager fileTypeManager = FileTypeManager.getInstance();
final String defaultExtension = ANTLRv4FileType.INSTANCE.getDefaultExtension();

WriteCommandAction.runWriteCommandAction(this.project, () ->
fileTypeManager.removeAssociatedExtension(FileTypes.PLAIN_TEXT, defaultExtension));

WriteCommandAction.runWriteCommandAction(this.project, () ->
fileTypeManager.associateExtension(ANTLRv4FileType.INSTANCE, defaultExtension));

}

@Override
Expand Down Expand Up @@ -267,7 +282,17 @@ public void setStartRuleNameEvent(VirtualFile grammarFile, String startRuleName)
}

public void grammarFileSavedEvent(VirtualFile grammarFile) {
LOG.info("grammarFileSavedEvent "+grammarFile.getPath()+" "+project.getName());

Long modCount = grammarFile.getModificationCount();
String grammarFilePath = grammarFile.getPath();

if (grammarFileMods.containsKey(grammarFilePath) && grammarFileMods.get(grammarFilePath).equals(modCount)) {
return;
}

grammarFileMods.put(grammarFilePath, modCount);

LOG.info("grammarFileSavedEvent "+grammarFilePath+" "+project.getName());
updateGrammarObjectsFromFile(grammarFile, true); // force reload
if ( previewPanel!=null ) {
previewPanel.grammarFileSaved(grammarFile);
Expand All @@ -277,24 +302,32 @@ public void grammarFileSavedEvent(VirtualFile grammarFile) {
}
}

public void currentEditorFileChangedEvent(VirtualFile oldFile, VirtualFile newFile) {
public void currentEditorFileChangedEvent(VirtualFile oldFile, VirtualFile newFile, boolean modified) {
LOG.info("currentEditorFileChangedEvent "+(oldFile!=null?oldFile.getPath():"none")+
" -> "+(newFile!=null?newFile.getPath():"none")+" "+project.getName());
if ( newFile==null ) { // all files must be closed I guess
return;
}
if ( newFile.getName().endsWith(".g") ) {

String newFileExt = newFile.getExtension();

if (newFileExt == null) {
return;
}

if (newFileExt.equals("g")) {
LOG.info("currentEditorFileChangedEvent ANTLR 4 cannot handle .g files, only .g4");
hidePreview();
return;
}
if ( !newFile.getName().endsWith(".g4") ) {

if ( !newFileExt.equals("g4") ) {
return;
}

// When switching from a lexer grammar, update its objects in case the grammar was modified.
// The updated objects might be needed later by another dependant grammar.
if ( oldFile != null && oldFile.getName().endsWith(".g4")) {
if ( oldFile != null && oldFile.getExtension().equals("g4") && modified) {
updateGrammarObjectsFromFile(oldFile, true);
}

Expand Down Expand Up @@ -611,13 +644,37 @@ public class MyFileEditorManagerAdapter implements FileEditorManagerListener {
@Override
public void selectionChanged(FileEditorManagerEvent event) {
if ( !projectIsClosed ) {
currentEditorFileChangedEvent(event.getOldFile(), event.getNewFile());
boolean modified = false;

if (event.getOldEditor() != null) {
if (event.getOldEditor().isModified()) {
modified = true;
} else {
VirtualFile oldFile = event.getOldEditor().getFile();
String oldFilePath = oldFile.getPath();
Long modCount = oldFile.getModificationCount();
modified = grammarFileMods.containsKey(oldFilePath) &&
!grammarFileMods.get(oldFilePath).equals(modCount);
}

}

if (modified) {
PsiDocumentManager psiMgr = PsiDocumentManager.getInstance(project);
FileDocumentManager docMgr = FileDocumentManager.getInstance();
Document doc = docMgr.getDocument(event.getOldFile());
if ( !psiMgr.isCommitted(doc) || docMgr.isDocumentUnsaved(doc) ) {
psiMgr.commitDocument(doc);
docMgr.saveDocument(doc);
}
}
currentEditorFileChangedEvent(event.getOldFile(), event.getNewFile(), modified);
}
}

@Override
public void fileClosed(FileEditorManager source, VirtualFile file) {
if ( !projectIsClosed && Objects.requireNonNull(source.getSelectedEditor()).getFile().equals(file) ) {
if ( !projectIsClosed && (source != null && source.getSelectedEditor() != null && source.getSelectedEditor().getFile().equals(file)) ) {
editorFileClosedEvent(file);
}
}
Expand Down
8 changes: 7 additions & 1 deletion src/test/java/org/antlr/intellij/plugin/TestUtils.java
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
package org.antlr.intellij.plugin;

import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.util.ThrowableRunnable;
import com.intellij.util.lang.CompoundRuntimeException;

import java.io.PrintWriter;
import java.io.StringWriter;

public class TestUtils {

public static void releaseEditorIfNotDisposed(Editor editor) {
if (!editor.isDisposed()) EditorFactory.getInstance().releaseEditor(editor);
}

public static void tearDownIgnoringObjectNotDisposedException(ThrowableRunnable<Exception> delegate) throws Exception {
try {
delegate.run();
Expand Down
98 changes: 98 additions & 0 deletions src/test/java/org/antlr/intellij/plugin/editor/Issue540Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package org.antlr.intellij.plugin.editor;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.WriteAction;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileEditor.FileDocumentManager;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiDocumentManager;
import com.intellij.testFramework.VfsTestUtil;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
import org.antlr.intellij.plugin.ANTLRv4PluginController;
import org.antlr.intellij.plugin.TestUtils;
import org.apache.commons.io.FileUtils;
import org.junit.Test;
import java.io.File;

public class Issue540Test extends BasePlatformTestCase {

private final File LEXER_FILE = new File(getTestDataPath()+"TestLexer.g4");
private final File PARSER_FILE = new File(getTestDataPath()+"TestParser.g4");
private final File TOKENS_FILE = new File(getTestDataGenPath()+"TestLexer.tokens");

@Test
public void test_shouldOnlyCreateTokensWhenModified() {

// Create files and controller
VirtualFile lexerFile = createAndOpenFile(LEXER_FILE, "lexer grammar TestLexer;\nTOKEN1: 'TOKEN1';");
VirtualFile parserFile = createAndOpenFile(PARSER_FILE, "parser grammar TestParser;\noptions {tokenVocab=TestLexer;}\nstartRule: TOKEN1;");
ANTLRv4PluginController controller = ANTLRv4PluginController.getInstance(getProject());

// No tokens should be created yet
assertFalse(TOKENS_FILE.exists());

// Add one token to file, switch to parser file and check that tokens were created
switchToFile(lexerFile);
addLineToCurrentFile("TOKEN2: 'TOKEN2';", lexerFile, controller);
switchToFile(parserFile);
assertTrue(TOKENS_FILE.exists());
long lastModified1 = TOKENS_FILE.lastModified();

// Switch to lexer file, add token, and check if tokens file was updated
switchToFile(lexerFile);
addLineToCurrentFile("TOKEN3: 'TOKEN3';", lexerFile, controller);
switchToFile(parserFile);
long lastModified2 = new File(TOKENS_FILE.getAbsolutePath()).lastModified();
assertTrue(lastModified2 > lastModified1);

// Switch back and forth again, and make sure tokens are not recreated
switchToFile(lexerFile);
switchToFile(parserFile);
assertEquals(lastModified2, TOKENS_FILE.lastModified());

}

private VirtualFile createAndOpenFile(File file, String contents) {
String absPath = file.getAbsolutePath();
VfsTestUtil.overwriteTestData(absPath, contents);
VirtualFile virtualFile = WriteAction.computeAndWait(() ->
LocalFileSystem.getInstance().refreshAndFindFileByPath(absPath));
myFixture.openFileInEditor(virtualFile);
return virtualFile;
}

private String getTestDataGenPath() {
return getTestDataPath() + "gen/";
}

private void addLineToCurrentFile(String line, VirtualFile file, ANTLRv4PluginController controller) {
ApplicationManager.getApplication().runWriteAction(() -> {
Document doc = myFixture.getEditor().getDocument();
doc.setText(doc.getText() + "\n" + line);
PsiDocumentManager.getInstance(getProject()).commitDocument(doc);
FileDocumentManager.getInstance().saveDocument(doc);
if (controller != null) controller.grammarFileSavedEvent(file);
});
}

private void switchToFile(VirtualFile vf) {
myFixture.openFileInEditor(vf);
}

@Override
protected String getTestDataPath() {
return "src/test/resources/";
}

@Override
protected void tearDown() throws Exception {
FileUtils.forceDeleteOnExit(LEXER_FILE);
FileUtils.forceDeleteOnExit(PARSER_FILE);
FileUtils.forceDeleteOnExit(new File(getTestDataGenPath()));
TestUtils.tearDownIgnoringObjectNotDisposedException(() -> {
super.tearDown();
});
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.antlr.intellij.plugin.editor;

import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
Expand Down Expand Up @@ -52,7 +51,7 @@ protected String getTestDataPath() {
@Override
protected void tearDown() throws Exception {
TestUtils.tearDownIgnoringObjectNotDisposedException(() -> {
EditorFactory.getInstance().releaseEditor(myFixture.getEditor());
TestUtils.releaseEditorIfNotDisposed(myFixture.getEditor());
super.tearDown();
});
}
Expand Down
50 changes: 50 additions & 0 deletions src/test/java/org/antlr/intellij/plugin/editor/Issue569Test.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package org.antlr.intellij.plugin.editor;

import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.fileTypes.FileTypes;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.testFramework.fixtures.BasePlatformTestCase;
import org.antlr.intellij.plugin.ANTLRv4FileType;
import org.antlr.intellij.plugin.ANTLRv4PluginController;
import org.antlr.intellij.plugin.TestUtils;
import org.junit.Test;

public class Issue569Test extends BasePlatformTestCase {

@Test
public void test_shouldReassignExtensionType() {

// Reassign extension temporarily
WriteCommandAction.runWriteCommandAction(getProject(), () ->
FileTypeManager.getInstance().associateExtension(FileTypes.PLAIN_TEXT, "g4"));

// Test File
VirtualFile file = myFixture.configureByFile("FooParser.g4").getVirtualFile();
assertEquals(file.getFileType(), FileTypes.PLAIN_TEXT);

// Create controller and initialize it
ANTLRv4PluginController controller = ANTLRv4PluginController.getInstance(getProject());
assertNotNull(controller);
controller.initComponent();

// Check if file type is reassigned
assertEquals(file.getFileType(), ANTLRv4FileType.INSTANCE);

}

@Override
protected String getTestDataPath() {
return "src/test/resources/references";
}

@Override
protected void tearDown() throws Exception {
TestUtils.tearDownIgnoringObjectNotDisposedException(() -> {
EditorFactory.getInstance().releaseEditor(myFixture.getEditor());
super.tearDown();
});
}

}

0 comments on commit 1700b68

Please sign in to comment.