001/* 002 * SonarQube 003 * Copyright (C) 2009-2016 SonarSource SA 004 * mailto:contact AT sonarsource DOT com 005 * 006 * This program is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.batch.sensor.highlighting.internal; 021 022import com.google.common.base.Preconditions; 023import java.util.ArrayList; 024import java.util.Collections; 025import java.util.Comparator; 026import java.util.Iterator; 027import java.util.List; 028import org.sonar.api.batch.fs.InputFile; 029import org.sonar.api.batch.fs.TextRange; 030import org.sonar.api.batch.fs.internal.DefaultInputFile; 031import org.sonar.api.batch.sensor.highlighting.NewHighlighting; 032import org.sonar.api.batch.sensor.highlighting.TypeOfText; 033import org.sonar.api.batch.sensor.internal.DefaultStorable; 034import org.sonar.api.batch.sensor.internal.SensorStorage; 035 036public class DefaultHighlighting extends DefaultStorable implements NewHighlighting { 037 038 private final List<SyntaxHighlightingRule> syntaxHighlightingRules; 039 private DefaultInputFile inputFile; 040 041 public DefaultHighlighting(SensorStorage storage) { 042 super(storage); 043 syntaxHighlightingRules = new ArrayList<>(); 044 } 045 046 public List<SyntaxHighlightingRule> getSyntaxHighlightingRuleSet() { 047 return syntaxHighlightingRules; 048 } 049 050 private void checkOverlappingBoudaries() { 051 if (syntaxHighlightingRules.size() > 1) { 052 Iterator<SyntaxHighlightingRule> it = syntaxHighlightingRules.iterator(); 053 SyntaxHighlightingRule previous = it.next(); 054 while (it.hasNext()) { 055 SyntaxHighlightingRule current = it.next(); 056 if (previous.range().end().compareTo(current.range().start()) > 0 && (previous.range().end().compareTo(current.range().end()) < 0)) { 057 String errorMsg = String.format("Cannot register highlighting rule for characters at %s as it " + 058 "overlaps at least one existing rule", current.range()); 059 throw new IllegalStateException(errorMsg); 060 } 061 previous = current; 062 } 063 } 064 } 065 066 @Override 067 public DefaultHighlighting onFile(InputFile inputFile) { 068 Preconditions.checkNotNull(inputFile, "file can't be null"); 069 this.inputFile = (DefaultInputFile) inputFile; 070 return this; 071 } 072 073 public InputFile inputFile() { 074 return inputFile; 075 } 076 077 @Override 078 public DefaultHighlighting highlight(int startOffset, int endOffset, TypeOfText typeOfText) { 079 checkInputFileNotNull(); 080 TextRange newRange; 081 try { 082 newRange = inputFile.newRange(startOffset, endOffset); 083 } catch (Exception e) { 084 throw new IllegalArgumentException("Unable to highlight file " + inputFile, e); 085 } 086 return highlight(newRange, typeOfText); 087 } 088 089 @Override 090 public DefaultHighlighting highlight(int startLine, int startLineOffset, int endLine, int endLineOffset, TypeOfText typeOfText) { 091 checkInputFileNotNull(); 092 TextRange newRange; 093 try { 094 newRange = inputFile.newRange(startLine, startLineOffset, endLine, endLineOffset); 095 } catch (Exception e) { 096 throw new IllegalArgumentException("Unable to highlight file " + inputFile, e); 097 } 098 return highlight(newRange, typeOfText); 099 } 100 101 @Override 102 public DefaultHighlighting highlight(TextRange range, TypeOfText typeOfText) { 103 SyntaxHighlightingRule syntaxHighlightingRule = SyntaxHighlightingRule.create(range, typeOfText); 104 this.syntaxHighlightingRules.add(syntaxHighlightingRule); 105 return this; 106 } 107 108 @Override 109 protected void doSave() { 110 checkInputFileNotNull(); 111 // Sort rules to avoid variation during consecutive runs 112 Collections.sort(syntaxHighlightingRules, new Comparator<SyntaxHighlightingRule>() { 113 @Override 114 public int compare(SyntaxHighlightingRule left, SyntaxHighlightingRule right) { 115 int result = left.range().start().compareTo(right.range().start()); 116 if (result == 0) { 117 result = right.range().end().compareTo(left.range().end()); 118 } 119 return result; 120 } 121 }); 122 checkOverlappingBoudaries(); 123 storage.store(this); 124 } 125 126 private void checkInputFileNotNull() { 127 Preconditions.checkState(inputFile != null, "Call onFile() first"); 128 } 129}