Skip to content

Commit

Permalink
Merge pull request #32667 from vespa-engine/interns/magnus/servicesxml
Browse files Browse the repository at this point in the history
Interns/magnus/servicesxml
  • Loading branch information
Mangern authored Oct 25, 2024
2 parents 217825f + 0cc4427 commit 69afb4d
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 28 deletions.
61 changes: 40 additions & 21 deletions integration/schema-language-server/clients/vscode/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -144,33 +144,52 @@ export function activate(context: vscode.ExtensionContext) {
})));


context.subscriptions.push(vscode.commands.registerCommand("vespaSchemaLS.servicesxml.findDocument", async (fileName) => {
if (schemaClient !== null) {
try {
const result = await schemaClient.sendRequest("workspace/executeCommand", {
command: "FIND_SCHEMA_DEFINITION",
arguments: [fileName]
});
return result;
} catch (err) {
logger.error("Error when sending command: ", err);
}
context.subscriptions.push(vscode.commands.registerCommand("vespaSchemaLS.commands.findSchemaDefinition", async (fileName) => {
if (schemaClient === null) {
return null;
}
try {
const result = await schemaClient.sendRequest("workspace/executeCommand", {
command: "FIND_SCHEMA_DEFINITION",
arguments: [fileName]
});
return result;
} catch (err) {
logger.error("Error when sending command: ", err);
}
return null;
}));

// This command exists to setup schema language server workspace in case the first opened document is an xml file (which not handled by schema language server)
context.subscriptions.push(vscode.commands.registerCommand("vespaSchemaLS.servicesxml.setupWorkspace", async (fileURI) => {
if (schemaClient !== null) {
try {
schemaClient.sendRequest("workspace/executeCommand", {
command: "SETUP_WORKSPACE",
arguments: [fileURI]
});
} catch (err) {
logger.error("Error when trying to send setup workspace command: ", err);
}
context.subscriptions.push(vscode.commands.registerCommand("vespaSchemaLS.commands.setupWorkspace", async (fileURI) => {
if (schemaClient === null) {
return;
}
try {
schemaClient.sendRequest("workspace/executeCommand", {
command: "SETUP_WORKSPACE",
arguments: [fileURI]
});
} catch (err) {
logger.error("Error when trying to send setup workspace command: ", err);
}
}));

context.subscriptions.push(vscode.commands.registerCommand("vespaSchemaLS.commands.hasSetupWorkspace", async () => {
if (schemaClient === null) {
return false;
}

try {
const result: boolean = await schemaClient.sendRequest("workspace/executeCommand", {
command: "HAS_SETUP_WORKSPACE",
arguments: []
});
return result;
} catch (err) {
logger.error("Error when sending command: ", err);
}
return false;
}));

logger.info("Vespa language client activated");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import ai.vespa.schemals.lsp.common.command.commandtypes.FindDocument;
import ai.vespa.schemals.lsp.common.command.commandtypes.SchemaCommand;
import ai.vespa.schemals.lsp.common.command.commandtypes.SetupWorkspace;
import ai.vespa.schemals.lsp.common.command.commandtypes.HasSetupWorkspace;

/**
* SchemaCommand
Expand Down Expand Up @@ -89,6 +90,18 @@ public enum CommandType implements GenericCommandType {
public String title() { return "Find schema document"; }
public SchemaCommand construct() { return new FindDocument(); }
},
HAS_SETUP_WORKSPACE {
/*
* Ask if the language server has setup a workspace directory yet.
*
* Parameters:
*
* Return value:
* boolean
*/
public String title() { return "Has setup workspace"; }
public SchemaCommand construct() { return new HasSetupWorkspace(); }
},
SETUP_WORKSPACE {
/*
* Set the workspace directory and parse *sd files within. If it is already set up, nothing will happen.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ai.vespa.schemals.lsp.common.command.commandtypes;

import java.util.List;

import ai.vespa.schemals.context.EventExecuteCommandContext;

public class HasSetupWorkspace implements SchemaCommand {

@Override
public int getArity() {
return 0;
}

@Override
public boolean setArguments(List<Object> arguments) {
assert arguments.size() == getArity();
return true;
}

@Override
public Object execute(EventExecuteCommandContext context) {
return Boolean.valueOf(context.scheduler.getWorkspaceURI() != null);
}
}
5 changes: 5 additions & 0 deletions integration/schema-language-server/lemminx-vespa/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
<version>0.28.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.yahoo.vespa</groupId>
<artifactId>config-model</artifactId>
<version>8-SNAPSHOT</version>
</dependency>
</dependencies>
<repositories>
<repository>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import java.util.List;
import java.util.logging.Logger;

import org.eclipse.lemminx.dom.DOMAttr;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.dom.DOMElement;
import org.eclipse.lemminx.dom.DOMNode;
Expand All @@ -14,23 +15,49 @@
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.w3c.dom.Node;

public class DiagnosticsParticipant implements IDiagnosticsParticipant {
private static final Logger logger = Logger.getLogger(DiagnosticsParticipant.class.getName());

private static final String DIAGNOSTIC_SOURCE = "LemMinX Vespa Extension";
private record DiagnosticsContext(DOMDocument xmlDocument, List<Diagnostic> diagnostics, boolean hasSetupWorkspace) {}

@Override
public void doDiagnostics(DOMDocument xmlDocument, List<Diagnostic> diagnostics,
XMLValidationSettings validationSettings, CancelChecker cancelChecker) {
traverse(xmlDocument, xmlDocument.getDocumentElement(), diagnostics);
DiagnosticsContext context = new DiagnosticsContext(xmlDocument, diagnostics, SchemaLSCommands.instance().hasSetupWorkspace());
traverse(xmlDocument.getDocumentElement(), context);
}

private void traverse(DOMDocument xmlDocument, DOMNode node, List<Diagnostic> diagnostics) {
private void traverse(DOMNode node, DiagnosticsContext context) {
if (node instanceof DOMElement) {
DOMElement element = (DOMElement)node;
// Diagnostics here
if (context.hasSetupWorkspace() && element.getTagName().equals("document")) {
validateDocumentElement(element, context);
}
}
for (DOMNode child : node.getChildren()) {
traverse(xmlDocument, child, diagnostics);
traverse(child, context);
}
}

private void validateDocumentElement(DOMElement element, DiagnosticsContext context) {
DOMAttr typeAttribute = element.getAttributeNode("type");
if (typeAttribute != null) {
String docName = typeAttribute.getValue();
Range range = XMLPositionUtility.createRange(typeAttribute.getStart(), typeAttribute.getEnd(), context.xmlDocument);

// TODO: (possibly) slow blocking call. Could be grouped
List<Location> locations = SchemaLSCommands.instance().findSchemaDefinition(docName);
if (locations.isEmpty()) {
context.diagnostics.add(new Diagnostic(
range,
"Document " + docName + " does not exist in the current application.",
DiagnosticSeverity.Warning,
DIAGNOSTIC_SOURCE
));
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,13 @@
public class SchemaLSCommands {
private static final Logger logger = Logger.getLogger(SchemaLSCommands.class.getName());
private IXMLCommandService commandService;
private Gson gson;

private static SchemaLSCommands INSTANCE;
private SchemaLSCommands() {}
private SchemaLSCommands(IXMLCommandService commandService) {
this.commandService = commandService;
this.gson = new Gson();
}

public static void init(IXMLCommandService commandService) {
Expand All @@ -33,7 +35,22 @@ public static SchemaLSCommands instance() {
}

public void sendSetupWorkspaceRequest(String fileURI) {
commandService.executeClientCommand(new ExecuteCommandParams("vespaSchemaLS.servicesxml.setupWorkspace", List.of(fileURI)));
commandService.executeClientCommand(new ExecuteCommandParams("vespaSchemaLS.commands.setupWorkspace", List.of(fileURI)));
}

public boolean hasSetupWorkspace() {
Object result = commandService.executeClientCommand(
new ExecuteCommandParams("vespaSchemaLS.commands.hasSetupWorkspace", List.of())).join();
if (result == null) return false;
try {
String json = gson.toJson(result);
Type booleanType = new TypeToken<Boolean>() {}.getType();
return gson.fromJson(json, booleanType);
} catch (Exception ex) {
logger.severe("Error when parsing json: " + ex.getMessage());
}

return false;
}

/**
Expand All @@ -42,11 +59,10 @@ public void sendSetupWorkspaceRequest(String fileURI) {
public List<Location> findSchemaDefinition(String schemaName) {
// run sync
Object findDocumentResult = commandService.executeClientCommand(
new ExecuteCommandParams("vespaSchemaLS.servicesxml.findDocument", List.of(schemaName))).join();
new ExecuteCommandParams("vespaSchemaLS.commands.findSchemaDefinition", List.of(schemaName))).join();

if (findDocumentResult == null) return List.of();
try {
Gson gson = new Gson();
String json = gson.toJson(findDocumentResult);
Type listOfLocationType = new TypeToken<List<Location>>() {}.getType();
return gson.fromJson(json, listOfLocationType);
Expand Down

0 comments on commit 69afb4d

Please sign in to comment.