~ubuntu-branches/ubuntu/hardy/texmacs/hardy

« back to all changes in this revision

Viewing changes to src/Edit/Modify/edit_dynamic.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Ralf Treinen
  • Date: 2004-04-19 20:34:00 UTC
  • Revision ID: james.westby@ubuntu.com-20040419203400-g4e34ih0315wcn8v
Tags: upstream-1.0.3-R2
ImportĀ upstreamĀ versionĀ 1.0.3-R2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
 
 
2
/******************************************************************************
 
3
* MODULE     : edit_dynamic.cpp
 
4
* DESCRIPTION: editing dynamic content
 
5
* COPYRIGHT  : (C) 1999  Joris van der Hoeven
 
6
*******************************************************************************
 
7
* This software falls under the GNU general public license and comes WITHOUT
 
8
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
 
9
* If you don't have this file, write to the Free Software Foundation, Inc.,
 
10
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 
11
******************************************************************************/
 
12
 
 
13
#include "edit_dynamic.hpp"
 
14
 
 
15
/******************************************************************************
 
16
* Constructors and destructors
 
17
******************************************************************************/
 
18
 
 
19
edit_dynamic_rep::edit_dynamic_rep () {}
 
20
edit_dynamic_rep::~edit_dynamic_rep () {}
 
21
 
 
22
/******************************************************************************
 
23
* Subroutines for inactive content
 
24
******************************************************************************/
 
25
 
 
26
bool
 
27
edit_dynamic_rep::in_preamble_mode () {
 
28
  return get_env_string (PREAMBLE) == "true";
 
29
}
 
30
 
 
31
bool
 
32
edit_dynamic_rep::is_deactivated () {
 
33
  return !nil (find_deactivated (tp));
 
34
}
 
35
 
 
36
path
 
37
edit_dynamic_rep::find_deactivated (path p) {
 
38
  path parent= path_up (p);
 
39
  if (nil (parent)) return parent;
 
40
  if (is_func (subtree (et, parent), INACTIVE)) return parent;
 
41
  return find_deactivated (parent);
 
42
}
 
43
 
 
44
path
 
45
edit_dynamic_rep::find_dynamic (path p) {
 
46
  path parent= path_up (p);
 
47
  if (nil (parent)) return parent;
 
48
  if (drd->is_dynamic (subtree (et, parent))) return p;
 
49
  return find_dynamic (parent);
 
50
}
 
51
 
 
52
/******************************************************************************
 
53
* Making general compound objects
 
54
******************************************************************************/
 
55
 
 
56
bool
 
57
edit_dynamic_rep::is_multi_paragraph_macro (tree t) {
 
58
  int n= arity (t);
 
59
  if (is_document (t) || is_func (t, PARA) || is_func (t, SURROUND))
 
60
    return true;
 
61
  if (is_func (t, MACRO) || is_func (t, WITH))
 
62
    return is_multi_paragraph_macro (t [n-1]);
 
63
  if (is_extension (t) && (!is_compound (t, "footnote"))) {
 
64
    int i;
 
65
    for (i=1; i<n; i++)
 
66
      if (is_multi_paragraph_macro (t[i]))
 
67
        return true;
 
68
    tree f= get_env_value (t[0]->label);
 
69
    return is_multi_paragraph_macro (f);
 
70
  }
 
71
  return false;
 
72
}
 
73
 
 
74
static bool
 
75
contains_table_format (tree t, tree var) {
 
76
  // FIXME: this should go into the DRD
 
77
  if (is_atomic (t)) return false;
 
78
  else {
 
79
    int i, n= N(t);
 
80
    for (i=0; i<n; i++)
 
81
      if (contains_table_format (t[i], var))
 
82
        return true;
 
83
    return is_func (t, TFORMAT) && (t[N(t)-1] == tree (ARG, var));
 
84
  }
 
85
}
 
86
 
 
87
void
 
