mirror of
https://github.com/sigmasternchen/xtext-core
synced 2025-03-15 08:18:55 +00:00
[eclipse/xtext#1679]ported more code to java
Signed-off-by: Christian Dietrich <christian.dietrich@itemis.de>
This commit is contained in:
parent
7e8ce132fb
commit
7b0d63dbd3
17 changed files with 608 additions and 1159 deletions
|
@ -0,0 +1,212 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, 2020 itemis AG (http://www.itemis.eu) and others.
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.eclipse.xtext.ide.editor.contentassist;
|
||||||
|
|
||||||
|
import org.eclipse.xtend2.lib.StringConcatenation;
|
||||||
|
import org.eclipse.xtend2.lib.StringConcatenationClient;
|
||||||
|
import org.eclipse.xtext.util.TextRegion;
|
||||||
|
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
||||||
|
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for adding template proposals from an {@link IdeContentProposalProvider} implementation. Use
|
||||||
|
* {@link #variable(String)} and {@link #cursor()} to generate edit positions and an exit position into the proposal,
|
||||||
|
* e.g.
|
||||||
|
* <pre>
|
||||||
|
* StringConcatenationClient template = new StringConcatenationClient() {
|
||||||
|
* {@literal @}Override
|
||||||
|
* protected void appendTo(StringConcatenationClient.TargetStringConcatenation target) {
|
||||||
|
* target.append("state ");
|
||||||
|
* target.append(variable("name"));
|
||||||
|
* target.newLineIfNotEmpty();
|
||||||
|
* target.append("\t");
|
||||||
|
* target.append(cursor(), "\t");
|
||||||
|
* target.newLineIfNotEmpty();
|
||||||
|
* target.append("end");
|
||||||
|
* target.newLine();
|
||||||
|
* }
|
||||||
|
* };
|
||||||
|
* acceptProposal("state", "Create a new state", template, context, acceptor);
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @since 2.10
|
||||||
|
*/
|
||||||
|
public abstract class AbstractIdeTemplateProposalProvider {
|
||||||
|
/**
|
||||||
|
* Placeholder for a variable (edit position) in a template.
|
||||||
|
*/
|
||||||
|
protected static class Variable {
|
||||||
|
private final String name;
|
||||||
|
|
||||||
|
public Variable(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
final int prime = 31;
|
||||||
|
int result = 1;
|
||||||
|
result = prime * result + ((name == null) ? 0 : name.hashCode());
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object obj) {
|
||||||
|
if (this == obj)
|
||||||
|
return true;
|
||||||
|
if (obj == null)
|
||||||
|
return false;
|
||||||
|
if (getClass() != obj.getClass())
|
||||||
|
return false;
|
||||||
|
Variable other = (Variable) obj;
|
||||||
|
if (name == null) {
|
||||||
|
if (other.name != null)
|
||||||
|
return false;
|
||||||
|
} else if (!name.equals(other.name))
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
ToStringBuilder b = new ToStringBuilder(this);
|
||||||
|
b.add("name", name);
|
||||||
|
return b.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Placeholder for the cursor (exit position) in a template.
|
||||||
|
*/
|
||||||
|
protected static class Cursor {
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TemplateStringConcatenation extends StringConcatenation {
|
||||||
|
private final ContentAssistContext context;
|
||||||
|
|
||||||
|
private final ContentAssistEntry entry;
|
||||||
|
|
||||||
|
public TemplateStringConcatenation(ContentAssistContext context, ContentAssistEntry entry,
|
||||||
|
String lineDelimiter) {
|
||||||
|
super(lineDelimiter);
|
||||||
|
this.context = context;
|
||||||
|
this.entry = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getStringRepresentation(Object object) {
|
||||||
|
if (object instanceof Variable) {
|
||||||
|
String varName = ((Variable) object).name;
|
||||||
|
int offset = context.getReplaceRegion().getOffset() + getCurrentOffset();
|
||||||
|
entry.getEditPositions().add(new TextRegion(offset, varName.length()));
|
||||||
|
return varName;
|
||||||
|
} else {
|
||||||
|
if (object instanceof Cursor) {
|
||||||
|
entry.setEscapePosition(
|
||||||
|
Integer.valueOf(context.getReplaceRegion().getOffset() + getCurrentOffset()));
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
return object.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getCurrentOffset() {
|
||||||
|
int result = 0;
|
||||||
|
for (String segment : getContent()) {
|
||||||
|
result = result + segment.length();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void newLineIfNotEmpty() {
|
||||||
|
newLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private IdeContentProposalCreator proposalCreator;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private IdeContentProposalPriorities proposalPriorities;
|
||||||
|
|
||||||
|
protected Variable variable(String name) {
|
||||||
|
return new Variable(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Cursor cursor() {
|
||||||
|
return new Cursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void acceptProposal(String name, String description, StringConcatenationClient template,
|
||||||
|
ContentAssistContext context, IIdeContentProposalAcceptor acceptor) {
|
||||||
|
acceptProposal(name, description, template, context, acceptor, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void acceptProposal(String name, String description, StringConcatenationClient template,
|
||||||
|
ContentAssistContext context, IIdeContentProposalAcceptor acceptor, boolean adaptIndentation) {
|
||||||
|
ContentAssistEntry entry = createProposal(template, context, adaptIndentation);
|
||||||
|
if (canAcceptProposal(entry, context)) {
|
||||||
|
entry.setLabel(name);
|
||||||
|
entry.setDescription(description);
|
||||||
|
acceptor.accept(entry, proposalPriorities.getDefaultPriority(entry));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean canAcceptProposal(ContentAssistEntry entry, ContentAssistContext context) {
|
||||||
|
return proposalCreator.isValidProposal(entry.getProposal(), entry.getPrefix(), context);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected ContentAssistEntry createProposal(StringConcatenationClient template, ContentAssistContext context,
|
||||||
|
boolean adaptIndentation) {
|
||||||
|
ContentAssistEntry entry = new ContentAssistEntry();
|
||||||
|
entry.setPrefix(context.getPrefix());
|
||||||
|
TemplateStringConcatenation stringConcat = new TemplateStringConcatenation(context, entry, getLineDelimiter());
|
||||||
|
String indentation = null;
|
||||||
|
if (adaptIndentation) {
|
||||||
|
indentation = getIndentation(context);
|
||||||
|
}
|
||||||
|
if (indentation == null) {
|
||||||
|
stringConcat.append(template);
|
||||||
|
} else {
|
||||||
|
stringConcat.append(template, indentation);
|
||||||
|
}
|
||||||
|
entry.setProposal(stringConcat.toString());
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getLineDelimiter() {
|
||||||
|
return StringConcatenation.DEFAULT_LINE_DELIMITER;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getIndentation(ContentAssistContext context) {
|
||||||
|
String text = null;
|
||||||
|
if (context.getRootNode() != null) {
|
||||||
|
text = context.getRootNode().getText();
|
||||||
|
}
|
||||||
|
if (text != null && text.length() >= context.getOffset()) {
|
||||||
|
int lineStart = context.getReplaceRegion().getOffset();
|
||||||
|
int indentEnd = lineStart;
|
||||||
|
while (lineStart > 0 && text.charAt(lineStart - 1) != '\n') {
|
||||||
|
lineStart--;
|
||||||
|
if (!Character.isWhitespace(text.charAt(lineStart))) {
|
||||||
|
indentEnd = lineStart;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text.substring(lineStart, indentEnd);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,147 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (c) 2016 itemis AG (http://www.itemis.eu) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*******************************************************************************/
|
|
||||||
package org.eclipse.xtext.ide.editor.contentassist
|
|
||||||
|
|
||||||
import com.google.inject.Inject
|
|
||||||
import org.eclipse.xtend.lib.annotations.Data
|
|
||||||
import org.eclipse.xtend2.lib.StringConcatenation
|
|
||||||
import org.eclipse.xtend2.lib.StringConcatenationClient
|
|
||||||
import org.eclipse.xtext.util.TextRegion
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for adding template proposals from an {@link IdeContentProposalProvider} implementation.
|
|
||||||
* Use {@link #variable(String)} and {@link #cursor()} to generate edit positions and an exit position
|
|
||||||
* into the proposal, e.g.
|
|
||||||
* <pre>
|
|
||||||
* val StringConcatenationClient template = '''
|
|
||||||
* state «variable('name')»
|
|
||||||
* «cursor»
|
|
||||||
* end
|
|
||||||
* '''
|
|
||||||
* acceptProposal('state', 'Create a new state', template, context, acceptor)
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @since 2.10
|
|
||||||
*/
|
|
||||||
abstract class AbstractIdeTemplateProposalProvider {
|
|
||||||
|
|
||||||
@Inject IdeContentProposalCreator proposalCreator
|
|
||||||
|
|
||||||
@Inject IdeContentProposalPriorities proposalPriorities
|
|
||||||
|
|
||||||
/** Placeholder for a variable (edit position) in a template. */
|
|
||||||
@Data
|
|
||||||
protected static class Variable {
|
|
||||||
String name
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def Variable variable(String name) {
|
|
||||||
new Variable(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Placeholder for the cursor (exit position) in a template. */
|
|
||||||
protected static class Cursor {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def Cursor cursor() {
|
|
||||||
new Cursor
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def void acceptProposal(String name, String description, StringConcatenationClient template,
|
|
||||||
ContentAssistContext context, IIdeContentProposalAcceptor acceptor) {
|
|
||||||
acceptProposal(name, description, template, context, acceptor, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def void acceptProposal(String name, String description, StringConcatenationClient template,
|
|
||||||
ContentAssistContext context, IIdeContentProposalAcceptor acceptor, boolean adaptIndentation) {
|
|
||||||
val entry = createProposal(template, context, adaptIndentation)
|
|
||||||
if (canAcceptProposal(entry, context)) {
|
|
||||||
entry.label = name
|
|
||||||
entry.description = description
|
|
||||||
acceptor.accept(entry, proposalPriorities.getDefaultPriority(entry))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def boolean canAcceptProposal(ContentAssistEntry entry, ContentAssistContext context) {
|
|
||||||
proposalCreator.isValidProposal(entry.proposal, entry.prefix, context)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def ContentAssistEntry createProposal(StringConcatenationClient template,
|
|
||||||
ContentAssistContext context, boolean adaptIndentation) {
|
|
||||||
val entry = new ContentAssistEntry
|
|
||||||
entry.prefix = context.prefix
|
|
||||||
val stringConcat = new TemplateStringConcatenation(context, entry, lineDelimiter)
|
|
||||||
val indentation = if (adaptIndentation) context.indentation else null
|
|
||||||
if (indentation === null)
|
|
||||||
stringConcat.append(template)
|
|
||||||
else
|
|
||||||
stringConcat.append(template, indentation)
|
|
||||||
entry.proposal = stringConcat.toString
|
|
||||||
return entry
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def String getLineDelimiter() {
|
|
||||||
StringConcatenation.DEFAULT_LINE_DELIMITER
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def String getIndentation(ContentAssistContext context) {
|
|
||||||
val text = context.rootNode?.text
|
|
||||||
if (text !== null && text.length >= context.offset) {
|
|
||||||
var lineStart = context.replaceRegion.offset
|
|
||||||
var indentEnd = lineStart
|
|
||||||
while (lineStart > 0 && text.charAt(lineStart - 1) != '\n'.charAt(0)) {
|
|
||||||
lineStart--
|
|
||||||
if (!Character.isWhitespace(text.charAt(lineStart)))
|
|
||||||
indentEnd = lineStart
|
|
||||||
}
|
|
||||||
return text.substring(lineStart, indentEnd)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TemplateStringConcatenation extends StringConcatenation {
|
|
||||||
|
|
||||||
val ContentAssistContext context
|
|
||||||
val ContentAssistEntry entry
|
|
||||||
|
|
||||||
new(ContentAssistContext context, ContentAssistEntry entry, String lineDelimiter) {
|
|
||||||
super(lineDelimiter)
|
|
||||||
this.context = context
|
|
||||||
this.entry = entry
|
|
||||||
}
|
|
||||||
|
|
||||||
override protected getStringRepresentation(Object object) {
|
|
||||||
if (object instanceof Variable) {
|
|
||||||
val varName = object.name
|
|
||||||
val offset = context.replaceRegion.offset + currentOffset
|
|
||||||
entry.editPositions.add(new TextRegion(offset, varName.length))
|
|
||||||
return varName
|
|
||||||
} else if (object instanceof Cursor) {
|
|
||||||
val offset = context.replaceRegion.offset + currentOffset
|
|
||||||
entry.setEscapePosition(offset)
|
|
||||||
return null
|
|
||||||
} else {
|
|
||||||
return object.toString
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def int getCurrentOffset() {
|
|
||||||
var result = 0
|
|
||||||
for (segment : content) {
|
|
||||||
result += segment.length
|
|
||||||
}
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
override newLineIfNotEmpty() {
|
|
||||||
newLine()
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2016, 2020 TypeFox GmbH (http://www.typefox.io) and others.
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.eclipse.xtext.ide.server;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.concurrent.Future;
|
||||||
|
|
||||||
|
import org.eclipse.lsp4j.jsonrpc.Launcher;
|
||||||
|
import org.eclipse.lsp4j.services.LanguageClient;
|
||||||
|
import org.eclipse.xtext.xbase.lib.Exceptions;
|
||||||
|
import org.eclipse.xtext.xbase.lib.InputOutput;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.common.io.ByteStreams;
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Sven Efftinge - Initial contribution and API
|
||||||
|
* @since 2.11
|
||||||
|
*/
|
||||||
|
public class ServerLauncher {
|
||||||
|
public static final String LOG = "-log";
|
||||||
|
|
||||||
|
public static final String TRACE = "-trace";
|
||||||
|
|
||||||
|
public static final String NO_VALIDATE = "-noValidate";
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
launch(ServerLauncher.class.getName(), args, new ServerModule());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void launch(String prefix, String[] args, com.google.inject.Module... modules) {
|
||||||
|
LaunchArgs launchArgs = createLaunchArgs(prefix, args);
|
||||||
|
ServerLauncher launcher = Guice.createInjector(modules).<ServerLauncher>getInstance(ServerLauncher.class);
|
||||||
|
launcher.start(launchArgs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
private LanguageServerImpl languageServer;
|
||||||
|
|
||||||
|
public void start(LaunchArgs args) {
|
||||||
|
try {
|
||||||
|
InputOutput.println("Xtext Language Server is starting.");
|
||||||
|
Launcher<LanguageClient> launcher = Launcher.createLauncher(languageServer,
|
||||||
|
LanguageClient.class, args.getIn(), args.getOut(), args.isValidate(), args.getTrace());
|
||||||
|
languageServer.connect(launcher.getRemoteProxy());
|
||||||
|
Future<Void> future = launcher.startListening();
|
||||||
|
InputOutput.println("Xtext Language Server has been started.");
|
||||||
|
while (!future.isDone()) {
|
||||||
|
Thread.sleep(10_000L);
|
||||||
|
}
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
throw Exceptions.sneakyThrow(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static LaunchArgs createLaunchArgs(String prefix, String[] args) {
|
||||||
|
LaunchArgs launchArgs = new LaunchArgs();
|
||||||
|
launchArgs.setIn(System.in);
|
||||||
|
launchArgs.setOut(System.out);
|
||||||
|
redirectStandardStreams(prefix, args);
|
||||||
|
launchArgs.setTrace(getTrace(args));
|
||||||
|
launchArgs.setValidate(shouldValidate(args));
|
||||||
|
return launchArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PrintWriter getTrace(String[] args) {
|
||||||
|
if (shouldTrace(args)) {
|
||||||
|
return createTrace();
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PrintWriter createTrace() {
|
||||||
|
return new PrintWriter(System.out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void redirectStandardStreams(String prefix, String[] args) {
|
||||||
|
if (shouldLogStandardStreams(args)) {
|
||||||
|
logStandardStreams(prefix);
|
||||||
|
} else {
|
||||||
|
silentStandardStreams();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldValidate(String[] args) {
|
||||||
|
return !testArg(args, ServerLauncher.NO_VALIDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldTrace(String[] args) {
|
||||||
|
return testArg(args, ServerLauncher.TRACE);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean shouldLogStandardStreams(String[] args) {
|
||||||
|
return testArg(args, ServerLauncher.LOG, "debug");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean testArg(String[] args, String... values) {
|
||||||
|
for (String arg : args) {
|
||||||
|
if (testArg(arg, values)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static boolean testArg(String arg, String... values) {
|
||||||
|
for(String value : values) {
|
||||||
|
if (Objects.equal(value, arg)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void logStandardStreams(String prefix) {
|
||||||
|
try {
|
||||||
|
FileOutputStream stdFileOut = new FileOutputStream(prefix + "-debug.log");
|
||||||
|
redirectStandardStreams(stdFileOut);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw Exceptions.sneakyThrow(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void silentStandardStreams() {
|
||||||
|
redirectStandardStreams(silentOut());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void redirectStandardStreams(OutputStream out) {
|
||||||
|
redirectStandardStreams(silentIn(), out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void redirectStandardStreams(InputStream in, OutputStream out) {
|
||||||
|
System.setIn(in);
|
||||||
|
System.setOut(new PrintStream(out));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static OutputStream silentOut() {
|
||||||
|
return ByteStreams.nullOutputStream();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InputStream silentIn() {
|
||||||
|
return new ByteArrayInputStream(new byte[0]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,131 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*******************************************************************************/
|
|
||||||
package org.eclipse.xtext.ide.server
|
|
||||||
|
|
||||||
import com.google.common.io.ByteStreams
|
|
||||||
import com.google.inject.Guice
|
|
||||||
import com.google.inject.Inject
|
|
||||||
import com.google.inject.Module
|
|
||||||
import java.io.ByteArrayInputStream
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.io.InputStream
|
|
||||||
import java.io.OutputStream
|
|
||||||
import java.io.PrintStream
|
|
||||||
import java.io.PrintWriter
|
|
||||||
import org.eclipse.lsp4j.jsonrpc.Launcher
|
|
||||||
import org.eclipse.lsp4j.services.LanguageClient
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sven Efftinge - Initial contribution and API
|
|
||||||
* @since 2.11
|
|
||||||
*/
|
|
||||||
class ServerLauncher {
|
|
||||||
|
|
||||||
public static val LOG = '-log'
|
|
||||||
public static val TRACE = '-trace'
|
|
||||||
public static val NO_VALIDATE = '-noValidate'
|
|
||||||
|
|
||||||
def static void main(String[] args) {
|
|
||||||
launch(ServerLauncher.name, args, new ServerModule)
|
|
||||||
}
|
|
||||||
|
|
||||||
def static void launch(String prefix, String[] args, Module... modules) {
|
|
||||||
val launchArgs = createLaunchArgs(prefix, args)
|
|
||||||
|
|
||||||
val launcher = Guice.createInjector(modules).getInstance(ServerLauncher)
|
|
||||||
launcher.start(launchArgs)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject LanguageServerImpl languageServer
|
|
||||||
|
|
||||||
def void start(LaunchArgs it) {
|
|
||||||
println("Xtext Language Server is starting.")
|
|
||||||
val launcher = Launcher.createLauncher(languageServer, LanguageClient, in, out, validate, trace)
|
|
||||||
languageServer.connect(launcher.remoteProxy)
|
|
||||||
val future = launcher.startListening
|
|
||||||
println("Xtext Language Server has been started.")
|
|
||||||
while (!future.done) {
|
|
||||||
Thread.sleep(10_000l)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def static LaunchArgs createLaunchArgs(String prefix, String[] args) {
|
|
||||||
val launchArgs = new LaunchArgs
|
|
||||||
launchArgs.in = System.in
|
|
||||||
launchArgs.out = System.out
|
|
||||||
redirectStandardStreams(prefix, args)
|
|
||||||
launchArgs.trace = args.trace
|
|
||||||
launchArgs.validate = args.shouldValidate
|
|
||||||
return launchArgs
|
|
||||||
}
|
|
||||||
|
|
||||||
def static PrintWriter getTrace(String[] args) {
|
|
||||||
if (shouldTrace(args))
|
|
||||||
return createTrace
|
|
||||||
}
|
|
||||||
|
|
||||||
def static PrintWriter createTrace() {
|
|
||||||
return new PrintWriter(System.out)
|
|
||||||
}
|
|
||||||
|
|
||||||
def static redirectStandardStreams(String prefix, String[] args) {
|
|
||||||
if (shouldLogStandardStreams(args)) {
|
|
||||||
logStandardStreams(prefix)
|
|
||||||
} else {
|
|
||||||
silentStandardStreams
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def static boolean shouldValidate(String[] args) {
|
|
||||||
return !args.testArg(NO_VALIDATE)
|
|
||||||
}
|
|
||||||
|
|
||||||
def static boolean shouldTrace(String[] args) {
|
|
||||||
return args.testArg(TRACE)
|
|
||||||
}
|
|
||||||
|
|
||||||
def static boolean shouldLogStandardStreams(String[] args) {
|
|
||||||
return args.testArg(ServerLauncher.LOG, 'debug')
|
|
||||||
}
|
|
||||||
|
|
||||||
def static boolean testArg(String[] args, String ... values) {
|
|
||||||
return args.exists[arg|arg.testArg(values)]
|
|
||||||
}
|
|
||||||
|
|
||||||
def static boolean testArg(String arg, String ... values) {
|
|
||||||
return values.exists[value|value == arg]
|
|
||||||
}
|
|
||||||
|
|
||||||
def static void logStandardStreams(String prefix) {
|
|
||||||
val stdFileOut = new FileOutputStream(prefix + "-debug.log")
|
|
||||||
redirectStandardStreams(stdFileOut)
|
|
||||||
}
|
|
||||||
|
|
||||||
def static void silentStandardStreams() {
|
|
||||||
redirectStandardStreams(ServerLauncher.silentOut)
|
|
||||||
}
|
|
||||||
|
|
||||||
def static void redirectStandardStreams(OutputStream out) {
|
|
||||||
redirectStandardStreams(ServerLauncher.silentIn, out)
|
|
||||||
}
|
|
||||||
|
|
||||||
def static void redirectStandardStreams(InputStream in, OutputStream out) {
|
|
||||||
System.setIn(in)
|
|
||||||
System.setOut(new PrintStream(out))
|
|
||||||
}
|
|
||||||
|
|
||||||
def static OutputStream silentOut() {
|
|
||||||
ByteStreams.nullOutputStream
|
|
||||||
}
|
|
||||||
|
|
||||||
def static InputStream silentIn() {
|
|
||||||
new ByteArrayInputStream(newByteArrayOfSize(0))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2019, 2020 TypeFox GmbH (http://www.typefox.io) and others.
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.eclipse.xtext.ide.server;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
|
import java.nio.channels.AsynchronousServerSocketChannel;
|
||||||
|
import java.nio.channels.AsynchronousSocketChannel;
|
||||||
|
import java.nio.channels.Channels;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.eclipse.lsp4j.jsonrpc.Launcher;
|
||||||
|
import org.eclipse.lsp4j.services.LanguageClient;
|
||||||
|
import org.eclipse.xtext.xbase.lib.ArrayExtensions;
|
||||||
|
|
||||||
|
import com.google.common.base.Objects;
|
||||||
|
import com.google.inject.Guice;
|
||||||
|
import com.google.inject.Injector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows to launch a language server via a server socket.
|
||||||
|
*
|
||||||
|
* Useful for debugging live language servers.
|
||||||
|
*
|
||||||
|
* @author Jan Köhnlein - Initial contribution and API
|
||||||
|
* @since 2.18
|
||||||
|
*/
|
||||||
|
public class SocketServerLauncher {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(SocketServerLauncher.class);
|
||||||
|
public static final String HOST = "-host";
|
||||||
|
|
||||||
|
public static final String PORT = "-port";
|
||||||
|
|
||||||
|
public static final String TRACE = "-trace";
|
||||||
|
|
||||||
|
public static final String NO_VALIDATE = "-noValidate";
|
||||||
|
|
||||||
|
public static final int DEFAULT_PORT = 5008;
|
||||||
|
|
||||||
|
public static final String DEFAULT_HOST = "0.0.0.0";
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
new SocketServerLauncher().launch(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void launch(String[] args) {
|
||||||
|
Injector injector = Guice.createInjector(getServerModule());
|
||||||
|
try (AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open()
|
||||||
|
.bind(getSocketAddress(args))) {
|
||||||
|
LOG.info("Started server socket at " + getSocketAddress(args));
|
||||||
|
while (true) {
|
||||||
|
AsynchronousSocketChannel socketChannel = serverSocket.accept().get();
|
||||||
|
InputStream in = Channels.newInputStream(socketChannel);
|
||||||
|
OutputStream out = Channels.newOutputStream(socketChannel);
|
||||||
|
PrintWriter trace = getTrace(args);
|
||||||
|
boolean validate = shouldValidate(args);
|
||||||
|
LanguageServerImpl languageServer = injector.getInstance(LanguageServerImpl.class);
|
||||||
|
LOG
|
||||||
|
.info("Starting Xtext Language Server for client " + socketChannel.getRemoteAddress());
|
||||||
|
Launcher<LanguageClient> launcher = Launcher.createLauncher(languageServer, LanguageClient.class, in,
|
||||||
|
out, validate, trace);
|
||||||
|
languageServer.connect(launcher.getRemoteProxy());
|
||||||
|
launcher.startListening();
|
||||||
|
LOG.info("Xtext Language Server has been started.");
|
||||||
|
}
|
||||||
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected com.google.inject.Module getServerModule() {
|
||||||
|
return new ServerModule();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected PrintWriter getTrace(String... args) {
|
||||||
|
if (ArrayExtensions.contains(args, TRACE)) {
|
||||||
|
return new PrintWriter(System.out);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected boolean shouldValidate(String... args) {
|
||||||
|
return !ArrayExtensions.contains(args, NO_VALIDATE);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected InetSocketAddress getSocketAddress(String... args) {
|
||||||
|
return new InetSocketAddress(getHost(args), getPort(args));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getHost(String... args) {
|
||||||
|
String host = getValue(args, HOST);
|
||||||
|
if (host != null) {
|
||||||
|
return host;
|
||||||
|
} else {
|
||||||
|
return DEFAULT_HOST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int getPort(String... args) {
|
||||||
|
Integer port = Integer.getInteger(getValue(args, PORT));
|
||||||
|
if (port != null) {
|
||||||
|
return port;
|
||||||
|
} else {
|
||||||
|
return DEFAULT_PORT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getValue(String[] args, String argName) {
|
||||||
|
for (int i = 0; (i < (args.length - 1)); i++) {
|
||||||
|
if (Objects.equal(args[i], argName)) {
|
||||||
|
return args[i + 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,102 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (c) 2019 TypeFox GmbH (http://www.typefox.io) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
package org.eclipse.xtext.ide.server
|
|
||||||
|
|
||||||
import com.google.inject.Guice
|
|
||||||
import java.io.PrintWriter
|
|
||||||
import java.net.InetSocketAddress
|
|
||||||
import java.nio.channels.AsynchronousServerSocketChannel
|
|
||||||
import java.nio.channels.Channels
|
|
||||||
import org.eclipse.lsp4j.jsonrpc.Launcher
|
|
||||||
import org.eclipse.lsp4j.services.LanguageClient
|
|
||||||
import org.eclipse.xtext.ide.server.LanguageServerImpl
|
|
||||||
import org.eclipse.xtext.ide.server.ServerModule
|
|
||||||
import org.eclipse.xtext.util.internal.Log
|
|
||||||
import com.google.inject.Module
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows to launch a language server vie a server socket.
|
|
||||||
*
|
|
||||||
* Useful for debugging live language servers.
|
|
||||||
*
|
|
||||||
* @author Jan Köhnlein - Initial contribution and API
|
|
||||||
* @since 2.18
|
|
||||||
*/
|
|
||||||
@Log
|
|
||||||
class SocketServerLauncher {
|
|
||||||
|
|
||||||
public static val HOST = '-host'
|
|
||||||
public static val PORT = '-port'
|
|
||||||
public static val TRACE = '-trace'
|
|
||||||
public static val NO_VALIDATE = '-noValidate'
|
|
||||||
|
|
||||||
public static val DEFAULT_PORT = 5008
|
|
||||||
public static val DEFAULT_HOST = '0.0.0.0'
|
|
||||||
|
|
||||||
def static void main(String[] args) {
|
|
||||||
new SocketServerLauncher().launch(args)
|
|
||||||
}
|
|
||||||
|
|
||||||
def void launch(String[] args) {
|
|
||||||
try {
|
|
||||||
val injector = Guice.createInjector(serverModule)
|
|
||||||
val serverSocket = AsynchronousServerSocketChannel.open.bind(args.socketAddress)
|
|
||||||
LOG.info("Started server socket at " + args.socketAddress)
|
|
||||||
while (true) {
|
|
||||||
val socketChannel = serverSocket.accept.get
|
|
||||||
val in = Channels.newInputStream(socketChannel)
|
|
||||||
val out = Channels.newOutputStream(socketChannel)
|
|
||||||
val trace = args.trace
|
|
||||||
val validate = args.shouldValidate
|
|
||||||
val languageServer = injector.getInstance(LanguageServerImpl)
|
|
||||||
LOG.info("Starting Xtext Language Server for client " + socketChannel.remoteAddress)
|
|
||||||
val launcher = Launcher.createLauncher(languageServer, LanguageClient, in, out, validate, trace)
|
|
||||||
languageServer.connect(launcher.remoteProxy)
|
|
||||||
launcher.startListening
|
|
||||||
LOG.info("Xtext Language Server has been started.")
|
|
||||||
}
|
|
||||||
} catch (Throwable throwable) {
|
|
||||||
throwable.printStackTrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def Module getServerModule() {
|
|
||||||
new ServerModule
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def PrintWriter getTrace(String... args) {
|
|
||||||
if (args.contains(TRACE))
|
|
||||||
new PrintWriter(System.out)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def boolean shouldValidate(String... args) {
|
|
||||||
!args.contains(NO_VALIDATE)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def InetSocketAddress getSocketAddress(String... args) {
|
|
||||||
new InetSocketAddress(args.host, args.port)
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def String getHost(String... args) {
|
|
||||||
args.getValue(HOST) ?: DEFAULT_HOST
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def int getPort(String... args) {
|
|
||||||
Integer.getInteger(args.getValue(PORT)) ?: DEFAULT_PORT
|
|
||||||
}
|
|
||||||
|
|
||||||
protected def String getValue(String[] args, String argName) {
|
|
||||||
for (var i = 0; i < args.length - 1; i++) {
|
|
||||||
if (args.get(i) == argName)
|
|
||||||
return args.get(i + 1)
|
|
||||||
}
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,233 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2016 itemis AG (http://www.itemis.eu) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.xtext.ide.editor.contentassist;
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import java.util.List;
|
|
||||||
import org.eclipse.xtend.lib.annotations.Data;
|
|
||||||
import org.eclipse.xtend2.lib.StringConcatenation;
|
|
||||||
import org.eclipse.xtend2.lib.StringConcatenationClient;
|
|
||||||
import org.eclipse.xtext.ide.editor.contentassist.ContentAssistContext;
|
|
||||||
import org.eclipse.xtext.ide.editor.contentassist.ContentAssistEntry;
|
|
||||||
import org.eclipse.xtext.ide.editor.contentassist.IIdeContentProposalAcceptor;
|
|
||||||
import org.eclipse.xtext.ide.editor.contentassist.IdeContentProposalCreator;
|
|
||||||
import org.eclipse.xtext.ide.editor.contentassist.IdeContentProposalPriorities;
|
|
||||||
import org.eclipse.xtext.nodemodel.ICompositeNode;
|
|
||||||
import org.eclipse.xtext.util.TextRegion;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Pure;
|
|
||||||
import org.eclipse.xtext.xbase.lib.util.ToStringBuilder;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base class for adding template proposals from an {@link IdeContentProposalProvider} implementation.
|
|
||||||
* Use {@link #variable(String)} and {@link #cursor()} to generate edit positions and an exit position
|
|
||||||
* into the proposal, e.g.
|
|
||||||
* <pre>
|
|
||||||
* val StringConcatenationClient template = '''
|
|
||||||
* state «variable('name')»
|
|
||||||
* «cursor»
|
|
||||||
* end
|
|
||||||
* '''
|
|
||||||
* acceptProposal('state', 'Create a new state', template, context, acceptor)
|
|
||||||
* </pre>
|
|
||||||
*
|
|
||||||
* @since 2.10
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public abstract class AbstractIdeTemplateProposalProvider {
|
|
||||||
/**
|
|
||||||
* Placeholder for a variable (edit position) in a template.
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
protected static class Variable {
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
public Variable(final String name) {
|
|
||||||
super();
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Pure
|
|
||||||
public int hashCode() {
|
|
||||||
return 31 * 1 + ((this.name== null) ? 0 : this.name.hashCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Pure
|
|
||||||
public boolean equals(final Object obj) {
|
|
||||||
if (this == obj)
|
|
||||||
return true;
|
|
||||||
if (obj == null)
|
|
||||||
return false;
|
|
||||||
if (getClass() != obj.getClass())
|
|
||||||
return false;
|
|
||||||
AbstractIdeTemplateProposalProvider.Variable other = (AbstractIdeTemplateProposalProvider.Variable) obj;
|
|
||||||
if (this.name == null) {
|
|
||||||
if (other.name != null)
|
|
||||||
return false;
|
|
||||||
} else if (!this.name.equals(other.name))
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Pure
|
|
||||||
public String toString() {
|
|
||||||
ToStringBuilder b = new ToStringBuilder(this);
|
|
||||||
b.add("name", this.name);
|
|
||||||
return b.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Pure
|
|
||||||
public String getName() {
|
|
||||||
return this.name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Placeholder for the cursor (exit position) in a template.
|
|
||||||
*/
|
|
||||||
protected static class Cursor {
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TemplateStringConcatenation extends StringConcatenation {
|
|
||||||
private final ContentAssistContext context;
|
|
||||||
|
|
||||||
private final ContentAssistEntry entry;
|
|
||||||
|
|
||||||
public TemplateStringConcatenation(final ContentAssistContext context, final ContentAssistEntry entry, final String lineDelimiter) {
|
|
||||||
super(lineDelimiter);
|
|
||||||
this.context = context;
|
|
||||||
this.entry = entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getStringRepresentation(final Object object) {
|
|
||||||
if ((object instanceof AbstractIdeTemplateProposalProvider.Variable)) {
|
|
||||||
final String varName = ((AbstractIdeTemplateProposalProvider.Variable)object).name;
|
|
||||||
int _offset = this.context.getReplaceRegion().getOffset();
|
|
||||||
int _currentOffset = this.getCurrentOffset();
|
|
||||||
final int offset = (_offset + _currentOffset);
|
|
||||||
List<TextRegion> _editPositions = this.entry.getEditPositions();
|
|
||||||
int _length = varName.length();
|
|
||||||
TextRegion _textRegion = new TextRegion(offset, _length);
|
|
||||||
_editPositions.add(_textRegion);
|
|
||||||
return varName;
|
|
||||||
} else {
|
|
||||||
if ((object instanceof AbstractIdeTemplateProposalProvider.Cursor)) {
|
|
||||||
int _offset_1 = this.context.getReplaceRegion().getOffset();
|
|
||||||
int _currentOffset_1 = this.getCurrentOffset();
|
|
||||||
final int offset_1 = (_offset_1 + _currentOffset_1);
|
|
||||||
this.entry.setEscapePosition(Integer.valueOf(offset_1));
|
|
||||||
return null;
|
|
||||||
} else {
|
|
||||||
return object.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getCurrentOffset() {
|
|
||||||
int result = 0;
|
|
||||||
List<String> _content = this.getContent();
|
|
||||||
for (final String segment : _content) {
|
|
||||||
int _result = result;
|
|
||||||
int _length = segment.length();
|
|
||||||
result = (_result + _length);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void newLineIfNotEmpty() {
|
|
||||||
this.newLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private IdeContentProposalCreator proposalCreator;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private IdeContentProposalPriorities proposalPriorities;
|
|
||||||
|
|
||||||
protected AbstractIdeTemplateProposalProvider.Variable variable(final String name) {
|
|
||||||
return new AbstractIdeTemplateProposalProvider.Variable(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected AbstractIdeTemplateProposalProvider.Cursor cursor() {
|
|
||||||
return new AbstractIdeTemplateProposalProvider.Cursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void acceptProposal(final String name, final String description, final StringConcatenationClient template, final ContentAssistContext context, final IIdeContentProposalAcceptor acceptor) {
|
|
||||||
this.acceptProposal(name, description, template, context, acceptor, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void acceptProposal(final String name, final String description, final StringConcatenationClient template, final ContentAssistContext context, final IIdeContentProposalAcceptor acceptor, final boolean adaptIndentation) {
|
|
||||||
final ContentAssistEntry entry = this.createProposal(template, context, adaptIndentation);
|
|
||||||
boolean _canAcceptProposal = this.canAcceptProposal(entry, context);
|
|
||||||
if (_canAcceptProposal) {
|
|
||||||
entry.setLabel(name);
|
|
||||||
entry.setDescription(description);
|
|
||||||
acceptor.accept(entry, this.proposalPriorities.getDefaultPriority(entry));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean canAcceptProposal(final ContentAssistEntry entry, final ContentAssistContext context) {
|
|
||||||
return this.proposalCreator.isValidProposal(entry.getProposal(), entry.getPrefix(), context);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected ContentAssistEntry createProposal(final StringConcatenationClient template, final ContentAssistContext context, final boolean adaptIndentation) {
|
|
||||||
final ContentAssistEntry entry = new ContentAssistEntry();
|
|
||||||
entry.setPrefix(context.getPrefix());
|
|
||||||
String _lineDelimiter = this.getLineDelimiter();
|
|
||||||
final AbstractIdeTemplateProposalProvider.TemplateStringConcatenation stringConcat = new AbstractIdeTemplateProposalProvider.TemplateStringConcatenation(context, entry, _lineDelimiter);
|
|
||||||
String _xifexpression = null;
|
|
||||||
if (adaptIndentation) {
|
|
||||||
_xifexpression = this.getIndentation(context);
|
|
||||||
} else {
|
|
||||||
_xifexpression = null;
|
|
||||||
}
|
|
||||||
final String indentation = _xifexpression;
|
|
||||||
if ((indentation == null)) {
|
|
||||||
stringConcat.append(template);
|
|
||||||
} else {
|
|
||||||
stringConcat.append(template, indentation);
|
|
||||||
}
|
|
||||||
entry.setProposal(stringConcat.toString());
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getLineDelimiter() {
|
|
||||||
return StringConcatenation.DEFAULT_LINE_DELIMITER;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getIndentation(final ContentAssistContext context) {
|
|
||||||
ICompositeNode _rootNode = context.getRootNode();
|
|
||||||
String _text = null;
|
|
||||||
if (_rootNode!=null) {
|
|
||||||
_text=_rootNode.getText();
|
|
||||||
}
|
|
||||||
final String text = _text;
|
|
||||||
if (((text != null) && (text.length() >= context.getOffset()))) {
|
|
||||||
int lineStart = context.getReplaceRegion().getOffset();
|
|
||||||
int indentEnd = lineStart;
|
|
||||||
while (((lineStart > 0) && (text.charAt((lineStart - 1)) != "\n".charAt(0)))) {
|
|
||||||
{
|
|
||||||
lineStart--;
|
|
||||||
boolean _isWhitespace = Character.isWhitespace(text.charAt(lineStart));
|
|
||||||
boolean _not = (!_isWhitespace);
|
|
||||||
if (_not) {
|
|
||||||
indentEnd = lineStart;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return text.substring(lineStart, indentEnd);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,164 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.xtext.ide.server;
|
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
|
||||||
import com.google.common.io.ByteStreams;
|
|
||||||
import com.google.inject.Guice;
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import java.io.ByteArrayInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import org.eclipse.lsp4j.jsonrpc.Launcher;
|
|
||||||
import org.eclipse.lsp4j.services.LanguageClient;
|
|
||||||
import org.eclipse.xtext.ide.server.LanguageServerImpl;
|
|
||||||
import org.eclipse.xtext.ide.server.LaunchArgs;
|
|
||||||
import org.eclipse.xtext.ide.server.ServerModule;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Conversions;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Exceptions;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Functions.Function1;
|
|
||||||
import org.eclipse.xtext.xbase.lib.InputOutput;
|
|
||||||
import org.eclipse.xtext.xbase.lib.IterableExtensions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Sven Efftinge - Initial contribution and API
|
|
||||||
* @since 2.11
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public class ServerLauncher {
|
|
||||||
public static final String LOG = "-log";
|
|
||||||
|
|
||||||
public static final String TRACE = "-trace";
|
|
||||||
|
|
||||||
public static final String NO_VALIDATE = "-noValidate";
|
|
||||||
|
|
||||||
public static void main(final String[] args) {
|
|
||||||
String _name = ServerLauncher.class.getName();
|
|
||||||
ServerModule _serverModule = new ServerModule();
|
|
||||||
ServerLauncher.launch(_name, args, _serverModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void launch(final String prefix, final String[] args, final com.google.inject.Module... modules) {
|
|
||||||
final LaunchArgs launchArgs = ServerLauncher.createLaunchArgs(prefix, args);
|
|
||||||
final ServerLauncher launcher = Guice.createInjector(modules).<ServerLauncher>getInstance(ServerLauncher.class);
|
|
||||||
launcher.start(launchArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
private LanguageServerImpl languageServer;
|
|
||||||
|
|
||||||
public void start(final LaunchArgs it) {
|
|
||||||
try {
|
|
||||||
InputOutput.<String>println("Xtext Language Server is starting.");
|
|
||||||
final Launcher<LanguageClient> launcher = Launcher.<LanguageClient>createLauncher(this.languageServer, LanguageClient.class, it.getIn(), it.getOut(), it.isValidate(), it.getTrace());
|
|
||||||
this.languageServer.connect(launcher.getRemoteProxy());
|
|
||||||
final Future<Void> future = launcher.startListening();
|
|
||||||
InputOutput.<String>println("Xtext Language Server has been started.");
|
|
||||||
while ((!future.isDone())) {
|
|
||||||
Thread.sleep(10_000l);
|
|
||||||
}
|
|
||||||
} catch (Throwable _e) {
|
|
||||||
throw Exceptions.sneakyThrow(_e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static LaunchArgs createLaunchArgs(final String prefix, final String[] args) {
|
|
||||||
final LaunchArgs launchArgs = new LaunchArgs();
|
|
||||||
launchArgs.setIn(System.in);
|
|
||||||
launchArgs.setOut(System.out);
|
|
||||||
ServerLauncher.redirectStandardStreams(prefix, args);
|
|
||||||
launchArgs.setTrace(ServerLauncher.getTrace(args));
|
|
||||||
launchArgs.setValidate(ServerLauncher.shouldValidate(args));
|
|
||||||
return launchArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PrintWriter getTrace(final String[] args) {
|
|
||||||
boolean _shouldTrace = ServerLauncher.shouldTrace(args);
|
|
||||||
if (_shouldTrace) {
|
|
||||||
return ServerLauncher.createTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static PrintWriter createTrace() {
|
|
||||||
return new PrintWriter(System.out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void redirectStandardStreams(final String prefix, final String[] args) {
|
|
||||||
boolean _shouldLogStandardStreams = ServerLauncher.shouldLogStandardStreams(args);
|
|
||||||
if (_shouldLogStandardStreams) {
|
|
||||||
ServerLauncher.logStandardStreams(prefix);
|
|
||||||
} else {
|
|
||||||
ServerLauncher.silentStandardStreams();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean shouldValidate(final String[] args) {
|
|
||||||
boolean _testArg = ServerLauncher.testArg(args, ServerLauncher.NO_VALIDATE);
|
|
||||||
return (!_testArg);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean shouldTrace(final String[] args) {
|
|
||||||
return ServerLauncher.testArg(args, ServerLauncher.TRACE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean shouldLogStandardStreams(final String[] args) {
|
|
||||||
return ServerLauncher.testArg(args, ServerLauncher.LOG, "debug");
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean testArg(final String[] args, final String... values) {
|
|
||||||
final Function1<String, Boolean> _function = (String arg) -> {
|
|
||||||
return Boolean.valueOf(ServerLauncher.testArg(arg, values));
|
|
||||||
};
|
|
||||||
return IterableExtensions.<String>exists(((Iterable<String>)Conversions.doWrapArray(args)), _function);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean testArg(final String arg, final String... values) {
|
|
||||||
final Function1<String, Boolean> _function = (String value) -> {
|
|
||||||
return Boolean.valueOf(Objects.equal(value, arg));
|
|
||||||
};
|
|
||||||
return IterableExtensions.<String>exists(((Iterable<String>)Conversions.doWrapArray(values)), _function);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void logStandardStreams(final String prefix) {
|
|
||||||
try {
|
|
||||||
final FileOutputStream stdFileOut = new FileOutputStream((prefix + "-debug.log"));
|
|
||||||
ServerLauncher.redirectStandardStreams(stdFileOut);
|
|
||||||
} catch (Throwable _e) {
|
|
||||||
throw Exceptions.sneakyThrow(_e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void silentStandardStreams() {
|
|
||||||
ServerLauncher.redirectStandardStreams(ServerLauncher.silentOut());
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void redirectStandardStreams(final OutputStream out) {
|
|
||||||
ServerLauncher.redirectStandardStreams(ServerLauncher.silentIn(), out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void redirectStandardStreams(final InputStream in, final OutputStream out) {
|
|
||||||
System.setIn(in);
|
|
||||||
PrintStream _printStream = new PrintStream(out);
|
|
||||||
System.setOut(_printStream);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static OutputStream silentOut() {
|
|
||||||
return ByteStreams.nullOutputStream();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InputStream silentIn() {
|
|
||||||
byte[] _newByteArrayOfSize = new byte[0];
|
|
||||||
return new ByteArrayInputStream(_newByteArrayOfSize);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,150 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2019 TypeFox GmbH (http://www.typefox.io) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.xtext.ide.server;
|
|
||||||
|
|
||||||
import com.google.common.base.Objects;
|
|
||||||
import com.google.inject.Guice;
|
|
||||||
import com.google.inject.Injector;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.PrintWriter;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.SocketAddress;
|
|
||||||
import java.nio.channels.AsynchronousServerSocketChannel;
|
|
||||||
import java.nio.channels.AsynchronousSocketChannel;
|
|
||||||
import java.nio.channels.Channels;
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.eclipse.lsp4j.jsonrpc.Launcher;
|
|
||||||
import org.eclipse.lsp4j.services.LanguageClient;
|
|
||||||
import org.eclipse.xtext.ide.server.LanguageServerImpl;
|
|
||||||
import org.eclipse.xtext.ide.server.ServerModule;
|
|
||||||
import org.eclipse.xtext.util.internal.Log;
|
|
||||||
import org.eclipse.xtext.xbase.lib.ArrayExtensions;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Exceptions;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Allows to launch a language server vie a server socket.
|
|
||||||
*
|
|
||||||
* Useful for debugging live language servers.
|
|
||||||
*
|
|
||||||
* @author Jan Köhnlein - Initial contribution and API
|
|
||||||
* @since 2.18
|
|
||||||
*/
|
|
||||||
@Log
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public class SocketServerLauncher {
|
|
||||||
public static final String HOST = "-host";
|
|
||||||
|
|
||||||
public static final String PORT = "-port";
|
|
||||||
|
|
||||||
public static final String TRACE = "-trace";
|
|
||||||
|
|
||||||
public static final String NO_VALIDATE = "-noValidate";
|
|
||||||
|
|
||||||
public static final int DEFAULT_PORT = 5008;
|
|
||||||
|
|
||||||
public static final String DEFAULT_HOST = "0.0.0.0";
|
|
||||||
|
|
||||||
public static void main(final String[] args) {
|
|
||||||
new SocketServerLauncher().launch(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void launch(final String[] args) {
|
|
||||||
try {
|
|
||||||
final Injector injector = Guice.createInjector(this.getServerModule());
|
|
||||||
final AsynchronousServerSocketChannel serverSocket = AsynchronousServerSocketChannel.open().bind(this.getSocketAddress(args));
|
|
||||||
InetSocketAddress _socketAddress = this.getSocketAddress(args);
|
|
||||||
String _plus = ("Started server socket at " + _socketAddress);
|
|
||||||
SocketServerLauncher.LOG.info(_plus);
|
|
||||||
while (true) {
|
|
||||||
{
|
|
||||||
final AsynchronousSocketChannel socketChannel = serverSocket.accept().get();
|
|
||||||
final InputStream in = Channels.newInputStream(socketChannel);
|
|
||||||
final OutputStream out = Channels.newOutputStream(socketChannel);
|
|
||||||
final PrintWriter trace = this.getTrace(args);
|
|
||||||
final boolean validate = this.shouldValidate(args);
|
|
||||||
final LanguageServerImpl languageServer = injector.<LanguageServerImpl>getInstance(LanguageServerImpl.class);
|
|
||||||
SocketAddress _remoteAddress = socketChannel.getRemoteAddress();
|
|
||||||
String _plus_1 = ("Starting Xtext Language Server for client " + _remoteAddress);
|
|
||||||
SocketServerLauncher.LOG.info(_plus_1);
|
|
||||||
final Launcher<LanguageClient> launcher = Launcher.<LanguageClient>createLauncher(languageServer, LanguageClient.class, in, out, validate, trace);
|
|
||||||
languageServer.connect(launcher.getRemoteProxy());
|
|
||||||
launcher.startListening();
|
|
||||||
SocketServerLauncher.LOG.info("Xtext Language Server has been started.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (final Throwable _t) {
|
|
||||||
if (_t instanceof Throwable) {
|
|
||||||
final Throwable throwable = (Throwable)_t;
|
|
||||||
throwable.printStackTrace();
|
|
||||||
} else {
|
|
||||||
throw Exceptions.sneakyThrow(_t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected com.google.inject.Module getServerModule() {
|
|
||||||
return new ServerModule();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected PrintWriter getTrace(final String... args) {
|
|
||||||
PrintWriter _xifexpression = null;
|
|
||||||
boolean _contains = ArrayExtensions.contains(args, SocketServerLauncher.TRACE);
|
|
||||||
if (_contains) {
|
|
||||||
_xifexpression = new PrintWriter(System.out);
|
|
||||||
}
|
|
||||||
return _xifexpression;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected boolean shouldValidate(final String... args) {
|
|
||||||
boolean _contains = ArrayExtensions.contains(args, SocketServerLauncher.NO_VALIDATE);
|
|
||||||
return (!_contains);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected InetSocketAddress getSocketAddress(final String... args) {
|
|
||||||
String _host = this.getHost(args);
|
|
||||||
int _port = this.getPort(args);
|
|
||||||
return new InetSocketAddress(_host, _port);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getHost(final String... args) {
|
|
||||||
String _elvis = null;
|
|
||||||
String _value = this.getValue(args, SocketServerLauncher.HOST);
|
|
||||||
if (_value != null) {
|
|
||||||
_elvis = _value;
|
|
||||||
} else {
|
|
||||||
_elvis = SocketServerLauncher.DEFAULT_HOST;
|
|
||||||
}
|
|
||||||
return _elvis;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected int getPort(final String... args) {
|
|
||||||
Integer _elvis = null;
|
|
||||||
Integer _integer = Integer.getInteger(this.getValue(args, SocketServerLauncher.PORT));
|
|
||||||
if (_integer != null) {
|
|
||||||
_elvis = _integer;
|
|
||||||
} else {
|
|
||||||
_elvis = Integer.valueOf(SocketServerLauncher.DEFAULT_PORT);
|
|
||||||
}
|
|
||||||
return (int) _elvis;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected String getValue(final String[] args, final String argName) {
|
|
||||||
for (int i = 0; (i < (args.length - 1)); i++) {
|
|
||||||
String _get = args[i];
|
|
||||||
boolean _equals = Objects.equal(_get, argName);
|
|
||||||
if (_equals) {
|
|
||||||
return args[(i + 1)];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final Logger LOG = Logger.getLogger(SocketServerLauncher.class);
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2016, 2017 TypeFox GmbH (http://www.typefox.io) and others.
|
* Copyright (c) 2016, 2020 TypeFox GmbH (http://www.typefox.io) and others.
|
||||||
* This program and the accompanying materials are made available under the
|
* This program and the accompanying materials are made available under the
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
* http://www.eclipse.org/legal/epl-2.0.
|
||||||
|
@ -12,7 +12,6 @@ import java.util.Collections;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.eclipse.lsp4j.InitializeParams;
|
import org.eclipse.lsp4j.InitializeParams;
|
||||||
import org.eclipse.xtext.xbase.lib.CollectionLiterals;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
||||||
|
|
||||||
public class TextDocumentConfiguration {
|
public class TextDocumentConfiguration {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/**
|
/**
|
||||||
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
|
* Copyright (c) 2015, 2020 itemis AG (http://www.itemis.eu) and others.
|
||||||
* This program and the accompanying materials are made available under the
|
* This program and the accompanying materials are made available under the
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
* http://www.eclipse.org/legal/epl-2.0.
|
||||||
|
@ -12,11 +12,9 @@ import com.google.common.annotations.Beta;
|
||||||
import java.lang.annotation.ElementType;
|
import java.lang.annotation.ElementType;
|
||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
import org.eclipse.xtend.lib.macro.Active;
|
import org.eclipse.xtend.lib.macro.Active;
|
||||||
import org.eclipse.xtext.util.internal.LogProcessor;
|
|
||||||
|
|
||||||
@Beta
|
@Beta
|
||||||
@Target(ElementType.TYPE)
|
@Target(ElementType.TYPE)
|
||||||
@Active(LogProcessor.class)
|
@Active(LogProcessor.class)
|
||||||
@SuppressWarnings("all")
|
|
||||||
public @interface Log {
|
public @interface Log {
|
||||||
}
|
}
|
|
@ -1,38 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*******************************************************************************/
|
|
||||||
package org.eclipse.xtext.util.internal
|
|
||||||
|
|
||||||
import com.google.common.annotations.Beta
|
|
||||||
import java.lang.annotation.Target
|
|
||||||
import org.apache.log4j.Logger
|
|
||||||
import org.eclipse.xtend.lib.macro.AbstractClassProcessor
|
|
||||||
import org.eclipse.xtend.lib.macro.Active
|
|
||||||
import org.eclipse.xtend.lib.macro.TransformationContext
|
|
||||||
import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration
|
|
||||||
|
|
||||||
@Beta
|
|
||||||
@Target(TYPE)
|
|
||||||
@Active(LogProcessor)
|
|
||||||
annotation Log {
|
|
||||||
}
|
|
||||||
|
|
||||||
class LogProcessor extends AbstractClassProcessor {
|
|
||||||
|
|
||||||
override doTransform(MutableClassDeclaration cls, extension TransformationContext context) {
|
|
||||||
cls.addField("LOG") [
|
|
||||||
static = true
|
|
||||||
final = true
|
|
||||||
type = Logger.newTypeReference
|
|
||||||
initializer = '''
|
|
||||||
«Logger».getLogger(«cls.simpleName».class)
|
|
||||||
'''
|
|
||||||
primarySourceElement = cls
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015, 2020 itemis AG (http://www.itemis.eu) and others.
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.eclipse.xtext.util.internal;
|
||||||
|
|
||||||
|
import org.apache.log4j.Logger;
|
||||||
|
import org.eclipse.xtend.lib.macro.AbstractClassProcessor;
|
||||||
|
import org.eclipse.xtend.lib.macro.TransformationContext;
|
||||||
|
import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration;
|
||||||
|
import org.eclipse.xtend2.lib.StringConcatenationClient;
|
||||||
|
|
||||||
|
public class LogProcessor extends AbstractClassProcessor {
|
||||||
|
@Override
|
||||||
|
public void doTransform(MutableClassDeclaration cls, TransformationContext context) {
|
||||||
|
cls.addField("LOG", field -> {
|
||||||
|
field.setStatic(true);
|
||||||
|
field.setFinal(true);
|
||||||
|
field.setType(context.newTypeReference(Logger.class));
|
||||||
|
field.setInitializer(new StringConcatenationClient() {
|
||||||
|
@Override
|
||||||
|
protected void appendTo(TargetStringConcatenation target) {
|
||||||
|
target.append(Logger.class);
|
||||||
|
target.append(".getLogger(");
|
||||||
|
target.append(cls.getSimpleName());
|
||||||
|
target.append(".class)");
|
||||||
|
target.newLineIfNotEmpty();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
context.setPrimarySourceElement(field, cls);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,44 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.xtext.util.internal;
|
|
||||||
|
|
||||||
import org.apache.log4j.Logger;
|
|
||||||
import org.eclipse.xtend.lib.macro.AbstractClassProcessor;
|
|
||||||
import org.eclipse.xtend.lib.macro.TransformationContext;
|
|
||||||
import org.eclipse.xtend.lib.macro.declaration.MutableClassDeclaration;
|
|
||||||
import org.eclipse.xtend.lib.macro.declaration.MutableFieldDeclaration;
|
|
||||||
import org.eclipse.xtend2.lib.StringConcatenationClient;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Extension;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public class LogProcessor extends AbstractClassProcessor {
|
|
||||||
@Override
|
|
||||||
public void doTransform(final MutableClassDeclaration cls, @Extension final TransformationContext context) {
|
|
||||||
final Procedure1<MutableFieldDeclaration> _function = (MutableFieldDeclaration it) -> {
|
|
||||||
it.setStatic(true);
|
|
||||||
it.setFinal(true);
|
|
||||||
it.setType(context.newTypeReference(Logger.class));
|
|
||||||
StringConcatenationClient _client = new StringConcatenationClient() {
|
|
||||||
@Override
|
|
||||||
protected void appendTo(StringConcatenationClient.TargetStringConcatenation _builder) {
|
|
||||||
_builder.append(Logger.class);
|
|
||||||
_builder.append(".getLogger(");
|
|
||||||
String _simpleName = cls.getSimpleName();
|
|
||||||
_builder.append(_simpleName);
|
|
||||||
_builder.append(".class)");
|
|
||||||
_builder.newLineIfNotEmpty();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
it.setInitializer(_client);
|
|
||||||
context.setPrimarySourceElement(it, cls);
|
|
||||||
};
|
|
||||||
cls.addField("LOG", _function);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
/**
|
||||||
|
* Copyright (c) 2015, 2020 itemis AG (http://www.itemis.eu) and others.
|
||||||
|
* This program and the accompanying materials are made available under the
|
||||||
|
* terms of the Eclipse Public License 2.0 which is available at
|
||||||
|
* http://www.eclipse.org/legal/epl-2.0.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: EPL-2.0
|
||||||
|
*/
|
||||||
|
package org.eclipse.xtext.xtext.wizard.cli;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.eclipse.xtext.util.Strings;
|
||||||
|
import org.eclipse.xtext.xbase.lib.Exceptions;
|
||||||
|
import org.eclipse.xtext.xtext.wizard.AbstractFile;
|
||||||
|
import org.eclipse.xtext.xtext.wizard.BinaryFile;
|
||||||
|
import org.eclipse.xtext.xtext.wizard.ProjectDescriptor;
|
||||||
|
import org.eclipse.xtext.xtext.wizard.ProjectsCreator;
|
||||||
|
import org.eclipse.xtext.xtext.wizard.SourceFolderDescriptor;
|
||||||
|
import org.eclipse.xtext.xtext.wizard.TextFile;
|
||||||
|
import org.eclipse.xtext.xtext.wizard.WizardConfiguration;
|
||||||
|
|
||||||
|
import com.google.common.base.Preconditions;
|
||||||
|
import com.google.common.io.Files;
|
||||||
|
import com.google.common.io.Resources;
|
||||||
|
|
||||||
|
public class CliProjectsCreator implements ProjectsCreator {
|
||||||
|
private String lineDelimiter;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createProjects(WizardConfiguration config) {
|
||||||
|
for (ProjectDescriptor p : config.getEnabledProjects()) {
|
||||||
|
createProject(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void createProject(ProjectDescriptor project) {
|
||||||
|
Preconditions.checkNotNull(lineDelimiter, "lineDelimiter may not be null");
|
||||||
|
try {
|
||||||
|
File projectRoot = new File(project.getLocation());
|
||||||
|
projectRoot.mkdirs();
|
||||||
|
for (AbstractFile f : project.getFiles()) {
|
||||||
|
String outletPath = project.getConfig().getSourceLayout().getPathFor(f.getOutlet());
|
||||||
|
String projectRelativePath = outletPath + "/" + f.getRelativePath();
|
||||||
|
File file = new File(projectRoot, projectRelativePath);
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
if (f instanceof TextFile) {
|
||||||
|
String normalizedContent = ((TextFile) f).getContent().replace(Strings.newLine(),
|
||||||
|
lineDelimiter);
|
||||||
|
Files.asCharSink(file, project.getConfig().getEncoding()).write(normalizedContent);
|
||||||
|
} else if (f instanceof BinaryFile) {
|
||||||
|
Files.write(Resources.toByteArray(((BinaryFile) f).getContent()), file);
|
||||||
|
}
|
||||||
|
if (f.isExecutable()) {
|
||||||
|
file.setExecutable(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (SourceFolderDescriptor folder : project.getSourceFolders()) {
|
||||||
|
new File(projectRoot, folder.getPath()).mkdirs();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw Exceptions.sneakyThrow(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getLineDelimiter() {
|
||||||
|
return lineDelimiter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setLineDelimiter(String lineDelimiter) {
|
||||||
|
this.lineDelimiter = lineDelimiter;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,57 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*******************************************************************************/
|
|
||||||
package org.eclipse.xtext.xtext.wizard.cli
|
|
||||||
|
|
||||||
import com.google.common.io.Files
|
|
||||||
import java.io.File
|
|
||||||
import org.eclipse.xtext.xtext.wizard.ProjectDescriptor
|
|
||||||
import org.eclipse.xtext.xtext.wizard.ProjectsCreator
|
|
||||||
import org.eclipse.xtext.xtext.wizard.WizardConfiguration
|
|
||||||
import org.eclipse.xtend.lib.annotations.Accessors
|
|
||||||
import org.eclipse.xtext.util.Strings
|
|
||||||
import org.eclipse.xtext.xtext.wizard.TextFile
|
|
||||||
import org.eclipse.xtext.xtext.wizard.BinaryFile
|
|
||||||
import com.google.common.io.Resources
|
|
||||||
|
|
||||||
class CliProjectsCreator implements ProjectsCreator {
|
|
||||||
|
|
||||||
@Accessors String lineDelimiter
|
|
||||||
|
|
||||||
override createProjects(WizardConfiguration config) {
|
|
||||||
config.enabledProjects.forEach [
|
|
||||||
createProject
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
def createProject(ProjectDescriptor project) {
|
|
||||||
val projectRoot = new File(project.location)
|
|
||||||
projectRoot.mkdirs
|
|
||||||
project.files.forEach [
|
|
||||||
val projectRelativePath = project.config.sourceLayout.getPathFor(outlet) + "/" + relativePath
|
|
||||||
val file = new File(projectRoot, projectRelativePath)
|
|
||||||
file.parentFile.mkdirs
|
|
||||||
switch(it) {
|
|
||||||
TextFile : {
|
|
||||||
val normalizedContent = content.replace(Strings.newLine, lineDelimiter)
|
|
||||||
Files.asCharSink(file, project.config.encoding).write(normalizedContent)
|
|
||||||
}
|
|
||||||
BinaryFile: {
|
|
||||||
Files.write(Resources.toByteArray(content), file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(executable) {
|
|
||||||
file.executable = true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
project.sourceFolders.forEach [
|
|
||||||
new File(projectRoot, it.path).mkdirs
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright (c) 2015 itemis AG (http://www.itemis.eu) and others.
|
|
||||||
* This program and the accompanying materials are made available under the
|
|
||||||
* terms of the Eclipse Public License 2.0 which is available at
|
|
||||||
* http://www.eclipse.org/legal/epl-2.0.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: EPL-2.0
|
|
||||||
*/
|
|
||||||
package org.eclipse.xtext.xtext.wizard.cli;
|
|
||||||
|
|
||||||
import com.google.common.io.Files;
|
|
||||||
import com.google.common.io.Resources;
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
import org.eclipse.xtend.lib.annotations.Accessors;
|
|
||||||
import org.eclipse.xtext.util.Strings;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Exceptions;
|
|
||||||
import org.eclipse.xtext.xbase.lib.Pure;
|
|
||||||
import org.eclipse.xtext.xtext.wizard.AbstractFile;
|
|
||||||
import org.eclipse.xtext.xtext.wizard.BinaryFile;
|
|
||||||
import org.eclipse.xtext.xtext.wizard.ProjectDescriptor;
|
|
||||||
import org.eclipse.xtext.xtext.wizard.ProjectsCreator;
|
|
||||||
import org.eclipse.xtext.xtext.wizard.SourceFolderDescriptor;
|
|
||||||
import org.eclipse.xtext.xtext.wizard.TextFile;
|
|
||||||
import org.eclipse.xtext.xtext.wizard.WizardConfiguration;
|
|
||||||
|
|
||||||
@SuppressWarnings("all")
|
|
||||||
public class CliProjectsCreator implements ProjectsCreator {
|
|
||||||
@Accessors
|
|
||||||
private String lineDelimiter;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void createProjects(final WizardConfiguration config) {
|
|
||||||
final Consumer<ProjectDescriptor> _function = (ProjectDescriptor it) -> {
|
|
||||||
this.createProject(it);
|
|
||||||
};
|
|
||||||
config.getEnabledProjects().forEach(_function);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void createProject(final ProjectDescriptor project) {
|
|
||||||
String _location = project.getLocation();
|
|
||||||
final File projectRoot = new File(_location);
|
|
||||||
projectRoot.mkdirs();
|
|
||||||
final Consumer<AbstractFile> _function = (AbstractFile it) -> {
|
|
||||||
try {
|
|
||||||
String _pathFor = project.getConfig().getSourceLayout().getPathFor(it.getOutlet());
|
|
||||||
String _plus = (_pathFor + "/");
|
|
||||||
String _relativePath = it.getRelativePath();
|
|
||||||
final String projectRelativePath = (_plus + _relativePath);
|
|
||||||
final File file = new File(projectRoot, projectRelativePath);
|
|
||||||
file.getParentFile().mkdirs();
|
|
||||||
boolean _matched = false;
|
|
||||||
if (it instanceof TextFile) {
|
|
||||||
_matched=true;
|
|
||||||
final String normalizedContent = ((TextFile)it).getContent().replace(Strings.newLine(), this.lineDelimiter);
|
|
||||||
Files.asCharSink(file, project.getConfig().getEncoding()).write(normalizedContent);
|
|
||||||
}
|
|
||||||
if (!_matched) {
|
|
||||||
if (it instanceof BinaryFile) {
|
|
||||||
_matched=true;
|
|
||||||
Files.write(Resources.toByteArray(((BinaryFile)it).getContent()), file);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
boolean _isExecutable = it.isExecutable();
|
|
||||||
if (_isExecutable) {
|
|
||||||
file.setExecutable(true);
|
|
||||||
}
|
|
||||||
} catch (Throwable _e) {
|
|
||||||
throw Exceptions.sneakyThrow(_e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
project.getFiles().forEach(_function);
|
|
||||||
final Consumer<SourceFolderDescriptor> _function_1 = (SourceFolderDescriptor it) -> {
|
|
||||||
String _path = it.getPath();
|
|
||||||
new File(projectRoot, _path).mkdirs();
|
|
||||||
};
|
|
||||||
project.getSourceFolders().forEach(_function_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Pure
|
|
||||||
public String getLineDelimiter() {
|
|
||||||
return this.lineDelimiter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLineDelimiter(final String lineDelimiter) {
|
|
||||||
this.lineDelimiter = lineDelimiter;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in a new issue