Skip to content

Commit

Permalink
[#26] add missing contentTypeBindings
Browse files Browse the repository at this point in the history
The org.eclipse.tm4e.language_pack plug-in adds content types for C/C++
files. These content types needs to be considered during filtering
This is a fix for eclipse-tm4e/tm4e#499
  • Loading branch information
ghentschke committed Mar 8, 2023
1 parent 1f3aa8c commit b4f87cf
Show file tree
Hide file tree
Showing 6 changed files with 210 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.file.Files;

import org.eclipse.cdt.lsp.LspPlugin;
import org.eclipse.cdt.lsp.editor.ui.test.TestUtils;
import org.eclipse.cdt.lsp.server.ICLanguageServerProvider;
Expand All @@ -15,18 +17,24 @@
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.io.TempDir;


public class LspEditorPreferencesTesterTest {
private static final String FILE_CONTENT = "// sample file content";
private static final String MAIN_CPP = "main.cpp";
private static final String EXTERNAL_HEADER_HPP = "ExternalHeader.hpp";
private static final String HEADER_HPP = "header.hpp";
private static final String MAIN_C = "main.c";
private static final String HEADER_H = "header.h";
//private static final String EXTERNAL_HEADER_HPP = "ExternalHeader.hpp";
private IProject project;

@TempDir
private File tempDir;
// @TempDir -> does not work with org.junit.jupiter.api. Needs junit-jupiter-api and junit-jupiter-params.
// These packages are not accessible on the CI build server because we build with Eclipse 2022-06
// Path tempDir = Files.createTempFile("ExternalHeader", ".hpp", null);

private File createTempHppHeaderfile() throws IOException {
return Files.createTempFile("ExternalHeader", ".hpp").toFile();
}

@BeforeEach
public void setUp(TestInfo testInfo) throws CoreException {
Expand Down Expand Up @@ -81,11 +89,11 @@ public void testLsEnableByUriTest_WITHOUT_LsEditorPreferred() throws CoreExcepti
}

/**
* Tests whether the C/C++ Editor is used for a resource to open whose project has "Prefer C/C++ Editor (LSP)" disabled.
* Tests whether the C/C++ Editor is used for a C++ source file to open whose project has "Prefer C/C++ Editor (LSP)" disabled.
* @throws UnsupportedEncodingException
*/
@Test
public void testEditorUsedToOpenFile_WITHOUT_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
public void testEditorUsedToOpenCppFile_WITHOUT_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
//GIVEN is a project with DISABLED "Prefer C/C++ Editor (LSP)" in the preferences:
TestUtils.setLspPreferred(project, false);
//AND a file exits in the given project:
Expand All @@ -94,14 +102,15 @@ public void testEditorUsedToOpenFile_WITHOUT_LsEditorPreferred() throws CoreExce
var editorPart = TestUtils.openInEditor(file);
//THEN it will be opened in the C/C++ Editor:
assertEquals(LspPlugin.C_EDITOR_ID, editorPart.getEditorSite().getId());
TestUtils.closeEditor(editorPart, false);
}

/**
* Tests whether the C/C++ Editor (LSP) is used for a resource to open whose project has "Prefer C/C++ Editor (LSP)" enabled.
* Tests whether the C/C++ Editor (LSP) is used for a C++ source file to open whose project has "Prefer C/C++ Editor (LSP)" enabled.
* @throws UnsupportedEncodingException
*/
@Test
public void testEditorUsedToOpenFile_WITH_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
public void testEditorUsedToOpenCppFile_WITH_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
//GIVEN is a project with ENABLED "Prefer C/C++ Editor (LSP)" in the preferences:
TestUtils.setLspPreferred(project, true);
//AND a file exits in the given project:
Expand All @@ -110,6 +119,109 @@ public void testEditorUsedToOpenFile_WITH_LsEditorPreferred() throws CoreExcepti
var editorPart = TestUtils.openInEditor(file);
//THEN it will be opened in the C/C++ Editor (LSP):
assertEquals(LspPlugin.LSP_C_EDITOR_ID, editorPart.getEditorSite().getId());
TestUtils.closeEditor(editorPart, false);
}

/**
* Tests whether the C/C++ Editor is used for a C++ header file to open whose project has "Prefer C/C++ Editor (LSP)" disabled.
* @throws UnsupportedEncodingException
*/
@Test
public void testEditorUsedToOpenCppHeaderFile_WITHOUT_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
//GIVEN is a project with DISABLED "Prefer C/C++ Editor (LSP)" in the preferences:
TestUtils.setLspPreferred(project, false);
//AND a file exits in the given project:
var file = TestUtils.createFile(project, HEADER_HPP, FILE_CONTENT);
//WHEN this file will be opened:
var editorPart = TestUtils.openInEditor(file);
//THEN it will be opened in the C/C++ Editor:
assertEquals(LspPlugin.C_EDITOR_ID, editorPart.getEditorSite().getId());
TestUtils.closeEditor(editorPart, false);
}