88
edit_dynamic_rep::make_compound (tree_label l, int n= -1) {
 
89
  // cout << "Make compound " << as_string (l) << "\n";
 
90
  if (n == -1) {
 
91
    for (n=0; true; n++) {
 
92
      if (drd->correct_arity (l, n) &&
 
93
          ((n>0) || (drd->get_arity_mode (l) == ARITY_NORMAL))) break;
 
94
      if (n == 100) return;
 
95
    }
 
96
  }
 
97
 
 
98
  tree t (l, n);
 
99
  path p (0, 0);
 
100
  if (n == 0) insert_tree (t, 1);
 
101
  else {
 
102
    tree f= get_env_value (as_string (l));
 
103
    bool block_macro= (N(f) == 2) && is_multi_paragraph_macro (f);
 
104
    bool table_macro= (N(f) == 2) && contains_table_format (f[1], f[0]);
 
105
 
 
106
    tree sel= "";
 
107
    if (selection_active_small () ||
 
108
        (block_macro && selection_active_normal ()))
 
109
      sel= selection_get_cut ();
 
110
    if (block_macro && (!table_macro)) {
 
111
      t[0]= tree (DOCUMENT, "");
 
112
      p   = path (0, 0, 0);
 
113
    }
 
114
    if ((!drd->all_accessible (l)) && (!in_preamble_mode ())) {
 
115
      t= tree (INACTIVE, t);
 
116
      p= path (0, p);
 
117
    }
 
118
    insert_tree (t, p);
 
119
    if (table_macro) make_table (1, 1);
 
120
    if (sel != "") insert_tree (sel, end (sel));
 
121
 
 
122
    string mess;
 
123
    if (drd->get_arity_mode (l) != ARITY_NORMAL)
 
124
      mess= "A-right: insert argument";
 
125
    if (!drd->all_accessible (l)) {
 
126
      if (mess != "") mess << ", ";
 
127
      mess << "return: activate";
 
128
    }
 
129
    if (mess == "") mess= "Move to the right when finished";
 
130
    set_message (mess, drd->get_name (l));
 
131
  }
 
132
}
 
133
 
 
134
void
 
135
edit_dynamic_rep::activate () {
 
136
  path p= find_deactivated (tp);
 
137
  if (nil (p)) return;
 
138
  tree st= subtree (et, p * 0);
 
139
 
 
140
  if (is_func (st, COMPOUND) && is_atomic (st[0])) {
 
141
    tree u (make_tree_label (st[0]->label));
 
142
    u << A (st (1, N(st)));
 
143
    st= u;
 
144
  }
 
145
 
 
146
  assign (p, st);
 
147
  go_to (end (et, p));
 
148
  correct (path_up (p));
 
149
}
 
150
 
 
151
/******************************************************************************
 
152
* Inserting and removing arguments
 
153
******************************************************************************/
 
154
 
 
155
void
 
156
edit_dynamic_rep::go_to_argument (path p, bool start_flag) {
 
157
  tree t= subtree (et, path_up (p));
 
158
  bool inactive= is_func (subtree (et, path_up (p, 2)), INACTIVE);
 
159
  int i= last_item (p), n= N(t);
 
160
  if (i < 0) go_to_start (path_up (p, inactive? 2: 1));
 
161
  else if (i >= n) go_to_end (path_up (p, inactive? 2: 1));
 
162
  else {
 
163
    if ((!drd->is_accessible_child (t, i)) &&
 
164
        (!inactive) && (!in_preamble_mode ()))
 
165
      {
 
166
        ins_unary (path_up (p), INACTIVE);
 
167
        p= path_up (p) * path (0, i);
 
168
      }
 
169
    if (start_flag) go_to_start (p);
 
170
    else go_to_end (p);
 
171
  }
 
172
}
 
173
 
 
174
void
 
175
edit_dynamic_rep::insert_argument (path p, bool forward) {
 
176
  tree t= subtree (et, path_up (p));
 
177
  int i= last_item (p), n= N(t), d= 1;
 
178
  if (forward) do i++; while ((i<=n) && (!drd->insert_point (L(t), i, n)));
 
179
  else while ((i>=0) && (!drd->insert_point (L(t), i, n))) i--;
 
180
  if ((i<0) || (i>n)) return;
 
181
  path q= path_up (p) * i;
 
182
  while (!drd->correct_arity (L(t), n+d)) d++;
 
183
  tree ins (L(t), d);
 
184
  insert (q, ins);
 
185
  go_to_argument (q, forward);
 
186
}
 
187
 
 
188
void
 
189
edit_dynamic_rep::insert_argument (bool forward) {
 
190
  path p= find_dynamic (tp);
 
191
  if (nil (p)) return;
 
192
  if (p == tp) p= find_dynamic (path_up (tp));
 
193
  if (nil (p)) return;
 
194
  insert_argument (p, forward);
 
195
}
 
196
 
 
197
void
 
