blob: fc22a5dcc5317df9e850bd95be292b1c70a6eb7a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2018 Alphonse Van Assche and others.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Alphonse Van Assche - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.internal.rpm.ui.editor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.source.Annotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotation;
import org.eclipse.jface.text.source.projection.ProjectionAnnotationModel;
import org.eclipse.linuxtools.rpm.ui.editor.parser.Specfile;
import org.eclipse.linuxtools.rpm.ui.editor.parser.SpecfileElement;
public class SpecfileFoldingStructureProvider {
private static class ElementByLineNbrComparator implements Comparator<SpecfileElement> {
@Override
public int compare(SpecfileElement element1, SpecfileElement element2) {
Integer lineNbr1 = element1.getLineNumber();
Integer lineNbr2 = element2.getLineNumber();
return lineNbr1.compareTo(lineNbr2);
}
}
private static final Annotation[] EMPTY = new Annotation[] {};
private SpecfileEditor sEditor;
private IDocument sDocument;
private IProgressMonitor sProgressMonitor;
public SpecfileFoldingStructureProvider(SpecfileEditor editor) {
sEditor = editor;
}
public void setProgressMonitor(IProgressMonitor progressMonitor) {
sProgressMonitor = progressMonitor;
}
public void setDocument(IDocument document) {
sDocument = document;
}
public void updateFoldingRegions() {
ProjectionAnnotationModel model = sEditor.getAdapter(ProjectionAnnotationModel.class);
if (model != null) {
updateFoldingRegions(model);
}
}
void updateFoldingRegions(ProjectionAnnotationModel model) {
Set<Position> structure = createFoldingStructure(sEditor.getSpecfile());
Annotation[] deletions = computeDifferences(model, structure);
Map<Annotation, Position> additions = computeAdditions(structure);
if ((deletions.length != 0 || !additions.isEmpty())
&& (sProgressMonitor == null || !sProgressMonitor.isCanceled())) {
model.modifyAnnotations(deletions, additions, EMPTY);
}
}
private Map<Annotation, Position> computeAdditions(Set<Position> currentRegions) {
Map<Annotation, Position> additionsMap = new HashMap<>();
for (Position position : currentRegions) {
additionsMap.put(new ProjectionAnnotation(), position);
}
return additionsMap;
}
private Annotation[] computeDifferences(ProjectionAnnotationModel model, Set<Position> current) {
List<Annotation> deletions = new ArrayList<>();
for (Iterator<Annotation> iter = model.getAnnotationIterator(); iter.hasNext();) {
Annotation annotation = iter.next();
if (annotation instanceof ProjectionAnnotation) {
Position position = model.getPosition(annotation);
if (current.contains(position)) {
current.remove(position);
} else {
deletions.add(annotation);
}
}
}
return deletions.toArray(new Annotation[deletions.size()]);
}
private Set<Position> createFoldingStructure(Specfile specfile) {
List<SpecfileElement> elements = new ArrayList<>();
elements.addAll(specfile.getSections());
elements.addAll(specfile.getComplexSections());
Collections.sort(elements, new ElementByLineNbrComparator());
return addFoldingRegions(elements);
}
private Set<Position> addFoldingRegions(List<SpecfileElement> elements) {
Set<Position> regions = new HashSet<>();
// add folding on the preamble section
Position position;
if (elements.size() > 0) {
SpecfileElement element = elements.get(0);
position = new Position(0, element.getLineStartPosition() - 1);
regions.add(position);
}
for (int i = 0; i < elements.size(); i++) {
SpecfileElement startElement = elements.get(i);
int offsetPos = startElement.getLineStartPosition();
int lenghtPos;
if (i < elements.size() - 1) {
SpecfileElement endElement = elements.get(i + 1);
lenghtPos = endElement.getLineStartPosition() - startElement.getLineStartPosition() - 1;
} else {
lenghtPos = sDocument.getLength() - startElement.getLineStartPosition();
}
position = new Position(offsetPos, lenghtPos);
regions.add(position);
}
return regions;
}
}