Back to index

texmacs  1.0.7.15
edit_typeset.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : typeset.cpp
00004 * DESCRIPTION: typeset the tree being edited
00005 * COPYRIGHT  : (C) 1999  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "edit_typeset.hpp"
00013 #include "tm_buffer.hpp"
00014 #include "convert.hpp"
00015 #include "file.hpp"
00016 #include "analyze.hpp"
00017 #include "timer.hpp"
00018 #include "Bridge/impl_typesetter.hpp"
00019 #include "new_style.hpp"
00020 #ifdef EXPERIMENTAL
00021 #include "../../Style/Environment/std_environment.hpp"
00022 #endif // EXPERIMENTAL
00023 
00024 //box empty_box (path ip, int x1=0, int y1=0, int x2=0, int y2=0);
00025 bool enable_fastenv= false;
00026 
00027 /******************************************************************************
00028 * Contructors, destructors and notification of modifications
00029 ******************************************************************************/
00030 
00031 static bool
00032 is_aux (url u) {
00033   if (!is_atomic (u->t)) return false;
00034   string s= u->t->label;
00035   return starts (s, "* ") && ends (s, " *");
00036 }
00037 
00038 edit_typeset_rep::edit_typeset_rep ():
00039   the_style (TUPLE),
00040   cur (hashmap<string,tree> (UNINIT)),
00041   pre (UNINIT), init (UNINIT), fin (UNINIT),
00042   env (drd, is_aux (buf->buf->name)? buf->buf->extra: buf->buf->name,
00043        buf->data->ref, (buf->prj==NULL? buf->data->ref: buf->prj->data->ref),
00044        buf->data->aux, (buf->prj==NULL? buf->data->aux: buf->prj->data->aux)),
00045   ttt (new_typesetter (env, subtree (et, rp), reverse (rp))) {}
00046 edit_typeset_rep::~edit_typeset_rep () { delete_typesetter (ttt); }
00047 
00048 void
00049 edit_typeset_rep::set_data (new_data data) {
00050   set_style (data->style);
00051   set_init  (data->init);
00052   set_fin   (data->fin);
00053   notify_page_change ();
00054   add_init (data->init);
00055   notify_change (THE_DECORATIONS);
00056   typeset_invalidate_env ();
00057 }
00058 
00059 void
00060 edit_typeset_rep::get_data (new_data& data) {
00061   data->style= get_style ();
00062   data->init = get_init ();
00063   data->fin  = get_fin ();
00064 }
00065 
00066 typesetter edit_typeset_rep::get_typesetter () { return ttt; }
00067 tree edit_typeset_rep::get_style () { return the_style; }
00068 void edit_typeset_rep::set_style (tree t) { the_style= copy (t); }
00069 hashmap<string,tree> edit_typeset_rep::get_init () { return init; }
00070 hashmap<string,tree> edit_typeset_rep::get_fin () { return fin; }
00071 void edit_typeset_rep::set_fin (hashmap<string,tree> H) { fin= H; }
00072 
00073 void
00074 edit_typeset_rep::set_init (hashmap<string,tree> H) {
00075   init= hashmap<string,tree> (UNINIT);
00076   add_init (H);
00077 }
00078 
00079 void
00080 edit_typeset_rep::add_init (hashmap<string,tree> H) {
00081   init->join (H);
00082   ::notify_assign (ttt, path(), subtree (et, rp));
00083   notify_change (THE_ENVIRONMENT);
00084 }
00085 
00086 void
00087 edit_typeset_rep::set_base_name (url name) {
00088   env->base_file_name= name;
00089 }
00090 
00091 void
00092 edit_typeset_rep::clear_local_info () {
00093   buf->data->ref= hashmap<string,tree> ();
00094   buf->data->aux= hashmap<string,tree> ();
00095 }
00096 
00097 /******************************************************************************
00098 * Miscellaneous routines for lengths arithmetic (should be elsewhere)
00099 ******************************************************************************/
00100 
00101 SI
00102 edit_typeset_rep::as_length (string l) {
00103   return env->as_length (l); }
00104 
00105 string
00106 edit_typeset_rep::add_lengths (string l1, string l2) {
00107   return env->add_lengths (l1, l2); }
00108 
00109 string
00110 edit_typeset_rep::multiply_length (double x, string l) {
00111   return env->multiply_length (x, l); }
00112 
00113 bool
00114 edit_typeset_rep::is_length (string s) {
00115   return env->is_length (s); }
00116 
00117 double
00118 edit_typeset_rep::divide_lengths (string l1, string l2) {
00119   return env->divide_lengths (l1, l2); }
00120 
00121 /******************************************************************************
00122 * Processing preamble
00123 ******************************************************************************/
00124 
00125 void
00126 use_modules (tree t) {
00127   if (is_tuple (t))
00128     for (int i=0; i<N(t); i++) {
00129       string s= as_string (t[i]);
00130       if (starts (s, "(")) eval ("(use-modules " * s * ")");
00131       else if (s != "") eval ("(plugin-initialize '" * s * ")");
00132     }
00133 }
00134 
00135 void
00136 edit_typeset_rep::typeset_style_use_cache (tree style) {
00137   //cout << "Typesetting style using cache " << style << LF;
00138   bool ok;
00139   hashmap<string,tree> H;
00140   tree t;
00141   style_get_cache (style, H, t, ok);
00142   if (ok) {
00143     env->patch_env (H);
00144     ok= drd->set_locals (t);
00145     drd->set_environment (H);
00146   }
00147   if (!ok) {
00148     //cout << "Typeset without cache " << style << LF;
00149     if (!is_tuple (style)) FAILED ("tuple expected as style");
00150     tree t (USE_PACKAGE, A (style));
00151     env->exec (t);
00152     env->read_env (H);
00153     drd->heuristic_init (H);
00154     style_set_cache (style, H, drd->get_locals ());
00155   }
00156   use_modules (env->read (THE_MODULES));
00157 }
00158 
00159 void
00160 edit_typeset_rep::typeset_preamble () {
00161   env->write_default_env ();
00162   typeset_style_use_cache (the_style);
00163   env->patch_env (init);
00164   env->update ();
00165   env->read_env (pre);
00166   drd->heuristic_init (pre);
00167 }
00168 
00169 void
00170 edit_typeset_rep::typeset_prepare () {
00171   env->read_only= buf->buf->read_only;
00172   env->write_default_env ();
00173   env->patch_env (pre);
00174   env->style_init_env ();
00175   env->update ();
00176 }
00177 
00178 void
00179 edit_typeset_rep::drd_update () {
00180   typeset_exec_until (tp);
00181   drd->heuristic_init (cur[tp]);
00182 }
00183 
00184 #ifdef EXPERIMENTAL
00185 void
00186 edit_typeset_rep::environment_update () {
00187   hashmap<string,tree> h;
00188   typeset_prepare ();
00189   env->assign ("base-file-name", as_string (env->base_file_name));
00190   env->assign ("cur-file-name", as_string (env->cur_file_name));
00191   env->assign ("secure", bool_as_tree (env->secure));
00192   env->read_env (h);
00193   ::primitive (ste, h);
00194 }
00195 #endif
00196 
00197 /******************************************************************************
00198 * Routines for getting information
00199 ******************************************************************************/
00200 
00201 void
00202 edit_typeset_rep::typeset_invalidate_env () {
00203   cur= hashmap<path,hashmap<string,tree> > (hashmap<string,tree> (UNINIT));
00204 }
00205 
00206 static void
00207 restricted_exec (edit_env env, tree t, int end) {
00208   if (is_func (t, ASSIGN, 2) && end == 2)
00209     env->exec (t);
00210   else if (is_document (t) || is_concat (t))
00211     for (int i=0; i < min (end, 10); i++)
00212       restricted_exec (env, t[i], arity (t[i]));
00213   else if (is_compound (t, "hide-preamble", 1) ||
00214            is_compound (t, "show-preamble", 1))
00215     env->exec (t[0]);
00216 }
00217 
00218 void
00219 edit_typeset_rep::typeset_exec_until (path p) {
00220   //time_t t1= texmacs_time ();
00221   if (has_changed (THE_TREE + THE_ENVIRONMENT))
00222     if (p != correct_cursor (et, rp * 0)) {
00223       if (DEBUG_STD)
00224        cout << "TeXmacs] Warning: resynchronizing for path " << p << "\n";
00225       // apply_changes ();
00226     }
00227   if (p == tp && inside_graphics (true) && p != closest_inside (et, p)) {
00228     //cout << "TeXmacs] Warning: corrected cursor\n";
00229     tp= closest_inside (et, tp);
00230     p = tp;
00231   }
00232 
00233   if (N(cur[p])!=0) return;
00234   if (N(cur)>=25) // avoids out of memory in weird cases
00235     typeset_invalidate_env ();
00236   typeset_prepare ();
00237   if (enable_fastenv) {
00238     if (!(rp < p)) {
00239       cerr << "TeXmacs] erroneous path " << p << "\n";
00240       FAILED ("invalid typesetting path");
00241     }
00242     tree t= subtree (et, rp);
00243     path q= path_up (p / rp);
00244     while (!is_nil (q)) {
00245       int i= q->item;
00246       restricted_exec (env, t, i);
00247       tree w= drd->get_env_child (t, i, tree (ATTR));
00248       if (w == "") break;
00249       //cout << "t= " << t << "\n";
00250       //cout << "i= " << i << "\n";
00251       //cout << "w= " << w << "\n";
00252       for (int j=0; j<N(w); j+=2) {
00253        //cout << w[j] << " := " << env->exec (w[j+1]) << "\n";
00254        env->write (w[j]->label, env->exec (w[j+1]));
00255       }
00256       t= t[i];
00257       q= q->next;
00258     }
00259     if (env->read (PREAMBLE) == "true")
00260       env->write (MODE, "src");
00261   }
00262   else exec_until (ttt, p / rp);
00263   env->read_env (cur (p));
00264   //time_t t2= texmacs_time ();
00265   //if (t2 - t1 >= 10) cout << "typeset_exec_until took " << t2-t1 << "ms\n";
00266 }
00267 
00268 bool
00269 edit_typeset_rep::defined_at_cursor (string var) {
00270   typeset_exec_until (tp);
00271   return cur[tp]->contains (var);
00272 }
00273 
00274 tree
00275 edit_typeset_rep::get_env_value (string var, path p) {
00276   typeset_exec_until (p);
00277   tree t= cur[p][var];
00278   return is_func (t, BACKUP, 2)? t[0]: t;
00279 }
00280 
00281 tree
00282 edit_typeset_rep::get_env_value (string var) {
00283  /* FIXME: tp is wrong (and consequently, crashes TeXmacs)
00284   *   when we call this routine from inside the code which
00285   *   is triggered by a button, for example.
00286   *
00287   * Test: fire TeXmacs, then open a new Graphics, then click
00288   *   on the icon for going in spline mode. Then it crashes,
00289   *   because we call (get-env-tree) from inside the Scheme.
00290   *   If we call (get-env-tree-at ... (cDr (cursor-path))),
00291   *   then it works.
00292   */
00293   return get_env_value (var, tp);
00294 }
00295 
00296 bool
00297 edit_typeset_rep::defined_at_init (string var) {
00298   if (init->contains (var)) return true;
00299   if (N(pre)==0) typeset_preamble ();
00300   return pre->contains (var);
00301 }
00302 
00303 bool
00304 edit_typeset_rep::defined_in_init (string var) {
00305   return init->contains (var);
00306 }
00307 
00308 tree
00309 edit_typeset_rep::get_init_value (string var) {
00310   if (init->contains (var)) {
00311     tree t= init [var];
00312     return is_func (t, BACKUP, 2)? t[0]: t;
00313   }
00314   if (N(pre)==0) typeset_preamble ();
00315   tree t= pre [var];
00316   return is_func (t, BACKUP, 2)? t[0]: t;
00317 }
00318 
00319 string
00320 edit_typeset_rep::get_env_string (string var) {
00321   return as_string (get_env_value (var));
00322 }
00323 
00324 string
00325 edit_typeset_rep::get_init_string (string var) {
00326   return as_string (get_init_value (var));
00327 }
00328 
00329 int
00330 edit_typeset_rep::get_env_int (string var) {
00331   return as_int (get_env_value (var));
00332 }
00333 
00334 int
00335 edit_typeset_rep::get_init_int (string var) {
00336   return as_int (get_init_value (var));
00337 }
00338 
00339 double
00340 edit_typeset_rep::get_env_double (string var) {
00341   return as_double (get_env_value (var));
00342 }
00343 
00344 double
00345 edit_typeset_rep::get_init_double (string var) {
00346   return as_double (get_init_value (var));
00347 }
00348 
00349 language
00350 edit_typeset_rep::get_env_language () {
00351   string mode= get_env_string (MODE);
00352   if (mode == "text")
00353     return text_language (get_env_string (LANGUAGE));
00354   else if (mode == "math")
00355     return math_language (get_env_string (MATH_LANGUAGE));
00356   else return prog_language (get_env_string (PROG_LANGUAGE));
00357 }
00358 
00359 /******************************************************************************
00360 * Execution without typesetting
00361 ******************************************************************************/
00362 
00363 static tree
00364 simplify_execed (tree t) {
00365   if (is_atomic (t)) return t;
00366   int i, n= N(t);
00367   tree r (t, n);
00368   for (i=0; i<n; i++)
00369     r[i]= simplify_execed (t[i]);
00370   if (is_func (r, QUOTE, 1) && is_atomic (r[0]))
00371     return r[0];
00372   else return r;
00373 }
00374 
00375 static tree
00376 expand_references (tree t, hashmap<string,tree> h) {
00377   if (is_atomic (t)) return t;
00378   if (is_func (t, REFERENCE, 1) || is_func (t, PAGEREF)) {
00379     string ref= as_string (simplify_execed (t[0]));
00380     if (h->contains (ref)) {
00381       int which= is_func (t, REFERENCE, 1)? 0: 1;
00382       return tree (HLINK, copy (h[ref][which]), "#" * ref);
00383     }
00384     return tree (HLINK, "?", "#" * ref);
00385   }
00386   int i, n= N(t);
00387   tree r (t, n);
00388   for (i=0; i<n; i++)
00389     r[i]= expand_references (t[i], h);
00390   return r;  
00391 }
00392 
00393 tree
00394 edit_typeset_rep::exec (tree t, hashmap<string,tree> H, bool expand_refs) {
00395   hashmap<string,tree> H2;
00396   env->read_env (H2);
00397   env->write_env (H);
00398   t= env->exec (t);
00399   if (expand_refs)
00400     t= expand_references (t, buf->data->ref);
00401   t= simplify_execed (t);
00402   t= simplify_correct (t);
00403   env->write_env (H2);
00404   return t;
00405 }
00406 
00407 tree
00408 edit_typeset_rep::exec_texmacs (tree t, path p) {
00409   typeset_exec_until (p);
00410   return exec (t, cur[p]);
00411 }
00412 
00413 tree
00414 edit_typeset_rep::exec_texmacs (tree t) {
00415   return exec_texmacs (t, rp * 0);
00416 }
00417 
00418 tree
00419 edit_typeset_rep::exec_verbatim (tree t, path p) {
00420   typeset_exec_until (p);
00421   hashmap<string,tree> H= copy (cur[p]);
00422   H ("TeXmacs")= tree (MACRO, "TeXmacs");
00423   H ("LaTeX")= tree (MACRO, "LaTeX");
00424   H ("TeX")= tree (MACRO, "TeX");
00425   return exec (t, H);
00426 }
00427 
00428 tree
00429 edit_typeset_rep::exec_verbatim (tree t) {
00430   return exec_verbatim (t, rp * 0);
00431 }
00432 
00433 tree
00434 edit_typeset_rep::exec_html (tree t, path p) {
00435   if (p == (rp * 0)) typeset_preamble ();
00436   typeset_exec_until (p);
00437   hashmap<string,tree> H= copy (cur[p]);
00438   tree patch= as_tree (eval ("(stree->tree (tmhtml-env-patch))"));
00439   hashmap<string,tree> P (UNINIT, patch);
00440   H->join (P);
00441   tree w (WITH);
00442   if (H->contains ("html-title"))
00443     w << string ("html-title") << H["html-title"];
00444   if (H->contains ("html-css"))
00445     w << string ("html-css") << H["html-css"];
00446   if (H->contains ("html-head-javascript"))
00447     w << string ("html-head-javascript") << H["html-head-javascript"];
00448   if (H->contains ("html-head-javascript-src"))
00449     w << string ("html-head-javascript-src") << H["html-head-javascript-src"];
00450   if (N(w) == 0) return exec (t, H);
00451   else {
00452     w << t;
00453     return exec (w, H);
00454   }
00455   //tree r= exec (t, H);
00456   //cout << "In: " << t << "\n";
00457   //cout << "Out: " << r << "\n";
00458   //return r;
00459 }
00460 
00461 tree
00462 edit_typeset_rep::exec_html (tree t) {
00463   return exec_html (t, rp * 0);
00464 }
00465 
00466 static tree
00467 value_to_compound (tree t, hashmap<string,tree> h) {
00468   if (is_atomic (t)) return t;
00469   else if (is_func (t, VALUE, 1) &&
00470           is_atomic (t[0]) &&
00471           h->contains (t[0]->label))
00472     return compound (t[0]->label);
00473   else {
00474     int i, n= N(t);
00475     tree r (t, n);
00476     for (i=0; i<n; i++)
00477       r[i]= value_to_compound (t[i], h);
00478     return r;
00479   }
00480 }
00481 
00482 tree
00483 edit_typeset_rep::exec_latex (tree t, path p) {
00484   string pref= "texmacs->latex:expand-macros";
00485   if (as_string (call ("get-preference", pref)) != "on") return t;
00486   if (p == (rp * 0)) typeset_preamble ();
00487   typeset_exec_until (p);
00488   hashmap<string,tree> H= copy (cur[p]);
00489   tree patch= as_tree (call ("stree->tree", call ("tmtex-env-patch", t)));
00490   hashmap<string,tree> P (UNINIT, patch);
00491   H->join (P);
00492   if (is_document (t) && is_compound (t[0], "hide-preamble")) {
00493     tree r= copy (t);
00494     r[0]= "";
00495     r= exec (value_to_compound (r, P), H, false);
00496     r[0]= exec (t[0], H, false);
00497     return r;
00498   }
00499   else return exec (value_to_compound (t, P), H, false);
00500 }
00501 
00502 tree
00503 edit_typeset_rep::exec_latex (tree t) {
00504   return exec_latex (t, rp * 0);
00505 }
00506 
00507 tree
00508 edit_typeset_rep::texmacs_exec (tree t) {
00509   return ::texmacs_exec (env, t);
00510 }
00511 
00512 /******************************************************************************
00513 * Initialization
00514 ******************************************************************************/
00515 
00516 void
00517 edit_typeset_rep::init_style () {
00518   notify_change (THE_ENVIRONMENT);
00519 }
00520 
00521 void
00522 edit_typeset_rep::init_style (string name) {
00523   if ((name == "none") || (name == "") || (name == "style")) the_style= TUPLE;
00524   else if (arity (the_style) == 0) the_style= tree (TUPLE, name);
00525   else the_style= tree (TUPLE, name) * the_style (1, N(the_style));
00526   require_save ();
00527   notify_change (THE_ENVIRONMENT);
00528 }
00529 
00530 void
00531 edit_typeset_rep::init_add_package (string name) {
00532   int i, n= N(the_style);
00533   for (i=0; i<n; i++)
00534     if (the_style[i] == name)
00535       return;
00536 
00537   the_style << tree (name);
00538   require_save ();
00539   notify_change (THE_ENVIRONMENT);
00540 }
00541 
00542 void
00543 edit_typeset_rep::init_remove_package (string name) {
00544   int i, n= N(the_style);
00545   tree new_style= tree (TUPLE);
00546   for (i=0; i<n; i++)
00547     if (the_style[i] == name) {
00548       require_save ();
00549       notify_change (THE_ENVIRONMENT);
00550     }
00551     else new_style << the_style[i];
00552   the_style= new_style;
00553 }
00554 
00555 void
00556 edit_typeset_rep::init_env (string var, tree by) {
00557   if (init (var) == by) return;
00558   init (var)= by;
00559   require_save();
00560   notify_change (THE_ENVIRONMENT);
00561 }
00562 
00563 void
00564 edit_typeset_rep::init_default (string var) {
00565   if (!init->contains (var)) return;
00566   init->reset (var);
00567   notify_change (THE_ENVIRONMENT);
00568 }
00569 
00570 /******************************************************************************
00571 * Actual typesetting
00572 ******************************************************************************/
00573 
00574 void
00575 edit_typeset_rep::typeset (SI& x1, SI& y1, SI& x2, SI& y2) {
00576   //time_t t1= texmacs_time ();
00577   typeset_prepare ();
00578   eb= empty_box (reverse (rp));
00579   // saves memory, also necessary for change_log update
00580   bench_start ("typeset");
00581   eb= ::typeset (ttt, x1, y1, x2, y2);
00582   bench_end ("typeset");
00583   //time_t t2= texmacs_time ();
00584   //if (t2 - t1 >= 10) cout << "typeset took " << t2-t1 << "ms\n";
00585 }
00586 
00587 void
00588 edit_typeset_rep::typeset_invalidate (path p) {
00589   if (rp <= p) {
00590     //cout << "Invalidate " << p << "\n";
00591     notify_change (THE_TREE);
00592     ::notify_assign (ttt, p / rp, subtree (et, p));
00593   }
00594 }
00595 
00596 void
00597 edit_typeset_rep::typeset_invalidate_all () {
00598   //cout << "Invalidate all\n";
00599   notify_change (THE_ENVIRONMENT);
00600   typeset_preamble ();
00601   ::notify_assign (ttt, path(), subtree (et, rp));
00602 }