198
edit_dynamic_rep::remove_argument (path p, bool forward) {
 
199
  tree t= subtree (et, path_up (p));
 
200
  int i= last_item (p), j, d, n= N(t);
 
201
 
 
202
  for (d=1; d<=n-i; d++)
 
203
    if (drd->correct_arity (L(t), n-d) &&
 
204
        drd->insert_point (L(t), i, n-d))
 
205
      {
 
206
        bool flag= true;
 
207
        for (j=0; j<d; j++)
 
208
          flag= flag && is_empty (t[i+j]);
 
209
        if (flag) {
 
210
          remove (p, d);
 
211
          if ((d == n) && is_func (subtree (et, path_up (p, 2)), INACTIVE)) {
 
212
            rem_unary (path_up (p, 2));
 
213
            go_to_border (path_up (p, 2), forward);
 
214
          }
 
215
          else if (forward) go_to_argument (path_up (p) * i, true);
 
216
          else go_to_argument (path_up (p) * (i-1), false);
 
217
          return;
 
218
        }
 
219
        else break;
 
220
      }
 
221
 
 
222
  bool flag= true;
 
223
  for (j=0; j<n; j++)
 
224
    flag= flag && is_empty (t[j]);
 
225
  if (flag) {
 
226
    assign (path_up (p), "");
 
227
    if (subtree (et, path_up (p, 2)) == tree (INACTIVE, "")) {
 
228
      assign (path_up (p, 2), "");
 
229
      correct (path_up (p, 3));
 
230
    }
 
231
    else correct (path_up (p, 2));
 
232
    return;
 
233
  }
 
234
 
 
235
  if (forward) go_to_argument (path_up (p) * (i+1), true);
 
236
  else go_to_argument (path_up (p) * (i-1), false);
 
237
}
 
238
 
 
239
/******************************************************************************
 
240
* Backspace and delete
 
241
******************************************************************************/
 
242
 
 
243
void
 
244
edit_dynamic_rep::back_monolithic (path p) {
 
245
  if (!is_concat (subtree (et, path_up (p)))) assign (p, "");
 
246
  else remove (p, 1);
 
247
  correct (path_up (p));
 
248
}
 
249
 
 
250
void
 
251
edit_dynamic_rep::back_general (path p, bool forward) {
 
252
  tree st= subtree (et, p);
 
253
  int n= N(st);
 
254
  if (n==0) back_monolithic (p);
 
255
  else if ((n==1) && is_func (st[0], DOCUMENT, 1) &&
 
256
           (is_func (st[0][0], TFORMAT) || is_func (st[0][0], TABLE)))
 
257
    back_table (p * path (0, 0), forward);
 
258
  else if ((n==1) && (is_func (st[0], TFORMAT) || is_func (st[0], TABLE)))
 
259
    back_table (p * 0, forward);
 
260
  else go_to_argument (p * (forward? 0: n-1), forward);
 
261
}
 
262
 
 
263
void
 
264
edit_dynamic_rep::back_in_general (tree t, path p, bool forward) {
 
265
  if (is_func (subtree (et, path_up (p, 2)), INACTIVE) || in_preamble_mode ())
 
266
    if ((L(t) >= START_EXTENSIONS) && (last_item (p) == 0)) {
 
267
      tree u (COMPOUND, copy (as_string (L(t))));
 
268
      u << A(copy(t));
 
269
      assign (path_up (p), u);
 
270
      go_to_end (p);
 
271
      return;
 
272
    }
 
273
  remove_argument (p, forward);
 
274
}
 
275
 
 
276
/******************************************************************************
 
277
* The WITH tag
 
278
******************************************************************************/
 
279
 
 
280
static tree
 
281
remove_changes_in (tree t, string var) {
 
282
  if (is_atomic (t)) return t;
 
283
  else if (is_func (t, WITH)) {
 
284
    int i, n=N(t), k=(n-1)>>1;
 
285
    if (k==1) {
 
286
      tree r= remove_changes_in (t[2], var);
 
287
      if (t[0] != var) r= tree (WITH, t[0], t[1], r);
 
288
      return simplify_correct (r);
 
289
    }
 
290
    tree r (WITH);
 
291
    for (i=0; i<k; i++)
 
292
      if (t[i<<1] != var) r << t[i<<1] << t[(i<<1)+1];
 
293
    r << remove_changes_in (t[i<<1], var);
 
294
    return simplify_correct (r);
 
295
  }
 
296
  else if (is_format (t) || is_func (t, SURROUND)) {
 
297
    int i, n= N(t);
 
298
    tree r (t, n);
 
299
    for (i=0; i<n; i++)
 
300
      r[i]= remove_changes_in (t[i], var);
 
301
    return simplify_correct (r);
 
302
  }
 
303
  else return t;
 
304
}
 
