Skip to content

Commit

Permalink
Merge pull request #402 from usethesource/code-actions-for-dsls
Browse files Browse the repository at this point in the history
code actions for dsls
  • Loading branch information
jurgenvinju authored Sep 27, 2024
2 parents 6f712be + f80d525 commit b0ec081
Show file tree
Hide file tree
Showing 18 changed files with 752 additions and 38 deletions.
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@ done

rm -f rascal-lsp/target/*.jar

(cd rascal-lsp && mvn $clean package $extra_flags )
(cd rascal-lsp && mvn $clean package -Drascal.monitor.batch $extra_flags )
(cd rascal-vscode-extension && npm run lsp4j:package )

Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ public CompletableFuture<Two<String, URI[]>[]> supplyPathConfig(PathConfigParame
return CompletableFuture.supplyAsync(() -> {
try {
var pcfg = PathConfig.fromSourceProjectMemberRascalManifest(projectFolder.getLocation(), projectFolder.getMode().mapConfigMode());
@SuppressWarnings("unchecked")
Two<String, URI[]>[] result = new Two[4];
result[0] = new Two<>("Sources", toURIArray(pcfg.getSrcs()));
result[1] = new Two<>("Libraries", toURIArray(pcfg.getLibs()));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,13 @@ public interface ILanguageContributions {
public InterruptibleFuture<IConstructor> build(ISourceLocation loc, ITree input);
public InterruptibleFuture<ISet> lenses(ITree input);
public InterruptibleFuture<@Nullable IValue> executeCommand(String command);
public CompletableFuture<IList> parseCodeActions(String command);
public InterruptibleFuture<IList> inlayHint(@Nullable ITree input);
public InterruptibleFuture<ISet> documentation(ISourceLocation loc, ITree input, ITree cursor);
public InterruptibleFuture<ISet> definitions(ISourceLocation loc, ITree input, ITree cursor);
public InterruptibleFuture<ISet> references(ISourceLocation loc, ITree input, ITree cursor);
public InterruptibleFuture<ISet> implementations(ISourceLocation loc, ITree input, ITree cursor);
public InterruptibleFuture<IList> codeActions(IList focus);

public CompletableFuture<Boolean> hasAnalyzer();
public CompletableFuture<Boolean> hasBuilder();
Expand All @@ -67,6 +69,7 @@ public interface ILanguageContributions {
public CompletableFuture<Boolean> hasDefiner();
public CompletableFuture<Boolean> hasReferrer();
public CompletableFuture<Boolean> hasImplementer();
public CompletableFuture<Boolean> hasCodeActionsContributor();

public CompletableFuture<SummaryConfig> getAnalyzerSummaryConfig();
public CompletableFuture<SummaryConfig> getBuilderSummaryConfig();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@
import io.usethesource.vallang.IValueFactory;
import io.usethesource.vallang.exceptions.FactTypeUseException;
import io.usethesource.vallang.io.StandardTextReader;
import io.usethesource.vallang.type.TypeFactory;
import io.usethesource.vallang.type.TypeStore;

public class InterpretedLanguageContributions implements ILanguageContributions {
Expand All @@ -84,6 +85,7 @@ public class InterpretedLanguageContributions implements ILanguageContributions
private final CompletableFuture<@Nullable IFunction> definer;
private final CompletableFuture<@Nullable IFunction> referrer;
private final CompletableFuture<@Nullable IFunction> implementer;
private final CompletableFuture<@Nullable IFunction> codeActionContributor;

private final CompletableFuture<Boolean> hasOutliner;
private final CompletableFuture<Boolean> hasAnalyzer;
Expand All @@ -95,6 +97,7 @@ public class InterpretedLanguageContributions implements ILanguageContributions
private final CompletableFuture<Boolean> hasDefiner;
private final CompletableFuture<Boolean> hasReferrer;
private final CompletableFuture<Boolean> hasImplementer;
private final CompletableFuture<Boolean> hasCodeActionContributor;

private final CompletableFuture<SummaryConfig> analyzerSummaryConfig;
private final CompletableFuture<SummaryConfig> builderSummaryConfig;
Expand Down Expand Up @@ -130,6 +133,7 @@ public InterpretedLanguageContributions(LanguageParameter lang, IBaseTextDocumen
this.definer = getFunctionFor(contributions, LanguageContributions.DEFINER);
this.referrer = getFunctionFor(contributions, LanguageContributions.REFERRER);
this.implementer = getFunctionFor(contributions, LanguageContributions.IMPLEMENTER);
this.codeActionContributor = getFunctionFor(contributions, LanguageContributions.CODE_ACTION_CONTRIBUTOR);

// assign boolean properties once instead of wasting futures all the time
this.hasOutliner = nonNull(this.outliner);
Expand All @@ -142,14 +146,15 @@ public InterpretedLanguageContributions(LanguageParameter lang, IBaseTextDocumen
this.hasDefiner = nonNull(this.definer);
this.hasReferrer = nonNull(this.referrer);
this.hasImplementer = nonNull(this.implementer);
this.hasCodeActionContributor = nonNull(this.codeActionContributor);

this.analyzerSummaryConfig = scheduledSummaryConfig(contributions, LanguageContributions.ANALYZER);
this.builderSummaryConfig = scheduledSummaryConfig(contributions, LanguageContributions.BUILDER);
this.ondemandSummaryConfig = ondemandSummaryConfig(contributions);

} catch (IOException e1) {
logger.catching(e1);
throw new RuntimeException(e1);
throw new IllegalArgumentException(e1);
}
}

Expand Down Expand Up @@ -207,12 +212,28 @@ private static ISet loadContributions(Evaluator eval, LanguageParameter lang) {
.getValue();
}

@Override
public CompletableFuture<IList> parseCodeActions(String command) {
return store.thenApply(commandStore -> {
try {
var TF = TypeFactory.getInstance();
return (IList) new StandardTextReader().read(VF, commandStore, TF.listType(commandStore.lookupAbstractDataType("CodeAction")), new StringReader(command));
} catch (FactTypeUseException | IOException e) {
// this should never happen as long as the Rascal code
// for creating errors is type-correct. So it _might_ happen
// when running the interpreter on broken code.
throw new IllegalArgumentException("The command could not be parsed", e);
}
});
}

private CompletableFuture<IConstructor> parseCommand(String command) {
return store.thenApply(commandStore -> {
try {
return (IConstructor) new StandardTextReader().read(VF, commandStore, commandStore.lookupAbstractDataType("Command"), new StringReader(command));
} catch (FactTypeUseException | IOException e) {
throw new RuntimeException(e);
logger.catching(e);
throw new IllegalArgumentException("The command could not be parsed", e);
}
});
}
Expand Down Expand Up @@ -287,12 +308,19 @@ public InterruptibleFuture<ISet> implementations(ISourceLocation loc, ITree inpu
debug(LanguageContributions.IMPLEMENTER, TreeAdapter.getLocation(cursor));
return execFunction(LanguageContributions.IMPLEMENTER, implementer, VF.set(), loc, input, cursor);
}

@Override
public InterruptibleFuture<ISet> references(ISourceLocation loc, ITree input, ITree cursor) {
debug(LanguageContributions.REFERRER, TreeAdapter.getLocation(cursor));
return execFunction(LanguageContributions.REFERRER, referrer, VF.set(), loc, input, cursor);
}

@Override
public InterruptibleFuture<IList> codeActions(IList focus) {
debug(LanguageContributions.CODE_ACTION_CONTRIBUTOR, "(focus list has " + focus.length() + " elements)");
return execFunction(LanguageContributions.CODE_ACTION_CONTRIBUTOR, codeActionContributor, VF.list(), focus);
}

private void debug(String name, Object param) {
logger.debug("{}({})", name, param);
}
Expand Down Expand Up @@ -341,6 +369,11 @@ public CompletableFuture<Boolean> hasOutliner() {
return hasOutliner;
}

@Override
public CompletableFuture<Boolean> hasCodeActionsContributor() {
return hasCodeActionContributor;
}

@Override
public CompletableFuture<Boolean> hasAnalyzer() {
return hasAnalyzer;
Expand Down Expand Up @@ -370,8 +403,26 @@ public CompletableFuture<SummaryConfig> getOndemandSummaryConfig() {
public InterruptibleFuture<@Nullable IValue> executeCommand(String command) {
logger.debug("executeCommand({}...) (full command value in TRACE level)", () -> command.substring(0, Math.min(10, command.length())));
logger.trace("Full command: {}", command);
return InterruptibleFuture.flatten(parseCommand(command).thenCombine(commandExecutor,
(cons, func) -> EvaluatorUtil.<@Nullable IValue>runEvaluator("executeCommand", eval, ev -> func.call(cons), null, exec, true, client)

return InterruptibleFuture.flatten(parseCommand(command).thenCombine(
commandExecutor,
(cons, func) -> {

if (func == null) {
logger.warn("Command is being executed without a registered command executor; for language {}", name);
throw new IllegalStateException("No command executor registered for " + name);
}

return EvaluatorUtil.<@Nullable IValue>runEvaluator(
"executeCommand",
eval,
ev -> func.call(cons),
null,
exec,
true,
client
);
}
), exec);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ private static final <T> CompletableFuture<T> failedInitialization() {
private volatile CompletableFuture<ILanguageContributions> documenter = failedInitialization();
private volatile CompletableFuture<ILanguageContributions> referrer = failedInitialization();
private volatile CompletableFuture<ILanguageContributions> implementer = failedInitialization();
private volatile CompletableFuture<ILanguageContributions> codeActionContributor = failedInitialization();

private volatile CompletableFuture<Boolean> hasDocumenter = failedInitialization();
private volatile CompletableFuture<Boolean> hasDefiner = failedInitialization();
Expand All @@ -74,6 +75,7 @@ private static final <T> CompletableFuture<T> failedInitialization() {
private volatile CompletableFuture<Boolean> hasLensDetector = failedInitialization();
private volatile CompletableFuture<Boolean> hasCommandExecutor = failedInitialization();
private volatile CompletableFuture<Boolean> hasInlayHinter = failedInitialization();
private volatile CompletableFuture<Boolean> hasCodeActionContributor = failedInitialization();

private volatile CompletableFuture<SummaryConfig> analyzerSummaryConfig;
private volatile CompletableFuture<SummaryConfig> builderSummaryConfig;
Expand Down Expand Up @@ -143,6 +145,7 @@ private synchronized void calculateRouting() {
documenter = findFirstOrDefault(ILanguageContributions::hasDocumenter);
referrer = findFirstOrDefault(ILanguageContributions::hasReferrer);
implementer = findFirstOrDefault(ILanguageContributions::hasImplementer);
codeActionContributor = findFirstOrDefault(ILanguageContributions::hasCodeActionsContributor);

hasDocumenter = anyTrue(ILanguageContributions::hasDocumenter);
hasDefiner = anyTrue(ILanguageContributions::hasDefiner);
Expand Down Expand Up @@ -253,6 +256,11 @@ public InterruptibleFuture<ISet> lenses(ITree input) {
return flatten(commandExecutor, c -> c.executeCommand(command));
}

@Override
public CompletableFuture<IList> parseCodeActions(String command) {
return commandExecutor.thenApply(c -> c.parseCodeActions(command)).thenCompose(Function.identity());
}

@Override
public InterruptibleFuture<IList> inlayHint(@Nullable ITree input) {
return flatten(inlayHinter, c -> c.inlayHint(input));
Expand All @@ -278,6 +286,15 @@ public InterruptibleFuture<ISet> implementations(ISourceLocation loc, ITree inpu
return flatten(implementer, c -> c.implementations(loc, input, cursor));
}

@Override
public InterruptibleFuture<IList> codeActions(IList focus) {
return flatten(codeActionContributor, c -> c.codeActions(focus));
}

@Override
public CompletableFuture<Boolean> hasCodeActionsContributor() {
return hasCodeActionContributor;
}

@Override
public CompletableFuture<Boolean> hasDocumenter() {
Expand Down
Loading

0 comments on commit b0ec081

Please sign in to comment.