/******************************************************************************* * Copyright (c) 2004, 2016 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Angelo Zerr <angelo.zerr@gmail.com> - copied from org.eclipse.wst.css.core.internal.formatter.AbstractCSSSourceFormatter * modified in order to process JSON Objects. *******************************************************************************/ package org.eclipse.wst.json.core.internal.format; import java.util.ArrayList; import java.util.Iterator; import org.eclipse.core.runtime.Preferences; import org.eclipse.jface.text.DefaultLineTracker; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.TextUtilities; import org.eclipse.wst.json.core.JSONCorePlugin; import org.eclipse.wst.json.core.cleanup.IJSONCleanupStrategy; import org.eclipse.wst.json.core.cleanup.JSONCleanupStrategyImpl; import org.eclipse.wst.json.core.document.IJSONArray; import org.eclipse.wst.json.core.document.IJSONDocument; import org.eclipse.wst.json.core.document.IJSONModel; import org.eclipse.wst.json.core.document.IJSONNode; import org.eclipse.wst.json.core.document.IJSONObject; import org.eclipse.wst.json.core.internal.util.RegionIterator; import org.eclipse.wst.json.core.preferences.JSONCorePreferenceNames; import org.eclipse.wst.json.core.regions.JSONRegionContexts; import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier; import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocument; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegionList; public abstract class AbstractJSONSourceFormatter implements IJSONSourceFormatter { protected final static short GENERATE = 0; protected final static short FORMAT = 1; protected final static short CLEANUP = 2; protected static short strategy; AbstractJSONSourceFormatter() { super(); } protected void appendDelimBefore(IJSONNode node, CompoundRegion toAppend, StringBuilder source) { if (node == null || source == null) return; if (isCleanup() && !getCleanupStrategy(node).isFormatSource()) return; // for not formatting case on cleanup action String delim = getLineDelimiter(node); boolean needIndent = !(node instanceof IJSONDocument); if (toAppend == null) { source.append(delim); source.append(getIndent(node)); if (needIndent) source.append(getIndentString()); } else { String type = toAppend.getType(); if (type == JSONRegionContexts.JSON_COMMENT) { RegionIterator it = new RegionIterator( toAppend.getDocumentRegion(), toAppend.getTextRegion()); it.prev(); ITextRegion prev = it.prev(); int[] result = null; if (prev == null || (prev.getType() == JSONRegionContexts.WHITE_SPACE && (result = TextUtilities .indexOf(DefaultLineTracker.DELIMITERS, it.getStructuredDocumentRegion() .getText(prev), 0))[0] >= 0)) { // Collapse to one empty line if there's more than one. if (result != null) { int offset = result[0] + DefaultLineTracker.DELIMITERS[result[1]] .length(); if (offset < it.getStructuredDocumentRegion() .getText(prev).length()) { if (TextUtilities.indexOf( DefaultLineTracker.DELIMITERS, it .getStructuredDocumentRegion() .getText(prev), offset)[0] >= 0) { source.append(delim); } } source.append(delim); source.append(getIndent(node)); if (needIndent) source.append(getIndentString()); } } else if (prev.getType() == JSONRegionContexts.JSON_COMMENT) { String fullText = toAppend.getDocumentRegion().getFullText( prev); String trimmedText = toAppend.getDocumentRegion().getText( prev); String whiteSpaces = "";//$NON-NLS-1$ if (fullText != null && trimmedText != null) whiteSpaces = fullText.substring(trimmedText.length()); int[] delimiterFound = TextUtilities.indexOf( DefaultLineTracker.DELIMITERS, whiteSpaces, 0); if (delimiterFound[0] != -1) { source.append(delim); } else { appendSpaceBefore(node, toAppend.getText(), source); /* * If two comments can't be adjusted in one * line(combined length exceeds line width), a tab is * also appended along with next line delimiter , we * need to remove that. */ if (source.toString().endsWith(getIndentString())) { source.delete((source.length() - getIndentString() .length()), source.length()); } } } else { appendSpaceBefore(node, toAppend.getText(), source); } } else if (type == JSONRegionContexts.JSON_COMMA) { RegionIterator it = new RegionIterator( toAppend.getDocumentRegion(), toAppend.getTextRegion()); it.prev(); ITextRegion prev = it.prev(); Preferences preferences = JSONCorePlugin.getDefault() .getPluginPreferences(); if (prev.getType() == JSONRegionContexts.WHITE_SPACE && TextUtilities.indexOf(DefaultLineTracker.DELIMITERS, it.getStructuredDocumentRegion().getText(prev), 0)[0] >= 0) { source.append(delim); source.append(getIndent(node)); if (needIndent) source.append(getIndentString()); } else if (preferences .getInt(JSONCorePreferenceNames.LINE_WIDTH) > 0 && (!preferences .getBoolean(JSONCorePreferenceNames.WRAPPING_PROHIBIT_WRAP_ON_ATTR) || node .getOwnerDocument().getNodeType() != IJSONNode.PAIR_NODE)) { int length = getLastLineLength(node, source); int append = 1; if (length + append > preferences .getInt(JSONCorePreferenceNames.LINE_WIDTH)) { source.append(getLineDelimiter(node)); source.append(getIndent(node)); if (needIndent) source.append(getIndentString()); } } } else if (type == JSONRegionContexts.JSON_OBJECT_OPEN || type == JSONRegionContexts.JSON_OBJECT_CLOSE || type == JSONRegionContexts.JSON_ARRAY_OPEN || type == JSONRegionContexts.JSON_ARRAY_CLOSE) { source.append(delim); source.append(getIndent(node)); } else { source.append(delim); source.append(getIndent(node)); if (needIndent) source.append(getIndentString()); } } } protected void appendSpaceBefore(IJSONNode node, CompoundRegion toAppend, StringBuilder source) { if (node == null || toAppend == null || source == null) return; if (isCleanup() && !getCleanupStrategy(node).isFormatSource()) return; // for not formatting case on cleanup action String type = toAppend.getType(); Preferences preferences = JSONCorePlugin.getDefault() .getPluginPreferences(); boolean needIndent = !(node instanceof IJSONDocument); /*if (type == JSONRegionContexts.JSON_COMMENT) { // check whether previous region is 'S' and has CR-LF String delim = getLineDelimiter(node); RegionIterator it = new RegionIterator( toAppend.getDocumentRegion(), toAppend.getTextRegion()); it.prev(); ITextRegion prev = it.prev(); // bug390904 if (prev.getType() == JSONRegionContexts.JSON_LBRACE && TextUtilities .indexOf(DefaultLineTracker.DELIMITERS, it.getStructuredDocumentRegion() .getFullText(prev), 0)[0] > 0) { source.append(delim); source.append(getIndent(node)); source.append(getIndentString()); } else if (prev.getType() == JSONRegionContexts.WHITE_SPACE && TextUtilities.indexOf(DefaultLineTracker.DELIMITERS, it .getStructuredDocumentRegion().getText(prev), 0)[0] >= 0) { source.append(delim); source.append(getIndent(node)); if (needIndent) source.append(getIndentString()); } else { appendSpaceBefore(node, toAppend.getText(), source); } }*/ if ((type == JSONRegionContexts.JSON_OBJECT_OPEN || type == JSONRegionContexts.JSON_ARRAY_OPEN) && preferences .getBoolean(JSONCorePreferenceNames.WRAPPING_NEWLINE_ON_OPEN_BRACE)) { String delim = getLineDelimiter(node); source.append(delim); source.append(getIndent(node)); // } else if (type == JSONRegionContexts.JSON_CURLY_BRACE_CLOSE) { // } else if (type == JSONRegionContexts.JSON_INCLUDES || type == // JSONRegionContexts.JSON_DASHMATCH) { /*} else if (type == JSONRegionContexts.JSON_DECLARATION_SEPARATOR && node instanceof IJSONStyleDeclItem) { int n = preferences .getInt(JSONCorePreferenceNames.FORMAT_PROP_PRE_DELIM); // no delimiter case while (n-- > 0) source.append(" ");//$NON-NLS-1$ } else if (type == JSONRegionContexts.JSON_DECLARATION_VALUE_OPERATOR || type == JSONRegionContexts.JSON_DECLARATION_VALUE_PARENTHESIS_CLOSE) { if (preferences.getInt(JSONCorePreferenceNames.LINE_WIDTH) > 0 && (!preferences .getBoolean(JSONCorePreferenceNames.WRAPPING_PROHIBIT_WRAP_ON_ATTR) || node .getOwnerDocument().getNodeType() != IJSONNode.STYLEDECLARATION_NODE)) { int length = getLastLineLength(node, source); int append = 1; if (length + append > preferences .getInt(JSONCorePreferenceNames.LINE_WIDTH)) { source.append(getLineDelimiter(node)); source.append(getIndent(node)); if (needIndent) source.append(getIndentString()); } } } else if (JSONRegionContexts.JSON_FOREIGN_ELEMENT == type || JSONRegionContexts.JSON_DECLARATION_DELIMITER == type) { return; */ } else appendSpaceBefore(node, toAppend.getText(), source); } protected void appendSpaceBefore(IJSONNode node, String toAppend, StringBuilder source) { if (node == null || source == null) return; if (isCleanup() && !getCleanupStrategy(node).isFormatSource()) return; // for not formatting case on cleanup action Preferences preferences = JSONCorePlugin.getDefault() .getPluginPreferences(); if (toAppend != null && toAppend.startsWith("{") && preferences.getBoolean(JSONCorePreferenceNames.WRAPPING_NEWLINE_ON_OPEN_BRACE)) {//$NON-NLS-1$ source.append(getLineDelimiter(node)); source.append(getIndent(node)); return; } else if (/* ! mgr.isOnePropertyPerLine() && */preferences .getInt(JSONCorePreferenceNames.LINE_WIDTH) > 0 && (!preferences .getBoolean(JSONCorePreferenceNames.WRAPPING_PROHIBIT_WRAP_ON_ATTR) /*|| node .getOwnerDocument().getNodeType() != IJSONNode.STYLEDECLARATION_NODE*/)) { int n = getLastLineLength(node, source); int append = (toAppend != null) ? TextUtilities.indexOf( DefaultLineTracker.DELIMITERS, toAppend, 0)[0] : 0; if (toAppend != null) append = (append < 0) ? toAppend.length() : append; if (n + append + 1 > preferences .getInt(JSONCorePreferenceNames.LINE_WIDTH)) { source.append(getLineDelimiter(node)); source.append(getIndent(node)); source.append(getIndentString()); return; } } // bug412395 // just verify if the source and the toAppend strings do not end with a // whitespace to avoid the whitespace duplication. if (!(source.length() > 0 && source.toString().charAt( source.length() - 1) == ' ') && !(toAppend.length() > 0 && toAppend .charAt(toAppend.length() - 1) == ' ')) { source.append(" ");//$NON-NLS-1$ } } @Override public final StringBuilder cleanup(IJSONNode node) { short oldStrategy = strategy; strategy = CLEANUP; StringBuilder source = formatProc(node); strategy = oldStrategy; return source; } @Override public final StringBuilder cleanup(IJSONNode node, IRegion region) { short oldStrategy = strategy; strategy = CLEANUP; StringBuilder source = formatProc(node, region); strategy = oldStrategy; return source; } protected String decoratedIdentRegion(CompoundRegion region, IJSONCleanupStrategy stgy) { if (isFormat()) return region.getText(); String text = null; if (!stgy.isFormatSource()) text = region.getFullText(); else text = region.getText(); // if (region.getType() == JSONRegionContexts.WHITE_SPACETRING // || region.getType() == JSONRegionContexts.JSON_URI) // return decoratedRegion(region, 0, stgy); if (isCleanup()) { if (stgy.getIdentCase() == IJSONCleanupStrategy.ASIS /*|| region.getType() == JSONRegionContexts.JSON_COMMENT*/) return text; else if (stgy.getIdentCase() == IJSONCleanupStrategy.UPPER) return text.toUpperCase(); else return text.toLowerCase(); } Preferences preferences = JSONCorePlugin.getDefault() .getPluginPreferences(); // if (region.getType() == JSONRegionContexts.JSON_COMMENT) // return text; // else if (preferences.getInt(JSONCorePreferenceNames.CASE_IDENTIFIER) == JSONCorePreferenceNames.UPPER) // return text.toUpperCase(); // else return text.toLowerCase(); } protected String decoratedPropNameRegion(CompoundRegion region, IJSONCleanupStrategy stgy) { if (isFormat()) return region.getText(); String text = null; if (!stgy.isFormatSource()) text = region.getFullText(); else text = region.getText(); // if (region.getType() == JSONRegionContexts.WHITE_SPACETRING // || region.getType() == JSONRegionContexts.JSON_URI) // return decoratedRegion(region, 1, stgy); if (isCleanup()) { /*if (stgy.getPropNameCase() == JSONCleanupStrategy.ASIS || region.getType() != JSONRegionContexts.JSON_DECLARATION_PROPERTY) return text; else*/ if (stgy.getPropNameCase() == IJSONCleanupStrategy.UPPER) return text.toUpperCase(); else return text.toLowerCase(); } Preferences preferences = JSONCorePlugin.getDefault() .getPluginPreferences(); // if (region.getType() != JSONRegionContexts.JSON_DECLARATION_PROPERTY) // return text; //else if (preferences.getInt(JSONCorePreferenceNames.CASE_PROPERTY_NAME) == JSONCorePreferenceNames.UPPER) return text.toUpperCase(); else return text.toLowerCase(); } protected String decoratedPropValueRegion(CompoundRegion region, IJSONCleanupStrategy stgy) { if (isFormat()) return region.getText(); String text = null; if (!stgy.isFormatSource()) text = region.getFullText(); else text = region.getText(); String type = region.getType(); // if (type == JSONRegionContexts.WHITE_SPACETRING // || type == JSONRegionContexts.JSON_URI // || type == JSONRegionContexts.JSON_DECLARATION_VALUE_URI) // return decoratedRegion(region, 2, stgy); if (isCleanup()) { if (stgy.getPropValueCase() != IJSONCleanupStrategy.ASIS) { //if (type == JSONRegionContexts.JSON_COMMENT) { //} else { if (stgy.getPropValueCase() == IJSONCleanupStrategy.UPPER) text = text.toUpperCase(); else text = text.toLowerCase(); //} } } return text; } protected String decoratedRegion(CompoundRegion region, int type, IJSONCleanupStrategy stgy) { if (isFormat()) return region.getText(); Preferences preferences = JSONCorePlugin.getDefault() .getPluginPreferences(); String text = null; if (!stgy.isFormatSource()) text = region.getFullText(); else text = region.getText(); return text; } @Override public final StringBuilder format(IJSONNode node) { short oldStrategy = strategy; strategy = FORMAT; StringBuilder source = formatProc(node); strategy = oldStrategy; return source; } @Override public final StringBuilder format(IJSONNode node, IRegion region) { short oldStrategy = strategy; strategy = FORMAT; StringBuilder source = formatProc(node, region); strategy = oldStrategy; return source; } protected void formatChildren(IJSONNode node, StringBuilder source) { IJSONNode child = node.getFirstChild(); IJSONNode last = null; while (child != null) { // append child IJSONSourceFormatter formatter = (IJSONSourceFormatter) ((INodeNotifier) child) .getAdapterFor(IJSONSourceFormatter.class); if (formatter == null) { formatter = JSONSourceFormatterFactory.getInstance() .getSourceFormatter(child); } StringBuilder childSource = ((AbstractJSONSourceFormatter) formatter) .formatProc(child); source.append(childSource); last = child; child = child.getNextSibling(); } } protected void formatChildren(IJSONNode node, IRegion region, StringBuilder source) { IJSONNode child = node.getFirstChild(); int start = region.getOffset(); int end = region.getOffset() + region.getLength(); while (child != null) { int curEnd = child.getEndOffset(); StringBuilder childSource = null; boolean toFinish = false; if (start < curEnd) { int curStart = child.getStartOffset(); if (curStart < end) { // append child IJSONSourceFormatter formatter = (IJSONSourceFormatter) ((INodeNotifier) child) .getAdapterFor(IJSONSourceFormatter.class); if (formatter == null) { formatter = JSONSourceFormatterFactory.getInstance() .getSourceFormatter(child); } if (includes(region, curStart, curEnd)) childSource = ((AbstractJSONSourceFormatter) formatter) .formatProc(child); else childSource = ((AbstractJSONSourceFormatter) formatter) .formatProc( child, overlappedRegion(region, curStart, curEnd)); } else toFinish = true; } if (childSource != null) { source.append(childSource); } if (toFinish) break; child = child.getNextSibling(); } } /** * Generate or format source after the last child and append to string * buffer */ protected abstract void formatPost(IJSONNode node, StringBuilder source); /** * Generate or format source after the last child and append to string * buffer */ protected abstract void formatPost(IJSONNode node, IRegion region, StringBuilder source); /** * Generate or format source before the first child and append to string * buffer */ protected abstract void formatPre(IJSONNode node, StringBuilder source); /** * Generate or format source before the first child and append to string * buffer */ abstract protected void formatPre(IJSONNode node, IRegion region, StringBuilder source); /** * * @return java.lang.StringBuilder * @param node * org.eclipse.wst.css.core.model.interfaces.IJSONNode */ protected final StringBuilder formatProc(IJSONNode node) { StringBuilder source = new StringBuilder(); formatPre(node, source); formatChildren(node, source); formatPost(node, source); return source; } /** * * @return java.lang.StringBuilder * @param node * org.eclipse.wst.css.core.model.interfaces.IJSONNode * @param region * org.eclipse.jface.text.IRegion */ protected StringBuilder formatProc(IJSONNode node, IRegion region) { StringBuilder source = new StringBuilder(); int curStart = node.getStartOffset(); int curEnd = node.getEndOffset(); if (node.hasChildNodes()) { curEnd = node.getFirstChild().getStartOffset(); if (overlaps(region, curStart, curEnd)) { if (includes(region, curStart, curEnd)) formatPre(node, source); else formatPre(node, overlappedRegion(region, curStart, curEnd), source); } curStart = curEnd; curEnd = node.getLastChild().getEndOffset(); if (overlaps(region, curStart, curEnd)) { if (includes(region, curStart, curEnd)) formatChildren(node, source); else formatChildren(node, overlappedRegion(region, curStart, curEnd), source); } curStart = curEnd; curEnd = node.getEndOffset(); if (overlaps(region, curStart, curEnd)) { if (includes(region, curStart, curEnd)) formatPost(node, source); else formatPost(node, overlappedRegion(region, curStart, curEnd), source); } } else if (node instanceof IJSONArray || node instanceof IJSONObject) { curStart = node.getStartOffset(); curEnd = node.getEndOffset(); if (overlaps(region, curStart, curEnd)) { if (includes(region, curStart, curEnd)) { formatPre(node, source); formatPost(node, source); } else { formatPre(node, overlappedRegion(region, curStart, curEnd), source); formatPost(node, overlappedRegion(region, curStart, curEnd), source); } } } else { // curEnd = getChildInsertPos(node); curEnd = node.getEndOffset() > 0 ? node.getEndOffset() : -1; if (overlaps(region, curStart, curEnd)) { if (includes(region, curStart, curEnd)) formatPre(node, source); else formatPre(node, overlappedRegion(region, curStart, curEnd), source); } curStart = curEnd; curEnd = node.getEndOffset(); if (overlaps(region, curStart, curEnd)) { if (includes(region, curStart, curEnd)) formatPost(node, source); else formatPost(node, overlappedRegion(region, curStart, curEnd), source); } } return source; } /** * Insert the method's description here. * * @return org.eclipse.wst.css.core.internal.cleanup.JSONCleanupStrategy * @param node * org.eclipse.wst.css.core.model.interfaces.IJSONNode */ protected IJSONCleanupStrategy getCleanupStrategy(IJSONNode node) { IJSONCleanupStrategy currentStrategy = JSONCleanupStrategyImpl .getInstance(); IJSONDocument doc = node.getOwnerDocument(); if (doc == null) return currentStrategy; IJSONModel model = doc.getModel(); if (model == null) return currentStrategy; return currentStrategy; } protected String getIndent(IJSONNode node) { if (node == null) return "";//$NON-NLS-1$ IJSONNode parent = node.getParentNode(); if (parent == null || parent instanceof IJSONDocument) return "";//$NON-NLS-1$ String parentIndent = getIndent(parent); return parentIndent + getIndentString(); } protected int getLastLineLength(IJSONNode node, StringBuilder source) { if (node == null || source == null) return 0; String delim = getLineDelimiter(node); String str = new String(source); int n = str.lastIndexOf(delim); if (n < 0) return str.length(); return str.length() - n - delim.length(); } String getLineDelimiter(IJSONNode node) { IJSONModel model = node != null ? node.getOwnerDocument().getModel() : null; IStructuredDocument structuredDocument = model != null ? model.getStructuredDocument() : null; return structuredDocument != null ? structuredDocument.getLineDelimiter() : "\n"; //$NON-NLS-1$ } protected CompoundRegion[] getOutsideRegions(IStructuredDocument model, IRegion reg) { CompoundRegion[] ret = new CompoundRegion[2]; RegionIterator it = new RegionIterator(model, reg.getOffset()); it.prev(); if (it.hasPrev()) { ITextRegion textRegion = it.prev(); IStructuredDocumentRegion documentRegion = it .getStructuredDocumentRegion(); ret[0] = new CompoundRegion(documentRegion, textRegion); } else { ret[0] = null; } it.reset(model, reg.getOffset() + reg.getLength()); if (it.hasNext()) { ITextRegion textRegion = it.next(); IStructuredDocumentRegion documentRegion = it .getStructuredDocumentRegion(); ret[1] = new CompoundRegion(documentRegion, textRegion); } else { ret[1] = null; } return ret; } protected IJSONSourceFormatter getParentFormatter(IJSONNode node) { IJSONNode parent = node.getParentNode(); if (parent != null) { IJSONSourceFormatter formatter = (IJSONSourceFormatter) ((INodeNotifier) parent) .getAdapterFor(IJSONSourceFormatter.class); if (formatter == null) { formatter = JSONSourceFormatterFactory.getInstance() .getSourceFormatter(parent); } return formatter; } return null; } protected CompoundRegion[] getRegions(IStructuredDocument model, IRegion reg, IRegion exceptFor, String pickupType) { int start = reg.getOffset(); int end = reg.getOffset() + reg.getLength(); int startE = (exceptFor != null) ? exceptFor.getOffset() : -1; int endE = (exceptFor != null) ? exceptFor.getOffset() + exceptFor.getLength() : 0; ArrayList list = new ArrayList(); IStructuredDocumentRegion flatNode = model .getRegionAtCharacterOffset(start); boolean pickuped = false; while (flatNode != null && flatNode.getStartOffset() < end) { ITextRegionList regionList = flatNode.getRegions(); Iterator it = regionList.iterator(); while (it.hasNext()) { ITextRegion region = (ITextRegion) it.next(); if (flatNode.getStartOffset(region) < start) continue; if (end <= flatNode.getStartOffset(region)) break; if (startE >= 0 && startE <= flatNode.getStartOffset(region) && flatNode.getEndOffset(region) <= endE) continue; // if (region.getType() == JSONRegionContexts.JSON_COMMENT // || region.getType() == JSONRegionContexts.JSON_CDC // || region.getType() == JSONRegionContexts.JSON_CDO) // list.add(new CompoundRegion(flatNode, region)); // else if (!pickuped && region.getType() == pickupType) { list.add(new CompoundRegion(flatNode, region)); pickuped = true; } } flatNode = flatNode.getNext(); } if (list.size() > 0) { CompoundRegion[] regions = new CompoundRegion[list.size()]; list.toArray(regions); return regions; } return new CompoundRegion[0]; } protected CompoundRegion[] getRegionsWithoutWhiteSpaces( IStructuredDocument model, IRegion reg, IJSONCleanupStrategy stgy) { int start = reg.getOffset(); int end = reg.getOffset() + reg.getLength() - 1; ArrayList list = new ArrayList(); IStructuredDocumentRegion flatNode = model .getRegionAtCharacterOffset(start); while (flatNode != null && flatNode.getStartOffset() <= end) { ITextRegionList regionList = flatNode.getRegions(); Iterator it = regionList.iterator(); while (it.hasNext()) { ITextRegion region = (ITextRegion) it.next(); if (flatNode.getStartOffset(region) < start) continue; if (end < flatNode.getStartOffset(region)) break; if (region.getType() != JSONRegionContexts.WHITE_SPACE || (isCleanup() && !stgy.isFormatSource())) // for // not // formatting // case // on // cleanup // action list.add(new CompoundRegion(flatNode, region)); } flatNode = flatNode.getNext(); } if (list.size() > 0) { CompoundRegion[] regions = new CompoundRegion[list.size()]; list.toArray(regions); return regions; } return new CompoundRegion[0]; } public static boolean includes(IRegion region, int start, int end) { if (region == null) return false; return (region.getOffset() <= start) && (end <= region.getOffset() + region.getLength()); } /** * * @return boolean */ protected static boolean isCleanup() { return strategy == CLEANUP; } /** * * @return boolean */ protected static boolean isFormat() { return strategy == FORMAT; } protected boolean isIncludesPreEnd(IJSONNode node, IRegion region) { return (node.getFirstChild() != null && ((IndexedRegion) node .getFirstChild()).getStartOffset() == (region.getOffset() + region .getLength())); } static protected boolean needS(CompoundRegion region) { return (region != null && region.getType() != JSONRegionContexts.WHITE_SPACE); } public static IRegion overlappedRegion(IRegion region, int start, int end) { if (overlaps(region, start, end)) { int offset = (region.getOffset() <= start) ? start : region .getOffset(); int length = ((end <= region.getOffset() + region.getLength()) ? end : region.getOffset() + region.getLength()) - offset; return new FormatRegion(offset, length); } return null; } public static boolean overlaps(IRegion region, int start, int end) { if (region == null) return false; return (start < region.getOffset() + region.getLength()) && (region.getOffset() < end); } protected String getIndentString() { StringBuilder indent = new StringBuilder(); Preferences preferences = JSONCorePlugin.getDefault() .getPluginPreferences(); if (preferences != null) { char indentChar = ' '; String indentCharPref = preferences .getString(JSONCorePreferenceNames.INDENTATION_CHAR); if (JSONCorePreferenceNames.TAB.equals(indentCharPref)) { indentChar = '\t'; } int indentationWidth = preferences .getInt(JSONCorePreferenceNames.INDENTATION_SIZE); for (int i = 0; i < indentationWidth; i++) { indent.append(indentChar); } } return indent.toString(); } protected void formatValue(IJSONNode node, StringBuilder source, IJSONNode value) { IJSONCleanupStrategy stgy = getCleanupStrategy(node); IStructuredDocument structuredDocument = node.getOwnerDocument().getModel().getStructuredDocument(); int start = node.getStartOffset(); int end = node.getEndOffset(); CompoundRegion[] regions = getRegionsWithoutWhiteSpaces(structuredDocument, new FormatRegion(start, end - start), stgy); if (regions.length > 2) { for (int i = 2; i < regions.length; i++) { source.append(decoratedRegion(regions[i], 0, stgy)); } } } protected void formatObject(IJSONNode node, StringBuilder source, IJSONNode jsonObject) { IJSONCleanupStrategy stgy = getCleanupStrategy(node); IStructuredDocument structuredDocument = node.getOwnerDocument().getModel().getStructuredDocument(); IStructuredDocumentRegion[] structuredRegions = structuredDocument .getStructuredDocumentRegions(node.getStartOffset(), node.getEndOffset()); if (structuredRegions.length >= 2) { int start = structuredRegions[1].getStartOffset(); int end = node.getEndOffset(); IJSONSourceFormatter formatter = (IJSONSourceFormatter) ((INodeNotifier) jsonObject) .getAdapterFor(IJSONSourceFormatter.class); if (formatter == null) { formatter = JSONSourceFormatterFactory.getInstance().getSourceFormatter(jsonObject); } StringBuilder objectSource = formatter.format(jsonObject, new FormatRegion(start, end - start)); if (objectSource != null) { source.append(objectSource); } } } }