Bug 499538 - Don't show existing JSON keys in popup completion The commit also fixes bug 499537. Change-Id: Ib0ff582c96c07f46e6b3a788836923da8cf8bc39 Signed-off-by: Snjezana Peco <snjeza.peco@gmail.com>
diff --git a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/contentassist/AbstractJSONCompletionProposalComputer.java b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/contentassist/AbstractJSONCompletionProposalComputer.java index e12e9be..616c6ac 100644 --- a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/contentassist/AbstractJSONCompletionProposalComputer.java +++ b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/contentassist/AbstractJSONCompletionProposalComputer.java
@@ -23,6 +23,7 @@ import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.wst.json.core.document.IJSONNode; import org.eclipse.wst.json.core.document.IJSONPair; +import org.eclipse.wst.json.core.document.IJSONValue; import org.eclipse.wst.json.core.regions.JSONRegionContexts; import org.eclipse.wst.json.ui.internal.JSONUIMessages; import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; @@ -37,8 +38,12 @@ public abstract class AbstractJSONCompletionProposalComputer implements ICompletionProposalComputer { - private static final String BLANK = ""; //$NON-NLS-1$ + private static final String BLANK = " "; //$NON-NLS-1$ + private static final String EMPTY = ""; //$NON-NLS-1$ private static final String COLON = ":"; //$NON-NLS-1$ + protected static final String QUOTE = "\""; //$NON-NLS-1$ + protected static final String TRUE = "true"; //$NON-NLS-1$ + protected static final String FALSE = "false"; //$NON-NLS-1$ private String fErrorMessage; private ITextViewer fTextViewer; @@ -78,17 +83,16 @@ if (completionRegion != null && completionRegion.getType() == JSONRegionContexts.JSON_OBJECT_CLOSE && documentPosition > 0) { completionRegion = getCompletionRegion(documentPosition, node); } - String matchString = BLANK; //$NON-NLS-1$ + String matchString = EMPTY; if (completionRegion != null) { if (isPairValue(context, node)) { try { - String nodeText = node.getStructuredDocument().get(node.getStartOffset(), node.getEndOffset() - node.getStartOffset()); + String nodeText = getNodeText(node); int colonIndex = nodeText.indexOf(COLON); - if (colonIndex >= 0) { - String str = nodeText.substring(colonIndex); - str = str.replaceAll(",", BLANK).trim(); - str = str.replaceAll(COLON, BLANK).trim(); - str = str.trim(); + int offset = documentPosition - node.getStartOffset(); + if (colonIndex >= 0 && offset >= 0) { + String str = nodeText.substring(colonIndex+1, offset); + str = str.replaceAll(",", BLANK); //$NON-NLS-1$ matchString = str; } } catch (BadLocationException e) { @@ -105,7 +109,7 @@ if (contentAssistRequest == null) { contentAssistRequest = new ContentAssistRequest( (IJSONNode) treeNode, node != null ? node.getParentNode() : null, sdRegion, - completionRegion, documentPosition, 0, BLANK); + completionRegion, documentPosition, 0, EMPTY); setErrorMessage(JSONUIMessages.Content_Assist_not_availab_UI_); } @@ -160,7 +164,7 @@ int documentPosition = context.getInvocationOffset(); ContentAssistRequest contentAssistRequest = null; - String regionType = completionRegion!= null ? completionRegion.getType() : BLANK; + String regionType = completionRegion!= null ? completionRegion.getType() : EMPTY; IStructuredDocumentRegion sdRegion = getStructuredDocumentRegion(documentPosition); // Handle the most common and best supported cases @@ -220,6 +224,40 @@ begin = sdRegion.getStartOffset(completionRegion); } + if (isPairValue(context, nodeAtOffset)) { + IJSONPair pair = (IJSONPair) nodeAtOffset; + IJSONValue value = pair.getValue(); + if (value != null) { + try { + begin = value.getStartOffset(); + String valueText = getNodeText(value); + valueText = valueText.trim(); + replaceLength = valueText.length(); + if (valueText.startsWith(QUOTE)) { + begin = begin + 1; + replaceLength = replaceLength - 1; + } + if (valueText.endsWith(QUOTE)) { + replaceLength = replaceLength - 1; + } + } catch (BadLocationException e) { + // ignore + } + } + } else if (nodeAtOffset instanceof IJSONPair) { + IJSONPair pair = (IJSONPair) nodeAtOffset; + try { + begin = pair.getStartOffset(); + String text = getNodeText(pair); + text = text.trim(); + replaceLength = pair.getName().length(); + if (text.startsWith(QUOTE)) { + begin = begin + 1; + } + } catch (BadLocationException e) { + // ignore + } + } contentAssistRequest = new ContentAssistRequest(nodeAtOffset, node.getParentNode(), sdRegion, completionRegion, begin, replaceLength, matchString); @@ -392,18 +430,18 @@ private String getMatchString(IStructuredDocumentRegion parent, ITextRegion aRegion, int offset) { if (aRegion == null) { - return BLANK; + return EMPTY; } String regionType = aRegion.getType(); if (regionType != JSONRegionContexts.JSON_OBJECT_KEY) { - return BLANK; + return EMPTY; } if ((parent.getText(aRegion).length() > 0) && (parent.getStartOffset(aRegion) < offset)) { return parent.getText(aRegion).substring(0, offset - parent.getStartOffset(aRegion)); } - return BLANK; + return EMPTY; } /** @@ -438,7 +476,7 @@ } int documentPosition = context.getInvocationOffset(); try { - String nodeText = node.getStructuredDocument().get(node.getStartOffset(), node.getEndOffset() - node.getStartOffset()); + String nodeText = getNodeText(node); int colonIndex = nodeText.indexOf(COLON); //$NON-NLS-1$ if (colonIndex >= 0) { return documentPosition > node.getStartOffset() + colonIndex; @@ -449,6 +487,10 @@ return false; } + private String getNodeText(IJSONNode node) throws BadLocationException { + return node.getStructuredDocument().get(node.getStartOffset(), node.getEndOffset() - node.getStartOffset()); + } + /** * <p> * helpful utility method for determining if one string starts with another
diff --git a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/contentassist/JSONCompletionProposalComputer.java b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/contentassist/JSONCompletionProposalComputer.java index 166f338..06f3345 100644 --- a/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/contentassist/JSONCompletionProposalComputer.java +++ b/bundles/org.eclipse.wst.json.ui/src/org/eclipse/wst/json/ui/internal/contentassist/JSONCompletionProposalComputer.java
@@ -11,6 +11,8 @@ package org.eclipse.wst.json.ui.internal.contentassist; import java.io.IOException; +import java.util.HashSet; +import java.util.Set; import org.eclipse.json.jsonpath.IJSONPath; import org.eclipse.json.jsonpath.JSONPath; @@ -37,10 +39,6 @@ public class JSONCompletionProposalComputer extends AbstractJSONCompletionProposalComputer { - private static final String QUOTE = "\""; //$NON-NLS-1$ - private static final String TRUE = "true"; //$NON-NLS-1$ - private static final String FALSE = "false"; //$NON-NLS-1$ - @Override public void sessionStarted() { // default is to do nothing @@ -98,24 +96,30 @@ boolean isValue = isPairValue(context, node); if (thisProperty != null && isValue) { if (thisProperty.getFirstType() == JSONSchemaType.Boolean) { - boolean showProperty = beginsWith(FALSE, matchString.trim()) - || beginsWith(TRUE, matchString.trim()); - if (showProperty) { - addStringProposal(contentAssistRequest, TRUE, false); + if (beginsWith(FALSE, matchString.trim())) { addStringProposal(contentAssistRequest, FALSE, false); } + if (beginsWith(TRUE, matchString.trim())) { + addStringProposal(contentAssistRequest, TRUE, false); + } return; } if (thisProperty.getFirstType() == JSONSchemaType.String) { if (thisProperty.getEnumList() != null && thisProperty.getEnumList().size() > 0) { for (String prop : thisProperty.getEnumList()) { - addStringProposal(contentAssistRequest, prop, - !(region.getType() == JSONRegionContexts.JSON_VALUE_STRING)); + boolean showProperty = beginsWith(prop, matchString.trim()); + if (showProperty) { + addStringProposal(contentAssistRequest, prop, + !(region.getType() == JSONRegionContexts.JSON_VALUE_STRING)); + } } } else { if (thisProperty.getDefaultValue() != null) { - addStringProposal(contentAssistRequest, thisProperty.getDefaultValue(), - !(region.getType() == JSONRegionContexts.JSON_VALUE_STRING)); + boolean showProperty = beginsWith(thisProperty.getDefaultValue(), matchString.trim()); + if (showProperty) { + addStringProposal(contentAssistRequest, thisProperty.getDefaultValue(), + !(region.getType() == JSONRegionContexts.JSON_VALUE_STRING)); + } } } return; @@ -131,14 +135,30 @@ } IJSONSchemaProperty parentProperty = schemaDocument .getProperty(path); + Set<String> existing = new HashSet<String>(); + boolean addComma = false; + if (node instanceof IJSONObject) { + addExisting(existing, node); + addComma = addComma(context, node); + } else if (node instanceof IJSONPair && node.getParentNode() instanceof IJSONObject) { + addExisting(existing, node.getParentNode()); + } if (parentProperty != null) { for (IJSONSchemaProperty property : parentProperty .getPropertyValues()) { - boolean showProperty = beginsWith(property.getName(), + boolean showProperty = !existing.contains(property.getName()) && beginsWith(property.getName(), matchString.trim()); if (showProperty) { - String replacementString = ContentAssistHelper + String replacementString; + if (node instanceof IJSONPair) { + replacementString = property.getName(); + } else { + replacementString = ContentAssistHelper .getRequiredName(node, property); + if (addComma) { + replacementString = replacementString + ","; + } + } String additionalProposalInfo = property .getDescription(); Image icon = JSONEditorPluginImageHelper @@ -164,6 +184,32 @@ } } + private boolean addComma(CompletionProposalInvocationContext context, IJSONNode node) { + IJSONNode child = node.getFirstChild(); + int documentPosition = context.getInvocationOffset(); + while (child != null) { + if (documentPosition > child.getStartOffset()) { + child = child.getNextSibling(); + } else { + break; + } + } + return child != null; + } + + private void addExisting(Set<String> existing, IJSONNode node) { + IJSONNode child = node.getFirstChild(); + while (child != null) { + if (child instanceof IJSONPair) { + String name = ((IJSONPair) child).getName(); + if (name != null && !name.isEmpty()) { + existing.add(name); + } + } + child = child.getNextSibling(); + } + } + private void addStringProposal(ContentAssistRequest contentAssistRequest, String replacementString, boolean addQuote) { String additionalProposalInfo = null; Image icon = null; @@ -178,7 +224,7 @@ JSONKeyCompletionProposal proposal = new JSONKeyCompletionProposal( replacementString, contentAssistRequest - .getReplacementBeginPosition() - matchString.length(), + .getReplacementBeginPosition(), contentAssistRequest.getReplacementLength(), replacementString.length() - 2, icon, displayString, null,