Skip to content

Commit

Permalink
working argslist
Browse files Browse the repository at this point in the history
  • Loading branch information
Peter Vanusanik committed Feb 3, 2023
1 parent 2165225 commit e41b114
Show file tree
Hide file tree
Showing 14 changed files with 282 additions and 132 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
### Added

- Thread list with actions
- Argslist

### Changes

- SLT library is now formatted into multiple chunks
- Grammar now properly reacts to user errors or unfinished forms

### Fixes

Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ You can also open this as a project in Intellij Idea.
* [x] Automatic indentation
* [x] REPL
* [x] Interactive debugging
* [x] Argument help (Ctrl+P)
* [ ] Inspection
* [x] Basic inspection
* [ ] Actions
Expand Down
30 changes: 25 additions & 5 deletions src/main/gen/com/en_circle/slt/plugin/lisp/LispParser.java

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion src/main/java/com/en_circle/slt/plugin/lisp/Lisp.bnf
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ array ::= ARRAY_START list

structure ::= STRUCTURE_TOKEN list

list ::= LPAREN sexpr* RPAREN
list ::= LPAREN sexpr* RPAREN { pin = 2 recoverWhile=list_recovery }
private list_recovery ::= !(RPAREN | sexpr)

pair ::= LPAREN sexpr+ DOT sexpr RPAREN

Expand Down
23 changes: 23 additions & 0 deletions src/main/java/com/en_circle/slt/plugin/params/LispArgslist.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package com.en_circle.slt.plugin.params;

import com.en_circle.slt.plugin.SltBundle;
import com.en_circle.slt.plugin.lisp.lisp.LispElement;
import com.en_circle.slt.plugin.lisp.lisp.LispString;

