Back to index

texmacs  1.0.7.15
bridge.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : bridge.cpp
00004 * DESCRIPTION: Bridge between logical and physically typesetted document
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 "bridge.hpp"
00013 #include "Boxes/construct.hpp"
00014 
00015 bridge bridge_document (typesetter, tree, path);
00016 bridge bridge_surround (typesetter, tree, path);
00017 bridge bridge_hidden (typesetter, tree, path);
00018 bridge bridge_formatting (typesetter, tree, path, string);
00019 bridge bridge_with (typesetter, tree, path);
00020 bridge bridge_rewrite (typesetter, tree, path);
00021 bridge bridge_argument (typesetter, tree, path);
00022 bridge bridge_default (typesetter, tree, path);
00023 bridge bridge_compound (typesetter, tree, path);
00024 bridge bridge_mark (typesetter, tree, path);
00025 bridge bridge_expand_as (typesetter, tree, path);
00026 bridge bridge_eval (typesetter, tree, path);
00027 bridge bridge_auto (typesetter, tree, path, tree, bool);
00028 bridge bridge_locus (typesetter, tree, path);
00029 bridge bridge_ornament (typesetter, tree, path);
00030 bridge bridge_canvas (typesetter, tree, path);
00031 
00032 bridge nil_bridge;
00033 
00034 /******************************************************************************
00035 * Constructors and basic operations
00036 ******************************************************************************/
00037 
00038 bridge_rep::bridge_rep (typesetter ttt2, tree st2, path ip2):
00039   ttt (ttt2), env (ttt->env), st (st2), ip (ip2),
00040   status (CORRUPTED), changes (UNINIT) {}
00041 
00042 static tree inactive_auto
00043   (MACRO, "x", tree (REWRITE_INACTIVE, tree (ARG, "x"), "recurse*"));
00044 static tree error_m
00045   (MACRO, "x", tree (REWRITE_INACTIVE, tree (ARG, "x", "0"), "error*"));
00046 static tree inactive_m
00047   (MACRO, "x", tree (REWRITE_INACTIVE, tree (ARG, "x", "0"), "once*"));
00048 static tree var_inactive_m
00049   (MACRO, "x", tree (REWRITE_INACTIVE, tree (ARG, "x", "0"), "recurse*"));
00050 
00051 bridge
00052 make_inactive_bridge (typesetter ttt, tree st, path ip) {
00053   if (is_document (st))
00054     return bridge_document (ttt, st, ip);
00055   else return bridge_auto (ttt, st, ip, inactive_auto, false);
00056 }
00057 
00058 bridge
00059 make_bridge (typesetter ttt, tree st, path ip) {
00060   // cout << "Make bridge " << st << ", " << ip << LF;
00061   // cout << "Preamble mode= " << ttt->env->preamble << LF;
00062   if (ttt->env->preamble)
00063     return make_inactive_bridge (ttt, st, ip);
00064   switch (L(st)) {
00065   case ERROR:
00066     return bridge_auto (ttt, st, ip, error_m, true);
00067   case DOCUMENT:
00068     return bridge_document (ttt, st, ip);
00069   case SURROUND:
00070     return bridge_surround (ttt, st, ip);
00071   case HIDDEN:
00072     return bridge_hidden (ttt, st, ip);
00073   case DATOMS:
00074     return bridge_formatting (ttt, st, ip, ATOM_DECORATIONS);
00075   case DLINES:
00076     return bridge_formatting (ttt, st, ip, LINE_DECORATIONS);
00077   case DPAGES:
00078     return bridge_formatting (ttt, st, ip, PAGE_DECORATIONS);
00079   case TFORMAT:
00080     return bridge_formatting (ttt, st, ip, CELL_FORMAT);
00081   case WITH:
00082     return bridge_with (ttt, st, ip);
00083   case COMPOUND:
00084     return bridge_compound (ttt, st, ip);
00085   case ARG:
00086     return bridge_argument (ttt, st, ip);
00087   case MARK:
00088     return bridge_mark (ttt, st, ip);
00089   case EXPAND_AS:
00090     return bridge_expand_as (ttt, st, ip);
00091   case EVAL:
00092   case QUASI:
00093     return bridge_eval (ttt, st, ip);
00094   case EXTERN:
00095     return bridge_rewrite (ttt, st, ip);
00096   case INCLUDE:
00097     return bridge_rewrite (ttt, st, ip);
00098   case STYLE_ONLY:
00099   case VAR_STYLE_ONLY:
00100   case ACTIVE:
00101   case VAR_ACTIVE:
00102     return bridge_compound (ttt, st, ip);
00103   case INACTIVE:
00104     return bridge_auto (ttt, st, ip, inactive_m, true);
00105   case VAR_INACTIVE:
00106     return bridge_auto (ttt, st, ip, var_inactive_m, true);
00107   case REWRITE_INACTIVE:
00108     return bridge_rewrite (ttt, st, ip);
00109   case LOCUS:
00110     return bridge_locus (ttt, st, ip);
00111   case HLINK:
00112   case ACTION:
00113     return bridge_compound (ttt, st, ip);
00114   case CANVAS:
00115     return bridge_canvas (ttt, st, ip);
00116   case ORNAMENT:
00117     return bridge_ornament (ttt, st, ip);
00118   default:
00119     if (L(st) < START_EXTENSIONS) return bridge_default (ttt, st, ip);
00120     else return bridge_compound (ttt, st, ip);
00121   }
00122 }
00123 
00124 void
00125 replace_bridge (bridge& br, tree st, path ip) {
00126   bridge new_br= make_bridge (br->ttt, st, ip);
00127   new_br->changes= br->changes;
00128   br= new_br;
00129 }
00130 
00131 void
00132 replace_bridge (bridge& br, path p, tree oldt, tree newt, path ip) {
00133   if (oldt == newt) return;
00134   if (is_atomic (newt) || L(oldt) != L(newt) || N(oldt) != N(newt)) {
00135     if (is_nil (p)) replace_bridge (br, newt, ip);
00136     else br->notify_assign (p, newt);
00137   }
00138   else
00139     for (int i=0; i<N(newt); i++)
00140       replace_bridge (br, p * i, oldt[i], newt[i], ip);
00141 }
00142 
00143 bool
00144 bridge::operator == (bridge item2) {
00145   return rep == item2.rep;
00146 }
00147 
00148 bool
00149 bridge::operator != (bridge item2) {
00150   return rep != item2.rep;
00151 }
00152 
00153 tm_ostream&
00154 operator << (tm_ostream& out, bridge br) {
00155   return out << "bridge [" << br->st << ", " << br->ip << "]";
00156 }
00157 
00158 /******************************************************************************
00159 * Event notification
00160 ******************************************************************************/
00161 
00162 void
00163 bridge_rep::notify_insert (path p, tree u) {
00164   // cout << "Insert " << p << ", " << u << " in " << st << "\n";
00165   path q= path_up (p);
00166   int  l= last_item (p);
00167   tree t= subtree (st, q);
00168   if (is_atomic (t)) {
00169     ASSERT (is_atomic (u), "two atoms expected");
00170     t= t->label (0, l) * u->label * t->label (l, N(t->label));
00171   }
00172   else t= (t (0, l) * u) * t (l, N(t));
00173   notify_assign (q, t);
00174 }
00175 
00176 void
00177 bridge_rep::notify_remove (path p, int nr) {
00178   // cout << "Insert " << p << ", " << nr << " in " << st << "\n";
00179   path q= path_up (p);
00180   int  l= last_item (p);
00181   tree t= subtree (st, q);
00182   if (is_atomic (t)) t= t->label (0, l) * t->label (l+nr, N(t->label));
00183   else t= t (0, l) * t (l+nr, N(t));
00184   notify_assign (q, t);
00185 }
00186 
00187 void
00188 bridge_rep::notify_split (path p) {
00189   // cout << "Split " << p << " in " << st << "\n";
00190   path q  = path_up (p, 2);
00191   int  pos= last_item (path_up (p));
00192   int  l  = last_item (p);
00193   tree t  = subtree (st, q);
00194 
00195   if (is_atomic (t[pos])) {
00196     string s1= t[pos]->label (0, l), s2= t[pos]->label (l, N (t[pos]->label));
00197     notify_insert (q * pos, tree (L(t), s1));
00198     notify_assign (q * (pos+1), s2);
00199   }
00200   else {
00201     tree t1= t[pos] (0, l), t2= t[pos] (l, N(t[pos]));
00202     notify_insert (q * pos, tree (L(t), t1));
00203     notify_assign (q * (pos+1), t2);
00204   }
00205 }
00206 
00207 void
00208 bridge_rep::notify_join (path p) {
00209   // cout << "Join " << p << " in " << st << "\n";
00210   path q  = path_up (p);
00211   int  pos= last_item (p);
00212   tree t  = subtree (st, q);
00213 
00214   if (is_atomic (t[pos]) && is_atomic (t[pos+1])) {
00215     string j= t[pos]->label * t[pos+1]->label;
00216     notify_remove (q * pos, 1);
00217     notify_assign (q * pos, j);
00218   }
00219   else {
00220     tree j= t[pos] * t[pos+1];
00221     notify_remove (q * pos, 1);
00222     notify_assign (q * pos, j);
00223   }
00224 }
00225 
00226 /******************************************************************************
00227 * Getting environment variables and typesetting
00228 ******************************************************************************/
00229 
00230 void
00231 bridge_rep::my_clean_links () {
00232   link_env= link_repository (true);
00233 }
00234 
00235 void
00236 bridge_rep::my_exec_until (path p) {
00237   env->exec_until (st, p);
00238 }
00239 
00240 bool
00241 bridge_rep::my_typeset_will_be_complete () {
00242   return (status & VALID_MASK) == CORRUPTED;
00243 }
00244 
00245 void
00246 bridge_rep::my_typeset (int desired_status) {
00247   if ((desired_status & WANTED_MASK) == WANTED_PARAGRAPH)
00248     ttt->insert_paragraph (st, ip);
00249   if ((desired_status & WANTED_MASK) == WANTED_PARUNIT)
00250     ttt->insert_parunit (st, ip);
00251 }
00252 
00253 void
00254 bridge_rep::exec_until (path p, bool skip_flag) {
00255   // This virtual routine is redefined in bridge_auto in order to
00256   // treat cursor positions on the border in a special way depending
00257   // on skip_flag
00258 
00259   (void) skip_flag;
00260   // cout << "Exec until " << p << " in " << st << "\n";
00261   if ((status & VALID_MASK) != PROCESSED) {
00262     // cout << "  Re-execute until\n";
00263     env->exec_until (st, p);
00264   }
00265   else if (p == path (right_index (st))) {
00266     // cout << "  Patch env\n";
00267     env->patch_env (changes);
00268   }
00269   else if (p != path (0)) {
00270     // cout << "  My execute until\n";
00271     my_exec_until (p);
00272   }
00273   // cout << "  Done\n";
00274 }
00275 
00276 extern tree the_et;
00277 
00278 void
00279 bridge_rep::typeset (int desired_status) {
00280   // FIXME: this dirty hack ensures a perfect coherence between
00281   // the bridge and the edit tree at the typesetting stage.
00282   // This should not be necessary, but we use because the ip_observers
00283   // may become wrong otherwise.
00284   if (is_accessible (ip))
00285     st= subtree (the_et, reverse (ip));
00286   if (!is_accessible (ip)) {
00287     path ip2= obtain_ip (st);
00288     if (ip2 != path (DETACHED))
00289       ip= ip2;
00290   }
00291 
00292   //cout << "Typesetting " << st << ", " << desired_status << LF << INDENT;
00293   if ((status==desired_status) && (N(ttt->old_patch)==0)) {
00294     //cout << "cached" << LF;
00295     env->monitored_patch_env (changes);
00296     // cout << "changes       = " << changes << LF;
00297   }
00298   else {
00299     // cout << "Typesetting " << st << ", " << desired_status << LF << INDENT;
00300     //cout << "recomputing" << LF;
00301     hashmap<string,tree> prev_back (UNINIT);
00302     my_clean_links ();
00303     link_repository old_link_env= env->link_env;
00304     env->link_env= link_env;
00305     ttt->local_start (l, sb);
00306     env->local_start (prev_back);
00307     if (env->hl_lan != 0) env->lan->highlight (st);
00308     my_typeset (desired_status);
00309     env->local_update (ttt->old_patch, changes);
00310     env->local_end (prev_back);
00311     ttt->local_end (l, sb);
00312     env->link_env= old_link_env;
00313     status= desired_status;
00314     // cout << "old_patch     = " << ttt->old_patch << LF;
00315     // cout << "changes       = " << changes << LF;
00316     // cout << UNINDENT << "Typesetted " << st << ", " << desired_status << LF;
00317   }
00318   //cout << UNINDENT << "Typesetted " << st << ", " << desired_status << LF;
00319 
00320   // ttt->insert_stack (l, sb);
00321   //if (N(l) == 0); else
00322   if (ttt->paper || (N(l) <= 1)) ttt->insert_stack (l, sb);
00323   else {
00324     bool flag= false;
00325     int i, n= N(l);
00326     for (i=0; i<n; i++)
00327       flag= flag || (N (l[i]->fl) != 0) || (l[i]->nr_cols > 1);
00328     if (flag) ttt->insert_stack (l, sb);
00329     else {
00330       int first=-1, last=-1;
00331       array<box> bs;
00332       array<SI>  spc;
00333       for (i=0; i<n; i++)
00334        if (l[i]->type != PAGE_CONTROL_ITEM) {
00335          if (first == -1 && l[i]->type == PAGE_LINE_ITEM) first= N(bs);
00336          bs  << l[i]->b;
00337          spc << l[i]->spc->def;
00338          last= i;
00339        }
00340       box lb= stack_box (path (ip), bs, spc);
00341       if (first != -1) lb= move_box (path (ip), lb, 0, bs[first]->y2);
00342       array<page_item> new_l (1);
00343       new_l[0]= page_item (lb);
00344       new_l[0]->spc= l[last]->spc;
00345       ttt->insert_stack (new_l, sb);
00346     }
00347   }
00348 
00349   //cout << "l   = " << l << LF;
00350   //cout << "sb  = " << sb << LF;
00351   //cout << "l   = " << ttt->l << LF;
00352   //cout << "a   = " << ttt->a << LF;
00353   //cout << "b   = " << ttt->b << LF;
00354 }