Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.lsp4j.FormattingOptions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.NullSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.junit.jupiter.MockitoExtension;

import com.microsoft.copilot.eclipse.core.format.FormatOptionProvider;
Expand All @@ -25,7 +30,9 @@ class FormatOptionProviderTests {
private IFile mockFile;
private IProject mockProject;

private static final int PREFERENCE_DEFAULT_TAB_SIZE = 4;
private static final String EDITOR_PREF_NODE = "org.eclipse.ui.editors";
private static final String TAB_WIDTH_KEY = "tabWidth";
private static final String SPACES_FOR_TABS_KEY = "spacesForTabs";

@BeforeEach
void setUp() {
Expand All @@ -52,20 +59,20 @@ void testGetEclipseDefaultJavaTabCharAndSize() {
assertEquals(tabSize, formatOptionProvider.getTabSize(mockFile));
}

@Test
void testGetCopilotDefaultTabCharAndSizeForUnknownLanguage() {
when(mockFile.getFileExtension()).thenReturn("js");

assertTrue(formatOptionProvider.useSpace(mockFile));
assertEquals(PREFERENCE_DEFAULT_TAB_SIZE, formatOptionProvider.getTabSize(mockFile));
}
@ParameterizedTest @NullSource @ValueSource(strings = { "js" })
void testUsesEclipseTextEditorFormattingOptionsForUnknownOrNoExtension(String extension) {
when(mockFile.getFileExtension()).thenReturn(extension);

@Test
void testGetCopilotDefaultTabCharAndSizeForNoExtensionFile() {
when(mockFile.getFileExtension()).thenReturn(null);
// Set the Eclipse preferences to be something other than the default (false, 4)
setEditorFormattingPreferences(true, 2);

assertTrue(formatOptionProvider.useSpace(mockFile));
assertEquals(PREFERENCE_DEFAULT_TAB_SIZE, formatOptionProvider.getTabSize(mockFile));
assertEquals(2, formatOptionProvider.getTabSize(mockFile));
}

private void setEditorFormattingPreferences(boolean useSpaces, int tabSize) {
IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(EDITOR_PREF_NODE);
prefs.putBoolean(SPACES_FOR_TABS_KEY, useSpaces);
prefs.putInt(TAB_WIDTH_KEY, tabSize);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.preferences.IPreferencesService;
import org.eclipse.lsp4j.FormattingOptions;

import com.microsoft.copilot.eclipse.core.CopilotCore;
Expand All @@ -26,6 +28,9 @@ public class FormatOptionProvider {
private static final String CPP_LANGUAGE_ID = "cpp";
private static final String[] CPP_LANGUAGE_EXTENSIONS = new String[] { "cpp", "c++", "cc", "cp", "cxx", "h", "h++",
"hh", ".hpp", ".hxx", ".inc", ".inl", ".ipp", ".tcc", ".tpp" };
private static final String EDITOR_PREF_NODE = "org.eclipse.ui.editors";
private static final String TAB_WIDTH_KEY = "tabWidth";
private static final String SPACES_FOR_TABS_KEY = "spacesForTabs";
private static final boolean DEFAULT_USE_SPACE = LanguageFormatReader.PREFERENCE_DEFAULT_TAB_CHAR.equals("space");
private static final int DEFAULT_TAB_SIZE = LanguageFormatReader.PREFERENCE_DEFAULT_TAB_SIZE;

Expand Down Expand Up @@ -85,13 +90,13 @@ private FormattingOptions getLanguageFormat(IFile file) {
IProject project = file.getProject();
if (project == null) {
CopilotCore.LOGGER.info("Project is null for file: " + file.getName() + "default format will be applied.");
return null;
return getEclipseTextEditorFormattingOptions();
}

String fileExtension = file.getFileExtension();
if (StringUtils.isEmpty(fileExtension)) {
CopilotCore.LOGGER.info("File extension is null or empty for file: " + file.getName());
return null;
return getEclipseTextEditorFormattingOptions();
} else {
fileExtension = fileExtension.toLowerCase();
}
Expand All @@ -110,14 +115,46 @@ private FormattingOptions getLanguageFormat(IFile file) {
if (languageFormatReaderForProject == null) {
languageFormatReaderForProject = loadFormatReaderForTheProject(languageId, project);
if (languageFormatReaderForProject == null) {
return new FormattingOptions(DEFAULT_TAB_SIZE, DEFAULT_USE_SPACE);
return getEclipseTextEditorFormattingOptions();
}
projectToLanguageFormatReaderMap.put(project, languageFormatReaderForProject);
}

return languageFormatReaderForProject.getFormattingOptions();
}

/**
* Attempts to read the Eclipse default text editor preferences for tab size and spaces-for-tabs.
* Falls back to hardcoded defaults if the preferences cannot be read.
*/
private FormattingOptions getEclipseTextEditorFormattingOptions() {
try {
IPreferencesService service = Platform.getPreferencesService();

boolean useSpaces = service.getBoolean(
EDITOR_PREF_NODE,
SPACES_FOR_TABS_KEY,
DEFAULT_USE_SPACE,
null
);

int tabSize = service.getInt(
EDITOR_PREF_NODE,
TAB_WIDTH_KEY,
DEFAULT_TAB_SIZE,
null
);

return new FormattingOptions(tabSize, useSpaces);
} catch (Exception e) {
CopilotCore.LOGGER.info(
"Failed to read Eclipse text editor preferences, using defaults");
return new FormattingOptions(DEFAULT_TAB_SIZE, DEFAULT_USE_SPACE);
}
}



private LanguageFormatReader loadFormatReaderForTheProject(String languageId, IProject project) {
switch (languageId) {
case JAVA_LANGUAGE_ID:
Expand All @@ -129,4 +166,4 @@ private LanguageFormatReader loadFormatReaderForTheProject(String languageId, IP
return null;
}
}
}
}
Loading