1 
2 /******************************************************************************
3 * MODULE     : new_style.cpp
4 * DESCRIPTION: Style and DRD computation and caching
5 * COPYRIGHT  : (C) 1999-2012  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 "new_style.hpp"
13 #include "file.hpp"
14 #include "data_cache.hpp"
15 #include "convert.hpp"
16 #include "../../Typeset/env.hpp"
17 
18 /******************************************************************************
19 * Global data
20 ******************************************************************************/
21 
22 struct style_data_rep {
23   hashmap<tree,hashmap<string,tree> > style_cache;
24   hashmap<tree,tree> style_drd;
25   hashmap<string,bool> style_busy;
26   hashmap<string,tree> style_void;
27   drd_info drd_void;
28   hashmap<tree,hashmap<string,tree> > style_cached;
29   hashmap<tree,drd_info> drd_cached;
30 
style_data_repstyle_data_rep31   style_data_rep ():
32     style_cache (hashmap<string,tree> (UNINIT)),
33     style_drd (tree (COLLECTION)),
34     style_busy (false),
35     style_void (UNINIT),
36     drd_void ("void"),
37     style_cached (style_void),
38     drd_cached (drd_void) {}
39 };
40 
41 static style_data_rep* sd= NULL;
42 
43 static void
init_style_data()44 init_style_data () {
45   if (sd == NULL) sd= tm_new<style_data_rep> ();
46 }
47 
48 extern hashmap<string,tree> style_tree_cache;
49 hashmap<string,bool> hidden_packages (false);
50 
51 /******************************************************************************
52 * Modify style so as to search in all ancestor directories
53 ******************************************************************************/
54 
55 tree
preprocess_style(tree st,url name)56 preprocess_style (tree st, url name) {
57   if (is_rooted_tmfs (name)) return st;
58   if (is_atomic (st)) st= tree (TUPLE, st);
59   if (!is_tuple (st)) return st;
60   tree r (TUPLE, N(st));
61   for (int i=0; i<N(st); i++) {
62     r[i]= st[i];
63     if (!is_atomic (st[i])) continue;
64     string pack= st[i]->label * ".ts";
65     url stf= resolve (expand (head (name) * url_ancestor () * pack));
66     if (!is_none (stf)) r[i]= as_string (stf);
67   }
68   //if (r != st) cout << "old: " << st << "\nnew: " << r << "\n";
69   return r;
70 }
71 
72 /******************************************************************************
73 * Caching style files on disk
74 ******************************************************************************/
75 
76 static string
cache_file_name(tree t)77 cache_file_name (tree t) {
78   if (is_atomic (t)) return replace (t->label, "/", "%");
79   else {
80     string s;
81     int i, n= N(t);
82     for (i=0; i<n; i++)
83       s << "__" << cache_file_name (t[i]);
84     return s * "__";
85   }
86 }
87 
88 void
style_invalidate_cache()89 style_invalidate_cache () {
90   style_tree_cache= hashmap<string,tree> ();
91   hidden_packages= hashmap<string,bool> (false);
92   if (sd != NULL) {
93     tm_delete<style_data_rep> (sd);
94     sd= NULL;
95   }
96   init_style_data ();
97   remove ("$TEXMACS_HOME_PATH/system/cache" * url_wildcard ("__*"));
98 }
99 
100 void
style_set_cache(tree style,hashmap<string,tree> H,tree t)101 style_set_cache (tree style, hashmap<string,tree> H, tree t) {
102   init_style_data ();
103   // cout << "set cache " << style << LF;
104   sd->style_cache (copy (style))= H;
105   sd->style_drd   (copy (style))= t;
106   url name ("$TEXMACS_HOME_PATH/system/cache", cache_file_name (style));
107   if (!exists (name)) {
108     save_string (name, tree_to_scheme (tuple ((tree) H, t)));
109     // cout << "saved " << name << LF;
110   }
111 }
112 
113 void
style_get_cache(tree style,hashmap<string,tree> & H,tree & t,bool & f)114 style_get_cache (tree style, hashmap<string,tree>& H, tree& t, bool& f) {
115   init_style_data ();
116   //cout << "get cache " << style << LF;
117   if ((style == "") || (style == tree (TUPLE))) { f= false; return; }
118   f= sd->style_cache->contains (style);
119   if (f) {
120     H= sd->style_cache [style];
121     t= sd->style_drd   [style];
122   }
123   else {
124     string s;
125     url name ("$TEXMACS_HOME_PATH/system/cache", cache_file_name (style));
126     if (exists (name) && (!load_string (name, s, false))) {
127       //cout << "loaded " << name << LF;
128       tree p= scheme_to_tree (s);
129       H= hashmap<string,tree> (UNINIT, p[0]);
130       t= p[1];
131       sd->style_cache (copy (style))= H;
132       sd->style_drd   (copy (style))= t;
133       f= true;
134     }
135   }
136 }
137 
138 /******************************************************************************
139 * Get environment and drd of style files
140 ******************************************************************************/
141 
142 bool
compute_env_and_drd(tree style)143 compute_env_and_drd (tree style) {
144   init_style_data ();
145   ASSERT (is_tuple (style), "style tuple expected");
146   bool busy= false;
147   for (int i=0; i<N(style); i++)
148     busy= busy || sd->style_busy->contains (as_string (style[i]));
149   hashmap<string,bool> old_busy= copy (sd->style_busy);
150   for (int i=0; i<N(style); i++)
151     sd->style_busy (as_string (style[i]))= true;
152 
153   //cout << "Get environment of " << style << INDENT << LF;
154   hashmap<string,tree> H;
155   drd_info drd ("none", std_drd);
156   url none= url ("$PWD/none");
157   hashmap<string,tree> lref;
158   hashmap<string,tree> gref;
159   hashmap<string,tree> laux;
160   hashmap<string,tree> gaux;
161   hashmap<string,tree> latt;
162   hashmap<string,tree> gatt;
163   edit_env env (drd, none, lref, gref, laux, gaux, latt, gatt);
164   if (!busy) {
165     tree t;
166     bool ok;
167     style_get_cache (style, H, t, ok);
168     if (ok) {
169       env->patch_env (H);
170       ok= drd->set_locals (t);
171       drd->set_environment (H);
172     }
173     if (!ok) {
174       env->exec (tree (USE_PACKAGE, A (style)));
175       env->read_env (H);
176       drd->heuristic_init (H);
177     }
178     sd->style_cached (style)= H;
179     sd->drd_cached (style)= drd;
180   }
181   //cout << UNINDENT << "Got environment of " << style << LF;
182 
183   sd->style_busy= old_busy;
184   return !busy;
185 }
186 
187 hashmap<string,tree>
get_style_env(tree style)188 get_style_env (tree style) {
189   //cout << "get_style_env " << style << "\n";
190   init_style_data ();
191   if (sd->style_cached->contains (style))
192     return sd->style_cached [style];
193   else if (compute_env_and_drd (style))
194     return sd->style_cached [style];
195   else {
196     //cout << "Busy style: " << style << "\n";
197     return hashmap<string,tree> ();
198   }
199 }
200 
201 drd_info
get_style_drd(tree style)202 get_style_drd (tree style) {
203   //cout << "get_style_drd " << style << "\n";
204   init_style_data ();
205   init_std_drd ();
206   if (sd->drd_cached->contains (style))
207     return sd->drd_cached [style];
208   else if (compute_env_and_drd (style))
209     return sd->drd_cached [style];
210   else {
211     //cout << "Busy drd: " << style << "\n";
212     return std_drd;
213   }
214 }
215 
216 tree
get_document_preamble(tree t)217 get_document_preamble (tree t) {
218   init_style_data ();
219   if (is_atomic (t)) return "";
220   else if (is_compound (t, "hide-preamble", 1)) return t[0];
221   else if (is_compound (t, "show-preamble", 1)) return t[0];
222   else {
223     int i, n= N(t);
224     for (i=0; i<n; i++) {
225       tree p= get_document_preamble (t[i]);
226       if (p != "") return p;
227     }
228     return "";
229   }
230 }
231 
232 drd_info
get_document_drd(tree doc)233 get_document_drd (tree doc) {
234   init_style_data ();
235   tree style= extract (doc, "style");
236   if (extract (doc, "TeXmacs") == "") {
237     if (the_drd->get_syntax (make_tree_label ("theorem")) != tree (UNINIT))
238       return the_drd;
239     style= tree (TUPLE, "generic");
240   }
241   //cout << "style= " << style << "\n";
242   drd_info drd= get_style_drd (style);
243   tree p= get_document_preamble (doc);
244   if (p != "") {
245     drd= drd_info ("preamble", drd);
246     url none= url ("$PWD/none");
247     hashmap<string,tree> lref;
248     hashmap<string,tree> gref;
249     hashmap<string,tree> laux;
250     hashmap<string,tree> gaux;
251     hashmap<string,tree> latt;
252     hashmap<string,tree> gatt;
253     edit_env env (drd, none, lref, gref, laux, gaux, latt, gatt);
254     hashmap<string,tree> H;
255     env->exec (tree (USE_PACKAGE, A (style)));
256     env->exec (p);
257     env->read_env (H);
258     drd->heuristic_init (H);
259   }
260   return drd;
261 }
262 
263 /******************************************************************************
264 * The style and package menus
265 ******************************************************************************/
266 
267 static bool
ignore_dir(string dir)268 ignore_dir (string dir) {
269   return
270     (dir == "Beamer") ||
271     (dir == "Compute") ||
272     (dir == "Customize") ||
273     (dir == "Environment") ||
274     (dir == "Gui") ||
275     (dir == "Header") ||
276     (dir == "Latex") ||
277     (dir == "Miscellaneous") ||
278     (dir == "Obsolete") ||
279     (dir == "Section") ||
280     (dir == "Session") ||
281     (dir == "Standard") ||
282     (dir == "Test");
283 }
284 
285 static bool
hidden_package(url u,string name,bool hidden)286 hidden_package (url u, string name, bool hidden) {
287   if (is_or (u))
288     return hidden_package (u[1], name, hidden) ||
289            hidden_package (u[2], name, hidden);
290   if (is_concat (u)) {
291     string dir= upcase_first (as_string (u[1]));
292     if (dir == "CVS" || dir == ".svn") return false;
293     return hidden_package (u[2], name, hidden || ignore_dir (dir));
294   }
295   if (hidden && is_atomic (u)) {
296     string l= as_string (u);
297     if (!ends (l, ".ts")) return false;
298     l= l(0, N(l)-3);
299     return name == l;
300   }
301   return false;
302 }
303 
304 bool
hidden_package(string name)305 hidden_package (string name) {
306   if (!hidden_packages->contains (name)) {
307     url pck_u= descendance ("$TEXMACS_PACKAGE_ROOT");
308     hidden_packages (name)= hidden_package (pck_u, name, false);
309   }
310   return hidden_packages [name];
311 }
312 
313 static string
compute_style_menu(url u,int kind)314 compute_style_menu (url u, int kind) {
315   if (is_or (u)) {
316     string sep= "\n";
317     if (is_atomic (u[1]) &&
318 	((is_concat (u[2]) && (u[2][1] != "CVS") && (u[2][1] != ".svn")) ||
319 	 (is_or (u[2]) && is_concat (u[2][1]))))
320       sep= "\n---\n";
321     return
322       compute_style_menu (u[1], kind) * sep *
323       compute_style_menu (u[2], kind);
324   }
325   if (is_concat (u)) {
326     string dir= upcase_first (as_string (u[1]));
327     string sub= compute_style_menu (u[2], kind);
328     if (ignore_dir (dir) || dir == "CVS" || dir == ".svn") return "";
329     return "(-> \"" * dir * "\" " * sub * ")";
330   }
331   if (is_atomic (u)) {
332     string l  = as_string (u);
333     if (!ends (l, ".ts")) return "";
334     l= l(0, N(l)-3);
335     string cmd ("set-main-style");
336     if (kind == 1) cmd= "add-style-package";
337     if (kind == 2) cmd= "remove-style-package";
338     if (kind == 3) cmd= "toggle-style-package";
339     return "((verbatim \"" * l * "\") (" * cmd * " \"" * l * "\"))";
340   }
341   return "";
342 }
343 
344 object
get_style_menu()345 get_style_menu () {
346   url sty_u= descendance ("$TEXMACS_STYLE_ROOT");
347   string sty= compute_style_menu (sty_u, 0);
348   return eval ("(menu-dynamic " * sty * ")");
349 }
350 
351 object
get_add_package_menu()352 get_add_package_menu () {
353   url pck_u= descendance ("$TEXMACS_PACKAGE_ROOT");
354   string pck= compute_style_menu (pck_u, 1);
355   return eval ("(menu-dynamic " * pck * ")");
356 }
357 
358 object
get_remove_package_menu()359 get_remove_package_menu () {
360   url pck_u= descendance ("$TEXMACS_PACKAGE_ROOT");
361   string pck= compute_style_menu (pck_u, 2);
362   return eval ("(menu-dynamic " * pck * ")");
363 }
364 
365 object
get_toggle_package_menu()366 get_toggle_package_menu () {
367   url pck_u= descendance ("$TEXMACS_PACKAGE_ROOT");
368   string pck= compute_style_menu (pck_u, 3);
369   return eval ("(menu-dynamic " * pck * ")");
370 }
371