Package de.sebastianbenz.task.ui.highlighting

Source Code of de.sebastianbenz.task.ui.highlighting.SemanticHighlightingCalculator$Implementation

/*******************************************************************************
* Copyright (c) 2011 Sebastian Benz.
* 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:
*     Sebastian Benz - initial API and implementation
******************************************************************************/
package de.sebastianbenz.task.ui.highlighting;

import static com.google.common.collect.Iterables.concat;
import static com.google.common.collect.Iterables.toArray;
import static de.sebastianbenz.task.ui.highlighting.HighlightingConfiguration.NOTE_DONE_ID;
import static de.sebastianbenz.task.ui.highlighting.HighlightingConfiguration.PROJECT1_DONE_ID;
import static de.sebastianbenz.task.ui.highlighting.HighlightingConfiguration.PROJECT2_DONE_ID;
import static de.sebastianbenz.task.ui.highlighting.HighlightingConfiguration.PROJECT2_ID;
import static de.sebastianbenz.task.ui.highlighting.HighlightingConfiguration.PROJECT3_DONE_ID;
import static de.sebastianbenz.task.ui.highlighting.HighlightingConfiguration.PROJECT3_ID;
import static de.sebastianbenz.task.ui.highlighting.HighlightingConfiguration.TAG_ID;
import static de.sebastianbenz.task.ui.highlighting.HighlightingConfiguration.TASK_DONE_ID;
import static de.sebastianbenz.task.ui.highlighting.HighlightingConfiguration.TASK_URL_ID;
import static de.sebastianbenz.task.util.Contents.offset;
import static de.sebastianbenz.task.util.Contents.region;
import static java.util.Collections.sort;
import static org.eclipse.xtext.util.Strings.isEmpty;

import java.util.Iterator;
import java.util.List;

import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.ui.editor.syntaxcoloring.IHighlightedPositionAcceptor;
import org.eclipse.xtext.ui.editor.syntaxcoloring.ISemanticHighlightingCalculator;

import com.google.common.collect.Lists;
import com.google.inject.Inject;

import de.sebastianbenz.task.Code;
import de.sebastianbenz.task.Content;
import de.sebastianbenz.task.Link;
import de.sebastianbenz.task.Note;
import de.sebastianbenz.task.Project;
import de.sebastianbenz.task.Tag;
import de.sebastianbenz.task.Task;
import de.sebastianbenz.task.impl.CodeImplCustom;
import de.sebastianbenz.task.tagging.Region;
import de.sebastianbenz.task.util.Contents;
import de.sebastianbenz.task.util.TaskSwitch;

public class SemanticHighlightingCalculator implements ISemanticHighlightingCalculator{
 
  private static final int CODE_SEPARATOR = CodeImplCustom.PREFIX.length();

  private static class Position implements Comparable<Position>{
   
    public final int offset;
    public final int length;
    public final String[] id;
   
    public Position(int offset, int length, String[] id) {
      this.offset = offset;
      this.length = length;
      this.id = id;
    }

    public int compareTo(Position other) {
      return this.offset < other.offset ? -1 : this.offset == other.offset ? 0 : 1;
    }
   
    @Override
    public String toString() {
      return offset + "-" + length + " " + id;
    }
   
  }

  public static class FilteringAcceptor implements IHighlightedPositionAcceptor {
   
    private final int baseOffset;
    private List<Position> matches = Lists.newArrayList();
    private final IHighlightedPositionAcceptor acceptor;
   
    private FilteringAcceptor(IHighlightedPositionAcceptor acceptor, int base) {
      this.acceptor = acceptor;
      this.baseOffset = base;
    }
 
    public void addPosition(int offset, int length, String... id) {
      matches.add(new Position(offset, length, id));
    }
 
    public void flush() {
      Position[] positions = filterHiddenMatches();
      for (Position match : positions) {
        if(match != null){
          acceptor.addPosition(baseOffset + match.offset, match.length, match.id);
        }
      }
    }
 
    private Position[] filterHiddenMatches() {
      sort(matches);
      Position[] positions = toArray(matches, Position.class);
      for(int i = 0; i < positions.length; i++){
        Position current = positions[i];
        if(isInsideOtherMatch(positions, current, i)){
           positions[i] = null;
        }
      }
      return positions;
    }
 
    private boolean isInsideOtherMatch(Position[] positions, Position current, int i) {
      for(int j = 0; j < i; j++){
        Position other =  positions[j];
        if(other != null && current.offset < other.offset + other.length){
          return true;
        }
      }
      return false;
    }
  }

  private class Implementation extends TaskSwitch<Boolean>{

    private final IHighlightedPositionAcceptor acceptor;

    public Implementation(IHighlightedPositionAcceptor acceptor) {
      this.acceptor = acceptor;
    }

    @Override
    public Boolean caseTask(Task content) {
      return applyHighlighting(content, TASK_DONE_ID, TASK_URL_ID);
    }

