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