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
******************************************************************************/
13
#include "edit_dynamic.hpp"
15
/******************************************************************************
16
* Constructors and destructors
17
******************************************************************************/
19
edit_dynamic_rep::edit_dynamic_rep () {}
20
edit_dynamic_rep::~edit_dynamic_rep () {}
22
/******************************************************************************
23
* Subroutines for inactive content
24
******************************************************************************/
27
edit_dynamic_rep::in_preamble_mode () {
28
return get_env_string (PREAMBLE) == "true";
32
edit_dynamic_rep::is_deactivated () {
33
return !nil (find_deactivated (tp));
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);
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);
52
/******************************************************************************
53
* Making general compound objects
54
******************************************************************************/
57
edit_dynamic_rep::is_multi_paragraph_macro (tree t) {
59
if (is_document (t) || is_func (t, PARA) || is_func (t, SURROUND))
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"))) {
66
if (is_multi_paragraph_macro (t[i]))
68
tree f= get_env_value (t[0]->label);
69
return is_multi_paragraph_macro (f);
75
contains_table_format (tree t, tree var) {
76
// FIXME: this should go into the DRD
77
if (is_atomic (t)) return false;
81
if (contains_table_format (t[i], var))
83
return is_func (t, TFORMAT) && (t[N(t)-1] == tree (ARG, var));
88
edit_dynamic_rep::make_compound (tree_label l, int n= -1) {
89
// cout << "Make compound " << as_string (l) << "\n";
91
for (n=0; true; n++) {
92
if (drd->correct_arity (l, n) &&
93
((n>0) || (drd->get_arity_mode (l) == ARITY_NORMAL))) break;
100
if (n == 0) insert_tree (t, 1);
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]);
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, "");
114
if ((!drd->all_accessible (l)) && (!in_preamble_mode ())) {
115
t= tree (INACTIVE, t);
119
if (table_macro) make_table (1, 1);
120
if (sel != "") insert_tree (sel, end (sel));
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";
129
if (mess == "") mess= "Move to the right when finished";
130
set_message (mess, drd->get_name (l));
135
edit_dynamic_rep::activate () {
136
path p= find_deactivated (tp);
138
tree st= subtree (et, p * 0);
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)));
148
correct (path_up (p));
151
/******************************************************************************
152
* Inserting and removing arguments
153
******************************************************************************/
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));
163
if ((!drd->is_accessible_child (t, i)) &&
164
(!inactive) && (!in_preamble_mode ()))
166
ins_unary (path_up (p), INACTIVE);
167
p= path_up (p) * path (0, i);
169
if (start_flag) go_to_start (p);
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++;
185
go_to_argument (q, forward);
189
edit_dynamic_rep::insert_argument (bool forward) {
190
path p= find_dynamic (tp);
192
if (p == tp) p= find_dynamic (path_up (tp));
194
insert_argument (p, forward);
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);
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))
208
flag= flag && is_empty (t[i+j]);
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);
215
else if (forward) go_to_argument (path_up (p) * i, true);
216
else go_to_argument (path_up (p) * (i-1), false);
224
flag= flag && is_empty (t[j]);
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));
231
else correct (path_up (p, 2));
235
if (forward) go_to_argument (path_up (p) * (i+1), true);
236
else go_to_argument (path_up (p) * (i-1), false);
239
/******************************************************************************
240
* Backspace and delete
241
******************************************************************************/
244
edit_dynamic_rep::back_monolithic (path p) {
245
if (!is_concat (subtree (et, path_up (p)))) assign (p, "");
247
correct (path_up (p));
251
edit_dynamic_rep::back_general (path p, bool forward) {
252
tree st= subtree (et, p);
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);
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))));
269
assign (path_up (p), u);
273
remove_argument (p, forward);
276
/******************************************************************************
278
******************************************************************************/
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;
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);
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);
296
else if (is_format (t) || is_func (t, SURROUND)) {
300
r[i]= remove_changes_in (t[i], var);
301
return simplify_correct (r);
307
edit_dynamic_rep::make_with (string var, string val) {
308
if (selection_active_normal ()) {
309
tree t= remove_changes_in (selection_get (), var);
311
insert_tree (tree (WITH, var, val, t), path (2, end (t)));
313
else insert_tree (tree (WITH, var, val, ""), path (2, 0));
317
edit_dynamic_rep::insert_with (path p, string var, tree val) {
318
tree st= subtree (et, p);
319
if (is_func (st, WITH)) {
323
assign (p * (i+1), copy (val));
326
insert (p * n, copy (tree (WITH, var, val)));
328
else if ((!nil (p)) && is_func (subtree (et, path_up (p)), WITH))
329
insert_with (path_up (p), var, val);
332
insert (p * 0, copy (tree (WITH, var, val)));
337
edit_dynamic_rep::remove_with (path p, string var) {
338
tree st= subtree (et, p);
339
if (is_func (st, WITH)) {
344
if (n == 2) rem_unary (p);
348
else if ((!nil (p)) && is_func (subtree (et, path_up (p)), WITH))
349
remove_with (path_up (p), var);
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));
360
else go_to_border (path_up (p), !forward);
363
/******************************************************************************
364
* The HYBRID and LATEX tags
365
******************************************************************************/
368
edit_dynamic_rep::make_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");
381
edit_dynamic_rep::activate_latex () {
382
path p= find_deactivated (tp);
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;
388
if (kbd_get_command (s, help, cmd)) {
391
if (N(st) == 2) insert_tree (copy (st[1]));
395
set_message ("Error: not a command name", "activate latex command");
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);
406
tree st= subtree (et, p * 0);
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);
413
tree mt= subtree (et, mp);
417
assign (p, tree (ARG, copy (name)));
419
correct (path_up (p));
424
// activate macro application
425
tree f= get_env_value (name);
426
if (is_func (f, MACRO) || is_func (f, XMACRO)) {
428
correct (path_up (p));
429
make_compound (make_tree_label (name));
430
if (N(st) == 2) insert_tree (st[1]);
432
else if (f != UNINIT) {
433
assign (p, tree (VALUE, copy (name)));
435
correct (path_up (p));
437
else set_message ("Error: unknown command", "activate hybrid command");
441
/******************************************************************************
442
* Other special tags (SYMBOL and COMPOUND)
443
******************************************************************************/
446
edit_dynamic_rep::activate_symbol () {
447
path p= find_deactivated (tp);
449
tree st= subtree (et, p * 0);
451
if (is_func (st, SYMBOL, 1) && is_atomic (st[0])) {
452
string s= st[0]->label;
454
assign (p, string (((char) as_int (s))));
458
if ((s[i]=='<') || (s[i]=='>'))
460
assign (p, "<" * s * ">");
463
correct (path_up (p));
468
edit_dynamic_rep::activate_compound () {
469
path p= search_upwards (COMPOUND);
471
tree st= subtree (et, p);
472
tree u (make_tree_label (st[0]->label));
473
u << A (st (1, N(st)));
479
/******************************************************************************
480
* Temporary fixes for block structures
481
******************************************************************************/
484
edit_dynamic_rep::make_return_before () {
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));
490
flag= insert_return ();
497
edit_dynamic_rep::make_return_after () {
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 ();
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, ""));