Skip to main content
aboutsummaryrefslogblamecommitdiffstats
blob: b6f5bfe6e049fe9f2c5d8df8898a6dc6676033b0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15














                                                                               




















































                                                                                                    
          



                                                           

                                                                                                             













                                                               
          














                                                                                                     
                                              
                                                          
                         






                                                                                    
          






                                      
                 
                                                                        
                                                                                                                                                   



                                                                              
                                               
                                         
                         
















                                                                                          
          











                                                                                    
                                       
                               
                 















                                                                     
          












                                                                                                   
                                                                                
                                                                                                 
                         









                                                                
                                        
                                                    
                 


                                                     
                                                                                        
                                                                                                            
                                 













                                                                                  
                 

                                                                     
                                       
                                                                              
                 






                                                                                     
                 

























                                                                                        
                 


                                                                           
                                          
                                       
                         



                                                                              
                                                            
                                       
                         


                                                                 
                                                                 
                                       
                         












                                                                                               
                                                                  

                                                                                       
                         
















                                                                               
/*****************************************************************************
 * Copyright (c) 2013 CEA LIST and others.
 *
 * All rights reserved. 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
 * http://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *   CEA LIST - Initial API and implementation
 *
 *****************************************************************************/

package org.eclipse.papyrus.uml.xtext.integration;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextInputListener;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.swt.widgets.Display;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.XtextSourceViewer;
import org.eclipse.xtext.ui.editor.model.IXtextDocument;
import org.eclipse.xtext.ui.editor.model.IXtextModelListener;
import org.eclipse.xtext.ui.editor.syntaxcoloring.AttributedPosition;
import org.eclipse.xtext.ui.editor.syntaxcoloring.HighlightingPresenter;
import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightedPositionAcceptor;
import org.eclipse.xtext.ui.editor.syntaxcoloring.ISemanticHighlightingCalculator;
import org.eclipse.xtext.ui.editor.syntaxcoloring.ITextAttributeProvider;
import org.eclipse.xtext.ui.editor.syntaxcoloring.MergingHighlightedPositionAcceptor;
import org.eclipse.xtext.util.concurrent.IUnitOfWork;

import com.google.inject.Inject;


/**
 * Modified copy of org.eclipse.xtext.ui.editor.syntaxcoloring.HighlightingReconciler
 */
