1 // SciTE - Scintilla based Text Editor
2 /** @file ExportTEX.cxx
3 ** Export the current document to TEX.
4 **/
5 // Copyright 1998-2006 by Neil Hodgson <neilh@scintilla.org>
6 // The License.txt file describes the conditions under which this software may be distributed.
7
8 #include <cstddef>
9 #include <cstdlib>
10 #include <cstdint>
11 #include <cstring>
12 #include <cstdio>
13 #include <ctime>
14
15 #include <string>
16 #include <string_view>
17 #include <vector>
18 #include <map>
19 #include <set>
20 #include <memory>
21 #include <chrono>
22 #include <sstream>
23 #include <atomic>
24 #include <mutex>
25
26 #include <fcntl.h>
27 #include <sys/stat.h>
28
29 #include "ILexer.h"
30
31 #include "ScintillaTypes.h"
32 #include "ScintillaCall.h"
33
34 #include "GUI.h"
35 #include "ScintillaWindow.h"
36
37 #include "StringList.h"
38 #include "StringHelpers.h"
39 #include "FilePath.h"
40 #include "StyleDefinition.h"
41 #include "PropSetFile.h"
42 #include "StyleWriter.h"
43 #include "Extender.h"
44 #include "SciTE.h"
45 #include "JobQueue.h"
46 #include "Cookie.h"
47 #include "Worker.h"
48 #include "MatchMarker.h"
49 #include "SciTEBase.h"
50
51 //---------- Save to TeX ----------
52
getTexRGB(char * texcolor,const char * stylecolor)53 static char *getTexRGB(char *texcolor, const char *stylecolor) noexcept {
54 //texcolor[rgb]{0,0.5,0}{....}
55 const double rf = IntFromHexByte(stylecolor + 1) / 256.0;
56 const double gf = IntFromHexByte(stylecolor + 3) / 256.0;
57 const double bf = IntFromHexByte(stylecolor + 5) / 256.0;
58 // avoid breakage due to locale setting
59 const int r = static_cast<int>(rf * 10 + 0.5);
60 const int g = static_cast<int>(gf * 10 + 0.5);
61 const int b = static_cast<int>(bf * 10 + 0.5);
62 sprintf(texcolor, "%d.%d, %d.%d, %d.%d", r / 10, r % 10, g / 10, g % 10, b / 10, b % 10);
63 return texcolor;
64 }
65
66 #define CHARZ ('z' - 'b')
texStyle(int style)67 static char *texStyle(int style) noexcept {
68 static char buf[10];
69 int i = 0;
70 do {
71 buf[i++] = static_cast<char>('a' + (style % CHARZ));
72 style /= CHARZ;
73 } while (style > 0);
74 buf[i] = 0;
75 return buf;
76 }
77
defineTexStyle(const StyleDefinition & style,FILE * fp,int istyle)78 static void defineTexStyle(const StyleDefinition &style, FILE *fp, int istyle) {
79 int closing_brackets = 2;
80 char rgb[200] = "";
81 fprintf(fp, "\\newcommand{\\scite%s}[1]{\\noindent{\\ttfamily{", texStyle(istyle));
82 if (style.italics) {
83 fputs("\\textit{", fp);
84 closing_brackets++;
85 }
86 if (style.IsBold()) {
87 fputs("\\textbf{", fp);
88 closing_brackets++;
89 }
90 if (style.fore.length()) {
91 fprintf(fp, "\\textcolor[rgb]{%s}{", getTexRGB(rgb, style.fore.c_str()));
92 closing_brackets++;
93 }
94 if (style.back.length()) {
95 fprintf(fp, "\\colorbox[rgb]{%s}{", getTexRGB(rgb, style.back.c_str()));
96 closing_brackets++;
97 }
98 fputs("#1", fp);
99 for (int i = 0; i <= closing_brackets; i++) {
100 fputc('}', fp);
101 }
102 fputc('\n', fp);
103 }
104
SaveToTEX(const FilePath & saveName)105 void SciTEBase::SaveToTEX(const FilePath &saveName) {
106 RemoveFindMarks();
107 wEditor.ColouriseAll();
108 int tabSize = props.GetInt("tabsize");
109 if (tabSize == 0)
110 tabSize = 4;
111
112 const SA::Position lengthDoc = LengthDocument();
113 TextReader acc(wEditor);
114 bool styleIsUsed[StyleMax + 1] = {};
115
116 const int titleFullPath = props.GetInt("export.tex.title.fullpath", 0);
117
118 for (SA::Position pos = 0; pos < lengthDoc; pos++) { // check the used styles
119 styleIsUsed[acc.StyleAt(pos)] = true;
120 }
121 styleIsUsed[StyleDefault] = true;
122
123 FILE *fp = saveName.Open(GUI_TEXT("wt"));
124 bool failedWrite = fp == nullptr;
125 if (fp) {
126 fputs("\\documentclass[a4paper]{article}\n"
127 "\\usepackage[a4paper,margin=2cm]{geometry}\n"
128 "\\usepackage[T1]{fontenc}\n"
129 "\\usepackage{color}\n"
130 "\\usepackage{alltt}\n"
131 "\\usepackage{times}\n"
132 "\\setlength{\\fboxsep}{0pt}\n", fp);
133
134 for (int istyle = 0; istyle < StyleMax; istyle++) { // get keys
135 if (styleIsUsed[istyle]) {
136 StyleDefinition sd = StyleDefinitionFor(istyle);
137 defineTexStyle(sd, fp, istyle); // writeout style macroses
138 }
139 }
140
141 fputs("\\begin{document}\n\n", fp);
142 fprintf(fp, "Source File: %s\n\n\\noindent\n\\small{\n",
143 titleFullPath ? filePath.AsUTF8().c_str() : filePath.Name().AsUTF8().c_str());
144
145 int styleCurrent = acc.StyleAt(0);
146
147 fprintf(fp, "\\scite%s{", texStyle(styleCurrent));
148
149 int lineIdx = 0;
150
151 for (SA::Position i = 0; i < lengthDoc; i++) { //here process each character of the document
152 const char ch = acc[i];
153 const int style = acc.StyleAt(i);
154
155 if (style != styleCurrent) { //new style?
156 fprintf(fp, "}\\scite%s{", texStyle(style));
157 styleCurrent = style;
158 }
159
160 switch (ch) { //write out current character.
161 case '\t': {
162 const int ts = tabSize - (lineIdx % tabSize);
163 lineIdx += ts - 1;
164 fprintf(fp, "\\hspace*{%dem}", ts);
165 break;
166 }
167 case '\\':
168 fputs("{\\textbackslash}", fp);
169 break;
170 case '>':
171 case '<':
172 case '@':
173 fprintf(fp, "$%c$", ch);
174 break;
175 case '{':
176 case '}':
177 case '^':
178 case '_':
179 case '&':
180 case '$':
181 case '#':
182 case '%':
183 case '~':
184 fprintf(fp, "\\%c", ch);
185 break;
186 case '\r':
187 case '\n':
188 lineIdx = -1; // Because incremented below
189 if (ch == '\r' && acc[i + 1] == '\n')
190 i++; // Skip the LF
191 styleCurrent = acc.StyleAt(i + 1);
192 fprintf(fp, "} \\\\\n\\scite%s{", texStyle(styleCurrent));
193 break;
194 case ' ':
195 if (acc[i + 1] == ' ') {
196 fputs("{\\hspace*{1em}}", fp);
197 } else {
198 fputc(' ', fp);
199 }
200 break;
201 default:
202 fputc(ch, fp);
203 }
204 lineIdx++;
205 }
206 fputs("}\n} %end small\n\n\\end{document}\n", fp); //close last empty style macros and document too
207 if (fclose(fp) != 0) {
208 failedWrite = true;
209 }
210 }
211 if (failedWrite) {
212 FailedSaveMessageBox(saveName);
213 }
214 }
215