~damien/jedit-lsp

900a9b1b36553da80ec6fefc82fc09e4a751bda1 — Damien Radtke 3 months ago b6dd43a
Move ProjectViewer integration to separate class
M LSP.props => LSP.props +1 -1
@@ 74,7 74,7 @@ lsp.server.jdtls.install=dir = lsp.Utils.getPluginSubdir("jdtls"); \
                         eclipseDownload(view, "jdtls", "1.23.0", dir); \
                         new File(dir, "bin/jdtls").setExecutable(true);
lsp.server.jdtls.root-files=build.xml pom.xml settings.gradle settings.gradle.kts - build.gradle build.gradle.kts
lsp.server.jdtls.hook.pre-init=initOptions = new HashMap(); params.setInitializationOptions(initOptions);
lsp.server.jdtls.hook.pre-init=initOptions = new HashMap(); initOptions.put("settings", settings.getAll()); params.setInitializationOptions(initOptions);

# Map a mode to the language server to use
mode.go.languageServer=gopls

M lsp/Capabilities.java => lsp/Capabilities.java +12 -0
@@ 1,14 1,20 @@
package lsp;

import java.util.Arrays;
import org.eclipse.lsp4j.ClientCapabilities;
import org.eclipse.lsp4j.DidChangeWatchedFilesCapabilities;
import org.eclipse.lsp4j.WorkspaceClientCapabilities;
import org.eclipse.lsp4j.WorkspaceEditCapabilities;
import org.eclipse.lsp4j.CodeActionCapabilities;
import org.eclipse.lsp4j.TextDocumentClientCapabilities;
import org.eclipse.lsp4j.WindowClientCapabilities;
import org.eclipse.lsp4j.FileOperationsWorkspaceCapabilities;

public class Capabilities {
	public static ClientCapabilities get() {
		return new ClientCapabilities(getWorkspace(), getDocument(), getWindow(), null);
	}

	public static WorkspaceClientCapabilities getWorkspace() {
		WorkspaceClientCapabilities workspaceClient = new WorkspaceClientCapabilities();



@@ 40,4 46,10 @@ public class Capabilities {

		return document;
	}

	public static WindowClientCapabilities getWindow() {
		WindowClientCapabilities window = new WindowClientCapabilities();
		window.setWorkDoneProgress(false);
		return window;
	}
}

M lsp/ErrorSource.java => lsp/ErrorSource.java +3 -3
@@ 5,7 5,7 @@ public class ErrorSource extends errorlist.DefaultErrorSource {
		super("LSP: " + server.getName(), null);
	}

