1
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 ******************************************************************************/
11
12 #include <climits>
13 #include "edit_typeset.hpp"
14 #include "tm_buffer.hpp"
15 #include "convert.hpp"
16 #include "file.hpp"
17 #include "analyze.hpp"
18 #include "timer.hpp"
19 #include "Bridge/impl_typesetter.hpp"
20 #include "new_style.hpp"
21 #include "iterator.hpp"
22 #include "merge_sort.hpp"
23 #ifdef EXPERIMENTAL
24 #include "../../Style/Environment/std_environment.hpp"
25 #endif // EXPERIMENTAL
26
27 //box empty_box (path ip, int x1=0, int y1=0, int x2=0, int y2=0);
28 bool enable_fastenv= false;
29
30 /******************************************************************************
31 * Contructors, destructors and notification of modifications
32 ******************************************************************************/
33
edit_typeset_rep()34 edit_typeset_rep::edit_typeset_rep ():
35 the_style (TUPLE),
36 cur (hashmap<string,tree> (UNINIT)),
37 stydef (UNINIT), pre (UNINIT), init (UNINIT), fin (UNINIT),
38 env (drd, buf->buf->master,
39 buf->data->ref, (buf->prj==NULL? buf->data->ref: buf->prj->data->ref),
40 buf->data->aux, (buf->prj==NULL? buf->data->aux: buf->prj->data->aux),
41 buf->data->att, (buf->prj==NULL? buf->data->att: buf->prj->data->att)),
42 ttt (new_typesetter (env, subtree (et, rp), reverse (rp))) {}
~edit_typeset_rep()43 edit_typeset_rep::~edit_typeset_rep () { delete_typesetter (ttt); }
44
45 void
set_data(new_data data)46 edit_typeset_rep::set_data (new_data data) {
47 set_style (data->style);
48 set_init (data->init);
49 set_fin (data->fin);
50 set_att (data->att);
51 notify_page_change ();
52 add_init (data->init);
53 notify_change (THE_DECORATIONS);
54 typeset_invalidate_env ();
55 iterator<string> it = iterate (data->att);
56 while (it->busy()) {
57 string key= it->next ();
58 (void) call (string ("notify-set-attachment"),
59 buf->buf->name, key, data->att [key]);
60 }
61 }
62
63 void
get_data(new_data & data)64 edit_typeset_rep::get_data (new_data& data) {
65 data->style= get_style ();
66 data->init = get_init ();
67 data->fin = get_fin ();
68 data->att = get_att ();
69 }
70
get_typesetter()71 typesetter edit_typeset_rep::get_typesetter () { return ttt; }
get_style()72 tree edit_typeset_rep::get_style () { return the_style; }
set_style(tree t)73 void edit_typeset_rep::set_style (tree t) { the_style= copy (t); }
get_init()74 hashmap<string,tree> edit_typeset_rep::get_init () { return init; }
get_fin()75 hashmap<string,tree> edit_typeset_rep::get_fin () { return fin; }
get_att()76 hashmap<string,tree> edit_typeset_rep::get_att () { return buf->data->att; }
set_fin(hashmap<string,tree> H)77 void edit_typeset_rep::set_fin (hashmap<string,tree> H) { fin= H; }
set_att(hashmap<string,tree> H)78 void edit_typeset_rep::set_att (hashmap<string,tree> H) { buf->data->att= H; }
79
80 tree
get_att(string key)81 edit_typeset_rep::get_att (string key) {
82 return buf->data->att[key];
83 }
84
85 void
set_att(string key,tree im)86 edit_typeset_rep::set_att (string key, tree im) {
87 buf->data->att (key)= im;
88 }
89
90 void
reset_att(string key)91 edit_typeset_rep::reset_att (string key) {
92 buf->data->att->reset (key);
93 }
94
95 array<string>
list_atts()96 edit_typeset_rep::list_atts () {
97 tree a= (tree) buf->data->att;
98 array<string> v;
99 int i, n= N(a);
100 for (i=0; i<n; i++)
101 v << a[i][0]->label;
102 merge_sort (v);
103 return v;
104 }
105
106 void
set_init(hashmap<string,tree> H)107 edit_typeset_rep::set_init (hashmap<string,tree> H) {
108 init= hashmap<string,tree> (UNINIT);
109 add_init (H);
110 }
111
112 void
add_init(hashmap<string,tree> H)113 edit_typeset_rep::add_init (hashmap<string,tree> H) {
114 init->join (H);
115 ::notify_assign (ttt, path(), subtree (et, rp));
116 notify_change (THE_ENVIRONMENT);
117 }
118
119 void
clear_local_info()120 edit_typeset_rep::clear_local_info () {
121 buf->data->ref= hashmap<string,tree> ();
122 buf->data->aux= hashmap<string,tree> ();
123 }
124
125 /******************************************************************************
126 * Miscellaneous routines for lengths arithmetic (should be elsewhere)
127 ******************************************************************************/
128
129 SI
as_length(string l)130 edit_typeset_rep::as_length (string l) {
131 return env->as_length (l); }
132
133 string
add_lengths(string l1,string l2)134 edit_typeset_rep::add_lengths (string l1, string l2) {
135 return env->add_lengths (l1, l2); }
136
137 string
multiply_length(double x,string l)138 edit_typeset_rep::multiply_length (double x, string l) {
139 return env->multiply_length (x, l); }
140
141 bool
is_length(string s)142 edit_typeset_rep::is_length (string s) {
143 return env->is_length (s); }
144
145 double
divide_lengths(string l1,string l2)146 edit_typeset_rep::divide_lengths (string l1, string l2) {
147 return env->divide_lengths (l1, l2); }
148
149 /******************************************************************************
150 * Processing preamble
151 ******************************************************************************/
152
153 void
use_modules(tree t)154 use_modules (tree t) {
155 if (is_tuple (t))
156 for (int i=0; i<N(t); i++) {
157 string s= as_string (t[i]);
158 if (starts (s, "(")) eval ("(use-modules " * s * ")");
159 else if (s != "") eval ("(plugin-initialize '" * s * ")");
160 }
161 }
162
163 void
typeset_style_use_cache(tree style)164 edit_typeset_rep::typeset_style_use_cache (tree style) {
165 style= preprocess_style (style, buf->buf->master);
166 //cout << "Typesetting style using cache " << style << LF;
167 bool ok;
168 hashmap<string,tree> H;
169 tree t;
170 style_get_cache (style, H, t, ok);
171 if (ok) {
172 env->patch_env (H);
173 ok= drd->set_locals (t);
174 drd->set_environment (H);
175 }
176 if (!ok) {
177 //cout << "Typeset without cache " << style << LF;
178 if (!is_tuple (style)) FAILED ("tuple expected as style");
179 H= get_style_env (style);
180 drd= get_style_drd (style);
181 style_set_cache (style, H, drd->get_locals ());
182 env->patch_env (H);
183 drd->set_environment (H);
184 }
185 use_modules (env->read (THE_MODULES));
186 }
187
188 void
typeset_preamble()189 edit_typeset_rep::typeset_preamble () {
190 env->write_default_env ();
191 typeset_style_use_cache (the_style);
192 env->update ();
193 env->read_env (stydef);
194 env->patch_env (init);
195 env->update ();
196 env->read_env (pre);
197 drd->heuristic_init (pre);
198 }
199
200 void
typeset_prepare()201 edit_typeset_rep::typeset_prepare () {
202 env->base_file_name= buf->buf->master;
203 env->read_only= buf->buf->read_only;
204 env->write_default_env ();
205 env->patch_env (pre);
206 env->style_init_env ();
207 env->update ();
208 }
209
210 void
drd_update()211 edit_typeset_rep::drd_update () {
212 typeset_exec_until (tp);
213 drd->heuristic_init (cur[tp]);
214 }
215
216 #ifdef EXPERIMENTAL
217 void
environment_update()218 edit_typeset_rep::environment_update () {
219 hashmap<string,tree> h;
220 typeset_prepare ();
221 env->assign ("base-file-name", as_string (env->base_file_name));
222 env->assign ("cur-file-name", as_string (env->cur_file_name));
223 env->assign ("secure", bool_as_tree (env->secure));
224 env->read_env (h);
225 ::primitive (ste, h);
226 }
227 #endif
228
229 /******************************************************************************
230 * Routines for getting information
231 ******************************************************************************/
232
233 void
typeset_invalidate_env()234 edit_typeset_rep::typeset_invalidate_env () {
235 cur= hashmap<path,hashmap<string,tree> > (hashmap<string,tree> (UNINIT));
236 }
237
238 static void
restricted_exec(edit_env env,tree t,int end)239 restricted_exec (edit_env env, tree t, int end) {
240 if (is_func (t, ASSIGN, 2) && end == 2)
241 env->exec (t);
242 else if (is_document (t) || is_concat (t))
243 for (int i=0; i < min (end, 10); i++)
244 restricted_exec (env, t[i], arity (t[i]));
245 else if (is_compound (t, "hide-preamble", 1) ||
246 is_compound (t, "show-preamble", 1))
247 env->exec (t[0]);
248 }
249
250 static tree
filter_format(tree fm,int i,int n)251 filter_format (tree fm, int i, int n) {
252 array<tree> r;
253 for (int k=0; k<N(fm); k++)
254 if (is_func (fm[k], CWITH) && N(fm[k]) >= 4 &&
255 is_int (fm[k][0]) && is_int (fm[k][1])) {
256 int j1= as_int (fm[k][0]->label);
257 int j2= as_int (fm[k][1]->label);
258 if (j1 > 0) j1--; else j1 += n;
259 if (j2 > 0) j2--; else j2 += n;
260 if (i >= j1 && i <= j2) r << fm[k] (2, N(fm[k]));
261 }
262 return tree (TFORMAT, r);
263 }
264
265 static void
table_descend(tree & t,path & p,tree & fm)266 table_descend (tree& t, path& p, tree& fm) {
267 while (!is_nil (p)) {
268 if (L(t) == TFORMAT && p->item == N(t) - 1) {
269 array<tree> r;
270 for (int k=0; k<N(t)-1; k++)
271 if (is_func (t[k], CWITH, 6) &&
272 is_atomic (t[k][4]) &&
273 !starts (t[k][4]->label, "cell-"))
274 r << t[k];
275 fm= tree (TFORMAT, r);
276 t= t[N(t)-1];
277 p= p->next;
278 }
279 else if ((L(t) == TABLE || L(t) == ROW) &&
280 p->item >= 0 && p->item < N(t)) {
281 fm= filter_format (fm, p->item, N(t));
282 t= t[p->item];
283 p= p->next;
284 }
285 else break;
286 }
287 }
288
289 void
typeset_exec_until(path p)290 edit_typeset_rep::typeset_exec_until (path p) {
291 //time_t t1= texmacs_time ();
292 if (has_changed (THE_TREE + THE_ENVIRONMENT))
293 if (p != correct_cursor (et, rp * 0)) {
294 if (DEBUG_STD) std_warning << "resynchronizing for path " << p << "\n";
295 // apply_changes ();
296 }
297 if (p == tp && inside_graphics (true) && p != closest_inside (et, p)) {
298 //cout << "TeXmacs] Warning: corrected cursor\n";
299 tp= closest_inside (et, tp);
300 p = tp;
301 }
302
303 //cout << "Exec until " << p << LF;
304 if (N(cur[p])!=0) return;
305 if (N(cur)>=25) // avoids out of memory in weird cases
306 typeset_invalidate_env ();
307 typeset_prepare ();
308 if (enable_fastenv) {
309 if (!(rp < p)) {
310 failed_error << "Erroneous path " << p << "\n";
311 FAILED ("invalid typesetting path");
312 }
313 tree t= subtree (et, rp);
314 path q= path_up (p / rp);
315 while (!is_nil (q)) {
316 int i= q->item;
317 restricted_exec (env, t, i);
318 if (L(t) == TFORMAT && i == N(t) - 1) {
319 tree fm= tree (TFORMAT);
320 table_descend (t, q, fm);
321 if (!is_nil (q))
322 for (int k=0; k<N(fm); k++)
323 if (is_func (fm[k], CWITH, 2))
324 env->write (fm[k][0]->label, fm[k][1]);
325 }
326 else {
327 tree w= drd->get_env_child (t, i, tree (ATTR));
328 if (w == "") break;
329 //cout << "t= " << t << "\n";
330 //cout << "i= " << i << "\n";
331 //cout << "w= " << w << "\n";
332 for (int j=0; j<N(w); j+=2) {
333 //cout << w[j] << " := " << env->exec (w[j+1]) << "\n";
334 env->write (w[j]->label, env->exec (w[j+1]));
335 }
336 t= t[i];
337 q= q->next;
338 }
339 }
340 if (env->read (PREAMBLE) == "true")
341 env->write (MODE, "src");
342 }
343 else exec_until (ttt, p / rp);
344 env->read_env (cur (p));
345 //time_t t2= texmacs_time ();
346 //if (t2 - t1 >= 10) cout << "typeset_exec_until took " << t2-t1 << "ms\n";
347 }
348
349 tree
get_full_env()350 edit_typeset_rep::get_full_env () {
351 typeset_exec_until (tp);
352 return (tree) cur[tp];
353 }
354
355 bool
defined_at_cursor(string var)356 edit_typeset_rep::defined_at_cursor (string var) {
357 typeset_exec_until (tp);
358 return cur[tp]->contains (var);
359 }
360
361 tree
get_env_value(string var,path p)362 edit_typeset_rep::get_env_value (string var, path p) {
363 typeset_exec_until (p);
364 tree t= cur[p][var];
365 return is_func (t, BACKUP, 2)? t[0]: t;
366 }
367
368 tree
get_env_value(string var)369 edit_typeset_rep::get_env_value (string var) {
370 /* FIXME: tp is wrong (and consequently, crashes TeXmacs)
371 * when we call this routine from inside the code which
372 * is triggered by a button, for example.
373 *
374 * Test: fire TeXmacs, then open a new Graphics, then click
375 * on the icon for going in spline mode. Then it crashes,
376 * because we call (get-env-tree) from inside the Scheme.
377 * If we call (get-env-tree-at ... (cDr (cursor-path))),
378 * then it works.
379 */
380 return get_env_value (var, tp);
381 }
382
383 bool
defined_at_init(string var)384 edit_typeset_rep::defined_at_init (string var) {
385 if (init->contains (var)) return true;
386 if (N(pre)==0) typeset_preamble ();
387 return pre->contains (var);
388 }
389
390 bool
defined_in_init(string var)391 edit_typeset_rep::defined_in_init (string var) {
392 return init->contains (var);
393 }
394
395 tree
get_init_value(string var)396 edit_typeset_rep::get_init_value (string var) {
397 if (init->contains (var)) {
398 tree t= init [var];
399 return is_func (t, BACKUP, 2)? t[0]: t;
400 }
401 if (N(pre)==0) typeset_preamble ();
402 tree t= pre [var];
403 return is_func (t, BACKUP, 2)? t[0]: t;
404 }
405
406 string
get_env_string(string var)407 edit_typeset_rep::get_env_string (string var) {
408 return as_string (get_env_value (var));
409 }
410
411 string
get_init_string(string var)412 edit_typeset_rep::get_init_string (string var) {
413 return as_string (get_init_value (var));
414 }
415
416 int
get_env_int(string var)417 edit_typeset_rep::get_env_int (string var) {
418 return as_int (get_env_value (var));
419 }
420
421 int
get_init_int(string var)422 edit_typeset_rep::get_init_int (string var) {
423 return as_int (get_init_value (var));
424 }
425
426 double
get_env_double(string var)427 edit_typeset_rep::get_env_double (string var) {
428 return as_double (get_env_value (var));
429 }
430
431 double
get_init_double(string var)432 edit_typeset_rep::get_init_double (string var) {
433 return as_double (get_init_value (var));
434 }
435
436 language
get_env_language()437 edit_typeset_rep::get_env_language () {
438 string mode= get_env_string (MODE);
439 if (mode == "text")
440 return text_language (get_env_string (LANGUAGE));
441 else if (mode == "math")
442 return math_language (get_env_string (MATH_LANGUAGE));
443 else return prog_language (get_env_string (PROG_LANGUAGE));
444 }
445
446 SI
get_page_width()447 edit_typeset_rep::get_page_width () {
448 (void) get_env_string (PAGE_WIDTH);
449 return (env->page_user_width + env->page_odd_margin +
450 env->page_right_margin + std_shrinkf - 1) / std_shrinkf;
451 }
452
453 SI
get_page_height()454 edit_typeset_rep::get_page_height () {
455 (void) get_env_string (PAGE_HEIGHT);
456 return (env->page_user_height + env->page_top_margin +
457 env->page_bottom_margin + std_shrinkf - 1) / std_shrinkf;
458 }
459
460 /******************************************************************************
461 * Execution without typesetting
462 ******************************************************************************/
463
464 static tree
simplify_execed(tree t)465 simplify_execed (tree t) {
466 if (is_atomic (t)) return t;
467 int i, n= N(t);
468 tree r (t, n);
469 for (i=0; i<n; i++)
470 r[i]= simplify_execed (t[i]);
471 if (is_func (r, QUOTE, 1) && is_atomic (r[0]))
472 return r[0];
473 else return r;
474 }
475
476 static tree
expand_references(tree t,hashmap<string,tree> h)477 expand_references (tree t, hashmap<string,tree> h) {
478 if (is_atomic (t)) return t;
479 if (is_func (t, REFERENCE, 1) || is_func (t, PAGEREF)) {
480 string ref= as_string (simplify_execed (t[0]));
481 if (h->contains (ref)) {
482 int which= is_func (t, REFERENCE, 1)? 0: 1;
483 return tree (HLINK, copy (h[ref][which]), "#" * ref);
484 }
485 return tree (HLINK, "?", "#" * ref);
486 }
487 int i, n= N(t);
488 tree r (t, n);
489 for (i=0; i<n; i++)
490 r[i]= expand_references (t[i], h);
491 return r;
492 }
493
494 tree
exec(tree t,hashmap<string,tree> H,bool expand_refs)495 edit_typeset_rep::exec (tree t, hashmap<string,tree> H, bool expand_refs) {
496 hashmap<string,tree> H2;
497 env->read_env (H2);
498 env->write_env (H);
499 t= env->exec (t);
500 if (expand_refs)
501 t= expand_references (t, buf->data->ref);
502 t= simplify_execed (t);
503 t= simplify_correct (t);
504 env->write_env (H2);
505 return t;
506 }
507
508 tree
exec_texmacs(tree t,path p)509 edit_typeset_rep::exec_texmacs (tree t, path p) {
510 typeset_exec_until (p);
511 return exec (t, cur[p]);
512 }
513
514 tree
exec_texmacs(tree t)515 edit_typeset_rep::exec_texmacs (tree t) {
516 return exec_texmacs (t, rp * 0);
517 }
518
519 tree
exec_verbatim(tree t,path p)520 edit_typeset_rep::exec_verbatim (tree t, path p) {
521 t= convert_OTS1_symbols_to_universal_encoding (t);
522 typeset_exec_until (p);
523 hashmap<string,tree> H= copy (cur[p]);
524 H ("TeXmacs")= tree (MACRO, "TeXmacs");
525 H ("LaTeX")= tree (MACRO, "LaTeX");
526 H ("TeX")= tree (MACRO, "TeX");
527 return exec (t, H);
528 }
529
530 tree
exec_verbatim(tree t)531 edit_typeset_rep::exec_verbatim (tree t) {
532 return exec_verbatim (t, rp * 0);
533 }
534
535 tree
exec_html(tree t,path p)536 edit_typeset_rep::exec_html (tree t, path p) {
537 t= convert_OTS1_symbols_to_universal_encoding (t);
538 if (p == (rp * 0)) typeset_preamble ();
539 typeset_exec_until (p);
540 hashmap<string,tree> H= copy (cur[p]);
541 tree patch= as_tree (eval ("(stree->tree (tmhtml-env-patch))"));
542 hashmap<string,tree> P (UNINIT, patch);
543 H->join (P);
544 tree w (WITH);
545 if (H->contains ("html-title"))
546 w << string ("html-title") << H["html-title"];
547 if (H->contains ("html-css"))
548 w << string ("html-css") << H["html-css"];
549 if (H->contains ("html-head-javascript"))
550 w << string ("html-head-javascript") << H["html-head-javascript"];
551 if (H->contains ("html-head-javascript-src"))
552 w << string ("html-head-javascript-src") << H["html-head-javascript-src"];
553 if (N(w) == 0) return exec (t, H);
554 else {
555 w << t;
556 return exec (w, H);
557 }
558 //tree r= exec (t, H);
559 //cout << "In: " << t << "\n";
560 //cout << "Out: " << r << "\n";
561 //return r;
562 }
563
564 tree
exec_html(tree t)565 edit_typeset_rep::exec_html (tree t) {
566 return exec_html (t, rp * 0);
567 }
568
569 static tree
value_to_compound(tree t,hashmap<string,tree> h)570 value_to_compound (tree t, hashmap<string,tree> h) {
571 if (is_atomic (t)) return t;
572 else if (is_func (t, VALUE, 1) &&
573 is_atomic (t[0]) &&
574 h->contains (t[0]->label))
575 return compound (t[0]->label);
576 else {
577 int i, n= N(t);
578 tree r (t, n);
579 for (i=0; i<n; i++)
580 r[i]= value_to_compound (t[i], h);
581 return r;
582 }
583 }
584
585 tree
exec_latex(tree t,path p)586 edit_typeset_rep::exec_latex (tree t, path p) {
587 t= convert_OTS1_symbols_to_universal_encoding (t);
588 bool expand_unknown_macros= "on" == as_string (
589 call ("get-preference", "texmacs->latex:expand-macros"));
590 bool expand_user_macro= "on" == as_string (
591 call ("get-preference", "texmacs->latex:expand-user-macros"));
592 if (!expand_unknown_macros && !expand_user_macro)
593 return t;
594 if (p == (rp * 0)) typeset_preamble ();
595 typeset_exec_until (p);
596 hashmap<string,tree> H= copy (cur[p]);
597 object l= null_object ();
598 iterator<string> it= iterate (H);
599 while (it->busy ()) l= cons (object (it->next ()), l);
600 tree patch= as_tree (call ("stree->tree", call ("tmtex-env-patch", t, l)));
601 hashmap<string,tree> P (UNINIT, patch);
602 H->join (P);
603
604 if (!expand_user_macro &&
605 is_document (t) && is_compound (t[0], "hide-preamble")) {
606 tree r= copy (t);
607 r[0]= "";
608 r= exec (value_to_compound (r, P), H, false);
609 r[0]= exec (t[0], H, false);
610 return r;
611 }
612 else {
613 tree r= exec (value_to_compound (t, P), H, false);
614 return r;
615 }
616 }
617
618 tree
exec_latex(tree t)619 edit_typeset_rep::exec_latex (tree t) {
620 return exec_latex (t, rp * 0);
621 }
622
623 tree
texmacs_exec(tree t)624 edit_typeset_rep::texmacs_exec (tree t) {
625 return ::texmacs_exec (env, t);
626 }
627
628 /******************************************************************************
629 * Initialization
630 ******************************************************************************/
631
632 void
change_style(tree t)633 edit_typeset_rep::change_style (tree t) {
634 bool changed= (the_style != t);
635 the_style= copy (t);
636 if (changed) {
637 require_save ();
638 notify_change (THE_ENVIRONMENT);
639 }
640 }
641
642 void
init_style()643 edit_typeset_rep::init_style () {
644 notify_change (THE_ENVIRONMENT);
645 }
646
647 void
init_style(string name)648 edit_typeset_rep::init_style (string name) {
649 if ((name == "none") || (name == "") || (name == "style")) the_style= TUPLE;
650 else if (arity (the_style) == 0) the_style= tree (TUPLE, name);
651 else the_style= tree (TUPLE, name) * the_style (1, N(the_style));
652 require_save ();
653 notify_change (THE_ENVIRONMENT);
654 }
655
656 tree
get_init_all()657 edit_typeset_rep::get_init_all () {
658 return (tree) init;
659 }
660
661 void
init_env(string var,tree by)662 edit_typeset_rep::init_env (string var, tree by) {
663 if (init (var) == by) return;
664 init (var)= by;
665 if (var != PAGE_SCREEN_WIDTH &&
666 var != PAGE_SCREEN_HEIGHT &&
667 var != ZOOM_FACTOR)
668 require_save ();
669 notify_change (THE_ENVIRONMENT);
670 }
671
672 void
init_default(string var)673 edit_typeset_rep::init_default (string var) {
674 if (!init->contains (var)) return;
675 init->reset (var);
676 if (stydef->contains (var)) pre(var)= stydef[var];
677 else pre->reset (var);
678 notify_change (THE_ENVIRONMENT);
679 }
680
681 /******************************************************************************
682 * Actual typesetting
683 ******************************************************************************/
684
685 void
typeset_sub(SI & x1,SI & y1,SI & x2,SI & y2)686 edit_typeset_rep::typeset_sub (SI& x1, SI& y1, SI& x2, SI& y2) {
687 //time_t t1= texmacs_time ();
688 typeset_prepare ();
689 eb= empty_box (reverse (rp));
690 // saves memory, also necessary for change_log update
691 bench_start ("typeset");
692 #ifdef USE_EXCEPTIONS
693 try {
694 #endif
695 eb= ::typeset (ttt, x1, y1, x2, y2);
696 #ifdef USE_EXCEPTIONS
697 }
698 catch (string msg) {
699 the_exception= msg;
700 std_error << "Typesetting failure, resetting to empty document\n";
701 assign (rp, tree (DOCUMENT, ""));
702 ::notify_assign (ttt, path(), subtree (et, rp));
703 eb= ::typeset (ttt, x1, y1, x2, y2);
704 }
705 handle_exceptions ();
706 #endif
707 bench_end ("typeset");
708 //time_t t2= texmacs_time ();
709 //if (t2 - t1 >= 10) cout << "typeset took " << t2-t1 << "ms\n";
710 picture_cache_clean ();
711 }
712
713 static void
report_missing(hashmap<string,tree> missing)714 report_missing (hashmap<string,tree> missing) {
715 array<string> a;
716 for (iterator<string> it= iterate (missing); it->busy(); a << it->next ());
717 merge_sort (a);
718 for (int i=0; i<N(a); i++)
719 if (!starts (a[i], "bib-"))
720 typeset_warning << "Undefined reference " << a[i] << LF;
721 }
722
723 static void
report_redefined(array<tree> redefined)724 report_redefined (array<tree> redefined) {
725 for (int i=0; i<N(redefined); i++) {
726 tree t= redefined[i];
727 if (t[1]->label == "")
728 typeset_warning << "Redefined " << t[0]->label << LF;
729 else
730 typeset_warning << "Redefined " << t[0]->label
731 << " as " << t[1]->label << LF;
732 }
733 }
734
735 void
typeset(SI & x1,SI & y1,SI & x2,SI & y2)736 edit_typeset_rep::typeset (SI& x1, SI& y1, SI& x2, SI& y2) {
737 int missing_nr= INT_MAX;
738 int redefined_nr= INT_MAX;
739 while (true) {
740 typeset_sub (x1, y1, x2, y2);
741 if (!env->complete) break;
742 env->complete= false;
743 if (N(env->missing) == 0 && N(env->redefined) == 0) break;
744 if ((N(env->missing) == missing_nr && N(env->redefined) == redefined_nr) ||
745 (N(env->missing) > missing_nr || N(env->redefined) > redefined_nr)) {
746 report_missing (env->missing);
747 report_redefined (env->redefined);
748 break;
749 }
750 missing_nr= N(env->missing);
751 redefined_nr= N(env->redefined);
752 ::notify_assign (ttt, path(), ttt->br->st);
753 }
754 }
755
756 void
typeset_invalidate(path p)757 edit_typeset_rep::typeset_invalidate (path p) {
758 if (rp <= p) {
759 //cout << "Invalidate " << p << "\n";
760 notify_change (THE_TREE);
761 ::notify_assign (ttt, p / rp, subtree (et, p));
762 }
763 }
764
765 void
typeset_invalidate_all()766 edit_typeset_rep::typeset_invalidate_all () {
767 //cout << "Invalidate all\n";
768 notify_change (THE_ENVIRONMENT);
769 typeset_preamble ();
770 ::notify_assign (ttt, path(), subtree (et, rp));
771 }
772