2 /******************************************************************************
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"
16 #include "analyze.hpp"
18 #include "Bridge/impl_typesetter.hpp"
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 ******************************************************************************/
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 ():
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
; }
55 edit_typeset_rep::set_init (hashmap
<string
,tree
> H
) {
56 init
= hashmap
<string
,tree
> (UNINIT
);
61 edit_typeset_rep::add_init (hashmap
<string
,tree
> H
) {
63 ::notify_assign (ttt
, path(), subtree (et
, rp
));
64 notify_change (THE_ENVIRONMENT
);
68 edit_typeset_rep::set_base_name (url name
) {
69 env
->base_file_name
= name
;
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
); }
87 edit_typeset_rep::add_lengths (string l1
, string l2
) {
88 return env
->add_lengths (l1
, l2
); }
91 edit_typeset_rep::multiply_length (double x
, string l
) {
92 return env
->multiply_length (x
, l
); }
95 edit_typeset_rep::is_length (string s
) {
96 return env
->is_length (s
); }
99 edit_typeset_rep::divide_lengths (string l1
, string l2
) {
100 return env
->divide_lengths (l1
, l2
); }
102 /******************************************************************************
103 * Processing preamble
104 ******************************************************************************/
107 use_modules (tree 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
* ")");
117 edit_typeset_rep::typeset_style_use_cache (tree style
) {
119 hashmap
<string
,tree
> H
;
121 SERVER (style_get_cache (style
, H
, t
, ok
));
124 ok
= drd
->set_locals (t
);
127 if (!is_tuple (style
)) FAILED ("tuple expected as style");
128 tree
t (USE_PACKAGE
, A (style
));
131 drd
->heuristic_init (H
);
132 SERVER (style_set_cache (style
, H
, drd
->get_locals ()));
134 use_modules (env
->read (THE_MODULES
));
138 edit_typeset_rep::typeset_preamble () {
139 env
->write_default_env ();
140 typeset_style_use_cache (the_style
);
141 env
->patch_env (init
);
144 drd
->heuristic_init (pre
);
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 ();
157 edit_typeset_rep::drd_update () {
158 typeset_exec_until (tp
);
159 drd
->heuristic_init (cur
[tp
]);
164 edit_typeset_rep::environment_update () {
165 hashmap
<string
,tree
> h
;
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
));
171 ::primitive (ste
, h
);
175 /******************************************************************************
176 * Routines for getting information
177 ******************************************************************************/
180 edit_typeset_rep::typeset_invalidate_env () {
181 cur
= hashmap
<path
,hashmap
<string
,tree
> > (hashmap
<string
,tree
> (UNINIT
));
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)) {
190 cout
<< "TeXmacs] Warning: resynchronizing for path " << p
<< "\n";
193 if (N(cur
[p
])!=0) return;
194 if (N(cur
)>=25) // avoids out of memory in weird cases
195 typeset_invalidate_env ();
197 if (enable_fastenv
) {
198 tree t
= subtree (et
, rp
);
199 path q
= path_up (p
/ rp
);
200 while (!is_nil (q
)) {
202 tree w
= drd
->get_env_child (t
, i
, tree (WITH
));
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]));
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";
220 edit_typeset_rep::defined_at_cursor (string var
) {
221 typeset_exec_until (tp
);
222 return cur
[tp
]->contains (var
);
226 edit_typeset_rep::get_env_value (string var
, path p
) {
227 typeset_exec_until (p
);
229 return is_func (t
, BACKUP
, 2)? t
[0]: t
;
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))),
244 return get_env_value (var
, tp
);
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
);
255 edit_typeset_rep::defined_in_init (string var
) {
256 return init
->contains (var
);
260 edit_typeset_rep::get_init_value (string var
) {
261 if (init
->contains (var
)) {
263 return is_func (t
, BACKUP
, 2)? t
[0]: t
;
265 if (N(pre
)==0) typeset_preamble ();
267 return is_func (t
, BACKUP
, 2)? t
[0]: t
;
271 edit_typeset_rep::get_env_string (string var
) {
272 return as_string (get_env_value (var
));
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
));
291 edit_typeset_rep::get_env_double (string var
) {
292 return as_double (get_env_value (var
));
296 edit_typeset_rep::get_init_double (string var
) {
297 return as_double (get_init_value (var
));
301 edit_typeset_rep::get_env_language () {
302 string mode
= get_env_string (MODE
);
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 ******************************************************************************/
315 simplify_execed (tree t
) {
316 if (is_atomic (t
)) return t
;
320 r
[i
]= simplify_execed (t
[i
]);
321 if (is_func (r
, QUOTE
, 1) && is_atomic (r
[0]))
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
);
340 r
[i
]= expand_references (t
[i
], h
);
345 edit_typeset_rep::exec (tree t
, hashmap
<string
,tree
> H
, bool expand_refs
) {
346 hashmap
<string
,tree
> H2
;
351 t
= expand_references (t
, buf
->ref
);
352 t
= simplify_execed (t
);
353 t
= simplify_correct (t
);
359 edit_typeset_rep::exec_texmacs (tree t
, path p
) {
360 typeset_exec_until (p
);
361 return exec (t
, cur
[p
]);
365 edit_typeset_rep::exec_texmacs (tree t
) {
366 return exec_texmacs (t
, rp
* 0);
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
);
378 //tree r= exec (t, H);
379 //cout << "In: " << t << "\n";
380 //cout << "Out: " << r << "\n";
385 edit_typeset_rep::exec_html (tree t
) {
386 return exec_html (t
, rp
* 0);
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) &&
394 h
->contains (t
[0]->label
))
395 return compound (t
[0]->label
);
400 r
[i
]= value_to_compound (t
[i
], h
);
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
);
415 if (is_document (t
) && is_compound (t
[0], "hide-preamble")) {
418 r
= exec (value_to_compound (r
, P
), H
, false);
419 r
[0]= exec (t
[0], H
, false);
422 else return exec (value_to_compound (t
, P
), H
, false);
426 edit_typeset_rep::exec_latex (tree t
) {
427 return exec_latex (t
, rp
* 0);
431 edit_typeset_rep::texmacs_exec (tree t
) {
432 return ::texmacs_exec (env
, t
);
435 /******************************************************************************
437 ******************************************************************************/
440 edit_typeset_rep::init_style () {
441 notify_change (THE_ENVIRONMENT
);
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
));
450 notify_change (THE_ENVIRONMENT
);
454 edit_typeset_rep::init_add_package (string name
) {
455 int i
, n
= N(the_style
);
457 if (the_style
[i
] == name
)
460 the_style
<< tree (name
);
462 notify_change (THE_ENVIRONMENT
);
466 edit_typeset_rep::init_remove_package (string name
) {
467 int i
, n
= N(the_style
);
468 tree new_style
= tree (TUPLE
);
470 if (the_style
[i
] == name
) {
472 notify_change (THE_ENVIRONMENT
);
474 else new_style
<< the_style
[i
];
475 the_style
= new_style
;
479 edit_typeset_rep::init_env (string var
, tree by
) {
480 if (init (var
) == by
) return;
482 notify_change (THE_ENVIRONMENT
);
486 edit_typeset_rep::init_default (string var
) {
487 if (!init
->contains (var
)) return;
489 notify_change (THE_ENVIRONMENT
);
492 /******************************************************************************
494 ******************************************************************************/
497 edit_typeset_rep::typeset (SI
& x1
, SI
& y1
, SI
& x2
, SI
& y2
) {
498 //time_t t1= texmacs_time ();
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";
510 edit_typeset_rep::typeset_invalidate (path p
) {
512 //cout << "Invalidate " << p << "\n";
513 notify_change (THE_TREE
);
514 ::notify_assign (ttt
, p
/ rp
, subtree (et
, p
));
519 edit_typeset_rep::typeset_invalidate_all () {
520 //cout << "Invalidate all\n";
521 notify_change (THE_ENVIRONMENT
);
523 ::notify_assign (ttt
, path(), subtree (et
, rp
));