Back to index

texmacs  1.0.7.15
edit_process.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : edit_process.cpp
00004 * DESCRIPTION: incorporate automatically generated data into text
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 "Process/edit_process.hpp"
00013 #include "analyze.hpp"
00014 #include "tm_buffer.hpp"
00015 #include "merge_sort.hpp"
00016 #include "Bibtex/bibtex.hpp"
00017 #include "Bibtex/bibtex_functions.hpp"
00018 #include "file.hpp"
00019 #include "convert.hpp"
00020 #include "scheme.hpp"
00021 
00022 /******************************************************************************
00023 * Constructors and destructors
00024 ******************************************************************************/
00025 
00026 edit_process_rep::edit_process_rep () {}
00027 edit_process_rep::~edit_process_rep () {}
00028 
00029 /******************************************************************************
00030 * Automatically generate a bibliography
00031 ******************************************************************************/
00032 
00033 url
00034 find_bib_file (url base, string fname, string suffix= ".bib") {
00035   if (!ends (fname, suffix)) fname= fname * suffix;
00036   url bibf (fname);
00037   if (exists (bibf))
00038     return bibf;
00039   if (exists (relative (base, bibf)))
00040     return relative (base, bibf);
00041   if (exists (expand (relative (base, url_ancestor () * bibf))))
00042     return resolve (expand (relative (base, url_ancestor () * bibf)));
00043   return url_none ();
00044 }
00045 
00046 void
00047 edit_process_rep::generate_bibliography (
00048   string bib, string style, string fname)
00049 {
00050   if (DEBUG_AUTO)
00051     cout << "TeXmacs] Generating bibliography"
00052         << " [" << bib << ", " << style << ", " << fname << "]\n";
00053   tree bib_t= buf->data->aux[bib];
00054   if (buf->prj != NULL) bib_t= buf->prj->data->aux[bib];
00055   tree t;
00056   url bib_file= find_bib_file (buf->buf->name, fname);
00057   if (is_none (bib_file)) {
00058     url bbl_file= find_bib_file (buf->buf->name, fname, ".bbl");
00059     if (is_none (bbl_file)) {
00060       set_message ("Could not find bibliography file", "compile bibliography");
00061       return;
00062     }
00063     t= bibtex_load_bbl (bib, bbl_file);
00064   }
00065   //cout << fname << " -> " << concretize (bib_file) << "\n";
00066   else {
00067     if (!bibtex_present () && !starts (style, "tm-")) {
00068       if (style == "alpha") style= "tm-alpha";
00069       else if (style == "acm") style= "tm-acm";
00070       else if (style == "ieeetr") style= "tm-ieeetr";
00071       else if (style == "siam") style= "tm-siam";
00072       else style= "tm-plain";
00073     }
00074     if (starts (style, "tm-")) {
00075       string sbib;
00076       load_string (bib_file, sbib, false);
00077       tree te= bib_entries (parse_bib (sbib), bib_t);
00078       object ot= tree_to_stree (te);
00079       eval ("(use-modules (bibtex " * style (3, N(style)) * "))");
00080       t= stree_to_tree (call (string ("bibstyle"), style (3, N(style)), ot));
00081     }
00082     else {
00083       string dir= concretize (head (buf->buf->name));
00084       t= bibtex_run (bib, style, bib_file, bib_t);
00085     }
00086   }
00087   if (is_atomic (t) && starts (t->label, "Error:"))
00088     set_message (t->label, "compile bibliography");
00089   else if (is_compound (t) && N(t) > 0) insert_tree (t);
00090 }
00091 
00092 /******************************************************************************
00093 * Automatically generate table of contents
00094 ******************************************************************************/
00095 
00096 void
00097 edit_process_rep::generate_table_of_contents (string toc) {
00098   if (DEBUG_AUTO)
00099     cout << "TeXmacs] Generating table of contents [" << toc << "]\n";
00100   tree toc_t= buf->data->aux[toc];
00101   if (buf->prj != NULL) toc_t= copy (buf->prj->data->aux[toc]);
00102   if (N(toc_t)>0) insert_tree (toc_t);
00103 }
00104 
00105 /******************************************************************************
00106 * Automatically generate an index
00107 ******************************************************************************/
00108 
00109 static hashmap<string,tree> followup (TUPLE);
00110 
00111 static string
00112 index_name_sub (tree t, bool all) {
00113   if (is_atomic (t)) {
00114     string s= t->label, r;
00115     int i, n= N(s);
00116     for (i=0; i<n; i++)
00117       if (is_iso_alpha (s[i]) || is_digit (s[i]) || (s[i] == ' ') ||
00118          (all && (s[i] >= ' '))) r << s[i];
00119     return r;
00120   }
00121   else if (is_concat (t)) {
00122     string r;
00123     int i, n= N(t);
00124     for (i=0; i<n; i++)
00125       r << index_name_sub (t[i], all);
00126     return r;
00127   }
00128   else if (is_tuple (t)) {
00129     string r;
00130     int i, j, n= N(t);
00131     for (i=0; i<n; i++) {
00132       if (i!=0) r << "\t";
00133       string s= index_name_sub (t[i], false);
00134       if (s == "") s= index_name_sub (t[i], true);
00135       tree u= copy (followup [s]);
00136       for (j=0; j<N(u); j++)
00137        if (u[j] == t[i]) break;
00138       if (j == N(u)) { u << t[i]; followup (s)= u; }
00139       r << s;
00140       if (j != 0) r << "\n" << as_string (j);
00141     }
00142     return r;
00143   }
00144   else if (all && is_func (t, WITH))
00145     return index_name_sub (t[N(t)-1], all);
00146   else return "";
00147 }
00148 
00149 static string
00150 index_name (tree t) {
00151   if (is_func (t, TUPLE, 2)) t= t[0];
00152   else if (is_func (t, TUPLE, 3)) t= t[0];
00153   else if (is_func (t, TUPLE, 5)) {
00154     if (t[0] == "") t= t[3];
00155     else t= t[0];
00156   }
00157   if (!is_tuple (t)) t= tuple (t);
00158   return locase_all (index_name_sub (t, false));
00159 }
00160 
00161 static tree
00162 index_value (tree t) {
00163   if (is_func (t, TUPLE, 2)) return t;
00164   else if (is_func (t, TUPLE, 3)) return tuple (t[2]);
00165   else if (is_func (t, TUPLE, 5)) {
00166     tree l= t[3], r= t[4];
00167     if (!is_tuple (l)) l= tuple (l);
00168     if (t[1] == "strong") r= compound ("strong", r);
00169     if (t[2] != "") r= tuple ("range", t[2], r);
00170     return tuple (l, r);
00171   }
00172   return "";
00173 }
00174 
00175 static void
00176 insert_recursively (array<string>& a, string s, hashmap<string,tree>& h) {
00177   // cout << "Insert recursively \t" << s << "\n";
00178   int i= search_backwards ("\t", s);
00179   if (i != -1) {
00180     string r= s (0, i);
00181     if (!h->contains (r)) {
00182       tree u= h[s][0][0];
00183       h (r)= tuple (tuple (copy (u (0, N(u)-1)), ""));
00184       insert_recursively (a, s (0, i), h);
00185     }
00186   }
00187   a << s;
00188 }
00189 
00190 static void
00191 make_entry (tree& D, tree t) {
00192   // cout << "Make entry " << t << "\n";
00193   int i, j, n= N(t);
00194   for (i=0; i<n; i++)
00195     if (is_func (t[i], TUPLE, 1)) {
00196       bool flag= true;
00197       for (j=0; j<n; j++)
00198        if (is_func (t[j], TUPLE, 2) && (t[i][0] == t[j][0]))
00199          flag= false;
00200       if (flag) D << t[i][0];
00201     }
00202 
00203   for (i=0; i<n; i++)
00204     if (is_func (t[i], TUPLE, 2) && is_tuple (t[i][1], "range", 2)) {
00205       bool flag= true;
00206       for (j=i+1; j<n; j++)
00207        if (is_func (t[j], TUPLE, 2) && is_tuple (t[j][1], "range", 2))
00208          if ((t[i][0] == t[j][0]) && (t[i][1][1] == t[j][1][1])) {
00209            t[i][1]= tree (CONCAT, t[i][1][2], "--", t[j][1][2]);
00210            t[j]= "";
00211            flag= false;
00212            break;
00213          }
00214       if (flag) t[i][1]= tree (CONCAT, t[i][1][2], "--?");
00215     }
00216 
00217   hashmap<tree,tree> h ("");
00218   for (i=0; i<n; i++)
00219     if (is_func (t[i], TUPLE, 2)) {
00220       tree l= t[i][0], r= t[i][1];
00221       if (!h->contains (l)) h (l)= r;
00222       else {
00223        tree rr= h[l];
00224        if (rr == "") rr= r;
00225        else if (r != "") {
00226          if (!is_concat (rr)) rr= tree (CONCAT, rr);
00227          rr << ", " << r;
00228        }
00229        h (l)= rr;
00230       }
00231     }
00232 
00233   for (i=0; i<n; i++)
00234     if (is_func (t[i], TUPLE, 2)) {
00235       tree l= t[i][0];
00236       if (h->contains (l)) {
00237        int k= N(l);
00238        tree e= compound ("index-" * as_string (k), copy (l[k-1]), h[l]);
00239        if (h[l] == "")
00240          e= compound ("index-" * as_string (k) * "*", copy (l[k-1]));
00241        D << e;
00242        h->reset (l);
00243       }
00244     }
00245 }
00246 
00247 void
00248 edit_process_rep::generate_index (string idx) {
00249   if (DEBUG_AUTO)
00250     cout << "TeXmacs] Generating index [" << idx << "]\n";
00251   tree I= copy (buf->data->aux[idx]);
00252   if (buf->prj != NULL) I= copy (buf->prj->data->aux[idx]);
00253   if (N(I)>0) {
00254     followup= hashmap<string,tree> (TUPLE);
00255     int i, n= N(I);
00256     array<string> entry (n);
00257     for (i=0; i<n; i++)
00258       entry[i]= index_name (I[i]);
00259     merge_sort (entry);
00260 
00261     hashmap<string,tree> h (TUPLE);
00262     for (i=0; i<n; i++) {
00263       string name = index_name  (I[i]);
00264       tree   value= index_value (I[i]);
00265       if (!h->contains (name)) h (name)= tuple (value);
00266       else h (name) << value;
00267     }
00268 
00269     array<string> new_entry;
00270     for (i=0; i<n; i++) {
00271       if ((i>0) && (entry[i] == entry[i-1])) continue;
00272       insert_recursively (new_entry, entry[i], h);
00273     }
00274     entry= new_entry;
00275     n= N(entry);
00276 
00277     tree D (DOCUMENT);
00278     for (i=0; i<n; i++)
00279       make_entry (D, h (entry[i]));
00280     insert_tree (D);
00281   }
00282 }
00283 
00284 /******************************************************************************
00285 * Automatically generate a glossary
00286 ******************************************************************************/
00287 
00288 void
00289 edit_process_rep::generate_glossary (string gly) {
00290   if (DEBUG_AUTO)
00291     cout << "TeXmacs] Generating glossary [" << gly << "]\n";
00292   tree G= copy (buf->data->aux[gly]);
00293   if (buf->prj != NULL) G= copy (buf->prj->data->aux[gly]);
00294   if (N(G)>0) {
00295     int i, n= N(G);
00296     tree D (DOCUMENT);
00297     for (i=0; i<n; i++)
00298       if (is_func (G[i], TUPLE, 1)) D << G[i][0];
00299       else if (is_func (G[i], TUPLE, 3) && (G[i][0] == "normal")) {
00300        tree L= compound ("glossary-1", G[i][1], G[i][2]);
00301        D << L;
00302       }
00303       else if (is_func (G[i], TUPLE, 4) && (G[i][0] == "normal")) {
00304        tree L= compound ("glossary-2", G[i][1], G[i][2], G[i][3]);
00305        D << L;
00306       }
00307       else if (is_func (G[i], TUPLE, 3) && (G[i][0] == "dup")) {
00308        int j;
00309        for (j=0; j<N(D); j++)
00310          if ((is_compound (D[j], "glossary-1") ||
00311               is_compound (D[j], "glossary-2")) &&
00312              (D[j][1] == G[i][1]))
00313            {
00314              tree C= D[j][N(D[j])-1];
00315              if (!is_concat (C)) C= tree (CONCAT, C);
00316              C << ", ";
00317              C << G[i][2];
00318              D[j][N(D[j])-1]= C;
00319            }
00320       }
00321     insert_tree (D);
00322   }
00323 }
00324 
00325 /******************************************************************************
00326 * Automatically generate auxiliairy data and replace in text
00327 ******************************************************************************/
00328 
00329 static bool
00330 is_aux (tree t) {
00331   return
00332     is_compound (t, "bibliography", 4) ||
00333     is_compound (t, "bibliography*", 5) ||
00334     is_compound (t, "table-of-contents", 2) ||
00335     is_compound (t, "table-of-contents*", 3) ||
00336     is_compound (t, "the-index", 2) ||
00337     is_compound (t, "the-index*", 3) ||
00338     is_compound (t, "the-glossary", 2) ||
00339     is_compound (t, "the-glossary*", 3) ||
00340     is_compound (t, "list-of-figures", 2) ||
00341     is_compound (t, "list-of-tables", 2);
00342 }
00343 
00344 void
00345 edit_process_rep::generate_aux_recursively (string which, tree st, path p) {
00346   int i, n= N(st);
00347   for (i=0; i<n; i++)
00348     if (!is_aux (st[i])) {
00349       if (is_compound (st[i]))
00350        generate_aux_recursively (which, st[i], p * i);
00351     }
00352     else {
00353       tree t= st[i];
00354       path doc_p= p * path (i, N(t)-1);
00355       assign (doc_p, tree (DOCUMENT, ""));
00356       go_to (doc_p * path (0, 0));
00357 
00358       /*
00359        cout << "et= " << et << "\n";
00360        cout << "tp= " << tp << "\n";
00361        cout << "------------------------------------------------------\n";
00362       */
00363       if (arity (t) >= 1) {
00364        if ((arity(t) >= 3) &&
00365            (is_compound (t, "bibliography") ||
00366             is_compound (t, "bibliography*")) &&
00367            ((which == "") || (which == "bibliography")))
00368          generate_bibliography (as_string (t[0]), as_string (t[1]),
00369                              as_string (t[2]));
00370        if ((is_compound (t, "table-of-contents") ||
00371             is_compound (t, "table-of-contents*")) &&
00372            ((which == "") || (which == "table-of-contents")))
00373          generate_table_of_contents (as_string (t[0]));
00374        if ((is_compound (t, "the-index") || is_compound (t, "the-index*")) &&
00375            ((which == "") || (which == "the-index")))
00376          generate_index (as_string (t[0]));
00377        if ((is_compound (t, "the-glossary") ||
00378             is_compound (t, "the-glossary*")) &&
00379            ((which == "") || (which == "the-glossary")))
00380          generate_glossary (as_string (t[0]));
00381        if (is_compound (t, "list-of-figures") &&
00382            ((which == "") || (which == "list-of-figures")))
00383          generate_glossary (as_string (t[0]));
00384        if (is_compound (t, "list-of-tables") &&
00385            ((which == "") || (which == "list-of-tables")))
00386          generate_glossary (as_string (t[0]));
00387       }
00388       /*
00389        cout << "et= " << et << "\n";
00390        cout << "tp= " << tp << "\n";
00391        cout << "------------------------------------------------------\n\n\n";
00392       */
00393     }
00394 }
00395 
00396 void
00397 edit_process_rep::generate_aux (string which) {
00398   // path saved_path= tp;
00399   generate_aux_recursively (which, subtree (et, rp), rp);
00400   // if (which == "") go_to (saved_path);
00401   // ... may be problematic if cursor was inside regenerated content
00402 }
00403 
00404 bool
00405 edit_process_rep::get_save_aux () {
00406   return as_bool (get_init_string (SAVE_AUX));
00407 }