Replace old java formatter to jdt.ls formatter (#8829)

Signed-off-by: Valeriy Svydenko <vsvydenk@redhat.com>
6.19.x
Valeriy Svydenko 2018-02-20 21:15:13 +02:00 committed by Thomas Mäder
parent 0e98bda4a0
commit fc2f76bc5c
9 changed files with 92 additions and 222 deletions

View File

@ -1,27 +0,0 @@
/**
* ***************************************************************************** Copyright (c)
* 2012-2015 Red Hat, Inc. All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* <p>Contributors: Red Hat, Inc. - initial API and implementation
* *****************************************************************************
*/
package org.eclipse.jdt.internal.corext.format;
import java.util.Hashtable;
import java.util.Map;
import org.eclipse.jdt.internal.core.JavaModelManager;
/** @author Roman Nikitenko */
public class CheCodeFormatterInitializer {
@SuppressWarnings("unchecked")
public void initializeDefaultPreferences() {
Map<String, String> codeFormatterDefaultSettings =
CheCodeFormatterOptions.getDefaultFormatSettings();
Hashtable<String, String> options = JavaModelManager.getJavaModelManager().getOptions();
options.putAll(codeFormatterDefaultSettings);
JavaModelManager.getJavaModelManager().setOptions(options);
}
}

View File

@ -1,71 +0,0 @@
/**
* ***************************************************************************** Copyright (c)
* 2012-2015 Red Hat, Inc. All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* <p>Contributors: Red Hat, Inc. - initial API and implementation
* *****************************************************************************
*/
package org.eclipse.jdt.internal.corext.format;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
/** @author Roman Nikitenko */
public class CheCodeFormatterOptions {
private static final Logger LOG = LoggerFactory.getLogger(CheCodeFormatterInitializer.class);
private static final String DEFAULT_CODESTYLE = "che-codestyle-eclipse_.xml";
private static Map<String, String> formatSettings;
public static Map<String, String> getDefaultFormatSettings() {
if (formatSettings != null && !formatSettings.isEmpty()) {
return formatSettings;
}
formatSettings = new CheCodeFormatterOptions().getCheDefaultSettings();
if (formatSettings != null && !formatSettings.isEmpty()) {
return formatSettings;
}
return DefaultCodeFormatterConstants.getEclipseDefaultSettings();
}
/**
* Parses code formatter file.
*
* @param file file which describes formatting settings
* @return map with formatting settings
*/
public static Map<String, String> getFormatSettingsFromFile(File file) {
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLParser parserXML = new XMLParser();
try (FileInputStream fis = new FileInputStream(file)) {
SAXParser parser = factory.newSAXParser();
parser.parse(fis, parserXML);
} catch (ParserConfigurationException | SAXException | IOException e) {
LOG.error("It is not possible to parse file " + file.getName(), e);
}
return parserXML.getSettings();
}
private Map<String, String> getCheDefaultSettings() {
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLParser parserXML = new XMLParser();
try {
SAXParser parser = factory.newSAXParser();
parser.parse(getClass().getResourceAsStream(DEFAULT_CODESTYLE), parserXML);
} catch (ParserConfigurationException | SAXException | IOException e) {
LOG.error("It is not possible to parse file " + DEFAULT_CODESTYLE, e);
}
return parserXML.getSettings();
}
}

View File

@ -1,52 +0,0 @@
/**
* ***************************************************************************** Copyright (c)
* 2012-2015 Red Hat, Inc. All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* <p>Contributors: Red Hat, Inc. - initial API and implementation
* *****************************************************************************
*/
package org.eclipse.jdt.internal.corext.format;
import java.io.File;
import java.util.List;
import java.util.Map;
import org.eclipse.che.ide.ext.java.shared.dto.Change;
import org.eclipse.jdt.core.formatter.CodeFormatter;
import org.eclipse.jdt.internal.corext.util.CodeFormatterUtil;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.TextEdit;
/** @author Roman Nikitenko */
public class Formatter {
/**
* Creates edits that describe how to format the given string. Returns the changes required to
* format source.
*
* @param formatter The file with custom formatter settings
* @param content The content to format
* @param offset The given offset to start recording the edits (inclusive).
* @param length the given length to stop recording the edits (exclusive).
* @return <code>List<Change></code> describing the changes required to format source
* @throws IllegalArgumentException If the offset and length are not inside the string, a
* IllegalArgumentException is thrown.
*/
public List<Change> getFormatChanges(File formatter, String content, int offset, int length)
throws BadLocationException, IllegalArgumentException {
IDocument document = new Document(content);
DocumentChangeListener documentChangeListener = new DocumentChangeListener(document);
Map<String, String> options = null;
if (formatter != null && formatter.exists()) {
options = CheCodeFormatterOptions.getFormatSettingsFromFile(formatter);
}
TextEdit textEdit =
CodeFormatterUtil.format2(
CodeFormatter.K_COMPILATION_UNIT, content, offset, length, 0, null, options);
textEdit.apply(document);
return documentChangeListener.getChanges();
}
}

View File

@ -26,7 +26,6 @@ import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.internal.core.JavaCorePreferenceInitializer;
import org.eclipse.jdt.internal.corext.format.CheCodeFormatterInitializer;
import org.eclipse.jdt.internal.corext.template.java.AbstractJavaContextType;
import org.eclipse.jdt.internal.corext.template.java.CodeTemplateContextType;
import org.eclipse.jdt.internal.corext.template.java.JavaContextType;
@ -210,7 +209,6 @@ public class JavaPlugin {
fMembersOrderPreferenceCache = new MembersOrderPreferenceCache();
PreferenceConstants.initializeDefaultValues(PreferenceConstants.getPreferenceStore());
new JavaCorePreferenceInitializer().initializeDefaultPreferences();
new CheCodeFormatterInitializer().initializeDefaultPreferences();
}
@PreDestroy

View File

@ -18,82 +18,31 @@ import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import java.io.File;
import java.util.List;
import javax.inject.Inject;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import org.eclipse.che.api.core.ConflictException;
import org.eclipse.che.api.core.NotFoundException;
import org.eclipse.che.api.core.ServerException;
import org.eclipse.che.api.fs.server.FsManager;
import org.eclipse.che.api.fs.server.PathTransformer;
import org.eclipse.che.ide.ext.java.shared.dto.Change;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.internal.core.JavaModel;
import org.eclipse.jdt.internal.core.JavaModelManager;
import org.eclipse.jdt.internal.corext.format.Formatter;
import org.eclipse.jface.text.BadLocationException;
/**
* Java formatter service. Have a functionality to format java code and update formatter
* configuration for the project or for whole workspace.
* Java formatter service. Updates formatter's configuration for the project or for whole workspace.
*/
@Path("java/formatter/")
public class JavaFormatterService {
private static final String CHE_FOLDER = ".che";
private static final String CHE_FORMATTER_XML = "che-formatter.xml";
private static final JavaModel model = JavaModelManager.getJavaModelManager().getJavaModel();
public static final String CHE_FOLDER = ".che";
public static final String CHE_FORMATTER_XML = "che-formatter.xml";
private final FsManager fsManager;
private final PathTransformer pathTransformer;
private Formatter formatter;
@Inject
public JavaFormatterService(
FsManager fsManager, PathTransformer pathTransformer, Formatter formatter) {
public JavaFormatterService(FsManager fsManager) {
this.fsManager = fsManager;
this.pathTransformer = pathTransformer;
this.formatter = formatter;
}
@POST
@Path("/format")
@Consumes(MediaType.TEXT_PLAIN)
@Produces({MediaType.APPLICATION_JSON})
@ApiOperation(value = "Creates edits that describe how to format the given string")
@ApiResponses({
@ApiResponse(code = 200, message = "The response contains all changes after formating"),
@ApiResponse(code = 500, message = "Internal server error occurred")
})
public List<Change> getFormatChanges(
@ApiParam(value = "Path to the root project") @QueryParam("projectpath") String projectPath,
@ApiParam(value = "The given offset to start recording the edits (inclusive)")
@QueryParam("offset")
int offset,
@ApiParam(value = "The given length to stop recording the edits (exclusive)")
@QueryParam("length")
int length,
@ApiParam(value = "The content to format. Java code formatting is supported only")
String content)
throws BadLocationException, IllegalArgumentException {
IJavaProject javaProject = model.getJavaProject(projectPath);
String formatterPath = CHE_FOLDER + '/' + CHE_FORMATTER_XML;
File file = null;
IFile iFile = javaProject.getProject().getFile(formatterPath);
if (iFile != null) {
file = iFile.getLocation().toFile();
}
if (file == null || !file.exists()) {
file = getFormatterFromRootFolder(formatterPath);
}
return formatter.getFormatChanges(file, content, offset, length);
}
@POST
@ -161,9 +110,4 @@ public class JavaFormatterService {
throw new ServerException(e);
}
}
private File getFormatterFromRootFolder(String formatterPath) {
return fsManager.toIoFile(absolutize(formatterPath));
}
}

View File

@ -89,6 +89,10 @@
<groupId>org.eclipse.che.ls.jdt</groupId>
<artifactId>jdt.ls.extension.api</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.plugin</groupId>
<artifactId>che-plugin-java-ext-lang-server</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.che.plugin</groupId>
<artifactId>che-plugin-java-ext-lang-shared</artifactId>

View File

@ -10,13 +10,39 @@
*/
package org.eclipse.che.plugin.java.languageserver;
import static org.eclipse.che.api.fs.server.WsPathUtils.SEPARATOR;
import static org.eclipse.che.api.languageserver.service.LanguageServiceUtils.PROJECTS;
import static org.eclipse.che.api.languageserver.service.LanguageServiceUtils.extractProjectPath;
import static org.eclipse.che.plugin.java.server.rest.JavaFormatterService.CHE_FOLDER;
import static org.eclipse.che.plugin.java.server.rest.JavaFormatterService.CHE_FORMATTER_XML;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.che.api.fs.server.WsPathUtils;
import org.eclipse.che.api.languageserver.exception.LanguageServerException;
import org.eclipse.lsp4j.CodeActionParams;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.DocumentFormattingParams;
import org.eclipse.lsp4j.FormattingOptions;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
public class JavaTextDocumentServiceWraper {
private static final Logger LOG = LoggerFactory.getLogger(JavaTextDocumentServiceWraper.class);
private TextDocumentService wrapped;
public JavaTextDocumentServiceWraper(TextDocumentService wrapped) {
@ -36,4 +62,51 @@ public class JavaTextDocumentServiceWraper {
return commands;
});
}
public CompletableFuture<List<? extends TextEdit>> formatting(DocumentFormattingParams params)
throws LanguageServerException {
String fileUri = params.getTextDocument().getUri();
FormattingOptions options = params.getOptions();
if (options == null) {
options = new FormattingOptions();
params.setOptions(options);
}
updateFormatterOptions(params, fileUri);
return wrapped.formatting(params);
}
private void updateFormatterOptions(DocumentFormattingParams params, String fileUri)
throws LanguageServerException {
String projectPath = WsPathUtils.absolutize(extractProjectPath(fileUri));
String formatterPathSuffix = CHE_FOLDER + SEPARATOR + CHE_FORMATTER_XML;
Path projectFormatterPath = Paths.get(projectPath, formatterPathSuffix);
Path wsFormatterPath = Paths.get(PROJECTS, formatterPathSuffix);
if (Files.exists(projectFormatterPath)) {
updateFormatterOptions(params, getFormatSettingsFromFile(projectFormatterPath.toFile()));
} else if (Files.exists(wsFormatterPath)) {
updateFormatterOptions(params, getFormatSettingsFromFile(wsFormatterPath.toFile()));
}
}
private void updateFormatterOptions(
DocumentFormattingParams params, Map<String, String> options) {
for (String key : options.keySet()) {
params.getOptions().putString(key, options.get(key));
}
}
private static Map<String, String> getFormatSettingsFromFile(File file) {
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLParser parserXML = new XMLParser();
try (FileInputStream fis = new FileInputStream(file)) {
SAXParser parser = factory.newSAXParser();
parser.parse(fis, parserXML);
} catch (ParserConfigurationException | SAXException | IOException e) {
LOG.error("It is not possible to parse file " + file.getName(), e);
}
return parserXML.getSettings();
}
}

View File

@ -1,13 +1,14 @@
/**
* ***************************************************************************** Copyright (c)
* 2012-2015 Red Hat, Inc. All rights reserved. This program and the accompanying materials are made
* available under the terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
/*
* Copyright (c) 2012-2018 Red Hat, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* <p>Contributors: Red Hat, Inc. - initial API and implementation
* *****************************************************************************
* Contributors:
* Red Hat, Inc. - initial API and implementation
*/
package org.eclipse.jdt.internal.corext.format;
package org.eclipse.che.plugin.java.languageserver;
import java.util.HashMap;
import java.util.Map;

View File

@ -30,8 +30,8 @@ import org.eclipse.lsp4j.Location;
*/
public class LanguageServiceUtils {
private static final String PROJECTS = "/projects";
private static final String FILE_PROJECTS = "file:///projects";
public static final String PROJECTS = "/projects";
public static final String FILE_PROJECTS = "file:///projects";
public static String prefixURI(String uri) {
return uri.startsWith("/") ? FILE_PROJECTS + uri : uri;