Back to index

texmacs  1.0.7.15
edit_text.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : edit_text.cpp
00004 * DESCRIPTION: modification of 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 "edit_text.hpp"
00013 #include "file.hpp"
00014 #include "analyze.hpp"
00015 #include "scheme.hpp"
00016 
00017 /******************************************************************************
00018 * Constructors and destructors
00019 ******************************************************************************/
00020 
00021 edit_text_rep::edit_text_rep () {}
00022 edit_text_rep::~edit_text_rep () {}
00023 
00024 /******************************************************************************
00025 * Correction routines for the edit tree
00026 ******************************************************************************/
00027 
00028 void
00029 edit_text_rep::correct_concat (path p, int done) {
00030   tree t (subtree (et, p));
00031   if (L(t) != CONCAT) {
00032     cerr << "\nThe tree was <" << t << ">\n";
00033     FAILED ("concat expected");
00034   }
00035 
00036   int i, n= N(t);
00037   if (n == 0) { assign (p, string ("")); return; }
00038   if (n == 1) { remove_node (p * 0); return; }
00039   for (i=done; i<n; i++) {
00040     if (t[i] == "") {
00041       remove (p * i, 1);
00042       correct_concat (p, i);
00043       return;
00044     }
00045     if ((i<n-1) && is_atomic (t[i]) && is_atomic (t[i+1])) {
00046       join (p * i);
00047       correct_concat (p, i);
00048       return;
00049     }
00050     if (is_concat (t[i])) {
00051       insert_node (p * 0, CONCAT);
00052       split (p * path (0, i));
00053       split (p * path (1, 1));
00054       remove_node (p * path (1, 0));
00055       if (subtree (et, p * 0) == tree (CONCAT)) remove (p * 0, 1);
00056       else join (p * 0);
00057       if (subtree (et, p * 1) == tree (CONCAT)) remove (p * 1, 1);
00058       else join (p * 0);
00059       remove_node (p * 0);
00060       correct_concat (p, max (i-1, 0));
00061       return;
00062     }
00063     else if (is_multi_paragraph (t[i]) &&
00064             is_document (subtree (et, path_up (p))))
00065       {
00066        if ((i+1)<n) {
00067          split (p * (i+1));
00068          correct_concat (path_inc (p));
00069        }
00070        if (i==0) remove_node (p * 0);
00071        else {
00072          split (p * i);
00073          remove_node (path_inc (p) * 0);
00074          correct_concat (p);
00075        }
00076        return;
00077       }
00078   }
00079 }
00080 
00081 void
00082 edit_text_rep::correct (path p) {
00083   tree t (subtree (et, p));
00084   if (L(t) == CONCAT) correct_concat (p);
00085   if (t == "") correct (path_up (p));
00086 }
00087 
00088 /******************************************************************************
00089 * Inserting line breaks (text-mode only)
00090 ******************************************************************************/
00091 
00092 bool
00093 edit_text_rep::pure_line (path p) {
00094   p= path_up (p);
00095   tree st= subtree (et, path_up (p));
00096   return
00097     is_document (st) ||
00098     ((is_func (st, WITH) || is_func (st, LOCUS) ||
00099       is_func (st, CANVAS) || is_func (st, ORNAMENT)) &&
00100      (last_item (p) == (N(st)-1)) && pure_line (p)) ||
00101     (is_extension (st) && (last_item (p) >= 0) && pure_line (p));
00102 }
00103 
00104 bool
00105 edit_text_rep::accepts_return (path p) {
00106   tree st= subtree (et, path_up (p));
00107   return
00108     is_document (st) ||
00109     (is_func (st, SURROUND, 3) && (last_item (p) == 2)) ||
00110     (is_func (st, _FLOAT) && (last_item (p) == (N(st)-1))) ||
00111     (is_func (st, DATOMS) &&
00112      (last_item (p) == (N(st)-1)) && pure_line (p)) ||
00113     (is_func (st, MACRO) && (last_item (p) == (N(st)-1))) ||
00114     (is_func (st, XMACRO, 2) && (last_item (p) == 1)) ||
00115     ((is_func (st, WITH) || is_mod_active (st) ||
00116       is_func (st, STYLE_WITH) || is_func (st, VAR_STYLE_WITH) ||
00117       is_func (st, LOCUS) ||
00118       is_func (st, CANVAS) || is_func (st, ORNAMENT)) &&
00119      (last_item (p) == (N(st)-1)) && pure_line (p)) ||
00120     (is_extension (st) && (last_item (p) >= 0) && pure_line (p));
00121 }
00122 
00123 bool
00124 edit_text_rep::insert_return () {
00125   if (accepts_return (path_up (tp)))
00126     insert_node (path_up (tp) * 0, CONCAT);
00127   path p= path_up (tp, 2);
00128   if (!is_concat (subtree (et, p))) return true;
00129   if (!accepts_return (p)) return true;
00130   if (!is_document (subtree (et, path_up (p)))) {
00131     insert_node (p * 0, DOCUMENT);
00132     p= path_up (tp, 2);
00133   }
00134 
00135   if (is_atomic (subtree (et, path_up (tp)))) split (tp);
00136   if (last_item (tp)==right_index (subtree (et, path_up (tp))))
00137     split (path_inc (path_up (tp)));
00138   else split (path_up (tp));
00139   go_to (correct_cursor (et, path_inc (p) * 0));
00140   correct_concat (p);
00141   correct_concat (path_inc (p));
00142   return false;
00143 }
00144 
00145 void
00146 edit_text_rep::remove_return (path p) {
00147   if (!is_document (subtree (et, path_up (p))))
00148     FAILED ("parent is not a document");
00149 
00150   if (!is_concat (subtree (et, p)))
00151     insert_node (p * 0, CONCAT);
00152   if (!is_concat (subtree (et, path_inc (p))))
00153     insert_node (path_inc (p) * 0, CONCAT);
00154   join (p);
00155   correct_concat (p);
00156 }
00157 
00158 /******************************************************************************
00159 * Inserting a simple formula or tree
00160 ******************************************************************************/
00161 
00162 path
00163 edit_text_rep::prepare_for_insert () {
00164   path p = path_up (tp);
00165   int  l = last_item (tp);
00166   tree st= subtree (et, p);
00167 
00168   if ((!is_document (st)) && is_multi_paragraph (st)) {
00169     if (!is_document (subtree (et, path_up (p))))
00170       insert_node (p * 0, DOCUMENT);
00171     else {
00172       if (l == 0) {
00173        insert (p, tree (DOCUMENT, ""));
00174        go_to (p * 0);
00175       }
00176       else {
00177        insert (path_inc (p), tree (DOCUMENT, ""));
00178        go_to (path_inc (p) * 0);
00179       }
00180     }
00181     return prepare_for_insert ();
00182   }
00183 
00184   if ((rp < p) && is_concat (subtree (et, path_up (p)))) {
00185     if (l==0) return p;
00186     if (is_compound (st) || (l==N(st->label))) return path_inc (p);
00187     split (tp);
00188     return path_inc (p);
00189   }
00190   
00191   insert_node (p * 0, CONCAT);
00192   if (is_atomic (st) && (l!=0) && (l!=N(st->label))) {
00193     split (p * path (0, l));
00194     return p * 1;
00195   }
00196   return p * ((l==0)? 0: 1);
00197 }
00198 
00199 void
00200 edit_text_rep::insert_tree (tree t, path p_in_t) {
00201   if (!as_bool (call ("like-emacs?"))) selection_cut ("none");
00202   if (is_atomic (t) && (p_in_t == end (t)) &&
00203       is_atomic (subtree (et, path_up (tp))))
00204     insert (tp, t);
00205   else if (is_document (t)) {
00206     if (insert_return ()) return;
00207     path p= search_parent_upwards (DOCUMENT);
00208     bool empty= (subtree (et, p) == "");
00209     if (empty) remove (p, 1);
00210     insert (p, t);
00211     path q= path_add (p, p_in_t->item) * p_in_t->next;
00212     go_to (correct_cursor (et, q));
00213     remove_return (path_dec (p));
00214     if (!empty) remove_return (path_add (p, N(t)-2));
00215   }
00216   else if (is_multi_paragraph (t)) {
00217     if (make_return_after ()) return;
00218     path p= search_parent_upwards (DOCUMENT);
00219     if (subtree (et, p) == "") remove (p, 1);
00220     insert (p, tree (DOCUMENT, t));
00221     go_to (correct_cursor (et, p * p_in_t));
00222   }
00223   else {
00224     path p= prepare_for_insert ();
00225     if (!is_concat (t)) { t= tree (CONCAT, t); p_in_t= path (0, p_in_t); }
00226     insert (p, t);
00227     path q= path_add (p, p_in_t->item) * p_in_t->next;
00228     go_to (correct_cursor (et, q));
00229     correct_concat (path_up (p));
00230   }
00231 }
00232 
00233 void
00234 edit_text_rep::insert_tree (tree t) {
00235   t= copy (simplify_correct (t));
00236   insert_tree (t, end (t));
00237 }
00238 
00239 void
00240 edit_text_rep::var_insert_tree (tree t, path p_in_t) {
00241   if (selection_active_any ()) {
00242     selection_cut ("primary");
00243     insert_tree (t, p_in_t);
00244     selection_paste ("primary");
00245   }
00246   else insert_tree (t, p_in_t);
00247 }
00248 
00249 /******************************************************************************
00250 * Spaces
00251 ******************************************************************************/
00252 
00253 static string
00254 get_unit (tree t) {
00255   int i;
00256   string s= as_string (t);
00257   for (i=0; i<N(s); i++)
00258     if ((s[i]>='a') && (s[i]<='z')) break;
00259   return s (i, N(s));
00260 }
00261 
00262 static string
00263 get_quantity (tree t) {
00264   int i;
00265   string s= as_string (t);
00266   for (i=0; i<N(s); i++)
00267     if ((s[i]>='a') && (s[i]<='z')) break;
00268   return s (0, i);
00269 }
00270 
00271 void
00272 edit_text_rep::make_space (tree u) {
00273   if (is_atomic (u)) return;
00274   tree t= subtree (et, path_up (tp));
00275 
00276   int i, n= N(u);
00277   bool flag= is_func (t, L (u), n);
00278   for (i=0; i<n; i++) {
00279     if (!flag) break;
00280     string u1= get_unit (t[i]);
00281     string u2= get_unit (t[0]);
00282     double x1= as_double (get_quantity (t[i]));
00283     double x2= as_double (get_quantity (u[i]));
00284     flag= flag && (u1==u2) && ((x1*x2)>0);
00285   }
00286   
00287   if (flag) {
00288     for (i=0; i<n; i++) {
00289       double w1= as_double (get_quantity (t[i]));
00290       double w2= as_double (get_quantity (u[i]));
00291       string sum= as_string (w1+w2) * get_unit (t[i]);
00292       assign (path_up (tp) * i, sum);
00293     }
00294   }
00295   else insert_tree (u);
00296 }
00297 
00298 void
00299 edit_text_rep::make_space (string w) {
00300   make_space (tree (SPACE, w));
00301 }
00302 
00303 void
00304 edit_text_rep::make_space (string w, string y1, string y2) {
00305   insert_tree (tree (SPACE, w, y1, y2));
00306 }
00307 
00308 void
00309 edit_text_rep::make_hspace (string s) {
00310   make_space (tree (HSPACE, s));
00311 }
00312 
00313 void
00314 edit_text_rep::make_hspace (string smin, string sdef, string smax) {
00315   make_space (tree (HSPACE, smin, sdef, smax));
00316 }
00317 
00318 void
00319 edit_text_rep::make_vspace_before (string s) {
00320   make_space (tree (VAR_VSPACE, s));
00321 }
00322 
00323 void
00324 edit_text_rep::make_vspace_before (string smin, string sdef, string smax) {
00325   make_space (tree (VAR_VSPACE, smin, sdef, smax));
00326 }
00327 
00328 void
00329 edit_text_rep::make_vspace_after (string s) {
00330   make_space (tree (VSPACE, s));
00331 }
00332 
00333 void
00334 edit_text_rep::make_vspace_after (string smin, string sdef, string smax) {
00335   make_space (tree (VSPACE, smin, sdef, smax));
00336 }
00337 
00338 /******************************************************************************
00339 * Insert formatting objects and miscellaneous
00340 ******************************************************************************/
00341 
00342 void
00343 edit_text_rep::make_htab (string spc) {
00344   insert_tree (tree (HTAB, spc));
00345 }
00346 
00347 void
00348 edit_text_rep::make_image (
00349   string file_name, bool link, string w, string h, string x, string y)
00350 {
00351   url image= url_system (file_name);
00352   string type= "";
00353   if (is_rooted (image))
00354     image= delta (get_name (), image);
00355 
00356   tree t (IMAGE);
00357   if (link) {
00358     if (is_rooted (image, "default")) image= reroot (image, "file");
00359     t << as_string (image, URL_STANDARD);
00360   }
00361   else {
00362     string s;
00363     tree vim= verbatim (as_string (image));
00364     load_string (relative (get_name (), image), s, false);
00365     if (s == "") {
00366       set_message (concat ("File '", vim, "' not found"), "make image");
00367       return;
00368     }
00369     type= suffix (image);
00370     if (type == "") {
00371       set_message (concat ("File '", vim, "' is not an image"), "make image");
00372       return;
00373     }
00374     t << tuple (tree (RAW_DATA, s), type);
00375   }
00376   t << tree (w) << tree (h) << tree (x) << tree (y);
00377   insert_tree (t);
00378 }