Skip to content

Commit 02d5018

Browse files
committed
Qute debugging support inside Java file
Signed-off-by: azerr <[email protected]>
1 parent 0716372 commit 02d5018

File tree

18 files changed

+802
-260
lines changed

18 files changed

+802
-260
lines changed

extensions/qute/deployment/src/main/java/io/quarkus/qute/deployment/QuteProcessor.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
import io.quarkus.qute.Expression;
119119
import io.quarkus.qute.Expression.VirtualMethodPart;
120120
import io.quarkus.qute.Identifiers;
121+
import io.quarkus.qute.JavaElementUriBuilder;
121122
import io.quarkus.qute.LoopSectionHelper;
122123
import io.quarkus.qute.NamespaceResolver;
123124
import io.quarkus.qute.ParameterDeclaration;
@@ -129,6 +130,7 @@
129130
import io.quarkus.qute.SectionHelperFactory;
130131
import io.quarkus.qute.SetSectionHelper;
131132
import io.quarkus.qute.Template;
133+
import io.quarkus.qute.TemplateContents;
132134
import io.quarkus.qute.TemplateData;
133135
import io.quarkus.qute.TemplateException;
134136
import io.quarkus.qute.TemplateExtension;
@@ -2627,6 +2629,7 @@ void collecTemplateContents(BeanArchiveIndexBuildItem index, List<CheckedTemplat
26272629
.path(getCheckedTemplatePath(index.getIndex(), checkedTemplateAnnotation, fragmentId, target)
26282630
+ suffix)
26292631
.extensionInfo(target.toString())
2632+
.source(getSource(target, TemplateContents.class))
26302633
.build());
26312634
continue;
26322635
}
@@ -2651,6 +2654,13 @@ void collecTemplateContents(BeanArchiveIndexBuildItem index, List<CheckedTemplat
26512654
}
26522655
}
26532656