    private Boolean applyHighlighting(Content content, String doneStyle, String urlStyle) {
      Iterable<Tag> allTags = content.getTags();
      if(content.isDone()){
        markAsDone(content, allTags, doneStyle);
      }else{
        highlightUrls(content, urlStyle);
      }
      highlightTags(content, allTags);
      return Boolean.TRUE;
    }
   
    private void highlightUrls(Content content, String style) {
      int offset = offset(content);
      for (Link link : concat(content.getLinks(), content.getImages())) {
        int linkOffset;
        int linkLength;
        if(isEmpty(link.getDescription())){
          linkOffset = offset + link.getOffset();
          linkLength = link.getLength();
        }else{
          int descriptionLength = link.getDescription().length();
          linkOffset = offset + link.getOffset() + descriptionLength + 3;
          linkLength = link.getLength() - descriptionLength - 4;
        }
        acceptor.addPosition(linkOffset, linkLength, style);
      }
    }

    @Override
    public Boolean caseNote(Note content) {
      return applyHighlighting(content, NOTE_DONE_ID, HighlightingConfiguration.NOTE_URL_ID);
    }
   
    private void markAsDone(Content content, Iterable<Tag> allTags, String doneStyle) {
      Region region = Contents.region(content);
      int begin = 0;
      int lastTagEnd = region.getOffset();
      int taskOffset = lastTagEnd;
      for (Tag tag : allTags) {
        int length = tag.getOffset() - begin - whiteSpaces(content, tag.getOffset());
        if(length > 0){
          int offset = taskOffset + begin;
          if(isNotWhiteSpace(content, taskOffset, length, offset)){
            acceptor.addPosition(offset, length, doneStyle);
          }
          lastTagEnd = offset + length + tag.getLength();
        }
        begin = tag.getOffset() + tag.getLength() + 1;
      }
     
      int taskLength = content.getText().trim().length();
      if(lastTagEnd < taskOffset + taskLength){
        acceptor.addPosition(lastTagEnd, taskLength-begin, doneStyle);
      }
    }

    private int whiteSpaces(Content content, int offset) {
      int whiteSpaceCount = 0;
      for(int i = offset-1; content.getText().charAt(i) == ' '; i--){
        whiteSpaceCount++;
      }
      return whiteSpaceCount;
    }

    private boolean isNotWhiteSpace(Content content, int taskOffset,
        int length, int offset) {
      int beginIndex = offset - taskOffset;
      return content.getText().substring(beginIndex, beginIndex + length).trim().length() > 0;
    }


    private void highlightTags(Content content, Iterable<Tag> allTags) {
      for (Tag tag : allTags) {
        acceptor.addPosition(offset(content) + tag.getOffset(), tag.getLength(), TAG_ID);
      }
    }

   
   
    @Override
    public Boolean caseProject(Project project) {
      int level = project.getLevel();
      if(level == 1){
        highlight(project, PROJECT2_ID, PROJECT2_DONE_ID);
      }else if(level >= 2) {
        highlight(project, PROJECT3_ID, PROJECT3_DONE_ID);
      }else if(project.isDone()){
        highlight(project, PROJECT1_DONE_ID);
      }
      return Boolean.TRUE;
    }

    private void highlight(Project project, String normal,
        String done) {
      String id = project.isDone() ? done : normal;
      highlight(project, id);
    }

    protected void highlight(Content content, String id) {
      Region region = region(content);
       acceptor.addPosition(region.getOffset(), region.getLength(), id);
    }
   
    @Override
    public Boolean caseCode(Code code) {
      applyBrushes(code);
      return Boolean.TRUE;
    }

    protected void applyBrushes(Code code) {
      FilteringAcceptor filter = new FilteringAcceptor(acceptor, codeOffset(code));
      Brush brush = brushFor(code);
      brush.apply(textOf(code), filter);
      filter.flush();
    }

    protected String textOf(Code code) {
      return code.getText();
    }

    protected Brush brushFor(Code code) {
      return configurationRegistry.get(code.getLang());
    }

    protected int codeOffset(Code code) {
      return offset(code) + CODE_SEPARATOR;
    }

  }
 
  @Inject
  public SemanticHighlightingCalculator(BrushRegistry configurationRegistry){
    this.configurationRegistry = configurationRegistry;
  }
 
  private final BrushRegistry configurationRegistry;

  public void provideHighlightingFor(XtextResource resource,
      IHighlightedPositionAcceptor acceptor) {
    if (noNodeModel(resource)){
      return;
    }
   
    Implementation highlighter = new Implementation(acceptor);
    Iterator<EObject> contents = resource.getAllContents();
    while (contents.hasNext()) {
      highlighter.doSwitch((EObject) contents.next());
    }
  }

  protected EObject root(XtextResource resource) {
    return resource.getParseResult().getRootASTElement();
  }

  protected boolean noNodeModel(XtextResource resource) {
    return resource == null || resource.getParseResult() == null || root(resource) == null;
  }
 
}
TOP

Related Classes of de.sebastianbenz.task.ui.highlighting.SemanticHighlightingCalculator$Implementation

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.