package com.github.sommeri.less4j.utils; import java.net.URI; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import com.github.sommeri.less4j.LessCompiler.Problem; import com.github.sommeri.less4j.LessSource; import com.github.sommeri.less4j.LessSource.CannotReadFile; import com.github.sommeri.less4j.LessSource.FileNotFound; public class ProblemsPrinter { private SourceNamePrinter sourceNamePrinter = new AbsoluteSourceNamePrinter(); public ProblemsPrinter() { } public ProblemsPrinter(SourceNamePrinter sourceNamePrinter) { this.sourceNamePrinter = sourceNamePrinter; } public String printWarnings(List<Problem> warnings) { StringBuilder builder = new StringBuilder(); for (Problem warning : warnings) { builder.append(toWarning(warning, sourceNamePrinter)).append("\n"); } return builder.toString(); } public String printErrors(List<Problem> errors) { StringBuilder builder = new StringBuilder(); Set<String> previousMessages = new HashSet<String>(); for (Problem error : errors) { String message = toError(error, sourceNamePrinter); if (!previousMessages.contains(message)) { builder.append(message).append("\n"); previousMessages.add(message); } } return builder.toString(); } private String toWarning(Problem warning, SourceNamePrinter sourceNamePrinter) { return "WARNING " + toString(warning, sourceNamePrinter); } private String toError(Problem warning, SourceNamePrinter sourceNamePrinter) { return "ERROR " + toString(warning, sourceNamePrinter); } private String toString(Problem problem, SourceNamePrinter sourceNamePrinter) { String filename = sourceNamePrinter.printSourceName(problem.getSource()); if (!filename.isEmpty()) filename = filename + " "; String lineChar = toLineCharReport(problem); if (!lineChar.isEmpty()) lineChar = lineChar + " "; String snippet = codeSnippet(problem); return filename + lineChar + problem.getMessage() + snippet; } private String codeSnippet(Problem problem) { StringBuilder result = new StringBuilder(); String[] lines = getContentLines(problem); if (lines == null || lines.length == 0) return result.toString(); int errorLine = problem.getLine(); int start = errorLine - 1; int end = errorLine + 1; start = start < 1 ? 1 : start; end = end > lines.length ? lines.length : end; int numberLength = String.valueOf(end).length()+1; for (int i = start; i<=end; i++) { result.append("\n").append(toPaddedNumber(i, numberLength)).append(": "); result.append(lines[i-1]); } result.append("\n"); return result.toString(); } private String toPaddedNumber(int number, int length) { String numStr = String.valueOf(number); char[] prefix = new char[length - numStr.length()]; Arrays.fill(prefix, ' '); return new String(prefix) + numStr; } private String[] getContentLines(Problem problem) { try { LessSource source = problem.getSource(); if (source==null) return new String[0]; String content = source.getContent(); if (content == null) return new String[0]; return content.split("\n"); } catch (FileNotFound e) { } catch (CannotReadFile e) { } return new String[0]; } private String toLineCharReport(Problem problem) { if (problem.getLine() == -1 || problem.getCharacter() == -1) return ""; return problem.getLine() + ":" + problem.getCharacter(); } public interface SourceNamePrinter { String printSourceName(LessSource source); } public static class AbsoluteSourceNamePrinter implements SourceNamePrinter { @Override public String printSourceName(LessSource source) { if (source == null) return ""; URI uri = source.getURI(); if (uri!=null) return uri.toString(); String name = source.getName(); return name == null ? "" : name; } } }