diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2ddc7a5..bf32300 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 0.5.1
+## 0.5.1 230508
### Added
- Symbol inspection
@@ -6,6 +6,9 @@
- More browser options
- Evaluate top level action
+### Changes
+- Macroexpand is now action and menu, no longer automatic!
+
### Fixes
- Added symbols with no file into all search places
diff --git a/README.md b/README.md
index 7ea13a6..779aeb4 100644
--- a/README.md
+++ b/README.md
@@ -95,26 +95,21 @@ You can also open this as a project in Intellij Idea.
* [x] Breakpoints
* [x] Documentation
* [x] Hyperspec intergration
-* [x] Macro expand in documentation
- * Macro expand requires you to hover element twice for now
+* [x] Macro expand (all, 1, normal)
* [x] Find function by symbol name
* [x] Search for symbols
* [x] Back references
+* [x] Rainbow braces
* [ ] 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
-
-### Far futures / possible goals
-
-* [x] SDK Support
- * not a true SDK because that is only available in Intellij and not in (for instance) PyCharm, thus
-this is implemented manually.
- * [x] Download SBCL and quicklisp for user
+* [x] SDK Support
+ * not a true SDK because that is only available in Intellij and not in (for instance) PyCharm, thus
+ this is implemented manually.
+ * [x] Download SBCL and quicklisp for user
* [x] Automatic download of lisp interpret and quicklisp
-* [x] Different lisp interpreter support
-* [ ] Remote connections to interpreters
-* [ ] Rewrite everything into ABCL just for purity’s sake lol
+* [x] Different lisp interpreter support
## License
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 e8c2530..bed54ec 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,7 @@
package com.en_circle.slt.plugin;
-import com.en_circle.slt.plugin.SymbolState.SymbolBinding;
import com.en_circle.slt.plugin.environment.LispFeatures;
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.services.lisp.LispEnvironmentService;
import com.intellij.lang.documentation.AbstractDocumentationProvider;
@@ -68,7 +66,7 @@ public class SltDocumentationProvider extends AbstractDocumentationProvider {
String text = element.getText();
String packageName = LispParserUtil.getPackage(element);
SymbolState state = LispEnvironmentService.getInstance(element.getProject()).refreshSymbolFromServer(packageName, text);
- return asHtml(state, packageName, element);
+ return asHtml(state, element);
}
}
return null;
@@ -82,7 +80,7 @@ private PsiElement decideOnElement(PsiElement element, PsiElement originalElemen
return originalElement;
}
- private String asHtml(SymbolState state, String packageName, PsiElement element) {
+ private String asHtml(SymbolState state, PsiElement element) {
HtmlBuilder builder = new HtmlBuilder();
if (LispEnvironmentService.getInstance(element.getProject()).hasFeature(LispFeatures.DOCUMENTATION)) {
String documentation = StringUtils.replace(StringUtils.replace(escape(state.documentation), " ", " "),
@@ -91,24 +89,6 @@ private String asHtml(SymbolState state, String packageName, PsiElement element)
HtmlChunk.raw(documentation));
}
- if (LispEnvironmentService.getInstance(element.getProject()).hasFeature(LispFeatures.MACROEXPAND)) {
- LispList form = LispParserUtil.getIfHead(element);
- if (form != null && state.binding == SymbolBinding.MACRO) {
- String macroExpand = LispEnvironmentService.getInstance(element.getProject()).macroexpand(form, packageName);
- if (macroExpand != null) {
- macroExpand = StringUtils.replace(StringUtils.replace(escape(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));
- } else {
- builder.append(HtmlChunk.hr());
- builder.append(HtmlChunk.text(SltBundle.message("slt.documentation.macroexpand.generating")));
- }
- }
- }
-
String doc = builder.toString();
return StringUtils.isBlank(doc) ? null : doc;
}
diff --git a/src/main/java/com/en_circle/slt/plugin/actions/Macroexpand1Action.java b/src/main/java/com/en_circle/slt/plugin/actions/Macroexpand1Action.java
new file mode 100644
index 0000000..8c500c3
--- /dev/null
+++ b/src/main/java/com/en_circle/slt/plugin/actions/Macroexpand1Action.java
@@ -0,0 +1,29 @@
+package com.en_circle.slt.plugin.actions;
+
+import com.en_circle.slt.plugin.SltBundle;
+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.Macroexpand1;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class Macroexpand1Action extends MacroexpandActionBase {
+ private static final Logger log = LoggerFactory.getLogger(Macroexpand1Action.class);
+
+ @Override
+ protected void macroexpand(Project project, LispList form, String packageName, MacroexpandCallback callback) {
+ try {
+ LispEnvironmentService service = LispEnvironmentService.getInstance(project);
+ service.sendToLisp(new Macroexpand1(form.getText(), packageName, result -> {
+ callback.showMacroexpand(LispUtils.unescape(((LispString) result).getValue()));
+ }), true);
+ } catch (Exception e) {
+ log.warn(SltBundle.message("slt.error.start"), e);
+ Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start"));
+ }
+ }
+}
diff --git a/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandAction.java b/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandAction.java
new file mode 100644
index 0000000..a32e3c6
--- /dev/null
+++ b/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandAction.java
@@ -0,0 +1,29 @@
+package com.en_circle.slt.plugin.actions;
+
+import com.en_circle.slt.plugin.SltBundle;
+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.Macroexpand;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MacroexpandAction extends MacroexpandActionBase {
+ private static final Logger log = LoggerFactory.getLogger(MacroexpandAction.class);
+
+ @Override
+ protected void macroexpand(Project project, LispList form, String packageName, MacroexpandCallback callback) {
+ try {
+ LispEnvironmentService service = LispEnvironmentService.getInstance(project);
+ service.sendToLisp(new Macroexpand(form.getText(), packageName, result -> {
+ callback.showMacroexpand(LispUtils.unescape(((LispString) result).getValue()));
+ }), true);
+ } catch (Exception e) {
+ log.warn(SltBundle.message("slt.error.start"), e);
+ Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start"));
+ }
+ }
+}
diff --git a/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandActionBase.java b/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandActionBase.java
new file mode 100644
index 0000000..129d82f
--- /dev/null
+++ b/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandActionBase.java
@@ -0,0 +1,122 @@
+package com.en_circle.slt.plugin.actions;
+
+import com.en_circle.slt.plugin.SltBundle;
+import com.en_circle.slt.plugin.SltCommonLispFileType;
+import com.en_circle.slt.plugin.environment.LispFeatures;
+import com.en_circle.slt.plugin.lisp.LispParserUtil;
+import com.en_circle.slt.plugin.lisp.psi.LispList;
+import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService;
+import com.intellij.openapi.actionSystem.ActionUpdateThread;
+import com.intellij.openapi.actionSystem.AnAction;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.openapi.editor.ex.EditorEx;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.popup.JBPopup;
+import com.intellij.openapi.ui.popup.JBPopupFactory;
+import com.intellij.openapi.util.text.HtmlBuilder;
+import com.intellij.openapi.util.text.HtmlChunk;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+
+import javax.swing.*;
+import javax.swing.text.html.HTMLEditorKit;
+import java.awt.*;
+import java.util.Objects;
+
+public abstract class MacroexpandActionBase extends AnAction {
+
+ protected abstract void macroexpand(Project project, LispList form, String packageName, MacroexpandCallback callback);
+
+ @Override
+ public void actionPerformed(@NotNull AnActionEvent event) {
+ EditorEx editor = (EditorEx) event.getData(CommonDataKeys.EDITOR);
+ LispList list = null;
+
+ if (editor != null) {
+ PsiDocumentManager psiMgr = PsiDocumentManager.getInstance(Objects.requireNonNull(editor.getProject()));
+ psiMgr.commitDocument(editor.getDocument());
+ PsiFile psiFile = psiMgr.getPsiFile(editor.getDocument());
+ if (psiFile != null) {
+ int caretOffset = editor.getExpectedCaretOffset();
+ list = findList(psiFile, caretOffset, editor.getDocument());
+ if (list != null) {
+ editor.getSelectionModel().setSelection(list.getTextOffset(), list.getTextOffset() + list.getTextLength());
+ }
+ }
+
+ if (list != null) {
+ int offset = list.getTextOffset();
+ String packageName = LispParserUtil.getPackage(psiFile, offset);
+ macroexpand(editor.getProject(), list, packageName, text -> SwingUtilities.invokeLater(() -> {
+ HtmlBuilder builder = new HtmlBuilder();
+ String macroExpand = StringUtils.replace(StringUtils.replace(StringEscapeUtils.escapeHtml(text), " ", " "),
+ "\n", HtmlChunk.br().toString());
+ builder.append(HtmlChunk.raw(macroExpand));
+
+ JEditorPane editorPane = new JEditorPane("text/html", "");
+ editorPane.setEditorKit(new HTMLEditorKit());
+ editorPane.setText(builder.toString());
+
+ JPanel textPanel = new JPanel(new BorderLayout());
+ textPanel.add(editorPane, BorderLayout.CENTER);
+
+ JBPopup popup = JBPopupFactory.getInstance()
+ .createComponentPopupBuilder(textPanel, null)
+ .setProject(editor.getProject())
+ .setTitle(SltBundle.message("slt.documentation.macroexpand"))
+ .setShowBorder(true)
+ .setMovable(true)
+ .setFocusable(true)
+ .setRequestFocus(true)
+ .createPopup();
+ popup.showInBestPositionFor(editor.getDataContext());
+ }));
+ }
+ }
+ }
+
+ protected LispList findList(PsiFile psiFile, int caretOffset, Document document) {
+ PsiElement element = psiFile.findElementAt(caretOffset);
+ if (element != null) {
+ PsiElement parent = element;
+ while (parent != null) {
+ parent = parent.getParent();
+ if (parent instanceof LispList) {
+ return (LispList) parent;
+ }
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent event) {
+ event.getPresentation().setEnabledAndVisible(false);
+ Editor editor = event.getData(CommonDataKeys.EDITOR);
+ 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(LispEnvironmentService.getInstance(event.getProject())
+ .hasFeature(LispFeatures.MACROEXPAND));
+ }
+ }
+ }
+
+ @Override
+ public @NotNull ActionUpdateThread getActionUpdateThread() {
+ return ActionUpdateThread.BGT;
+ }
+
+ protected interface MacroexpandCallback {
+
+ void showMacroexpand(String text);
+
+ }
+}
diff --git a/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandAllAction.java b/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandAllAction.java
new file mode 100644
index 0000000..c10ae54
--- /dev/null
+++ b/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandAllAction.java
@@ -0,0 +1,29 @@
+package com.en_circle.slt.plugin.actions;
+
+import com.en_circle.slt.plugin.SltBundle;
+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.intellij.openapi.project.Project;
+import com.intellij.openapi.ui.Messages;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class MacroexpandAllAction extends MacroexpandActionBase {
+ private static final Logger log = LoggerFactory.getLogger(MacroexpandAllAction.class);
+
+ @Override
+ protected void macroexpand(Project project, LispList form, String packageName, MacroexpandCallback callback) {
+ try {
+ LispEnvironmentService service = LispEnvironmentService.getInstance(project);
+ service.sendToLisp(new MacroexpandAll(form.getText(), packageName, result -> {
+ callback.showMacroexpand(LispUtils.unescape(((LispString) result).getValue()));
+ }), true);
+ } catch (Exception e) {
+ log.warn(SltBundle.message("slt.error.start"), e);
+ Messages.showErrorDialog(project, e.getMessage(), SltBundle.message("slt.ui.errors.lisp.start"));
+ }
+ }
+}
diff --git a/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandGroup.java b/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandGroup.java
new file mode 100644
index 0000000..2f40169
--- /dev/null
+++ b/src/main/java/com/en_circle/slt/plugin/actions/MacroexpandGroup.java
@@ -0,0 +1,42 @@
+package com.en_circle.slt.plugin.actions;
+
+import com.en_circle.slt.plugin.SltBundle;
+import com.en_circle.slt.plugin.SltCommonLispFileType;
+import com.en_circle.slt.plugin.environment.LispFeatures;
+import com.en_circle.slt.plugin.services.lisp.LispEnvironmentService;
+import com.intellij.openapi.actionSystem.ActionUpdateThread;
+import com.intellij.openapi.actionSystem.AnActionEvent;
+import com.intellij.openapi.actionSystem.CommonDataKeys;
+import com.intellij.openapi.actionSystem.DefaultActionGroup;
+import com.intellij.openapi.editor.Editor;
+import com.intellij.psi.PsiDocumentManager;
+import com.intellij.psi.PsiFile;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Objects;
+
+public class MacroexpandGroup extends DefaultActionGroup {
+
+ public MacroexpandGroup() {
+ super(() -> SltBundle.message("action.slt.actions.macroexpand.group.text"), true);
+ }
+
+ @Override
+ public void update(@NotNull AnActionEvent event) {
+ event.getPresentation().setEnabledAndVisible(false);
+ Editor editor = event.getData(CommonDataKeys.EDITOR);
+ 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(LispEnvironmentService.getInstance(event.getProject())
+ .hasFeature(LispFeatures.MACROEXPAND));
+ }
+ }
+ }
+
+ @Override
+ public @NotNull ActionUpdateThread getActionUpdateThread() {
+ return ActionUpdateThread.BGT;
+ }
+
+}
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
index c9400f1..e860bec 100644
--- 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
@@ -5,7 +5,6 @@
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.services.lisp.components.SltBreakpoint;
import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentSymbolCache.BatchedSymbolRefreshAction;
import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface;
@@ -55,8 +54,6 @@ static LispEnvironmentService getInstance(Project project) {
SltLispEnvironment getEnvironment();
- String macroexpand(LispList form, String packageName);
-
void updateIndentation(LispElement element);
Integer calculateOffset(PsiElement element, PsiFile file, boolean wasAfter, String text, int offset, String packageOverride);
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
index d6c69a9..dfba7ec 100644
--- 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
@@ -8,11 +8,13 @@
import com.en_circle.slt.plugin.environment.SltLispEnvironmentConfiguration;
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.sdk.LispProjectSdk;
import com.en_circle.slt.plugin.sdk.LispSdk;
import com.en_circle.slt.plugin.sdk.SdkList;
-import com.en_circle.slt.plugin.services.lisp.components.*;
+import com.en_circle.slt.plugin.services.lisp.components.SltBreakpoint;
+import com.en_circle.slt.plugin.services.lisp.components.SltBreakpointContainer;
+import com.en_circle.slt.plugin.services.lisp.components.SltIndentationContainer;
+import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentSymbolCache;
import com.en_circle.slt.plugin.services.lisp.components.SltLispEnvironmentSymbolCache.BatchedSymbolRefreshAction;
import com.en_circle.slt.plugin.swank.SlimeListener;
import com.en_circle.slt.plugin.swank.SlimeListener.DebugInterface;
@@ -63,7 +65,6 @@ public class LispEnvironmentServiceImpl implements LispEnvironmentService {
private final Project project;
private final SltIndentationContainer indentationContainer;
private final SltLispEnvironmentSymbolCache symbolCache;
- private final SltLispEnvironmentMacroExpandCache macroExpandCache;
private final SltBreakpointContainer breakpointContainer;
public LispEnvironmentServiceImpl(Project project) {
@@ -71,7 +72,6 @@ public LispEnvironmentServiceImpl(Project project) {
indentationContainer = new SltIndentationContainer();
indentationContainer.init(project);
symbolCache = new SltLispEnvironmentSymbolCache(project);
- macroExpandCache = new SltLispEnvironmentMacroExpandCache();
breakpointContainer = new SltBreakpointContainer(project);
symbolCache.start();
@@ -330,23 +330,9 @@ 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);
-
- // also clear macro cache since we get this hit on macro update
- macroExpandCache.clear();
}
@Override
diff --git a/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentMacroExpandCache.java b/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentMacroExpandCache.java
deleted file mode 100644
index 599affb..0000000
--- a/src/main/java/com/en_circle/slt/plugin/services/lisp/components/SltLispEnvironmentMacroExpandCache.java
+++ /dev/null
@@ -1,90 +0,0 @@
-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;
-
-import java.util.Objects;
-
-public class SltLispEnvironmentMacroExpandCache {
-
- private final LoadingCache
Hyperspec embedded in the tool window (requires internet connection to see obviously)
0.5.1 New features:
Symbol inspection
Rainbow braces option
More CLHS browser options
Evaluate top level action
0.5.1 Changes and fixes:
Macroexpand is now action and menu, no longer automatic!
Added symbols with no file into all search places
0.5.0 Changes and fixes:
Support for definitions under other expressions
SltPlainTextSymbolCompletionContributor - to be used with git and such