class XtextStyledTextHighlightingReconciler implements
		ITextInputListener, IXtextModelListener, IHighlightedPositionAcceptor {

	@Inject(optional = true)
	private ISemanticHighlightingCalculator calculator;

	@Inject
	private ITextAttributeProvider attributeProvider;

	/** The Xtext editor this highlighting reconciler is installed on */
	private StyledTextXtextAdapter styledTextXtextAdapter;
	/** The source viewer this highlighting reconciler is installed on */
	private XtextSourceViewer sourceViewer;
	/** The highlighting presenter */
	private HighlightingPresenter presenter;

	/** Background job's added highlighted positions */
	private final List<AttributedPosition> addedPositions = new ArrayList<AttributedPosition>();
	/** Background job's removed highlighted positions */
	private List<AttributedPosition> removedPositions = new ArrayList<AttributedPosition>();
	/** Number of removed positions */
	private int removedPositionCount;

	/**
	 * Reconcile operation lock.
	 *
	 * @since 3.2
	 */
	private final Object fReconcileLock = new Object();
	/**
	 * <code>true</code> if any thread is executing <code>reconcile</code>, <code>false</code> otherwise.
	 *
	 * @since 3.2
	 */
	private boolean reconciling = false;

	/**
	 * Start reconciling positions.
	 */
	private void startReconcilingPositions() {
		presenter.addAllPositions(removedPositions);
		removedPositionCount = removedPositions.size();
	}

	/**
	 * Reconcile positions based on the AST subtrees
	 *
	 * @param subtrees
	 *            the AST subtrees
	 */
	private void reconcilePositions(XtextResource resource) {
		// for (int i= 0, n= subtrees.length; i < n; i++)
		// subtrees[i].accept(fCollector);
		MergingHighlightedPositionAcceptor acceptor = new MergingHighlightedPositionAcceptor(
				calculator);
		acceptor.provideHighlightingFor(resource, this);
		// calculator.provideHighlightingFor(resource, this);
		List<AttributedPosition> oldPositions = removedPositions;
		List<AttributedPosition> newPositions = new ArrayList<AttributedPosition>(
				removedPositionCount);
		for (int i = 0, n = oldPositions.size(); i < n; i++) {
			AttributedPosition current = oldPositions.get(i);
			if (current != null) {
				newPositions.add(current);
			}
		}
		removedPositions = newPositions;
	}

	/**
	 * Add a position with the given range and highlighting if it does not exist
	 * already.
	 *
	 * @param offset
	 *            The range offset
	 * @param length
	 *            The range length
	 * @param highlighting
	 *            The highlighting
	 */
	@Override
	public void addPosition(int offset, int length, String... ids) {
		TextAttribute highlighting = ids.length == 1 ? attributeProvider.getAttribute(ids[0]) : attributeProvider.getMergedAttributes(ids);
		boolean isExisting = false;
		// TODO: use binary search
		for (int i = 0, n = removedPositions.size(); i < n; i++) {
			AttributedPosition position = removedPositions.get(i);
			if (position == null) {
				continue;
			}
			if (position.isEqual(offset, length, highlighting)) {
				isExisting = true;
				removedPositions.set(i, null);
				removedPositionCount--;
				break;
			}
		}

		if (!isExisting) {
			AttributedPosition position = presenter.createHighlightedPosition(
					offset, length, highlighting);
			addedPositions.add(position);
		}
	}

	/**
	 * Update the presentation.
	 *
	 * @param textPresentation
	 *            the text presentation
	 * @param addedPositions
	 *            the added positions
	 * @param removedPositions
	 *            the removed positions
	 */
	private void updatePresentation(TextPresentation textPresentation,
			List<AttributedPosition> addedPositions,
			List<AttributedPosition> removedPositions) {
		Runnable runnable = presenter.createUpdateRunnable(textPresentation,
				addedPositions, removedPositions);
		if (runnable == null) {
			return;
		}

		Display display = Display.getDefault();
		display.asyncExec(runnable);
	}

	/**
	 * Stop reconciling positions.
	 */
	private void stopReconcilingPositions() {
		removedPositions.clear();
		removedPositionCount = 0;
		addedPositions.clear();
	}

	/**
	 * Install this reconciler on the given editor and presenter.
	 *
	 * @param editor
	 *            the editor
	 * @param sourceViewer
	 *            the source viewer
	 * @param presenter
	 *            the highlighting presenter
	 */
	public void install(StyledTextXtextAdapter xtextStyledText, XtextSourceViewer sourceViewer,
			HighlightingPresenter presenter) {
		this.presenter = presenter;
		this.styledTextXtextAdapter = xtextStyledText;
		this.sourceViewer = sourceViewer;
		if (calculator != null) {
			if (styledTextXtextAdapter.getXtextDocument() != null) {
				styledTextXtextAdapter.getXtextDocument().addModelListener(this);
			}

			sourceViewer.addTextInputListener(this);
		}
		refresh();
	}

	/**
	 * Uninstall this reconciler from the editor
	 */
	public void uninstall() {
		if (presenter != null) {
			presenter.setCanceled(true);
		}

		if (styledTextXtextAdapter != null) {
			if (calculator != null) {
				if (styledTextXtextAdapter.getXtextDocument() != null) {
					styledTextXtextAdapter.getXtextDocument().removeModelListener(this);
				}
				sourceViewer.removeTextInputListener(this);
			}
			styledTextXtextAdapter = null;
		}

		sourceViewer = null;
		presenter = null;
	}

	/*
	 * @see
	 * org.eclipse.jface.text.ITextInputListener#inputDocumentAboutToBeChanged
	 * (org.eclipse.jface.text.IDocument, org.eclipse.jface.text.IDocument)
	 */
	@Override
	public void inputDocumentAboutToBeChanged(IDocument oldInput,
			IDocument newInput) {
		if (oldInput != null) {
			((IXtextDocument) oldInput).removeModelListener(this);
		}
	}

	/*
	 * @see
	 * org.eclipse.jface.text.ITextInputListener#inputDocumentChanged(org.eclipse
	 * .jface.text.IDocument, org.eclipse.jface.text.IDocument)
	 */
	@Override
	public void inputDocumentChanged(IDocument oldInput, IDocument newInput) {
		if (newInput != null) {
			refresh();
			((IXtextDocument) newInput).addModelListener(this);
		}
	}

	/**
	 * Refreshes the highlighting.
	 */
	public void refresh() {
		if (calculator != null) {
			styledTextXtextAdapter.getXtextDocument().readOnly(
					new IUnitOfWork.Void<XtextResource>() {
						@Override
						public void process(XtextResource state)
								throws Exception {
							modelChanged(state);
						}
					});
		} else {
			Display display = Display.getDefault();
			display.asyncExec(presenter.createSimpleUpdateRunnable());
		}
	}

	@Override
	public void modelChanged(XtextResource resource) {
		// ensure at most one thread can be reconciling at any time
		synchronized (fReconcileLock) {
			if (reconciling) {
				return;
			}
			reconciling = true;
		}
		final HighlightingPresenter highlightingPresenter = presenter;
		try {
			if (highlightingPresenter == null) {
				return;
			}

			highlightingPresenter.setCanceled(false);

			if (highlightingPresenter.isCanceled()) {
				return;
			}

			startReconcilingPositions();

			if (!highlightingPresenter.isCanceled()) {
				reconcilePositions(resource);
			}

			final TextPresentation[] textPresentation = new TextPresentation[1];
			if (!highlightingPresenter.isCanceled()) {
				textPresentation[0] = highlightingPresenter.createPresentation(
						addedPositions, removedPositions);
			}

			if (!highlightingPresenter.isCanceled()) {
				updatePresentation(textPresentation[0], addedPositions,
						removedPositions);
			}

			stopReconcilingPositions();
		} finally {
			synchronized (fReconcileLock) {
				reconciling = false;
			}
		}
	}

	public void setCalculator(ISemanticHighlightingCalculator calculator) {
		this.calculator = calculator;
	}

	public ISemanticHighlightingCalculator getCalculator() {
		return calculator;
	}
}

Back to the top