	public void removeErrors(String uri) {
	public void removeErrorsForURI(String uri) {
		String path = lsp.Error.getErrorPath(uri);
		super.removeFileErrors(path);
	}


@@ 14,9 14,9 @@ public class ErrorSource extends errorlist.DefaultErrorSource {
	// all the errors getting removed from the ErrorList panel.
	// Removing the errors explicitly seems to do a better job here.
	@Override
	public void clear() {
	public synchronized void clear() {
		for (String path : errors.keySet()) {
			removeErrors(path);
			removeErrorsForURI(path);
		}
	}
}

A lsp/ProjectUpdater.java => lsp/ProjectUpdater.java +60 -0
@@ 0,0 1,60 @@
package lsp;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Paths;

import org.gjt.sp.jedit.jEdit;
import org.gjt.sp.util.Log;

public class ProjectUpdater {
	public static boolean hasProjectViewer() {
		return jEdit.getPlugin("projectviewer.ProjectPlugin") != null;
	}

	// NOTE: This doesn't seem to refresh the ProjectViewer interface.
	// Running AutoReimporter.runNow() does, but that seems heavy-handed.
	public static void addToProjects(boolean isDir, String uri) {
		if (!hasProjectViewer()) {
			return;
		}
		Log.log(Log.DEBUG, ProjectUpdater.class, "Adding to projects: " + uri);
		try {
			for (projectviewer.vpt.VPTProject project : projectviewer.ProjectManager.getInstance().getProjects()) {
				project = projectviewer.ProjectManager.getInstance().getProject(project.getName()); // ensure it's loaded
				if (Paths.get(new URI(uri).getPath()).startsWith(Paths.get(project.getRootPath()))) {
					if (isDir) {
						Log.log(Log.DEBUG, ProjectUpdater.class, "Registering new directory in " + project + ": " + uri);
						project.registerNodePath(new projectviewer.vpt.VPTDirectory(uri));
					} else {
						Log.log(Log.DEBUG, ProjectUpdater.class, "Registering new file in " + project + ": " + uri);
						project.registerNodePath(new projectviewer.vpt.VPTFile(uri));
					}
					// NOTE: For some reason, the call to project.registerNodePath() causes the plugin to
					// fail loading due to a NoClassDefFound error if we try to make ProjectViewer an
					// optional dependency.
				} else {
					Log.log(Log.WARNING, ProjectUpdater.class, "URI " + uri + " does not start with " + project.getRootPath());
				}
			}
		} catch (URISyntaxException e) {
			Log.log(Log.ERROR, ProjectUpdater.class, e);
		}
	}

	public static void addToProjects(String uri) {
		addToProjects(uri.endsWith("/"), uri);
	}

	public static void removeFromProjects(String uri) {
		if (!hasProjectViewer()) {
			return;
		}
		Log.log(Log.DEBUG, ProjectUpdater.class, "Removing from projects: " + uri);
		for (projectviewer.vpt.VPTProject project : projectviewer.ProjectManager.getInstance().getProjects()) {
			project = projectviewer.ProjectManager.getInstance().getProject(project.getName()); // ensure it's loaded
			Log.log(Log.DEBUG, ProjectUpdater.class, "Removing path from " + project + ": " + uri);
			project.unregisterNodePath(uri);
		}
	}
}

M lsp/Server.java => lsp/Server.java +8 -6
@@ 11,6 11,8 @@ import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import java.io.IOException;
import java.net.URI;
import java.net.URL;


@@ 39,7 41,6 @@ import javax.swing.event.HyperlinkListener;
import org.commonmark.node.Node;
import org.commonmark.parser.Parser;
import org.commonmark.renderer.html.HtmlRenderer;
import org.eclipse.lsp4j.ClientCapabilities;
import org.eclipse.lsp4j.ClientInfo;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionContext;


@@ 264,8 265,7 @@ public class Server {
	private void initialize(Buffer buffer) throws UtilEvalError {
		InitializeParams params = new InitializeParams();
		params.setProcessId((int) ProcessHandle.current().pid());
		//params.setInitializationOptions(initOptions);
		params.setCapabilities(new ClientCapabilities(Capabilities.getWorkspace(), Capabilities.getDocument(), null));
		params.setCapabilities(Capabilities.get());
		params.setClientInfo(new ClientInfo("jEdit", jEdit.getVersion()));

		List<String> roots = this.findWorkspaceFolders(buffer);


@@ 282,11 282,14 @@ public class Server {
		}
		// params.setLocale(...);

		Settings settings = Settings.get(this.workspaceFolders);

		String hookPreInit = this.serverDefinition.getHookPreInit();
		if (hookPreInit != null && !hookPreInit.equals("")) {
			log(Log.NOTICE, "Running pre-initialization hook: " + hookPreInit);
			NameSpace ns = new NameSpace(BeanShell.getNameSpace(), "LSP " + this.getName() + ": pre-init");
			ns.setVariable("params", params);
			ns.setVariable("settings", settings);
			try {
				BeanShell._eval(jEdit.getActiveView(), ns, hookPreInit);
			} catch (Exception e) {


@@ 306,7 309,7 @@ public class Server {
				log(Log.DEBUG, "Initialization response: " + result.toString());
				this.handle.getRemoteProxy().initialized(new InitializedParams());
				this.initResult = result;
				sendConfiguration();
				//sendConfiguration(settings);
				Synchronization.didOpenAll(this);
				Utils.showTemporaryMessage("Server ready");
			} catch (Exception e) {


@@ 316,9 319,8 @@ public class Server {
		}));
	}

	private void sendConfiguration() {
	private void sendConfiguration(Settings settings) {
		try {
			Settings settings = Settings.get(this.workspaceFolders);
			DidChangeConfigurationParams params = new DidChangeConfigurationParams(settings.getAll());
			log(Log.DEBUG, "Initializing with configuration: " + settings.getAll().toString());
			this.handle.getRemoteProxy().getWorkspaceService().didChangeConfiguration(params);

M lsp/ServerDefinition.java => lsp/ServerDefinition.java +1 -0
@@ 74,6 74,7 @@ public class ServerDefinition implements Comparable<ServerDefinition> {
	public String[] getCommand() {
		String command = this.rawCommand;
		command = command.replace("${PLUGIN_HOME}", LanguageServerPlugin.get().getPluginHome().getAbsolutePath());
		command = command.replace("${HOME}", System.getProperty("user.home"));
		return Utils.parseCommand(command);
	}


M lsp/jEditLanguageClient.java => lsp/jEditLanguageClient.java +5 -52
@@ 118,7 118,7 @@ public class jEditLanguageClient implements LanguageClient {
		}

		synchronized (this.errorSource) {
			this.errorSource.removeErrors(uri);
			this.errorSource.removeErrorsForURI(uri);
			if (jEdit.getBooleanProperty("lsp.general.errorListDiagnostics")) {
				// Ignore diagnostics for nonexistent URIs.
				// jdt.ls will sometimes send warnings about files within its workspace, but they don't actually exist.


@@ 657,7 657,7 @@ public class jEditLanguageClient implements LanguageClient {
				jEdit.closeBuffer(view, buffer);
			}

			addToProjects(isDir, create.getUri());
			ProjectUpdater.addToProjects(isDir, create.getUri());

			return true;
		} finally {


@@ 707,8 707,8 @@ public class jEditLanguageClient implements LanguageClient {
				jEdit.openFile(view, rename.getNewUri());
			}

			removeFromProjects(rename.getOldUri());
			addToProjects(rename.getNewUri());
			ProjectUpdater.removeFromProjects(rename.getOldUri());
			ProjectUpdater.addToProjects(rename.getNewUri());

			return true;
		} finally {


@@ 749,58 749,11 @@ public class jEditLanguageClient implements LanguageClient {
				}
			}
			vfs._delete(vfsSession, path, view);
			removeFromProjects(delete.getUri());
			ProjectUpdater.removeFromProjects(delete.getUri());
			return true;
		} finally {
			vfs._endVFSSession(vfsSession, view);
		}
	}

	// NOTE: This doesn't seem to refresh the ProjectViewer interface.
	// Running AutoReimporter.runNow() does, but that seems heavy-handed.
	private void addToProjects(boolean isDir, String uri) {
		if (jEdit.getPlugin("projectviewer.ProjectPlugin") == null) {
			return;
		}
		Log.log(Log.DEBUG, this, "Adding to projects: " + uri);
		try {
			for (projectviewer.vpt.VPTProject project : projectviewer.ProjectManager.getInstance().getProjects()) {
				project = projectviewer.ProjectManager.getInstance().getProject(project.getName()); // ensure it's loaded
				if (Paths.get(new URI(uri).getPath()).startsWith(Paths.get(project.getRootPath()))) {
					projectviewer.vpt.VPTNode node = null;
					if (isDir) {
						Log.log(Log.DEBUG, this, "Registering new directory in " + project + ": " + uri);
						node = new projectviewer.vpt.VPTDirectory(uri);
					} else {
						Log.log(Log.DEBUG, this, "Registering new file in " + project + ": " + uri);
						node = new projectviewer.vpt.VPTFile(uri);
					}
					// NOTE: For some reason, the call to project.registerNodePath() causes the plugin to
					// fail loading due to a NoClassDefFound error if we try to make ProjectViewer an
					// optional dependency.
					project.registerNodePath(node);
				} else {
					Log.log(Log.WARNING, this, "URI " + uri + " does not start with " + project.getRootPath());
				}
			}
		} catch (URISyntaxException e) {
			Log.log(Log.ERROR, this, e);
		}
	}

	private void addToProjects(String uri) {
		addToProjects(uri.endsWith("/"), uri);
	}

	private void removeFromProjects(String uri) {
		if (jEdit.getPlugin("projectviewer.ProjectPlugin") == null) {
			return;
		}
		Log.log(Log.DEBUG, this, "Removing from projects: " + uri);
		for (projectviewer.vpt.VPTProject project : projectviewer.ProjectManager.getInstance().getProjects()) {
			project = projectviewer.ProjectManager.getInstance().getProject(project.getName()); // ensure it's loaded
			Log.log(Log.DEBUG, this, "Removing path from " + project + ": " + uri);
			project.unregisterNodePath(uri);
		}
	}
}