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, version 3 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 package info.globalcode.sql.dk.formatting;
19 import info.globalcode.sql.dk.ColorfulPrintWriter;
20 import info.globalcode.sql.dk.Constants;
21 import info.globalcode.sql.dk.configuration.PropertyDeclaration;
22 import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL;
23 import static info.globalcode.sql.dk.formatting.CommonProperties.COLORFUL_DESCRIPTION;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
30 * Outputs result sets in (La)TeX format.
32 * @author Ing. František Kučera (frantovo.cz)
34 @PropertyDeclaration(name = COLORFUL, defaultValue = "false", type = Boolean.class, description = COLORFUL_DESCRIPTION)
35 public class TeXFormatter extends AbstractFormatter {
37 public static final String NAME = "tex"; // bash-completion:formatter
38 private static final ColorfulPrintWriter.TerminalColor COMMAND_COLOR = ColorfulPrintWriter.TerminalColor.Magenta;
39 private static final ColorfulPrintWriter.TerminalColor OPTIONS_COLOR = ColorfulPrintWriter.TerminalColor.Yellow;
40 private static final Map<Character, String> TEX_ESCAPE_MAP;
41 private final ColorfulPrintWriter out;
44 Map<Character, String> replacements = new HashMap<>();
46 replacements.put('\\', "\\textbackslash{}");
47 replacements.put('{', "\\{{}");
48 replacements.put('}', "\\}{}");
49 replacements.put('_', "\\_{}");
50 replacements.put('^', "\\textasciicircum{}");
51 replacements.put('#', "\\#{}");
52 replacements.put('&', "\\&{}");
53 replacements.put('$', "\\${}");
54 replacements.put('%', "\\%{}");
55 replacements.put('~', "\\textasciitilde{}");
56 replacements.put('-', "{-}");
58 TEX_ESCAPE_MAP = Collections.unmodifiableMap(replacements);
61 public TeXFormatter(FormatterContext formatterContext) {
62 super(formatterContext);
63 boolean colorful = formatterContext.getProperties().getBoolean(COLORFUL, false);
64 out = new ColorfulPrintWriter(formatterContext.getOutputStream(), false, colorful);
68 public void writeStartBatch() {
69 super.writeStartBatch();
71 printCommand("documentclass", "a4paper,twoside", "article", true);
72 printCommand("usepackage", "T1", "fontenc", true);
73 printCommand("usepackage", "utf8x", "inputenc", true);
74 printCommand("usepackage", "pdfauthor={" + Constants.WEBSITE + "}, bookmarks=true,unicode,colorlinks=true,linkcolor=black,urlcolor=blue,citecolor=blue", "hyperref", true);
75 printBegin("document");
79 public void writeEndBatch() {
80 super.writeEndBatch();
85 public void writeColumnValue(Object value) {
86 super.writeColumnValue(value);
87 // TODO: arrays, numbers, booleans, nulls etc.:
88 out.print(escapeTex(toString(value)));
90 if (!isCurrentColumnLast()) {
91 printColumnSeparator();
96 public void writeEndRow() {
102 public void writeStartResultSet(ColumnsHeader header) {
103 super.writeStartResultSet(header);
104 printCommand("begin", null, "tabular", false);
106 List<ColumnDescriptor> columnDescriptors = header.getColumnDescriptors();
108 StringBuilder columnAlignments = new StringBuilder();
109 for (ColumnDescriptor cd : columnDescriptors) {
110 if (cd.isNumeric() || cd.isBoolean()) {
111 columnAlignments.append('r');
113 columnAlignments.append('l');
117 printCommand(null, null, columnAlignments.toString(), true);
118 printCommand("hline", null, null, true);
120 for (ColumnDescriptor cd : columnDescriptors) {
121 printCommand("textbf", null, cd.getLabel(), false);
122 if (cd.isLastColumn()) {
125 printColumnSeparator();
129 printCommand("hline", null, null, true);
133 public void writeEndResultSet() {
134 super.writeEndResultSet();
135 printCommand("hline", null, null, true);
139 private String escapeTex(String text) {
143 StringBuilder result = new StringBuilder(text.length() * 2);
145 for (char ch : text.toCharArray()) {
146 String replacement = TEX_ESCAPE_MAP.get(ch);
147 result.append(replacement == null ? ch : replacement);
150 return result.toString();
154 protected String toString(Object value) {
155 return String.valueOf(value);
158 private void printColumnSeparator() {
159 out.print(COMMAND_COLOR, " & ");
162 private void printEndRow() {
163 out.println(COMMAND_COLOR, " \\\\");
169 * @param command will not be escaped – should contain just a valid TeX command name
170 * @param options will not be escaped – should be properly formatted to be printed inside [
172 * @param value will be escaped
173 * @param println whether to print line end and flush
175 private void printCommand(String command, String options, String value, boolean println) {
177 if (command != null) {
178 out.print(COMMAND_COLOR, "\\" + command);
181 if (options != null) {
182 out.print(COMMAND_COLOR, "[");
183 out.print(OPTIONS_COLOR, options);
184 out.print(COMMAND_COLOR, "]");
188 out.print(COMMAND_COLOR, "{");
189 out.print(escapeTex(value));
190 out.print(COMMAND_COLOR, "}");
199 private void printBegin(String environment) {
200 printCommand("begin", null, environment, true);
203 private void printEnd(String environment) {
204 printCommand("end", null, environment, true);