PageRenderTime 41ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/source/src/Edit/Editor/edit_typeset.cpp

http://itexmacs.googlecode.com/
C++ | 582 lines | 452 code | 68 blank | 62 comment | 103 complexity | 429bcc3f3777ffbe5a7337848b1a3789 MD5 | raw file
Possible License(s): GPL-3.0, GPL-2.0, MPL-2.0-no-copyleft-exception, LGPL-2.0
  1. /******************************************************************************
  2. * MODULE : typeset.cpp
  3. * DESCRIPTION: typeset the tree being edited
  4. * COPYRIGHT : (C) 1999 Joris van der Hoeven
  5. *******************************************************************************
  6. * This software falls under the GNU general public license version 3 or later.
  7. * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
  8. * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
  9. ******************************************************************************/
  10. #include "edit_typeset.hpp"
  11. #include "tm_buffer.hpp"
  12. #include "convert.hpp"
  13. #include "file.hpp"
  14. #include "analyze.hpp"
  15. #include "timer.hpp"
  16. #include "Bridge/impl_typesetter.hpp"
  17. #ifdef EXPERIMENTAL
  18. #include "../../Style/Environment/std_environment.hpp"
  19. #endif // EXPERIMENTAL
  20. //box empty_box (path ip, int x1=0, int y1=0, int x2=0, int y2=0);
  21. bool enable_fastenv= false;
  22. /******************************************************************************
  23. * Contructors, destructors and notification of modifications
  24. ******************************************************************************/
  25. static bool
  26. is_aux (url u) {
  27. if (!is_atomic (u->t)) return false;
  28. string s= u->t->label;
  29. return starts (s, "* ") && ends (s, " *");
  30. }
  31. edit_typeset_rep::edit_typeset_rep ():
  32. the_style (TUPLE),
  33. cur (hashmap<string,tree> (UNINIT)),
  34. pre (UNINIT), init (UNINIT), fin (UNINIT),
  35. env (drd, is_aux (buf->name)? buf->extra: buf->name,
  36. buf->ref, (buf->prj==NULL? buf->ref: buf->prj->ref),
  37. buf->aux, (buf->prj==NULL? buf->aux: buf->prj->aux)),
  38. ttt (new_typesetter (env, subtree (et, rp), reverse (rp))) {}
  39. edit_typeset_rep::~edit_typeset_rep () { delete_typesetter (ttt); }
  40. typesetter edit_typeset_rep::get_typesetter () { return ttt; }
  41. tree edit_typeset_rep::get_style () { return the_style; }
  42. void edit_typeset_rep::set_style (tree t) { the_style= copy (t); }
  43. hashmap<string,tree> edit_typeset_rep::get_init () { return init; }
  44. hashmap<string,tree> edit_typeset_rep::get_fin () { return fin; }
  45. void edit_typeset_rep::set_fin (hashmap<string,tree> H) { fin= H; }
  46. void
  47. edit_typeset_rep::set_init (hashmap<string,tree> H) {
  48. init= hashmap<string,tree> (UNINIT);
  49. add_init (H);
  50. }
  51. void
  52. edit_typeset_rep::add_init (hashmap<string,tree> H) {
  53. init->join (H);
  54. ::notify_assign (ttt, path(), subtree (et, rp));
  55. notify_change (THE_ENVIRONMENT);
  56. }
  57. void
  58. edit_typeset_rep::set_base_name (url name) {
  59. env->base_file_name= name;
  60. }
  61. void
  62. edit_typeset_rep::clear_local_info () {
  63. buf->ref= hashmap<string,tree> ();
  64. buf->aux= hashmap<string,tree> ();
  65. }
  66. /******************************************************************************
  67. * Miscellaneous routines for lengths arithmetic (should be elsewhere)
  68. ******************************************************************************/
  69. SI
  70. edit_typeset_rep::as_length (string l) {
  71. return env->as_length (l); }
  72. string
  73. edit_typeset_rep::add_lengths (string l1, string l2) {
  74. return env->add_lengths (l1, l2); }
  75. string
  76. edit_typeset_rep::multiply_length (double x, string l) {
  77. return env->multiply_length (x, l); }
  78. bool
  79. edit_typeset_rep::is_length (string s) {
  80. return env->is_length (s); }
  81. double
  82. edit_typeset_rep::divide_lengths (string l1, string l2) {
  83. return env->divide_lengths (l1, l2); }
  84. /******************************************************************************
  85. * Processing preamble
  86. ******************************************************************************/
  87. void
  88. use_modules (tree t) {
  89. if (is_tuple (t))
  90. for (int i=0; i<N(t); i++) {
  91. string s= as_string (t[i]);
  92. if (starts (s, "(")) eval ("(use-modules " * s * ")");
  93. else if (s != "") eval ("(plugin-initialize '" * s * ")");
  94. }
  95. }
  96. void
  97. edit_typeset_rep::typeset_style_use_cache (tree style) {
  98. //cout << "Typesetting style using cache " << style << LF;
  99. bool ok;
  100. hashmap<string,tree> H;
  101. tree t;
  102. SERVER (style_get_cache (style, H, t, ok));
  103. if (ok) {
  104. env->patch_env (H);
  105. ok= drd->set_locals (t);
  106. drd->set_environment (H);
  107. }
  108. if (!ok) {
  109. //cout << "Typeset without cache " << style << LF;
  110. if (!is_tuple (style)) FAILED ("tuple expected as style");
  111. tree t (USE_PACKAGE, A (style));
  112. env->exec (t);
  113. env->read_env (H);
  114. drd->heuristic_init (H);
  115. SERVER (style_set_cache (style, H, drd->get_locals ()));
  116. }
  117. use_modules (env->read (THE_MODULES));
  118. }
  119. void
  120. edit_typeset_rep::typeset_preamble () {
  121. env->write_default_env ();
  122. typeset_style_use_cache (the_style);
  123. env->patch_env (init);
  124. env->update ();
  125. env->read_env (pre);
  126. drd->heuristic_init (pre);
  127. }
  128. void
  129. edit_typeset_rep::typeset_prepare () {
  130. env->read_only= buf->read_only;
  131. env->write_default_env ();
  132. env->patch_env (pre);
  133. env->style_init_env ();
  134. env->update ();
  135. }
  136. void
  137. edit_typeset_rep::drd_update () {
  138. typeset_exec_until (tp);
  139. drd->heuristic_init (cur[tp]);
  140. }
  141. #ifdef EXPERIMENTAL
  142. void
  143. edit_typeset_rep::environment_update () {
  144. hashmap<string,tree> h;
  145. typeset_prepare ();
  146. env->assign ("base-file-name", as_string (env->base_file_name));
  147. env->assign ("cur-file-name", as_string (env->cur_file_name));
  148. env->assign ("secure", bool_as_tree (env->secure));
  149. env->read_env (h);
  150. ::primitive (ste, h);
  151. }
  152. #endif
  153. /******************************************************************************
  154. * Routines for getting information
  155. ******************************************************************************/
  156. void
  157. edit_typeset_rep::typeset_invalidate_env () {
  158. cur= hashmap<path,hashmap<string,tree> > (hashmap<string,tree> (UNINIT));
  159. }
  160. static void
  161. restricted_exec (edit_env env, tree t, int end) {
  162. if (is_func (t, ASSIGN, 2) && end == 2)
  163. env->exec (t);
  164. else if (is_document (t) || is_concat (t))
  165. for (int i=0; i < min (end, 10); i++)
  166. restricted_exec (env, t[i], arity (t[i]));
  167. else if (is_compound (t, "hide-preamble", 1) ||
  168. is_compound (t, "show-preamble", 1))
  169. env->exec (t[0]);
  170. }
  171. void
  172. edit_typeset_rep::typeset_exec_until (path p) {
  173. //time_t t1= texmacs_time ();
  174. if (has_changed (THE_TREE + THE_ENVIRONMENT))
  175. if (p != correct_cursor (et, rp * 0)) {
  176. if (DEBUG_STD)
  177. cout << "TeXmacs] Warning: resynchronizing for path " << p << "\n";
  178. // apply_changes ();
  179. }
  180. if (p == tp && inside_graphics (true) && p != closest_inside (et, p)) {
  181. //cout << "TeXmacs] Warning: corrected cursor\n";
  182. tp= closest_inside (et, tp);
  183. p = tp;
  184. }
  185. if (N(cur[p])!=0) return;
  186. if (N(cur)>=25) // avoids out of memory in weird cases
  187. typeset_invalidate_env ();
  188. typeset_prepare ();
  189. if (enable_fastenv) {
  190. if (!(rp < p)) {
  191. cerr << "TeXmacs] erroneous path " << p << "\n";
  192. FAILED ("invalid typesetting path");
  193. }
  194. tree t= subtree (et, rp);
  195. path q= path_up (p / rp);
  196. while (!is_nil (q)) {
  197. int i= q->item;
  198. restricted_exec (env, t, i);
  199. tree w= drd->get_env_child (t, i, tree (ATTR));
  200. if (w == "") break;
  201. //cout << "t= " << t << "\n";
  202. //cout << "i= " << i << "\n";
  203. //cout << "w= " << w << "\n";
  204. for (int j=0; j<N(w); j+=2) {
  205. //cout << w[j] << " := " << env->exec (w[j+1]) << "\n";
  206. env->write (w[j]->label, env->exec (w[j+1]));
  207. }
  208. t= t[i];
  209. q= q->next;
  210. }
  211. if (env->read (PREAMBLE) == "true")
  212. env->write (MODE, "src");
  213. }
  214. else exec_until (ttt, p / rp);
  215. env->read_env (cur (p));
  216. //time_t t2= texmacs_time ();
  217. //if (t2 - t1 >= 10) cout << "typeset_exec_until took " << t2-t1 << "ms\n";
  218. }
  219. bool
  220. edit_typeset_rep::defined_at_cursor (string var) {
  221. typeset_exec_until (tp);
  222. return cur[tp]->contains (var);
  223. }
  224. tree
  225. edit_typeset_rep::get_env_value (string var, path p) {
  226. typeset_exec_until (p);
  227. tree t= cur[p][var];
  228. return is_func (t, BACKUP, 2)? t[0]: t;
  229. }
  230. tree
  231. edit_typeset_rep::get_env_value (string var) {
  232. /* FIXME: tp is wrong (and consequently, crashes TeXmacs)
  233. * when we call this routine from inside the code which
  234. * is triggered by a button, for example.
  235. *
  236. * Test: fire TeXmacs, then open a new Graphics, then click
  237. * on the icon for going in spline mode. Then it crashes,
  238. * because we call (get-env-tree) from inside the Scheme.
  239. * If we call (get-env-tree-at ... (cDr (cursor-path))),
  240. * then it works.
  241. */
  242. return get_env_value (var, tp);
  243. }
  244. bool
  245. edit_typeset_rep::defined_at_init (string var) {
  246. if (init->contains (var)) return true;
  247. if (N(pre)==0) typeset_preamble ();
  248. return pre->contains (var);
  249. }
  250. bool
  251. edit_typeset_rep::defined_in_init (string var) {
  252. return init->contains (var);
  253. }
  254. tree
  255. edit_typeset_rep::get_init_value (string var) {
  256. if (init->contains (var)) {
  257. tree t= init [var];
  258. return is_func (t, BACKUP, 2)? t[0]: t;
  259. }
  260. if (N(pre)==0) typeset_preamble ();
  261. tree t= pre [var];
  262. return is_func (t, BACKUP, 2)? t[0]: t;
  263. }
  264. string
  265. edit_typeset_rep::get_env_string (string var) {
  266. return as_string (get_env_value (var));
  267. }
  268. string
  269. edit_typeset_rep::get_init_string (string var) {
  270. return as_string (get_init_value (var));
  271. }
  272. int
  273. edit_typeset_rep::get_env_int (string var) {
  274. return as_int (get_env_value (var));
  275. }
  276. int
  277. edit_typeset_rep::get_init_int (string var) {
  278. return as_int (get_init_value (var));
  279. }
  280. double
  281. edit_typeset_rep::get_env_double (string var) {
  282. return as_double (get_env_value (var));
  283. }
  284. double
  285. edit_typeset_rep::get_init_double (string var) {
  286. return as_double (get_init_value (var));
  287. }
  288. language
  289. edit_typeset_rep::get_env_language () {
  290. string mode= get_env_string (MODE);
  291. if (mode == "text")
  292. return text_language (get_env_string (LANGUAGE));
  293. else if (mode == "math")
  294. return math_language (get_env_string (MATH_LANGUAGE));
  295. else return prog_language (get_env_string (PROG_LANGUAGE));
  296. }
  297. /******************************************************************************
  298. * Execution without typesetting
  299. ******************************************************************************/
  300. static tree
  301. simplify_execed (tree t) {
  302. if (is_atomic (t)) return t;
  303. int i, n= N(t);
  304. tree r (t, n);
  305. for (i=0; i<n; i++)
  306. r[i]= simplify_execed (t[i]);
  307. if (is_func (r, QUOTE, 1) && is_atomic (r[0]))
  308. return r[0];
  309. else return r;
  310. }
  311. static tree
  312. expand_references (tree t, hashmap<string,tree> h) {
  313. if (is_atomic (t)) return t;
  314. if (is_func (t, REFERENCE, 1) || is_func (t, PAGEREF)) {
  315. string ref= as_string (simplify_execed (t[0]));
  316. if (h->contains (ref)) {
  317. int which= is_func (t, REFERENCE, 1)? 0: 1;
  318. return tree (HLINK, copy (h[ref][which]), "#" * ref);
  319. }
  320. return tree (HLINK, "?", "#" * ref);
  321. }
  322. int i, n= N(t);
  323. tree r (t, n);
  324. for (i=0; i<n; i++)
  325. r[i]= expand_references (t[i], h);
  326. return r;
  327. }
  328. tree
  329. edit_typeset_rep::exec (tree t, hashmap<string,tree> H, bool expand_refs) {
  330. hashmap<string,tree> H2;
  331. env->read_env (H2);
  332. env->write_env (H);
  333. t= env->exec (t);
  334. if (expand_refs)
  335. t= expand_references (t, buf->ref);
  336. t= simplify_execed (t);
  337. t= simplify_correct (t);
  338. env->write_env (H2);
  339. return t;
  340. }
  341. tree
  342. edit_typeset_rep::exec_texmacs (tree t, path p) {
  343. typeset_exec_until (p);
  344. return exec (t, cur[p]);
  345. }
  346. tree
  347. edit_typeset_rep::exec_texmacs (tree t) {
  348. return exec_texmacs (t, rp * 0);
  349. }
  350. tree
  351. edit_typeset_rep::exec_verbatim (tree t, path p) {
  352. typeset_exec_until (p);
  353. hashmap<string,tree> H= copy (cur[p]);
  354. H ("TeXmacs")= tree (MACRO, "TeXmacs");
  355. H ("LaTeX")= tree (MACRO, "LaTeX");
  356. H ("TeX")= tree (MACRO, "TeX");
  357. return exec (t, H);
  358. }
  359. tree
  360. edit_typeset_rep::exec_verbatim (tree t) {
  361. return exec_verbatim (t, rp * 0);
  362. }
  363. tree
  364. edit_typeset_rep::exec_html (tree t, path p) {
  365. if (p == (rp * 0)) typeset_preamble ();
  366. typeset_exec_until (p);
  367. hashmap<string,tree> H= copy (cur[p]);
  368. tree patch= as_tree (eval ("(stree->tree (tmhtml-env-patch))"));
  369. hashmap<string,tree> P (UNINIT, patch);
  370. H->join (P);
  371. tree w (WITH);
  372. if (H->contains ("html-title"))
  373. w << string ("html-title") << H["html-title"];
  374. if (H->contains ("html-css"))
  375. w << string ("html-css") << H["html-css"];
  376. if (H->contains ("html-head-javascript"))
  377. w << string ("html-head-javascript") << H["html-head-javascript"];
  378. if (H->contains ("html-head-javascript-src"))
  379. w << string ("html-head-javascript-src") << H["html-head-javascript-src"];
  380. if (N(w) == 0) return exec (t, H);
  381. else {
  382. w << t;
  383. return exec (w, H);
  384. }
  385. //tree r= exec (t, H);
  386. //cout << "In: " << t << "\n";
  387. //cout << "Out: " << r << "\n";
  388. //return r;
  389. }
  390. tree
  391. edit_typeset_rep::exec_html (tree t) {
  392. return exec_html (t, rp * 0);
  393. }
  394. static tree
  395. value_to_compound (tree t, hashmap<string,tree> h) {
  396. if (is_atomic (t)) return t;
  397. else if (is_func (t, VALUE, 1) &&
  398. is_atomic (t[0]) &&
  399. h->contains (t[0]->label))
  400. return compound (t[0]->label);
  401. else {
  402. int i, n= N(t);
  403. tree r (t, n);
  404. for (i=0; i<n; i++)
  405. r[i]= value_to_compound (t[i], h);
  406. return r;
  407. }
  408. }
  409. tree
  410. edit_typeset_rep::exec_latex (tree t, path p) {
  411. string pref= "texmacs->latex:expand-macros";
  412. if (as_string (call ("get-preference", pref)) != "on") return t;
  413. if (p == (rp * 0)) typeset_preamble ();
  414. typeset_exec_until (p);
  415. hashmap<string,tree> H= copy (cur[p]);
  416. tree patch= as_tree (call ("stree->tree", call ("tmtex-env-patch", t)));
  417. hashmap<string,tree> P (UNINIT, patch);
  418. H->join (P);
  419. if (is_document (t) && is_compound (t[0], "hide-preamble")) {
  420. tree r= copy (t);
  421. r[0]= "";
  422. r= exec (value_to_compound (r, P), H, false);
  423. r[0]= exec (t[0], H, false);
  424. return r;
  425. }
  426. else return exec (value_to_compound (t, P), H, false);
  427. }
  428. tree
  429. edit_typeset_rep::exec_latex (tree t) {
  430. return exec_latex (t, rp * 0);
  431. }
  432. tree
  433. edit_typeset_rep::texmacs_exec (tree t) {
  434. return ::texmacs_exec (env, t);
  435. }
  436. /******************************************************************************
  437. * Initialization
  438. ******************************************************************************/
  439. void
  440. edit_typeset_rep::init_style () {
  441. notify_change (THE_ENVIRONMENT);
  442. }
  443. void
  444. edit_typeset_rep::init_style (string name) {
  445. if ((name == "none") || (name == "") || (name == "style")) the_style= TUPLE;
  446. else if (arity (the_style) == 0) the_style= tree (TUPLE, name);
  447. else the_style= tree (TUPLE, name) * the_style (1, N(the_style));
  448. require_save ();
  449. notify_change (THE_ENVIRONMENT);
  450. }
  451. void
  452. edit_typeset_rep::init_add_package (string name) {
  453. int i, n= N(the_style);
  454. for (i=0; i<n; i++)
  455. if (the_style[i] == name)
  456. return;
  457. the_style << tree (name);
  458. require_save ();
  459. notify_change (THE_ENVIRONMENT);
  460. }
  461. void
  462. edit_typeset_rep::init_remove_package (string name) {
  463. int i, n= N(the_style);
  464. tree new_style= tree (TUPLE);
  465. for (i=0; i<n; i++)
  466. if (the_style[i] == name) {
  467. require_save ();
  468. notify_change (THE_ENVIRONMENT);
  469. }
  470. else new_style << the_style[i];
  471. the_style= new_style;
  472. }
  473. void
  474. edit_typeset_rep::init_env (string var, tree by) {
  475. if (init (var) == by) return;
  476. init (var)= by;
  477. notify_change (THE_ENVIRONMENT);
  478. }
  479. void
  480. edit_typeset_rep::init_default (string var) {
  481. if (!init->contains (var)) return;
  482. init->reset (var);
  483. notify_change (THE_ENVIRONMENT);
  484. }
  485. /******************************************************************************
  486. * Actual typesetting
  487. ******************************************************************************/
  488. void
  489. edit_typeset_rep::typeset (SI& x1, SI& y1, SI& x2, SI& y2) {
  490. //time_t t1= texmacs_time ();
  491. typeset_prepare ();
  492. eb= empty_box (reverse (rp));
  493. // saves memory, also necessary for change_log update
  494. bench_start ("typeset");
  495. eb= ::typeset (ttt, x1, y1, x2, y2);
  496. bench_end ("typeset");
  497. //time_t t2= texmacs_time ();
  498. //if (t2 - t1 >= 10) cout << "typeset took " << t2-t1 << "ms\n";
  499. }
  500. void
  501. edit_typeset_rep::typeset_invalidate (path p) {
  502. if (rp <= p) {
  503. //cout << "Invalidate " << p << "\n";
  504. notify_change (THE_TREE);
  505. ::notify_assign (ttt, p / rp, subtree (et, p));
  506. }
  507. }
  508. void
  509. edit_typeset_rep::typeset_invalidate_all () {
  510. //cout << "Invalidate all\n";
  511. notify_change (THE_ENVIRONMENT);
  512. typeset_preamble ();
  513. ::notify_assign (ttt, path(), subtree (et, rp));
  514. }