Skip to content

Commit

Permalink
Preference to convert single quote attribute values to double quote o…
Browse files Browse the repository at this point in the history
…n format.

Fixes eclipse-lemminx#263, eclipse-lemminx#294

Signed-off-by: Nikolas <nikolaskomonen@gmail.com>
  • Loading branch information
NikolasKomonen committed Feb 26, 2019
1 parent 458d491 commit a89f394
Show file tree
Hide file tree
Showing 15 changed files with 467 additions and 50 deletions.
28 changes: 28 additions & 0 deletions .vscode/java.test.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{
"run": {
"default": "",
"items": [
{
"name": "lsp4xml",
"projectName": "lsp4xml",
"workingDirectory": "",
"args": [],
"vmargs": [],
"preLaunchTask": ""
}
]
},
"debug": {
"default": "",
"items": [
{
"name": "lsp4xml",
"projectName": "lsp4xml",
"workingDirectory": "",
"args": [],
"vmargs": [],
"preLaunchTask": ""
}
]
}
}
34 changes: 33 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,38 @@
//Use consistent indentation
"editor.detectIndentation": false,
"editor.tabSize": 4,
"editor.insertSpaces": false
"editor.insertSpaces": false,
"java.test.defaultConfig": "config-41b2e8",
"java.test.config": [
{
"run": {
"default": "",
"items": [
{
"name": "lsp4xml",
"projectName": "lsp4xml",
"workingDirectory": "",
"args": [],
"vmargs": [],
"preLaunchTask": ""
}
]
},
"debug": {
"default": "",
"items": [
{
"name": "lsp4xml",
"projectName": "lsp4xml",
"workingDirectory": "",
"args": [],
"vmargs": [],
"preLaunchTask": ""
}
]
},
"name": "config-41b2e8"
}
]

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ public class DOMAttr extends DOMNode implements org.w3c.dom.Attr {

private DOMNode nodeAttrValue;

private String value;
private String quotelessValue;//Value without quotes

private String originalValue;//Exact value from document

private final DOMNode ownerElement;

private boolean hasDelimiter; // has '='

class AttrNameOrValue extends DOMNode {

private final DOMAttr ownerAttr;
Expand Down Expand Up @@ -110,7 +114,7 @@ public DOMElement getOwnerElement() {
*/
@Override
public String getValue() {
return value;
return quotelessValue;
}

/*
Expand Down Expand Up @@ -157,23 +161,71 @@ public DOMNode getNodeAttrName() {
return nodeAttrName;
}

public void setDelimiter(boolean hasDelimiter) {
this.hasDelimiter = hasDelimiter;
}

public boolean hasDelimiter() {
return this.hasDelimiter;
}

/**
* Get original attribute value from the document.
*
* This will include quotations (", ').
* @return attribute value with quotations if it had them.
*/
public String getOriginalValue() {
return originalValue;
}

public void setValue(String value, int start, int end) {
this.value = getValue(value);
this.originalValue = value;
this.quotelessValue = convertToQuotelessValue(value);
this.nodeAttrValue = start != -1 ? new AttrNameOrValue(start, end, this) : null;
}

private static String getValue(String value) {
/**
* Returns a String of 'value' without surrounding quotes if it had them.
* @param value
* @return
*/
public static String convertToQuotelessValue(String value) {
if (value == null) {
return null;
}
if (value.isEmpty()) {
return value;
}
int start = value.charAt(0) == '\"' ? 1 : 0;
int end = value.charAt(value.length() - 1) == '\"' ? value.length() - 1 : value.length();
char quoteValue = value.charAt(0);
int start = quoteValue == '\"' || quoteValue == '\'' ? 1 : 0;
quoteValue = value.charAt(value.length() - 1);
int end = quoteValue == '\"' || quoteValue == '\'' ? value.length() - 1 : value.length();
return value.substring(start, end);
}

/**
* Checks if 'value' has matching surrounding quotations.
* @param value
* @return
*/
public static boolean isQuoted(String value) {
if (value == null) {
return false;
}
if (value.isEmpty()) {
return false;
}
char quoteValueStart = value.charAt(0);
boolean start = quoteValueStart == '\"' || quoteValueStart == '\'' ? true : false;
if(start == false) {
return false;
}
char quoteValueEnd = value.charAt(value.length() - 1);
boolean end = (quoteValueEnd == '\"' || quoteValueEnd == '\'') && quoteValueEnd == quoteValueStart ? true : false;
return end;
}

public DOMNode getNodeAttrValue() {
return nodeAttrValue;
}
Expand Down Expand Up @@ -201,7 +253,7 @@ public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + ((value == null) ? 0 : value.hashCode());
result = prime * result + ((quotelessValue == null) ? 0 : quotelessValue.hashCode());
return result;
}

Expand All @@ -219,10 +271,10 @@ public boolean equals(Object obj) {
return false;
} else if (!name.equals(other.name))
return false;
if (value == null) {
if (other.value != null)
if (quotelessValue == null) {
if (other.quotelessValue != null)
return false;
} else if (!value.equals(other.value))
} else if (!quotelessValue.equals(other.quotelessValue))
return false;
return true;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ public DOMDocument parse(TextDocument document, URIResolverExtensionManager reso
break;
}

case DelimiterAssign: {
if(attr != null) {
//Sets the value to the '=' position in case there is no AttributeValue
attr.setValue(null, scanner.getTokenOffset(), scanner.getTokenEnd());
attr.setDelimiter(true);
}
break;
}

case AttributeValue: {
String value = scanner.getTokenText();
if (curr.hasAttributes() && attr != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public class Constants {

public static final Pattern ATTRIBUTE_NAME_REGEX = Pattern.compile("^[^\\s\"'<>/=\\x00-\\x0F\\x7F\\x80-\\x9F]*");

public static final Pattern ATTRIBUTE_VALUE_REGEX = Pattern.compile("^[^\\s\"'`=<>\\/]+");
public static final Pattern ATTRIBUTE_VALUE_REGEX = Pattern.compile("^(\"[^\"]*\"?)|(\'[^\']*\'?)");

public static final Pattern URL_VALUE_REGEX = Pattern.compile("^(\"|\')[^<>\"]*(\"|\')");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ private Matcher getCachedMatcher(Pattern regex) {
matcher = regex.matcher(source);
regexpCache.put(regex, matcher);
}
matcher.reset(); // Cached regex caused issues, needed to reset it.
return matcher;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -318,22 +318,26 @@ TokenType internalScan() {
hasSpaceAfterTag = false;
return finishToken(offset, TokenType.AttributeValue);
}
int ch = stream.peekChar();
if (ch == _SQO || ch == _DQO || ch == _SIQ) { // " || " || '
stream.advance(1); // consume quote
if (stream.advanceUntilChar(ch)) {
stream.advance(1); // consume quote
}
if ("type".equals(lastAttributeName)) {
lastTypeValue = stream.getSource().substring(offset + 1, stream.pos() - 1);
}
state = ScannerState.WithinTag;
hasSpaceAfterTag = false;
return finishToken(offset, TokenType.AttributeValue);
}
hasSpaceAfterTag = true;
state = ScannerState.WithinTag;
hasSpaceAfterTag = false;
return internalScan(); // no advance yet - jump to WithinTag
return internalScan();

// int ch = stream.peekChar();
// if (ch == _SQO || ch == _DQO || ch == _SIQ) { // " || " || '
// stream.advance(1); // consume quote
// if (stream.advanceUntilChar(ch)) {
// stream.advance(1); // consume quote
// }
// if ("type".equals(lastAttributeName)) {
// lastTypeValue = stream.getSource().substring(offset + 1, stream.pos() - 1);
// }
// state = ScannerState.WithinTag;
// hasSpaceAfterTag = false;
// return finishToken(offset, TokenType.AttributeValue);
// }
// state = ScannerState.WithinTag;
// hasSpaceAfterTag = false;
// return internalScan(); // no advance yet - jump to WithinTag

// DTD

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ private int generate(Collection<CMAttributeDeclaration> attributes, int level, i
String value = generateAttributeValue(defaultValue, enumerationValues, canSupportSnippets, snippetIndex,
false);
if (attributesSize != 1) {
xml.addAttribute(attributeDeclaration.getName(), value, attributeIndex, level, tagName);
xml.addAttribute(attributeDeclaration.getName(), value, level, true);
} else {
xml.addSingleAttribute(attributeDeclaration.getName(), value);
xml.addSingleAttribute(attributeDeclaration.getName(), value, true);
}
attributeIndex++;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,12 @@ private void format(DOMNode node, int level, int end, XMLBuilder xml) {
List<DOMAttr> attributes = element.getAttributeNodes();
if (attributes.size() == 1) {
DOMAttr singleAttribute = attributes.get(0);
xml.addSingleAttribute(singleAttribute.getName(), singleAttribute.getValue());
xml.addSingleAttribute(singleAttribute.getName(), singleAttribute.getOriginalValue());
} else {
int attributeIndex = 0;
for (DOMAttr attr : attributes) {
String attributeName = attr.getName();
xml.addAttribute(attributeName, attr.getValue(), attributeIndex, level, tag);
xml.addAttribute(attr, level);
attributeIndex++;
}
}
Expand Down Expand Up @@ -205,7 +205,7 @@ private void format(DOMNode node, int level, int end, XMLBuilder xml) {
if (value == null) {
continue;
}
xml.addSingleAttribute(name, value);
xml.addSingleAttribute(name, value, true);
}
}
xml.endPrologOrPI();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
*/
package org.eclipse.lsp4xml.settings;

import java.util.Objects;

import org.eclipse.lsp4j.FormattingOptions;

/**
Expand All @@ -27,6 +29,14 @@ public class XMLFormattingOptions extends FormattingOptions {
private static final String JOIN_CONTENT_LINES = "joinContentLines";
private static final String ENABLED = "enabled";
private static final String SPACE_BEFORE_EMPTY_CLOSE_TAG = "spaceBeforeEmptyCloseTag";
private static final String QUOTATIONS = "quotations";

// Values for QUOTATIONS
public static final String DOUBLE_QUOTES_VALUE = "doubleQuotes";
public static final String SINGLE_QUOTES_VALUE = "singleQuotes";
enum Quotations {
doubleQuotes, singleQuotes
}

public XMLFormattingOptions() {
this(false);
Expand All @@ -53,6 +63,7 @@ public void initializeDefaultSettings() {
this.setJoinContentLines(false);
this.setEnabled(true);
this.setSpaceBeforeEmptyCloseTag(true);
this.setQuotations(DOUBLE_QUOTES_VALUE);
}

public XMLFormattingOptions(int tabSize, boolean insertSpaces, boolean initializeDefaultSettings) {
Expand Down Expand Up @@ -168,6 +179,46 @@ public boolean isSpaceBeforeEmptyCloseTag() {
}
}

public void setQuotations(final String quotations) {
this.putString(XMLFormattingOptions.QUOTATIONS, quotations);
}

/**
* Returns the value of the format.quotations preference.
*
* If invalid or null, the default is {@link XMLFormattingOptions#DOUBLE_QUOTES_VALUE}.
*/
public String getQuotations() {
final String value = this.getString(XMLFormattingOptions.QUOTATIONS);
if ((value != null) && isValidQuotations()) {
return value;
} else {
this.setQuotations(XMLFormattingOptions.DOUBLE_QUOTES_VALUE);
return DOUBLE_QUOTES_VALUE;// default
}
}

/**
* If the quotations preference is a valid option.
*
* Keep up to date with new preferences.
* @return
*/
private boolean isValidQuotations() {
final String value = this.getString(XMLFormattingOptions.QUOTATIONS);
return SINGLE_QUOTES_VALUE.equals(value) || DOUBLE_QUOTES_VALUE.equals(value);
}

/**
* Checks if {@code quotation} equals the current value for {@code format.quotations}.
* @param quotation
* @return
*/
public boolean isQuotations(String quotation) {
String value = getQuotations();
return Objects.equals(value, quotation);
}

public XMLFormattingOptions merge(FormattingOptions formattingOptions) {
formattingOptions.entrySet().stream().forEach(entry -> {
String key = entry.getKey();
Expand Down
Loading

0 comments on commit a89f394

Please sign in to comment.