/**
* Tests whether the C/C++ Editor (LSP) is used for a C++ header file to open whose project has "Prefer C/C++ Editor (LSP)" enabled.
* @throws UnsupportedEncodingException
*/
@Test
public void testEditorUsedToOpenCppHeaderFile_WITH_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
//GIVEN is a project with ENABLED "Prefer C/C++ Editor (LSP)" in the preferences:
TestUtils.setLspPreferred(project, true);
//AND a file exits in the given project:
var file = TestUtils.createFile(project, HEADER_HPP, FILE_CONTENT);
//WHEN this file will be opened:
var editorPart = TestUtils.openInEditor(file);
//THEN it will be opened in the C/C++ Editor (LSP):
assertEquals(LspPlugin.LSP_C_EDITOR_ID, editorPart.getEditorSite().getId());
TestUtils.closeEditor(editorPart, false);
}

/**
* Tests whether the C/C++ Editor is used for a C source file to open whose project has "Prefer C/C++ Editor (LSP)" disabled.
* @throws UnsupportedEncodingException
*/
@Test
public void testEditorUsedToOpenCFile_WITHOUT_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
//GIVEN is a project with DISABLED "Prefer C/C++ Editor (LSP)" in the preferences:
TestUtils.setLspPreferred(project, false);
//AND a file exits in the given project:
var file = TestUtils.createFile(project, MAIN_C, FILE_CONTENT);
//WHEN this file will be opened:
var editorPart = TestUtils.openInEditor(file);
//THEN it will be opened in the C/C++ Editor:
assertEquals(LspPlugin.C_EDITOR_ID, editorPart.getEditorSite().getId());
TestUtils.closeEditor(editorPart, false);
}

/**
* Tests whether the C/C++ Editor (LSP) is used for a C source file to open whose project has "Prefer C/C++ Editor (LSP)" enabled.
* @throws UnsupportedEncodingException
*/
@Test
public void testEditorUsedToOpenCFile_WITH_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
//GIVEN is a project with ENABLED "Prefer C/C++ Editor (LSP)" in the preferences:
TestUtils.setLspPreferred(project, true);
//AND a file exits in the given project:
var file = TestUtils.createFile(project, MAIN_C, FILE_CONTENT);
//WHEN this file will be opened:
var editorPart = TestUtils.openInEditor(file);
//THEN it will be opened in the C/C++ Editor (LSP):
assertEquals(LspPlugin.LSP_C_EDITOR_ID, editorPart.getEditorSite().getId());
TestUtils.closeEditor(editorPart, false);
}

/**
* Tests whether the C/C++ Editor is used for a C header file to open whose project has "Prefer C/C++ Editor (LSP)" disabled.
* @throws UnsupportedEncodingException
*/
@Test
public void testEditorUsedToOpenCHeaderFile_WITHOUT_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
//GIVEN is a project with DISABLED "Prefer C/C++ Editor (LSP)" in the preferences:
TestUtils.setLspPreferred(project, false);
//AND a file exits in the given project:
var file = TestUtils.createFile(project, HEADER_HPP, FILE_CONTENT);
//WHEN this file will be opened:
var editorPart = TestUtils.openInEditor(file);
//THEN it will be opened in the C/C++ Editor:
assertEquals(LspPlugin.C_EDITOR_ID, editorPart.getEditorSite().getId());
TestUtils.closeEditor(editorPart, false);
}

/**
* Tests whether the C/C++ Editor (LSP) is used for a C header file to open whose project has "Prefer C/C++ Editor (LSP)" enabled.
* @throws UnsupportedEncodingException
*/
@Test
public void testEditorUsedToOpenCHeaderFile_WITH_LsEditorPreferred() throws CoreException, UnsupportedEncodingException {
//GIVEN is a project with ENABLED "Prefer C/C++ Editor (LSP)" in the preferences:
TestUtils.setLspPreferred(project, true);
//AND a file exits in the given project:
var file = TestUtils.createFile(project, HEADER_H, FILE_CONTENT);
//WHEN this file will be opened:
var editorPart = TestUtils.openInEditor(file);
//THEN it will be opened in the C/C++ Editor (LSP):
assertEquals(LspPlugin.LSP_C_EDITOR_ID, editorPart.getEditorSite().getId());
TestUtils.closeEditor(editorPart, false);
}