public class LispArgslist {

private final String information;

public LispArgslist(LispElement data) {
if (data instanceof LispString str) {
this.information = str.getValue();
} else {
this.information = SltBundle.message("slt.argslist.error");
}
}

public String getInformation() {
return information;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package com.en_circle.slt.plugin.params;

import com.en_circle.slt.plugin.lisp.LispParserUtil;
import com.en_circle.slt.plugin.lisp.LispParserUtil.QuoteState;
import com.en_circle.slt.plugin.lisp.psi.LispList;
import com.en_circle.slt.plugin.lisp.psi.LispSexpr;
import com.en_circle.slt.plugin.lisp.psi.LispSymbol;
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.Argslist;
import com.en_circle.slt.tools.SltApplicationUtils;
import com.intellij.lang.parameterInfo.CreateParameterInfoContext;
import com.intellij.lang.parameterInfo.ParameterInfoHandler;
import com.intellij.lang.parameterInfo.ParameterInfoUIContext;
import com.intellij.lang.parameterInfo.UpdateParameterInfoContext;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiWhiteSpace;
import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

public class SltParameterInfoHandler implements ParameterInfoHandler<LispList, LispArgslist> {

@Override
public @Nullable LispList findElementForParameterInfo(@NotNull CreateParameterInfoContext context) {
LispList candidate = findElementAtOffset(context.getFile(), context.getOffset());
if (candidate != null) {
if (LispEnvironmentService.getInstance(context.getProject()).getState() == LispEnvironmentState.READY) {
LispSymbol symbol = getHead(candidate);
if (symbol == null)
return null;

String packageName = LispParserUtil.getPackage(candidate);
Object[] items = SltApplicationUtils.getAsyncResultNoThrow(context.getProject(), finishRequest -> Argslist
.getArgslist(symbol.getName(), packageName,
result -> finishRequest.accept(getCandidateObjects(result))));
if (items != null) {
context.setItemsToShow(items);
return candidate;
}
}
}
return null;
}

private LispSymbol getHead(LispList candidate) {
if (candidate.getSexprList().size() > 0) {
LispSexpr sexpr = candidate.getSexprList().get(0);
if (sexpr.getDatum() != null && sexpr.getDatum().getCompoundSymbol() != null) {
return sexpr.getDatum().getCompoundSymbol().getSymbol();
}
}
return null;
}

private Object[] getCandidateObjects(LispArgslist result) {
return new Object[] { result };
}

@Override
public void showParameterInfo(@NotNull LispList element, @NotNull CreateParameterInfoContext context) {
context.showHint(element, element.getTextRange().getStartOffset() + 1, this);
}

@Override
public @Nullable LispList findElementForUpdatingParameterInfo(@NotNull UpdateParameterInfoContext context) {
LispList candidate = findElementAtOffset(context.getFile(), context.getOffset());
if (candidate != null) {
PsiElement current = context.getParameterOwner();
if (current == null || current == candidate) return candidate;
}
return null;
}

@Override
public void updateParameterInfo(@NotNull LispList lispList, @NotNull UpdateParameterInfoContext context) {
context.setParameterOwner(lispList);
}

@Override
public void updateUI(LispArgslist p, @NotNull ParameterInfoUIContext context) {
context.setupUIComponentPresentation(p.getInformation(), 0, 0, false,
false, true, context.getDefaultParameterColor());
}

private LispList findElementAtOffset(PsiFile file, int offset) {
PsiElement element = file.findElementAt(offset);
while (element == null || element instanceof PsiWhiteSpace) {
element = file.findElementAt(offset--);
}

LispList l;
if ((element instanceof LispList)) {
l = (LispList) element;
} else {
l = PsiTreeUtil.getParentOfType(element, LispList.class);
}

if (l != null) {
QuoteState quoteState = LispParserUtil.getQuoteState(l);
if (quoteState == QuoteState.NO_STATE || quoteState == QuoteState.ERROR_STATE) {
return l;
}
}
return null;
}

// private LispSexpr @NotNull [] getActualParameters(@NotNull LispList o) {
// List<LispSexpr> arguments = new ArrayList<>();
// QuoteState quoteState = LispParserUtil.getQuoteState(o);
// if (quoteState == QuoteState.ERROR_STATE || quoteState == QuoteState.NO_STATE) {
// for (int i=1; i<o.getSexprList().size(); i++) {
// LispSexpr element = o.getSexprList().get(i);
// LispSymbol symbol = PsiTreeUtil.getChildOfType(element, LispSymbol.class);
// LispList list = PsiTreeUtil.getChildOfType(element, LispList.class);
// if (list == null && symbol != null) {
// if (symbol.getName() == null || !symbol.getName().startsWith(":")) {
// arguments.add(element);
// }
// } else {
// arguments.add(element);
// }
// }
// }
//
// return arguments.toArray(new LispSexpr[0]);
// }

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,7 @@
import com.en_circle.slt.plugin.lisp.psi.LispTypes;
import com.en_circle.slt.templates.Indentation;
import com.intellij.openapi.project.Project;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiFileFactory;
import com.intellij.psi.PsiManager;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import org.apache.commons.lang3.StringUtils;

Expand Down Expand Up @@ -202,7 +199,24 @@ public Integer calculateIndent(PsiElement element, PsiFile file, boolean wasAfte

try {
String formText = documentText.substring(toplevel.getTextOffset(), offset);
if (!wasAfter) {
boolean isUnfinished = false;
LispList list = PsiTreeUtil.getParentOfType(element, LispList.class);
if (list != null) {
if (element.getNode().getElementType() == LispTypes.RPAREN) {
list = PsiTreeUtil.getParentOfType(list, LispList.class);
}
if (list != null) {
if (list.getNextSibling() instanceof PsiErrorElement) {
isUnfinished = true;
if (element.getNode().getElementType() == LispTypes.RPAREN) {
if (numBraces > 0) {
--numBraces;
}
}
}
}
}
if (!wasAfter || isUnfinished) {
// insert fake element at the end, so we identify correct form
state.hasRealElement = false;
formText += " 0";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ private void processReturn(LispContainer reply) {
if (request instanceof SuspendThread suspendThread) {
suspendThread.processReply((LispContainer) reply.getItems().get(1));
}

if (request instanceof Argslist argslist) {
argslist.processReply((LispContainer) reply.getItems().get(1));
}
} finally {
requests.remove(replyId.getValue());
}
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/en_circle/slt/plugin/swank/SwankPacket.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,16 @@ public static SwankPacket killThread(BigInteger thread, BigInteger continuation)
return new SwankPacket(formatted);
}

public static SwankPacket argslist(String symbol, String packageName, BigInteger continuation) {
symbol = StringUtils.replace(symbol, "\\", "\\\\");
symbol = StringUtils.replace(symbol, "\"", "\\\"");
packageName = StringUtils.replace(packageName, "\\", "\\\\");
packageName = StringUtils.replace(packageName, "\"", "\\\"");

String formatted = String.format("(:emacs-rex (swank:operator-arglist \"%s\" \"%s\") \":CL-USER\" T %s)", symbol, packageName, continuation);
return new SwankPacket(formatted);
}

private int length;
private String expressionSource;

Expand Down
Original file line number Diff line number Diff line change
@@ -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.LispSymbol;
import com.en_circle.slt.plugin.params.LispArgslist;
import com.en_circle.slt.plugin.swank.SlimeRequest;
import com.en_circle.slt.plugin.swank.SwankPacket;

import java.math.BigInteger;

public class Argslist extends SlimeRequest {

public static SlimeRequest getArgslist(String symbol, String packageName, Callback callback) {
return new Argslist(symbol, packageName, callback);
}

private final String symbol;
private final String packageName;
private final Callback callback;

private Argslist(String symbol, String packageName, Callback callback) {
this.symbol = symbol;
this.packageName = packageName;
this.callback = callback;
}

@Override
public SwankPacket createPacket(BigInteger requestId) {
return SwankPacket.argslist(symbol, packageName, requestId);
}

public void processReply(LispContainer data) {
if (isOk(data)) {
callback.onResult(new LispArgslist(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());
}

public interface Callback {
void onResult(LispArgslist result);
}

}
25 changes: 11 additions & 14 deletions src/main/java/com/en_circle/slt/tools/SltApplicationUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
import java.util.function.Function;

Expand Down Expand Up @@ -63,27 +62,25 @@ public static <X> Future<X> getAsyncResultNoProgress(Project project, Function<C
}

return ApplicationManager.getApplication().executeOnPooledThread(() -> {
BlockingQueue<X> pointer = new ArrayBlockingQueue<>(1);
SlimeRequest r = request.apply(result ->
ApplicationManager.getApplication().invokeLater(() ->
ApplicationManager.getApplication().runWriteAction(() -> {
try {
pointer.put(result);
} catch (Exception ignored) {

}
})));
AtomicReference<X> pointer = new AtomicReference<>(null);
SlimeRequest r = request.apply(result -> {
try {
pointer.set(result);
} catch (Exception ignored) {

}
});
LispEnvironmentService.getInstance(project).sendToLisp(r, startLisp);
try {
Awaitility.await()
.atMost(2, TimeUnit.SECONDS)
.pollInterval(new FixedPollInterval(10, TimeUnit.MILLISECONDS))
.failFast(ProgressManager::checkCanceled)
.until(() -> pointer.peek() != null);
.until(() -> pointer.get() != null);
} catch (ConditionTimeoutException exception) {
return null;
}
return pointer.isEmpty() ? null : pointer.take();
return pointer.get();
});
}

Expand Down
Loading

0 comments on commit e41b114

Please sign in to comment.