305
 
 
306
void
 
307
edit_dynamic_rep::make_with (string var, string val) {
 
308
  if (selection_active_normal ()) {
 
309
    tree t= remove_changes_in (selection_get (), var);
 
310
    selection_cut ();
 
311
    insert_tree (tree (WITH, var, val, t), path (2, end (t)));
 
312
  }
 
313
  else insert_tree (tree (WITH, var, val, ""), path (2, 0));
 
314
}
 
315
 
 
316
void
 
317
edit_dynamic_rep::insert_with (path p, string var, tree val) {
 
318
  tree st= subtree (et, p);
 
319
  if (is_func (st, WITH)) {
 
320
    int i, n= N(st)-1;
 
321
    for (i=0; i<n; i+=2)
 
322
      if (st[i] == var) {
 
323
        assign (p * (i+1), copy (val));
 
324
        return;
 
325
      }
 
326
    insert (p * n, copy (tree (WITH, var, val)));    
 
327
  }
 
328
  else if ((!nil (p)) && is_func (subtree (et, path_up (p)), WITH))
 
329
    insert_with (path_up (p), var, val);
 
330
  else {
 
331
    ins_unary (p, WITH);
 
332
    insert (p * 0, copy (tree (WITH, var, val)));
 
333
  }
 
334
}
 
335
 
 
336
void
 
337
edit_dynamic_rep::remove_with (path p, string var) {
 
338
  tree st= subtree (et, p);
 
339
  if (is_func (st, WITH)) {
 
340
    int i, n= N(st)-1;
 
341
    for (i=0; i<n; i+=2)
 
342
      if (st[i] == var) {
 
343
        remove (p * i, 2);
 
344
        if (n == 2) rem_unary (p);
 
345
        return;
 
346
      }
 
347
  }
 
348
  else if ((!nil (p)) && is_func (subtree (et, path_up (p)), WITH))
 
349
    remove_with (path_up (p), var);
 
350
}
 
351
 
 
352
void
 
353
edit_dynamic_rep::back_in_with (tree t, path p, bool forward) {
 
354
  if (is_func (subtree (et, path_up (p, 2)), INACTIVE) || in_preamble_mode ())
 
355
    back_in_general (t, p, forward);
 
356
  else if (t[N(t)-1] == "") {
 
357
    assign (path_up (p), "");
 
358
    correct (path_up (p, 2));
 
359
  }
 
360
  else go_to_border (path_up (p), !forward);
 
361
}
 
362
 
 
363
/******************************************************************************
 
364
* The HYBRID and LATEX tags
 
365
******************************************************************************/
 
366
 
 
367
void
 
368
edit_dynamic_rep::make_hybrid () {
 
369
  tree t (HYBRID, "");
 
370
  if (selection_active_small ())
 
371
    t[0]= selection_get_cut ();
 
372
  if (is_func (t, HYBRID, 1) && (t[0] != "") &&
 
373
      (!(is_atomic (t[0]) && drd->contains (t[0]->label))))
 
374
    t= tree (HYBRID, "", t[0]);
 
375
  path p= end (t, path (0));
 
376
  insert_tree (tree (INACTIVE, t), path (0, p));
 
377
  set_message ("return: activate symbol or macro", "hybrid");
 
378
}
 
379
 
 
380
bool
 
381
edit_dynamic_rep::activate_latex () {
 
382
  path p= find_deactivated (tp);
 
383
  if (!nil (p)) {
 
384
    tree st= subtree (et, p * 0);
 
385
    if ((is_func (st, LATEX) || (is_func (st, HYBRID))) && is_atomic (st[0])) {
 
386
      string  s= st[0]->label, help;
 
387
      command cmd;
 
388
      if (kbd_get_command (s, help, cmd)) {
 
389
        cut (p * 0, p * 1);
 
390
        cmd ();
 
391
        if (N(st) == 2) insert_tree (copy (st[1]));
 
392
        return true;
 
393
      }
 
394
    }
 
395
    set_message ("Error: not a command name", "activate latex command");
 
396
  }
 
397
  return false;
 
398
}
 
399
 
 
400
void
 
