final int length = replacement.length();
boolean inAttribute = false, hasGroup = false, inEndTag = false;
int offset = 0;
char attType = 0;
int exitPosition = -1;
LinkedModeModel model = new LinkedModeModel();
try {
for (int i = 0; i < length; i++) {
final char c = replacement.charAt(i);
switch (c) {
case '=':
break;
case '\'':
case '\"':
if (!inAttribute) {
offset = i;
attType = c;
inAttribute = true;
}
else {
// Found matching quotes establishing an attribute value region
if (attType == c && replacement.charAt(i - 1) != '\\') {
inAttribute = false; // Record position length
addPosition(model, document, getReplacementOffset() + offset + 1, i - offset - 1);
hasGroup = true;
}
}
break;
case '/':
if (!inAttribute) {
inEndTag = i > 0 && replacement.charAt(i - 1) == '<';
}
break;
case '>':
if (!inAttribute) {
if (i == length - 1) {
exitPosition = getReplacementOffset() + i + 1;
if (!inEndTag) { // Don't add a position within the end-tag
addPosition(model, document, getReplacementOffset() + i, 0); // position within start tag
hasGroup = true;
}
}
else {
addPosition(model, document, getReplacementOffset() + i, 0); // position within start tag
addPosition(model, document, getReplacementOffset() + i + 1, 0); // position after start tag
hasGroup = true;
}
}
break;
}
}
if (hasGroup) {
model.forceInstall();
final LinkedModeUI ui= new EditorLinkedModeUI(model, viewer);
ui.setExitPosition(viewer, exitPosition < 0 ? getReplacementOffset() + getReplacementLength() + replacement.length() - 1 : exitPosition, 0, Integer.MAX_VALUE);
ui.setCyclingMode(LinkedModeUI.CYCLE_WHEN_NO_PARENT);
ui.setDoContextInfo(true);
ui.enter();