001 /*
002 * Sonar, open source software quality management tool.
003 * Copyright (C) 2009 SonarSource SA
004 * mailto:contact AT sonarsource DOT com
005 *
006 * Sonar 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 * Sonar 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
017 * License along with Sonar; if not, write to the Free Software
018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02
019 */
020 package org.sonar.colorizer;
021
022 import java.util.List;
023
024 public class ColorizationEngine {
025
026 private List<Tokenizer> tokenizers;
027 private CharacterTransformer charTransformer;
028
029 public ColorizationEngine(List<Tokenizer> tokenizers) {
030 this(tokenizers, new NoTransformer());
031 }
032
033 public ColorizationEngine(List<Tokenizer> tokenizers, CharacterTransformer charTransformer) {
034 this.tokenizers = tokenizers;
035 this.charTransformer = charTransformer;
036 }
037
038 public final String colorize(String code) {
039 return colorize(new CodeReader(code));
040 }
041
042 public final String colorize(CodeReader code) {
043 StringBuilder colorizedCode = new StringBuilder();
044 appendBeginOfFile(colorizedCode);
045 nextChar:
046 while (code.peek() != -1) {
047 for (Tokenizer codeTokenizer : tokenizers) {
048 if (codeTokenizer.hasNextToken(code)) {
049 appendNextToken(code, codeTokenizer, colorizedCode);
050 continue nextChar;
051 }
052 }
053
054 transformAndAppend((char) code.pop(), colorizedCode);
055 }
056 appendEndOfFile(colorizedCode);
057 code.close();
058 return colorizedCode.toString();
059 }
060
061 private void appendBeginOfFile(StringBuilder colorizedCode) {
062 for (Tokenizer tokenizer : tokenizers) {
063 colorizedCode.append(tokenizer.getTagBeginOfFile());
064 }
065 }
066
067 private void appendEndOfFile(StringBuilder colorizedCode) {
068 for (Tokenizer tokenizer : tokenizers) {
069 colorizedCode.append(tokenizer.getTagEndOfFile());
070 }
071 }
072
073 private void appendNextToken(CodeReader code, Tokenizer codeTokenizer, StringBuilder colorizedCode) {
074 colorizedCode.append(codeTokenizer.getTagBefore());
075 transformAndAppend(codeTokenizer.nextToken(code), colorizedCode);
076 colorizedCode.append(codeTokenizer.getTagAfter());
077 }
078
079 private void transformAndAppend(String code, StringBuilder output) {
080 char[] chars = code.toCharArray();
081 for (char character : chars) {
082 transformAndAppend(character, output);
083 }
084 }
085
086 private void transformAndAppend(char character, StringBuilder output) {
087 if (charTransformer.canTransform((int) character)) {
088 output.append(charTransformer.transform((int) character));
089 } else {
090 output.append(character);
091 }
092 }
093
094
095 private static class NoTransformer extends CharacterTransformer {
096 @Override
097 boolean canTransform(int character) {
098 return false;
099 }
100
101 @Override
102 String transform(int character) {
103 throw new IllegalStateException("This method should not be called.");
104 }
105 }
106 }