/**
Expand All @@ -119,12 +231,14 @@ public void testEditorUsedToOpenFile_WITH_LsEditorPreferred() throws CoreExcepti
@Test
public void testLsEnableByExternalUriTest_NoEditorOpen() throws CoreException, IOException {
//GIVEN is an external file which does not exists in the given project and is not opened:
File externalFile = new File(tempDir, EXTERNAL_HEADER_HPP);
File externalFile = createTempHppHeaderfile();
//AND a ICLanguageServerProvider which uses LspEditorPreferencesTester as enabledWhen tester:
ICLanguageServerProvider cLanguageServerProvider = LspPlugin.getDefault().getCLanguageServerProvider();
//WHEN the LspEditorPreferencesTester gets called by the property tester in the enabledWhen element of the serverProvider extension point,
//THEN the LspEditorPreferencesTester.test returns FALSE for the given file URI:
assertTrue(!cLanguageServerProvider.isEnabledFor(externalFile.toURI()));
//ensure clean up
externalFile.delete();
}

/**
Expand All @@ -133,7 +247,7 @@ public void testLsEnableByExternalUriTest_NoEditorOpen() throws CoreException, I
@Test
public void testLsEnableByExternalUriTest_OpenedInLspCEditor() throws CoreException, IOException {
//GIVEN is an existing external file:
File externalFile = new File(tempDir, EXTERNAL_HEADER_HPP);
File externalFile = createTempHppHeaderfile();
externalFile.createNewFile();
//AND it's opened in the LSP based C/C++ Editor:
var editor = TestUtils.openInEditor(externalFile.toURI(), LspPlugin.LSP_C_EDITOR_ID);
Expand All @@ -143,6 +257,8 @@ public void testLsEnableByExternalUriTest_OpenedInLspCEditor() throws CoreExcept
//THEN the LspEditorPreferencesTester.test returns TRUE for the given file URI:
assertTrue(cLanguageServerProvider.isEnabledFor(externalFile.toURI()));
TestUtils.closeEditor(editor, false);
//ensure clean up
externalFile.delete();
}

/**
Expand All @@ -151,7 +267,7 @@ public void testLsEnableByExternalUriTest_OpenedInLspCEditor() throws CoreExcept
@Test
public void testLsEnableByExternalUriTest_OpenedInCEditor() throws CoreException, IOException {
//GIVEN is an existing external file:
File externalFile = new File(tempDir, EXTERNAL_HEADER_HPP);
File externalFile = createTempHppHeaderfile();
externalFile.createNewFile();
//AND it's opened in the C/C++ Editor:
var editor = TestUtils.openInEditor(externalFile.toURI(), LspPlugin.C_EDITOR_ID);
Expand All @@ -161,6 +277,8 @@ public void testLsEnableByExternalUriTest_OpenedInCEditor() throws CoreException
//THEN the LspEditorPreferencesTester.test returns FALSE for the given file URI:
assertTrue(!cLanguageServerProvider.isEnabledFor(externalFile.toURI()));
TestUtils.closeEditor(editor, false);
//ensure clean up
externalFile.delete();
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import java.util.Set;
import java.util.stream.Stream;

import org.eclipse.cdt.lsp.LspUtils;
import org.eclipse.cdt.lsp.editor.ui.LspEditorUiPlugin;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
Expand Down Expand Up @@ -71,8 +72,7 @@ private boolean isCppFile(IResource resource) {
if (resource instanceof IFile) {
var contentTypes = Platform.getContentTypeManager().findContentTypesFor(((IFile) resource).getName());
return Arrays.stream(contentTypes).anyMatch(contentType -> {
var id = contentType.getId();
return id.startsWith("org.eclipse.cdt.core.c") && (id.endsWith("Source") || id.endsWith("Header"));
return LspUtils.isCContentType(contentType.getId());
});
}
return false;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.eclipse.cdt.lsp.test;

import static org.junit.jupiter.api.Assertions.*;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.lsp.LspUtils;
import org.junit.jupiter.api.Test;

class LspUtilsTest {

@Test
void testIsCContentType_EmptyId() {
assertTrue(!LspUtils.isCContentType(""));
}

@Test
void testIsCContentType_CppContentTypeFromTM4E() {
assertTrue(LspUtils.isCContentType("lng.cpp"));
}

@Test
void testIsCContentType_CONTENT_TYPE_CSOURCE() {
assertTrue(LspUtils.isCContentType(CCorePlugin.CONTENT_TYPE_CSOURCE));
}

@Test
void testIsCContentType_CONTENT_TYPE_CHEADER() {
assertTrue(LspUtils.isCContentType(CCorePlugin.CONTENT_TYPE_CHEADER));
}

@Test
void testIsCContentType_CONTENT_TYPE_CXXSOURCE() {
assertTrue(LspUtils.isCContentType(CCorePlugin.CONTENT_TYPE_CXXSOURCE));
}

@Test
void testIsCContentType_CONTENT_TYPE_CXXHEADER() {
assertTrue(LspUtils.isCContentType(CCorePlugin.CONTENT_TYPE_CXXHEADER));
}

}
9 changes: 9 additions & 0 deletions bundles/org.eclipse.cdt.lsp/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,16 @@
<contentTypeBinding
contentTypeId="org.eclipse.cdt.core.cxxSource">
</contentTypeBinding>
<contentTypeBinding
contentTypeId="lng.cpp"> <!-- // TODO: The content type definition from TM4E "lng.cpp" can be omitted here if either https://github.com/eclipse-cdt/cdt/pull/310 or
// https://github.com/eclipse/tm4e/pull/500 has been merged. -->
</contentTypeBinding>
</editor>
<editorContentTypeBinding
contentTypeId="lng.cpp"
editorId="org.eclipse.cdt.ui.editor.CEditor"> <!-- // TODO: The content type definition from TM4E "lng.cpp" can be omitted here if either https://github.com/eclipse-cdt/cdt/pull/310 or
// https://github.com/eclipse/tm4e/pull/500 has been merged. -->
</editorContentTypeBinding>
</extension>
<extension
point="org.eclipse.lsp4e.languageServer">
Expand Down
17 changes: 17 additions & 0 deletions bundles/org.eclipse.cdt.lsp/src/org/eclipse/cdt/lsp/LspUtils.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.eclipse.cdt.lsp;

public class LspUtils {

/**
* Checks if given ContentType id matches the content types for C/C++ files.
*
* @param id ContentType id
* @return {@code true} if C/C++ content type
*/
public static boolean isCContentType(String id) {
// TODO: The content type definition from TM4E "lng.cpp" can be omitted if either https://github.com/eclipse-cdt/cdt/pull/310 or
// https://github.com/eclipse/tm4e/pull/500 has been merged.
return ( id.startsWith("org.eclipse.cdt.core.c") && (id.endsWith("Source") || id.endsWith("Header")) ) || "lng.cpp".equals(id);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@

package org.eclipse.cdt.lsp.editor;

import org.eclipse.cdt.core.CCorePlugin;
import org.eclipse.cdt.lsp.LspPlugin;
import org.eclipse.cdt.lsp.LspUtils;
import org.eclipse.cdt.lsp.server.ICLanguageServerProvider;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
Expand Down Expand Up @@ -72,12 +72,10 @@ public IEditorDescriptor overrideDefaultEditor(String fileName, IContentType con
}

private boolean isNoCElement(IContentType contentType) {
if (contentType == null || !(CCorePlugin.CONTENT_TYPE_CHEADER.equals(contentType.getId()) ||
CCorePlugin.CONTENT_TYPE_CSOURCE.equals(contentType.getId()) ||
CCorePlugin.CONTENT_TYPE_CXXHEADER.equals(contentType.getId()) ||
CCorePlugin.CONTENT_TYPE_CXXSOURCE.equals(contentType.getId())))
if (contentType == null) {
return true;
return false;
}
return !LspUtils.isCContentType(contentType.getId());
}

private IEditorDescriptor[] editorFilter(String editorId, IEditorDescriptor[] editorDescriptors) {
Expand All @@ -100,15 +98,17 @@ private IEditorDescriptor getEditorDescriptor(IEditorInput editorInput, IContent
return null;

if (cLanguageServerProvider.isEnabledFor(editorInput)) {
return getLspCEditor(editorInput, contentType);
}
return null;
return getEditorDescriptorById(editorInput.getName(), LspPlugin.LSP_C_EDITOR_ID, contentType); // return LSP based C/C++ Editor
}
// TODO: return null; when either https://github.com/eclipse-cdt/cdt/pull/310 or
// https://github.com/eclipse/tm4e/pull/500 has been merged.
return getEditorDescriptorById(editorInput.getName(), LspPlugin.C_EDITOR_ID, contentType); // return C/C++ Editor
}

private IEditorDescriptor getLspCEditor(IEditorInput editorInput, IContentType contentType) {
private IEditorDescriptor getEditorDescriptorById(String fileName, String editorId, IContentType contentType) {
IEditorRegistry registry = PlatformUI.getWorkbench().getEditorRegistry();
for (IEditorDescriptor descriptor : registry.getEditors(editorInput.getName(), contentType)) {
if (LspPlugin.LSP_C_EDITOR_ID.equals(descriptor.getId())) {
for (IEditorDescriptor descriptor : registry.getEditors(fileName, contentType)) {
if (editorId.equals(descriptor.getId())) {
return descriptor;
}
}
Expand Down

0 comments on commit b4f87cf

Please sign in to comment.