SpringJavaFormatterService.java
/*
* Copyright (c) 2020 bahlef.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
* Contributors:
* bahlef - initial API and implementation and/or initial documentation
*/
package de.funfried.netbeans.plugins.external.formatter.java.spring;
import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;
import java.util.Properties;
import java.util.SortedSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.prefs.Preferences;
import javax.swing.text.BadLocationException;
import javax.swing.text.Document;
import javax.swing.text.StyledDocument;
import org.apache.commons.lang3.tuple.Pair;
import org.netbeans.api.annotations.common.CheckForNull;
import org.netbeans.api.annotations.common.NonNull;
import org.netbeans.api.project.Project;
import org.openide.util.NbBundle;
import org.openide.util.lookup.ServiceProvider;
import de.funfried.netbeans.plugins.external.formatter.FormatterService;
import de.funfried.netbeans.plugins.external.formatter.java.base.AbstractJavaFormatterService;
import de.funfried.netbeans.plugins.external.formatter.java.spring.ui.SpringJavaFormatterOptionsPanel;
import de.funfried.netbeans.plugins.external.formatter.ui.options.FormatterOptionsPanel;
import de.funfried.netbeans.plugins.external.formatter.ui.options.Settings;
import io.spring.javaformat.formatter.eclipse.EclipseCodeFormatter;
/**
* Spring implementation of the {@link AbstractJavaFormatterService}.
*
* @author bahlef
*/
@NbBundle.Messages({
"FormatterName=Spring Java Code Formatter"
})
@ServiceProvider(service = FormatterService.class, position = 1500)
public class SpringJavaFormatterService extends AbstractJavaFormatterService<SpringFormatJob> {
/** {@link Logger} of this class. */
private static final Logger log = Logger.getLogger(SpringJavaFormatterService.class.getName());
/** The ID of this formatter service. */
public static final String ID = "spring-java-formatter";
/** * The {@link SpringJavaFormatterWrapper} implementation. */
private final SpringJavaFormatterWrapper formatter = new SpringJavaFormatterWrapper();
/**
* {@inheritDoc}
*/
@NonNull
@Override
public String getDisplayName() {
return NbBundle.getMessage(SpringJavaFormatterService.class, "FormatterName");
}
/**
* {@inheritDoc}
*/
@NonNull
@Override
public String getId() {
return ID;
}
/**
* {@inheritDoc}
*/
@Override
public FormatterOptionsPanel createOptionsPanel(Project project) {
return new SpringJavaFormatterOptionsPanel(project);
}
/**
* {@inheritDoc}
*/
@CheckForNull
@Override
public Integer getContinuationIndentSize(Document document) {
if (document == null) {
return null;
}
Integer ret = null;
Preferences preferences = Settings.getActivePreferences(document);
if (isUseFormatterIndentationSettings(preferences)) {
String propKey = "core.formatter.continuation_indentation";
String prop = this.getSpringFormatterProperty(propKey);
if (prop != null) {
try {
ret = Integer.parseInt(prop);
Integer indentSize = getIndentSize(document);
if (indentSize != null) {
ret *= indentSize;
}
} catch (NumberFormatException ex) {
log.log(Level.WARNING, "Property '" + propKey + "' is not an integer: " + prop, ex);
}
}
if (ret == null) {
ret = 2;
}
}
return ret;
}
/**
* {@inheritDoc}
*/
@CheckForNull
@Override
public Integer getIndentSize(Document document) {
if (document == null) {
return null;
}
Integer ret = null;
Preferences preferences = Settings.getActivePreferences(document);
if (isUseFormatterIndentationSettings(preferences)) {
String tabChar = getSpringFormatterProperty("core.formatter.tabulation.char");
if (Objects.equals(tabChar, "mixed")) {
String propKey = "core.formatter.indentation.size";
String prop = this.getSpringFormatterProperty(propKey);
if (prop != null) {
try {
ret = Integer.parseInt(prop);
} catch (NumberFormatException ex) {
log.log(Level.WARNING, "Property '" + propKey + "' is not an integer: " + prop, ex);
}
}
} else {
ret = getSpacesPerTab(document);
}
if (ret == null) {
ret = 4;
}
}
return ret;
}
/**
* {@inheritDoc}
*/
@CheckForNull
@Override
public Integer getRightMargin(Document document) {
if (document == null) {
return null;
}
Integer ret = 120;
String propKey = "core.formatter.lineSplit";
String prop = this.getSpringFormatterProperty(propKey);
if (prop != null) {
try {
ret = Integer.parseInt(prop);
} catch (NumberFormatException ex) {
log.log(Level.WARNING, "Property '" + propKey + "' is not an integer: " + prop, ex);
}
}
return ret;
}
/**
* {@inheritDoc}
*/
@Override
protected SpringFormatJob getFormatJob(StyledDocument document, SortedSet<Pair<Integer, Integer>> changedElements) {
return new SpringFormatJob(document, formatter, changedElements);
}
/**
* {@inheritDoc}
*/
@CheckForNull
@Override
public Integer getSpacesPerTab(Document document) {
if (document == null) {
return null;
}
Integer ret = null;
Preferences preferences = Settings.getActivePreferences(document);
if (isUseFormatterIndentationSettings(preferences)) {
if (!isExpandTabToSpaces(document, preferences) && preferences.getBoolean(Settings.OVERRIDE_TAB_SIZE, true)) {
ret = preferences.getInt(Settings.OVERRIDE_TAB_SIZE_VALUE, 4);
} else {
String propKey = "core.formatter.tabulation.size";
String prop = this.getSpringFormatterProperty(propKey);
if (prop != null) {
try {
ret = Integer.parseInt(prop);
} catch (NumberFormatException ex) {
log.log(Level.WARNING, "Property '" + propKey + "' is not an integer: " + prop, ex);
}
}
if (ret == null) {
ret = 4;
}
}
}
return ret;
}
/**
* Reads the configuration value of the internal Spring formatter configuration for the
* given {@code key}.
*
* @param key the key of the value which should be read
*
* @return the configuration value of the internal Spring formatter configuration for
* the given {@code key}
*/
private String getSpringFormatterProperty(String key) {
Properties props = new Properties();
try (InputStream is = EclipseCodeFormatter.class.getResourceAsStream("formatter.prefs")) {
props.load(is);
} catch (IOException ex) {
log.log(Level.SEVERE, "Could not read internal Spring formatter configuration", ex);
}
return props.getProperty(key);
}
/**
* {@inheritDoc}
*/
@CheckForNull
@Override
public Boolean isExpandTabToSpaces(Document document) {
if (document == null) {
return null;
}
return isExpandTabToSpaces(document, Settings.getActivePreferences(document));
}
@CheckForNull
private Boolean isExpandTabToSpaces(Document document, Preferences preferences) {
if (document == null || preferences == null) {
return null;
}
Boolean ret = null;
if (isUseFormatterIndentationSettings(preferences)) {
String propKey = "core.formatter.tabulation.char";
String prop = this.getSpringFormatterProperty(propKey);
if (prop != null) {
ret = Objects.equals(prop, "space");
}
if (ret == null) {
ret = false;
}
}
return ret;
}
/**
* Returns {@code true} if using the formatter indentation settings from the external
* formatter is activated, otherwise {@code false}.
*
* @param prefs the {@link Preferences} where to check
*
* @return {@code true} if using the formatter indentation settings from the external
* formatter is activated, otherwise {@code false}
*/
private boolean isUseFormatterIndentationSettings(Preferences prefs) {
return prefs.getBoolean(Settings.ENABLE_USE_OF_INDENTATION_SETTINGS, true);
}
/**
* {@inheritDoc}
*/
@Override
@CheckForNull
public Boolean organizeImports(StyledDocument document, boolean afterFixImports) throws BadLocationException {
return null;
}
}