From 8c3809bd47648307af68fcc14fbf971820ad294e Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 01:05:42 +0100 Subject: [PATCH 01/30] cleanup --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2ccc965..d266cf3 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,12 @@ You can also open this as a project in Intellij Idea. * [ ] Refactoring * [ ] List of quicklisp installed packages / ASDF packages * [ ] List of modified top level forms that are yet to be evaluated +* [ ] Actually make an IDE, ie just plugin with dependencies as one application, not a plugin ## License -This project is licensed under [Apache License v2](LICENSE.txt). \ No newline at end of file +This project is licensed under [Apache License v2](LICENSE.txt). + +### What does SLT even mean? + +SLT - Speech Language Therapy. Only cure for LISP! \ No newline at end of file From 51e65d94cc0ff5e6e7841ba9b95a107580ada8ef Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 13:01:04 +0100 Subject: [PATCH 02/30] rewrite of lisp environment - possibly new lisps supports, but not right now --- .../slt/plugin/SltCommonLispLanguage.java | 1 - .../slt/plugin/SltDocumentationProvider.java | 4 +- .../plugin/SltLispEnvironmentProvider.java | 177 ++++++++++++++++++ ...ava => SltLispEnvironmentSymbolCache.java} | 13 +- .../com/en_circle/slt/plugin/SltSBCL.java | 132 ------------- .../slt/plugin/actions/EvalActionBase.java | 10 +- .../slt/plugin/actions/EvalFile.java | 4 +- .../slt/plugin/actions/EvalRegionAction.java | 6 +- .../environment/SltLispEnvironment.java | 21 +++ .../environment/SltLispEnvironmentBase.java | 7 + .../SltLispEnvironmentConfiguration.java | 17 ++ .../SltLispEnvironmentProcess.java | 81 ++++++++ .../SltLispProcessInformation.java | 7 + .../environment/SltProcessException.java | 24 +++ .../SltProcessStreamGobbler.java} | 23 ++- .../environment/SltSBCLEnvironment.java | 111 +++++++++++ .../SltSBCLEnvironmentConfiguration.java} | 25 ++- .../annotators/SymbolAnnotator.java | 4 +- .../slt/plugin/lisp/LispParserUtil.java | 6 +- .../SltDirectNavigationProvider.java | 4 +- .../slt/plugin/references/SltReference.java | 4 +- .../settings/SltSettingsConfigurable.java | 6 +- .../slt/plugin/swank/SwankServer.java | 111 ----------- .../plugin/ui/PackageSelectorComponent.java | 9 +- .../en_circle/slt/plugin/ui/SltComponent.java | 4 +- .../slt/plugin/ui/SltCoreWindow.java | 47 +++-- .../slt/plugin/ui/SltGeneralLog.java | 4 +- .../plugin/ui/SltOutputHandlerComponent.java | 12 +- .../slt/plugin/ui/console/SltConsole.java | 11 +- .../slt/plugin/ui/debug/SltDebuggerImpl.java | 10 +- .../slt/plugin/ui/debug/SltDebuggers.java | 12 +- .../slt/plugin/ui/debug/SltFrameConsole.java | 4 +- .../slt/plugin/ui/debug/SltFrameInfo.java | 4 +- .../slt/templates/InitScriptTemplate.java | 19 -- .../resources/messages/SltBundle.properties | 8 +- src/test/java/SlimeTest.java | 12 +- src/test/java/SwankTest.java | 16 +- 37 files changed, 587 insertions(+), 383 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java rename src/main/java/com/en_circle/slt/plugin/{SltSBCLSymbolCache.java => SltLispEnvironmentSymbolCache.java} (95%) delete mode 100644 src/main/java/com/en_circle/slt/plugin/SltSBCL.java create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironment.java create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentBase.java create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentConfiguration.java create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentProcess.java create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/SltLispProcessInformation.java create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/SltProcessException.java rename src/main/java/com/en_circle/slt/plugin/{swank/SwankStreamController.java => environment/SltProcessStreamGobbler.java} (80%) create mode 100644 src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java rename src/main/java/com/en_circle/slt/plugin/{swank/SwankServerConfiguration.java => environment/SltSBCLEnvironmentConfiguration.java} (64%) delete mode 100644 src/main/java/com/en_circle/slt/plugin/swank/SwankServer.java delete mode 100644 src/main/java/com/en_circle/slt/templates/InitScriptTemplate.java diff --git a/src/main/java/com/en_circle/slt/plugin/SltCommonLispLanguage.java b/src/main/java/com/en_circle/slt/plugin/SltCommonLispLanguage.java index f6c7dfe..30fe23b 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltCommonLispLanguage.java +++ b/src/main/java/com/en_circle/slt/plugin/SltCommonLispLanguage.java @@ -1,6 +1,5 @@ package com.en_circle.slt.plugin; -import com.en_circle.slt.plugin.swank.SwankServer; import com.intellij.lang.Language; public class SltCommonLispLanguage extends Language { diff --git a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java index ddad593..0509013 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java @@ -17,7 +17,7 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider { String text = LispPsiImplUtil.getSExpressionHead(element); if (text != null) { String packageName = LispParserUtil.getPackage(element); - SymbolState state = SltSBCL.getInstance().refreshSymbolFromServer(packageName, text, element); + SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, text, element); switch (state.binding) { case NONE: return SltBundle.message("slt.documentation.types.symbol") + " " + text; @@ -43,7 +43,7 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider { if (element instanceof LispSymbol) { String text = element.getText(); String packageName = LispParserUtil.getPackage(element); - SymbolState state = SltSBCL.getInstance().refreshSymbolFromServer(packageName, text, element); + SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, text, element); return asHtml(state.documentation); } return null; diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java new file mode 100644 index 0000000..86a08e2 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java @@ -0,0 +1,177 @@ +package com.en_circle.slt.plugin; + +import com.en_circle.slt.plugin.environment.SltLispEnvironment; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltLispOutputChangedListener; +import com.en_circle.slt.plugin.environment.SltLispEnvironmentConfiguration; +import com.en_circle.slt.plugin.environment.SltProcessException; +import com.en_circle.slt.plugin.swank.SlimeListener; +import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; +import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankClient; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.Disposer; +import com.intellij.psi.PsiElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +public class SltLispEnvironmentProvider implements Disposable { + private static final Logger log = LoggerFactory.getLogger(SltLispEnvironmentProvider.class); + + private static final SltLispEnvironmentProvider INSTANCE = new SltLispEnvironmentProvider(); + + public static SltLispEnvironmentProvider getInstance() { + return INSTANCE; + } + + private Supplier environmentProvider; + private SltLispEnvironment environment; + private SltLispEnvironmentConfiguration.Builder configurationBuilder; + private SltLispEnvironmentConfiguration configuration; + + private SwankClient client; + private SlimeListener slimeListener; + private Project project; + private RequestResponseLogger logger; + private DebugInterface debugInterface; + private final List serverListeners = Collections.synchronizedList(new ArrayList<>()); + + public void start() throws Exception { + for (SBCLServerListener listener : serverListeners) { + listener.onPreStart(); + } + + if (configuration == null) { + configuration = configurationBuilder + .setListener((output, newData) -> { + for (SBCLServerListener listener : serverListeners) { + listener.onOutputChanged(output, newData); + } + }) + .build(); + } + environment = environmentProvider.get(); + environment.start(configuration); + + slimeListener = new SlimeListener(project, true, logger, debugInterface); + client = new SwankClient("127.0.0.1", SltState.getInstance().port, slimeListener); + + for (SBCLServerListener listener : serverListeners) { + listener.onPostStart(); + } + } + + public void setEnvironmentProvider(Supplier environmentProvider) { + this.environmentProvider = environmentProvider; + } + + public void setConfigurationBuilder(SltLispEnvironmentConfiguration.Builder configurationBuilder) { + this.configurationBuilder = configurationBuilder; + this.configuration = null; + } + + public void setRequestResponseLogger(RequestResponseLogger logger) { + this.logger = logger; + } + + public void setDebugInterface(DebugInterface debugInterface) { + this.debugInterface = debugInterface; + } + + public void sendToLisp(SlimeRequest request) throws Exception { + sendToLisp(request, true); + } + + public void sendToLisp(SlimeRequest request, boolean startServer) throws Exception { + if (startServer && environment == null || !environment.isActive()) { + start(); + } + if (environment == null || !environment.isActive()) { + if (!startServer) + return; // ignored + throw new SltProcessException("server offline"); + } + + if (slimeListener != null) { + slimeListener.call(request, client); + } + } + + public void stop() throws Exception { + for (SBCLServerListener listener : serverListeners) { + listener.onPreStop(); + } + try { + client.close(); + } finally { + SltLispEnvironmentSymbolCache.INSTANCE.clear(); + if (environment != null) { + environment.stop(); + environment = null; + } + } + + for (SBCLServerListener listener : serverListeners) { + listener.onPostStop(); + } + } + + public void addServerListener(SBCLServerListener listener) { + serverListeners.add(listener); + } + + public Project getProject() { + return project; + } + + public void setProject(Project project) { + Disposer.register(project, this); + this.project = project; + } + + public String getGlobalPackage() { + return "CL-USER"; + } + + public SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element) { + return SltLispEnvironmentSymbolCache.INSTANCE.refreshSymbolFromServer(packageName, symbolName, element); + } + + public boolean hasEventsSet() { + return logger != null; + } + + public boolean isLispEnvironmentActive() { + return environment != null && environment.isActive(); + } + + public SltLispEnvironment getEnvironment() { + return environment; + } + + @Override + public void dispose() { + try { + stop(); + } catch (Exception e) { + log.error(e.getMessage()); + log.debug(e.getMessage(), e); + } + } + + public interface SBCLServerListener extends SltLispOutputChangedListener { + + void onPreStart(); + void onPostStart(); + void onPreStop(); + void onPostStop(); + + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/SltSBCLSymbolCache.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java similarity index 95% rename from src/main/java/com/en_circle/slt/plugin/SltSBCLSymbolCache.java rename to src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java index 85ea7ca..4c54842 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltSBCLSymbolCache.java +++ b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java @@ -2,7 +2,6 @@ import com.en_circle.slt.plugin.SymbolState.SymbolBinding; import com.en_circle.slt.plugin.lisp.lisp.*; -import com.en_circle.slt.plugin.swank.SwankServer; import com.en_circle.slt.plugin.swank.components.SourceLocation; import com.en_circle.slt.plugin.swank.requests.SwankEvalAndGrab; import com.google.common.collect.Lists; @@ -17,9 +16,9 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -public class SltSBCLSymbolCache extends Thread { +public class SltLispEnvironmentSymbolCache extends Thread { - public static final SltSBCLSymbolCache INSTANCE = new SltSBCLSymbolCache(); + public static final SltLispEnvironmentSymbolCache INSTANCE = new SltLispEnvironmentSymbolCache(); static { INSTANCE.start(); } @@ -27,7 +26,7 @@ public class SltSBCLSymbolCache extends Thread { private final Map symbolInformation = Collections.synchronizedMap(new HashMap<>()); private final List symbolRefreshQueue = Collections.synchronizedList(new ArrayList<>()); - private SltSBCLSymbolCache() { + private SltLispEnvironmentSymbolCache() { setDaemon(true); setName("SBCL Symbol Cache Thread"); } @@ -36,7 +35,7 @@ private SltSBCLSymbolCache() { public void run() { while (true) { try { - if (SwankServer.INSTANCE.isActive()) { + if (SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()) { while (symbolRefreshQueue.isEmpty()) { Thread.sleep(1000); } @@ -130,11 +129,11 @@ private void refreshSymbolsBatched(List refreshStates) throws Excep refreshStates.stream().map(x -> x.name.toUpperCase() + " ").collect(Collectors.joining()) + ")"; request = StringUtils.replace(request, "\"", "\\\""); - SltSBCL.getInstance().sendToSbcl(SwankEvalAndGrab.eval( + SltLispEnvironmentProvider.getInstance().sendToLisp(SwankEvalAndGrab.eval( String.format( "(slt-core:analyze-symbols (slt-core:read-fix-packages \"%s\"))", request), - SltSBCL.getInstance().getGlobalPackage(), true, (result, stdout, parsed) -> { + SltLispEnvironmentProvider.getInstance().getGlobalPackage(), true, (result, stdout, parsed) -> { Set toRefresh = new HashSet<>(); if (parsed.size() == 1 && parsed.get(0).getType() == LispElementType.CONTAINER) { int ix = 0; diff --git a/src/main/java/com/en_circle/slt/plugin/SltSBCL.java b/src/main/java/com/en_circle/slt/plugin/SltSBCL.java deleted file mode 100644 index 7bcb19f..0000000 --- a/src/main/java/com/en_circle/slt/plugin/SltSBCL.java +++ /dev/null @@ -1,132 +0,0 @@ -package com.en_circle.slt.plugin; - -import com.en_circle.slt.plugin.swank.*; -import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; -import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; -import com.en_circle.slt.plugin.swank.SwankServer.SwankServerListener; -import com.intellij.openapi.project.Project; -import com.intellij.psi.PsiElement; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -public class SltSBCL { - - private static final SltSBCL currentState = new SltSBCL(); - - public static SltSBCL getInstance() { - return currentState; - } - - private SwankClient client; - private SlimeListener slimeListener; - private Project project; - private RequestResponseLogger logger; - private DebugInterface debugInterface; - private final List serverListeners = Collections.synchronizedList(new ArrayList<>()); - - public void start() throws Exception { - for (SBCLServerListener listener : serverListeners) { - listener.onPreStart(); - } - - SwankServerConfiguration c = new SwankServerConfiguration.Builder() - .setExecutable(SltState.getInstance().sbclExecutable) - .setPort(SltState.getInstance().port) - .setQuicklispStartScriptPath(SltState.getInstance().quicklispStartScript) - .setProjectDirectory(project.getBasePath()) - .setListener((output, newData) -> { - for (SBCLServerListener listener : serverListeners) { - listener.onOutputChanged(output, newData); - } - }) - .build(); - SwankServer.startSbcl(c); - - slimeListener = new SlimeListener(project, true, logger, debugInterface); - client = new SwankClient("127.0.0.1", SltState.getInstance().port, slimeListener); - - for (SBCLServerListener listener : serverListeners) { - listener.onPostStart(); - } - } - - public void setRequestResponseLogger(RequestResponseLogger logger) { - this.logger = logger; - } - - public void setDebugInterface(DebugInterface debugInterface) { - this.debugInterface = debugInterface; - } - - public void sendToSbcl(SlimeRequest request) throws Exception { - sendToSbcl(request, true); - } - - public void sendToSbcl(SlimeRequest request, boolean startServer) throws Exception { - if (startServer && !SwankServer.INSTANCE.isActive()) { - start(); - } - if (!SwankServer.INSTANCE.isActive()) { - if (!startServer) - return; // ignored - throw new IOException("server offline"); - } - - if (slimeListener != null) { - slimeListener.call(request, client); - } - } - - public void stop() throws Exception { - for (SBCLServerListener listener : serverListeners) { - listener.onPreStop(); - } - try { - client.close(); - } finally { - SltSBCLSymbolCache.INSTANCE.clear(); - SwankServer.stop(); - } - - for (SBCLServerListener listener : serverListeners) { - listener.onPostStop(); - } - } - - public void addServerListener(SBCLServerListener listener) { - serverListeners.add(listener); - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - this.project = project; - } - - public String getGlobalPackage() { - return "cl-user"; - } - - public SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element) { - return SltSBCLSymbolCache.INSTANCE.refreshSymbolFromServer(packageName, symbolName, element); - } - - public boolean hasEventsSet() { - return logger != null; - } - - public interface SBCLServerListener extends SwankServerListener { - - void onPreStart(); - void onPostStart(); - void onPreStop(); - void onPostStop(); - - } - -} diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java index 5f0dfc2..e8c0b75 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java @@ -2,7 +2,7 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltCommonLispFileType; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.swank.requests.LoadFile; import com.en_circle.slt.plugin.swank.requests.SltEval; import com.en_circle.slt.plugin.swank.requests.SwankEvalFromVirtualFile; @@ -31,14 +31,14 @@ public void update(@NotNull AnActionEvent event) { if (editor != null && event.getProject() != null) { PsiFile file = PsiDocumentManager.getInstance(Objects.requireNonNull(editor.getProject())).getPsiFile(editor.getDocument()); if (file != null && SltCommonLispFileType.INSTANCE.equals(file.getFileType())) { - event.getPresentation().setEnabledAndVisible(SltSBCL.getInstance().hasEventsSet()); + event.getPresentation().setEnabledAndVisible(SltLispEnvironmentProvider.getInstance().hasEventsSet()); } } } protected void evaluate(Project project, String buffer, String packageName, Runnable callback) { try { - SltSBCL.getInstance().sendToSbcl(SltEval.eval(buffer, packageName, result -> callback.run()), true); + SltLispEnvironmentProvider.getInstance().sendToLisp(SltEval.eval(buffer, packageName, result -> callback.run()), true); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); @@ -47,7 +47,7 @@ protected void evaluate(Project project, String buffer, String packageName, Runn protected void evaluateRegion(Project project, String buffer, String packageName, String filename, int bufferPosition, int lineno, int charno, Runnable callback) { try { - SltSBCL.getInstance().sendToSbcl(SwankEvalFromVirtualFile + SltLispEnvironmentProvider.getInstance().sendToLisp(SwankEvalFromVirtualFile .eval(buffer, filename, bufferPosition, lineno, charno, packageName, result -> callback.run()), true); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -57,7 +57,7 @@ protected void evaluateRegion(Project project, String buffer, String packageName protected void evaluateFile(Project project, String filename) { try { - SltSBCL.getInstance().sendToSbcl(LoadFile.loadFile(filename), true); + SltLispEnvironmentProvider.getInstance().sendToLisp(LoadFile.loadFile(filename), true); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java index e63602d..c543b29 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java @@ -2,7 +2,7 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltCommonLispFileType; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -35,7 +35,7 @@ public void update(@NotNull AnActionEvent event) { VirtualFile vf = event.getData(CommonDataKeys.VIRTUAL_FILE); if (vf != null) { if (vf.getFileType().equals(SltCommonLispFileType.INSTANCE)) { - event.getPresentation().setEnabledAndVisible(SltSBCL.getInstance().hasEventsSet()); + event.getPresentation().setEnabledAndVisible(SltLispEnvironmentProvider.getInstance().hasEventsSet()); } } } diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalRegionAction.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalRegionAction.java index ada83ba..6758b12 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalRegionAction.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalRegionAction.java @@ -1,7 +1,7 @@ package com.en_circle.slt.plugin.actions; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -59,7 +59,7 @@ public void actionPerformed(@NotNull AnActionEvent event) { int offset = editor.getSelectionModel().getSelectionStart(); evaluate(editor.getProject(), selectedText, LispParserUtil.getPackage(psiFile, offset), () -> { }); } else { - evaluate(editor.getProject(), selectedText, SltSBCL.getInstance().getGlobalPackage(), () -> { }); + evaluate(editor.getProject(), selectedText, SltLispEnvironmentProvider.getInstance().getGlobalPackage(), () -> { }); } } } @@ -84,7 +84,7 @@ private void evalEachCaret(Editor editor, String filename, List carets) { PsiDocumentManager psiMgr = PsiDocumentManager.getInstance(Objects.requireNonNull(editor.getProject())); psiMgr.commitDocument(editor.getDocument()); PsiFile psiFile = psiMgr.getPsiFile(editor.getDocument()); - String packageName = SltSBCL.getInstance().getGlobalPackage(); + String packageName = SltLispEnvironmentProvider.getInstance().getGlobalPackage(); if (psiFile != null) { packageName = LispParserUtil.getPackage(psiFile, offset); } diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironment.java b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironment.java new file mode 100644 index 0000000..9da6ada --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironment.java @@ -0,0 +1,21 @@ +package com.en_circle.slt.plugin.environment; + +public interface SltLispEnvironment { + + void start(SltLispEnvironmentConfiguration configuration) throws SltProcessException; + void stop() throws SltProcessException; + + boolean isActive(); + SltLispProcessInformation getInformation(); + + interface SltLispOutputChangedListener { + + void onOutputChanged(SltOutput output, String newData); + + } + + enum SltOutput { + STDOUT, STDERR + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentBase.java b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentBase.java new file mode 100644 index 0000000..345d283 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentBase.java @@ -0,0 +1,7 @@ +package com.en_circle.slt.plugin.environment; + +public abstract class SltLispEnvironmentBase implements SltLispEnvironment { + + + +} diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentConfiguration.java b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentConfiguration.java new file mode 100644 index 0000000..8764b5e --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentConfiguration.java @@ -0,0 +1,17 @@ +package com.en_circle.slt.plugin.environment; + +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltLispOutputChangedListener; + +public interface SltLispEnvironmentConfiguration { + + SltLispOutputChangedListener getListener(); + + interface Builder, RESULT extends SltLispEnvironmentConfiguration> { + + Builder setListener(SltLispOutputChangedListener listener); + + RESULT build(); + + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentProcess.java b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentProcess.java new file mode 100644 index 0000000..364fa9b --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentProcess.java @@ -0,0 +1,81 @@ +package com.en_circle.slt.plugin.environment; + +import com.en_circle.slt.plugin.environment.SltProcessStreamGobbler.ProcessInitializationWaiter; +import com.intellij.openapi.application.ApplicationManager; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +public abstract class SltLispEnvironmentProcess extends SltLispEnvironmentBase { + + protected Process process; + protected SltProcessStreamGobbler errorController; + protected SltProcessStreamGobbler outputController; + protected List listeners = new ArrayList<>(); + + protected abstract Object prepareProcessEnvironment(SltLispEnvironmentProcessConfiguration configuration) throws SltProcessException; + protected abstract File getProcessWorkDirectory(SltLispEnvironmentProcessConfiguration configuration, Object environment) throws SltProcessException; + protected abstract String[] getProcessCommand(SltLispEnvironmentProcessConfiguration configuration, Object environment) throws SltProcessException; + protected abstract ProcessInitializationWaiter waitForFullInitialization(SltLispEnvironmentProcessConfiguration configuration, Object environment) throws SltProcessException; + + @Override + public boolean isActive() { + return process != null && process.isAlive(); + } + + public void start(SltLispEnvironmentConfiguration configuration) throws SltProcessException { + if (process != null) + return; + if (!(configuration instanceof SltLispEnvironmentProcessConfiguration)) + throw new SltProcessException("Configuration incorrect"); + SltLispEnvironmentProcessConfiguration processConfiguration = (SltLispEnvironmentProcessConfiguration) + configuration; + + try { + Object environment = prepareProcessEnvironment(processConfiguration); + + ProcessBuilder pb = new ProcessBuilder(getProcessCommand(processConfiguration, environment)); + pb.directory(getProcessWorkDirectory(processConfiguration, environment)); + process = pb.start(); + + errorController = new SltProcessStreamGobbler(process.getErrorStream()); + outputController = new SltProcessStreamGobbler(process.getInputStream()); + + ProcessInitializationWaiter waiter = waitForFullInitialization(processConfiguration, environment); + + SltLispOutputChangedListener listener = processConfiguration.getListener(); + if (listener != null) { + if (ApplicationManager.getApplication() != null) { + errorController.addUpdateListener(data -> + ApplicationManager.getApplication().invokeLater(() -> listener.onOutputChanged(SltOutput.STDERR, data))); + outputController.addUpdateListener(data -> + ApplicationManager.getApplication().invokeLater(() -> listener.onOutputChanged(SltOutput.STDOUT, data))); + } else { + errorController.addUpdateListener(data -> listener.onOutputChanged(SltOutput.STDERR, data)); + outputController.addUpdateListener(data -> listener.onOutputChanged(SltOutput.STDOUT, data)); + } + } + + errorController.start(); + outputController.start(); + + waiter.awaitFor(process); + } catch (SltProcessException e) { + throw e; + } catch (Exception e) { + throw new SltProcessException(e); + } + } + public void stop() throws SltProcessException { + if (process != null) { + process.destroy(); + process = null; + } + } + + public interface SltLispEnvironmentProcessConfiguration extends SltLispEnvironmentConfiguration { + + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltLispProcessInformation.java b/src/main/java/com/en_circle/slt/plugin/environment/SltLispProcessInformation.java new file mode 100644 index 0000000..a93f037 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltLispProcessInformation.java @@ -0,0 +1,7 @@ +package com.en_circle.slt.plugin.environment; + +public interface SltLispProcessInformation { + + String getPid(); + +} diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltProcessException.java b/src/main/java/com/en_circle/slt/plugin/environment/SltProcessException.java new file mode 100644 index 0000000..25d2a64 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltProcessException.java @@ -0,0 +1,24 @@ +package com.en_circle.slt.plugin.environment; + +public class SltProcessException extends Exception { + + public SltProcessException() { + } + + public SltProcessException(String message) { + super(message); + } + + public SltProcessException(String message, Throwable cause) { + super(message, cause); + } + + public SltProcessException(Throwable cause) { + super(cause); + } + + public SltProcessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankStreamController.java b/src/main/java/com/en_circle/slt/plugin/environment/SltProcessStreamGobbler.java similarity index 80% rename from src/main/java/com/en_circle/slt/plugin/swank/SwankStreamController.java rename to src/main/java/com/en_circle/slt/plugin/environment/SltProcessStreamGobbler.java index 0e27488..7d6d5cf 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankStreamController.java +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltProcessStreamGobbler.java @@ -1,4 +1,4 @@ -package com.en_circle.slt.plugin.swank; +package com.en_circle.slt.plugin.environment; import org.awaitility.Awaitility; import org.awaitility.pollinterval.FixedPollInterval; @@ -11,18 +11,18 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; -public class SwankStreamController extends Thread { +public class SltProcessStreamGobbler extends Thread { private final InputStream inputStream; - private final List updateListeners = Collections.synchronizedList(new ArrayList<>()); + private final List updateListeners = Collections.synchronizedList(new ArrayList<>()); - public SwankStreamController(InputStream inputStream) { + public SltProcessStreamGobbler(InputStream inputStream) { this.inputStream = inputStream; - setName("SwanStreamController reader " + inputStream); + setName("SltProcessStreamGobbler " + inputStream); setDaemon(true); } - public void addUpdateListener(SwankStreamControllerUpdateListener listener) { + public void addUpdateListener(SltProcessStreamControllerUpdateListener listener) { updateListeners.add(listener); } @@ -43,7 +43,7 @@ public void run() { if (readSize > 0) { String data = new String(buffer, 0, readSize, StandardCharsets.UTF_8); - for (SwankStreamControllerUpdateListener listener : updateListeners) { + for (SltProcessStreamControllerUpdateListener listener : updateListeners) { listener.onDataRead(data); } } @@ -53,13 +53,18 @@ public void run() { } } - public interface SwankStreamControllerUpdateListener { + public interface SltProcessStreamControllerUpdateListener { void onDataRead(String data); } - public static class WaitForOccurrence implements SwankStreamControllerUpdateListener { + public interface ProcessInitializationWaiter { + boolean awaitFor(Process process); + + } + + public static class WaitForOccurrence implements ProcessInitializationWaiter, SltProcessStreamControllerUpdateListener { private final String occurrence; private final String[] occurrenceStrings; diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java new file mode 100644 index 0000000..294aad1 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java @@ -0,0 +1,111 @@ +package com.en_circle.slt.plugin.environment; + +import com.en_circle.slt.plugin.environment.SltProcessStreamGobbler.ProcessInitializationWaiter; +import com.en_circle.slt.plugin.environment.SltProcessStreamGobbler.WaitForOccurrence; +import com.en_circle.slt.templates.SltScriptTemplate; +import org.apache.commons.io.FileUtils; +import org.watertemplate.Template; + +import java.io.File; +import java.nio.charset.StandardCharsets; + +public class SltSBCLEnvironment extends SltLispEnvironmentProcess { + + @Override + public SltLispProcessInformation getInformation() { + return new SltSBCLLispProcessInformation(); + } + + @Override + protected Object prepareProcessEnvironment(SltLispEnvironmentProcessConfiguration configuration) throws SltProcessException { + SltSBCLEnvironmentConfiguration c = getConfiguration(configuration); + SBCLEnvironment e = new SBCLEnvironment(); + try { + e.sltCore = File.createTempFile("slt", ".cl"); + e.sltCore.deleteOnExit(); + String sltScriptTemplate = new SltScriptTemplate().render(); + FileUtils.write(e.sltCore, sltScriptTemplate, StandardCharsets.UTF_8); + + e.serverStartSetup = File.createTempFile("startServer", ".cl"); + e.serverStartSetup.deleteOnExit(); + String startScriptTemplate = new SBCLInitScriptTemplate(c, e.sltCore.getAbsolutePath()).render(); + FileUtils.write(e.serverStartSetup, startScriptTemplate, StandardCharsets.UTF_8); + } catch (Exception ex) { + throw new SltProcessException(ex); + } + return e; + } + + @Override + protected File getProcessWorkDirectory(SltLispEnvironmentProcessConfiguration configuration, Object environment) throws SltProcessException { + SltSBCLEnvironmentConfiguration c = getConfiguration(configuration); + SBCLEnvironment e = getEnvironment(environment); + + return e.serverStartSetup.getParentFile(); + } + + @Override + protected String[] getProcessCommand(SltLispEnvironmentProcessConfiguration configuration, Object environment) throws SltProcessException { + SltSBCLEnvironmentConfiguration c = getConfiguration(configuration); + SBCLEnvironment e = getEnvironment(environment); + + return new String[]{ + c.getExecutablePath(), + "--load", + e.serverStartSetup.getName() + }; + } + + @Override + protected ProcessInitializationWaiter waitForFullInitialization(SltLispEnvironmentProcessConfiguration configuration, Object environment) throws SltProcessException { + SltSBCLEnvironmentConfiguration c = getConfiguration(configuration); + SBCLEnvironment e = getEnvironment(environment); + + WaitForOccurrence wait = new WaitForOccurrence("Swank started at port"); + errorController.addUpdateListener(wait); + + return wait; + } + + private SltSBCLEnvironmentConfiguration getConfiguration(SltLispEnvironmentProcessConfiguration configuration) throws SltProcessException { + if (!(configuration instanceof SltSBCLEnvironmentConfiguration)) + throw new SltProcessException("Configuration must be SltSBCLEnvironmentConfiguration"); + return (SltSBCLEnvironmentConfiguration) configuration; + } + + private SBCLEnvironment getEnvironment(Object environment) { + assert (environment instanceof SBCLEnvironment); + + return (SBCLEnvironment) environment; + } + + private class SltSBCLLispProcessInformation implements SltLispProcessInformation { + + @Override + public String getPid() { + return "" + process.pid(); + } + } + + private static class SBCLEnvironment { + + File sltCore; + File serverStartSetup; + + } + + private static class SBCLInitScriptTemplate extends Template { + + public SBCLInitScriptTemplate(SltSBCLEnvironmentConfiguration configuration, String sltCoreScript) { + add("qlpath", configuration.getQuicklispStartScript()); + add("port", "" + configuration.getPort()); + add("cwd", configuration.getProjectDirectory()); + add("sbclcorefile", sltCoreScript); + } + + @Override + protected String getFilePath() { + return "initscript.cl"; + } + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankServerConfiguration.java b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironmentConfiguration.java similarity index 64% rename from src/main/java/com/en_circle/slt/plugin/swank/SwankServerConfiguration.java rename to src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironmentConfiguration.java index 5fe6200..32baf87 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankServerConfiguration.java +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironmentConfiguration.java @@ -1,16 +1,18 @@ -package com.en_circle.slt.plugin.swank; +package com.en_circle.slt.plugin.environment; -import com.en_circle.slt.plugin.swank.SwankServer.SwankServerListener; -public class SwankServerConfiguration { +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltLispOutputChangedListener; +import com.en_circle.slt.plugin.environment.SltLispEnvironmentProcess.SltLispEnvironmentProcessConfiguration; + +public class SltSBCLEnvironmentConfiguration implements SltLispEnvironmentProcessConfiguration { private String executablePath = "sbcl"; private String quicklispStartScript = "~/quicklisp/setup.lisp"; private int port = 4005; private String projectDirectory = "/tmp"; - private SwankServerListener listener = null; + private SltLispOutputChangedListener listener = null; - private SwankServerConfiguration() { + private SltSBCLEnvironmentConfiguration() { } @@ -30,13 +32,14 @@ public String getProjectDirectory() { return projectDirectory; } - public SwankServerListener getListener() { + @Override + public SltLispOutputChangedListener getListener() { return listener; } - public static class Builder { + public static class Builder implements SltLispEnvironmentConfiguration.Builder { - private final SwankServerConfiguration c = new SwankServerConfiguration(); + private final SltSBCLEnvironmentConfiguration c = new SltSBCLEnvironmentConfiguration(); private boolean built = false; public Builder setExecutable(String executable) { @@ -68,14 +71,16 @@ public Builder setProjectDirectory(String projectDirectory) { return this; } - public Builder setListener(SwankServerListener listener) { + @Override + public Builder setListener(SltLispOutputChangedListener listener) { checkNotBuilt(); c.listener = listener; return this; } - public SwankServerConfiguration build() { + @Override + public SltSBCLEnvironmentConfiguration build() { checkNotBuilt(); built = true; return c; diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java index ed899f2..e30698e 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java @@ -1,6 +1,6 @@ package com.en_circle.slt.plugin.highlights.annotators; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SymbolState; import com.en_circle.slt.plugin.highlights.CommonLispHighlighterColors; import com.en_circle.slt.plugin.lisp.LispParserUtil; @@ -17,7 +17,7 @@ public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder hold if (element instanceof LispSymbol) { String text = element.getText(); String packageName = LispParserUtil.getPackage(element); - SymbolState state = SltSBCL.getInstance().refreshSymbolFromServer(packageName, text, element); + SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, text, element); setHighlight(element, text, holder, state); } } diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java b/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java index 8046686..57d93a5 100644 --- a/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java +++ b/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java @@ -1,6 +1,6 @@ package com.en_circle.slt.plugin.lisp; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.lisp.lisp.LispUtils; import com.en_circle.slt.plugin.lisp.psi.*; import com.intellij.lang.ASTNode; @@ -19,7 +19,7 @@ public static String getPackage(PsiFile psiFile, int offset) { if (locationNode != null) return getPackage(locationNode.getPsi()); else - return SltSBCL.getInstance().getGlobalPackage(); + return SltLispEnvironmentProvider.getInstance().getGlobalPackage(); } public static String getPackage(PsiElement element) { @@ -38,7 +38,7 @@ public static String getPackage(PsiElement element) { previous = previous.getPrevSibling(); } - return SltSBCL.getInstance().getGlobalPackage(); + return SltLispEnvironmentProvider.getInstance().getGlobalPackage(); } private static LispList isLispList(PsiElement form) { diff --git a/src/main/java/com/en_circle/slt/plugin/references/SltDirectNavigationProvider.java b/src/main/java/com/en_circle/slt/plugin/references/SltDirectNavigationProvider.java index a0719bd..b80a8e1 100644 --- a/src/main/java/com/en_circle/slt/plugin/references/SltDirectNavigationProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/references/SltDirectNavigationProvider.java @@ -1,6 +1,6 @@ package com.en_circle.slt.plugin.references; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SymbolState; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; @@ -27,7 +27,7 @@ public class SltDirectNavigationProvider implements DirectNavigationProvider { String packageName = LispParserUtil.getPackage(element); Project project = element.getProject(); String symbolName = ((LispSymbol) element).getName(); - SymbolState state = SltSBCL.getInstance().refreshSymbolFromServer(packageName, symbolName, element); + SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, symbolName, element); SourceLocation location = state.location; if (location.isFile()) { VirtualFile vf = LocalFileSystem.getInstance().findFileByIoFile(new File(location.getLocation())); diff --git a/src/main/java/com/en_circle/slt/plugin/references/SltReference.java b/src/main/java/com/en_circle/slt/plugin/references/SltReference.java index 550a1b6..8061f63 100644 --- a/src/main/java/com/en_circle/slt/plugin/references/SltReference.java +++ b/src/main/java/com/en_circle/slt/plugin/references/SltReference.java @@ -1,6 +1,6 @@ package com.en_circle.slt.plugin.references; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SymbolState; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; @@ -26,7 +26,7 @@ public SltReference(@NotNull LispSymbol element) { public ResolveResult @NotNull [] multiResolve(boolean incompleteCode) { String symbolName = myElement.getName(); String packageName = LispParserUtil.getPackage(myElement); - SymbolState state = SltSBCL.getInstance().refreshSymbolFromServer(packageName, symbolName, myElement); + SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, symbolName, myElement); SourceLocation location = state.location; if (location.isFile()) { VirtualFile vf = LocalFileSystem.getInstance().findFileByIoFile(new File(location.getLocation())); diff --git a/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java b/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java index 8aaa2b0..3a273b9 100644 --- a/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java +++ b/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java @@ -1,7 +1,7 @@ package com.en_circle.slt.plugin.settings; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SltState; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; @@ -67,8 +67,8 @@ public void apply() throws ConfigurationException { SltBundle.message("slt.ui.settings.restart.no"), Messages.getQuestionIcon())) { try { - SltSBCL.getInstance().stop(); - SltSBCL.getInstance().start(); + SltLispEnvironmentProvider.getInstance().stop(); + SltLispEnvironmentProvider.getInstance().start(); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); Messages.showErrorDialog(ProjectManager.getInstance().getDefaultProject(), diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankServer.java b/src/main/java/com/en_circle/slt/plugin/swank/SwankServer.java deleted file mode 100644 index 0533e4f..0000000 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankServer.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.en_circle.slt.plugin.swank; - -import com.en_circle.slt.plugin.swank.SwankStreamController.WaitForOccurrence; -import com.en_circle.slt.templates.InitScriptTemplate; -import com.en_circle.slt.templates.SltScriptTemplate; -import com.intellij.openapi.application.ApplicationManager; -import org.apache.commons.io.FileUtils; - -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; - -public class SwankServer { - - public static SwankServer INSTANCE = new SwankServer(); - - private Process sbclProcess; - - public static void startSbcl(SwankServerConfiguration configuration) { - INSTANCE.start(configuration); - } - - public static void restart(SwankServerConfiguration configuration) { - INSTANCE.stopInstance(); - INSTANCE.start(configuration); - } - - public static void stop() { - INSTANCE.stopInstance(); - } - - public static Process getProcess() { - return INSTANCE.sbclProcess; - } - - private synchronized void stopInstance() { - if (sbclProcess != null) { - sbclProcess.destroy(); - sbclProcess = null; - } - } - - private synchronized void start(SwankServerConfiguration configuration) { - if (sbclProcess != null) - return; - - try { - File sltCore = File.createTempFile("slt", ".cl"); - sltCore.deleteOnExit(); - String sltScriptTemplate = new SltScriptTemplate().render(); - FileUtils.write(sltCore, sltScriptTemplate, StandardCharsets.UTF_8); - - File serverStartSetup = File.createTempFile("startServer", ".cl"); - serverStartSetup.deleteOnExit(); - String startScriptTemplate = new InitScriptTemplate(configuration, sltCore.getAbsolutePath()).render(); - FileUtils.write(serverStartSetup, startScriptTemplate, StandardCharsets.UTF_8); - - String[] commands = new String[]{ - configuration.getExecutablePath(), - "--load", - serverStartSetup.getName() - }; - ProcessBuilder pb = new ProcessBuilder(commands); - pb.directory(serverStartSetup.getParentFile()); - sbclProcess = pb.start(); - - SwankStreamController errorController = new SwankStreamController(sbclProcess.getErrorStream()); - SwankStreamController outputController = new SwankStreamController(sbclProcess.getInputStream()); - - WaitForOccurrence wait = new WaitForOccurrence("Swank started at port"); - errorController.addUpdateListener(wait); - - SwankServerListener listener = configuration.getListener(); - if (listener != null) { - if (ApplicationManager.getApplication() != null) { - errorController.addUpdateListener(data -> - ApplicationManager.getApplication().invokeLater(() -> listener.onOutputChanged(SwankServerOutput.STDERR, data))); - outputController.addUpdateListener(data -> - ApplicationManager.getApplication().invokeLater(() -> listener.onOutputChanged(SwankServerOutput.STDOUT, data))); - } else { - errorController.addUpdateListener(data -> listener.onOutputChanged(SwankServerOutput.STDERR, data)); - outputController.addUpdateListener(data -> listener.onOutputChanged(SwankServerOutput.STDOUT, data)); - } - } - - errorController.start(); - outputController.start(); - - if (!wait.awaitFor(sbclProcess)) { - throw new IOException("Failed to start sbcl!"); - } - } catch (Exception e) { - throw new RuntimeException(e); - } - } - - public boolean isActive() { - return sbclProcess != null && sbclProcess.isAlive(); - } - - public interface SwankServerListener { - - void onOutputChanged(SwankServerOutput output, String newData); - - } - - public enum SwankServerOutput { - STDOUT, STDERR - } - -} diff --git a/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java b/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java index 1996a02..1614432 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java @@ -1,11 +1,10 @@ package com.en_circle.slt.plugin.ui; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.lisp.lisp.LispContainer; import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.lisp.lisp.LispString; -import com.en_circle.slt.plugin.swank.SwankServer; import com.en_circle.slt.plugin.swank.requests.SwankEvalAndGrab; import com.intellij.icons.AllIcons.Actions; import com.intellij.openapi.actionSystem.*; @@ -55,7 +54,7 @@ public ActionToolbar getActionToolbar() { public void refresh() { try { - SltSBCL.getInstance().sendToSbcl(SwankEvalAndGrab.eval("(slt-core:list-package-names)", true, (result, stdout, parsed) -> { + SltLispEnvironmentProvider.getInstance().sendToLisp(SwankEvalAndGrab.eval("(slt-core:list-package-names)", true, (result, stdout, parsed) -> { resolvePackages(parsed); }), false); } catch (Exception e) { @@ -114,7 +113,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SwankServer.INSTANCE.isActive()); + e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); } } @@ -134,7 +133,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SwankServer.INSTANCE.isActive()); + e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltComponent.java b/src/main/java/com/en_circle/slt/plugin/ui/SltComponent.java index 6af2c69..367e624 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltComponent.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltComponent.java @@ -1,6 +1,6 @@ package com.en_circle.slt.plugin.ui; -import com.en_circle.slt.plugin.swank.SwankServer.SwankServerOutput; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; import com.intellij.ui.tabs.TabInfo; public interface SltComponent { @@ -11,7 +11,7 @@ public interface SltComponent { void onPreStart(); void onPostStart(); - void handleOutput(SwankServerOutput output, String data); + void handleOutput(SltOutput output, String data); void onPreStop(); void onPostStop(); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java b/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java index 9ca06c5..ffbe9aa 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java @@ -2,10 +2,12 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltCommonLispFileType; -import com.en_circle.slt.plugin.SltSBCL; -import com.en_circle.slt.plugin.SltSBCL.SBCLServerListener; -import com.en_circle.slt.plugin.swank.SwankServer; -import com.en_circle.slt.plugin.swank.SwankServer.SwankServerOutput; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider.SBCLServerListener; +import com.en_circle.slt.plugin.SltState; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; +import com.en_circle.slt.plugin.environment.SltSBCLEnvironment; +import com.en_circle.slt.plugin.environment.SltSBCLEnvironmentConfiguration; import com.en_circle.slt.plugin.ui.console.SltConsole; import com.en_circle.slt.plugin.ui.console.SltREPL; import com.intellij.icons.AllIcons; @@ -44,15 +46,21 @@ public class SltCoreWindow implements SBCLServerListener { public SltCoreWindow(ToolWindow toolWindow) { this.project = toolWindow.getProject(); - SltSBCL.getInstance().addServerListener(this); - SltSBCL.getInstance().setProject(toolWindow.getProject()); + SltLispEnvironmentProvider.getInstance().setEnvironmentProvider(SltSBCLEnvironment::new); + SltLispEnvironmentProvider.getInstance().setConfigurationBuilder(new SltSBCLEnvironmentConfiguration.Builder() + .setExecutable(SltState.getInstance().sbclExecutable) + .setPort(SltState.getInstance().port) + .setQuicklispStartScriptPath(SltState.getInstance().quicklispStartScript) + .setProjectDirectory(project.getBasePath())); + SltLispEnvironmentProvider.getInstance().addServerListener(this); + SltLispEnvironmentProvider.getInstance().setProject(toolWindow.getProject()); content = new JPanel(new BorderLayout()); - components.add(new SltOutputHandlerComponent(this, SwankServerOutput.STDOUT)); - components.add(new SltOutputHandlerComponent(this, SwankServerOutput.STDERR)); + components.add(new SltOutputHandlerComponent(this, SltOutput.STDOUT)); + components.add(new SltOutputHandlerComponent(this, SltOutput.STDERR)); SltGeneralLog generalLog = new SltGeneralLog(); components.add(generalLog); - SltSBCL.getInstance().setRequestResponseLogger(generalLog); + SltLispEnvironmentProvider.getInstance().setRequestResponseLogger(generalLog); createSbclControls(); @@ -92,7 +100,7 @@ private void createSbclControls() { public void start() { try { - SltSBCL.getInstance().start(); + SltLispEnvironmentProvider.getInstance().start(); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); @@ -111,7 +119,7 @@ public void start() { public void stop() { try { - SltSBCL.getInstance().stop(); + SltLispEnvironmentProvider.getInstance().stop(); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstop"), e); Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.stop")); @@ -156,8 +164,7 @@ public void onPostStart() { component.onPostStart(); } - Process p = SwankServer.getProcess(); - process.setText("" + p.pid()); + process.setText(SltLispEnvironmentProvider.getInstance().getEnvironment().getInformation().getPid()); } @Override @@ -176,7 +183,7 @@ public void onPostStop() { } @Override - public void onOutputChanged(SwankServerOutput output, String newData) { + public void onOutputChanged(SltOutput output, String newData) { for (SltComponent component : components) { component.handleOutput(output, newData); } @@ -189,7 +196,7 @@ public Project getProject() { private class StartSbclAction extends AnAction { private StartSbclAction() { - super(SltBundle.message("slt.ui.process.startsbcl"), "", AllIcons.RunConfigurations.TestState.Run); + super(SltBundle.message("slt.ui.process.startinstance"), "", AllIcons.RunConfigurations.TestState.Run); } @Override @@ -201,14 +208,14 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(!SwankServer.INSTANCE.isActive()); + e.getPresentation().setEnabled(!SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); } } private class StopSbclAction extends AnAction { private StopSbclAction() { - super(SltBundle.message("slt.ui.process.stopsbcl"), "", AllIcons.Actions.Suspend); + super(SltBundle.message("slt.ui.process.stopinstance"), "", AllIcons.Actions.Suspend); } @Override @@ -220,14 +227,14 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SwankServer.INSTANCE.isActive()); + e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); } } private class ConsoleWindowAction extends AnAction { private ConsoleWindowAction() { - super(SltBundle.message("slt.ui.process.openrepl"), "", General.Add); + super(SltBundle.message("slt.ui.process.openrepl.sbcl"), "", General.Add); } @Override @@ -239,7 +246,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SwankServer.INSTANCE.isActive()); + e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java b/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java index 6413558..741411c 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltGeneralLog.java @@ -1,8 +1,8 @@ package com.en_circle.slt.plugin.ui; import com.en_circle.slt.plugin.SltBundle; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; -import com.en_circle.slt.plugin.swank.SwankServer.SwankServerOutput; import com.en_circle.slt.tools.BufferedString; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.*; @@ -110,7 +110,7 @@ public void onPostStart() { } @Override - public void handleOutput(SwankServerOutput output, String data) { + public void handleOutput(SltOutput output, String data) { } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltOutputHandlerComponent.java b/src/main/java/com/en_circle/slt/plugin/ui/SltOutputHandlerComponent.java index 8db8576..4ec8b73 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltOutputHandlerComponent.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltOutputHandlerComponent.java @@ -1,7 +1,7 @@ package com.en_circle.slt.plugin.ui; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.swank.SwankServer.SwankServerOutput; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; import com.intellij.icons.AllIcons; import com.intellij.openapi.actionSystem.*; import com.intellij.ui.components.JBScrollPane; @@ -15,17 +15,17 @@ public class SltOutputHandlerComponent implements SltComponent { - private final SwankServerOutput output; + private final SltOutput output; private final JPanel dataContainer; private JTextArea area; private TabInfo tabInfo; - public SltOutputHandlerComponent(SltCoreWindow coreWindow, SwankServerOutput output) { + public SltOutputHandlerComponent(SltCoreWindow coreWindow, SltOutput output) { this.output = output; this.dataContainer = new JPanel(new BorderLayout()); } - public SwankServerOutput getOutput() { + public SltOutput getOutput() { return output; } @@ -106,7 +106,7 @@ public void onPostStart() { } @Override - public void handleOutput(SwankServerOutput output, String data) { + public void handleOutput(SltOutput output, String data) { if (output == this.output) { area.setText(area.getText() + data); DefaultCaret caret = (DefaultCaret) area.getCaret(); @@ -127,7 +127,7 @@ public void onPostStop() { @Override public String getTitle() { - return getOutput() == SwankServerOutput.STDERR ? SltBundle.message("slt.ui.process.log.error.title") : + return getOutput() == SltOutput.STDERR ? SltBundle.message("slt.ui.process.log.error.title") : SltBundle.message("slt.ui.process.log.output.title"); } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java index 3b35daa..e41044a 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java @@ -2,9 +2,8 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltCommonLispLanguage; -import com.en_circle.slt.plugin.SltSBCL; -import com.en_circle.slt.plugin.swank.SwankServer; -import com.en_circle.slt.plugin.swank.SwankServer.SwankServerOutput; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; import com.en_circle.slt.plugin.swank.requests.SltEval; import com.en_circle.slt.plugin.ui.SltComponent; import com.intellij.execution.console.ConsoleExecuteAction; @@ -59,7 +58,7 @@ protected void execute(String code) { eval(code); } - }, languageConsoleView -> SwankServer.INSTANCE.isActive()); + }, languageConsoleView -> SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); action.registerCustomShortcutSet(action.getShortcutSet(), languageConsole.getConsoleEditor().getComponent()); new ConsoleHistoryController(new MyConsoleRootType("cl"), null, languageConsole).install(); @@ -73,7 +72,7 @@ protected void execute(String code) { protected void eval(String data) { try { if (StringUtils.isNotBlank(data)) { - SltSBCL.getInstance().sendToSbcl(SltEval.eval(data, currentModule, + SltLispEnvironmentProvider.getInstance().sendToLisp(SltEval.eval(data, currentModule, result -> languageConsole.print(result + "\n", ConsoleViewContentType.NORMAL_OUTPUT))); } } catch (Exception e) { @@ -98,7 +97,7 @@ public void onPostStart() { } @Override - public void handleOutput(SwankServerOutput output, String data) { + public void handleOutput(SltOutput output, String data) { } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java index 88a15d1..7839fba 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java @@ -1,7 +1,7 @@ package com.en_circle.slt.plugin.ui.debug; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SltUIConstants; import com.en_circle.slt.plugin.swank.debug.SltDebugAction; import com.en_circle.slt.plugin.swank.debug.SltDebugArgument; @@ -189,7 +189,7 @@ private void actionAccepted(SltDebugAction action, SltDebugInfo debugInfo) { int ix = debugInfo.getActions().indexOf(action); if (action.getArguments().isEmpty()) { try { - SltSBCL.getInstance().sendToSbcl(SltInvokeNthRestart.nthRestart(debugInfo.getThreadId(), + SltLispEnvironmentProvider.getInstance().sendToLisp(SltInvokeNthRestart.nthRestart(debugInfo.getThreadId(), BigInteger.valueOf(ix), debugInfo.getDebugLevel(), "NIL", "NIL", () -> {})); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -213,7 +213,7 @@ private void actionAccepted(SltDebugAction action, SltDebugInfo debugInfo) { } String args = arguments.size() == 0 ? "NIL" : "(" + String.join(" ", arguments) + ")"; try { - SltSBCL.getInstance().sendToSbcl(SltInvokeNthRestart.nthRestart(debugInfo.getThreadId(), + SltLispEnvironmentProvider.getInstance().sendToLisp(SltInvokeNthRestart.nthRestart(debugInfo.getThreadId(), BigInteger.valueOf(ix), debugInfo.getDebugLevel(), args, rest, () -> {})); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -252,7 +252,7 @@ private void stackframeClicked(SltDebugStackTraceElement element, SltDebugInfo d } } try { - SltSBCL.getInstance().sendToSbcl(SltFrameLocalsAndCatchTags.getLocals(BigInteger.valueOf(ix), + SltLispEnvironmentProvider.getInstance().sendToLisp(SltFrameLocalsAndCatchTags.getLocals(BigInteger.valueOf(ix), debugInfo.getThreadId(), result -> { ApplicationManager.getApplication().invokeLater(() -> { SltFrameInfo frameInfo = new SltFrameInfo(parent.getProject(), debugInfo.getThreadId(), BigInteger.valueOf(ix), @@ -270,7 +270,7 @@ private void stackframeClicked(SltDebugStackTraceElement element, SltDebugInfo d private void close() { try { - SltSBCL.getInstance().sendToSbcl(new ThrowToToplevel(lastDebugId)); + SltLispEnvironmentProvider.getInstance().sendToLisp(new ThrowToToplevel(lastDebugId)); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java index bf201d8..b160e60 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java @@ -1,9 +1,9 @@ package com.en_circle.slt.plugin.ui.debug; -import com.en_circle.slt.plugin.SltSBCL; -import com.en_circle.slt.plugin.SltSBCL.SBCLServerListener; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider.SBCLServerListener; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; -import com.en_circle.slt.plugin.swank.SwankServer.SwankServerOutput; import com.en_circle.slt.plugin.swank.debug.SltDebugInfo; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; @@ -32,8 +32,8 @@ public SltDebuggers(ToolWindow toolWindow) { this.tabs = new JBTabsImpl(toolWindow.getProject()); this.content.add(this.tabs.getComponent()); - SltSBCL.getInstance().addServerListener(this); - SltSBCL.getInstance().setDebugInterface(this); + SltLispEnvironmentProvider.getInstance().addServerListener(this); + SltLispEnvironmentProvider.getInstance().setDebugInterface(this); } public JPanel getContent() { @@ -106,7 +106,7 @@ public void onPostStop() { } @Override - public void onOutputChanged(SwankServerOutput output, String newData) { + public void onOutputChanged(SltOutput output, String newData) { } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java index ebe20ad..dbb4ad0 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java @@ -1,7 +1,7 @@ package com.en_circle.slt.plugin.ui.debug; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.swank.requests.EvalStringInFrameEval; import com.en_circle.slt.plugin.ui.console.SltConsole; import com.intellij.execution.ui.ConsoleViewContentType; @@ -32,7 +32,7 @@ public SltFrameConsole(Project project, BigInteger threadId, BigInteger frame, R protected void eval(String data) { try { if (StringUtils.isNotBlank(data)) { - SltSBCL.getInstance().sendToSbcl(EvalStringInFrameEval.evalInFrame(data, frame, threadId, currentModule, + SltLispEnvironmentProvider.getInstance().sendToLisp(EvalStringInFrameEval.evalInFrame(data, frame, threadId, currentModule, result -> { languageConsole.print(result + "\n", ConsoleViewContentType.NORMAL_OUTPUT); onChange.run(); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java index f9311fb..048211d 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java @@ -1,7 +1,7 @@ package com.en_circle.slt.plugin.ui.debug; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltSBCL; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.lisp.lisp.*; import com.en_circle.slt.plugin.swank.requests.SltFrameLocalsAndCatchTags; import com.intellij.openapi.application.ApplicationManager; @@ -61,7 +61,7 @@ private void create() { private void reloadLocals() { try { - SltSBCL.getInstance().sendToSbcl(SltFrameLocalsAndCatchTags.getLocals(frameId, threadId, result -> { + SltLispEnvironmentProvider.getInstance().sendToLisp(SltFrameLocalsAndCatchTags.getLocals(frameId, threadId, result -> { ApplicationManager.getApplication().invokeLater(() -> { refreshFrameValues(result); }); diff --git a/src/main/java/com/en_circle/slt/templates/InitScriptTemplate.java b/src/main/java/com/en_circle/slt/templates/InitScriptTemplate.java deleted file mode 100644 index a6cb931..0000000 --- a/src/main/java/com/en_circle/slt/templates/InitScriptTemplate.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.en_circle.slt.templates; - -import com.en_circle.slt.plugin.swank.SwankServerConfiguration; -import org.watertemplate.Template; - -public class InitScriptTemplate extends Template { - - public InitScriptTemplate(SwankServerConfiguration configuration, String sltCoreScript) { - add("qlpath", configuration.getQuicklispStartScript()); - add("port", "" + configuration.getPort()); - add("cwd", configuration.getProjectDirectory()); - add("sbclcorefile", sltCoreScript); - } - - @Override - protected String getFilePath() { - return "initscript.cl"; - } -} diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index 06f7f03..33570ee 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -35,10 +35,10 @@ slt.ui.colorsettings.reader=Reader macro # Process slt.ui.process.title=SBCL Process -slt.ui.process.processpid=SBCL Process Pid: -slt.ui.process.startsbcl=Start SBCL Instance -slt.ui.process.stopsbcl=Stop SBCL Instance -slt.ui.process.openrepl=Create SBCL REPL +slt.ui.process.processpid=Lisp Process Pid: +slt.ui.process.startinstance=Start Lisp Instance +slt.ui.process.stopinstance=Stop Lisp Instance +slt.ui.process.openrepl.sbcl=Create Lisp REPL slt.ui.process.gl.clear=Clear Text slt.ui.process.gl.wrap=Soft Wrap slt.ui.process.gl.scroll=Scroll to End diff --git a/src/test/java/SlimeTest.java b/src/test/java/SlimeTest.java index a3e90ce..e2634e0 100644 --- a/src/test/java/SlimeTest.java +++ b/src/test/java/SlimeTest.java @@ -1,5 +1,10 @@ -import com.en_circle.slt.plugin.swank.*; +import com.en_circle.slt.plugin.environment.SltLispEnvironment; +import com.en_circle.slt.plugin.environment.SltSBCLEnvironment; +import com.en_circle.slt.plugin.environment.SltSBCLEnvironmentConfiguration; +import com.en_circle.slt.plugin.swank.SlimeListener; import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; +import com.en_circle.slt.plugin.swank.SwankClient; +import com.en_circle.slt.plugin.swank.SwankPacket; import com.en_circle.slt.plugin.swank.debug.SltDebugInfo; import org.awaitility.Awaitility; @@ -13,7 +18,8 @@ public static void main(String[] args) throws Exception { try { AtomicLong sent = new AtomicLong(); AtomicLong expected = new AtomicLong(); - SwankServer.startSbcl(new SwankServerConfiguration.Builder().build()); + SltLispEnvironment environment = new SltSBCLEnvironment(); + environment.start(new SltSBCLEnvironmentConfiguration.Builder().build()); SlimeListener listener = new SlimeListener(null, false, null, new DebugInterface() { @Override public void onDebugCreate(SltDebugInfo info) { @@ -42,7 +48,7 @@ public void onDebugReturn(BigInteger debugId, BigInteger level) { .atMost(10, TimeUnit.SECONDS) .until(() -> expected.get() > sent.get() && sent.get() > 0); } - SwankServer.stop(); + environment.stop(); } catch (Exception e) { } diff --git a/src/test/java/SwankTest.java b/src/test/java/SwankTest.java index f2b64e2..45b6262 100644 --- a/src/test/java/SwankTest.java +++ b/src/test/java/SwankTest.java @@ -1,14 +1,15 @@ import com.en_circle.slt.plugin.SltCommonLispFileType; import com.en_circle.slt.plugin.SltCommonLispLanguage; import com.en_circle.slt.plugin.SltCommonLispParserDefinition; +import com.en_circle.slt.plugin.environment.SltLispEnvironment; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; +import com.en_circle.slt.plugin.environment.SltSBCLEnvironment; +import com.en_circle.slt.plugin.environment.SltSBCLEnvironmentConfiguration; import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.lisp.lisp.LispUtils; import com.en_circle.slt.plugin.lisp.psi.LispCoreProjectEnvironment; import com.en_circle.slt.plugin.swank.SwankClient; import com.en_circle.slt.plugin.swank.SwankPacket; -import com.en_circle.slt.plugin.swank.SwankServer; -import com.en_circle.slt.plugin.swank.SwankServer.SwankServerOutput; -import com.en_circle.slt.plugin.swank.SwankServerConfiguration; import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFileFactory; @@ -18,14 +19,15 @@ public class SwankTest { public static void main(String[] args) throws Exception { try { - SwankServerConfiguration c = new SwankServerConfiguration.Builder() + SltSBCLEnvironmentConfiguration c = new SltSBCLEnvironmentConfiguration.Builder() .setListener((output, newData) -> { - if (output == SwankServerOutput.STDERR) { + if (output == SltOutput.STDERR) { System.err.print(newData); } }) .build(); - SwankServer.startSbcl(c); + SltLispEnvironment environment = new SltSBCLEnvironment(); + environment.start(c); try (SwankClient client = new SwankClient("127.0.0.1", 4005, packet -> { LispCoreProjectEnvironment projectEnvironment = new LispCoreProjectEnvironment(); projectEnvironment.getEnvironment() @@ -50,7 +52,7 @@ public static void main(String[] args) throws Exception { Thread.sleep(10000); } - SwankServer.stop(); + environment.stop(); } catch (Exception e) { e.printStackTrace(); } From 36db2e453a376ab31bd7c1084b25ad4746c11d6b Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 13:13:32 +0100 Subject: [PATCH 03/30] version change for 0.2.0 development, forgot to do it --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index bd2d304..cff2132 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "com.en_circle.slt" -version = "0.1.0" +version = "0.2.0" repositories { mavenCentral() From 065c50c5b8bf61c1f2e886f5bc0be6e6d8452894 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 18:55:34 +0100 Subject: [PATCH 04/30] preparing for inspector --- .../slt/plugin/SltDocumentationProvider.java | 2 + .../plugin/SltLispEnvironmentSymbolCache.java | 4 ++ .../com/en_circle/slt/plugin/SymbolState.java | 2 +- .../environment/SltLispEnvironmentBase.java | 2 - .../CommonLispHighlighterColors.java | 1 + .../highlights/SltColorSettingsPage.java | 1 + .../annotators/SymbolAnnotator.java | 4 ++ .../slt/plugin/swank/SlimeListener.java | 12 ++-- .../slt/plugin/swank/SwankPacket.java | 12 ++++ .../requests/SltFrameLocalsAndCatchTags.java | 5 +- .../swank/requests/SltInspectFrameVar.java | 56 ++++++++++++++++++ .../slt/plugin/ui/debug/SltDebugger.java | 3 +- .../slt/plugin/ui/debug/SltDebuggerImpl.java | 12 ++-- .../slt/plugin/ui/debug/SltFrameInfo.java | 59 +++++++++++++++++++ .../slt/plugin/ui/debug/SltInspector.java | 19 ++++++ .../resources/messages/SltBundle.properties | 3 + src/main/resources/templates/en_US/slt.cl | 10 +++- 17 files changed, 188 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectFrameVar.java create mode 100644 src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java diff --git a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java index 0509013..f185cd2 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java @@ -33,6 +33,8 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider { return SltBundle.message("slt.documentation.types.specvariable") + " " + text; case KEYWORD: return SltBundle.message("slt.documentation.types.keyword") + " " + text; + case CLASS: + return SltBundle.message("slt.documentation.types.class") + " " + text; } } return null; diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java index 4c54842..4c7818d 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java +++ b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java @@ -153,6 +153,10 @@ private void refreshSymbolsBatched(List refreshStates) throws Excep boolean changed = false; state.timestamp = System.currentTimeMillis(); switch (symValue) { + case ":CLASS": + changed |= state.binding != SymbolBinding.CLASS; + state.binding = SymbolBinding.CLASS; + break; case ":SPECIAL-FORM": changed |= state.binding != SymbolBinding.SPECIAL_FORM; state.binding = SymbolBinding.SPECIAL_FORM; diff --git a/src/main/java/com/en_circle/slt/plugin/SymbolState.java b/src/main/java/com/en_circle/slt/plugin/SymbolState.java index d2ba2b2..c32920a 100644 --- a/src/main/java/com/en_circle/slt/plugin/SymbolState.java +++ b/src/main/java/com/en_circle/slt/plugin/SymbolState.java @@ -28,7 +28,7 @@ public SymbolState(String name, String packageName, String symbolName) { public enum SymbolBinding { NONE, FUNCTION, MACRO, SPECIAL_FORM, - CONSTANT, KEYWORD, SPECIAL_VARIABLE + CONSTANT, KEYWORD, SPECIAL_VARIABLE, CLASS } @Override diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentBase.java b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentBase.java index 345d283..4152fe5 100644 --- a/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentBase.java +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentBase.java @@ -2,6 +2,4 @@ public abstract class SltLispEnvironmentBase implements SltLispEnvironment { - - } diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java b/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java index 1824605..a746d59 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java @@ -21,6 +21,7 @@ public class CommonLispHighlighterColors { public static TextAttributesKey SPECIAL_FORM = TextAttributesKey.createTextAttributesKey("CL.SPECIAL_FORM", DefaultLanguageHighlighterColors.KEYWORD); public static TextAttributesKey FUNCTION = TextAttributesKey.createTextAttributesKey("CL.FUNCTION", DefaultLanguageHighlighterColors.FUNCTION_CALL); public static TextAttributesKey MACRO = TextAttributesKey.createTextAttributesKey("CL.MACRO", DefaultLanguageHighlighterColors.KEYWORD); + public static TextAttributesKey CLASS = TextAttributesKey.createTextAttributesKey("CL.CLASS", DefaultLanguageHighlighterColors.CLASS_NAME); public static void setHighlighting(PsiElement element, AnnotationHolder holder, TextAttributesKey key) { // Annotation a = holder.createInfoAnnotation(element, null); diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java index a2b8ac7..db3ed59 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java @@ -33,6 +33,7 @@ public class SltColorSettingsPage implements ColorSettingsPage { new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.function"), CommonLispHighlighterColors.FUNCTION), new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.macro"), CommonLispHighlighterColors.MACRO), new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.reader"), CommonLispHighlighterColors.SUGAR), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.class"), CommonLispHighlighterColors.CLASS), }; @Override diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java index e30698e..8b4e64d 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java @@ -30,6 +30,10 @@ private void setHighlight(PsiElement element, String name, AnnotationHolder hold switch (state.binding) { case NONE: break; + case CLASS: + CommonLispHighlighterColors.setHighlighting(element, holder, + CommonLispHighlighterColors.CLASS); + break; case FUNCTION: CommonLispHighlighterColors.setHighlighting(element, holder, CommonLispHighlighterColors.FUNCTION); diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java index 6c4677b..61e7e3e 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java @@ -6,10 +6,7 @@ import com.en_circle.slt.plugin.lisp.lisp.*; import com.en_circle.slt.plugin.lisp.psi.LispCoreProjectEnvironment; import com.en_circle.slt.plugin.swank.debug.SltDebugInfo; -import com.en_circle.slt.plugin.swank.requests.SltEval; -import com.en_circle.slt.plugin.swank.requests.SltFrameLocalsAndCatchTags; -import com.en_circle.slt.plugin.swank.requests.SltInvokeNthRestart; -import com.en_circle.slt.plugin.swank.requests.SwankEvalAndGrab; +import com.en_circle.slt.plugin.swank.requests.*; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; @@ -23,7 +20,7 @@ public class SlimeListener implements SwankClient.SwankReply { - private static BigInteger rpcIdentifier = new BigInteger("0"); + private static BigInteger rpcIdentifier = BigInteger.ZERO; public static synchronized BigInteger nextRpc() { BigInteger next = rpcIdentifier.add(BigInteger.ONE); @@ -145,6 +142,11 @@ private void processReturn(LispContainer reply) { SltFrameLocalsAndCatchTags frames = (SltFrameLocalsAndCatchTags) request; frames.processReply((LispContainer) reply.getItems().get(1)); } + + if (request instanceof SltInspectFrameVar) { + SltInspectFrameVar frames = (SltInspectFrameVar) request; + frames.processReply((LispContainer) reply.getItems().get(1)); + } } finally { requests.remove(replyId.getValue()); } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java index e174940..6355723 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java @@ -152,6 +152,18 @@ public static SwankPacket frameLocals(BigInteger frame, BigInteger threadId, Str return new SwankPacket(formatted); } + public static SwankPacket inspectLocal(BigInteger ix, BigInteger frameId, BigInteger threadId, BigInteger continuation) { + return inspectLocal(ix, frameId, threadId, "CL-USER", continuation); + } + + public static SwankPacket inspectLocal(BigInteger ix, BigInteger frameId, BigInteger threadId, String packageName, BigInteger continuation) { + packageName = StringUtils.replace(packageName, "\\", "\\\\"); + packageName = StringUtils.replace(packageName, "\"", "\\\""); + String formatted = String.format("(:emacs-rex (swank:inspect-frame-var %s %s) :%s %s %s)", + frameId, ix, packageName, threadId, continuation); + return new SwankPacket(formatted); + } + public static SwankPacket loadFile(String file, BigInteger continuation) { return loadFile(file, "CL-USER", continuation); } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltFrameLocalsAndCatchTags.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/SltFrameLocalsAndCatchTags.java index 4bbc169..e5b2586 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltFrameLocalsAndCatchTags.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/SltFrameLocalsAndCatchTags.java @@ -15,7 +15,7 @@ public static SlimeRequest getLocals(BigInteger frame, BigInteger threadId, Stri } public static SlimeRequest getLocals(BigInteger frame, BigInteger threadId, Callback callback) { - return new SltFrameLocalsAndCatchTags(frame, threadId, "cl-user", callback); + return new SltFrameLocalsAndCatchTags(frame, threadId, "CL-USER", callback); } protected final Callback callback; @@ -30,8 +30,7 @@ protected SltFrameLocalsAndCatchTags(BigInteger frame, BigInteger threadId, Stri this.threadId = threadId; } - public void processReply(LispContainer data - ) { + public void processReply(LispContainer data) { if (isOk(data)) { callback.onResult(data.getItems().get(1)); } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectFrameVar.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectFrameVar.java new file mode 100644 index 0000000..c55a862 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectFrameVar.java @@ -0,0 +1,56 @@ +package com.en_circle.slt.plugin.swank.requests; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.lisp.LispSymbol; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankPacket; + +import java.math.BigInteger; + +public class SltInspectFrameVar extends SlimeRequest { + + public static SlimeRequest inspectVariable(BigInteger ix, BigInteger frame, BigInteger threadId, String module, Callback callback) { + return new SltInspectFrameVar(ix, frame, threadId, module, callback); + } + + public static SlimeRequest inspectVariable(BigInteger ix, BigInteger frame, BigInteger threadId, Callback callback) { + return new SltInspectFrameVar(ix, frame, threadId, "CL-USER", callback); + } + + protected final Callback callback; + protected final String module; + protected final BigInteger ix; + protected final BigInteger frame; + protected final BigInteger threadId; + + protected SltInspectFrameVar(BigInteger ix, BigInteger frame, BigInteger threadId, String module, Callback callback) { + this.callback = callback; + this.module = module; + this.ix = ix; + this.frame = frame; + this.threadId = threadId; + } + + public void processReply(LispContainer data) { + if (isOk(data)) { + callback.onResult(data.getItems().get(1)); + } + } + + private boolean isOk(LispContainer data) { + return data.getItems().size() > 0 && + data.getItems().get(0) instanceof LispSymbol && + ":ok".equals(((LispSymbol) data.getItems().get(0)).getValue()); + } + + @Override + public SwankPacket createPacket(BigInteger requestId) { + return SwankPacket.inspectLocal(ix, frame, threadId, module, requestId); + } + + public interface Callback { + void onResult(LispElement result); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebugger.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebugger.java index 108d082..a111edb 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebugger.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebugger.java @@ -1,9 +1,10 @@ package com.en_circle.slt.plugin.ui.debug; import com.en_circle.slt.plugin.swank.debug.SltDebugInfo; +import com.intellij.openapi.Disposable; import com.intellij.ui.tabs.TabInfo; -public interface SltDebugger { +public interface SltDebugger extends Disposable { TabInfo getTab(); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java index 7839fba..87b66e4 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java @@ -11,6 +11,7 @@ import com.en_circle.slt.plugin.swank.requests.SltInvokeNthRestart; import com.en_circle.slt.plugin.swank.requests.ThrowToToplevel; import com.intellij.icons.AllIcons.Actions; +import com.intellij.openapi.Disposable; import com.intellij.openapi.actionSystem.ActionPlaces; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; @@ -47,7 +48,7 @@ import java.util.List; import java.util.Map; -public class SltDebuggerImpl implements SltDebugger { +public class SltDebuggerImpl implements SltDebugger, Disposable { private static final Logger log = LoggerFactory.getLogger(SltDebuggerImpl.class); private final JComponent content; @@ -56,6 +57,7 @@ public class SltDebuggerImpl implements SltDebugger { private BigInteger lastDebugId; private JPanel singleFrameComponent; private final List stackframes = new ArrayList<>(); + private BigInteger debugContext; public SltDebuggerImpl(SltDebuggers parent) { this.parent = parent; @@ -223,10 +225,6 @@ private void actionAccepted(SltDebugAction action, SltDebugInfo debugInfo) { } - private void closeGui() { - parent.removeDebugger(this, lastDebugId); - } - private void stackframeClicked(SltDebugStackTraceElement element, SltDebugInfo debugInfo) { int ix = debugInfo.getStacktrace().indexOf(element); for (int ix2=0; ix2())); localsTable.setFillsViewportHeight(true); + localsTable.setFocusable(false); + localsTable.setRowSelectionAllowed(false); + localsTable.addMouseListener(new MouseAdapter() { + @Override + public void mouseClicked(MouseEvent e) { + int row = localsTable.rowAtPoint(e.getPoint()); + int column = localsTable.columnAtPoint(e.getPoint()); + if (column == 0) { + FrameTableModel model = (FrameTableModel) localsTable.getModel(); + openInspector(model.locals.get(row)); + } + } + }); + resetRenderer(); TabInfo locals = new TabInfo(new JBScrollPane(localsTable)); locals.setText(SltBundle.message("slt.ui.debugger.frame.locals")); @@ -56,9 +78,36 @@ private void create() { SltFrameConsole frameConsole = new SltFrameConsole(project, threadId, frameId, this::reloadLocals, module); TabInfo consoleTab = frameConsole.create(); tabs.addTab(consoleTab); + + inspector = new SltInspector(); + TabInfo inspectorTab = new TabInfo(new JBScrollPane(inspector.getContent())); + inspectorTab.setText(SltBundle.message("slt.ui.debugger.frame.inspector")); + tabs.addTab(inspectorTab); + content.add(tabs.getComponent(), BorderLayout.CENTER); } + private void resetRenderer() { + localsTable.getColumn(SltBundle.message("slt.ui.debugger.frame.arg")).setCellRenderer(new DefaultTableCellRenderer() { + @Override + public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { + super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); + + Map attributes = new HashMap<>(getFont().getAttributes()); + attributes.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE_ON); + setFont(getFont().deriveFont(attributes)); + setForeground(SltUIConstants.HYPERLINK_COLOR); + setCursor(new Cursor(Cursor.HAND_CURSOR)); + + return this; + } + }); + } + + private void openInspector(Local local) { + + } + private void reloadLocals() { try { SltLispEnvironmentProvider.getInstance().sendToLisp(SltFrameLocalsAndCatchTags.getLocals(frameId, threadId, result -> { @@ -81,12 +130,14 @@ public void refreshFrameValues(LispElement localsAndTags) { if (locals instanceof LispContainer) { LispContainer locs = (LispContainer) locals; List parsedLocals = new ArrayList<>(); + int ix=0; for (LispElement e : locs.getItems()) { try { LispContainer ec = (LispContainer) e; String name = ((LispString) LispUtils.pvalue(ec, new LispSymbol(":NAME"))).getValue(); String value = ((LispString) LispUtils.pvalue(ec, new LispSymbol(":VALUE"))).getValue(); Local l = new Local(); + l.ix = ix++; l.name = name; l.value = value; parsedLocals.add(l); @@ -98,13 +149,16 @@ public void refreshFrameValues(LispElement localsAndTags) { } } localsTable.setModel(new FrameTableModel(parsedLocals)); + resetRenderer(); } else { localsTable.setModel(new FrameTableModel(new ArrayList<>())); + resetRenderer(); } } private static class Local { + private int ix; private String name; private String value; @@ -145,5 +199,10 @@ public Object getValueAt(int rowIndex, int columnIndex) { return locals.get(rowIndex).value; } } + + @Override + public Class getColumnClass(int columnIndex) { + return String.class; + } } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java new file mode 100644 index 0000000..a8efc6c --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java @@ -0,0 +1,19 @@ +package com.en_circle.slt.plugin.ui.debug; + +import javax.swing.*; +import java.awt.*; + +public class SltInspector { + + private final JPanel content; + + public SltInspector() { + + content = new JPanel(new BorderLayout()); + } + + public JComponent getContent() { + return content; + } + +} diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index 33570ee..004b939 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -13,6 +13,7 @@ slt.documentation.types.specialform=Special Form slt.documentation.types.constant=Constant Form slt.documentation.types.specvariable=Special Variable slt.documentation.types.keyword=Keyword +slt.documentation.types.class=Class # UI slt.ui.errors.sbcl.start=Failed to Start SBCL @@ -32,6 +33,7 @@ slt.ui.colorsettings.specialform=Special form slt.ui.colorsettings.function=Function call slt.ui.colorsettings.macro=Macro call slt.ui.colorsettings.reader=Reader macro +slt.ui.colorsettings.class=Class # Process slt.ui.process.title=SBCL Process @@ -65,6 +67,7 @@ slt.ui.debugger.rest.text=Expressions separated by space for rest argument: slt.ui.debugger.rest.title=Specify Restart Rest Arguments slt.ui.debugger.frame.repl=Frame REPL slt.ui.debugger.frame.locals=Locals +slt.ui.debugger.frame.inspector=Inspector slt.ui.debugger.frame.failedtoparse=Failed to parse slt.ui.debugger.frame.arg=Name slt.ui.debugger.frame.value=Value diff --git a/src/main/resources/templates/en_US/slt.cl b/src/main/resources/templates/en_US/slt.cl index d1be363..82c57ee 100644 --- a/src/main/resources/templates/en_US/slt.cl +++ b/src/main/resources/templates/en_US/slt.cl @@ -2,7 +2,9 @@ (defpackage :slt-core (:use :cl :swank) - (:export analyze-symbol analyze-symbols read-fix-packages list-package-names)) + (:export analyze-symbol analyze-symbols read-fix-packages list-package-names + initialize-or-get-debug-context debug-context debug-frame-variable register-variable + )) ; swank/slime overrides @@ -95,6 +97,10 @@ format suitable for Emacs." (let ((*standard-output* (make-string-output-stream))) (cond ((not test-sym) (list NIL NIL NIL)) + ((find-class test-sym NIL) (progn + (describe test-sym) + (list :class (get-output-stream-string *standard-output*) + (swank:find-source-location (find-class test-sym))))) ((special-operator-p test-sym) (list :special-form NIL NIL)) ((macro-function test-sym) (progn (describe test-sym) @@ -107,7 +113,7 @@ format suitable for Emacs." (list :function (get-output-stream-string *standard-output*) - (swank:find-source-location (symbol-function test-sym))))) + (swank:find-source-location (symbol-function test-sym))))) ((specialp test-sym) (progn (describe test-sym) (list :special (get-output-stream-string *standard-output*) NIL))) From 4c3b7f3ff00c67e433158091471dba8998d70783 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 19:31:06 +0100 Subject: [PATCH 05/30] fixed typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 524ee45..154f6e4 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ IDE capabilities for Common Lisp. ## Requirements -1) Intellij based IDE - tested on `Intellij Idea Community/Ultimate` but should workd on all major IDEs +1) Intellij based IDE - tested on `Intellij Idea Community/Ultimate` but should work on all major IDEs 1) Versions supported are from 2022.2 and upwards 2) [Steel Bank Common Lisp](https://www.sbcl.org/) installed 3) [Quicklisp](https://www.quicklisp.org/beta/) From c815ea6822289cf2106fc01dc5756d69cdf1caa1 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 19:31:32 +0100 Subject: [PATCH 06/30] change of version --- build.gradle.kts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle.kts b/build.gradle.kts index dc3ddb0..d9cb34a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,7 +4,7 @@ plugins { } group = "com.en_circle.slt" -version = "0.1.1" +version = "0.1.2" repositories { mavenCentral() From 529b5b1a363004a6b1f86fcdafed984ebe39ebb3 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 19:33:15 +0100 Subject: [PATCH 07/30] merge with stable && master --- .../en_circle/slt/plugin/settings/SltSettingsConfigurable.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java b/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java index 542fe1a..2b558d8 100644 --- a/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java +++ b/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java @@ -3,7 +3,6 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SltState; -import com.en_circle.slt.plugin.swank.SwankServer; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; import com.intellij.openapi.project.ProjectManager; @@ -63,7 +62,7 @@ public void apply() throws ConfigurationException { settings.port = component.getPort(); settings.quicklispStartScript = component.getQuicklispStartScript(); - if (restartServer && SwankServer.INSTANCE.isActive()) { + if (restartServer && SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()) { if (Messages.YES == Messages.showYesNoDialog( SltBundle.message("slt.ui.settings.restart.prompt"), SltBundle.message("slt.ui.settings.restart.title"), From 364e88e143abe80d025e1b9dfde005c2b8acff50 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 21:32:18 +0100 Subject: [PATCH 08/30] #17 - basic inspection with clicking --- README.md | 4 + contributing.md | 2 +- .../slt/plugin/swank/SlimeListener.java | 14 +- .../slt/plugin/swank/SwankPacket.java | 40 +++- .../swank/debug/SltInspectedObject.java | 70 ++++++ .../plugin/swank/requests/SltInspectNth.java | 54 +++++ .../swank/requests/SltInspectorAction.java | 68 ++++++ .../slt/plugin/ui/console/SltConsole.java | 2 + .../slt/plugin/ui/debug/SltDebuggerImpl.java | 2 +- .../slt/plugin/ui/debug/SltFrameInfo.java | 25 ++- .../slt/plugin/ui/debug/SltInspector.java | 207 +++++++++++++++++- .../resources/messages/SltBundle.properties | 5 + 12 files changed, 470 insertions(+), 23 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/debug/SltInspectedObject.java create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectNth.java create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectorAction.java diff --git a/README.md b/README.md index ca93930..18110d1 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,10 @@ You can also open this as a project in Intellij Idea. * [ ] Upload to marketplace when it has enough features * [x] REPL * [x] Interactive debugging +* [ ] Inspection + * [x] Basic inspection + * [ ] Actions + * [ ] Inspection eval * [ ] Walkable debugger without actions * [ ] Breakpoints * [x] Documentation diff --git a/contributing.md b/contributing.md index f1a8a40..2f41d7f 100644 --- a/contributing.md +++ b/contributing.md @@ -1,3 +1,3 @@ Report any bugs please! -I will think of what to write here at later date when it's bit bigger project. \ No newline at end of file +I will think of what to write here at later date when it's a bit bigger project. \ No newline at end of file diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java index 61e7e3e..937aab8 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java @@ -144,8 +144,18 @@ private void processReturn(LispContainer reply) { } if (request instanceof SltInspectFrameVar) { - SltInspectFrameVar frames = (SltInspectFrameVar) request; - frames.processReply((LispContainer) reply.getItems().get(1)); + SltInspectFrameVar frameVar = (SltInspectFrameVar) request; + frameVar.processReply((LispContainer) reply.getItems().get(1)); + } + + if (request instanceof SltInspectNth) { + SltInspectNth inspectNth = (SltInspectNth) request; + inspectNth.processReply((LispContainer) reply.getItems().get(1)); + } + + if (request instanceof SltInspectorAction) { + SltInspectorAction action = (SltInspectorAction) request; + action.processReply((LispContainer) reply.getItems().get(1)); } } finally { requests.remove(replyId.getValue()); diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java index 6355723..7f87c98 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java @@ -140,10 +140,6 @@ public static SwankPacket throwToToplevel(BigInteger threadId, BigInteger contin return new SwankPacket(formatted); } - public static SwankPacket frameLocals(BigInteger frame, BigInteger threadId, BigInteger continuation) { - return frameLocals(frame, threadId, "CL-USER", continuation); - } - public static SwankPacket frameLocals(BigInteger frame, BigInteger threadId, String packageName, BigInteger continuation) { packageName = StringUtils.replace(packageName, "\\", "\\\\"); packageName = StringUtils.replace(packageName, "\"", "\\\""); @@ -152,10 +148,6 @@ public static SwankPacket frameLocals(BigInteger frame, BigInteger threadId, Str return new SwankPacket(formatted); } - public static SwankPacket inspectLocal(BigInteger ix, BigInteger frameId, BigInteger threadId, BigInteger continuation) { - return inspectLocal(ix, frameId, threadId, "CL-USER", continuation); - } - public static SwankPacket inspectLocal(BigInteger ix, BigInteger frameId, BigInteger threadId, String packageName, BigInteger continuation) { packageName = StringUtils.replace(packageName, "\\", "\\\\"); packageName = StringUtils.replace(packageName, "\"", "\\\""); @@ -164,6 +156,38 @@ public static SwankPacket inspectLocal(BigInteger ix, BigInteger frameId, BigInt return new SwankPacket(formatted); } + public static SwankPacket frameInspectNth(BigInteger ix, BigInteger threadId, String packageName, BigInteger continuation) { + packageName = StringUtils.replace(packageName, "\\", "\\\\"); + packageName = StringUtils.replace(packageName, "\"", "\\\""); + String formatted = String.format("(:emacs-rex (swank:inspect-nth-part %s) :%s %s %s)", + ix, packageName, threadId, continuation); + return new SwankPacket(formatted); + } + + public static SwankPacket inspectorBack(BigInteger threadId, String packageName, BigInteger continuation) { + packageName = StringUtils.replace(packageName, "\\", "\\\\"); + packageName = StringUtils.replace(packageName, "\"", "\\\""); + String formatted = String.format("(:emacs-rex (swank:inspector-pop) :%s %s %s)", + packageName, threadId, continuation); + return new SwankPacket(formatted); + } + + public static SwankPacket inspectorForward(BigInteger threadId, String packageName, BigInteger continuation) { + packageName = StringUtils.replace(packageName, "\\", "\\\\"); + packageName = StringUtils.replace(packageName, "\"", "\\\""); + String formatted = String.format("(:emacs-rex (swank:inspector-next) :%s %s %s)", + packageName, threadId, continuation); + return new SwankPacket(formatted); + } + + public static SwankPacket inspectorRefresh(BigInteger threadId, String packageName, BigInteger continuation) { + packageName = StringUtils.replace(packageName, "\\", "\\\\"); + packageName = StringUtils.replace(packageName, "\"", "\\\""); + String formatted = String.format("(:emacs-rex (swank:inspector-reinspect) :%s %s %s)", + packageName, threadId, continuation); + return new SwankPacket(formatted); + } + public static SwankPacket loadFile(String file, BigInteger continuation) { return loadFile(file, "CL-USER", continuation); } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/debug/SltInspectedObject.java b/src/main/java/com/en_circle/slt/plugin/swank/debug/SltInspectedObject.java new file mode 100644 index 0000000..2e018bd --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/debug/SltInspectedObject.java @@ -0,0 +1,70 @@ +package com.en_circle.slt.plugin.swank.debug; + +import com.en_circle.slt.plugin.lisp.lisp.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.List; + +public class SltInspectedObject { + private static final Logger log = LoggerFactory.getLogger(SltInspectedObject.class); + + private final String title; + private final BigInteger id; + private final List elements = new ArrayList<>(); + + public SltInspectedObject(LispContainer container) throws Exception { + this.title = ((LispString) LispUtils.pvalue(container, new LispSymbol(":TITLE"))).getValue(); + this.id = ((LispInteger) LispUtils.pvalue(container, new LispSymbol(":ID"))).getValue(); + + LispContainer contents = (LispContainer) LispUtils.pvalue(container, new LispSymbol(":CONTENT")); + LispContainer content = (LispContainer) contents.getItems().get(0); + for (LispElement element : content.getItems()) { + if (element instanceof LispString) { + if (elements.isEmpty() || elements.get(elements.size() - 1).id != null) { + SltInspectionElement e = new SltInspectionElement(); + e.text = LispUtils.unescape(((LispString) element).getValue()); + elements.add(e); + } else { + elements.get(elements.size() - 1).text += LispUtils.unescape(((LispString) element).getValue()); + } + } else if (element instanceof LispContainer) { + LispContainer subelement = (LispContainer) element; + SltInspectionElement e = new SltInspectionElement(); + e.text = LispUtils.unescape(((LispString) LispUtils.pvalue(subelement, new LispSymbol(":VALUE"))).getValue()); + e.id = ((LispInteger) subelement.getItems().get(2)).getValue(); + elements.add(e); + } else { + log.warn("Unknown element in inspector!"); + } + } + } + + public String getTitle() { + return title; + } + + public BigInteger getId() { + return id; + } + + public List getElements() { + return elements; + } + + public static class SltInspectionElement { + + private String text; + private BigInteger id = null; + + public String getText() { + return text; + } + + public BigInteger getId() { + return id; + } + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectNth.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectNth.java new file mode 100644 index 0000000..c377e2d --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectNth.java @@ -0,0 +1,54 @@ +package com.en_circle.slt.plugin.swank.requests; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.lisp.LispSymbol; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankPacket; + +import java.math.BigInteger; + +public class SltInspectNth extends SlimeRequest { + + public static SlimeRequest inspectVariable(BigInteger ix, BigInteger threadId, String module, Callback callback) { + return new SltInspectNth(ix, threadId, module, callback); + } + + public static SlimeRequest inspectVariable(BigInteger ix, BigInteger threadId, Callback callback) { + return new SltInspectNth(ix, threadId, "CL-USER", callback); + } + + protected final Callback callback; + protected final String module; + protected final BigInteger ix; + protected final BigInteger threadId; + + protected SltInspectNth(BigInteger ix,BigInteger threadId, String module, Callback callback) { + this.callback = callback; + this.module = module; + this.ix = ix; + this.threadId = threadId; + } + + public void processReply(LispContainer data) { + if (isOk(data)) { + callback.onResult(data.getItems().get(1)); + } + } + + private boolean isOk(LispContainer data) { + return data.getItems().size() > 0 && + data.getItems().get(0) instanceof LispSymbol && + ":ok".equals(((LispSymbol) data.getItems().get(0)).getValue()); + } + + @Override + public SwankPacket createPacket(BigInteger requestId) { + return SwankPacket.frameInspectNth(ix, threadId, module, requestId); + } + + public interface Callback { + void onResult(LispElement result); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectorAction.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectorAction.java new file mode 100644 index 0000000..9cd8f2f --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectorAction.java @@ -0,0 +1,68 @@ +package com.en_circle.slt.plugin.swank.requests; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.lisp.LispSymbol; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankPacket; + +import java.math.BigInteger; + +public class SltInspectorAction extends SlimeRequest { + + public static SlimeRequest action(ActionType actionType, BigInteger threadId, String module, SltInspectNth.Callback callback) { + return new SltInspectorAction(actionType, threadId, module, callback); + } + + public static SlimeRequest action(ActionType actionType, BigInteger threadId, SltInspectNth.Callback callback) { + return new SltInspectorAction(actionType, threadId, "CL-USER", callback); + } + + protected final SltInspectNth.Callback callback; + protected final String module; + protected final ActionType actionType; + protected final BigInteger threadId; + + protected SltInspectorAction(ActionType actionType, BigInteger threadId, String module, SltInspectNth.Callback callback) { + this.callback = callback; + this.module = module; + this.actionType = actionType; + this.threadId = threadId; + } + + public void processReply(LispContainer data) { + if (isOk(data)) { + callback.onResult(data.getItems().get(1)); + } + } + + private boolean isOk(LispContainer data) { + return data.getItems().size() > 0 && + data.getItems().get(0) instanceof LispSymbol && + ":ok".equals(((LispSymbol) data.getItems().get(0)).getValue()); + } + + @Override + public SwankPacket createPacket(BigInteger requestId) { + switch (actionType) { + + case GO_BACK: + return SwankPacket.inspectorBack(threadId, module, requestId); + case GO_FORWARD: + return SwankPacket.inspectorForward(threadId, module, requestId); + case REFRESH: + return SwankPacket.inspectorRefresh(threadId, module, requestId); + } + throw new IllegalStateException(); + } + + public interface Callback { + void onResult(LispElement result); + } + + public enum ActionType { + + GO_BACK, GO_FORWARD, REFRESH + + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java index e41044a..162dfab 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java @@ -14,6 +14,7 @@ import com.intellij.execution.ui.ConsoleViewContentType; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.Disposer; import com.intellij.ui.tabs.TabInfo; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -49,6 +50,7 @@ protected void setPackage(String packageName) { public TabInfo create() { languageConsole = new LanguageConsoleBuilder() .build(project, SltCommonLispLanguage.INSTANCE); + Disposer.register(project, languageConsole); languageConsole.setPrompt(currentModule + "> "); ConsoleExecuteAction action = new ConsoleExecuteAction(languageConsole, new SltConsoleExecuteActionHandler(languageConsole) { diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java index 87b66e4..0bd5a70 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java @@ -252,7 +252,7 @@ private void stackframeClicked(SltDebugStackTraceElement element, SltDebugInfo d try { SltLispEnvironmentProvider.getInstance().sendToLisp(SltFrameLocalsAndCatchTags.getLocals(BigInteger.valueOf(ix), debugInfo.getThreadId(), result -> { - ApplicationManager.getApplication().invokeLater(() -> { + ApplicationManager.getApplication().runWriteAction(() -> { SltFrameInfo frameInfo = new SltFrameInfo(parent.getProject(), debugInfo.getThreadId(), BigInteger.valueOf(ix), element.getFramePackage()); singleFrameComponent.removeAll(); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java index 80b5e6f..2d35866 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java @@ -39,6 +39,8 @@ public class SltFrameInfo { private final JComponent content; private SltInspector inspector; private JBTable localsTable; + private JBTabs tabs; + private TabInfo inspectorTab; public SltFrameInfo(Project project, BigInteger threadId, BigInteger frameId, String module) { this.project = project; @@ -52,7 +54,7 @@ public SltFrameInfo(Project project, BigInteger threadId, BigInteger frameId, St } private void create() { - JBTabs tabs = new JBTabsImpl(project); + tabs = new JBTabsImpl(project); localsTable = new JBTable(new FrameTableModel(new ArrayList<>())); localsTable.setFillsViewportHeight(true); @@ -62,10 +64,12 @@ private void create() { @Override public void mouseClicked(MouseEvent e) { int row = localsTable.rowAtPoint(e.getPoint()); - int column = localsTable.columnAtPoint(e.getPoint()); - if (column == 0) { - FrameTableModel model = (FrameTableModel) localsTable.getModel(); - openInspector(model.locals.get(row)); + if (row >= 0) { + int column = localsTable.columnAtPoint(e.getPoint()); + if (column == 0) { + FrameTableModel model = (FrameTableModel) localsTable.getModel(); + openInspector(model.locals.get(row)); + } } } }); @@ -79,8 +83,8 @@ public void mouseClicked(MouseEvent e) { TabInfo consoleTab = frameConsole.create(); tabs.addTab(consoleTab); - inspector = new SltInspector(); - TabInfo inspectorTab = new TabInfo(new JBScrollPane(inspector.getContent())); + inspector = new SltInspector(project, threadId); + inspectorTab = new TabInfo(new JBScrollPane(inspector.getContent())); inspectorTab.setText(SltBundle.message("slt.ui.debugger.frame.inspector")); tabs.addTab(inspectorTab); @@ -105,7 +109,8 @@ public Component getTableCellRendererComponent(JTable table, Object value, boole } private void openInspector(Local local) { - + inspector.loadLocal(local, frameId); + tabs.select(inspectorTab, true); } private void reloadLocals() { @@ -156,9 +161,9 @@ public void refreshFrameValues(LispElement localsAndTags) { } } - private static class Local { + public static class Local { - private int ix; + int ix; private String name; private String value; diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java index a8efc6c..b433b6d 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java @@ -1,15 +1,220 @@ package com.en_circle.slt.plugin.ui.debug; +import com.en_circle.slt.plugin.SltBundle; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.swank.debug.SltInspectedObject; +import com.en_circle.slt.plugin.swank.debug.SltInspectedObject.SltInspectionElement; +import com.en_circle.slt.plugin.swank.requests.SltInspectFrameVar; +import com.en_circle.slt.plugin.swank.requests.SltInspectNth; +import com.en_circle.slt.plugin.swank.requests.SltInspectorAction; +import com.en_circle.slt.plugin.swank.requests.SltInspectorAction.ActionType; +import com.en_circle.slt.plugin.ui.debug.SltFrameInfo.Local; +import com.intellij.icons.AllIcons.Actions; +import com.intellij.openapi.actionSystem.*; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.util.text.HtmlBuilder; +import com.intellij.openapi.util.text.HtmlChunk; +import com.intellij.ui.components.JBScrollPane; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import javax.swing.*; +import javax.swing.event.HyperlinkEvent.EventType; +import javax.swing.text.DefaultEditorKit; +import javax.swing.text.html.HTMLEditorKit; import java.awt.*; +import java.math.BigInteger; +import java.util.regex.Pattern; public class SltInspector { + private static final Logger log = LoggerFactory.getLogger(SltInspector.class); + private final Project project; private final JPanel content; + private final BigInteger threadId; + private final JEditorPane inspectorGeneratedContents; - public SltInspector() { + public SltInspector(Project project, BigInteger threadId) { + this.project = project; + this.threadId = threadId; content = new JPanel(new BorderLayout()); + DefaultActionGroup controlGroup = new DefaultActionGroup(); + controlGroup.add(new GoBackAction()); + controlGroup.add(new GoForwardAction()); + controlGroup.add(new RefreshAction()); + ActionToolbar toolbar = ActionManager.getInstance() + .createActionToolbar(SltInspector.class.getName(), controlGroup, true); + toolbar.setTargetComponent(content); + content.add(toolbar.getComponent(), BorderLayout.NORTH); + + inspectorGeneratedContents = new JEditorPane("text/html", ""); + inspectorGeneratedContents.setEditorKit(new HTMLEditorKit()); + inspectorGeneratedContents.setEditable(false); + inspectorGeneratedContents.addHyperlinkListener(e -> { + if (e.getEventType() == EventType.ACTIVATED) + navigate(e.getDescription()); + }); + content.add(new JBScrollPane(inspectorGeneratedContents), BorderLayout.CENTER); + } + + public void loadLocal(Local local, BigInteger frame) { + try { + SltLispEnvironmentProvider.getInstance() + .sendToLisp(SltInspectFrameVar.inspectVariable(BigInteger.valueOf(local.ix), frame, threadId, + result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.sbclstart"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + } + } + + private void processResult(LispElement result) { + SltInspectedObject parsedResult = null; + try { + parsedResult = new SltInspectedObject((LispContainer) result); + } catch (Exception ignored) { + // in case we get garbage we show error + } + clear(); + if (parsedResult == null) { + inspectorGeneratedContents.setText("Failed to parse result. Please report bug with this text: \n" + result.toString()); + inspectorGeneratedContents.setEditorKit(new DefaultEditorKit()); + } else { + inspectorGeneratedContents.setContentType("text/html"); + inspectorGeneratedContents.setEditorKit(new HTMLEditorKit()); + loadInspectedObject(parsedResult); + } + inspectorGeneratedContents.setCaretPosition(0); + } + + private void loadInspectedObject(SltInspectedObject inspectedObject) { + HtmlBuilder contentBuilder = new HtmlBuilder(); + contentBuilder.append(HtmlChunk.text(inspectedObject.getTitle()) + .wrapWith("h2")); + contentBuilder.append(HtmlChunk.br()); + for (SltInspectionElement element : inspectedObject.getElements()) { + String text = element.getText(); + if (element.getId() == null) { + String[] parts = text.split(Pattern.quote("\n")); + for (int i=0; i + ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.sbclstart"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + } + } + + private class GoBackAction extends AnAction { + + private GoBackAction() { + super(SltBundle.message("slt.ui.inspector.navigation.back"), "", Actions.Back); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent event) { + try { + SltLispEnvironmentProvider.getInstance() + .sendToLisp(SltInspectorAction.action(ActionType.GO_BACK, threadId, result -> + ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.sbclstart"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + } + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + + e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + } + } + + private class GoForwardAction extends AnAction { + + private GoForwardAction() { + super(SltBundle.message("slt.ui.inspector.navigation.forward"), "", Actions.Forward); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent event) { + try { + SltLispEnvironmentProvider.getInstance() + .sendToLisp(SltInspectorAction.action(ActionType.GO_FORWARD, threadId, result -> + ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.sbclstart"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + } + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + + e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + } + } + + private class RefreshAction extends AnAction { + + private RefreshAction() { + super(SltBundle.message("slt.ui.inspector.navigation.refresh"), "", Actions.Refresh); + } + + @Override + public void actionPerformed(@NotNull AnActionEvent event) { + try { + SltLispEnvironmentProvider.getInstance() + .sendToLisp(SltInspectorAction.action(ActionType.REFRESH, threadId, result -> + ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.sbclstart"), e); + Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + } + } + + @Override + public void update(@NotNull AnActionEvent e) { + super.update(e); + + e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + } } public JComponent getContent() { diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index dfb2c99..dbcbcbb 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -72,6 +72,11 @@ slt.ui.debugger.frame.failedtoparse=Failed to parse slt.ui.debugger.frame.arg=Name slt.ui.debugger.frame.value=Value +# inspector +slt.ui.inspector.navigation.back=Go Back in History +slt.ui.inspector.navigation.forward=Go Forward in History +slt.ui.inspector.navigation.refresh=Refresh Currently Inspected Object + # Settings slt.ui.settings.title=SLT Configuration slt.ui.settings.executable=SBCL executable: From 9f27a868256ef6ef6e16191ceacf67404c22e0bc Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 21:54:44 +0100 Subject: [PATCH 09/30] #17 - color changed --- src/main/java/com/en_circle/slt/plugin/SltUIConstants.java | 4 ++++ .../com/en_circle/slt/plugin/ui/debug/SltInspector.java | 6 ++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/en_circle/slt/plugin/SltUIConstants.java b/src/main/java/com/en_circle/slt/plugin/SltUIConstants.java index 8dc03d4..9eb5cad 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltUIConstants.java +++ b/src/main/java/com/en_circle/slt/plugin/SltUIConstants.java @@ -10,4 +10,8 @@ public class SltUIConstants { public static final JBColor DEBUG_FRAMES_COLOR = new JBColor(new Color(230, 245, 95), new Color(5, 51, 12)); public static final JBColor DEBUG_FRAMES_SELECTED_COLOR = new JBColor(new Color(230, 145, 95), new Color(5, 51, 72)); + public static String colorToHex(JBColor color) { + int rgba = (color.getRGB() << 8) | color.getAlpha(); + return String.format("#%08X", rgba); + } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java index b433b6d..1c708c7 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java @@ -2,6 +2,7 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.SltUIConstants; import com.en_circle.slt.plugin.lisp.lisp.LispContainer; import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.swank.debug.SltInspectedObject; @@ -97,7 +98,7 @@ private void loadInspectedObject(SltInspectedObject inspectedObject) { HtmlBuilder contentBuilder = new HtmlBuilder(); contentBuilder.append(HtmlChunk.text(inspectedObject.getTitle()) .wrapWith("h2")); - contentBuilder.append(HtmlChunk.br()); + contentBuilder.append(HtmlChunk.hr()); for (SltInspectionElement element : inspectedObject.getElements()) { String text = element.getText(); if (element.getId() == null) { @@ -109,7 +110,8 @@ private void loadInspectedObject(SltInspectedObject inspectedObject) { } } } else { - contentBuilder.append(HtmlChunk.link(mkLink(inspectedObject, element), text)); + contentBuilder.append(HtmlChunk.link(mkLink(inspectedObject, element), text) + .style("color:" + SltUIConstants.colorToHex(SltUIConstants.HYPERLINK_COLOR))); } } From c9d601a1d1dfb19c9517c16019cc6d6bb86bcfe0 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 22:02:46 +0100 Subject: [PATCH 10/30] #17 - cleanup --- .../java/com/en_circle/slt/plugin/ui/debug/SltInspector.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java index 1c708c7..433503f 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java @@ -85,7 +85,6 @@ private void processResult(LispElement result) { clear(); if (parsedResult == null) { inspectorGeneratedContents.setText("Failed to parse result. Please report bug with this text: \n" + result.toString()); - inspectorGeneratedContents.setEditorKit(new DefaultEditorKit()); } else { inspectorGeneratedContents.setContentType("text/html"); inspectorGeneratedContents.setEditorKit(new HTMLEditorKit()); @@ -97,7 +96,7 @@ private void processResult(LispElement result) { private void loadInspectedObject(SltInspectedObject inspectedObject) { HtmlBuilder contentBuilder = new HtmlBuilder(); contentBuilder.append(HtmlChunk.text(inspectedObject.getTitle()) - .wrapWith("h2")); + .wrapWith("h3")); contentBuilder.append(HtmlChunk.hr()); for (SltInspectionElement element : inspectedObject.getElements()) { String text = element.getText(); @@ -124,6 +123,7 @@ private String mkLink(SltInspectedObject inspectedObject, SltInspectionElement e private void clear() { inspectorGeneratedContents.setContentType("text/plain"); + inspectorGeneratedContents.setEditorKit(new DefaultEditorKit()); inspectorGeneratedContents.setText(""); } From 31b73dea95050b0ea5636b81979c66bd0ae4f206 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 23:18:06 +0100 Subject: [PATCH 11/30] implementation of #11 --- README.md | 3 +- build.gradle.kts | 1 + .../slt/plugin/SltDocumentationProvider.java | 29 ++++-- .../SltLispEnvironmentMacroExpandCache.java | 88 +++++++++++++++++++ .../plugin/SltLispEnvironmentProvider.java | 12 +++ .../plugin/SltLispEnvironmentSymbolCache.java | 4 +- .../slt/plugin/actions/EvalActionBase.java | 13 +-- .../slt/plugin/actions/EvalFile.java | 2 +- .../plugin/actions/EvalFileFromEditor.java | 8 +- .../slt/plugin/lisp/LispParserUtil.java | 20 +++++ .../slt/plugin/swank/SlimeListener.java | 33 ++++--- .../slt/plugin/swank/SwankPacket.java | 14 +++ .../requests/{SltEval.java => Eval.java} | 8 +- ...SwankEvalAndGrab.java => EvalAndGrab.java} | 8 +- ...tualFile.java => EvalFromVirtualFile.java} | 6 +- .../swank/requests/EvalStringInFrameEval.java | 2 +- ...Tags.java => FrameLocalsAndCatchTags.java} | 8 +- ...pectFrameVar.java => InspectFrameVar.java} | 8 +- .../{SltInspectNth.java => InspectNth.java} | 8 +- ...pectorAction.java => InspectorAction.java} | 14 +-- ...eNthRestart.java => InvokeNthRestart.java} | 6 +- .../plugin/swank/requests/MacroexpandAll.java | 48 ++++++++++ .../plugin/ui/PackageSelectorComponent.java | 4 +- .../slt/plugin/ui/console/SltConsole.java | 4 +- .../slt/plugin/ui/debug/SltDebuggerImpl.java | 10 +-- .../slt/plugin/ui/debug/SltFrameInfo.java | 4 +- .../slt/plugin/ui/debug/SltInspector.java | 18 ++-- .../resources/messages/SltBundle.properties | 1 + 28 files changed, 301 insertions(+), 83 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentMacroExpandCache.java rename src/main/java/com/en_circle/slt/plugin/swank/requests/{SltEval.java => Eval.java} (86%) rename src/main/java/com/en_circle/slt/plugin/swank/requests/{SwankEvalAndGrab.java => EvalAndGrab.java} (88%) rename src/main/java/com/en_circle/slt/plugin/swank/requests/{SwankEvalFromVirtualFile.java => EvalFromVirtualFile.java} (80%) rename src/main/java/com/en_circle/slt/plugin/swank/requests/{SltFrameLocalsAndCatchTags.java => FrameLocalsAndCatchTags.java} (81%) rename src/main/java/com/en_circle/slt/plugin/swank/requests/{SltInspectFrameVar.java => InspectFrameVar.java} (82%) rename src/main/java/com/en_circle/slt/plugin/swank/requests/{SltInspectNth.java => InspectNth.java} (84%) rename src/main/java/com/en_circle/slt/plugin/swank/requests/{SltInspectorAction.java => InspectorAction.java} (77%) rename src/main/java/com/en_circle/slt/plugin/swank/requests/{SltInvokeNthRestart.java => InvokeNthRestart.java} (83%) create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/requests/MacroexpandAll.java diff --git a/README.md b/README.md index 18110d1..94528e1 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,8 @@ You can also open this as a project in Intellij Idea. * [ ] Walkable debugger without actions * [ ] Breakpoints * [x] Documentation -* [ ] Macro expand in documentation +* [x] Macro expand in documentation + * Macro expand requires you to hover element twice for now * [x] Find function by symbol name * [ ] Search for symbols * [ ] Back references diff --git a/build.gradle.kts b/build.gradle.kts index 6f54396..b5c0c1b 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -13,6 +13,7 @@ repositories { dependencies { implementation("org.awaitility:awaitility:4.2.0") implementation("org.watertemplate:watertemplate-engine:1.2.2") + implementation("com.google.guava:guava:30.0-jre") } sourceSets { diff --git a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java index f185cd2..ba0a1ef 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java @@ -1,9 +1,12 @@ package com.en_circle.slt.plugin; +import com.en_circle.slt.plugin.SymbolState.SymbolBinding; import com.en_circle.slt.plugin.lisp.LispParserUtil; +import com.en_circle.slt.plugin.lisp.psi.LispList; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; import com.en_circle.slt.plugin.lisp.psi.impl.LispPsiImplUtil; import com.intellij.lang.documentation.AbstractDocumentationProvider; +import com.intellij.openapi.util.text.HtmlBuilder; import com.intellij.openapi.util.text.HtmlChunk; import com.intellij.psi.PsiElement; import org.apache.commons.lang3.StringUtils; @@ -46,15 +49,31 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider { String text = element.getText(); String packageName = LispParserUtil.getPackage(element); SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, text, element); - return asHtml(state.documentation); + return asHtml(state, packageName, element, originalElement); } return null; } - private String asHtml(String documentation) { - if (documentation == null) - return null; + private String asHtml(SymbolState state, String packageName, PsiElement element, @Nullable PsiElement originalElement) { + HtmlBuilder builder = new HtmlBuilder(); + String documentation = StringUtils.replace(StringUtils.replace(state.documentation, " ", " "), + "\n", HtmlChunk.br().toString()); + builder.append(documentation == null ? HtmlChunk.raw("") : HtmlChunk.raw(documentation)); - return StringUtils.replace(StringUtils.replace(documentation, " ", " "), "\n", HtmlChunk.br().toString()); + LispList form = LispParserUtil.getIfHead(element); + if (form != null && state.binding == SymbolBinding.MACRO) { + String macroExpand = SltLispEnvironmentProvider.getInstance().macroexpand(form, packageName); + if (macroExpand != null) { + macroExpand = StringUtils.replace(StringUtils.replace(macroExpand, " ", " "), + "\n", HtmlChunk.br().toString()); + builder.append(HtmlChunk.hr()); + builder.append(HtmlChunk.text(SltBundle.message("slt.documentation.macroexpand"))); + builder.append(HtmlChunk.br()); + builder.append(HtmlChunk.raw(macroExpand)); + } + } + + String doc = builder.toString(); + return StringUtils.isBlank(doc) ? null : doc; } } diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentMacroExpandCache.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentMacroExpandCache.java new file mode 100644 index 0000000..2d3372a --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentMacroExpandCache.java @@ -0,0 +1,88 @@ +package com.en_circle.slt.plugin; + +import com.en_circle.slt.plugin.lisp.lisp.LispString; +import com.en_circle.slt.plugin.lisp.lisp.LispUtils; +import com.en_circle.slt.plugin.lisp.psi.LispList; +import com.en_circle.slt.plugin.swank.requests.MacroexpandAll; +import com.google.common.cache.CacheBuilder; +import com.google.common.cache.CacheLoader; +import com.google.common.cache.LoadingCache; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class SltLispEnvironmentMacroExpandCache { + + public static final SltLispEnvironmentMacroExpandCache INSTANCE = new SltLispEnvironmentMacroExpandCache(); + + private final LoadingCache expandedMacros; + + public SltLispEnvironmentMacroExpandCache() { + CacheLoader loader = new CacheLoader<>() { + @Override + public MacroExpandEntry load(@NotNull SltLispEnvironmentMacroExpandCache.MacroExpandEntry key) throws Exception { + SltLispEnvironmentProvider.getInstance().sendToLisp( + MacroexpandAll.macroexpand(key.form, key.packageName, result -> { + key.evaluated = LispUtils.unescape(((LispString) result).getValue()); + })); + return key; + } + }; + expandedMacros = CacheBuilder.newBuilder() + .maximumSize(512) + .build(loader); + } + + + public String macroexpand(LispList form, String packageName) throws Exception { + MacroExpandEntry entry = new MacroExpandEntry(); + entry.form = form.getNode().getText(); + PsiFile file = form.getContainingFile(); + if (file != null) { + entry.virtualFile = file.getVirtualFile(); + entry.modification = file.getModificationStamp(); + entry.packageName = packageName; + MacroExpandEntry cachedEntry = expandedMacros.get(entry); + if (cachedEntry.modification < entry.modification) { + expandedMacros.refresh(cachedEntry); + } + return expandedMacros.get(entry).evaluated; + } + return null; + } + + public void clear() { + expandedMacros.invalidateAll(); + } + + private static class MacroExpandEntry { + + private String form; + private String packageName; + private String evaluated; + private VirtualFile virtualFile; + private long modification; + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + MacroExpandEntry entry = (MacroExpandEntry) o; + + if (!Objects.equals(form, entry.form)) return false; + if (!Objects.equals(packageName, entry.packageName)) return false; + return Objects.equals(virtualFile, entry.virtualFile); + } + + @Override + public int hashCode() { + int result = form != null ? form.hashCode() : 0; + result = 31 * result + (packageName != null ? packageName.hashCode() : 0); + result = 31 * result + (virtualFile != null ? virtualFile.hashCode() : 0); + return result; + } + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java index 86a08e2..7b2095d 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java @@ -4,6 +4,7 @@ import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltLispOutputChangedListener; import com.en_circle.slt.plugin.environment.SltLispEnvironmentConfiguration; import com.en_circle.slt.plugin.environment.SltProcessException; +import com.en_circle.slt.plugin.lisp.psi.LispList; import com.en_circle.slt.plugin.swank.SlimeListener; import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; @@ -110,6 +111,7 @@ public void stop() throws Exception { try { client.close(); } finally { + SltLispEnvironmentMacroExpandCache.INSTANCE.clear(); SltLispEnvironmentSymbolCache.INSTANCE.clear(); if (environment != null) { environment.stop(); @@ -165,6 +167,16 @@ public void dispose() { } } + public String macroexpand(LispList form, String packageName) { + try { + return SltLispEnvironmentMacroExpandCache.INSTANCE.macroexpand(form, packageName); + } catch (Exception e) { + log.error(e.getMessage()); + log.debug(e.getMessage(), e); + } + return null; + } + public interface SBCLServerListener extends SltLispOutputChangedListener { void onPreStart(); diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java index 4c7818d..701be20 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java +++ b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java @@ -3,7 +3,7 @@ import com.en_circle.slt.plugin.SymbolState.SymbolBinding; import com.en_circle.slt.plugin.lisp.lisp.*; import com.en_circle.slt.plugin.swank.components.SourceLocation; -import com.en_circle.slt.plugin.swank.requests.SwankEvalAndGrab; +import com.en_circle.slt.plugin.swank.requests.EvalAndGrab; import com.google.common.collect.Lists; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.vfs.VirtualFile; @@ -129,7 +129,7 @@ private void refreshSymbolsBatched(List refreshStates) throws Excep refreshStates.stream().map(x -> x.name.toUpperCase() + " ").collect(Collectors.joining()) + ")"; request = StringUtils.replace(request, "\"", "\\\""); - SltLispEnvironmentProvider.getInstance().sendToLisp(SwankEvalAndGrab.eval( + SltLispEnvironmentProvider.getInstance().sendToLisp(EvalAndGrab.eval( String.format( "(slt-core:analyze-symbols (slt-core:read-fix-packages \"%s\"))", request), diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java index e8c0b75..c0f302b 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java @@ -3,17 +3,19 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltCommonLispFileType; import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.swank.requests.Eval; +import com.en_circle.slt.plugin.swank.requests.EvalFromVirtualFile; import com.en_circle.slt.plugin.swank.requests.LoadFile; -import com.en_circle.slt.plugin.swank.requests.SltEval; -import com.en_circle.slt.plugin.swank.requests.SwankEvalFromVirtualFile; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiDocumentManager; import com.intellij.psi.PsiFile; +import com.intellij.util.FileContentUtilCore; import org.jetbrains.annotations.NotNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +40,7 @@ public void update(@NotNull AnActionEvent event) { protected void evaluate(Project project, String buffer, String packageName, Runnable callback) { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(SltEval.eval(buffer, packageName, result -> callback.run()), true); + SltLispEnvironmentProvider.getInstance().sendToLisp(Eval.eval(buffer, packageName, result -> callback.run()), true); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); @@ -47,7 +49,7 @@ protected void evaluate(Project project, String buffer, String packageName, Runn protected void evaluateRegion(Project project, String buffer, String packageName, String filename, int bufferPosition, int lineno, int charno, Runnable callback) { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(SwankEvalFromVirtualFile + SltLispEnvironmentProvider.getInstance().sendToLisp(EvalFromVirtualFile .eval(buffer, filename, bufferPosition, lineno, charno, packageName, result -> callback.run()), true); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -55,9 +57,10 @@ protected void evaluateRegion(Project project, String buffer, String packageName } } - protected void evaluateFile(Project project, String filename) { + protected void evaluateFile(Project project, String filename, VirtualFile virtualFile) { try { SltLispEnvironmentProvider.getInstance().sendToLisp(LoadFile.loadFile(filename), true); + FileContentUtilCore.reparseFiles(virtualFile); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java index c543b29..1310313 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java @@ -18,7 +18,7 @@ public class EvalFile extends EvalActionBase { public void actionPerformed(@NotNull AnActionEvent event) { VirtualFile vf = event.getData(CommonDataKeys.VIRTUAL_FILE); if (vf != null) { - evaluateFile(event.getProject(), vf.getPath()); + evaluateFile(event.getProject(), vf.getPath(), vf); for (VirtualFile openedFiles : FileEditorManager.getInstance(Objects.requireNonNull(event.getProject())) .getOpenFiles()) { FileContentUtilCore.reparseFiles(openedFiles); diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalFileFromEditor.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalFileFromEditor.java index f307a33..dbbe59d 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalFileFromEditor.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalFileFromEditor.java @@ -6,8 +6,11 @@ import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.fileEditor.FileDocumentManager; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiDocumentManager; import org.jetbrains.annotations.NotNull; +import java.util.Objects; + public class EvalFileFromEditor extends EvalActionBase { @Override @@ -21,9 +24,12 @@ public void update(@NotNull AnActionEvent event) { public void actionPerformed(@NotNull AnActionEvent event) { EditorEx editor = (EditorEx) event.getData(CommonDataKeys.EDITOR); if (editor != null) { + PsiDocumentManager psiMgr = PsiDocumentManager.getInstance(Objects.requireNonNull(editor.getProject())); + psiMgr.commitDocument(editor.getDocument()); + VirtualFile vf = FileDocumentManager.getInstance().getFile(editor.getDocument()); if (vf != null) { - evaluateFile(editor.getProject(), vf.getPath()); + evaluateFile(editor.getProject(), vf.getPath(), vf); } } } diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java b/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java index 57d93a5..ae7dd19 100644 --- a/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java +++ b/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java @@ -25,6 +25,9 @@ public static String getPackage(PsiFile psiFile, int offset) { public static String getPackage(PsiElement element) { while (!(element instanceof LispToplevel)) { element = element.getParent(); + if (element == null) { + return SltLispEnvironmentProvider.getInstance().getGlobalPackage(); + } } PsiElement previous = element.getPrevSibling(); while (previous != null) { @@ -94,4 +97,21 @@ private static String getAsSymbol(LispSexpr seSymbol) { } return null; } + + public static LispList getIfHead(PsiElement element) { + PsiElement original = element; + while (!(element instanceof LispList)) { + element = element.getParent(); + if (element == null) { + return null; + } + } + LispList list = (LispList) element; + LispSexpr firstElement = list.getSexprList().get(0); + if (firstElement.getDatum() != null && firstElement.getDatum().getCompoundSymbol() != null && + firstElement.getDatum().getCompoundSymbol().getSymbol().equals(original)) { + return list; + } + return null; + } } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java index 937aab8..9e43c28 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java @@ -123,40 +123,45 @@ private void processReturn(LispContainer reply) { LispInteger replyId = (LispInteger) reply.getItems().get(2); try { SlimeRequest request = requests.get(replyId.getValue()); - if (request instanceof SltEval) { - SltEval eval = (SltEval) request; + if (request instanceof Eval) { + Eval eval = (Eval) request; eval.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof SwankEvalAndGrab) { - SwankEvalAndGrab evalAndGrab = (SwankEvalAndGrab) request; + if (request instanceof EvalAndGrab) { + EvalAndGrab evalAndGrab = (EvalAndGrab) request; evalAndGrab.processReply((LispContainer) reply.getItems().get(1), this::parse); } - if (request instanceof SltInvokeNthRestart) { - SltInvokeNthRestart restart = (SltInvokeNthRestart) request; + if (request instanceof InvokeNthRestart) { + InvokeNthRestart restart = (InvokeNthRestart) request; restart.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof SltFrameLocalsAndCatchTags) { - SltFrameLocalsAndCatchTags frames = (SltFrameLocalsAndCatchTags) request; + if (request instanceof FrameLocalsAndCatchTags) { + FrameLocalsAndCatchTags frames = (FrameLocalsAndCatchTags) request; frames.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof SltInspectFrameVar) { - SltInspectFrameVar frameVar = (SltInspectFrameVar) request; + if (request instanceof InspectFrameVar) { + InspectFrameVar frameVar = (InspectFrameVar) request; frameVar.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof SltInspectNth) { - SltInspectNth inspectNth = (SltInspectNth) request; + if (request instanceof InspectNth) { + InspectNth inspectNth = (InspectNth) request; inspectNth.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof SltInspectorAction) { - SltInspectorAction action = (SltInspectorAction) request; + if (request instanceof InspectorAction) { + InspectorAction action = (InspectorAction) request; action.processReply((LispContainer) reply.getItems().get(1)); } + + if (request instanceof MacroexpandAll) { + MacroexpandAll macroexpandAll = (MacroexpandAll) request; + macroexpandAll.processReply((LispContainer) reply.getItems().get(1)); + } } finally { requests.remove(replyId.getValue()); } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java index 7f87c98..fb57132 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java @@ -206,6 +206,20 @@ public static SwankPacket loadFile(String file, String packageName, String threa return new SwankPacket(formatted); } + public static SwankPacket macroexpand(String form, String packageName, BigInteger continuation) { + return macroexpand(form, "T", packageName, continuation); + } + + public static SwankPacket macroexpand(String form, String threadId, String packageName, BigInteger continuation) { + form = StringUtils.replace(form, "\\", "\\\\"); + form = StringUtils.replace(form, "\"", "\\\""); + packageName = StringUtils.replace(packageName, "\\", "\\\\"); + packageName = StringUtils.replace(packageName, "\"", "\\\""); + String formatted = String.format("(:emacs-rex (swank:swank-macroexpand-all \"%s\") :%s %s %s)", + form, packageName, threadId, continuation); + return new SwankPacket(formatted); + } + private int length; private String expressionSource; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltEval.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/Eval.java similarity index 86% rename from src/main/java/com/en_circle/slt/plugin/swank/requests/SltEval.java rename to src/main/java/com/en_circle/slt/plugin/swank/requests/Eval.java index eacc891..1eeb394 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltEval.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/Eval.java @@ -8,21 +8,21 @@ import java.math.BigInteger; -public class SltEval extends SlimeRequest { +public class Eval extends SlimeRequest { public static SlimeRequest eval(String code, String module, Callback callback) { - return new SltEval(code, module, callback); + return new Eval(code, module, callback); } public static SlimeRequest eval(String code, Callback callback) { - return new SltEval(code, "cl-user", callback); + return new Eval(code, "cl-user", callback); } protected final Callback callback; protected final String module; protected final String code; - protected SltEval(String code, String module, Callback callback) { + protected Eval(String code, String module, Callback callback) { this.callback = callback; this.module = module; this.code = code; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SwankEvalAndGrab.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/EvalAndGrab.java similarity index 88% rename from src/main/java/com/en_circle/slt/plugin/swank/requests/SwankEvalAndGrab.java rename to src/main/java/com/en_circle/slt/plugin/swank/requests/EvalAndGrab.java index 10b80fd..19925f7 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/SwankEvalAndGrab.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/EvalAndGrab.java @@ -12,14 +12,14 @@ import java.util.List; import java.util.function.Function; -public class SwankEvalAndGrab extends SlimeRequest { +public class EvalAndGrab extends SlimeRequest { public static SlimeRequest eval(String code, String module, boolean parse, Callback callback) { - return new SwankEvalAndGrab(code, module, parse, callback); + return new EvalAndGrab(code, module, parse, callback); } public static SlimeRequest eval(String code, boolean parse, Callback callback) { - return new SwankEvalAndGrab(code, "cl-user", parse, callback); + return new EvalAndGrab(code, "cl-user", parse, callback); } protected final Callback callback; @@ -27,7 +27,7 @@ public static SlimeRequest eval(String code, boolean parse, Callback callback) { protected final String code; protected final boolean parse; - protected SwankEvalAndGrab(String code, String module, boolean parse, Callback callback) { + protected EvalAndGrab(String code, String module, boolean parse, Callback callback) { this.callback = callback; this.module = module; this.code = code; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SwankEvalFromVirtualFile.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/EvalFromVirtualFile.java similarity index 80% rename from src/main/java/com/en_circle/slt/plugin/swank/requests/SwankEvalFromVirtualFile.java rename to src/main/java/com/en_circle/slt/plugin/swank/requests/EvalFromVirtualFile.java index a95bad1..60acaf0 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/SwankEvalFromVirtualFile.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/EvalFromVirtualFile.java @@ -5,14 +5,14 @@ import java.math.BigInteger; -public class SwankEvalFromVirtualFile extends SlimeRequest { +public class EvalFromVirtualFile extends SlimeRequest { public static SlimeRequest eval(String code, String filename, int bufferPosition, int lineno, int charno, Callback callback) { return eval(code, filename, bufferPosition, lineno, charno, "cl-user", callback); } public static SlimeRequest eval(String code, String filename, int bufferPosition, int lineno, int charno, String module, Callback callback) { - return new SwankEvalFromVirtualFile(code, module, filename, bufferPosition, lineno, charno, callback); + return new EvalFromVirtualFile(code, module, filename, bufferPosition, lineno, charno, callback); } protected final Callback callback; @@ -23,7 +23,7 @@ public static SlimeRequest eval(String code, String filename, int bufferPosition protected final int lineno; protected final int charno; - protected SwankEvalFromVirtualFile(String code, String module, String filename, int bufferPosition, int lineno, int charno, Callback callback) { + protected EvalFromVirtualFile(String code, String module, String filename, int bufferPosition, int lineno, int charno, Callback callback) { this.callback = callback; this.module = module; this.code = code; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/EvalStringInFrameEval.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/EvalStringInFrameEval.java index ebe4a67..bc9367e 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/EvalStringInFrameEval.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/EvalStringInFrameEval.java @@ -5,7 +5,7 @@ import java.math.BigInteger; -public class EvalStringInFrameEval extends SltEval { +public class EvalStringInFrameEval extends Eval { public static SlimeRequest evalInFrame(String code, BigInteger frame, BigInteger thread, String module, Callback callback) { return new EvalStringInFrameEval(code, frame, thread, module, callback); diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltFrameLocalsAndCatchTags.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/FrameLocalsAndCatchTags.java similarity index 81% rename from src/main/java/com/en_circle/slt/plugin/swank/requests/SltFrameLocalsAndCatchTags.java rename to src/main/java/com/en_circle/slt/plugin/swank/requests/FrameLocalsAndCatchTags.java index e5b2586..4898e52 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltFrameLocalsAndCatchTags.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/FrameLocalsAndCatchTags.java @@ -8,14 +8,14 @@ import java.math.BigInteger; -public class SltFrameLocalsAndCatchTags extends SlimeRequest { +public class FrameLocalsAndCatchTags extends SlimeRequest { public static SlimeRequest getLocals(BigInteger frame, BigInteger threadId, String module, Callback callback) { - return new SltFrameLocalsAndCatchTags(frame, threadId, module, callback); + return new FrameLocalsAndCatchTags(frame, threadId, module, callback); } public static SlimeRequest getLocals(BigInteger frame, BigInteger threadId, Callback callback) { - return new SltFrameLocalsAndCatchTags(frame, threadId, "CL-USER", callback); + return new FrameLocalsAndCatchTags(frame, threadId, "CL-USER", callback); } protected final Callback callback; @@ -23,7 +23,7 @@ public static SlimeRequest getLocals(BigInteger frame, BigInteger threadId, Call protected final BigInteger frame; protected final BigInteger threadId; - protected SltFrameLocalsAndCatchTags(BigInteger frame, BigInteger threadId, String module, Callback callback) { + protected FrameLocalsAndCatchTags(BigInteger frame, BigInteger threadId, String module, Callback callback) { this.callback = callback; this.module = module; this.frame = frame; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectFrameVar.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/InspectFrameVar.java similarity index 82% rename from src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectFrameVar.java rename to src/main/java/com/en_circle/slt/plugin/swank/requests/InspectFrameVar.java index c55a862..99e32f6 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectFrameVar.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/InspectFrameVar.java @@ -8,14 +8,14 @@ import java.math.BigInteger; -public class SltInspectFrameVar extends SlimeRequest { +public class InspectFrameVar extends SlimeRequest { public static SlimeRequest inspectVariable(BigInteger ix, BigInteger frame, BigInteger threadId, String module, Callback callback) { - return new SltInspectFrameVar(ix, frame, threadId, module, callback); + return new InspectFrameVar(ix, frame, threadId, module, callback); } public static SlimeRequest inspectVariable(BigInteger ix, BigInteger frame, BigInteger threadId, Callback callback) { - return new SltInspectFrameVar(ix, frame, threadId, "CL-USER", callback); + return new InspectFrameVar(ix, frame, threadId, "CL-USER", callback); } protected final Callback callback; @@ -24,7 +24,7 @@ public static SlimeRequest inspectVariable(BigInteger ix, BigInteger frame, BigI protected final BigInteger frame; protected final BigInteger threadId; - protected SltInspectFrameVar(BigInteger ix, BigInteger frame, BigInteger threadId, String module, Callback callback) { + protected InspectFrameVar(BigInteger ix, BigInteger frame, BigInteger threadId, String module, Callback callback) { this.callback = callback; this.module = module; this.ix = ix; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectNth.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/InspectNth.java similarity index 84% rename from src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectNth.java rename to src/main/java/com/en_circle/slt/plugin/swank/requests/InspectNth.java index c377e2d..cebee54 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectNth.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/InspectNth.java @@ -8,14 +8,14 @@ import java.math.BigInteger; -public class SltInspectNth extends SlimeRequest { +public class InspectNth extends SlimeRequest { public static SlimeRequest inspectVariable(BigInteger ix, BigInteger threadId, String module, Callback callback) { - return new SltInspectNth(ix, threadId, module, callback); + return new InspectNth(ix, threadId, module, callback); } public static SlimeRequest inspectVariable(BigInteger ix, BigInteger threadId, Callback callback) { - return new SltInspectNth(ix, threadId, "CL-USER", callback); + return new InspectNth(ix, threadId, "CL-USER", callback); } protected final Callback callback; @@ -23,7 +23,7 @@ public static SlimeRequest inspectVariable(BigInteger ix, BigInteger threadId, C protected final BigInteger ix; protected final BigInteger threadId; - protected SltInspectNth(BigInteger ix,BigInteger threadId, String module, Callback callback) { + protected InspectNth(BigInteger ix, BigInteger threadId, String module, Callback callback) { this.callback = callback; this.module = module; this.ix = ix; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectorAction.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/InspectorAction.java similarity index 77% rename from src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectorAction.java rename to src/main/java/com/en_circle/slt/plugin/swank/requests/InspectorAction.java index 9cd8f2f..4d56a68 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInspectorAction.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/InspectorAction.java @@ -8,22 +8,22 @@ import java.math.BigInteger; -public class SltInspectorAction extends SlimeRequest { +public class InspectorAction extends SlimeRequest { - public static SlimeRequest action(ActionType actionType, BigInteger threadId, String module, SltInspectNth.Callback callback) { - return new SltInspectorAction(actionType, threadId, module, callback); + public static SlimeRequest action(ActionType actionType, BigInteger threadId, String module, Callback callback) { + return new InspectorAction(actionType, threadId, module, callback); } - public static SlimeRequest action(ActionType actionType, BigInteger threadId, SltInspectNth.Callback callback) { - return new SltInspectorAction(actionType, threadId, "CL-USER", callback); + public static SlimeRequest action(ActionType actionType, BigInteger threadId, Callback callback) { + return new InspectorAction(actionType, threadId, "CL-USER", callback); } - protected final SltInspectNth.Callback callback; + protected final Callback callback; protected final String module; protected final ActionType actionType; protected final BigInteger threadId; - protected SltInspectorAction(ActionType actionType, BigInteger threadId, String module, SltInspectNth.Callback callback) { + protected InspectorAction(ActionType actionType, BigInteger threadId, String module, Callback callback) { this.callback = callback; this.module = module; this.actionType = actionType; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInvokeNthRestart.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/InvokeNthRestart.java similarity index 83% rename from src/main/java/com/en_circle/slt/plugin/swank/requests/SltInvokeNthRestart.java rename to src/main/java/com/en_circle/slt/plugin/swank/requests/InvokeNthRestart.java index 81d3496..348b511 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/requests/SltInvokeNthRestart.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/InvokeNthRestart.java @@ -7,10 +7,10 @@ import java.math.BigInteger; -public class SltInvokeNthRestart extends SlimeRequest { +public class InvokeNthRestart extends SlimeRequest { public static SlimeRequest nthRestart(BigInteger threadId, BigInteger option, BigInteger nestLevel, String arg, String args, Callback callback) { - return new SltInvokeNthRestart(threadId, option, nestLevel, arg, args, callback); + return new InvokeNthRestart(threadId, option, nestLevel, arg, args, callback); } protected final Callback callback; @@ -20,7 +20,7 @@ public static SlimeRequest nthRestart(BigInteger threadId, BigInteger option, Bi protected final String arg; protected final String args; - protected SltInvokeNthRestart(BigInteger threadId, BigInteger option, BigInteger nestLevel, String arg, String args, Callback callback) { + protected InvokeNthRestart(BigInteger threadId, BigInteger option, BigInteger nestLevel, String arg, String args, Callback callback) { this.threadId = threadId; this.callback = callback; this.restart = option; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/MacroexpandAll.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/MacroexpandAll.java new file mode 100644 index 0000000..489486f --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/MacroexpandAll.java @@ -0,0 +1,48 @@ +package com.en_circle.slt.plugin.swank.requests; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.lisp.LispSymbol; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankPacket; + +import java.math.BigInteger; + +public class MacroexpandAll extends SlimeRequest { + + public static SlimeRequest macroexpand(String form, String module, Callback callback) { + return new MacroexpandAll(form, module, callback); + } + + private final Callback callback; + private final String form; + private final String module; + + public MacroexpandAll(String form, String module, Callback callback) { + this.form = form; + this.module = module; + this.callback = callback; + } + + public void processReply(LispContainer data) { + if (isOk(data)) { + callback.onResult(data.getItems().get(1)); + } + } + + private boolean isOk(LispContainer data) { + return data.getItems().size() > 0 && + data.getItems().get(0) instanceof LispSymbol && + ":ok".equals(((LispSymbol) data.getItems().get(0)).getValue()); + } + + @Override + public SwankPacket createPacket(BigInteger requestId) { + return SwankPacket.macroexpand(form, module, requestId); + } + + public interface Callback { + void onResult(LispElement result); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java b/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java index 1614432..a255c29 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java @@ -5,7 +5,7 @@ import com.en_circle.slt.plugin.lisp.lisp.LispContainer; import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.lisp.lisp.LispString; -import com.en_circle.slt.plugin.swank.requests.SwankEvalAndGrab; +import com.en_circle.slt.plugin.swank.requests.EvalAndGrab; import com.intellij.icons.AllIcons.Actions; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.CustomComponentAction; @@ -54,7 +54,7 @@ public ActionToolbar getActionToolbar() { public void refresh() { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(SwankEvalAndGrab.eval("(slt-core:list-package-names)", true, (result, stdout, parsed) -> { + SltLispEnvironmentProvider.getInstance().sendToLisp(EvalAndGrab.eval("(slt-core:list-package-names)", true, (result, stdout, parsed) -> { resolvePackages(parsed); }), false); } catch (Exception e) { diff --git a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java index 162dfab..78be4c5 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java @@ -4,7 +4,7 @@ import com.en_circle.slt.plugin.SltCommonLispLanguage; import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; -import com.en_circle.slt.plugin.swank.requests.SltEval; +import com.en_circle.slt.plugin.swank.requests.Eval; import com.en_circle.slt.plugin.ui.SltComponent; import com.intellij.execution.console.ConsoleExecuteAction; import com.intellij.execution.console.ConsoleHistoryController; @@ -74,7 +74,7 @@ protected void execute(String code) { protected void eval(String data) { try { if (StringUtils.isNotBlank(data)) { - SltLispEnvironmentProvider.getInstance().sendToLisp(SltEval.eval(data, currentModule, + SltLispEnvironmentProvider.getInstance().sendToLisp(Eval.eval(data, currentModule, result -> languageConsole.print(result + "\n", ConsoleViewContentType.NORMAL_OUTPUT))); } } catch (Exception e) { diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java index 0bd5a70..8740114 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java @@ -7,8 +7,8 @@ import com.en_circle.slt.plugin.swank.debug.SltDebugArgument; import com.en_circle.slt.plugin.swank.debug.SltDebugInfo; import com.en_circle.slt.plugin.swank.debug.SltDebugStackTraceElement; -import com.en_circle.slt.plugin.swank.requests.SltFrameLocalsAndCatchTags; -import com.en_circle.slt.plugin.swank.requests.SltInvokeNthRestart; +import com.en_circle.slt.plugin.swank.requests.FrameLocalsAndCatchTags; +import com.en_circle.slt.plugin.swank.requests.InvokeNthRestart; import com.en_circle.slt.plugin.swank.requests.ThrowToToplevel; import com.intellij.icons.AllIcons.Actions; import com.intellij.openapi.Disposable; @@ -191,7 +191,7 @@ private void actionAccepted(SltDebugAction action, SltDebugInfo debugInfo) { int ix = debugInfo.getActions().indexOf(action); if (action.getArguments().isEmpty()) { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(SltInvokeNthRestart.nthRestart(debugInfo.getThreadId(), + SltLispEnvironmentProvider.getInstance().sendToLisp(InvokeNthRestart.nthRestart(debugInfo.getThreadId(), BigInteger.valueOf(ix), debugInfo.getDebugLevel(), "NIL", "NIL", () -> {})); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -215,7 +215,7 @@ private void actionAccepted(SltDebugAction action, SltDebugInfo debugInfo) { } String args = arguments.size() == 0 ? "NIL" : "(" + String.join(" ", arguments) + ")"; try { - SltLispEnvironmentProvider.getInstance().sendToLisp(SltInvokeNthRestart.nthRestart(debugInfo.getThreadId(), + SltLispEnvironmentProvider.getInstance().sendToLisp(InvokeNthRestart.nthRestart(debugInfo.getThreadId(), BigInteger.valueOf(ix), debugInfo.getDebugLevel(), args, rest, () -> {})); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -250,7 +250,7 @@ private void stackframeClicked(SltDebugStackTraceElement element, SltDebugInfo d } } try { - SltLispEnvironmentProvider.getInstance().sendToLisp(SltFrameLocalsAndCatchTags.getLocals(BigInteger.valueOf(ix), + SltLispEnvironmentProvider.getInstance().sendToLisp(FrameLocalsAndCatchTags.getLocals(BigInteger.valueOf(ix), debugInfo.getThreadId(), result -> { ApplicationManager.getApplication().runWriteAction(() -> { SltFrameInfo frameInfo = new SltFrameInfo(parent.getProject(), debugInfo.getThreadId(), BigInteger.valueOf(ix), diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java index 2d35866..da0be83 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java @@ -4,7 +4,7 @@ import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SltUIConstants; import com.en_circle.slt.plugin.lisp.lisp.*; -import com.en_circle.slt.plugin.swank.requests.SltFrameLocalsAndCatchTags; +import com.en_circle.slt.plugin.swank.requests.FrameLocalsAndCatchTags; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; @@ -115,7 +115,7 @@ private void openInspector(Local local) { private void reloadLocals() { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(SltFrameLocalsAndCatchTags.getLocals(frameId, threadId, result -> { + SltLispEnvironmentProvider.getInstance().sendToLisp(FrameLocalsAndCatchTags.getLocals(frameId, threadId, result -> { ApplicationManager.getApplication().invokeLater(() -> { refreshFrameValues(result); }); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java index 433503f..6647286 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java @@ -7,10 +7,10 @@ import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.swank.debug.SltInspectedObject; import com.en_circle.slt.plugin.swank.debug.SltInspectedObject.SltInspectionElement; -import com.en_circle.slt.plugin.swank.requests.SltInspectFrameVar; -import com.en_circle.slt.plugin.swank.requests.SltInspectNth; -import com.en_circle.slt.plugin.swank.requests.SltInspectorAction; -import com.en_circle.slt.plugin.swank.requests.SltInspectorAction.ActionType; +import com.en_circle.slt.plugin.swank.requests.InspectFrameVar; +import com.en_circle.slt.plugin.swank.requests.InspectNth; +import com.en_circle.slt.plugin.swank.requests.InspectorAction; +import com.en_circle.slt.plugin.swank.requests.InspectorAction.ActionType; import com.en_circle.slt.plugin.ui.debug.SltFrameInfo.Local; import com.intellij.icons.AllIcons.Actions; import com.intellij.openapi.actionSystem.*; @@ -67,7 +67,7 @@ public SltInspector(Project project, BigInteger threadId) { public void loadLocal(Local local, BigInteger frame) { try { SltLispEnvironmentProvider.getInstance() - .sendToLisp(SltInspectFrameVar.inspectVariable(BigInteger.valueOf(local.ix), frame, threadId, + .sendToLisp(InspectFrameVar.inspectVariable(BigInteger.valueOf(local.ix), frame, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -133,7 +133,7 @@ private void navigate(String description) { try { SltLispEnvironmentProvider.getInstance() - .sendToLisp(SltInspectNth.inspectVariable(ix, threadId, result -> + .sendToLisp(InspectNth.inspectVariable(ix, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -151,7 +151,7 @@ private GoBackAction() { public void actionPerformed(@NotNull AnActionEvent event) { try { SltLispEnvironmentProvider.getInstance() - .sendToLisp(SltInspectorAction.action(ActionType.GO_BACK, threadId, result -> + .sendToLisp(InspectorAction.action(ActionType.GO_BACK, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -177,7 +177,7 @@ private GoForwardAction() { public void actionPerformed(@NotNull AnActionEvent event) { try { SltLispEnvironmentProvider.getInstance() - .sendToLisp(SltInspectorAction.action(ActionType.GO_FORWARD, threadId, result -> + .sendToLisp(InspectorAction.action(ActionType.GO_FORWARD, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -203,7 +203,7 @@ private RefreshAction() { public void actionPerformed(@NotNull AnActionEvent event) { try { SltLispEnvironmentProvider.getInstance() - .sendToLisp(SltInspectorAction.action(ActionType.REFRESH, threadId, result -> + .sendToLisp(InspectorAction.action(ActionType.REFRESH, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index dbcbcbb..d9c5089 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -14,6 +14,7 @@ slt.documentation.types.constant=Constant Form slt.documentation.types.specvariable=Special Variable slt.documentation.types.keyword=Keyword slt.documentation.types.class=Class +slt.documentation.macroexpand=Macro expansion: # UI slt.ui.errors.sbcl.start=Failed to Start SBCL From cd5f0bc1c6c1d0efaf4b72ecfebf28b7860bcbf6 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Sun, 15 Jan 2023 23:38:19 +0100 Subject: [PATCH 12/30] added goal --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 94528e1..c8fc0f1 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ You can also open this as a project in Intellij Idea. ## Planned features / goals * [ ] Upload to marketplace when it has enough features +* [ ] Automatic indentation * [x] REPL * [x] Interactive debugging * [ ] Inspection From 0548372a99ca334b19e68382391e3a9a8e106a42 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Mon, 16 Jan 2023 09:05:10 +0100 Subject: [PATCH 13/30] #15 --- .github/dependabot.yml | 7 +++++++ .../slt/plugin/environment/SltSBCLEnvironment.java | 9 +++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..9c087ac --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,7 @@ +version: 2 +updates: + - package-ecosystem: "gradle" + directory: "/" + target-branch: "master" + schedule: + interval: "daily" \ No newline at end of file diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java index 294aad1..cf3d2ca 100644 --- a/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java @@ -3,6 +3,7 @@ import com.en_circle.slt.plugin.environment.SltProcessStreamGobbler.ProcessInitializationWaiter; import com.en_circle.slt.plugin.environment.SltProcessStreamGobbler.WaitForOccurrence; import com.en_circle.slt.templates.SltScriptTemplate; +import com.intellij.openapi.util.io.FileUtil; import org.apache.commons.io.FileUtils; import org.watertemplate.Template; @@ -21,15 +22,19 @@ protected Object prepareProcessEnvironment(SltLispEnvironmentProcessConfiguratio SltSBCLEnvironmentConfiguration c = getConfiguration(configuration); SBCLEnvironment e = new SBCLEnvironment(); try { - e.sltCore = File.createTempFile("slt", ".cl"); + File tempDir = FileUtil.createTempDirectory("SLTinit", ""); + + e.sltCore = new File(tempDir, "slt.cl"); e.sltCore.deleteOnExit(); String sltScriptTemplate = new SltScriptTemplate().render(); FileUtils.write(e.sltCore, sltScriptTemplate, StandardCharsets.UTF_8); - e.serverStartSetup = File.createTempFile("startServer", ".cl"); + e.serverStartSetup = new File(tempDir, "startServer.cl"); e.serverStartSetup.deleteOnExit(); String startScriptTemplate = new SBCLInitScriptTemplate(c, e.sltCore.getAbsolutePath()).render(); FileUtils.write(e.serverStartSetup, startScriptTemplate, StandardCharsets.UTF_8); + + tempDir.deleteOnExit(); } catch (Exception ex) { throw new SltProcessException(ex); } From 957702f1c67d2255152a958dd9137dba80ceae55 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Mon, 16 Jan 2023 09:31:57 +0100 Subject: [PATCH 14/30] changelog --- CHANGELOG.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..fb17c33 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,40 @@ + +## 0.2.0 + +### Added + +- Added first version of inspector - so far only read-only. +To access, start interactive debugging and then click on any local variable. +- Macro expand. When you hover over a symbol that is a macro call in a form, +it will macro expand it in the documentation. Due to async notion, +you need to hover again to see it. + +### Fixes + +- Changed internal environment to be more decoupled + +## 0.1.1 - 230115 + +### Fixes + +- Fixed bug in build without certificates (oops!) +- Fixed package detector to work with `#:` packages +- Fixed settings to correctly restart on change +- Fixed settings to save quicklisp path + +## 0.1.0 - 230115 + +Initial release + +### Added + +- Basic language parsing and lexing +- REPL + - Click on `+` icon to create REPL +- Interactive debugger +- Eval actions - right click menu in editor + - Eval in region + - Eval previous/next/current form + - Eval file of current editor +- Eval file action +- Some basic `.cl`, `.lisp` and `.asdf` templates \ No newline at end of file From 2e4b96c945d1b223e4931eab746e8541bd515921 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Tue, 17 Jan 2023 15:58:40 +0100 Subject: [PATCH 15/30] documentation fix, logo, change of build --- README.md | 7 +- build.gradle.kts | 8 +- gradle.properties | 2 +- .../slt/plugin/SltDocumentationProvider.java | 3 + .../slt/plugin/SltWindowFactory.java | 4 +- src/main/resources/META-INF/pluginIcon.svg | 260 +++++++++++++++++- src/main/resources/logo/logo.svg | 256 +++++++++++++++++ .../resources/messages/SltBundle.properties | 1 + 8 files changed, 524 insertions(+), 17 deletions(-) create mode 100644 src/main/resources/logo/logo.svg diff --git a/README.md b/README.md index c8fc0f1..da165d9 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ [![0.1.0](https://badgen.net/github/milestones/enerccio/SLT/1)](https://github.com/enerccio/SLT/milestone/1) [![0.2.0](https://badgen.net/github/milestones/enerccio/SLT/2)](https://github.com/enerccio/SLT/milestone/2) +![Image](src/main/resources/logo/logo.svg) + **THIS PLUGIN IS EXPERIMENTAL and can crash at any time! Please report all bugs!** This plugin is providing support for Common Lisp for JetBrains IDEs. @@ -23,7 +25,8 @@ IDE capabilities for Common Lisp. Download plugin for your IDE from releases and install it via file. -_ie_ File->Settings->Plugin, click on gear icon and then 'Install plugin from disk' +_ie_ File->Settings->Plugin, click on gear icon and then 'Install plugin from disk' +and then select the downloaded zip (do not unzip the zip) To find out which release applies to you check this table: @@ -94,7 +97,7 @@ You can also open this as a project in Intellij Idea. ### Far futures / possible goals -* [ ] Virtual Environment à la pycharm so you can specify which interpret instance you want +* [ ] SDK Support * [ ] Automatic download of lisp interpret and quicklisp * [ ] Different lisp interpreter support * [ ] Remote connections to interpreters diff --git a/build.gradle.kts b/build.gradle.kts index b5c0c1b..36d6ee5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -27,7 +27,7 @@ sourceSets { // Configure Gradle IntelliJ Plugin // Read more: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html intellij { - version.set("2022.1") + version.set("2022.2") pluginName.set("slt") var ide = System.getenv("TARGET_IDE") if (ide == null || "" == ide) @@ -42,12 +42,12 @@ intellij { tasks { // Set the JVM compatibility versions withType { - sourceCompatibility = "11" - targetCompatibility = "11" + sourceCompatibility = "17" + targetCompatibility = "17" } patchPluginXml { - sinceBuild.set("221") + sinceBuild.set("222") untilBuild.set("231.*") } diff --git a/gradle.properties b/gradle.properties index 80959e1..2057f59 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,4 +1,4 @@ org.gradle.jvmargs=-XX:MaxHeapSize=512m -Xms512m -Xmx1g # CL GO IC IU PS PY PC RD -targetIDE=IC \ No newline at end of file +targetIDE=IU \ No newline at end of file diff --git a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java index ba0a1ef..82c8ce9 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java @@ -70,6 +70,9 @@ private String asHtml(SymbolState state, String packageName, PsiElement element, builder.append(HtmlChunk.text(SltBundle.message("slt.documentation.macroexpand"))); builder.append(HtmlChunk.br()); builder.append(HtmlChunk.raw(macroExpand)); + } else { + builder.append(HtmlChunk.hr()); + builder.append(HtmlChunk.text(SltBundle.message("slt.documentation.macroexpand.generating"))); } } diff --git a/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java b/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java index 72ef420..35b7255 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java +++ b/src/main/java/com/en_circle/slt/plugin/SltWindowFactory.java @@ -15,7 +15,7 @@ public class SltWindowFactory implements ToolWindowFactory { public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { { SltCoreWindow sltCoreWindow = new SltCoreWindow(toolWindow); - ContentFactory contentFactory = ContentFactory.SERVICE.getInstance(); + ContentFactory contentFactory = ContentFactory.getInstance(); Content content = contentFactory.createContent(sltCoreWindow.getContent(), SltBundle.message("slt.ui.process.title"), false); toolWindow.getContentManager().addContent(content); @@ -23,7 +23,7 @@ public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindo { SltDebuggers debugger = new SltDebuggers(toolWindow); - ContentFactory contentFactory = ContentFactory.SERVICE.getInstance(); + ContentFactory contentFactory = ContentFactory.getInstance(); Content content = contentFactory.createContent(debugger.getContent(), SltBundle.message("slt.ui.debuggers.title"), false); debugger.setSelf(content); diff --git a/src/main/resources/META-INF/pluginIcon.svg b/src/main/resources/META-INF/pluginIcon.svg index dcf6b99..51db885 100644 --- a/src/main/resources/META-INF/pluginIcon.svg +++ b/src/main/resources/META-INF/pluginIcon.svg @@ -1,12 +1,256 @@ - - + + - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SLT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/logo/logo.svg b/src/main/resources/logo/logo.svg new file mode 100644 index 0000000..a1f4846 --- /dev/null +++ b/src/main/resources/logo/logo.svg @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SLT + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index d9c5089..5ee27d5 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -15,6 +15,7 @@ slt.documentation.types.specvariable=Special Variable slt.documentation.types.keyword=Keyword slt.documentation.types.class=Class slt.documentation.macroexpand=Macro expansion: +slt.documentation.macroexpand.generating=Generating macro expansion, hover again to see it # UI slt.ui.errors.sbcl.start=Failed to Start SBCL From 455a1abce7a2ec52c3e29c4f51afd4af91a8c015 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Tue, 17 Jan 2023 18:26:01 +0100 Subject: [PATCH 16/30] changelog --- src/main/resources/META-INF/plugin.xml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index e759fcc..b44b753 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -108,4 +108,20 @@ + + ## 0.2.0 + + ### Added + + - Added first version of inspector - so far only read-only. + To access, start interactive debugging and then click on any local variable. + - Macro expand. When you hover over a symbol that is a macro call in a form, + it will macro expand it in the documentation. Due to async notion, + you need to hover again to see it. + + ### Fixes + + - Changed internal environment to be more decoupled + + \ No newline at end of file From 4838318764ffebafa7a294eef5205de55ba72624 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Tue, 17 Jan 2023 21:33:52 +0100 Subject: [PATCH 17/30] #21 - implemented basic feature but it suggests elements without package, will investigate slime --- .../slt/plugin/SltCompletionContributor.java | 14 ++++ .../plugin/SltLispEnvironmentSymbolCache.java | 4 +- .../com/en_circle/slt/plugin/SymbolState.java | 3 +- .../autocomplete/HeadCompletionProvider.java | 65 +++++++++++++++++++ .../CommonLispHighlighterColors.java | 1 + .../highlights/SltColorSettingsPage.java | 1 + .../annotators/SymbolAnnotator.java | 4 ++ .../slt/plugin/lisp/psi/SltPatterns.java | 19 ++++++ .../slt/plugin/swank/SlimeListener.java | 28 ++++---- .../slt/plugin/swank/SwankPacket.java | 12 ++++ .../swank/requests/SimpleCompletion.java | 50 ++++++++++++++ .../slt/tools/SltApplicationUtils.java | 61 +++++++++++++++++ src/main/resources/META-INF/plugin.xml | 2 + .../resources/messages/SltBundle.properties | 1 + src/main/resources/templates/en_US/slt.cl | 6 ++ 15 files changed, 253 insertions(+), 18 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/SltCompletionContributor.java create mode 100644 src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java create mode 100644 src/main/java/com/en_circle/slt/plugin/lisp/psi/SltPatterns.java create mode 100644 src/main/java/com/en_circle/slt/plugin/swank/requests/SimpleCompletion.java create mode 100644 src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java diff --git a/src/main/java/com/en_circle/slt/plugin/SltCompletionContributor.java b/src/main/java/com/en_circle/slt/plugin/SltCompletionContributor.java new file mode 100644 index 0000000..f5112f3 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/SltCompletionContributor.java @@ -0,0 +1,14 @@ +package com.en_circle.slt.plugin; + +import com.en_circle.slt.plugin.autocomplete.HeadCompletionProvider; +import com.en_circle.slt.plugin.lisp.psi.SltPatterns; +import com.intellij.codeInsight.completion.CompletionContributor; +import com.intellij.codeInsight.completion.CompletionType; + +public class SltCompletionContributor extends CompletionContributor { + + public SltCompletionContributor() { + extend(CompletionType.BASIC, SltPatterns.getHeadPattern(), new HeadCompletionProvider()); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java index 701be20..9569e8d 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java +++ b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java @@ -61,7 +61,9 @@ public void run() { public SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element) { SymbolState state = getOrCreateBinding(packageName, symbolName); SymbolState undefinedSymbol = getOrCreateBinding(null, symbolName); - state.containerFiles.add(new WeakReference<>(element.getContainingFile().getVirtualFile())); + if (element != null) { + state.containerFiles.add(new WeakReference<>(element.getContainingFile().getVirtualFile())); + } SymbolBinding currentBinding = state.binding; if (currentBinding == SymbolBinding.NONE) { symbolRefreshQueue.add(state); diff --git a/src/main/java/com/en_circle/slt/plugin/SymbolState.java b/src/main/java/com/en_circle/slt/plugin/SymbolState.java index c32920a..06dd33f 100644 --- a/src/main/java/com/en_circle/slt/plugin/SymbolState.java +++ b/src/main/java/com/en_circle/slt/plugin/SymbolState.java @@ -28,7 +28,8 @@ public SymbolState(String name, String packageName, String symbolName) { public enum SymbolBinding { NONE, FUNCTION, MACRO, SPECIAL_FORM, - CONSTANT, KEYWORD, SPECIAL_VARIABLE, CLASS + CONSTANT, KEYWORD, SPECIAL_VARIABLE, CLASS, + METHOD } @Override diff --git a/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java b/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java new file mode 100644 index 0000000..cfc3378 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java @@ -0,0 +1,65 @@ +package com.en_circle.slt.plugin.autocomplete; + +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.SymbolState; +import com.en_circle.slt.plugin.SymbolState.SymbolBinding; +import com.en_circle.slt.plugin.lisp.LispParserUtil; +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.lisp.LispString; +import com.en_circle.slt.plugin.swank.requests.SimpleCompletion; +import com.en_circle.slt.tools.SltApplicationUtils; +import com.intellij.codeInsight.completion.CompletionParameters; +import com.intellij.codeInsight.completion.CompletionProvider; +import com.intellij.codeInsight.completion.CompletionResultSet; +import com.intellij.codeInsight.lookup.LookupElementBuilder; +import com.intellij.icons.AllIcons.Nodes; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; + +public class HeadCompletionProvider extends CompletionProvider { + @Override + protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet result) { + if (SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()) { + String startedSymbol = result.getPrefixMatcher().getPrefix(); + String packageName = LispParserUtil.getPackage(parameters.getOriginalFile(), parameters.getOffset()); + List builderList = SltApplicationUtils.getAsyncResultNoThrow(finishRequest -> SimpleCompletion + .simpleCompletion(startedSymbol, packageName, lr -> { + List builders = new ArrayList<>(); + try { + if (lr instanceof LispContainer container) { + if (container.getItems().get(0) instanceof LispContainer innerList) { + for (LispElement element : innerList.getItems()) { + if (element instanceof LispString str) { + SymbolState state = SltLispEnvironmentProvider.getInstance() + .refreshSymbolFromServer(null, str.getValue(), null); + LookupElementBuilder builder = LookupElementBuilder.create(str.getValue()); + if (state.binding == SymbolBinding.MACRO) { + builder = builder.withIcon(Nodes.Template); + } else if (state.binding == SymbolBinding.FUNCTION) { + builder = builder.withIcon(Nodes.Function); + } else if (state.binding == SymbolBinding.METHOD) { + builder = builder.withIcon(Nodes.Method); + } else { + builder = builder.withIcon(Nodes.Lambda); + } + builders.add(builder); + } + } + } + } + } finally { + finishRequest.accept(builders); + } + })); + if (builderList != null) { + for (LookupElementBuilder builder : builderList) { + result.addElement(builder); + } + } + } + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java b/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java index a746d59..87e2ea5 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java @@ -22,6 +22,7 @@ public class CommonLispHighlighterColors { public static TextAttributesKey FUNCTION = TextAttributesKey.createTextAttributesKey("CL.FUNCTION", DefaultLanguageHighlighterColors.FUNCTION_CALL); public static TextAttributesKey MACRO = TextAttributesKey.createTextAttributesKey("CL.MACRO", DefaultLanguageHighlighterColors.KEYWORD); public static TextAttributesKey CLASS = TextAttributesKey.createTextAttributesKey("CL.CLASS", DefaultLanguageHighlighterColors.CLASS_NAME); + public static TextAttributesKey METHOD = TextAttributesKey.createTextAttributesKey("CL.METHOD", DefaultLanguageHighlighterColors.INSTANCE_METHOD); public static void setHighlighting(PsiElement element, AnnotationHolder holder, TextAttributesKey key) { // Annotation a = holder.createInfoAnnotation(element, null); diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java index db3ed59..745cafc 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java @@ -34,6 +34,7 @@ public class SltColorSettingsPage implements ColorSettingsPage { new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.macro"), CommonLispHighlighterColors.MACRO), new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.reader"), CommonLispHighlighterColors.SUGAR), new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.class"), CommonLispHighlighterColors.CLASS), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.method"), CommonLispHighlighterColors.METHOD), }; @Override diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java index 8b4e64d..211e262 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java @@ -34,6 +34,10 @@ private void setHighlight(PsiElement element, String name, AnnotationHolder hold CommonLispHighlighterColors.setHighlighting(element, holder, CommonLispHighlighterColors.CLASS); break; + case METHOD: + CommonLispHighlighterColors.setHighlighting(element, holder, + CommonLispHighlighterColors.METHOD); + break; case FUNCTION: CommonLispHighlighterColors.setHighlighting(element, holder, CommonLispHighlighterColors.FUNCTION); diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/psi/SltPatterns.java b/src/main/java/com/en_circle/slt/plugin/lisp/psi/SltPatterns.java new file mode 100644 index 0000000..beafd04 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/lisp/psi/SltPatterns.java @@ -0,0 +1,19 @@ +package com.en_circle.slt.plugin.lisp.psi; + +import com.intellij.patterns.ElementPattern; +import com.intellij.patterns.PlatformPatterns; +import com.intellij.psi.PsiElement; + +public class SltPatterns { + + public static ElementPattern getLParen() { + return PlatformPatterns.psiElement(LispTypes.LPAREN); + } + + public static ElementPattern getHeadPattern() { + return PlatformPatterns.psiElement(LispTypes.SYMBOL_TOKEN) + .afterLeaf("(") + .andNot(PlatformPatterns.psiElement().withParent(LispString.class)); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java index 9e43c28..079219d 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java @@ -123,45 +123,41 @@ private void processReturn(LispContainer reply) { LispInteger replyId = (LispInteger) reply.getItems().get(2); try { SlimeRequest request = requests.get(replyId.getValue()); - if (request instanceof Eval) { - Eval eval = (Eval) request; + if (request instanceof Eval eval) { eval.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof EvalAndGrab) { - EvalAndGrab evalAndGrab = (EvalAndGrab) request; + if (request instanceof EvalAndGrab evalAndGrab) { evalAndGrab.processReply((LispContainer) reply.getItems().get(1), this::parse); } - if (request instanceof InvokeNthRestart) { - InvokeNthRestart restart = (InvokeNthRestart) request; + if (request instanceof InvokeNthRestart restart) { restart.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof FrameLocalsAndCatchTags) { - FrameLocalsAndCatchTags frames = (FrameLocalsAndCatchTags) request; + if (request instanceof FrameLocalsAndCatchTags frames) { frames.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof InspectFrameVar) { - InspectFrameVar frameVar = (InspectFrameVar) request; + if (request instanceof InspectFrameVar frameVar) { frameVar.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof InspectNth) { - InspectNth inspectNth = (InspectNth) request; + if (request instanceof InspectNth inspectNth) { inspectNth.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof InspectorAction) { - InspectorAction action = (InspectorAction) request; + if (request instanceof InspectorAction action) { action.processReply((LispContainer) reply.getItems().get(1)); } - if (request instanceof MacroexpandAll) { - MacroexpandAll macroexpandAll = (MacroexpandAll) request; + if (request instanceof MacroexpandAll macroexpandAll) { macroexpandAll.processReply((LispContainer) reply.getItems().get(1)); } + + if (request instanceof SimpleCompletion simpleCompletion) { + simpleCompletion.processReply((LispContainer) reply.getItems().get(1)); + } } finally { requests.remove(replyId.getValue()); } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java index fb57132..0c60863 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java @@ -220,6 +220,18 @@ public static SwankPacket macroexpand(String form, String threadId, String packa return new SwankPacket(formatted); } + public static SwankPacket simpleCompletion(String prefix, String packageName, String requestPackageName, BigInteger continuation) { + return simpleCompletion(prefix, packageName, "T", requestPackageName, continuation); + } + + public static SwankPacket simpleCompletion(String prefix, String packageName, String threadId, String requestPackageName, BigInteger continuation) { + requestPackageName = StringUtils.replace(requestPackageName, "\\", "\\\\"); + requestPackageName = StringUtils.replace(requestPackageName, "\"", "\\\""); + String formatted = String.format("(:emacs-rex (swank:simple-completions \"%s\" \"%s\") :%s %s %s)", + prefix, packageName, requestPackageName, threadId, continuation); + return new SwankPacket(formatted); + } + private int length; private String expressionSource; diff --git a/src/main/java/com/en_circle/slt/plugin/swank/requests/SimpleCompletion.java b/src/main/java/com/en_circle/slt/plugin/swank/requests/SimpleCompletion.java new file mode 100644 index 0000000..a0ead5f --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/swank/requests/SimpleCompletion.java @@ -0,0 +1,50 @@ +package com.en_circle.slt.plugin.swank.requests; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.lisp.LispSymbol; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankPacket; + +import java.math.BigInteger; + +public class SimpleCompletion extends SlimeRequest { + + public static SlimeRequest simpleCompletion(String prefix, String packageName, Callback callback) { + return new SimpleCompletion(prefix, packageName, "CL-USER", callback); + } + + protected final Callback callback; + protected final String module; + protected final String prefix; + protected final String packageName; + + protected SimpleCompletion(String prefix, String packageName, String module, Callback callback) { + this.callback = callback; + this.module = module; + this.prefix = prefix; + this.packageName = packageName; + } + + public void processReply(LispContainer data) { + if (isOk(data)) { + callback.onResult(data.getItems().get(1)); + } + } + + private boolean isOk(LispContainer data) { + return data.getItems().size() > 0 && + data.getItems().get(0) instanceof LispSymbol && + ":ok".equals(((LispSymbol) data.getItems().get(0)).getValue()); + } + + @Override + public SwankPacket createPacket(BigInteger requestId) { + return SwankPacket.simpleCompletion(prefix, packageName, module, requestId); + } + + public interface Callback { + void onResult(LispElement result); + } + +} diff --git a/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java new file mode 100644 index 0000000..8597d7a --- /dev/null +++ b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java @@ -0,0 +1,61 @@ +package com.en_circle.slt.tools; + +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.application.ex.ApplicationUtil; +import com.intellij.openapi.progress.ProgressIndicatorProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.CyclicBarrier; +import java.util.concurrent.Future; +import java.util.function.Consumer; +import java.util.function.Function; + +public class SltApplicationUtils { + private static final Logger log = LoggerFactory.getLogger(SltApplicationUtils.class); + + public static X getAsyncResultNoThrow(Function, SlimeRequest> request) { + return getAsyncResultNoThrow(request, true); + } + + public static X getAsyncResultNoThrow(Function, SlimeRequest> request, boolean startLisp) { + try { + return getAsyncResult(request, startLisp); + } catch (Exception e) { + log.warn(e.getMessage()); + return null; + } + } + + public static X getAsyncResult(Function, SlimeRequest> request) throws Exception { + return getAsyncResult(request, true); + } + + public static X getAsyncResult(Function, SlimeRequest> request, boolean startLisp) throws Exception { + if (SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive() && !startLisp) { + return null; + } + + Future future = ApplicationManager.getApplication().executeOnPooledThread(() -> { + CyclicBarrier barrier = new CyclicBarrier(2); + List pointer = new ArrayList<>(); + SltLispEnvironmentProvider.getInstance().sendToLisp(request.apply(result -> { + pointer.add(result); + try { + barrier.await(); + } catch (Exception ignored) { + + } + }), startLisp); + barrier.await(); + return pointer.isEmpty() ? null : pointer.get(0); + }); + return ApplicationUtil.runWithCheckCanceled(future, + ProgressIndicatorProvider.getInstance().getProgressIndicator()); + } + +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index b44b753..33bf5fb 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -57,6 +57,8 @@ + + diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index 5ee27d5..fc47ab9 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -36,6 +36,7 @@ slt.ui.colorsettings.function=Function call slt.ui.colorsettings.macro=Macro call slt.ui.colorsettings.reader=Reader macro slt.ui.colorsettings.class=Class +slt.ui.colorsettings.method=Method # Process slt.ui.process.title=SBCL Process diff --git a/src/main/resources/templates/en_US/slt.cl b/src/main/resources/templates/en_US/slt.cl index 82c57ee..a6de7fe 100644 --- a/src/main/resources/templates/en_US/slt.cl +++ b/src/main/resources/templates/en_US/slt.cl @@ -101,6 +101,12 @@ format suitable for Emacs." (describe test-sym) (list :class (get-output-stream-string *standard-output*) (swank:find-source-location (find-class test-sym))))) + ((and (fboundp test-sym) + (typep (symbol-function test-sym) 'generic-function)) + (progn + (describe test-sym) + (list :method (get-output-stream-string *standard-output*) + (swank:find-source-location (symbol-function test-sym))))) ((special-operator-p test-sym) (list :special-form NIL NIL)) ((macro-function test-sym) (progn (describe test-sym) From 6decf3940c0ca299727272145601596b474b73fd Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Tue, 17 Jan 2023 21:57:00 +0100 Subject: [PATCH 18/30] fixed method code highlight --- CHANGELOG.md | 2 ++ .../en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java | 4 ++++ .../com/en_circle/slt/plugin/actions/EvalFileFromEditor.java | 2 ++ 3 files changed, 8 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb17c33..36ceea0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,10 +8,12 @@ To access, start interactive debugging and then click on any local variable. - Macro expand. When you hover over a symbol that is a macro call in a form, it will macro expand it in the documentation. Due to async notion, you need to hover again to see it. +- Basic completion suggestion working ### Fixes - Changed internal environment to be more decoupled +- Fixed code highlight for methods ## 0.1.1 - 230115 diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java index 9569e8d..9b90f88 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java +++ b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java @@ -159,6 +159,10 @@ private void refreshSymbolsBatched(List refreshStates) throws Excep changed |= state.binding != SymbolBinding.CLASS; state.binding = SymbolBinding.CLASS; break; + case ":METHOD": + changed |= state.binding != SymbolBinding.METHOD; + state.binding = SymbolBinding.METHOD; + break; case ":SPECIAL-FORM": changed |= state.binding != SymbolBinding.SPECIAL_FORM; state.binding = SymbolBinding.SPECIAL_FORM; diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalFileFromEditor.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalFileFromEditor.java index dbbe59d..c8a442c 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalFileFromEditor.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalFileFromEditor.java @@ -26,9 +26,11 @@ public void actionPerformed(@NotNull AnActionEvent event) { if (editor != null) { PsiDocumentManager psiMgr = PsiDocumentManager.getInstance(Objects.requireNonNull(editor.getProject())); psiMgr.commitDocument(editor.getDocument()); + FileDocumentManager.getInstance().saveDocument(editor.getDocument()); VirtualFile vf = FileDocumentManager.getInstance().getFile(editor.getDocument()); if (vf != null) { + evaluateFile(editor.getProject(), vf.getPath(), vf); } } From 515a705f215207a6c40f9d1fc2e949a258f05d79 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 18 Jan 2023 16:50:34 +0100 Subject: [PATCH 19/30] preparement for indentation, fixed bad package --- CHANGELOG.md | 1 + .../slt/plugin/SltIndentationContainer.java | 48 +++++++++++++++++++ .../plugin/SltLispEnvironmentProvider.java | 7 +++ .../slt/plugin/swank/SlimeListener.java | 9 ++++ .../slt/plugin/swank/SwankPacket.java | 38 +++++++-------- 5 files changed, 84 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/SltIndentationContainer.java diff --git a/CHANGELOG.md b/CHANGELOG.md index 36ceea0..2579d14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ you need to hover again to see it. - Changed internal environment to be more decoupled - Fixed code highlight for methods +- Fixed bad package when package does not exist ## 0.1.1 - 230115 diff --git a/src/main/java/com/en_circle/slt/plugin/SltIndentationContainer.java b/src/main/java/com/en_circle/slt/plugin/SltIndentationContainer.java new file mode 100644 index 0000000..35bdd2d --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/SltIndentationContainer.java @@ -0,0 +1,48 @@ +package com.en_circle.slt.plugin; + +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.lisp.LispInteger; +import com.en_circle.slt.plugin.lisp.lisp.LispString; + +import java.math.BigInteger; +import java.util.*; + +public class SltIndentationContainer { + + static final SltIndentationContainer INSTANCE = new SltIndentationContainer(); + + private Map indentations = new HashMap<>(); + + public synchronized void update(LispContainer updates) { + for (LispElement element : updates.getItems()) { + LispContainer macro = (LispContainer) element; + LispString symbolNameElement = (LispString) macro.getItems().get(0); + String symbolName = symbolNameElement.getValue(); + IndentationUpdate update = indentations.computeIfAbsent(symbolName, s -> new IndentationUpdate()); + update.name = symbolName.toUpperCase(Locale.ROOT); + update.bodyArg = (macro.getItems().get(1) instanceof LispInteger) ? ((LispInteger) macro.getItems().get(1)).getValue() : null; + update.packages.clear(); + if (macro.getItems().size() > 2 && macro.getItems().get(2) instanceof LispContainer packages) { + for (LispElement packageNameValue : packages.getItems()) { + if (packageNameValue instanceof LispString packageName) { + update.packages.add(packageName.getValue()); + } + } + } + } + } + + public synchronized void clear() { + indentations.clear(); + } + + private static class IndentationUpdate { + + private String name; + private BigInteger bodyArg; + private final Set packages = new HashSet<>(); + + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java index 7b2095d..450524f 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java @@ -4,6 +4,8 @@ import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltLispOutputChangedListener; import com.en_circle.slt.plugin.environment.SltLispEnvironmentConfiguration; import com.en_circle.slt.plugin.environment.SltProcessException; +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.lisp.psi.LispList; import com.en_circle.slt.plugin.swank.SlimeListener; import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; @@ -111,6 +113,7 @@ public void stop() throws Exception { try { client.close(); } finally { + SltIndentationContainer.INSTANCE.clear(); SltLispEnvironmentMacroExpandCache.INSTANCE.clear(); SltLispEnvironmentSymbolCache.INSTANCE.clear(); if (environment != null) { @@ -177,6 +180,10 @@ public String macroexpand(LispList form, String packageName) { return null; } + public void updateIndentation(LispElement element) { + SltIndentationContainer.INSTANCE.update((LispContainer) element); + } + public interface SBCLServerListener extends SltLispOutputChangedListener { void onPreStart(); diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java index 079219d..7f3494c 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java @@ -3,6 +3,7 @@ import com.en_circle.slt.plugin.SltCommonLispFileType; import com.en_circle.slt.plugin.SltCommonLispLanguage; import com.en_circle.slt.plugin.SltCommonLispParserDefinition; +import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.lisp.lisp.*; import com.en_circle.slt.plugin.lisp.psi.LispCoreProjectEnvironment; import com.en_circle.slt.plugin.swank.debug.SltDebugInfo; @@ -92,6 +93,8 @@ private void resolve(String data) { processDebugReturn(reply); } else if (isDebugActivate(reply)) { processDebugActivate(reply); + } else if (isIndentation(reply)) { + SltLispEnvironmentProvider.getInstance().updateIndentation(reply.getItems().get(1)); } } } @@ -204,6 +207,12 @@ private boolean isDebugActivate(LispContainer reply) { ":debug-activate".equals(((LispSymbol) reply.getItems().get(0)).getValue()); } + private boolean isIndentation(LispContainer reply) { + return reply.getItems().size() > 0 && + reply.getItems().get(0) instanceof LispSymbol && + ":indentation-update".equals(((LispSymbol) reply.getItems().get(0)).getValue()); + } + public interface RequestResponseLogger { void logRequest(String request); diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java index 0c60863..111d4cd 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java @@ -40,7 +40,7 @@ public static SwankPacket rpcWriteString(String sexpression) { } public static SwankPacket sltEval(String sexpression, BigInteger continuation) { - return sltEval(sexpression, "CL-USER", continuation); + return sltEval(sexpression, ":CL-USER", continuation); } public static SwankPacket sltEval(String sexpression, String packageName, BigInteger continuation) { @@ -52,7 +52,7 @@ public static SwankPacket sltEval(String sexpression, String packageName, String packageName = StringUtils.replace(packageName, "\"", "\\\""); sexpression = StringUtils.replace(sexpression, "\\", "\\\\"); sexpression = StringUtils.replace(sexpression, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:slt-eval \"%s\") %s %s %s)", + String formatted = String.format("(:emacs-rex (swank:slt-eval \"%s\") \":%s\" %s %s)", sexpression, packageName, thread, continuation); return new SwankPacket(formatted); } @@ -62,13 +62,13 @@ public static SwankPacket evalInFrame(String sexpression, BigInteger frame, Stri packageName = StringUtils.replace(packageName, "\"", "\\\""); sexpression = StringUtils.replace(sexpression, "\\", "\\\\"); sexpression = StringUtils.replace(sexpression, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:eval-string-in-frame \"%s\" %s \"%s\") :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:eval-string-in-frame \"%s\" %s \"%s\") \":%s\" %s %s)", sexpression, frame, packageName, packageName, thread, continuation); return new SwankPacket(formatted); } public static SwankPacket evalRegion(String region, BigInteger continuation) { - return evalRegion(region, "CL-USER", "T", continuation); + return evalRegion(region, ":CL-USER", "T", continuation); } public static SwankPacket evalRegion(String region, String packageName, BigInteger continuation) { @@ -80,13 +80,13 @@ public static SwankPacket evalRegion(String region, String packageName, String t packageName = StringUtils.replace(packageName, "\"", "\\\""); region = StringUtils.replace(region, "\\", "\\\\"); region = StringUtils.replace(region, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:interactive-eval-region \"%s\") :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:interactive-eval-region \"%s\") \":%s\" %s %s)", region, packageName, thread, continuation); return new SwankPacket(formatted); } public static SwankPacket swankEvalAndGrab(String sexpression, BigInteger continuation) { - return swankEvalAndGrab(sexpression, "CL-USER", continuation); + return swankEvalAndGrab(sexpression, ":CL-USER", continuation); } public static SwankPacket swankEvalAndGrab(String sexpression, String packageName, BigInteger continuation) { @@ -98,13 +98,13 @@ public static SwankPacket swankEvalAndGrab(String sexpression, String packageNam packageName = StringUtils.replace(packageName, "\"", "\\\""); sexpression = StringUtils.replace(sexpression, "\\", "\\\\"); sexpression = StringUtils.replace(sexpression, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:eval-and-grab-output \"%s\") :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:eval-and-grab-output \"%s\") \":%s\" %s %s)", sexpression, packageName, thread, continuation); return new SwankPacket(formatted); } public static SwankPacket swankEvalRegion(String code, String filename, int bufferPosition, BigInteger continuation) { - return swankEvalRegion(code, filename, bufferPosition, "CL-USER", continuation); + return swankEvalRegion(code, filename, bufferPosition, ":CL-USER", continuation); } public static SwankPacket swankEvalRegion(String code, String filename, int bufferPosition, String packageName, BigInteger continuation) { @@ -119,7 +119,7 @@ public static SwankPacket swankEvalRegion(String code, String filename, int buff code = StringUtils.replace(code, "\"", "\\\""); filename = StringUtils.replace(filename, "\\", "\\\\"); filename = StringUtils.replace(filename, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:compile-string-region-slt \"%s\" \"%s\" %s \"%s\" :%s) :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:compile-string-region-slt \"%s\" \"%s\" %s \"%s\" :%s) \":%s\" %s %s)", code, filename, bufferPosition, filename, packageName, packageName, thread, continuation); return new SwankPacket(formatted); } @@ -130,7 +130,7 @@ public static SwankPacket invokeNthRestart(BigInteger option, BigInteger level, restartArg = StringUtils.replace(restartArg, "\"", "\\\""); restartArgs = StringUtils.replace(restartArgs, "\\", "\\\\"); restartArgs = StringUtils.replace(restartArgs, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:invoke-nth-restart-slt '%s '%s \"%s\" \"%s\") :CL-USER %s %s)", + String formatted = String.format("(:emacs-rex (swank:invoke-nth-restart-slt '%s '%s \"%s\" \"%s\") \":CL-USER\" %s %s)", level, option, restartArg, restartArgs, threadId, continuation); return new SwankPacket(formatted); } @@ -143,7 +143,7 @@ public static SwankPacket throwToToplevel(BigInteger threadId, BigInteger contin public static SwankPacket frameLocals(BigInteger frame, BigInteger threadId, String packageName, BigInteger continuation) { packageName = StringUtils.replace(packageName, "\\", "\\\\"); packageName = StringUtils.replace(packageName, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:frame-locals-and-catch-tags %s) :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:frame-locals-and-catch-tags %s) \":%s\" %s %s)", frame, packageName, threadId, continuation); return new SwankPacket(formatted); } @@ -151,7 +151,7 @@ public static SwankPacket frameLocals(BigInteger frame, BigInteger threadId, Str public static SwankPacket inspectLocal(BigInteger ix, BigInteger frameId, BigInteger threadId, String packageName, BigInteger continuation) { packageName = StringUtils.replace(packageName, "\\", "\\\\"); packageName = StringUtils.replace(packageName, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:inspect-frame-var %s %s) :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:inspect-frame-var %s %s) \":%s\" %s %s)", frameId, ix, packageName, threadId, continuation); return new SwankPacket(formatted); } @@ -159,7 +159,7 @@ public static SwankPacket inspectLocal(BigInteger ix, BigInteger frameId, BigInt public static SwankPacket frameInspectNth(BigInteger ix, BigInteger threadId, String packageName, BigInteger continuation) { packageName = StringUtils.replace(packageName, "\\", "\\\\"); packageName = StringUtils.replace(packageName, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:inspect-nth-part %s) :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:inspect-nth-part %s) \":%s\" %s %s)", ix, packageName, threadId, continuation); return new SwankPacket(formatted); } @@ -167,7 +167,7 @@ public static SwankPacket frameInspectNth(BigInteger ix, BigInteger threadId, St public static SwankPacket inspectorBack(BigInteger threadId, String packageName, BigInteger continuation) { packageName = StringUtils.replace(packageName, "\\", "\\\\"); packageName = StringUtils.replace(packageName, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:inspector-pop) :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:inspector-pop) \":%s\" %s %s)", packageName, threadId, continuation); return new SwankPacket(formatted); } @@ -175,7 +175,7 @@ public static SwankPacket inspectorBack(BigInteger threadId, String packageName, public static SwankPacket inspectorForward(BigInteger threadId, String packageName, BigInteger continuation) { packageName = StringUtils.replace(packageName, "\\", "\\\\"); packageName = StringUtils.replace(packageName, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:inspector-next) :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:inspector-next) \":%s\" %s %s)", packageName, threadId, continuation); return new SwankPacket(formatted); } @@ -183,7 +183,7 @@ public static SwankPacket inspectorForward(BigInteger threadId, String packageNa public static SwankPacket inspectorRefresh(BigInteger threadId, String packageName, BigInteger continuation) { packageName = StringUtils.replace(packageName, "\\", "\\\\"); packageName = StringUtils.replace(packageName, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:inspector-reinspect) :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:inspector-reinspect) \":%s\" %s %s)", packageName, threadId, continuation); return new SwankPacket(formatted); } @@ -201,7 +201,7 @@ public static SwankPacket loadFile(String file, String packageName, String threa packageName = StringUtils.replace(packageName, "\"", "\\\""); file = StringUtils.replace(file, "\\", "\\\\"); file = StringUtils.replace(file, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:load-file \"%s\") :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:load-file \"%s\") \":%s\" %s %s)", file, packageName, thread, continuation); return new SwankPacket(formatted); } @@ -215,7 +215,7 @@ public static SwankPacket macroexpand(String form, String threadId, String packa form = StringUtils.replace(form, "\"", "\\\""); packageName = StringUtils.replace(packageName, "\\", "\\\\"); packageName = StringUtils.replace(packageName, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:swank-macroexpand-all \"%s\") :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:swank-macroexpand-all \"%s\") \":%s\" %s %s)", form, packageName, threadId, continuation); return new SwankPacket(formatted); } @@ -227,7 +227,7 @@ public static SwankPacket simpleCompletion(String prefix, String packageName, St public static SwankPacket simpleCompletion(String prefix, String packageName, String threadId, String requestPackageName, BigInteger continuation) { requestPackageName = StringUtils.replace(requestPackageName, "\\", "\\\\"); requestPackageName = StringUtils.replace(requestPackageName, "\"", "\\\""); - String formatted = String.format("(:emacs-rex (swank:simple-completions \"%s\" \"%s\") :%s %s %s)", + String formatted = String.format("(:emacs-rex (swank:simple-completions \"%s\" \"%s\") \":%s\" %s %s)", prefix, packageName, requestPackageName, threadId, continuation); return new SwankPacket(formatted); } From e36bddb13cf903d4ff822a0f806a4e98b48cc56f Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 18 Jan 2023 17:39:55 +0100 Subject: [PATCH 20/30] goals lol --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index da165d9..4706140 100644 --- a/README.md +++ b/README.md @@ -101,6 +101,7 @@ You can also open this as a project in Intellij Idea. * [ ] Automatic download of lisp interpret and quicklisp * [ ] Different lisp interpreter support * [ ] Remote connections to interpreters +* [ ] Rewrite everything into ABCL just for purity sake lol ## License From 2376001e6488f3b9665139bad6eed614a10a24c3 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 18 Jan 2023 18:01:58 +0100 Subject: [PATCH 21/30] fixed REFERENCE_LABEL --- CHANGELOG.md | 1 + .../en_circle/slt/plugin/lisp/LispParser.java | 6 +++--- .../com/en_circle/slt/plugin/lisp/Lisp.bnf | 4 ++-- .../resources/templates/en_US/highlight.cl | 18 +++++++++++++++++- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2579d14..38c0462 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ you need to hover again to see it. - Changed internal environment to be more decoupled - Fixed code highlight for methods - Fixed bad package when package does not exist +- Fixed lisp parser, `REFERENCE_LABEL` requiring `datum`, now it is stand alone ## 0.1.1 - 230115 diff --git a/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java b/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java index ce9c7c1..d3fd7fa 100644 --- a/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java +++ b/src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java @@ -94,7 +94,7 @@ private static boolean compound_symbol_0(PsiBuilder b, int l) { } /* ********************************************************** */ - // tested | evaled | pathname | UNDEFINED_SEQUENCE | BIT_ARRAY | CHARACTER + // tested | evaled | pathname | UNDEFINED_SEQUENCE | BIT_ARRAY | CHARACTER | REFERENCE_LABEL // | number | real_pair // | compound_symbol // | string | vector | array | structure | list | pair @@ -108,6 +108,7 @@ public static boolean datum(PsiBuilder b, int l) { if (!r) r = consumeToken(b, UNDEFINED_SEQUENCE); if (!r) r = consumeToken(b, BIT_ARRAY); if (!r) r = consumeToken(b, CHARACTER); + if (!r) r = consumeToken(b, REFERENCE_LABEL); if (!r) r = number(b, l + 1); if (!r) r = real_pair(b, l + 1); if (!r) r = compound_symbol(b, l + 1); @@ -122,13 +123,12 @@ public static boolean datum(PsiBuilder b, int l) { } /* ********************************************************** */ - // REFERENCE_SET | REFERENCE_LABEL | TEST_SUCCESS | COMMA | BACKQUOTE | QUOTE | FUNCTION + // REFERENCE_SET | TEST_SUCCESS | COMMA | BACKQUOTE | QUOTE | FUNCTION public static boolean enhancement(PsiBuilder b, int l) { if (!recursion_guard_(b, l, "enhancement")) return false; boolean r; Marker m = enter_section_(b, l, _NONE_, ENHANCEMENT, ""); r = consumeToken(b, REFERENCE_SET); - if (!r) r = consumeToken(b, REFERENCE_LABEL); if (!r) r = consumeToken(b, TEST_SUCCESS); if (!r) r = consumeToken(b, COMMA); if (!r) r = consumeToken(b, BACKQUOTE); diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf b/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf index 6a5f6f1..4313672 100644 --- a/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf +++ b/src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf @@ -24,9 +24,9 @@ sexpr ::= (enhancement* datum) | comment comment ::= LINE_COMMENT | BLOCK_COMMENT -enhancement ::= REFERENCE_SET | REFERENCE_LABEL | TEST_SUCCESS | COMMA | BACKQUOTE | QUOTE | FUNCTION +enhancement ::= REFERENCE_SET | TEST_SUCCESS | COMMA | BACKQUOTE | QUOTE | FUNCTION -datum ::= tested | evaled | pathname | UNDEFINED_SEQUENCE | BIT_ARRAY | CHARACTER +datum ::= tested | evaled | pathname | UNDEFINED_SEQUENCE | BIT_ARRAY | CHARACTER | REFERENCE_LABEL | number | real_pair | compound_symbol | string | vector | array | structure | list | pair diff --git a/src/main/resources/templates/en_US/highlight.cl b/src/main/resources/templates/en_US/highlight.cl index 01b6746..b27ca8b 100644 --- a/src/main/resources/templates/en_US/highlight.cl +++ b/src/main/resources/templates/en_US/highlight.cl @@ -1 +1,17 @@ -((#x4505) 5) \ No newline at end of file +(defpackage :example + (:use :cl) + (:export foobar)) + +(in-package :example) + +(defun foobar (arg1 &rest bar) + "Implements the foo bar!" + (cons #1=(if bar + (loop for x from 0 to 47 collect + `(arg1 ,x)) + (loop for x from 10 to 20 collect + `(,@arg1 ,x))) + #1#)) + +(defclass foo (T) + ()) \ No newline at end of file From 969836e1154a85829838610c810c085b464469f6 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 18 Jan 2023 18:09:18 +0100 Subject: [PATCH 22/30] fixed line comment highlight --- CHANGELOG.md | 1 + .../slt/plugin/highlights/CommonLispStaticHighlighter.java | 2 +- src/main/resources/templates/en_US/highlight.cl | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 38c0462..8511db5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ you need to hover again to see it. - Fixed code highlight for methods - Fixed bad package when package does not exist - Fixed lisp parser, `REFERENCE_LABEL` requiring `datum`, now it is stand alone +- Fixed line comment highlight color ## 0.1.1 - 230115 diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighter.java b/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighter.java index 4fadb05..1c02cf7 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighter.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighter.java @@ -16,7 +16,7 @@ public class CommonLispStaticHighlighter extends SyntaxHighlighterBase { static { SyntaxHighlighterBase.fillMap(colors, CommonLispHighlighterColors.COMMENT, - LispTypes.COMMENT, LispTypes.BLOCK_COMMENT); + LispTypes.LINE_COMMENT, LispTypes.BLOCK_COMMENT); SyntaxHighlighterBase.fillMap(colors, CommonLispHighlighterColors.PARENTS, LispTypes.LPAREN, LispTypes.RPAREN); SyntaxHighlighterBase.fillMap(colors, CommonLispHighlighterColors.NUMBER, LispTypes.BIT_ARRAY, LispTypes.BINARY_NUMBER_TOKEN, LispTypes.HEX_NUMBER_TOKEN, LispTypes.RADIX_NUMBER_TOKEN, diff --git a/src/main/resources/templates/en_US/highlight.cl b/src/main/resources/templates/en_US/highlight.cl index b27ca8b..088c5c8 100644 --- a/src/main/resources/templates/en_US/highlight.cl +++ b/src/main/resources/templates/en_US/highlight.cl @@ -2,7 +2,7 @@ (:use :cl) (:export foobar)) -(in-package :example) +(in-package :example) ; my example comment (defun foobar (arg1 &rest bar) "Implements the foo bar!" @@ -13,5 +13,8 @@ `(,@arg1 ,x))) #1#)) +#| long +comment |# + (defclass foo (T) ()) \ No newline at end of file From 31b0afa41ac09688efd16400346d90cec886bdcf Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 18 Jan 2023 21:34:22 +0100 Subject: [PATCH 23/30] fixed method generation documentation --- .../java/com/en_circle/slt/plugin/SltDocumentationProvider.java | 2 ++ src/main/resources/messages/SltBundle.properties | 1 + 2 files changed, 3 insertions(+) diff --git a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java index 82c8ce9..0e00986 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java @@ -38,6 +38,8 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider { return SltBundle.message("slt.documentation.types.keyword") + " " + text; case CLASS: return SltBundle.message("slt.documentation.types.class") + " " + text; + case METHOD: + return SltBundle.message("slt.documentation.types.method") + " " + text; } } return null; diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index fc47ab9..ed28d59 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -15,6 +15,7 @@ slt.documentation.types.specvariable=Special Variable slt.documentation.types.keyword=Keyword slt.documentation.types.class=Class slt.documentation.macroexpand=Macro expansion: +slt.documentation.types.method=Method slt.documentation.macroexpand.generating=Generating macro expansion, hover again to see it # UI From 91789b3149a52d37ec1ea2d9daa142ece8fa1a3e Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 18 Jan 2023 21:35:02 +0100 Subject: [PATCH 24/30] quick refactor --- .../com/en_circle/slt/plugin/SymbolState.java | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/en_circle/slt/plugin/SymbolState.java b/src/main/java/com/en_circle/slt/plugin/SymbolState.java index 06dd33f..63717b3 100644 --- a/src/main/java/com/en_circle/slt/plugin/SymbolState.java +++ b/src/main/java/com/en_circle/slt/plugin/SymbolState.java @@ -26,12 +26,6 @@ public SymbolState(String name, String packageName, String symbolName) { this.symbolName = symbolName; } - public enum SymbolBinding { - NONE, FUNCTION, MACRO, SPECIAL_FORM, - CONSTANT, KEYWORD, SPECIAL_VARIABLE, CLASS, - METHOD - } - @Override public boolean equals(Object o) { if (this == o) return true; @@ -51,4 +45,16 @@ public int hashCode() { result = 31 * result + (symbolName != null ? symbolName.hashCode() : 0); return result; } + + public enum SymbolBinding { + NONE, + FUNCTION, + MACRO, + SPECIAL_FORM, + CONSTANT, + KEYWORD, + SPECIAL_VARIABLE, + CLASS, + METHOD + } } From 1d054430d0c7f9661cca3a550bf8a70bcaad1efb Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Wed, 18 Jan 2023 22:16:59 +0100 Subject: [PATCH 25/30] quick refactor --- ...BraceMatcher.java => SltBraceMatcher.java} | 2 +- .../highlights/SltColorSettingsPage.java | 30 +++++++-------- ...rColors.java => SltHighlighterColors.java} | 2 +- ...lighter.java => SltStaticHighlighter.java} | 12 +++--- ....java => SltStaticHighlighterFactory.java} | 4 +- .../annotators/StaticHighlightAnnotator.java | 6 +-- .../annotators/SymbolAnnotator.java | 38 +++++++++---------- src/main/resources/META-INF/plugin.xml | 6 +-- 8 files changed, 50 insertions(+), 50 deletions(-) rename src/main/java/com/en_circle/slt/plugin/highlights/{CommonLispBraceMatcher.java => SltBraceMatcher.java} (92%) rename src/main/java/com/en_circle/slt/plugin/highlights/{CommonLispHighlighterColors.java => SltHighlighterColors.java} (98%) rename src/main/java/com/en_circle/slt/plugin/highlights/{CommonLispStaticHighlighter.java => SltStaticHighlighter.java} (71%) rename src/main/java/com/en_circle/slt/plugin/highlights/{CommonLispStaticHighlighterFactory.java => SltStaticHighlighterFactory.java} (78%) diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispBraceMatcher.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceMatcher.java similarity index 92% rename from src/main/java/com/en_circle/slt/plugin/highlights/CommonLispBraceMatcher.java rename to src/main/java/com/en_circle/slt/plugin/highlights/SltBraceMatcher.java index 013bbc9..024f9fc 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispBraceMatcher.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceMatcher.java @@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class CommonLispBraceMatcher implements PairedBraceMatcher { +public class SltBraceMatcher implements PairedBraceMatcher { private static final BracePair[] PAIRS = new BracePair[] { new BracePair(LispTypes.LPAREN, LispTypes.RPAREN, true), diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java index 745cafc..4136409 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltColorSettingsPage.java @@ -21,20 +21,20 @@ public class SltColorSettingsPage implements ColorSettingsPage { public static final String DEMO_CODE = new CodeHighlightTemplate().render(); private static final AttributesDescriptor[] DESCRIPTORS = new AttributesDescriptor[] { - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.parenthesis"), CommonLispHighlighterColors.PARENTS), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.number"), CommonLispHighlighterColors.NUMBER), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.stringliteral"), CommonLispHighlighterColors.STRING), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.comment"), CommonLispHighlighterColors.COMMENT), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.keyword"), CommonLispHighlighterColors.KEYWORD), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.helper"), CommonLispHighlighterColors.DEFUN_FORM), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.specvariable"), CommonLispHighlighterColors.SPECIAL_VARIABLE), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.constant"), CommonLispHighlighterColors.CONSTANT), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.specialform"), CommonLispHighlighterColors.SPECIAL_FORM), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.function"), CommonLispHighlighterColors.FUNCTION), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.macro"), CommonLispHighlighterColors.MACRO), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.reader"), CommonLispHighlighterColors.SUGAR), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.class"), CommonLispHighlighterColors.CLASS), - new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.method"), CommonLispHighlighterColors.METHOD), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.parenthesis"), SltHighlighterColors.PARENTS), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.number"), SltHighlighterColors.NUMBER), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.stringliteral"), SltHighlighterColors.STRING), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.comment"), SltHighlighterColors.COMMENT), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.keyword"), SltHighlighterColors.KEYWORD), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.helper"), SltHighlighterColors.DEFUN_FORM), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.specvariable"), SltHighlighterColors.SPECIAL_VARIABLE), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.constant"), SltHighlighterColors.CONSTANT), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.specialform"), SltHighlighterColors.SPECIAL_FORM), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.function"), SltHighlighterColors.FUNCTION), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.macro"), SltHighlighterColors.MACRO), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.reader"), SltHighlighterColors.SUGAR), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.class"), SltHighlighterColors.CLASS), + new AttributesDescriptor(SltBundle.message("slt.ui.colorsettings.method"), SltHighlighterColors.METHOD), }; @Override @@ -44,7 +44,7 @@ public class SltColorSettingsPage implements ColorSettingsPage { @Override public @NotNull SyntaxHighlighter getHighlighter() { - return new CommonLispStaticHighlighter(); + return new SltStaticHighlighter(); } @Override diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltHighlighterColors.java similarity index 98% rename from src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java rename to src/main/java/com/en_circle/slt/plugin/highlights/SltHighlighterColors.java index 87e2ea5..9740cc6 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispHighlighterColors.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltHighlighterColors.java @@ -7,7 +7,7 @@ import com.intellij.openapi.editor.colors.TextAttributesKey; import com.intellij.psi.PsiElement; -public class CommonLispHighlighterColors { +public class SltHighlighterColors { public static TextAttributesKey COMMENT = TextAttributesKey.createTextAttributesKey("CL.COMMENT", DefaultLanguageHighlighterColors.BLOCK_COMMENT); public static TextAttributesKey PARENTS = TextAttributesKey.createTextAttributesKey("CL.PARENTS", DefaultLanguageHighlighterColors.PARENTHESES); diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighter.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighter.java similarity index 71% rename from src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighter.java rename to src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighter.java index 1c02cf7..2646add 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighter.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighter.java @@ -10,19 +10,19 @@ import java.util.HashMap; -public class CommonLispStaticHighlighter extends SyntaxHighlighterBase { +public class SltStaticHighlighter extends SyntaxHighlighterBase { private static final HashMap colors = new HashMap<>(); static { - SyntaxHighlighterBase.fillMap(colors, CommonLispHighlighterColors.COMMENT, + SyntaxHighlighterBase.fillMap(colors, SltHighlighterColors.COMMENT, LispTypes.LINE_COMMENT, LispTypes.BLOCK_COMMENT); - SyntaxHighlighterBase.fillMap(colors, CommonLispHighlighterColors.PARENTS, LispTypes.LPAREN, LispTypes.RPAREN); - SyntaxHighlighterBase.fillMap(colors, CommonLispHighlighterColors.NUMBER, + SyntaxHighlighterBase.fillMap(colors, SltHighlighterColors.PARENTS, LispTypes.LPAREN, LispTypes.RPAREN); + SyntaxHighlighterBase.fillMap(colors, SltHighlighterColors.NUMBER, LispTypes.BIT_ARRAY, LispTypes.BINARY_NUMBER_TOKEN, LispTypes.HEX_NUMBER_TOKEN, LispTypes.RADIX_NUMBER_TOKEN, LispTypes.REAL_NUMBER, LispTypes.INTEGER_NUMBER, LispTypes.RATIO_NUMBER); - SyntaxHighlighterBase.fillMap(colors, CommonLispHighlighterColors.STRING, LispTypes.STRING_TOKEN); - SyntaxHighlighterBase.fillMap(colors, CommonLispHighlighterColors.SUGAR, + SyntaxHighlighterBase.fillMap(colors, SltHighlighterColors.STRING, LispTypes.STRING_TOKEN); + SyntaxHighlighterBase.fillMap(colors, SltHighlighterColors.SUGAR, LispTypes.FUNCTION, LispTypes.UNINTERN, LispTypes.REFERENCE_SET, LispTypes.REFERENCE_LABEL, LispTypes.TEST_SUCCESS, LispTypes.TEST_FALURE, LispTypes.EVAL_VALUE, LispTypes.ARRAY_START, LispTypes.PATHNAME_INDICATOR, LispTypes.STRUCTURE_TOKEN); diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighterFactory.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighterFactory.java similarity index 78% rename from src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighterFactory.java rename to src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighterFactory.java index d0d4049..03d1023 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/CommonLispStaticHighlighterFactory.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltStaticHighlighterFactory.java @@ -7,11 +7,11 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -public class CommonLispStaticHighlighterFactory extends SyntaxHighlighterFactory { +public class SltStaticHighlighterFactory extends SyntaxHighlighterFactory { @Override public @NotNull SyntaxHighlighter getSyntaxHighlighter(@Nullable Project project, @Nullable VirtualFile virtualFile) { - return new CommonLispStaticHighlighter(); + return new SltStaticHighlighter(); } } diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/StaticHighlightAnnotator.java b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/StaticHighlightAnnotator.java index 9c6234b..e36b125 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/StaticHighlightAnnotator.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/StaticHighlightAnnotator.java @@ -1,6 +1,6 @@ package com.en_circle.slt.plugin.highlights.annotators; -import com.en_circle.slt.plugin.highlights.CommonLispHighlighterColors; +import com.en_circle.slt.plugin.highlights.SltHighlighterColors; import com.en_circle.slt.plugin.lisp.psi.LispTypes; import com.intellij.lang.ASTNode; import com.intellij.lang.annotation.AnnotationHolder; @@ -14,8 +14,8 @@ public class StaticHighlightAnnotator implements Annotator { public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder holder) { ASTNode node = element.getNode(); if (node != null && LispTypes.REAL_PAIR.equals(node.getElementType())) { - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.NUMBER); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.NUMBER); } } diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java index 211e262..aceba70 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java @@ -2,7 +2,7 @@ import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SymbolState; -import com.en_circle.slt.plugin.highlights.CommonLispHighlighterColors; +import com.en_circle.slt.plugin.highlights.SltHighlighterColors; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; import com.intellij.lang.annotation.AnnotationHolder; @@ -24,43 +24,43 @@ public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder hold private void setHighlight(PsiElement element, String name, AnnotationHolder holder, SymbolState state) { if (name.startsWith("&")) - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.DEFUN_FORM); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.DEFUN_FORM); switch (state.binding) { case NONE: break; case CLASS: - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.CLASS); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.CLASS); break; case METHOD: - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.METHOD); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.METHOD); break; case FUNCTION: - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.FUNCTION); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.FUNCTION); break; case MACRO: - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.MACRO); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.MACRO); break; case SPECIAL_FORM: - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.SPECIAL_FORM); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.SPECIAL_FORM); break; case CONSTANT: - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.CONSTANT); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.CONSTANT); break; case SPECIAL_VARIABLE: - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.SPECIAL_VARIABLE); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.SPECIAL_VARIABLE); break; case KEYWORD: - CommonLispHighlighterColors.setHighlighting(element, holder, - CommonLispHighlighterColors.KEYWORD); + SltHighlighterColors.setHighlighting(element, holder, + SltHighlighterColors.KEYWORD); break; } } diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 33bf5fb..4443847 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -38,15 +38,15 @@ anchor="bottom" icon="/icons/fileicon.svg"/> + implementationClass="com.en_circle.slt.plugin.highlights.SltBraceMatcher"/> + implementationClass="com.en_circle.slt.plugin.highlights.SltStaticHighlighter"/> + implementationClass="com.en_circle.slt.plugin.highlights.SltStaticHighlighterFactory"/> From bac36ff65a38a435d1c7fa2f0173783e79f2ce5c Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Thu, 19 Jan 2023 00:18:32 +0100 Subject: [PATCH 26/30] massive refactor to service --- .../slt/plugin/SltDocumentationProvider.java | 7 +- .../plugin/SltLispEnvironmentProvider.java | 196 ------------ .../slt/plugin/actions/EvalActionBase.java | 10 +- .../slt/plugin/actions/EvalFile.java | 3 +- .../slt/plugin/actions/EvalRegionAction.java | 6 +- .../autocomplete/HeadCompletionProvider.java | 13 +- .../annotators/SymbolAnnotator.java | 4 +- .../slt/plugin/lisp/LispParserUtil.java | 16 +- .../SltDirectNavigationProvider.java | 4 +- .../slt/plugin/references/SltReference.java | 4 +- .../services/lisp/LispEnvironmentService.java | 67 ++++ .../lisp/LispEnvironmentServiceImpl.java | 288 ++++++++++++++++++ .../components}/SltIndentationContainer.java | 6 +- .../SltLispEnvironmentMacroExpandCache.java | 10 +- .../SltLispEnvironmentSymbolCache.java | 31 +- .../settings/SltSettingsConfigurable.java | 21 +- .../slt/plugin/swank/SlimeListener.java | 21 +- .../plugin/ui/PackageSelectorComponent.java | 24 +- .../slt/plugin/ui/SltCoreWindow.java | 47 +-- .../slt/plugin/ui/console/SltConsole.java | 7 +- .../slt/plugin/ui/debug/SltDebuggerImpl.java | 10 +- .../slt/plugin/ui/debug/SltDebuggers.java | 10 +- .../slt/plugin/ui/debug/SltFrameConsole.java | 4 +- .../slt/plugin/ui/debug/SltFrameInfo.java | 17 +- .../slt/plugin/ui/debug/SltInspector.java | 19 +- .../com/en_circle/slt/tools/ProjectUtils.java | 23 ++ .../slt/tools/SltApplicationUtils.java | 22 +- src/main/resources/META-INF/plugin.xml | 5 +- .../resources/messages/SltBundle.properties | 1 + src/main/resources/templates/en_US/slt.cl | 8 +- 30 files changed, 544 insertions(+), 360 deletions(-) delete mode 100644 src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java create mode 100644 src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentService.java create mode 100644 src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java rename src/main/java/com/en_circle/slt/plugin/{ => services/lisp/components}/SltIndentationContainer.java (89%) rename src/main/java/com/en_circle/slt/plugin/{ => services/lisp/components}/SltLispEnvironmentMacroExpandCache.java (90%) rename src/main/java/com/en_circle/slt/plugin/{ => services/lisp/components}/SltLispEnvironmentSymbolCache.java (92%) create mode 100644 src/main/java/com/en_circle/slt/tools/ProjectUtils.java diff --git a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java index 0e00986..e74281f 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/SltDocumentationProvider.java @@ -5,6 +5,7 @@ import com.en_circle.slt.plugin.lisp.psi.LispList; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; import com.en_circle.slt.plugin.lisp.psi.impl.LispPsiImplUtil; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.intellij.lang.documentation.AbstractDocumentationProvider; import com.intellij.openapi.util.text.HtmlBuilder; import com.intellij.openapi.util.text.HtmlChunk; @@ -20,7 +21,7 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider { String text = LispPsiImplUtil.getSExpressionHead(element); if (text != null) { String packageName = LispParserUtil.getPackage(element); - SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, text, element); + SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text, element); switch (state.binding) { case NONE: return SltBundle.message("slt.documentation.types.symbol") + " " + text; @@ -50,7 +51,7 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider { if (element instanceof LispSymbol) { String text = element.getText(); String packageName = LispParserUtil.getPackage(element); - SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, text, element); + SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text, element); return asHtml(state, packageName, element, originalElement); } return null; @@ -64,7 +65,7 @@ private String asHtml(SymbolState state, String packageName, PsiElement element, LispList form = LispParserUtil.getIfHead(element); if (form != null && state.binding == SymbolBinding.MACRO) { - String macroExpand = SltLispEnvironmentProvider.getInstance().macroexpand(form, packageName); + String macroExpand = LispEnvironmentService.getInstance(element.getProject()).macroexpand(form, packageName); if (macroExpand != null) { macroExpand = StringUtils.replace(StringUtils.replace(macroExpand, " ", " "), "\n", HtmlChunk.br().toString()); diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java b/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java deleted file mode 100644 index 450524f..0000000 --- a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentProvider.java +++ /dev/null @@ -1,196 +0,0 @@ -package com.en_circle.slt.plugin; - -import com.en_circle.slt.plugin.environment.SltLispEnvironment; -import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltLispOutputChangedListener; -import com.en_circle.slt.plugin.environment.SltLispEnvironmentConfiguration; -import com.en_circle.slt.plugin.environment.SltProcessException; -import com.en_circle.slt.plugin.lisp.lisp.LispContainer; -import com.en_circle.slt.plugin.lisp.lisp.LispElement; -import com.en_circle.slt.plugin.lisp.psi.LispList; -import com.en_circle.slt.plugin.swank.SlimeListener; -import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; -import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; -import com.en_circle.slt.plugin.swank.SlimeRequest; -import com.en_circle.slt.plugin.swank.SwankClient; -import com.intellij.openapi.Disposable; -import com.intellij.openapi.project.Project; -import com.intellij.openapi.util.Disposer; -import com.intellij.psi.PsiElement; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.function.Supplier; - -public class SltLispEnvironmentProvider implements Disposable { - private static final Logger log = LoggerFactory.getLogger(SltLispEnvironmentProvider.class); - - private static final SltLispEnvironmentProvider INSTANCE = new SltLispEnvironmentProvider(); - - public static SltLispEnvironmentProvider getInstance() { - return INSTANCE; - } - - private Supplier environmentProvider; - private SltLispEnvironment environment; - private SltLispEnvironmentConfiguration.Builder configurationBuilder; - private SltLispEnvironmentConfiguration configuration; - - private SwankClient client; - private SlimeListener slimeListener; - private Project project; - private RequestResponseLogger logger; - private DebugInterface debugInterface; - private final List serverListeners = Collections.synchronizedList(new ArrayList<>()); - - public void start() throws Exception { - for (SBCLServerListener listener : serverListeners) { - listener.onPreStart(); - } - - if (configuration == null) { - configuration = configurationBuilder - .setListener((output, newData) -> { - for (SBCLServerListener listener : serverListeners) { - listener.onOutputChanged(output, newData); - } - }) - .build(); - } - environment = environmentProvider.get(); - environment.start(configuration); - - slimeListener = new SlimeListener(project, true, logger, debugInterface); - client = new SwankClient("127.0.0.1", SltState.getInstance().port, slimeListener); - - for (SBCLServerListener listener : serverListeners) { - listener.onPostStart(); - } - } - - public void setEnvironmentProvider(Supplier environmentProvider) { - this.environmentProvider = environmentProvider; - } - - public void setConfigurationBuilder(SltLispEnvironmentConfiguration.Builder configurationBuilder) { - this.configurationBuilder = configurationBuilder; - this.configuration = null; - } - - public void setRequestResponseLogger(RequestResponseLogger logger) { - this.logger = logger; - } - - public void setDebugInterface(DebugInterface debugInterface) { - this.debugInterface = debugInterface; - } - - public void sendToLisp(SlimeRequest request) throws Exception { - sendToLisp(request, true); - } - - public void sendToLisp(SlimeRequest request, boolean startServer) throws Exception { - if (startServer && environment == null || !environment.isActive()) { - start(); - } - if (environment == null || !environment.isActive()) { - if (!startServer) - return; // ignored - throw new SltProcessException("server offline"); - } - - if (slimeListener != null) { - slimeListener.call(request, client); - } - } - - public void stop() throws Exception { - for (SBCLServerListener listener : serverListeners) { - listener.onPreStop(); - } - try { - client.close(); - } finally { - SltIndentationContainer.INSTANCE.clear(); - SltLispEnvironmentMacroExpandCache.INSTANCE.clear(); - SltLispEnvironmentSymbolCache.INSTANCE.clear(); - if (environment != null) { - environment.stop(); - environment = null; - } - } - - for (SBCLServerListener listener : serverListeners) { - listener.onPostStop(); - } - } - - public void addServerListener(SBCLServerListener listener) { - serverListeners.add(listener); - } - - public Project getProject() { - return project; - } - - public void setProject(Project project) { - Disposer.register(project, this); - this.project = project; - } - - public String getGlobalPackage() { - return "CL-USER"; - } - - public SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element) { - return SltLispEnvironmentSymbolCache.INSTANCE.refreshSymbolFromServer(packageName, symbolName, element); - } - - public boolean hasEventsSet() { - return logger != null; - } - - public boolean isLispEnvironmentActive() { - return environment != null && environment.isActive(); - } - - public SltLispEnvironment getEnvironment() { - return environment; - } - - @Override - public void dispose() { - try { - stop(); - } catch (Exception e) { - log.error(e.getMessage()); - log.debug(e.getMessage(), e); - } - } - - public String macroexpand(LispList form, String packageName) { - try { - return SltLispEnvironmentMacroExpandCache.INSTANCE.macroexpand(form, packageName); - } catch (Exception e) { - log.error(e.getMessage()); - log.debug(e.getMessage(), e); - } - return null; - } - - public void updateIndentation(LispElement element) { - SltIndentationContainer.INSTANCE.update((LispContainer) element); - } - - public interface SBCLServerListener extends SltLispOutputChangedListener { - - void onPreStart(); - void onPostStart(); - void onPreStop(); - void onPostStop(); - - } - -} diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java index c0f302b..4845f27 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java @@ -2,7 +2,7 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltCommonLispFileType; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.swank.requests.Eval; import com.en_circle.slt.plugin.swank.requests.EvalFromVirtualFile; import com.en_circle.slt.plugin.swank.requests.LoadFile; @@ -33,14 +33,14 @@ public void update(@NotNull AnActionEvent event) { if (editor != null && event.getProject() != null) { PsiFile file = PsiDocumentManager.getInstance(Objects.requireNonNull(editor.getProject())).getPsiFile(editor.getDocument()); if (file != null && SltCommonLispFileType.INSTANCE.equals(file.getFileType())) { - event.getPresentation().setEnabledAndVisible(SltLispEnvironmentProvider.getInstance().hasEventsSet()); + event.getPresentation().setEnabledAndVisible(true); } } } protected void evaluate(Project project, String buffer, String packageName, Runnable callback) { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(Eval.eval(buffer, packageName, result -> callback.run()), true); + LispEnvironmentService.getInstance(project).sendToLisp(Eval.eval(buffer, packageName, result -> callback.run()), true); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); @@ -49,7 +49,7 @@ protected void evaluate(Project project, String buffer, String packageName, Runn protected void evaluateRegion(Project project, String buffer, String packageName, String filename, int bufferPosition, int lineno, int charno, Runnable callback) { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(EvalFromVirtualFile + LispEnvironmentService.getInstance(project).sendToLisp(EvalFromVirtualFile .eval(buffer, filename, bufferPosition, lineno, charno, packageName, result -> callback.run()), true); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -59,7 +59,7 @@ protected void evaluateRegion(Project project, String buffer, String packageName protected void evaluateFile(Project project, String filename, VirtualFile virtualFile) { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(LoadFile.loadFile(filename), true); + LispEnvironmentService.getInstance(project).sendToLisp(LoadFile.loadFile(filename), true); FileContentUtilCore.reparseFiles(virtualFile); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java index 1310313..51267d6 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalFile.java @@ -2,7 +2,6 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltCommonLispFileType; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.fileEditor.FileEditorManager; @@ -35,7 +34,7 @@ public void update(@NotNull AnActionEvent event) { VirtualFile vf = event.getData(CommonDataKeys.VIRTUAL_FILE); if (vf != null) { if (vf.getFileType().equals(SltCommonLispFileType.INSTANCE)) { - event.getPresentation().setEnabledAndVisible(SltLispEnvironmentProvider.getInstance().hasEventsSet()); + event.getPresentation().setEnabledAndVisible(true); } } } diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalRegionAction.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalRegionAction.java index 6758b12..53e025d 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalRegionAction.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalRegionAction.java @@ -1,8 +1,8 @@ package com.en_circle.slt.plugin.actions; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.lisp.LispParserUtil; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; import com.intellij.openapi.editor.Caret; @@ -59,7 +59,7 @@ public void actionPerformed(@NotNull AnActionEvent event) { int offset = editor.getSelectionModel().getSelectionStart(); evaluate(editor.getProject(), selectedText, LispParserUtil.getPackage(psiFile, offset), () -> { }); } else { - evaluate(editor.getProject(), selectedText, SltLispEnvironmentProvider.getInstance().getGlobalPackage(), () -> { }); + evaluate(editor.getProject(), selectedText, LispEnvironmentService.getInstance(editor.getProject()).getGlobalPackage(), () -> { }); } } } @@ -84,7 +84,7 @@ private void evalEachCaret(Editor editor, String filename, List carets) { PsiDocumentManager psiMgr = PsiDocumentManager.getInstance(Objects.requireNonNull(editor.getProject())); psiMgr.commitDocument(editor.getDocument()); PsiFile psiFile = psiMgr.getPsiFile(editor.getDocument()); - String packageName = SltLispEnvironmentProvider.getInstance().getGlobalPackage(); + String packageName = LispEnvironmentService.getInstance(editor.getProject()).getGlobalPackage(); if (psiFile != null) { packageName = LispParserUtil.getPackage(psiFile, offset); } diff --git a/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java b/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java index cfc3378..8a2d538 100644 --- a/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/autocomplete/HeadCompletionProvider.java @@ -1,12 +1,13 @@ package com.en_circle.slt.plugin.autocomplete; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SymbolState; import com.en_circle.slt.plugin.SymbolState.SymbolBinding; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.lisp.lisp.LispContainer; import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.lisp.lisp.LispString; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; import com.en_circle.slt.plugin.swank.requests.SimpleCompletion; import com.en_circle.slt.tools.SltApplicationUtils; import com.intellij.codeInsight.completion.CompletionParameters; @@ -14,6 +15,7 @@ import com.intellij.codeInsight.completion.CompletionResultSet; import com.intellij.codeInsight.lookup.LookupElementBuilder; import com.intellij.icons.AllIcons.Nodes; +import com.intellij.openapi.project.Project; import com.intellij.util.ProcessingContext; import org.jetbrains.annotations.NotNull; @@ -23,10 +25,13 @@ public class HeadCompletionProvider extends CompletionProvider { @Override protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull ProcessingContext context, @NotNull CompletionResultSet result) { - if (SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()) { + Project project = parameters.getEditor().getProject(); + assert project != null; + + if (LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY) { String startedSymbol = result.getPrefixMatcher().getPrefix(); String packageName = LispParserUtil.getPackage(parameters.getOriginalFile(), parameters.getOffset()); - List builderList = SltApplicationUtils.getAsyncResultNoThrow(finishRequest -> SimpleCompletion + List builderList = SltApplicationUtils.getAsyncResultNoThrow(project, finishRequest -> SimpleCompletion .simpleCompletion(startedSymbol, packageName, lr -> { List builders = new ArrayList<>(); try { @@ -34,7 +39,7 @@ protected void addCompletions(@NotNull CompletionParameters parameters, @NotNull if (container.getItems().get(0) instanceof LispContainer innerList) { for (LispElement element : innerList.getItems()) { if (element instanceof LispString str) { - SymbolState state = SltLispEnvironmentProvider.getInstance() + SymbolState state = LispEnvironmentService.getInstance(project) .refreshSymbolFromServer(null, str.getValue(), null); LookupElementBuilder builder = LookupElementBuilder.create(str.getValue()); if (state.binding == SymbolBinding.MACRO) { diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java index aceba70..1c8d847 100644 --- a/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java +++ b/src/main/java/com/en_circle/slt/plugin/highlights/annotators/SymbolAnnotator.java @@ -1,10 +1,10 @@ package com.en_circle.slt.plugin.highlights.annotators; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SymbolState; import com.en_circle.slt.plugin.highlights.SltHighlighterColors; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.intellij.lang.annotation.AnnotationHolder; import com.intellij.lang.annotation.Annotator; import com.intellij.psi.PsiElement; @@ -17,7 +17,7 @@ public void annotate(@NotNull PsiElement element, @NotNull AnnotationHolder hold if (element instanceof LispSymbol) { String text = element.getText(); String packageName = LispParserUtil.getPackage(element); - SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, text, element); + SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text, element); setHighlight(element, text, holder, state); } } diff --git a/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java b/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java index ae7dd19..86fb991 100644 --- a/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java +++ b/src/main/java/com/en_circle/slt/plugin/lisp/LispParserUtil.java @@ -1,11 +1,12 @@ package com.en_circle.slt.plugin.lisp; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.lisp.lisp.LispUtils; import com.en_circle.slt.plugin.lisp.psi.*; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.intellij.lang.ASTNode; import com.intellij.lang.FileASTNode; import com.intellij.lang.parser.GeneratedParserUtilBase; +import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -19,14 +20,15 @@ public static String getPackage(PsiFile psiFile, int offset) { if (locationNode != null) return getPackage(locationNode.getPsi()); else - return SltLispEnvironmentProvider.getInstance().getGlobalPackage(); + return LispEnvironmentService.getInstance(psiFile.getProject()).getGlobalPackage(); } public static String getPackage(PsiElement element) { + Project project = element.getProject(); while (!(element instanceof LispToplevel)) { element = element.getParent(); if (element == null) { - return SltLispEnvironmentProvider.getInstance().getGlobalPackage(); + return LispEnvironmentService.getInstance(project).getGlobalPackage(); } } PsiElement previous = element.getPrevSibling(); @@ -41,15 +43,14 @@ public static String getPackage(PsiElement element) { previous = previous.getPrevSibling(); } - return SltLispEnvironmentProvider.getInstance().getGlobalPackage(); + return LispEnvironmentService.getInstance(element.getProject()).getGlobalPackage(); } private static LispList isLispList(PsiElement form) { if (form instanceof LispList) { return (LispList) form; } - if (form instanceof LispToplevel) { - LispToplevel toplevel = (LispToplevel) form; + if (form instanceof LispToplevel toplevel) { LispSexpr sexpr = toplevel.getSexpr(); if (sexpr.getDatum() != null && sexpr.getDatum().getList() != null) { return sexpr.getDatum().getList(); @@ -100,13 +101,12 @@ private static String getAsSymbol(LispSexpr seSymbol) { public static LispList getIfHead(PsiElement element) { PsiElement original = element; - while (!(element instanceof LispList)) { + while (!(element instanceof LispList list)) { element = element.getParent(); if (element == null) { return null; } } - LispList list = (LispList) element; LispSexpr firstElement = list.getSexprList().get(0); if (firstElement.getDatum() != null && firstElement.getDatum().getCompoundSymbol() != null && firstElement.getDatum().getCompoundSymbol().getSymbol().equals(original)) { diff --git a/src/main/java/com/en_circle/slt/plugin/references/SltDirectNavigationProvider.java b/src/main/java/com/en_circle/slt/plugin/references/SltDirectNavigationProvider.java index b80a8e1..df2e339 100644 --- a/src/main/java/com/en_circle/slt/plugin/references/SltDirectNavigationProvider.java +++ b/src/main/java/com/en_circle/slt/plugin/references/SltDirectNavigationProvider.java @@ -1,9 +1,9 @@ package com.en_circle.slt.plugin.references; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SymbolState; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.swank.components.SourceLocation; import com.intellij.lang.ASTNode; import com.intellij.lang.FileASTNode; @@ -27,7 +27,7 @@ public class SltDirectNavigationProvider implements DirectNavigationProvider { String packageName = LispParserUtil.getPackage(element); Project project = element.getProject(); String symbolName = ((LispSymbol) element).getName(); - SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, symbolName, element); + SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, symbolName, element); SourceLocation location = state.location; if (location.isFile()) { VirtualFile vf = LocalFileSystem.getInstance().findFileByIoFile(new File(location.getLocation())); diff --git a/src/main/java/com/en_circle/slt/plugin/references/SltReference.java b/src/main/java/com/en_circle/slt/plugin/references/SltReference.java index 8061f63..dcac5f2 100644 --- a/src/main/java/com/en_circle/slt/plugin/references/SltReference.java +++ b/src/main/java/com/en_circle/slt/plugin/references/SltReference.java @@ -1,9 +1,9 @@ package com.en_circle.slt.plugin.references; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SymbolState; import com.en_circle.slt.plugin.lisp.LispParserUtil; import com.en_circle.slt.plugin.lisp.psi.LispSymbol; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.swank.components.SourceLocation; import com.intellij.lang.ASTNode; import com.intellij.lang.FileASTNode; @@ -26,7 +26,7 @@ public SltReference(@NotNull LispSymbol element) { public ResolveResult @NotNull [] multiResolve(boolean incompleteCode) { String symbolName = myElement.getName(); String packageName = LispParserUtil.getPackage(myElement); - SymbolState state = SltLispEnvironmentProvider.getInstance().refreshSymbolFromServer(packageName, symbolName, myElement); + SymbolState state = LispEnvironmentService.getInstance(myElement.getProject()).refreshSymbolFromServer(packageName, symbolName, myElement); SourceLocation location = state.location; if (location.isFile()) { VirtualFile vf = LocalFileSystem.getInstance().findFileByIoFile(new File(location.getLocation())); diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentService.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentService.java new file mode 100644 index 0000000..fdaacf3 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentService.java @@ -0,0 +1,67 @@ +package com.en_circle.slt.plugin.services.lisp; + +import com.en_circle.slt.plugin.SymbolState; +import com.en_circle.slt.plugin.environment.SltLispEnvironment; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltLispOutputChangedListener; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.psi.LispList; +import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; +import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; + + +public interface LispEnvironmentService extends Disposable { + + static LispEnvironmentService getInstance(Project project) { + LispEnvironmentServiceImpl impl = (LispEnvironmentServiceImpl) project.getService(LispEnvironmentService.class); + boolean wasInit = impl.initProject(project); + if (wasInit) { + impl.postInit(); + } + return impl; + } + + void resetConfiguration(); + + void addServerListener(LispEnvironmentListener listener); + + void setRequestResponseLogger(RequestResponseLogger logger); + + void setDebugInterface(DebugInterface debugInterface); + + void start(); + + void stop(); + + void sendToLisp(SlimeRequest request) throws Exception; + + void sendToLisp(SlimeRequest request, boolean startServer) throws Exception; + + String getGlobalPackage(); + + SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element); + + LispEnvironmentState getState(); + + SltLispEnvironment getEnvironment(); + + String macroexpand(LispList form, String packageName); + + void updateIndentation(LispElement element); + + enum LispEnvironmentState { + STOPPED, READY, INITIALIZING + } + + interface LispEnvironmentListener extends SltLispOutputChangedListener { + + void onPreStart(); + void onPostStart(); + void onPreStop(); + void onPostStop(); + + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java new file mode 100644 index 0000000..9054648 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/LispEnvironmentServiceImpl.java @@ -0,0 +1,288 @@ +package com.en_circle.slt.plugin.services.lisp; + +import com.en_circle.slt.plugin.SltBundle; +import com.en_circle.slt.plugin.SltState; +import com.en_circle.slt.plugin.SymbolState; +import com.en_circle.slt.plugin.environment.*; +import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; +import com.en_circle.slt.plugin.lisp.lisp.LispContainer; +import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.lisp.psi.LispList; +import com.en_circle.slt.plugin.services.lisp.components.SltIndentationContainer; +import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentMacroExpandCache; +import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentSymbolCache; +import com.en_circle.slt.plugin.swank.SlimeListener; +import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; +import com.en_circle.slt.plugin.swank.SlimeListener.RequestResponseLogger; +import com.en_circle.slt.plugin.swank.SlimeRequest; +import com.en_circle.slt.plugin.swank.SwankClient; +import com.en_circle.slt.tools.ProjectUtils; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.Messages; +import com.intellij.openapi.wm.ToolWindow; +import com.intellij.openapi.wm.ToolWindowManager; +import com.intellij.psi.PsiElement; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Supplier; + +public class LispEnvironmentServiceImpl implements LispEnvironmentService { + private static final Logger log = LoggerFactory.getLogger(LispEnvironmentServiceImpl.class); + + private Supplier environmentProvider; + private SltLispEnvironment environment; + private SltLispEnvironmentConfiguration.Builder configurationBuilder; + private SltLispEnvironmentConfiguration configuration; + private SwankClient client; + private SlimeListener slimeListener; + private RequestResponseLogger logger; + private DebugInterface debugInterface; + private final List serverListeners = Collections.synchronizedList(new ArrayList<>()); + private volatile boolean starting = false; + + private Project project; + private SltIndentationContainer indentationContainer; + private SltLispEnvironmentSymbolCache symbolCache; + private SltLispEnvironmentMacroExpandCache macroExpandCache; + + public synchronized boolean initProject(Project project) { + if (this.project == null) { + indentationContainer = new SltIndentationContainer(); + symbolCache = new SltLispEnvironmentSymbolCache(project); + macroExpandCache = new SltLispEnvironmentMacroExpandCache(); + this.project = project; + return true; + } + return false; + } + + public void postInit() { + symbolCache.start(); + } + + @Override + public void resetConfiguration() { + this.configurationBuilder = null; + } + + public boolean configured() { + environmentProvider = SltSBCLEnvironment::new; + configurationBuilder = new SltSBCLEnvironmentConfiguration.Builder() + .setExecutable(SltState.getInstance().sbclExecutable) + .setPort(SltState.getInstance().port) + .setQuicklispStartScriptPath(SltState.getInstance().quicklispStartScript) + .setProjectDirectory(ProjectUtils.getCurrentProject().getBasePath()); + + // add validation checks and custom "SDK" + + return true; + } + + @Override + public void addServerListener(LispEnvironmentListener listener) { + serverListeners.add(listener); + } + + @Override + public void setRequestResponseLogger(RequestResponseLogger logger) { + this.logger = logger; + } + + @Override + public void setDebugInterface(DebugInterface debugInterface) { + this.debugInterface = debugInterface; + } + + @Override + public void start() { + starting = true; + ApplicationManager.getApplication().invokeLater(() -> { + try { + ensureToolWindowIsOpen(); + doStart(); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.sbclstart"), e); + Messages.showErrorDialog(ProjectUtils.getCurrentProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + } + }); + } + + private void ensureToolWindowIsOpen() { + ToolWindow toolWindow = ToolWindowManager.getInstance(ProjectUtils.getCurrentProject()) + .getToolWindow("Common Lisp"); + assert toolWindow != null; + toolWindow.show(); + } + + @Override + public void stop() { + ApplicationManager.getApplication().invokeLater(() -> { + try { + doStop(); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.sbclstop"), e); + Messages.showErrorDialog(ProjectUtils.getCurrentProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.stop")); + } + }); + } + + private void doStart() throws Exception { + try { + if (configurationBuilder == null) { + if (!configured()) { + log.warn(SltBundle.message("slt.error.sbclstart")); + Messages.showErrorDialog(ProjectUtils.getCurrentProject(), + SltBundle.message("slt.ui.errors.sbcl.start.noconf"), + SltBundle.message("slt.ui.errors.sbcl.start")); + return; + } + } + + for (LispEnvironmentListener listener : serverListeners) { + listener.onPreStart(); + } + + if (configuration == null) { + configuration = configurationBuilder + .setListener(this::onServerOutput) + .build(); + } + environment = environmentProvider.get(); + environment.start(configuration); + + slimeListener = new SlimeListener(ProjectUtils.getCurrentProject(), true, logger, debugInterface); + client = new SwankClient("127.0.0.1", SltState.getInstance().port, slimeListener); + + for (LispEnvironmentListener listener : serverListeners) { + listener.onPostStart(); + } + } finally { + starting = false; + } + } + + private void onServerOutput(SltOutput output, String newData) { + for (LispEnvironmentListener listener : serverListeners) { + listener.onOutputChanged(output, newData); + } + } + + private void doStop() throws Exception { + for (LispEnvironmentListener listener : serverListeners) { + listener.onPreStop(); + } + try { + client.close(); + } finally { + indentationContainer.clear(); + indentationContainer.clear(); + symbolCache.clear(); + if (environment != null) { + environment.stop(); + environment = null; + } + } + + for (LispEnvironmentListener listener : serverListeners) { + listener.onPostStop(); + } + } + + @Override + public void sendToLisp(SlimeRequest request) throws Exception { + sendToLisp(request, true); + } + + @Override + public void sendToLisp(SlimeRequest request, boolean startServer) throws Exception { + if (startServer && environment == null || !environment.isActive()) { + ApplicationManager.getApplication().invokeLater(() -> { + starting = true; + ApplicationManager.getApplication().invokeLater(() -> { + try { + ensureToolWindowIsOpen(); + doStart(); + doSend(request); + } catch (Exception e) { + log.warn(SltBundle.message("slt.error.sbclstart"), e); + Messages.showErrorDialog(ProjectUtils.getCurrentProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); + } + }); + }); + return; + } + + if (environment == null || !environment.isActive()) { + if (!startServer) + return; // ignored + throw new SltProcessException("server offline"); + } + + doSend(request); + } + + private void doSend(SlimeRequest request) { + if (slimeListener != null) { + slimeListener.call(request, client); + } + } + + @Override + public String getGlobalPackage() { + return "CL-USER"; + } + + @Override + public SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element) { + return symbolCache.refreshSymbolFromServer(packageName, symbolName, element); + } + + @Override + public LispEnvironmentState getState() { + if (starting) { + return LispEnvironmentState.INITIALIZING; + } + if (environment != null && environment.isActive()) { + return LispEnvironmentState.READY; + } + return LispEnvironmentState.STOPPED; + } + + @Override + public SltLispEnvironment getEnvironment() { + return environment; + } + + @Override + public String macroexpand(LispList form, String packageName) { + try { + return macroExpandCache.macroexpand(form, packageName); + } catch (Exception e) { + log.error(e.getMessage()); + log.debug(e.getMessage(), e); + } + return null; + } + + @Override + public void updateIndentation(LispElement element) { + indentationContainer.update((LispContainer) element); + } + + @Override + public void dispose() { + try { + doStop(); + } catch (Exception ignored) { + + } + if (symbolCache != null) + symbolCache.terminate(); + } + +} diff --git a/src/main/java/com/en_circle/slt/plugin/SltIndentationContainer.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltIndentationContainer.java similarity index 89% rename from src/main/java/com/en_circle/slt/plugin/SltIndentationContainer.java rename to src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltIndentationContainer.java index 35bdd2d..daca83c 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltIndentationContainer.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltIndentationContainer.java @@ -1,4 +1,4 @@ -package com.en_circle.slt.plugin; +package com.en_circle.slt.plugin.services.lisp.components; import com.en_circle.slt.plugin.lisp.lisp.LispContainer; import com.en_circle.slt.plugin.lisp.lisp.LispElement; @@ -10,9 +10,7 @@ public class SltIndentationContainer { - static final SltIndentationContainer INSTANCE = new SltIndentationContainer(); - - private Map indentations = new HashMap<>(); + private final Map indentations = new HashMap<>(); public synchronized void update(LispContainer updates) { for (LispElement element : updates.getItems()) { diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentMacroExpandCache.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentMacroExpandCache.java similarity index 90% rename from src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentMacroExpandCache.java rename to src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentMacroExpandCache.java index 2d3372a..599affb 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentMacroExpandCache.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentMacroExpandCache.java @@ -1,12 +1,14 @@ -package com.en_circle.slt.plugin; +package com.en_circle.slt.plugin.services.lisp.components; import com.en_circle.slt.plugin.lisp.lisp.LispString; import com.en_circle.slt.plugin.lisp.lisp.LispUtils; import com.en_circle.slt.plugin.lisp.psi.LispList; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.swank.requests.MacroexpandAll; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; +import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import org.jetbrains.annotations.NotNull; @@ -15,15 +17,13 @@ public class SltLispEnvironmentMacroExpandCache { - public static final SltLispEnvironmentMacroExpandCache INSTANCE = new SltLispEnvironmentMacroExpandCache(); - private final LoadingCache expandedMacros; public SltLispEnvironmentMacroExpandCache() { CacheLoader loader = new CacheLoader<>() { @Override public MacroExpandEntry load(@NotNull SltLispEnvironmentMacroExpandCache.MacroExpandEntry key) throws Exception { - SltLispEnvironmentProvider.getInstance().sendToLisp( + LispEnvironmentService.getInstance(key.project).sendToLisp( MacroexpandAll.macroexpand(key.form, key.packageName, result -> { key.evaluated = LispUtils.unescape(((LispString) result).getValue()); })); @@ -44,6 +44,7 @@ public String macroexpand(LispList form, String packageName) throws Exception { entry.virtualFile = file.getVirtualFile(); entry.modification = file.getModificationStamp(); entry.packageName = packageName; + entry.project = form.getProject(); MacroExpandEntry cachedEntry = expandedMacros.get(entry); if (cachedEntry.modification < entry.modification) { expandedMacros.refresh(cachedEntry); @@ -59,6 +60,7 @@ public void clear() { private static class MacroExpandEntry { + public Project project; private String form; private String packageName; private String evaluated; diff --git a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java similarity index 92% rename from src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java rename to src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java index 9b90f88..493002f 100644 --- a/src/main/java/com/en_circle/slt/plugin/SltLispEnvironmentSymbolCache.java +++ b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentSymbolCache.java @@ -1,11 +1,15 @@ -package com.en_circle.slt.plugin; +package com.en_circle.slt.plugin.services.lisp.components; +import com.en_circle.slt.plugin.SymbolState; import com.en_circle.slt.plugin.SymbolState.SymbolBinding; import com.en_circle.slt.plugin.lisp.lisp.*; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; import com.en_circle.slt.plugin.swank.components.SourceLocation; import com.en_circle.slt.plugin.swank.requests.EvalAndGrab; import com.google.common.collect.Lists; import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiElement; import com.intellij.util.FileContentUtilCore; @@ -18,24 +22,24 @@ public class SltLispEnvironmentSymbolCache extends Thread { - public static final SltLispEnvironmentSymbolCache INSTANCE = new SltLispEnvironmentSymbolCache(); - static { - INSTANCE.start(); - } - private final Map symbolInformation = Collections.synchronizedMap(new HashMap<>()); private final List symbolRefreshQueue = Collections.synchronizedList(new ArrayList<>()); - private SltLispEnvironmentSymbolCache() { + private final Project project; + private volatile boolean active = true; + + public SltLispEnvironmentSymbolCache(Project project) { + this.project = project; + setDaemon(true); setName("SBCL Symbol Cache Thread"); } @Override public void run() { - while (true) { + while (active) { try { - if (SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()) { + if (LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY) { while (symbolRefreshQueue.isEmpty()) { Thread.sleep(1000); } @@ -58,6 +62,10 @@ public void run() { } } + public void terminate() { + active = false; + } + public SymbolState refreshSymbolFromServer(String packageName, String symbolName, PsiElement element) { SymbolState state = getOrCreateBinding(packageName, symbolName); SymbolState undefinedSymbol = getOrCreateBinding(null, symbolName); @@ -131,11 +139,11 @@ private void refreshSymbolsBatched(List refreshStates) throws Excep refreshStates.stream().map(x -> x.name.toUpperCase() + " ").collect(Collectors.joining()) + ")"; request = StringUtils.replace(request, "\"", "\\\""); - SltLispEnvironmentProvider.getInstance().sendToLisp(EvalAndGrab.eval( + LispEnvironmentService.getInstance(project).sendToLisp(EvalAndGrab.eval( String.format( "(slt-core:analyze-symbols (slt-core:read-fix-packages \"%s\"))", request), - SltLispEnvironmentProvider.getInstance().getGlobalPackage(), true, (result, stdout, parsed) -> { + LispEnvironmentService.getInstance(project).getGlobalPackage(), true, (result, stdout, parsed) -> { Set toRefresh = new HashSet<>(); if (parsed.size() == 1 && parsed.get(0).getType() == LispElementType.CONTAINER) { int ix = 0; @@ -236,4 +244,5 @@ public void clear() { symbolInformation.clear(); symbolRefreshQueue.clear(); } + } diff --git a/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java b/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java index 2b558d8..5941efe 100644 --- a/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java +++ b/src/main/java/com/en_circle/slt/plugin/settings/SltSettingsConfigurable.java @@ -1,11 +1,13 @@ package com.en_circle.slt.plugin.settings; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SltState; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; +import com.en_circle.slt.tools.ProjectUtils; import com.intellij.openapi.options.Configurable; import com.intellij.openapi.options.ConfigurationException; -import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.openapi.util.NlsContexts.ConfigurableName; import org.jetbrains.annotations.Nullable; @@ -62,21 +64,18 @@ public void apply() throws ConfigurationException { settings.port = component.getPort(); settings.quicklispStartScript = component.getQuicklispStartScript(); - if (restartServer && SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()) { + Project project = ProjectUtils.getCurrentProject(); + + if (restartServer && LispEnvironmentService.getInstance(project).getState() != LispEnvironmentState.STOPPED) { if (Messages.YES == Messages.showYesNoDialog( SltBundle.message("slt.ui.settings.restart.prompt"), SltBundle.message("slt.ui.settings.restart.title"), SltBundle.message("slt.ui.settings.restart.yes"), SltBundle.message("slt.ui.settings.restart.no"), Messages.getQuestionIcon())) { - try { - SltLispEnvironmentProvider.getInstance().stop(); - SltLispEnvironmentProvider.getInstance().start(); - } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(ProjectManager.getInstance().getDefaultProject(), - e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); - } + LispEnvironmentService.getInstance(project).resetConfiguration(); + LispEnvironmentService.getInstance(project).stop(); + LispEnvironmentService.getInstance(project).start(); } } } diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java index 7f3494c..8a57801 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SlimeListener.java @@ -3,11 +3,12 @@ import com.en_circle.slt.plugin.SltCommonLispFileType; import com.en_circle.slt.plugin.SltCommonLispLanguage; import com.en_circle.slt.plugin.SltCommonLispParserDefinition; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.lisp.lisp.*; import com.en_circle.slt.plugin.lisp.psi.LispCoreProjectEnvironment; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.swank.debug.SltDebugInfo; import com.en_circle.slt.plugin.swank.requests.*; +import com.en_circle.slt.tools.ProjectUtils; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiFile; @@ -68,23 +69,10 @@ private void resolve(String data) { logger.logResponse(data); } - PsiFile source; - if (project == null) { - LispCoreProjectEnvironment projectEnvironment = new LispCoreProjectEnvironment(); - projectEnvironment.getEnvironment() - .registerParserDefinition(SltCommonLispLanguage.INSTANCE, new SltCommonLispParserDefinition()); - PsiFileFactory factory = PsiFileFactory.getInstance(projectEnvironment.getProject()); - source = factory.createFileFromText("swank-reply.cl", SltCommonLispFileType.INSTANCE, data); - } else { - PsiFileFactory factory = PsiFileFactory.getInstance(project); - source = factory.createFileFromText("swank-reply.cl", SltCommonLispFileType.INSTANCE, data); - } - List elements = parse(data); if (elements.size() == 1) { LispElement element = elements.get(0); - if (element instanceof LispContainer) { - LispContainer reply = (LispContainer) element; + if (element instanceof LispContainer reply) { if (isReturn(reply)) { processReturn(reply); } else if (isDebug(reply)) { @@ -94,7 +82,8 @@ private void resolve(String data) { } else if (isDebugActivate(reply)) { processDebugActivate(reply); } else if (isIndentation(reply)) { - SltLispEnvironmentProvider.getInstance().updateIndentation(reply.getItems().get(1)); + Project project = ProjectUtils.getCurrentProject(); + LispEnvironmentService.getInstance(project).updateIndentation(reply.getItems().get(1)); } } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java b/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java index a255c29..22b985d 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/PackageSelectorComponent.java @@ -1,14 +1,17 @@ package com.en_circle.slt.plugin.ui; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.lisp.lisp.LispContainer; import com.en_circle.slt.plugin.lisp.lisp.LispElement; import com.en_circle.slt.plugin.lisp.lisp.LispString; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; import com.en_circle.slt.plugin.swank.requests.EvalAndGrab; +import com.en_circle.slt.tools.ProjectUtils; import com.intellij.icons.AllIcons.Actions; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.actionSystem.ex.CustomComponentAction; +import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectManager; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.Messages; @@ -30,8 +33,11 @@ public class PackageSelectorComponent { private final Supplier currentPackage; private final ComboBox packageComboBox; private PackageChangedListener listener; + private Project project; public PackageSelectorComponent(String id, Supplier currentPackage) { + this.project = ProjectUtils.getCurrentProject(); + this.currentPackage = currentPackage; this.packageComboBox = new ComboBox<>(); this.packageComboBox.addActionListener(e -> { @@ -54,7 +60,7 @@ public ActionToolbar getActionToolbar() { public void refresh() { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(EvalAndGrab.eval("(slt-core:list-package-names)", true, (result, stdout, parsed) -> { + LispEnvironmentService.getInstance(project).sendToLisp(EvalAndGrab.eval("(slt-core:list-package-names)", true, (result, stdout, parsed) -> { resolvePackages(parsed); }), false); } catch (Exception e) { @@ -101,6 +107,11 @@ public void actionPerformed(@NotNull AnActionEvent e) { } + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.EDT; + } + @Override public @NotNull JComponent createCustomComponent(@NotNull Presentation presentation, @NotNull String place) { JPanel panel = new JPanel(new BorderLayout()); @@ -113,7 +124,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY); } } @@ -124,6 +135,11 @@ private RefreshPackagesAction() { super(SltBundle.message("slt.ui.packageselector.refresh"), "", Actions.Refresh); } + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.EDT; + } + @Override public void actionPerformed(@NotNull AnActionEvent e) { refresh(); @@ -133,7 +149,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java b/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java index ffbe9aa..cb22c39 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/SltCoreWindow.java @@ -2,12 +2,10 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltCommonLispFileType; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider.SBCLServerListener; -import com.en_circle.slt.plugin.SltState; import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; -import com.en_circle.slt.plugin.environment.SltSBCLEnvironment; -import com.en_circle.slt.plugin.environment.SltSBCLEnvironmentConfiguration; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentListener; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; import com.en_circle.slt.plugin.ui.console.SltConsole; import com.en_circle.slt.plugin.ui.console.SltREPL; import com.intellij.icons.AllIcons; @@ -15,10 +13,8 @@ import com.intellij.icons.AllIcons.General; import com.intellij.openapi.actionSystem.*; import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.fileEditor.FileEditorManager; import com.intellij.openapi.project.Project; -import com.intellij.openapi.ui.Messages; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.ToolWindow; import com.intellij.psi.PsiFile; @@ -33,8 +29,7 @@ import java.util.Collections; import java.util.List; -public class SltCoreWindow implements SBCLServerListener { - private static final Logger log = Logger.getInstance(SltCoreWindow.class); +public class SltCoreWindow implements LispEnvironmentListener { private final Project project; private final JTextField process; @@ -45,22 +40,14 @@ public class SltCoreWindow implements SBCLServerListener { public SltCoreWindow(ToolWindow toolWindow) { this.project = toolWindow.getProject(); - - SltLispEnvironmentProvider.getInstance().setEnvironmentProvider(SltSBCLEnvironment::new); - SltLispEnvironmentProvider.getInstance().setConfigurationBuilder(new SltSBCLEnvironmentConfiguration.Builder() - .setExecutable(SltState.getInstance().sbclExecutable) - .setPort(SltState.getInstance().port) - .setQuicklispStartScriptPath(SltState.getInstance().quicklispStartScript) - .setProjectDirectory(project.getBasePath())); - SltLispEnvironmentProvider.getInstance().addServerListener(this); - SltLispEnvironmentProvider.getInstance().setProject(toolWindow.getProject()); + LispEnvironmentService.getInstance(project).addServerListener(this); content = new JPanel(new BorderLayout()); components.add(new SltOutputHandlerComponent(this, SltOutput.STDOUT)); components.add(new SltOutputHandlerComponent(this, SltOutput.STDERR)); SltGeneralLog generalLog = new SltGeneralLog(); components.add(generalLog); - SltLispEnvironmentProvider.getInstance().setRequestResponseLogger(generalLog); + LispEnvironmentService.getInstance(project).setRequestResponseLogger(generalLog); createSbclControls(); @@ -99,12 +86,7 @@ private void createSbclControls() { } public void start() { - try { - SltLispEnvironmentProvider.getInstance().start(); - } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstart"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); - } + LispEnvironmentService.getInstance(project).start(); PsiManager psiManager = PsiManager.getInstance(project); List toReparse = new ArrayList<>(); @@ -118,12 +100,7 @@ public void start() { } public void stop() { - try { - SltLispEnvironmentProvider.getInstance().stop(); - } catch (Exception e) { - log.warn(SltBundle.message("slt.error.sbclstop"), e); - Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.stop")); - } + LispEnvironmentService.getInstance(project).stop(); } public JComponent getContent() { @@ -164,7 +141,7 @@ public void onPostStart() { component.onPostStart(); } - process.setText(SltLispEnvironmentProvider.getInstance().getEnvironment().getInformation().getPid()); + process.setText(LispEnvironmentService.getInstance(project).getEnvironment().getInformation().getPid()); } @Override @@ -208,7 +185,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(!SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.STOPPED); } } @@ -227,7 +204,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() != LispEnvironmentState.STOPPED); } } @@ -246,7 +223,7 @@ public void actionPerformed(@NotNull AnActionEvent e) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY); } } diff --git a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java index 78be4c5..7e2e206 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/console/SltConsole.java @@ -2,8 +2,9 @@ import com.en_circle.slt.plugin.SltBundle; import com.en_circle.slt.plugin.SltCommonLispLanguage; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; import com.en_circle.slt.plugin.swank.requests.Eval; import com.en_circle.slt.plugin.ui.SltComponent; import com.intellij.execution.console.ConsoleExecuteAction; @@ -60,7 +61,7 @@ protected void execute(String code) { eval(code); } - }, languageConsoleView -> SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + }, languageConsoleView -> LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY); action.registerCustomShortcutSet(action.getShortcutSet(), languageConsole.getConsoleEditor().getComponent()); new ConsoleHistoryController(new MyConsoleRootType("cl"), null, languageConsole).install(); @@ -74,7 +75,7 @@ protected void execute(String code) { protected void eval(String data) { try { if (StringUtils.isNotBlank(data)) { - SltLispEnvironmentProvider.getInstance().sendToLisp(Eval.eval(data, currentModule, + LispEnvironmentService.getInstance(project).sendToLisp(Eval.eval(data, currentModule, result -> languageConsole.print(result + "\n", ConsoleViewContentType.NORMAL_OUTPUT))); } } catch (Exception e) { diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java index 8740114..786bea4 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggerImpl.java @@ -1,8 +1,8 @@ package com.en_circle.slt.plugin.ui.debug; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SltUIConstants; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.swank.debug.SltDebugAction; import com.en_circle.slt.plugin.swank.debug.SltDebugArgument; import com.en_circle.slt.plugin.swank.debug.SltDebugInfo; @@ -191,7 +191,7 @@ private void actionAccepted(SltDebugAction action, SltDebugInfo debugInfo) { int ix = debugInfo.getActions().indexOf(action); if (action.getArguments().isEmpty()) { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(InvokeNthRestart.nthRestart(debugInfo.getThreadId(), + LispEnvironmentService.getInstance(parent.getProject()).sendToLisp(InvokeNthRestart.nthRestart(debugInfo.getThreadId(), BigInteger.valueOf(ix), debugInfo.getDebugLevel(), "NIL", "NIL", () -> {})); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -215,7 +215,7 @@ private void actionAccepted(SltDebugAction action, SltDebugInfo debugInfo) { } String args = arguments.size() == 0 ? "NIL" : "(" + String.join(" ", arguments) + ")"; try { - SltLispEnvironmentProvider.getInstance().sendToLisp(InvokeNthRestart.nthRestart(debugInfo.getThreadId(), + LispEnvironmentService.getInstance(parent.getProject()).sendToLisp(InvokeNthRestart.nthRestart(debugInfo.getThreadId(), BigInteger.valueOf(ix), debugInfo.getDebugLevel(), args, rest, () -> {})); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); @@ -250,7 +250,7 @@ private void stackframeClicked(SltDebugStackTraceElement element, SltDebugInfo d } } try { - SltLispEnvironmentProvider.getInstance().sendToLisp(FrameLocalsAndCatchTags.getLocals(BigInteger.valueOf(ix), + LispEnvironmentService.getInstance(parent.getProject()).sendToLisp(FrameLocalsAndCatchTags.getLocals(BigInteger.valueOf(ix), debugInfo.getThreadId(), result -> { ApplicationManager.getApplication().runWriteAction(() -> { SltFrameInfo frameInfo = new SltFrameInfo(parent.getProject(), debugInfo.getThreadId(), BigInteger.valueOf(ix), @@ -268,7 +268,7 @@ private void stackframeClicked(SltDebugStackTraceElement element, SltDebugInfo d private void close() { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(new ThrowToToplevel(lastDebugId)); + LispEnvironmentService.getInstance(parent.getProject()).sendToLisp(new ThrowToToplevel(lastDebugId)); } catch (Exception e) { log.warn(SltBundle.message("slt.error.sbclstart"), e); Messages.showErrorDialog(parent.getProject(), e.getMessage(), SltBundle.message("slt.ui.errors.sbcl.start")); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java index b160e60..bb2e642 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltDebuggers.java @@ -1,8 +1,8 @@ package com.en_circle.slt.plugin.ui.debug; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider.SBCLServerListener; import com.en_circle.slt.plugin.environment.SltLispEnvironment.SltOutput; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentListener; import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface; import com.en_circle.slt.plugin.swank.debug.SltDebugInfo; import com.intellij.openapi.application.ApplicationManager; @@ -17,7 +17,7 @@ import java.util.HashMap; import java.util.Map; -public class SltDebuggers implements DebugInterface, SBCLServerListener { +public class SltDebuggers implements DebugInterface, LispEnvironmentListener { private final ToolWindow toolWindow; private final JPanel content; @@ -32,8 +32,8 @@ public SltDebuggers(ToolWindow toolWindow) { this.tabs = new JBTabsImpl(toolWindow.getProject()); this.content.add(this.tabs.getComponent()); - SltLispEnvironmentProvider.getInstance().addServerListener(this); - SltLispEnvironmentProvider.getInstance().setDebugInterface(this); + LispEnvironmentService.getInstance(toolWindow.getProject()).addServerListener(this); + LispEnvironmentService.getInstance(toolWindow.getProject()).setDebugInterface(this); } public JPanel getContent() { diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java index dbb4ad0..a842578 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameConsole.java @@ -1,7 +1,7 @@ package com.en_circle.slt.plugin.ui.debug; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.swank.requests.EvalStringInFrameEval; import com.en_circle.slt.plugin.ui.console.SltConsole; import com.intellij.execution.ui.ConsoleViewContentType; @@ -32,7 +32,7 @@ public SltFrameConsole(Project project, BigInteger threadId, BigInteger frame, R protected void eval(String data) { try { if (StringUtils.isNotBlank(data)) { - SltLispEnvironmentProvider.getInstance().sendToLisp(EvalStringInFrameEval.evalInFrame(data, frame, threadId, currentModule, + LispEnvironmentService.getInstance(project).sendToLisp(EvalStringInFrameEval.evalInFrame(data, frame, threadId, currentModule, result -> { languageConsole.print(result + "\n", ConsoleViewContentType.NORMAL_OUTPUT); onChange.run(); diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java index da0be83..5829bd6 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltFrameInfo.java @@ -1,9 +1,9 @@ package com.en_circle.slt.plugin.ui.debug; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SltUIConstants; import com.en_circle.slt.plugin.lisp.lisp.*; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; import com.en_circle.slt.plugin.swank.requests.FrameLocalsAndCatchTags; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.project.Project; @@ -115,7 +115,7 @@ private void openInspector(Local local) { private void reloadLocals() { try { - SltLispEnvironmentProvider.getInstance().sendToLisp(FrameLocalsAndCatchTags.getLocals(frameId, threadId, result -> { + LispEnvironmentService.getInstance(project).sendToLisp(FrameLocalsAndCatchTags.getLocals(frameId, threadId, result -> { ApplicationManager.getApplication().invokeLater(() -> { refreshFrameValues(result); }); @@ -132,8 +132,7 @@ public JComponent getContent() { public void refreshFrameValues(LispElement localsAndTags) { LispElement locals = ((LispContainer) localsAndTags).getItems().get(0); - if (locals instanceof LispContainer) { - LispContainer locs = (LispContainer) locals; + if (locals instanceof LispContainer locs) { List parsedLocals = new ArrayList<>(); int ix=0; for (LispElement e : locs.getItems()) { @@ -179,11 +178,11 @@ private FrameTableModel(List locals) { @Override public String getColumnName(int column) { - switch (column) { - case 0: return SltBundle.message("slt.ui.debugger.frame.arg"); - case 1: return SltBundle.message("slt.ui.debugger.frame.value"); - } - return null; + return switch (column) { + case 0 -> SltBundle.message("slt.ui.debugger.frame.arg"); + case 1 -> SltBundle.message("slt.ui.debugger.frame.value"); + default -> null; + }; } @Override diff --git a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java index 6647286..ecbc4fa 100644 --- a/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java +++ b/src/main/java/com/en_circle/slt/plugin/ui/debug/SltInspector.java @@ -1,10 +1,11 @@ package com.en_circle.slt.plugin.ui.debug; import com.en_circle.slt.plugin.SltBundle; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; import com.en_circle.slt.plugin.SltUIConstants; import com.en_circle.slt.plugin.lisp.lisp.LispContainer; import com.en_circle.slt.plugin.lisp.lisp.LispElement; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; import com.en_circle.slt.plugin.swank.debug.SltInspectedObject; import com.en_circle.slt.plugin.swank.debug.SltInspectedObject.SltInspectionElement; import com.en_circle.slt.plugin.swank.requests.InspectFrameVar; @@ -66,7 +67,7 @@ public SltInspector(Project project, BigInteger threadId) { public void loadLocal(Local local, BigInteger frame) { try { - SltLispEnvironmentProvider.getInstance() + LispEnvironmentService.getInstance(project) .sendToLisp(InspectFrameVar.inspectVariable(BigInteger.valueOf(local.ix), frame, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { @@ -132,7 +133,7 @@ private void navigate(String description) { BigInteger ix = new BigInteger(parts[1]); try { - SltLispEnvironmentProvider.getInstance() + LispEnvironmentService.getInstance(project) .sendToLisp(InspectNth.inspectVariable(ix, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { @@ -150,7 +151,7 @@ private GoBackAction() { @Override public void actionPerformed(@NotNull AnActionEvent event) { try { - SltLispEnvironmentProvider.getInstance() + LispEnvironmentService.getInstance(project) .sendToLisp(InspectorAction.action(ActionType.GO_BACK, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { @@ -163,7 +164,7 @@ public void actionPerformed(@NotNull AnActionEvent event) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY); } } @@ -176,7 +177,7 @@ private GoForwardAction() { @Override public void actionPerformed(@NotNull AnActionEvent event) { try { - SltLispEnvironmentProvider.getInstance() + LispEnvironmentService.getInstance(project) .sendToLisp(InspectorAction.action(ActionType.GO_FORWARD, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { @@ -189,7 +190,7 @@ public void actionPerformed(@NotNull AnActionEvent event) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() ==LispEnvironmentState.READY); } } @@ -202,7 +203,7 @@ private RefreshAction() { @Override public void actionPerformed(@NotNull AnActionEvent event) { try { - SltLispEnvironmentProvider.getInstance() + LispEnvironmentService.getInstance(project) .sendToLisp(InspectorAction.action(ActionType.REFRESH, threadId, result -> ApplicationManager.getApplication().invokeLater(() -> processResult(result)))); } catch (Exception e) { @@ -215,7 +216,7 @@ public void actionPerformed(@NotNull AnActionEvent event) { public void update(@NotNull AnActionEvent e) { super.update(e); - e.getPresentation().setEnabled(SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive()); + e.getPresentation().setEnabled(LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY); } } diff --git a/src/main/java/com/en_circle/slt/tools/ProjectUtils.java b/src/main/java/com/en_circle/slt/tools/ProjectUtils.java new file mode 100644 index 0000000..86e525d --- /dev/null +++ b/src/main/java/com/en_circle/slt/tools/ProjectUtils.java @@ -0,0 +1,23 @@ +package com.en_circle.slt.tools; + +import com.intellij.openapi.project.Project; +import com.intellij.openapi.project.ProjectManager; +import com.intellij.openapi.wm.WindowManager; + +import java.awt.*; + +public class ProjectUtils { + + public static Project getCurrentProject() { + Project[] projects = ProjectManager.getInstance().getOpenProjects(); + Project activeProject = null; + for (Project project : projects) { + Window window = WindowManager.getInstance().suggestParentWindow(project); + if (window != null && window.isActive()) { + activeProject = project; + } + } + return activeProject; + } + +} diff --git a/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java index 8597d7a..0d47db0 100644 --- a/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java +++ b/src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java @@ -1,10 +1,12 @@ package com.en_circle.slt.tools; -import com.en_circle.slt.plugin.SltLispEnvironmentProvider; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService; +import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService.LispEnvironmentState; import com.en_circle.slt.plugin.swank.SlimeRequest; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.ex.ApplicationUtil; import com.intellij.openapi.progress.ProgressIndicatorProvider; +import com.intellij.openapi.project.Project; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,32 +20,32 @@ public class SltApplicationUtils { private static final Logger log = LoggerFactory.getLogger(SltApplicationUtils.class); - public static X getAsyncResultNoThrow(Function, SlimeRequest> request) { - return getAsyncResultNoThrow(request, true); + public static X getAsyncResultNoThrow(Project project, Function, SlimeRequest> request) { + return getAsyncResultNoThrow(project, request, true); } - public static X getAsyncResultNoThrow(Function, SlimeRequest> request, boolean startLisp) { + public static X getAsyncResultNoThrow(Project project, Function, SlimeRequest> request, boolean startLisp) { try { - return getAsyncResult(request, startLisp); + return getAsyncResult(project, request, startLisp); } catch (Exception e) { log.warn(e.getMessage()); return null; } } - public static X getAsyncResult(Function, SlimeRequest> request) throws Exception { - return getAsyncResult(request, true); + public static X getAsyncResult(Project project, Function, SlimeRequest> request) throws Exception { + return getAsyncResult(project, request, true); } - public static X getAsyncResult(Function, SlimeRequest> request, boolean startLisp) throws Exception { - if (SltLispEnvironmentProvider.getInstance().isLispEnvironmentActive() && !startLisp) { + public static X getAsyncResult(Project project, Function, SlimeRequest> request, boolean startLisp) throws Exception { + if (LispEnvironmentService.getInstance(project).getState() == LispEnvironmentState.READY && !startLisp) { return null; } Future future = ApplicationManager.getApplication().executeOnPooledThread(() -> { CyclicBarrier barrier = new CyclicBarrier(2); List pointer = new ArrayList<>(); - SltLispEnvironmentProvider.getInstance().sendToLisp(request.apply(result -> { + LispEnvironmentService.getInstance(project).sendToLisp(request.apply(result -> { pointer.add(result); try { barrier.await(); diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 4443847..9481760 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -13,6 +13,9 @@ messages.SltBundle + + @@ -35,7 +38,7 @@ + anchor="bottom" icon="/icons/fileicon.svg" /> diff --git a/src/main/resources/messages/SltBundle.properties b/src/main/resources/messages/SltBundle.properties index ed28d59..f418b83 100644 --- a/src/main/resources/messages/SltBundle.properties +++ b/src/main/resources/messages/SltBundle.properties @@ -21,6 +21,7 @@ slt.documentation.macroexpand.generating=Generating macro expansion, hover again # UI slt.ui.errors.sbcl.start=Failed to Start SBCL slt.ui.errors.sbcl.stop=Failed to Stop SBCL +slt.ui.errors.sbcl.start.noconf=No configuration set up slt.ui.packageselector.title=Current package: slt.ui.packageselector.refresh=Refresh Packages diff --git a/src/main/resources/templates/en_US/slt.cl b/src/main/resources/templates/en_US/slt.cl index a6de7fe..68ed20f 100644 --- a/src/main/resources/templates/en_US/slt.cl +++ b/src/main/resources/templates/en_US/slt.cl @@ -97,10 +97,6 @@ format suitable for Emacs." (let ((*standard-output* (make-string-output-stream))) (cond ((not test-sym) (list NIL NIL NIL)) - ((find-class test-sym NIL) (progn - (describe test-sym) - (list :class (get-output-stream-string *standard-output*) - (swank:find-source-location (find-class test-sym))))) ((and (fboundp test-sym) (typep (symbol-function test-sym) 'generic-function)) (progn @@ -129,6 +125,10 @@ format suitable for Emacs." ((constantp test-sym) (progn (describe test-sym) (list :constant (get-output-stream-string *standard-output*) NIL))) + ((find-class test-sym NIL) (progn + (describe test-sym) + (list :class (get-output-stream-string *standard-output*) + (swank:find-source-location (find-class test-sym))))) (T (list NIL NIL NIL)))))) (defun analyze-symbols (symbols) From 9f7b976d43f63666d058a9c3997df873d65c1a87 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 20 Jan 2023 09:42:28 +0100 Subject: [PATCH 27/30] manual brace highlight, so I don't have to deal with "smart" insertion --- .../slt/plugin/actions/EvalActionBase.java | 5 + .../highlights/SltBraceHighlighter.java | 510 ++++++++++++++++++ .../plugin/highlights/SltBraceMatcher.java | 31 -- src/main/resources/META-INF/plugin.xml | 6 +- 4 files changed, 518 insertions(+), 34 deletions(-) create mode 100644 src/main/java/com/en_circle/slt/plugin/highlights/SltBraceHighlighter.java delete mode 100644 src/main/java/com/en_circle/slt/plugin/highlights/SltBraceMatcher.java diff --git a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java index 4845f27..2a0d225 100644 --- a/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java +++ b/src/main/java/com/en_circle/slt/plugin/actions/EvalActionBase.java @@ -6,6 +6,7 @@ import com.en_circle.slt.plugin.swank.requests.Eval; import com.en_circle.slt.plugin.swank.requests.EvalFromVirtualFile; import com.en_circle.slt.plugin.swank.requests.LoadFile; +import com.intellij.openapi.actionSystem.ActionUpdateThread; import com.intellij.openapi.actionSystem.AnAction; import com.intellij.openapi.actionSystem.AnActionEvent; import com.intellij.openapi.actionSystem.CommonDataKeys; @@ -67,4 +68,8 @@ protected void evaluateFile(Project project, String filename, VirtualFile virtua } } + @Override + public @NotNull ActionUpdateThread getActionUpdateThread() { + return ActionUpdateThread.EDT; + } } diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceHighlighter.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceHighlighter.java new file mode 100644 index 0000000..32d5bf2 --- /dev/null +++ b/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceHighlighter.java @@ -0,0 +1,510 @@ +package com.en_circle.slt.plugin.highlights; + +import com.en_circle.slt.plugin.SltCommonLispFileType; +import com.en_circle.slt.plugin.SltCommonLispLanguage; +import com.en_circle.slt.plugin.lisp.psi.LispTypes; +import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory; +import com.intellij.codeInsight.highlighting.BraceHighlightingHandler; +import com.intellij.codeInsight.highlighting.BraceMatchingUtil; +import com.intellij.codeInsight.highlighting.BraceMatchingUtil.BraceHighlightingAndNavigationContext; +import com.intellij.codeInsight.template.impl.TemplateManagerImpl; +import com.intellij.codeInsight.template.impl.TemplateState; +import com.intellij.injected.editor.EditorWindow; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.application.ApplicationManager; +import com.intellij.openapi.editor.Document; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.editor.EditorFactory; +import com.intellij.openapi.editor.SelectionModel; +import com.intellij.openapi.editor.colors.CodeInsightColors; +import com.intellij.openapi.editor.colors.TextAttributesKey; +import com.intellij.openapi.editor.event.*; +import com.intellij.openapi.editor.ex.EditorEx; +import com.intellij.openapi.editor.highlighter.EditorHighlighter; +import com.intellij.openapi.editor.highlighter.HighlighterIterator; +import com.intellij.openapi.editor.markup.HighlighterLayer; +import com.intellij.openapi.editor.markup.HighlighterTargetArea; +import com.intellij.openapi.editor.markup.RangeHighlighter; +import com.intellij.openapi.extensions.ExtensionPointUtil; +import com.intellij.openapi.fileEditor.FileEditor; +import com.intellij.openapi.fileEditor.FileEditorManagerEvent; +import com.intellij.openapi.fileEditor.FileEditorManagerListener; +import com.intellij.openapi.fileEditor.TextEditor; +import com.intellij.openapi.fileTypes.BinaryFileTypeDecompilers; +import com.intellij.openapi.fileTypes.FileType; +import com.intellij.openapi.fileTypes.FileTypes; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.startup.StartupActivity; +import com.intellij.openapi.util.Disposer; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.PsiBinaryFile; +import com.intellij.psi.PsiCompiledFile; +import com.intellij.psi.PsiDocumentManager; +import com.intellij.psi.PsiFile; +import com.intellij.psi.tree.IElementType; +import com.intellij.psi.util.PsiUtilBase; +import com.intellij.util.Alarm; +import com.intellij.util.containers.Stack; +import com.intellij.util.text.CharArrayUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +// Copied from IJ source to implement highlight WITHOUT smart insertion! + +public class SltBraceHighlighter implements StartupActivity.DumbAware { + private static final Key> BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY = Key.create("BraceHighlighter.BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY"); + private static final Key LINE_MARKER_IN_EDITOR_KEY = Key.create("BraceHighlighter.LINE_MARKER_IN_EDITOR_KEY"); + + private final Alarm alarm = new Alarm(); + + @Override + public void runActivity(@NotNull Project project) { + if (ApplicationManager.getApplication().isHeadlessEnvironment() && !ApplicationManager.getApplication().isUnitTestMode() || + !IdentifierHighlighterPassFactory.isEnabled()) { + return; + } + + Disposable activityDisposable = ExtensionPointUtil.createExtensionDisposable(this, StartupActivity.POST_STARTUP_ACTIVITY); + // lul they have this in code with warning... + Disposer.register(project, activityDisposable); + registerListeners(project, activityDisposable); + } + + private void registerListeners(@NotNull Project project, @NotNull Disposable parentDisposable) { + EditorEventMulticaster eventMulticaster = EditorFactory.getInstance().getEventMulticaster(); + + eventMulticaster.addCaretListener(new CaretListener() { + @Override + public void caretPositionChanged(@NotNull CaretEvent e) { + if (e.getCaret() != e.getEditor().getCaretModel().getPrimaryCaret()) return; + onCaretUpdate(e.getEditor(), project); + } + + @Override + public void caretAdded(@NotNull CaretEvent e) { + if (e.getCaret() != e.getEditor().getCaretModel().getPrimaryCaret()) return; + onCaretUpdate(e.getEditor(), project); + } + + @Override + public void caretRemoved(@NotNull CaretEvent e) { + onCaretUpdate(e.getEditor(), project); + } + }, parentDisposable); + + SelectionListener selectionListener = new SelectionListener() { + @Override + public void selectionChanged(@NotNull SelectionEvent e) { + alarm.cancelAllRequests(); + Editor editor = e.getEditor(); + if (editor.getProject() != project) { + return; + } + if (isNotCLFile(editor)) { + return; + } + + TextRange oldRange = e.getOldRange(); + TextRange newRange = e.getNewRange(); + if (oldRange != null && newRange != null && oldRange.isEmpty() == newRange.isEmpty()) { + return; + } + updateHighlighted(project, editor); + } + }; + eventMulticaster.addSelectionListener(selectionListener, parentDisposable); + + DocumentListener documentListener = new DocumentListener() { + @Override + public void documentChanged(@NotNull DocumentEvent e) { + alarm.cancelAllRequests(); + EditorFactory.getInstance().editors(e.getDocument(), project).forEach(editor -> updateHighlighted(project, editor)); + } + }; + eventMulticaster.addDocumentListener(documentListener, parentDisposable); + + project.getMessageBus().connect(parentDisposable) + .subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, new FileEditorManagerListener() { + @Override + public void selectionChanged(@NotNull FileEditorManagerEvent e) { + alarm.cancelAllRequests(); + FileEditor oldEditor = e.getOldEditor(); + if (oldEditor instanceof TextEditor) { + clearBraces(((TextEditor) oldEditor).getEditor()); + } + FileEditor newEditor = e.getNewEditor(); + if (newEditor instanceof TextEditor) { + updateHighlighted(project, ((TextEditor) newEditor).getEditor()); + } + } + }); + } + + private boolean isNotCLFile(Editor editor) { + PsiFile file = PsiDocumentManager.getInstance(Objects.requireNonNull(editor.getProject())).getPsiFile(editor.getDocument()); + return file == null || !file.getFileType().equals(SltCommonLispFileType.INSTANCE); + } + + private void clearBraces(Editor editor) { + List highlighters = getHighlightersList(editor); + for (RangeHighlighter highlighter : highlighters) { + highlighter.dispose(); + } + highlighters.clear(); + } + + private void updateHighlighted(Project project, Editor editor) { + ApplicationManager.getApplication().assertIsDispatchThread(); + if (editor.getDocument().isInBulkUpdate()) { + return; + } + + clearBraces(editor); + + PsiFile psiFile = PsiUtilBase.getPsiFileInEditor(editor, project); + if (psiFile == null) return; + if (psiFile instanceof PsiCompiledFile) { + psiFile = ((PsiCompiledFile) psiFile).getDecompiledPsiFile(); + } + if (psiFile instanceof PsiBinaryFile && BinaryFileTypeDecompilers.getInstance().forFileType(psiFile.getFileType()) == null) { + return; + } + + if (editor instanceof EditorEx) { + removeLineMarkers((EditorEx) editor); + } + + if (editor.getSelectionModel().hasSelection()) return; + + if (editor.getSoftWrapModel().isInsideOrBeforeSoftWrap(editor.getCaretModel().getVisualPosition())) return; + + TemplateState state = TemplateManagerImpl.getTemplateState(editor); + if (state != null && !state.isFinished()) return; + + int offset = editor.getCaretModel().getOffset(); + CharSequence chars = editor.getDocument().getCharsSequence(); + + alarm.cancelAllRequests(); + BraceHighlightingAndNavigationContext context = computeHighlightingAndNavigationContext(editor, psiFile, offset); + + if (context != null) { + doHighlight(editor, project, psiFile, context.currentBraceOffset, context.isCaretAfterBrace); + offset = context.currentBraceOffset; + } else if (offset > 0 && offset < chars.length()) { + // There is a possible case that there are paired braces nearby the caret position and the document contains only white + // space symbols between them. We want to highlight such braces as well. + // Example: + // public void test() { + // } + char c = chars.charAt(offset); + boolean searchForward = c != '\n'; + + // Try to find matched brace backwards. + int backwardNonSpaceEndOffset = CharArrayUtil.shiftBackward(chars, offset - 1, "\t ") + 1; + if (backwardNonSpaceEndOffset > 0 && backwardNonSpaceEndOffset < offset) { + context = computeHighlightingAndNavigationContext(editor, psiFile, backwardNonSpaceEndOffset); + if (context != null) { + doHighlight(editor, project, psiFile, context.currentBraceOffset, true); + offset = context.currentBraceOffset; + searchForward = false; + } + } + + // Try to find matched brace forward. + if (searchForward) { + int nextNonSpaceCharOffset = CharArrayUtil.shiftForward(chars, offset, "\t "); + if (nextNonSpaceCharOffset > offset) { + context = computeHighlightingAndNavigationContext(editor, psiFile, nextNonSpaceCharOffset); + if (context != null) { + doHighlight(editor, project, psiFile, context.currentBraceOffset, true); + offset = context.currentBraceOffset; + } + } + } + } + } + + private void doHighlight(Editor editor, Project project, PsiFile psiFile, int offset, boolean isAdjustedPosition) { + if (editor.getFoldingModel().isOffsetCollapsed(offset)) return; + Document document = editor.getDocument(); + + HighlighterIterator iterator = BraceHighlightingHandler.getLazyParsableHighlighterIfAny(project, editor, psiFile).createIterator(offset); + CharSequence chars = document.getCharsSequence(); + + FileType fileType = getFileTypeByOffset(psiFile, offset); + + if (isLBraceToken(iterator, chars, fileType)) { + highlightLeftBrace(editor, iterator, false, fileType, document); + + if (offset > 0 && !isAdjustedPosition && !editor.getSettings().isBlockCursor()) { + iterator = BraceHighlightingHandler.getLazyParsableHighlighterIfAny(project, editor, psiFile).createIterator(offset - 1); + if (isRBraceToken(iterator, chars, fileType)) { + highlightRightBrace(editor, iterator, fileType, document); + } + } + } else if (isRBraceToken(iterator, chars, fileType)) { + highlightRightBrace(editor, iterator, fileType, document); + } + } + + private void highlightRightBrace(Editor editor, @NotNull HighlighterIterator iterator, @NotNull FileType fileType, Document document) { + TextRange brace1 = TextRange.create(iterator.getStart(), iterator.getEnd()); + + boolean matched = matchBrace(document.getCharsSequence(), fileType, iterator, false); + + TextRange brace2 = iterator.atEnd() ? null : TextRange.create(iterator.getStart(), iterator.getEnd()); + + highlightBraces(editor, brace2, brace1, matched, false, fileType); + } + + private void highlightLeftBrace(Editor editor, @NotNull HighlighterIterator iterator, boolean scopeHighlighting, @NotNull FileType fileType, Document document) { + TextRange brace1Start = TextRange.create(iterator.getStart(), iterator.getEnd()); + boolean matched = matchBrace(document.getCharsSequence(), fileType, iterator, true); + + TextRange brace2End = iterator.atEnd() ? null : TextRange.create(iterator.getStart(), iterator.getEnd()); + + highlightBraces(editor, brace1Start, brace2End, matched, scopeHighlighting, fileType); + } + + private void highlightBraces(Editor editor, @Nullable TextRange lBrace, + @Nullable TextRange rBrace, boolean matched, boolean scopeHighlighting, @NotNull FileType fileType) { + if (!matched && fileType == FileTypes.PLAIN_TEXT) { + return; + } + + if (rBrace != null && !scopeHighlighting) { + highlightBrace(editor, rBrace, matched); + } + + if (lBrace != null && !scopeHighlighting) { + highlightBrace(editor, lBrace, matched); + } + } + + private void highlightBrace(Editor editor, @NotNull TextRange braceRange, boolean matched) { + TextAttributesKey attributesKey = matched ? CodeInsightColors.MATCHED_BRACE_ATTRIBUTES : CodeInsightColors.UNMATCHED_BRACE_ATTRIBUTES; + RangeHighlighter rbraceHighlighter = + editor.getMarkupModel().addRangeHighlighter(attributesKey, braceRange.getStartOffset(), braceRange.getEndOffset(), + HighlighterLayer.LAST + 1, HighlighterTargetArea.EXACT_RANGE); + rbraceHighlighter.setGreedyToLeft(false); + rbraceHighlighter.setGreedyToRight(false); + registerHighlighter(editor, rbraceHighlighter); + } + + private void registerHighlighter(Editor editor, @NotNull RangeHighlighter highlighter) { + getHighlightersList(editor).add(highlighter); + } + + @NotNull + private List getHighlightersList(Editor myEditor) { + // braces are highlighted across the whole editor, not in each injected editor separately + Editor editor = myEditor instanceof EditorWindow ? ((EditorWindow) myEditor).getDelegate() : myEditor; + List highlighters = editor.getUserData(BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY); + if (highlighters == null) { + highlighters = new ArrayList<>(); + editor.putUserData(BRACE_HIGHLIGHTERS_IN_EDITOR_VIEW_KEY, highlighters); + } + return highlighters; + } + + @NotNull + private static FileType getFileTypeByOffset(PsiFile psiFile, int offset) { + return PsiUtilBase.getPsiFileAtOffset(psiFile, offset).getFileType(); + } + + private static void removeLineMarkers(@NotNull EditorEx editor) { + ApplicationManager.getApplication().assertIsDispatchThread(); + RangeHighlighter marker = editor.getUserData(LINE_MARKER_IN_EDITOR_KEY); + if (marker != null && editor.getMarkupModel().containsHighlighter(marker)) { + marker.dispose(); + } + editor.putUserData(LINE_MARKER_IN_EDITOR_KEY, null); + } + + private void onCaretUpdate(Editor editor, Project project) { + alarm.cancelAllRequests(); + SelectionModel selectionModel = editor.getSelectionModel(); + if (editor.getProject() != project || selectionModel.hasSelection()) { + return; + } + if (isNotCLFile(editor)) { + return; + } + updateHighlighted(project, editor); + } + + @Nullable + private static BraceMatchingUtil.BraceHighlightingAndNavigationContext computeHighlightingAndNavigationContext(@NotNull Editor editor, + @NotNull PsiFile file, + int offset) { + EditorHighlighter highlighter = BraceHighlightingHandler.getLazyParsableHighlighterIfAny(file.getProject(), editor, file); + CharSequence text = editor.getDocument().getCharsSequence(); + + HighlighterIterator iterator = highlighter.createIterator(offset); + FileType fileType = iterator.atEnd() ? null : getFileType(file, iterator.getStart()); + + boolean isBeforeOrInsideLeftBrace = fileType != null && isLBraceToken(iterator, text, fileType); + boolean isBeforeOrInsideRightBrace = !isBeforeOrInsideLeftBrace && fileType != null && isRBraceToken(iterator, text, fileType); + boolean isInsideBrace = (isBeforeOrInsideLeftBrace || isBeforeOrInsideRightBrace) && iterator.getStart() < offset; + + HighlighterIterator preOffsetIterator = offset > 0 && !isInsideBrace ? highlighter.createIterator(offset - 1) : null; + FileType preOffsetFileType = preOffsetIterator != null ? getFileType(file, preOffsetIterator.getStart()) : null; + + boolean isAfterLeftBrace = preOffsetIterator != null && + isLBraceToken(preOffsetIterator, text, preOffsetFileType); + boolean isAfterRightBrace = !isAfterLeftBrace && preOffsetIterator != null && + isRBraceToken(preOffsetIterator, text, preOffsetFileType); + + int offsetTokenStart = iterator.atEnd() ? -1 : iterator.getStart(); + int preOffsetTokenStart = preOffsetIterator == null || preOffsetIterator.atEnd() ? -1 : preOffsetIterator.getStart(); + + if (editor.getSettings().isBlockCursor()) { + if (isBeforeOrInsideLeftBrace && matchBrace(text, fileType, iterator, true)) { + return new BraceHighlightingAndNavigationContext(offsetTokenStart, iterator.getStart(), isInsideBrace); + } else if (isBeforeOrInsideRightBrace && matchBrace(text, fileType, iterator, false)) { + return new BraceHighlightingAndNavigationContext(offsetTokenStart, iterator.getStart(), isInsideBrace); + } else if (isAfterRightBrace && matchBrace(text, preOffsetFileType, preOffsetIterator, false)) { + return new BraceHighlightingAndNavigationContext(preOffsetTokenStart, preOffsetIterator.getStart(), true); + } else if (isAfterLeftBrace && matchBrace(text, preOffsetFileType, preOffsetIterator, true)) { + return new BraceHighlightingAndNavigationContext(preOffsetTokenStart, preOffsetIterator.getStart(), true); + } + } else { + if (isAfterRightBrace && matchBrace(text, preOffsetFileType, preOffsetIterator, false)) { + return new BraceHighlightingAndNavigationContext(preOffsetTokenStart, preOffsetIterator.getStart(), true); + } else if (isBeforeOrInsideLeftBrace && matchBrace(text, fileType, iterator, true)) { + return new BraceHighlightingAndNavigationContext(offsetTokenStart, iterator.getEnd(), isInsideBrace); + } else if (isAfterLeftBrace && matchBrace(text, preOffsetFileType, preOffsetIterator, true)) { + return new BraceHighlightingAndNavigationContext(preOffsetTokenStart, preOffsetIterator.getEnd(), true); + } else if (isBeforeOrInsideRightBrace && matchBrace(text, fileType, iterator, false)) { + return new BraceHighlightingAndNavigationContext(offsetTokenStart, iterator.getStart(), isInsideBrace); + } + } + return null; + } + + private static boolean isLBraceToken(@NotNull HighlighterIterator iterator, @NotNull CharSequence fileText, @NotNull FileType fileType) { + IElementType tokenType = iterator.getTokenType(); + return tokenType.equals(LispTypes.LPAREN); + } + + private static boolean isRBraceToken(@NotNull HighlighterIterator iterator, @NotNull CharSequence fileText, @NotNull FileType fileType) { + IElementType tokenType = iterator.getTokenType(); + return tokenType.equals(LispTypes.RPAREN); + } + + @NotNull + private static FileType getFileType(PsiFile file, int offset) { + return PsiUtilBase.getPsiFileAtOffset(file, offset).getFileType(); + } + + private static class MatchBraceContext { + private final CharSequence fileText; + private final FileType fileType; + private final HighlighterIterator iterator; + private final boolean forward; + + private final IElementType brace1Token; + private final int group; + + private final Stack myBraceStack = new Stack<>(); + + MatchBraceContext(@NotNull CharSequence fileText, + @NotNull FileType fileType, + @NotNull HighlighterIterator iterator, + boolean forward) { + this.fileText = fileText; + this.fileType = fileType; + this.iterator = iterator; + this.forward = forward; + + brace1Token = this.iterator.getTokenType(); + group = getTokenGroup(brace1Token, this.fileType); + } + + private boolean doBraceMatch() { + myBraceStack.clear(); + myBraceStack.push(brace1Token); + boolean matched = false; + while (true) { + advance(iterator, forward); + if (iterator.atEnd()) { + break; + } + + IElementType tokenType = iterator.getTokenType(); + + if (getTokenGroup(tokenType, fileType) != group) { + continue; + } + + if (isBraceToken(iterator, fileText, fileType, !forward)) { + myBraceStack.push(tokenType); + } else if (isBraceToken(iterator, fileText, fileType, forward)) { + IElementType topTokenType = myBraceStack.pop(); + + IElementType baseType = getOppositeBraceTokenType(tokenType); + if (myBraceStack.contains(baseType)) { + while (!isPairBraces(topTokenType, tokenType, fileType) && !myBraceStack.empty()) { + topTokenType = myBraceStack.pop(); + } + } + + if (!isPairBraces(topTokenType, tokenType, fileType)) { + break; + } + + if (myBraceStack.isEmpty()) { + matched = true; + break; + } + } + } + return matched; + } + + private IElementType getOppositeBraceTokenType(IElementType tokenType) { + if (tokenType.equals(LispTypes.LPAREN)) + return LispTypes.RPAREN; + else if (tokenType.equals(LispTypes.RPAREN)) + return LispTypes.LPAREN; + return null; + } + } + + private static synchronized boolean matchBrace(@NotNull CharSequence fileText, + @NotNull FileType fileType, + @NotNull HighlighterIterator iterator, + boolean forward) { + return new MatchBraceContext(fileText, fileType, iterator, forward).doBraceMatch(); + } + + + private static boolean isPairBraces(@NotNull IElementType tokenType1, @NotNull IElementType tokenType2, @NotNull FileType fileType) { + return (tokenType1.equals(LispTypes.LPAREN) && tokenType2.equals(LispTypes.RPAREN)) || (tokenType1.equals(LispTypes.RPAREN) && tokenType2.equals(LispTypes.LPAREN)); + } + + private static int getTokenGroup(@Nullable IElementType tokenType, FileType fileType) { + return LispTypes.LPAREN.equals(tokenType) || LispTypes.RPAREN.equals(tokenType) ? SltCommonLispLanguage.INSTANCE.hashCode() : -1; + } + + private static boolean isBraceToken(@NotNull HighlighterIterator iterator, + @NotNull CharSequence fileText, + @NotNull FileType fileType, + boolean searchingForRight) { + return searchingForRight ? isRBraceToken(iterator, fileText, fileType) + : isLBraceToken(iterator, fileText, fileType); + } + + private static void advance(@NotNull HighlighterIterator iterator, boolean forward) { + if (forward) { + iterator.advance(); + } else { + iterator.retreat(); + } + } +} diff --git a/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceMatcher.java b/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceMatcher.java deleted file mode 100644 index 024f9fc..0000000 --- a/src/main/java/com/en_circle/slt/plugin/highlights/SltBraceMatcher.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.en_circle.slt.plugin.highlights; - -import com.en_circle.slt.plugin.lisp.psi.LispTypes; -import com.intellij.lang.BracePair; -import com.intellij.lang.PairedBraceMatcher; -import com.intellij.psi.PsiFile; -import com.intellij.psi.tree.IElementType; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -public class SltBraceMatcher implements PairedBraceMatcher { - - private static final BracePair[] PAIRS = new BracePair[] { - new BracePair(LispTypes.LPAREN, LispTypes.RPAREN, true), - }; - - @Override - public BracePair @NotNull [] getPairs() { - return PAIRS; - } - - @Override - public boolean isPairedBracesAllowedBeforeType(@NotNull IElementType lbraceType, @Nullable IElementType contextType) { - return false; - } - - @Override - public int getCodeConstructStart(PsiFile file, int openingBraceOffset) { - return openingBraceOffset; - } -} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index 9481760..b50411a 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -40,9 +40,6 @@ - - @@ -62,6 +59,9 @@ implementation="com.en_circle.slt.plugin.references.SltDirectNavigationProvider"/> + + From 296c7b9f9257cacf550defd315c9c78faf2d956a Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 20 Jan 2023 09:51:54 +0100 Subject: [PATCH 28/30] #24 --- .../java/com/en_circle/slt/plugin/swank/SwankServer.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/en_circle/slt/plugin/swank/SwankServer.java b/src/main/java/com/en_circle/slt/plugin/swank/SwankServer.java index 0533e4f..9f15350 100644 --- a/src/main/java/com/en_circle/slt/plugin/swank/SwankServer.java +++ b/src/main/java/com/en_circle/slt/plugin/swank/SwankServer.java @@ -5,6 +5,7 @@ import com.en_circle.slt.templates.SltScriptTemplate; import com.intellij.openapi.application.ApplicationManager; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import java.io.File; import java.io.IOException; @@ -52,7 +53,11 @@ private synchronized void start(SwankServerConfiguration configuration) { File serverStartSetup = File.createTempFile("startServer", ".cl"); serverStartSetup.deleteOnExit(); - String startScriptTemplate = new InitScriptTemplate(configuration, sltCore.getAbsolutePath()).render(); + String sltCorePath = sltCore.getAbsolutePath(); + if (sltCorePath.contains("\\")) { + sltCorePath = StringUtils.replace(sltCorePath, "\\", "\\\\"); + } + String startScriptTemplate = new InitScriptTemplate(configuration, sltCorePath).render(); FileUtils.write(serverStartSetup, startScriptTemplate, StandardCharsets.UTF_8); String[] commands = new String[]{ From 90e522296a57fb7ff7fa9402d541beb4f31e0eb3 Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 20 Jan 2023 09:55:15 +0100 Subject: [PATCH 29/30] #24 in develop --- .../slt/plugin/environment/SltLispEnvironmentProcess.java | 4 +--- .../slt/plugin/environment/SltSBCLEnvironment.java | 7 ++++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentProcess.java b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentProcess.java index 364fa9b..b53c5ac 100644 --- a/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentProcess.java +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltLispEnvironmentProcess.java @@ -27,10 +27,8 @@ public boolean isActive() { public void start(SltLispEnvironmentConfiguration configuration) throws SltProcessException { if (process != null) return; - if (!(configuration instanceof SltLispEnvironmentProcessConfiguration)) + if (!(configuration instanceof SltLispEnvironmentProcessConfiguration processConfiguration)) throw new SltProcessException("Configuration incorrect"); - SltLispEnvironmentProcessConfiguration processConfiguration = (SltLispEnvironmentProcessConfiguration) - configuration; try { Object environment = prepareProcessEnvironment(processConfiguration); diff --git a/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java index cf3d2ca..9971f0f 100644 --- a/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java +++ b/src/main/java/com/en_circle/slt/plugin/environment/SltSBCLEnvironment.java @@ -5,6 +5,7 @@ import com.en_circle.slt.templates.SltScriptTemplate; import com.intellij.openapi.util.io.FileUtil; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.StringUtils; import org.watertemplate.Template; import java.io.File; @@ -31,7 +32,11 @@ protected Object prepareProcessEnvironment(SltLispEnvironmentProcessConfiguratio e.serverStartSetup = new File(tempDir, "startServer.cl"); e.serverStartSetup.deleteOnExit(); - String startScriptTemplate = new SBCLInitScriptTemplate(c, e.sltCore.getAbsolutePath()).render(); + String sltCorePath = e.sltCore.getAbsolutePath(); + if (sltCorePath.contains("//")) { + sltCorePath = StringUtils.replace(sltCorePath, "\\", "\\\\"); + } + String startScriptTemplate = new SBCLInitScriptTemplate(c, sltCorePath).render(); FileUtils.write(e.serverStartSetup, startScriptTemplate, StandardCharsets.UTF_8); tempDir.deleteOnExit(); From 03fe04ac78d8bd88154fac0301ae0383451f2a3a Mon Sep 17 00:00:00 2001 From: Peter Vanusanik Date: Fri, 20 Jan 2023 10:04:12 +0100 Subject: [PATCH 30/30] release --- CHANGELOG.md | 4 +++- README.md | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8511db5..2bd1b9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,5 @@ -## 0.2.0 +## 0.2.0 - 230120 ### Added @@ -17,6 +17,8 @@ you need to hover again to see it. - Fixed bad package when package does not exist - Fixed lisp parser, `REFERENCE_LABEL` requiring `datum`, now it is stand alone - Fixed line comment highlight color +- Fixed highlight on braces + - no longer using standard BracePair but instead use internal brace matcher to prevent auto brace inserting ## 0.1.1 - 230115 diff --git a/README.md b/README.md index 4706140..46e681b 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,7 @@ [![License: APACHE](https://badgen.net/github/license/enerccio/SLT?color=green)](LICENSE) [![0.1.0](https://badgen.net/github/milestones/enerccio/SLT/1)](https://github.com/enerccio/SLT/milestone/1) [![0.2.0](https://badgen.net/github/milestones/enerccio/SLT/2)](https://github.com/enerccio/SLT/milestone/2) +[![0.3.0](https://badgen.net/github/milestones/enerccio/SLT/4)](https://github.com/enerccio/SLT/milestone/4) ![Image](src/main/resources/logo/logo.svg)