2657+
private URI getSource(ClassInfo target, Class<?> annotationClass) {
2658+
return JavaElementUriBuilder
2659+
.builder(target.toString())
2660+
.setAnnotation(annotationClass.getName())
2661+
.build();
2662+
}
2663+
26542664
@BuildStep
26552665
@Record(value = STATIC_INIT)
26562666
void initialize(BuildProducer<SyntheticBeanBuildItem> syntheticBeans, QuteRecorder recorder,

extensions/qute/runtime/src/main/java/io/quarkus/qute/runtime/EngineProducer.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -380,7 +380,7 @@ private Optional<TemplateLocation> locate(String path) {
380380
LOGGER.debugf("Locate template contents for %s", path);
381381
TemplateInfo template = templates.get(path);
382382
if (template != null && template.hasContent()) {
383-
return getTemplateLocation(template.content, path);
383+
return getTemplateLocation(template, path);
384384
}
385385

386386
// Try path with suffixes
@@ -391,7 +391,7 @@ private Optional<TemplateLocation> locate(String path) {
391391
}
392392
template = templates.get(pathWithSuffix);
393393
if (template != null && template.hasContent()) {
394-
return getTemplateLocation(template.content, pathWithSuffix);
394+
return getTemplateLocation(template, pathWithSuffix);
395395
}
396396
}
397397

@@ -421,8 +421,10 @@ private Optional<TemplateLocation> locate(String path) {
421421
return Optional.empty();
422422
}
423423

424-
private Optional<TemplateLocation> getTemplateLocation(String content, String pathWithSuffix) {
425-
return Optional.of(new StringTemplateLocation(content, Optional.ofNullable(createVariant(pathWithSuffix))));
424+
private Optional<TemplateLocation> getTemplateLocation(TemplateInfo templateInfo, String pathWithSuffix) {
425+
String content = templateInfo.content;
426+
URI source = templateInfo.parseSource();
427+
return Optional.of(new StringTemplateLocation(content, Optional.ofNullable(createVariant(pathWithSuffix)), source));
426428
}
427429

428430
private Optional<TemplateLocation> getTemplateLocation(URL resource, String templatePath, String path) {
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package io.quarkus.qute;
2+
3+
import java.net.URI;
4+
5+
public class JavaElementUriBuilder {
6+
7+
public static final String QUTE_JAVA_SCHEME = "qute-java";
8+
public static final String QUTE_JAVA_URI_PREFIX = QUTE_JAVA_SCHEME + "://";
9+
10+
private final String typeName;
11+
12+
private String method;
13+
14+
private String annotation;
15+
16+
private JavaElementUriBuilder(String typeName) {
17+
this.typeName = typeName;
18+
}
19+
20+
public String getTypeName() {
21+
return typeName;
22+
}
23+
24+
public String getMethod() {
25+
return method;
26+
}
27+
28+
public JavaElementUriBuilder setMethod(String method) {
29+
this.method = method;
30+
return this;
31+
}
32+
33+
public String getAnnotation() {
34+
return annotation;
35+
}
36+
37+
public JavaElementUriBuilder setAnnotation(String annotation) {
38+
this.annotation = annotation;
39+
return this;
40+
}
41+
42+
public static JavaElementUriBuilder builder(String typeName) {
43+
return new JavaElementUriBuilder(typeName);
44+
}
45+
46+
public URI build() {
47+
StringBuilder uri = new StringBuilder(QUTE_JAVA_URI_PREFIX);
48+
uri.append(typeName);
49+
if (method != null) {
50+
uri.append("#");
51+
uri.append(method);
52+
}
53+
if (annotation != null) {
54+
uri.append("@");
55+
uri.append(annotation);
56+
}
57+
return URI.create(uri.toString());
58+
}
59+
60+
public static boolean isJavaUri(URI uri) {
61+
return uri != null && QUTE_JAVA_SCHEME.equals(uri.getScheme());
62+
}
63+
64+
public static boolean isJavaUri(String uri) {
65+
return uri != null && uri.startsWith(QUTE_JAVA_URI_PREFIX);
66+
}
67+
}

independent-projects/qute/core/src/main/java/io/quarkus/qute/StringTemplateLocation.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package io.quarkus.qute;
22

33
import java.io.Reader;
4+
import java.net.URI;
45
import java.util.Objects;
56
import java.util.Optional;
67

@@ -11,14 +12,20 @@ public class StringTemplateLocation implements TemplateLocation {
1112

1213
private final String content;
1314
private final Optional<Variant> variant;
15+
private final URI source;
1416

1517
public StringTemplateLocation(String content) {
1618
this(content, Optional.empty());
1719
}
1820

1921
public StringTemplateLocation(String content, Optional<Variant> variant) {
22+
this(content, variant, null);
23+
}
24+
25+
public StringTemplateLocation(String content, Optional<Variant> variant, URI source) {
2026
this.content = Objects.requireNonNull(content);
2127
this.variant = Objects.requireNonNull(variant);
28+
this.source = source;
2229
}
2330

2431
@Override
@@ -31,4 +38,12 @@ public Optional<Variant> getVariant() {
3138
return variant;
3239
}
3340

41+
@Override
42+
public Optional<URI> getSource() {
43+
if (source != null) {
44+
return Optional.of(source);
45+
}
46+
return Optional.empty();
47+
}
48+
3449
}

independent-projects/qute/debug/src/main/java/io/quarkus/qute/debug/Debugger.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,12 @@
1515
import org.eclipse.lsp4j.debug.Thread;
1616
import org.eclipse.lsp4j.debug.Variable;
1717

18+
import io.quarkus.qute.debug.client.JavaSourceResolver;
19+
1820
/**
1921
* Qute debugger API.
2022
*/
21-
public interface Debugger {
23+
public interface Debugger extends JavaSourceResolver {
2224

2325
/**
2426
* Returns the current state of the remote debugger for a given thread.

independent-projects/qute/debug/src/main/java/io/quarkus/qute/debug/adapter/DebugServerAdapter.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import io.quarkus.qute.debug.StoppedEvent;
4949
import io.quarkus.qute.debug.ThreadEvent;
5050
import io.quarkus.qute.debug.agent.DebuggeeAgent;
51+
import io.quarkus.qute.debug.client.JavaSourceResolver;
5152

5253
/**
5354
* Debug Adapter Protocol (DAP) server implementation for Qute debugging.
@@ -130,6 +131,9 @@ public CompletableFuture<Capabilities> initialize(InitializeRequestArguments arg
130131
public void connect(IDebugProtocolClient client) {
131132
this.client = client;
132133
this.agent.setEnabled(true);
134+
if (client instanceof JavaSourceResolver javaFileInfoProvider) {
135+
((DebuggeeAgent) agent).setJavaSourceResolver(javaFileInfoProvider);
136+
}
133137
}
134138

135139
/**

independent-projects/qute/debug/src/main/java/io/quarkus/qute/debug/adapter/RegisterDebugServerAdapter.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@
1010
import java.util.concurrent.Future;
1111
import java.util.concurrent.TimeUnit;
1212

13-
import org.eclipse.lsp4j.debug.launch.DSPLauncher;
14-
import org.eclipse.lsp4j.debug.services.IDebugProtocolClient;
1513
import org.eclipse.lsp4j.jsonrpc.Launcher;
14+
import org.eclipse.lsp4j.jsonrpc.debug.DebugLauncher;
1615

1716
import io.quarkus.qute.Engine;
1817
import io.quarkus.qute.EngineBuilder.EngineListener;
1918
import io.quarkus.qute.debug.agent.DebuggeeAgent;
19+
import io.quarkus.qute.debug.client.QuteDebugProtocolClient;
2020
import io.quarkus.qute.trace.TemplateEvent;
2121
import io.quarkus.qute.trace.TraceListener;
2222

@@ -279,8 +279,8 @@ private void setupLauncher(Socket client, boolean suspend) throws IOException {
279279
launcherFuture.cancel(true);
280280
}
281281

282-
Launcher<IDebugProtocolClient> launcher = DSPLauncher.createServerLauncher(server, client.getInputStream(),
283-
client.getOutputStream(), executor, null);
282+
Launcher<QuteDebugProtocolClient> launcher = DebugLauncher.createLauncher(server, QuteDebugProtocolClient.class,
283+
client.getInputStream(), client.getOutputStream(), executor, null);
284284

285285
var clientProxy = launcher.getRemoteProxy();
286286
server.connect(clientProxy);

independent-projects/qute/debug/src/main/java/io/quarkus/qute/debug/agent/DebuggeeAgent.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
import io.quarkus.qute.debug.agent.source.SourceReferenceRegistry;
4242
import io.quarkus.qute.debug.agent.source.SourceTemplateRegistry;
4343
import io.quarkus.qute.debug.agent.variables.VariablesRegistry;
44+
import io.quarkus.qute.debug.client.JavaSourceResolver;
45+
import io.quarkus.qute.debug.client.JavaSourceLocationArguments;
46+
import io.quarkus.qute.debug.client.JavaSourceLocationResponse;
4447
import io.quarkus.qute.trace.ResolveEvent;
4548
import io.quarkus.qute.trace.TemplateEvent;
4649

@@ -103,6 +106,8 @@ public class DebuggeeAgent implements Debugger {
103106
/** Indicates whether the debugging agent is enabled. */
104107
private boolean enabled;
105108

109+
private JavaSourceResolver javaSourceResolver;
110+
106111
/**
107112
* Creates a new {@link DebuggeeAgent} instance.
108113
*/
@@ -472,7 +477,11 @@ public VariablesRegistry getVariablesRegistry() {
472477

473478
public SourceTemplateRegistry getSourceTemplateRegistry(Engine engine) {
474479
return this.sourceTemplateRegistry.computeIfAbsent(engine,
475-
k -> new SourceTemplateRegistry(breakpointsRegistry, sourceReferenceRegistry, engine));
480+
k -> new SourceTemplateRegistry(breakpointsRegistry, sourceReferenceRegistry, this, engine));
481+
}
482+
483+
public void setJavaSourceResolver(JavaSourceResolver javaSourceResolver) {
484+
this.javaSourceResolver = javaSourceResolver;
476485
}
477486

478487
@Override
@@ -516,4 +525,12 @@ public void reset() {
516525
this.sourceTemplateRegistry.clear();
517526
this.sourceReferenceRegistry.reset();
518527
}
528+
529+
@Override
530+
public CompletableFuture<JavaSourceLocationResponse> resolveJavaSource(JavaSourceLocationArguments params) {
531+
if (javaSourceResolver != null) {
532+
return javaSourceResolver.resolveJavaSource(params);
533+
}
534+
return CompletableFuture.completedFuture(null);
535+
}
519536
}

independent-projects/qute/debug/src/main/java/io/quarkus/qute/debug/agent/frames/RemoteStackFrame.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,11 @@ public RemoteStackFrame(ResolveEvent event, RemoteStackFrame previousFrame,
8787
int line = event.getTemplateNode().getOrigin().getLine();
8888
super.setId(id);
8989
super.setName(event.getTemplateNode().toString());
90-
super.setLine(line);
9190

9291
this.templateId = event.getTemplateNode().getOrigin().getTemplateId();
9392
super.setSource(
9493
sourceTemplateRegistry.getSource(templateId, previousFrame != null ? previousFrame.getSource() : null));
94+
super.setLine(line + (getSource() != null ? getSource().getStartLine() : 0));
9595
}
9696

9797
/** @return the template ID associated with this frame */

independent-projects/qute/debug/src/main/java/io/quarkus/qute/debug/agent/source/FileSource.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,18 @@
2121
*/
2222
public class FileSource extends RemoteSource {
2323

24+
public FileSource(URI uri, String templateId) {
25+
this(uri, templateId, 0);
26+
}
27+
2428
/**
2529
* Creates a new {@link FileSource} for a Qute template located on the local filesystem.
2630
*
2731
* @param uri the URI of the template file (must use the {@code file:} scheme)
2832
* @param templateId the Qute template identifier
2933
*/
30-
public FileSource(URI uri, String templateId) {
31-
super(uri, templateId);
34+
protected FileSource(URI uri, String templateId, int startLine) {
35+
super(uri, templateId, startLine);
3236

3337
// Initialize the DAP "path" field so the client can open the file.
3438
try {

0 commit comments

Comments
 (0)