401
edit_dynamic_rep::activate_hybrid () {
 
402
  // WARNING: update edit_interface_rep::set_hybrid_footer when updating this
 
403
  if (activate_latex ()) return;
 
404
  path p= find_deactivated (tp);
 
405
  if (nil (p)) return;
 
406
  tree st= subtree (et, p * 0);
 
407
 
 
408
  if (is_func (st, HYBRID) && is_atomic (st[0])) {
 
409
    // activate macro argument
 
410
    string name= st[0]->label;
 
411
    path mp= search_upwards (MACRO);
 
412
    if (!nil (mp)) {
 
413
      tree mt= subtree (et, mp);
 
414
      int i, n= N(mt)-1;
 
415
      for (i=0; i<n; i++)
 
416
        if (mt[i] == name) {
 
417
          assign (p, tree (ARG, copy (name)));
 
418
          go_to (end (et, p));
 
419
          correct (path_up (p));
 
420
          return;
 
421
        }
 
422
    }
 
423
 
 
424
    // activate macro application
 
425
    tree f= get_env_value (name);
 
426
    if (is_func (f, MACRO) || is_func (f, XMACRO)) {
 
427
      assign (p, "");
 
428
      correct (path_up (p));
 
429
      make_compound (make_tree_label (name));
 
430
      if (N(st) == 2) insert_tree (st[1]);
 
431
    }
 
432
    else if (f != UNINIT) {
 
433
      assign (p, tree (VALUE, copy (name)));
 
434
      go_to (end (et, p));
 
435
      correct (path_up (p));
 
436
    }
 
437
    else set_message ("Error: unknown command", "activate hybrid command");
 
438
  }
 
439
}
 
440
 
 
441
/******************************************************************************
 
442
* Other special tags (SYMBOL and COMPOUND)
 
443
******************************************************************************/
 
444
 
 
445
void
 
446
edit_dynamic_rep::activate_symbol () {
 
447
  path p= find_deactivated (tp);
 
448
  if (nil (p)) return;
 
449
  tree st= subtree (et, p * 0);
 
450
 
 
451
  if (is_func (st, SYMBOL, 1) && is_atomic (st[0])) {
 
452
    string s= st[0]->label;
 
453
    if (is_int (s))
 
454
      assign (p, string (((char) as_int (s))));
 
455
    else {
 
456
      int i, n= N(s);
 
457
      for (i=0; i<n; i++)
 
458
        if ((s[i]=='<') || (s[i]=='>'))
 
459
          { s= ""; break; }
 
460
      assign (p, "<" * s * ">");
 
461
    }
 
462
    go_to (end (et, p));
 
463
    correct (path_up (p));
 
464
  }
 
465
}
 
466
 
 
467
void
 
468
edit_dynamic_rep::activate_compound () {
 
469
  path p= search_upwards (COMPOUND);
 
470
  if (!nil (p)) {
 
471
    tree st= subtree (et, p);
 
472
    tree u (make_tree_label (st[0]->label));
 
473
    u << A (st (1, N(st)));
 
474
    assign (p, u);
 
475
    go_to (end (et, p));
 
476
  }
 
477
}
 
478
 
 
479
/******************************************************************************
 
480
* Temporary fixes for block structures
 
481
******************************************************************************/
 
482
 
 
483
bool
 
484
edit_dynamic_rep::make_return_before () {
 
485
  bool flag;
 
486
  path q= tp;
 
487
  while (!is_document (subtree (et, path_up (q)))) q= path_up (q);
 
488
  flag= (N (subtree (et, path_up (q))) == (q->item+1)) || (tp != end (et, q));
 
489
  if (flag) {
 
490
    flag= insert_return ();
 
491
    go_to (end (et, q));
 
492
  }
 
493
  return flag;
 
494
}
 
495
 
 
496
bool
 
497
edit_dynamic_rep::make_return_after () {
 
498
  path q= tp;
 
499
  while (!is_document (subtree (et, path_up (q)))) q= path_up (q);
 
500
  if (tp == start (et, q)) return false;
 
501
  return insert_return ();
 
502
}
 
503
 
 
504
void
 
505
edit_dynamic_rep::temp_proof_fix () {
 
506
  /* this routine should be removed as soon as possible */
 
507
  path p = search_upwards_compound ("proof");
 
508
  if (nil (p) || (N(tp) < N(p)+2)) return;
 
509
  path q = head (tp, N(p)+2);
 
510
  tree st= subtree (et, path_up (q));
 
511
  if ((!is_document (st)) || (last_item (q) != (N(st)-1))) return;
 
512
  insert (path_inc (q), tree (DOCUMENT, ""));
 
513
}