blob: 0898507c76fc9f7eff694794625ee47a63c689df [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2017 Red Hat Inc. and others
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Lucas Bullen (Red Hat Inc.) - initial implementation
*******************************************************************************/
package org.eclipse.ui.genericeditor.examples.dotproject;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.reconciler.DirtyRegion;
import org.eclipse.jface.text.reconciler.IReconcilingStrategy;
import org.eclipse.jface.text.reconciler.IReconcilingStrategyExtension;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
import org.eclipse.jface.text.source.projection.ProjectionViewer;
public class FoldingStrategy implements IReconcilingStrategy, IReconcilingStrategyExtension {
private IDocument document;
private String oldDocument;
private ProjectionViewer projectionViewer;
private List<Annotation> oldAnnotations = new ArrayList<>();
private List<Position> oldPositions = new ArrayList<>();
@Override
public void setDocument(IDocument document) {
this.document = document;
}
public void setProjectionViewer(ProjectionViewer projectionViewer) {
this.projectionViewer = projectionViewer;
}
@Override
public void reconcile(DirtyRegion dirtyRegion, IRegion subRegion) {
initialReconcile();
}
@Override
public void reconcile(IRegion partition) {
initialReconcile();
}
@Override
public void initialReconcile() {
if(document.get().equals(oldDocument)) return;
oldDocument = document.get();
List<Position> positions = getNewPositionsOfAnnotations();
List<Position> positionsToRemove = new ArrayList<>();
List<Annotation> annotationToRemove = new ArrayList<>();
for (Position position : oldPositions) {
if(!positions.contains(position)) {
projectionViewer.getProjectionAnnotationModel().removeAnnotation(oldAnnotations.get(oldPositions.indexOf(position)));
positionsToRemove.add(position);
annotationToRemove.add(oldAnnotations.get(oldPositions.indexOf(position)));
}else {
positions.remove(position);
}
}
oldPositions.removeAll(positionsToRemove);
oldAnnotations.removeAll(annotationToRemove);
for (Position position : positions) {
Annotation annotation = new ProjectionAnnotation();
projectionViewer.getProjectionAnnotationModel().addAnnotation(annotation, position);
oldPositions.add(position);
oldAnnotations.add(annotation);
}
}
private static enum SearchingFor {
START_OF_TAG, START_OF_WORD, END_OF_WORD, END_OF_LINE
}
private List<Position> getNewPositionsOfAnnotations(){
List<Position> positions = new ArrayList<>();
Map<String, Integer> startOfAnnotation = new HashMap<>();
SearchingFor searchingFor = SearchingFor.START_OF_TAG;
int characters = document.getLength();
int currentCharIndex = 0;
int wordStartIndex = 0;
int sectionStartIndex = 0;
String word = "";
try {
while (currentCharIndex < characters) {
char currentChar = document.getChar(currentCharIndex);
switch (searchingFor) {
case START_OF_TAG:
if(currentChar == '<') {
char nextChar = document.getChar(currentCharIndex+1);
if(nextChar != '?') {
sectionStartIndex = currentCharIndex;
searchingFor = SearchingFor.START_OF_WORD;
}
}
break;
case START_OF_WORD:
if(Character.isLetter(currentChar)) {
wordStartIndex = currentCharIndex;
searchingFor = SearchingFor.END_OF_WORD;
}
break;
case END_OF_WORD:
if(!Character.isLetter(currentChar)) {
word = document.get(wordStartIndex, currentCharIndex - wordStartIndex);
if(startOfAnnotation.containsKey(word)) {
searchingFor = SearchingFor.END_OF_LINE;
}else {
startOfAnnotation.put(word, sectionStartIndex);
searchingFor = SearchingFor.START_OF_TAG;
}
}
break;
case END_OF_LINE:
if(currentChar == '\n') {
int start = startOfAnnotation.get(word);
if(document.getLineOfOffset(start) != document.getLineOfOffset(currentCharIndex)) {
positions.add(new Position(start,currentCharIndex + 1 - start));
}
startOfAnnotation.remove(word);
searchingFor = SearchingFor.START_OF_TAG;
}
break;
}
currentCharIndex++;
}
} catch (BadLocationException e) {
// skip the remainder of file due to error
}
return positions;
}
@Override
public void setProgressMonitor(IProgressMonitor monitor) {
// no progress monitor used
}
}