3 * Copyright © 2014 František Kučera (frantovo.cz)
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 package info.globalcode.sql.dk.formatting;
20 import info.globalcode.sql.dk.ColorfulPrintWriter;
21 import info.globalcode.sql.dk.Constants;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.List;
28 * Outputs result sets in (La)TeX format.
30 * @author Ing. František Kučera (frantovo.cz)
32 public class TeXFormatter extends AbstractFormatter {
34 public static final String NAME = "tex"; // bash-completion:formatter
35 public static final String PROPERTY_COLORFUL = "color";
36 private static final ColorfulPrintWriter.TerminalColor COMMAND_COLOR = ColorfulPrintWriter.TerminalColor.Magenta;
37 private static final ColorfulPrintWriter.TerminalColor OPTIONS_COLOR = ColorfulPrintWriter.TerminalColor.Yellow;
38 private static final Map<Character, String> TEX_ESCAPE_MAP;
39 private final ColorfulPrintWriter out;
42 Map<Character, String> replacements = new HashMap<>();
44 replacements.put('\\', "\\textbackslash{}");
45 replacements.put('{', "\\{{}");
46 replacements.put('}', "\\}{}");
47 replacements.put('_', "\\_{}");
48 replacements.put('^', "\\textasciicircum{}");
49 replacements.put('#', "\\#{}");
50 replacements.put('&', "\\&{}");
51 replacements.put('$', "\\${}");
52 replacements.put('%', "\\%{}");
53 replacements.put('~', "\\textasciitilde{}");
54 replacements.put('-', "{-}");
56 TEX_ESCAPE_MAP = Collections.unmodifiableMap(replacements);
59 public TeXFormatter(FormatterContext formatterContext) {
60 super(formatterContext);
61 boolean colorful = formatterContext.getProperties().getBoolean(PROPERTY_COLORFUL, false);
62 out = new ColorfulPrintWriter(formatterContext.getOutputStream(), false, colorful);
66 public void writeStartBatch() {
67 super.writeStartBatch();
69 printCommand("documentclass", "a4paper,twoside", "article", true);
70 printCommand("usepackage", "T1", "fontenc", true);
71 printCommand("usepackage", "utf8x", "inputenc", true);
72 printCommand("usepackage", "pdfauthor={" + Constants.WEBSITE + "}, bookmarks=true,unicode,colorlinks=true,linkcolor=black,urlcolor=blue,citecolor=blue", "hyperref", true);
73 printBegin("document");
77 public void writeEndBatch() {
78 super.writeEndBatch();
83 public void writeColumnValue(Object value) {
84 super.writeColumnValue(value);
85 // TODO: arrays, numbers, booleans, nulls etc.:
86 out.print(escapeTex(toString(value)));
88 if (!isCurrentColumnLast()) {
89 printColumnSeparator();
94 public void writeEndRow() {
100 public void writeStartResultSet(ColumnsHeader header) {
101 super.writeStartResultSet(header);
102 printCommand("begin", null, "tabular", false);
104 List<ColumnDescriptor> columnDescriptors = header.getColumnDescriptors();
106 StringBuilder columnAlignments = new StringBuilder();
107 for (ColumnDescriptor cd : columnDescriptors) {
108 if (cd.isNumeric() || cd.isBoolean()) {
109 columnAlignments.append('r');
111 columnAlignments.append('l');
115 printCommand(null, null, columnAlignments.toString(), true);
116 printCommand("hline", null, null, true);
118 for (ColumnDescriptor cd : columnDescriptors) {
119 printCommand("textbf", null, cd.getLabel(), false);
120 if (cd.isLastColumn()) {
123 printColumnSeparator();
127 printCommand("hline", null, null, true);
131 public void writeEndResultSet() {
132 super.writeEndResultSet();
133 printCommand("hline", null, null, true);
137 private String escapeTex(String text) {
141 StringBuilder result = new StringBuilder(text.length() * 2);
143 for (char ch : text.toCharArray()) {
144 String replacement = TEX_ESCAPE_MAP.get(ch);
145 result.append(replacement == null ? ch : replacement);
148 return result.toString();
152 protected String toString(Object value) {
153 return String.valueOf(value);
156 private void printColumnSeparator() {
157 out.print(COMMAND_COLOR, " & ");
160 private void printEndRow() {
161 out.println(COMMAND_COLOR, " \\\\");
167 * @param command will not be escaped – should contain just a valid TeX command name
168 * @param options will not be escaped – should be properly formatted to be printed inside [
170 * @param value will be escaped
171 * @param println whether to print line end and flush
173 private void printCommand(String command, String options, String value, boolean println) {
175 if (command != null) {
176 out.print(COMMAND_COLOR, "\\" + command);
179 if (options != null) {
180 out.print(COMMAND_COLOR, "[");
181 out.print(OPTIONS_COLOR, options);
182 out.print(COMMAND_COLOR, "]");
186 out.print(COMMAND_COLOR, "{");
187 out.print(escapeTex(value));
188 out.print(COMMAND_COLOR, "}");
197 private void printBegin(String environment) {
198 printCommand("begin", null, environment, true);
201 private void printEnd(String environment) {
202 printCommand("end", null, environment, true);