tedi2tex.cpp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. * tedi2tex library code
  3. * Copyright (C) <2022> <alkeon> [alkeon@autistici.org]
  4. * Texdi is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * Texdi 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.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with tedi2tex. If not, see <http://www.gnu.org/licenses/>.
  16. */
  17. #include <iostream>
  18. #include <string>
  19. #include <fstream>
  20. #include <sstream>
  21. #include "tedi2tex.h"
  22. #include "../tedi2lang/tedi2lang.h"
  23. #include "../tedi2lang/exception.h"
  24. using namespace std;
  25. #define BLOCK 2
  26. #define IMAGE 1
  27. #define LINK 0
  28. #define NO_TAG -1
  29. tedi2tex::tedi2tex(tags_definition td): tedi2lang(td){}
  30. tedi2tex::tedi2tex(): tedi2lang(default_tags_value()){}
  31. tags_definition tedi2tex::default_tags_value(){
  32. tags_definition td;
  33. td.start_heading_first_level_tag = "\\section{";
  34. td.start_heading_second_level_tag = "\\subsection{";
  35. td.start_heading_third_level_tag = "\\subsubsection{";
  36. td.start_heading_fourth_level_tag = "\\subsubsection{";
  37. td.end_heading_first_level_tag = "}";
  38. td.end_heading_second_level_tag = "}";
  39. td.end_heading_third_level_tag = "}";
  40. td.end_heading_fourth_level_tag = "}";
  41. td.start_list_tag = "\\begin{itemize}";
  42. td.list_item_tag = "\\item ";
  43. td.end_list_tag = "\\end{itemize}";
  44. td.start_container_tag = "";
  45. td.middle_container_tag = "";
  46. td.end_container_tag = "";
  47. td.start_link_tag = "\\href{";
  48. td.middle_link_tag = "}{";
  49. td.end_link_tag = "}";
  50. td.start_image_tag = "\\begin{figure}[h!]\n\\centering\n\\includegraphics[width=1\\textwidth]{";
  51. td.middle_image_tag = "";
  52. td.end_image_tag = "";
  53. td.start_table_tag = "";
  54. td.end_table_tag = "\\hline\n\\end{longtable}\n";
  55. td.start_table_row_tag = "\\hline";
  56. td.end_table_row_tag = "\\tabularnewline";
  57. td.start_table_data_tag = " & ";
  58. td.end_table_data_tag = "";
  59. td.end_paragraph_tag = "\n";
  60. return td;
  61. }
  62. /*
  63. * Main logic converting line.
  64. *
  65. */
  66. string tedi2tex::convert_line(string& line) {
  67. if(line[0] != '<') {
  68. escape_underscores(line);
  69. string end_table = convert_end_table(line);
  70. size_t hash = line.find('#');
  71. if(found(hash) && is_first_tag(line, hash))
  72. return end_table + convert_line_heading(line, hash);
  73. else {
  74. size_t ul = line.find("__");
  75. if(found(ul))
  76. return end_table + convert_line_list_start(line);
  77. else {
  78. size_t li = line.find("--");
  79. if(found(li) && _is_unordered_list)
  80. convert_line_list_item(line, li);
  81. size_t ul_end = line.find(",,");
  82. if(found(ul_end) && _is_unordered_list)
  83. return end_table + convert_line_list_end(line);
  84. else{
  85. if(line[0] == '"')
  86. convert_line_quote(line);
  87. else
  88. convert_unquoted_tags(line);
  89. size_t first_pipe = line.find("|");
  90. if(found(first_pipe))
  91. return convert_line_table(line, first_pipe);
  92. else
  93. return end_table + convert_line_ending(line);
  94. }
  95. }
  96. }
  97. } else
  98. return convert_end_table_control_tags(line) + convert_line_control_tags(line);
  99. }
  100. /*
  101. * Deletes heading tag and insert image tag
  102. * - ([caption] image.png)
  103. * - image::image.png[caption]
  104. *
  105. */
  106. void tedi2tex::convert_line_image(string& line) {
  107. size_t start_tag = get_not_escaped_tag(line, "([");
  108. if(found(start_tag) && !is_tag_escaped(line, start_tag)) {
  109. line = line.erase(start_tag, 2);
  110. size_t square_bracket = get_not_escaped_tag(line, "] ");
  111. if(found(square_bracket) && !is_tag_escaped(line, square_bracket)) {
  112. string caption = line.substr(start_tag, square_bracket - start_tag);
  113. line = line.erase(start_tag, square_bracket + 2 - start_tag);
  114. line = line.insert(start_tag, _start_image_tag);
  115. int last_parenthesis = correct_position(line, start_tag + _start_image_tag.size(), '(', ')');
  116. if(found(last_parenthesis)) {
  117. line = line.erase(last_parenthesis, 1);
  118. line = line.insert(last_parenthesis, "}\n\\caption{" + caption + "}\n\\end{figure}");
  119. } else
  120. throw Invalid("Missing ')' in images tag.",line);
  121. } else
  122. throw Invalid("Missing ']' in images tag.",line);
  123. } else
  124. throw Invalid("Missing images tag.",line);
  125. }
  126. /*
  127. * Deletes block tag and insert block tag
  128. *
  129. */
  130. void tedi2tex::convert_line_block(string& line) {
  131. size_t start_tag = get_not_escaped_tag(line, "{(");
  132. if(found(start_tag) && !is_tag_escaped(line, start_tag)) {
  133. line = line.erase(start_tag, 2);
  134. line = line.insert(start_tag, _start_container_tag);
  135. size_t parenthesis = get_not_escaped_tag(line, ") ");
  136. if(found(parenthesis) && !is_tag_escaped(line, parenthesis)) {
  137. line = line.erase(start_tag, parenthesis - start_tag + 2);
  138. size_t end_tag = correct_position(line, start_tag, '{', '}');
  139. if(found(end_tag))
  140. line = line.erase(end_tag, 1);
  141. else
  142. ++_open_brackets;
  143. } else
  144. throw Invalid("Missing ')' in block tag.",line);
  145. } else
  146. throw Invalid("Missing block tag.",line);
  147. _has_block = true;
  148. }
  149. /*
  150. * Start or continue table conversion
  151. *
  152. */
  153. string tedi2tex::convert_line_table(string& line, size_t first_pipe) {
  154. string return_text;
  155. if(!_is_converting_table) {
  156. if(first_pipe != line.rfind("|")) {
  157. return_text += get_table_start_tag(line);
  158. _is_converting_table = true;
  159. return return_text + convert_line_table_row(line);
  160. } else
  161. return convert_line_ending(line);
  162. }else
  163. return return_text + convert_line_table_row(line);
  164. return return_text;
  165. }
  166. /*
  167. * Convert every cell of one table row
  168. *
  169. */
  170. string tedi2tex::convert_line_table_row(string& line) {
  171. size_t pipe = line.find("|");
  172. if(found(pipe)) {
  173. ++pipe;
  174. string return_text = _start_table_row_tag + "\n";
  175. line = line.substr(pipe, line.size() - 1);
  176. pipe = line.find("|");
  177. if(found(pipe)) {
  178. int size = line.size() - 1;
  179. if(line[size] == '|') {
  180. bool start = true;
  181. while(found(pipe) && line[size] == '|') {
  182. if(start) {
  183. return_text += strip_escaping(line.substr(0, pipe));
  184. start = false;
  185. } else
  186. return_text += _start_table_data_tag + strip_escaping(line.substr(0, pipe));
  187. ++pipe;
  188. line = line.substr(pipe, size);
  189. pipe = line.find("|");
  190. size = line.size() - 1;
  191. }
  192. return return_text + _end_table_row_tag + "\n";
  193. }else
  194. throw Invalid("Table not correctly written\n"
  195. "Maybe there's a whitespace at end of line", line);
  196. }else
  197. throw Invalid("Expected '|' in table", line);
  198. }else
  199. throw Invalid("Expected '|' in table", line);
  200. }
  201. string tedi2tex::convert_line_control_tags(string& line){
  202. if(line[1] != '!') {
  203. if(line[1] == '>') {
  204. line = line.erase(0,2);
  205. return line + "\n";
  206. } else if(line[1] == '+') {
  207. line = line.erase(0,2);
  208. return "\\begin{verbatim}\n" + line + "\n\\end{verbatim}\n\n";
  209. } else if(!found(line.find("!")) && !found(line.find("¡"))) {
  210. line = line.erase(0,1);
  211. return "\\verb!" + line + "!\n";
  212. } else if(!found(line.find("}")) && !found(line.find("{"))) {
  213. line = line.erase(0,1);
  214. return "\\verb{" + line + "}\n";
  215. } else {
  216. line = line.erase(0, 1);
  217. return "\\begin{verbatim}\n" + line + "\n\\end{verbatim}\n\n";
  218. }
  219. } else
  220. return "";
  221. }
  222. string tedi2tex::get_table_start_tag(string& line) {
  223. int columns = get_table_columns(line);
  224. string start_table_tag = "\\begin{longtable}{";
  225. double size_per_column = 0.9 / columns;
  226. for(int i = 0; i < columns; ++i)
  227. start_table_tag += "|p{" + to_string(size_per_column) + "\\linewidth}";
  228. start_table_tag += "|}\n";
  229. return start_table_tag;
  230. }
  231. int tedi2tex::get_table_columns(string line){
  232. int data = 0;
  233. size_t pipe = line.find("|");
  234. int size = line.size() - 1;
  235. while(found(pipe) && (line[size] == '|' || line[size - 1] == '|')) {
  236. ++pipe;
  237. line = line.substr(pipe, line.size() - 1);
  238. pipe = line.find("|");
  239. size = line.size() - 1;
  240. ++data;
  241. }
  242. return data - 1;
  243. }
  244. void tedi2tex::escape_underscores(string& line) {
  245. size_t underscore = line.find('_');
  246. while(found(underscore)) {
  247. if(underscore + 1 >= line.size() || line[underscore + 1] != '_')
  248. line = line.insert(underscore, 1, '\\');
  249. underscore = line.find('_', underscore + 2);
  250. }
  251. }