From a924eec43aa430a3b72ca09d223ee79729997bb7 Mon Sep 17 00:00:00 2001 From: Rodin Aarssen Date: Mon, 21 Sep 2026 15:12:27 +0200 Subject: [PATCH 1/6] Added Java declarations of Rascal ADTs and constructors --- src/org/rascalmpl/library/Messages.java | 30 +++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index a706600c504..6745adb7553 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -43,6 +43,36 @@ public class Messages { private static final io.usethesource.vallang.type.Type Message_warning = tf.constructor(ts, Message, "warning", tf.stringType(), "msg", tf.sourceLocationType(), "at"); private static final io.usethesource.vallang.type.Type Message_error = tf.constructor(ts, Message, "error", tf.stringType(), "msg", tf.sourceLocationType(), "at"); + // These declarations mirror the data definitions in the `util::IDEServices` module of the standard library + private static final io.usethesource.vallang.type.Type CodeAction = tf.abstractDataType(ts, "CodeAction"); + private static final io.usethesource.vallang.type.Type CodeAction_action = tf.constructor(ts, CodeAction, "action"); + + private static final io.usethesource.vallang.type.Type Command = tf.abstractDataType(ts, "Command"); + private static final io.usethesource.vallang.type.Type Command_noop = tf.constructor(ts, Command, "noop"); + + // These declarations mirror the data definition in the `analysis::diff::edits::FileSystemChanges` module of the standard library + private static final io.usethesource.vallang.type.Type FileSystemChange = tf.abstractDataType(ts, "FileSystemChange"); + private static final io.usethesource.vallang.type.Type FileSystemChange_removed = tf.constructor(ts, FileSystemChange, "removed", tf.sourceLocationType(), "file"); + private static final io.usethesource.vallang.type.Type FileSystemChange_created = tf.constructor(ts, FileSystemChange, "created", tf.sourceLocationType(), "file"); + private static final io.usethesource.vallang.type.Type FileSystemChange_renamed = tf.constructor(ts, FileSystemChange, "renamed", tf.sourceLocationType(), "from", tf.sourceLocationType(), "to"); + private static final io.usethesource.vallang.type.Type FileSystemChange_changed = tf.constructor(ts, FileSystemChange, "changed", tf.sourceLocationType(), "file"); + + // This declaration does not mirror a constructor from the standard library; it is here to be able to send the command, but the declaration must live in the implementing project (e.g., `rascal-lsp`) + public static final io.usethesource.vallang.type.Type Command_addRascalDependencyToPom = tf.constructor(ts, Command, "addRascalDependencyToPom", tf.sourceLocationType(), "pomLoc"); + + static { + // data Message(list[CodeAction] fixes = []]); + ts.declareKeywordParameter(Message, "fixes", tf.listType(CodeAction)); + + // data CodeAction(list[FileSystemChange] edits = [], Command command = noop(), str title = command.title); + ts.declareKeywordParameter(CodeAction, "edits", tf.listType(FileSystemChange)); + ts.declareKeywordParameter(CodeAction, "command", Command); + ts.declareKeywordParameter(CodeAction, "title", tf.stringType()); + + // data Command(str title=""); + ts.declareKeywordParameter(CodeAction, "title", tf.stringType()); + } + public static IConstructor info(String message, ISourceLocation loc) { return message(Message_info, message, loc); } From cff8fe70b41a3b52212ad024e705ce150e4e5141 Mon Sep 17 00:00:00 2001 From: Rodin Aarssen Date: Mon, 21 Sep 2026 15:14:18 +0200 Subject: [PATCH 2/6] Added utility function to more easily add fixes to a Message --- src/org/rascalmpl/library/Messages.java | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index 6745adb7553..f1bb286f716 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -3,6 +3,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; +import java.util.Map; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -103,6 +104,30 @@ public static IConstructor addCause(IConstructor msg, String cause, ISourceLocat return msg.asWithKeywordParameters().setParameter("causes", causes); } + public static IConstructor addAddRascalDependencyFix(IConstructor msg, ISourceLocation pomXml) { + var title = "Add Rascal dependency to pom.xml"; + var codeAction = vf.constructor(Messages.Command_addRascalDependencyToPom, new IValue[] { pomXml }, Map.of( + "title", vf.string(title) + )); + var fix = vf.constructor(Messages.CodeAction_action, new IValue[]{}, Map.of( + "command", codeAction, + "title", vf.string(title), + "edits", vf.list())); + return addFix(msg, fix); + } + + public static IConstructor addFix(IConstructor msg, IConstructor fix) { + if (fix == null) { + return msg; + } + + var kw = msg.asWithKeywordParameters(); + IList fixes = (IList) kw.getParameter("fixes"); + fixes = fixes == null ? vf.list(fix) : fixes.append(fix); + + return kw.setParameter("fixes", fixes); + } + public static boolean isError(IValue v) { return v instanceof IConstructor && ((IConstructor) v).getConstructorType() == Message_error; } From 21016b96b245ffbf9de090732f88fcc86fda79d5 Mon Sep 17 00:00:00 2001 From: Rodin Aarssen Date: Mon, 21 Sep 2026 15:16:20 +0200 Subject: [PATCH 3/6] A missing Rascal dependency is now signaled during path config creation --- src/org/rascalmpl/library/util/PathConfig.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 2c94283f391..ffcf1a539ef 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -520,7 +520,7 @@ private static void buildRascalSelfApplicationConfig(ISourceLocation workspaceRa * Configure paths for the rascal-lsp project when it's open in the IDE (the runtime inside rascal-lsp is not configured here) */ private static void buildRascalLSPConfig(ISourceLocation manifestRoot, RascalConfigMode mode, List mavenClasspath, IListWriter srcs, IListWriter libs, IListWriter messages) throws IOException { - var rascalRuntime = getRelevantRascal(mavenClasspath, mode); + var rascalRuntime = getRelevantRascal(mavenClasspath, mode, manifestRoot, messages); var insideRascalJar = JarURIResolver.jarify(MavenRepositoryURIResolver.mavenize(rascalRuntime)); var rascalLibrary = URIUtil.getChildLocation(insideRascalJar, "org/rascalmpl/library"); var rascalCompiler = URIUtil.getChildLocation(insideRascalJar, "org/rascalmpl/compiler"); @@ -576,7 +576,7 @@ public static boolean isRascalArtifact(Artifact art) { && coord.getGroupId().equals("org.rascalmpl"); } - private static ISourceLocation getRelevantRascal(List mavenClasspath, RascalConfigMode mode) throws IOException { + private static ISourceLocation getRelevantRascal(List mavenClasspath, RascalConfigMode mode, ISourceLocation manifestRoot, IListWriter messages) throws IOException { if (mode == RascalConfigMode.INTERPRETER_EXTERNAL || mode == RascalConfigMode.COMPILER) { var rascalFromPom = mavenClasspath.stream() .filter(PathConfig::isRascalArtifact) @@ -586,6 +586,10 @@ private static ISourceLocation getRelevantRascal(List mavenClasspath, .map(vf::sourceLocation); if (rascalFromPom.isPresent()) { return rascalFromPom.get(); + } else { + var pomXml = vf.sourceLocation(URIUtil.getChildLocation(manifestRoot, "pom.xml"), 0, 6, 1, 1, 0, 5); + var msg = Messages.warning("Missing required Rascal dependency in project " + URIUtil.getLocationName(manifestRoot), pomXml); + messages.append(Messages.addAddRascalDependencyFix(msg, pomXml)); } } return resolveCurrentRascalRuntime(); @@ -593,7 +597,7 @@ private static ISourceLocation getRelevantRascal(List mavenClasspath, private static void buildNormalProjectConfig(ISourceLocation manifestRoot, RascalConfigMode mode, List mavenClasspath, boolean isRoot, IListWriter srcs, IListWriter libs, IListWriter messages) throws IOException, URISyntaxException { if (isRoot) { - var rascal = getRelevantRascal(mavenClasspath, mode); + var rascal = getRelevantRascal(mavenClasspath, mode, manifestRoot, messages); var insideRascal = JarURIResolver.jarify(MavenRepositoryURIResolver.mavenize(rascal)); libs.append(rascal); From fbeb2bb644e2926379669538b43f761f655082d1 Mon Sep 17 00:00:00 2001 From: Rodin Aarssen Date: Mon, 21 Sep 2026 17:21:51 +0200 Subject: [PATCH 4/6] The message signaling a missing Rascal dependency is now artificially set to line 2 of the pom.xml file to ensure that the quick-fix pop-up does not immediately disappear --- src/org/rascalmpl/library/util/PathConfig.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index ffcf1a539ef..0737c8a877d 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -587,14 +587,20 @@ private static ISourceLocation getRelevantRascal(List mavenClasspath, if (rascalFromPom.isPresent()) { return rascalFromPom.get(); } else { - var pomXml = vf.sourceLocation(URIUtil.getChildLocation(manifestRoot, "pom.xml"), 0, 6, 1, 1, 0, 5); - var msg = Messages.warning("Missing required Rascal dependency in project " + URIUtil.getLocationName(manifestRoot), pomXml); - messages.append(Messages.addAddRascalDependencyFix(msg, pomXml)); + messages.append(makeMissingRascalMessage(manifestRoot)); } } return resolveCurrentRascalRuntime(); } + private static IConstructor makeMissingRascalMessage(ISourceLocation manifestRoot) { + // The `pomXml` location is given an artificial range on the second line to make sure that the hover remains within the bounds of the editor + // Otherwise, the quick-fix pop-up immediately disappears as the editor loses focus + var pomXml = vf.sourceLocation(URIUtil.getChildLocation(manifestRoot, "pom.xml"), 0, 0, 2, 2, 0, 8); + var msg = Messages.warning("Missing required Rascal dependency in project " + URIUtil.getLocationName(manifestRoot), pomXml); + return Messages.addAddRascalDependencyFix(msg, pomXml); + } + private static void buildNormalProjectConfig(ISourceLocation manifestRoot, RascalConfigMode mode, List mavenClasspath, boolean isRoot, IListWriter srcs, IListWriter libs, IListWriter messages) throws IOException, URISyntaxException { if (isRoot) { var rascal = getRelevantRascal(mavenClasspath, mode, manifestRoot, messages); From 2842b81caa95b50cbd2845d68e77ea70741a6678 Mon Sep 17 00:00:00 2001 From: Rodin Aarssen Date: Tue, 22 Sep 2026 10:13:06 +0200 Subject: [PATCH 5/6] Moved some PathConfig-specific constructors and functions from Messages to PathConfig after feedback from @DavyLandman --- src/org/rascalmpl/library/Messages.java | 19 ++----------------- .../rascalmpl/library/util/PathConfig.java | 12 +++++++++++- 2 files changed, 13 insertions(+), 18 deletions(-) diff --git a/src/org/rascalmpl/library/Messages.java b/src/org/rascalmpl/library/Messages.java index f1bb286f716..26121a15c28 100644 --- a/src/org/rascalmpl/library/Messages.java +++ b/src/org/rascalmpl/library/Messages.java @@ -46,9 +46,9 @@ public class Messages { // These declarations mirror the data definitions in the `util::IDEServices` module of the standard library private static final io.usethesource.vallang.type.Type CodeAction = tf.abstractDataType(ts, "CodeAction"); - private static final io.usethesource.vallang.type.Type CodeAction_action = tf.constructor(ts, CodeAction, "action"); + public static final io.usethesource.vallang.type.Type CodeAction_action = tf.constructor(ts, CodeAction, "action"); - private static final io.usethesource.vallang.type.Type Command = tf.abstractDataType(ts, "Command"); + public static final io.usethesource.vallang.type.Type Command = tf.abstractDataType(ts, "Command"); private static final io.usethesource.vallang.type.Type Command_noop = tf.constructor(ts, Command, "noop"); // These declarations mirror the data definition in the `analysis::diff::edits::FileSystemChanges` module of the standard library @@ -58,9 +58,6 @@ public class Messages { private static final io.usethesource.vallang.type.Type FileSystemChange_renamed = tf.constructor(ts, FileSystemChange, "renamed", tf.sourceLocationType(), "from", tf.sourceLocationType(), "to"); private static final io.usethesource.vallang.type.Type FileSystemChange_changed = tf.constructor(ts, FileSystemChange, "changed", tf.sourceLocationType(), "file"); - // This declaration does not mirror a constructor from the standard library; it is here to be able to send the command, but the declaration must live in the implementing project (e.g., `rascal-lsp`) - public static final io.usethesource.vallang.type.Type Command_addRascalDependencyToPom = tf.constructor(ts, Command, "addRascalDependencyToPom", tf.sourceLocationType(), "pomLoc"); - static { // data Message(list[CodeAction] fixes = []]); ts.declareKeywordParameter(Message, "fixes", tf.listType(CodeAction)); @@ -104,18 +101,6 @@ public static IConstructor addCause(IConstructor msg, String cause, ISourceLocat return msg.asWithKeywordParameters().setParameter("causes", causes); } - public static IConstructor addAddRascalDependencyFix(IConstructor msg, ISourceLocation pomXml) { - var title = "Add Rascal dependency to pom.xml"; - var codeAction = vf.constructor(Messages.Command_addRascalDependencyToPom, new IValue[] { pomXml }, Map.of( - "title", vf.string(title) - )); - var fix = vf.constructor(Messages.CodeAction_action, new IValue[]{}, Map.of( - "command", codeAction, - "title", vf.string(title), - "edits", vf.list())); - return addFix(msg, fix); - } - public static IConstructor addFix(IConstructor msg, IConstructor fix) { if (fix == null) { return msg; diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index 0737c8a877d..d9ecd29bd9a 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -593,12 +593,22 @@ private static ISourceLocation getRelevantRascal(List mavenClasspath, return resolveCurrentRascalRuntime(); } + // This declaration does not mirror a constructor from the standard library; it is here to be able to send the command, but the declaration must live in the implementing project (e.g., `rascal-lsp`) + private static final io.usethesource.vallang.type.Type Command_addRascalDependencyToPom = tf.constructor(store, Messages.Command, "addRascalDependencyToPom", tf.sourceLocationType(), "pomLoc"); + + public static IConstructor addAddRascalDependencyFix(IConstructor msg, ISourceLocation pomXml) { + var title = "Add Rascal dependency to pom.xml"; + var codeAction = vf.constructor(Command_addRascalDependencyToPom, new IValue[] { pomXml }, Map.of("title", vf.string(title))); + var fix = vf.constructor(Messages.CodeAction_action, new IValue[]{}, Map.of("command", codeAction)); + return Messages.addFix(msg, fix); + } + private static IConstructor makeMissingRascalMessage(ISourceLocation manifestRoot) { // The `pomXml` location is given an artificial range on the second line to make sure that the hover remains within the bounds of the editor // Otherwise, the quick-fix pop-up immediately disappears as the editor loses focus var pomXml = vf.sourceLocation(URIUtil.getChildLocation(manifestRoot, "pom.xml"), 0, 0, 2, 2, 0, 8); var msg = Messages.warning("Missing required Rascal dependency in project " + URIUtil.getLocationName(manifestRoot), pomXml); - return Messages.addAddRascalDependencyFix(msg, pomXml); + return addAddRascalDependencyFix(msg, pomXml); } private static void buildNormalProjectConfig(ISourceLocation manifestRoot, RascalConfigMode mode, List mavenClasspath, boolean isRoot, IListWriter srcs, IListWriter libs, IListWriter messages) throws IOException, URISyntaxException { From 1d52fa26ea69dae61dcf58c9829a051b9efe0351 Mon Sep 17 00:00:00 2001 From: Rodin Aarssen Date: Tue, 22 Sep 2026 10:35:22 +0200 Subject: [PATCH 6/6] Made function private --- src/org/rascalmpl/library/util/PathConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/org/rascalmpl/library/util/PathConfig.java b/src/org/rascalmpl/library/util/PathConfig.java index d9ecd29bd9a..359d9cb8013 100644 --- a/src/org/rascalmpl/library/util/PathConfig.java +++ b/src/org/rascalmpl/library/util/PathConfig.java @@ -596,7 +596,7 @@ private static ISourceLocation getRelevantRascal(List mavenClasspath, // This declaration does not mirror a constructor from the standard library; it is here to be able to send the command, but the declaration must live in the implementing project (e.g., `rascal-lsp`) private static final io.usethesource.vallang.type.Type Command_addRascalDependencyToPom = tf.constructor(store, Messages.Command, "addRascalDependencyToPom", tf.sourceLocationType(), "pomLoc"); - public static IConstructor addAddRascalDependencyFix(IConstructor msg, ISourceLocation pomXml) { + private static IConstructor addAddRascalDependencyFix(IConstructor msg, ISourceLocation pomXml) { var title = "Add Rascal dependency to pom.xml"; var codeAction = vf.constructor(Command_addRascalDependencyToPom, new IValue[] { pomXml }, Map.of("title", vf.string(title))); var fix = vf.constructor(Messages.CodeAction_action, new IValue[]{}, Map.of("command", codeAction));