Skip to content

Commit

Permalink
#16 Autocomple and documentation provider for fields
Browse files Browse the repository at this point in the history
  • Loading branch information
satran004 committed Mar 19, 2021
1 parent ba6516b commit 3d6983e
Show file tree
Hide file tree
Showing 10 changed files with 209 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ public class AlgoIcons {
public final static Icon TEAL_FILE_ICON = IconLoader.getIcon("/icons/teal_file.png", AlgoIcons.class);
public final static Icon MODULE_ICON = IconLoader.getIcon("/icons/module.png", AlgoIcons.class);
public final static Icon OPCODE_ICON = IconLoader.getIcon("/icons/opcode.png", AlgoIcons.class);
public static final Icon FIELD_ICON = IconLoader.getIcon("/icons/field.png", AlgoIcons.class);;
public static final Icon FIELD_ICON = IconLoader.getIcon("/icons/field.png", AlgoIcons.class);
public static final Icon NAMED_INT_CONSTANT_ICON = IconLoader.getIcon("/icons/constant.png ", AlgoIcons.class);
public static final Icon LSIG_FILE_ICON = IconLoader.getIcon("/icons/lsig_file.png", AlgoIcons.class);
public static final Icon TOK_FILE_ICON = IconLoader.getIcon("/icons/tok_file.png", AlgoIcons.class);
public static final Icon ALGO_TX_ICON = IconLoader.getIcon("/icons/algo_tx.png", AlgoIcons.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

package com.bloxbean.algodea.idea.language.completion.metadata.atoms;

import com.bloxbean.algodea.idea.language.completion.metadata.elements.TEALConstantElement;
import com.bloxbean.algodea.idea.language.completion.metadata.elements.TEALFieldElement;
import com.bloxbean.algodea.idea.language.completion.metadata.elements.TEALKeywordElement;
import com.bloxbean.algodea.idea.language.opcode.TEALOpCodeFactory;
Expand Down Expand Up @@ -132,8 +133,8 @@ public final class TEALKeywords {
public static final List<LookupElement> TYPEENUM_CONSTANT_ELEMENTS = TEALOpCodeFactory.getInstance()
.getFields(TYPE_ENUM_MAPPING)
.stream()
.map(f -> new TEALFieldElement(f))
.map(TEALFieldElement::getLookupElement)
.map(f -> new TEALConstantElement(f))
.map(TEALConstantElement::getLookupElement)
.collect(Collectors.toList());

public static final List<LookupElement> GLOBAL_FIELDS_ELEMENTS = TEALOpCodeFactory.getInstance()
Expand All @@ -160,8 +161,8 @@ public final class TEALKeywords {
public static final List<LookupElement> ONCOMPLETE_CONSTANT_ELEMENTS = TEALOpCodeFactory.getInstance()
.getFields(ONCOMPLETE_CONSTANTS)
.stream()
.map(f -> new TEALFieldElement(f))
.map(TEALFieldElement::getLookupElement)
.map(f -> new TEALConstantElement(f))
.map(TEALConstantElement::getLookupElement)
.collect(Collectors.toList());


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2020 BloxBean Project
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/

package com.bloxbean.algodea.idea.language.completion.metadata.elements;

import com.bloxbean.algodea.idea.common.AlgoIcons;
import com.bloxbean.algodea.idea.language.opcode.model.Field;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.openapi.diagnostic.Logger;

public class TEALConstantElement implements TEALElement {
private final static Logger LOG = Logger.getInstance(TEALConstantElement.class);

private final Field field;

public TEALConstantElement(Field field) {
this.field = field;
}

@Override
public LookupElement getLookupElement() {
if(field == null)
return null;

if(LOG.isDebugEnabled()) {
if (field.getName() == null) {
LOG.error("Field.getName() cannot be null" + field);
}
}
return LookupElementBuilder
.create(field.getName())
.withIcon(AlgoIcons.NAMED_INT_CONSTANT_ICON)
.withTypeText(field.getType());

}

public LookupElement getCompositeLookupElement(String prefix, String suffix) {

if(field == null)
return null;

if(LOG.isDebugEnabled()) {
if (field.getName() == null) {
LOG.error("Field.getName() cannot be null" + field);
}
}

StringBuilder sb = new StringBuilder();

if(prefix != null) {
sb.append(prefix)
.append(" ");
}

sb.append(field.getName());

if(suffix != null)
sb.append(" ")
.append(suffix);

return LookupElementBuilder
.create(sb.toString())
.withIcon(AlgoIcons.NAMED_INT_CONSTANT_ICON);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ protected void addCompletions(@NotNull CompletionParameters parameters,
@NotNull CompletionResultSet result) {
result.addAllElements(TEALKeywords.ONCOMPLETE_CONSTANT_ELEMENTS);
result.addAllElements(TEALKeywords.TYPEENUM_CONSTANT_ELEMENTS);

result.stopHere();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
package com.bloxbean.algodea.idea.language.documentation;

import com.bloxbean.algodea.idea.language.completion.metadata.atoms.TEALKeywords;
import com.bloxbean.algodea.idea.language.opcode.model.Field;
import com.bloxbean.algodea.idea.language.opcode.model.OpCode;
import com.bloxbean.algodea.idea.language.opcode.TEALOpCodeFactory;
import com.bloxbean.algodea.idea.language.psi.TEALTypes;
Expand All @@ -48,8 +49,20 @@ public class TEALDocumentationProvider extends AbstractDocumentationProvider {
TEALTypes.TXN_LOADING_OP,
TEALTypes.FLOWCONTROL_OP,
TEALTypes.STATEACCESS_OP,
TEALTypes.PSEUDO_OP
TEALTypes.PSEUDO_OP,
TEALTypes.NAMED_INTEGER_CONSTANT,
TEALTypes.TYPENUM_CONSTANT,
TEALTypes.GLOBAL_FIELD,
TEALTypes.TXN_FIELD_ARG,
TEALTypes.ASSET_PARAMS_GET_FIELD,
TEALTypes.ASSET_HOLDING_GET_FIELD
);
public static final String ONCOMPLETE = "oncomplete";
public static final String TYPEENUM_CONSTANTS = "typeenum_constants";
public static final String GLOBAL_FIELDS = "global_fields";
public static final String TXN_FIELDS = "txn_fields";
public static final String ASSET_PARAMS_GET_FIELDS = "asset_params_get_fields";
public static final String ASSET_HOLDING_GET_FIELDS = "asset_holding_get_fields";

static {
SEARCH_TYPES.addAll(GENERAL_OPERATIONS_ELEMENTS);
Expand All @@ -73,9 +86,15 @@ public String getQuickNavigateInfo(PsiElement element, PsiElement originalElemen
@Nullable
@Override
public String generateDoc(PsiElement element, @Nullable PsiElement originalElement) {
Optional<String> opcodeDocumentation = loadingOpcodeDocumentation(element);
if (opcodeDocumentation.isPresent()) {
return opcodeDocumentation.get();
Optional<String> documentation = loadingOpcodeDocumentation(element);
if (documentation.isPresent()) {
return documentation.get();
}

//Check if Named Integer Constant or TypeEnum Constant
documentation = loadFieldDocumentation(element);
if(documentation.isPresent()) {
return documentation.get();
}

return null;
Expand Down Expand Up @@ -105,6 +124,44 @@ private Optional<String> loadingOpcodeDocumentation(PsiElement element) {
return Optional.empty();
}

private Optional<String> loadFieldDocumentation(PsiElement element) {
if(element == null) return Optional.empty();

if (TEALTypes.NAMED_INTEGER_CONSTANT.equals(element.getNode().getElementType())) {
String value = element.getNode().getText();
Field field = TEALOpCodeFactory.getInstance().getField(ONCOMPLETE, value);
if(field != null)
return field.formatHtml();
} else if(TEALTypes.TYPENUM_CONSTANT.equals(element.getNode().getElementType())) {
String value = element.getNode().getText();
Field field = TEALOpCodeFactory.getInstance().getField(TYPEENUM_CONSTANTS, value);
if(field != null)
return field.formatHtml();
} else if(TEALTypes.GLOBAL_FIELD.equals(element.getNode().getElementType())) {
String value = element.getNode().getText();
Field field = TEALOpCodeFactory.getInstance().getField(GLOBAL_FIELDS, value);
if(field != null)
return field.formatHtml();
} else if(TEALTypes.TXN_FIELD_ARG.equals(element.getNode().getElementType())) {
String value = element.getNode().getText();
Field field = TEALOpCodeFactory.getInstance().getField(TXN_FIELDS, value);
if(field != null)
return field.formatHtml();
} else if(TEALTypes.ASSET_PARAMS_GET_FIELD.equals(element.getNode().getElementType())) {
String value = element.getNode().getText();
Field field = TEALOpCodeFactory.getInstance().getField(ASSET_PARAMS_GET_FIELDS, value);
if(field != null)
return field.formatHtml();
} else if(TEALTypes.ASSET_HOLDING_GET_FIELD.equals(element.getNode().getElementType())) {
String value = element.getNode().getText();
Field field = TEALOpCodeFactory.getInstance().getField(ASSET_HOLDING_GET_FIELDS, value);
if(field != null)
return field.formatHtml();
}

return Optional.empty();
}

private Optional<String> getDocumentHtmlForKey(String nodeText) {
OpCode opCode = TEALOpCodeFactory.getInstance().getOpCode(nodeText);
if (opCode == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.text.StringUtil;

import java.net.URL;
import java.util.*;
Expand Down Expand Up @@ -134,4 +135,13 @@ public Collection<Field> getFields(String type) {
return typeFields.values();
}

public Field getField(String type, String fieldText) {
if(StringUtil.isEmpty(fieldText)) return null;

Map<String, Field> typeFields = fields.get(type);
if(typeFields == null) return null;

return typeFields.get(fieldText);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.bloxbean.algodea.idea.language.opcode.model;

import java.util.Objects;
import java.util.Optional;

public class Field {
private int index;
Expand Down Expand Up @@ -80,4 +81,40 @@ public String toString() {
", desc='" + desc + '\'' +
'}';
}

public Optional<String> formatHtml() {
StringBuilder sb = new StringBuilder();
sb.append("<ul>");

//createLiTag(sb, "Value", String.valueOf(index));

if(name != null) {
createLiTag(sb, "Name", name);
}

if(type != null && !type.isEmpty()) {
createLiTag(sb, "Type", type);
}

if(desc != null && !desc.isEmpty()) {
createLiTag(sb, null, desc);
}

if(note != null && !note.isEmpty()) {
createLiTag(sb, null, note);
}

return Optional.of(sb.toString());
}

private void createLiTag(StringBuilder sb, String key, String value) {
sb.append("<li>");
if(key != null) {
sb.append(key);
sb.append(": ");
}
sb.append(value);
sb.append("</li>");
}

}
Binary file added src/main/resources/icons/constant.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions src/main/resources/icons/svg/constant.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
12 changes: 6 additions & 6 deletions src/main/resources/opcodes/fields.json
Original file line number Diff line number Diff line change
Expand Up @@ -294,37 +294,37 @@
"index": 0,
"name": "NoOp",
"type": "NoOp",
"desc": "NoOp"
"desc": "Only execute the ApprovalProgram associated with this application ID, with no additional effects."
},
{
"index": 1,
"name": "OptIn",
"type": "OptIn",
"desc": "OptIn"
"desc": "Before executing the ApprovalProgram, allocate local state for this application into the sender's account data."
},
{
"index": 2,
"name": "CloseOut",
"type": "CloseOut",
"desc": "CloseOut"
"desc": "After executing the ApprovalProgram, clear any local state for this application out of the sender's account data."
},
{
"index": 3,
"name": "ClearState",
"type": "ClearState",
"desc": "ClearState"
"desc": "Don't execute the ApprovalProgram, and instead execute the ClearStateProgram (which may not reject this transaction). Additionally, clear any local state for this application out of the sender's account data as in CloseOutOC."
},
{
"index": 4,
"name": "UpdateApplication",
"type": "UpdateApplication",
"desc": "UpdateApplication"
"desc": "After executing the ApprovalProgram, replace the ApprovalProgram and ClearStateProgram associated with this application ID with the programs specified in this transaction."
},
{
"index": 5,
"name": "DeleteApplication",
"type": "DeleteApplication",
"desc": "DeleteApplication"
"desc": "After executing the ApprovalProgram, delete the application parameters from the account data of the application's creator."
}
],
"typeenum_constants": [
Expand Down

0 comments on commit 3d6983e

Please sign in to comment.