]> git.lyx.org Git - lyx.git/blob - src/cursor.C
c5bbcc5429ca61e63b5a845ab01bfcafde4c52bd
[lyx.git] / src / cursor.C
1 /**
2  * \file cursor.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Alejandro Aguilar Sierra
7  * \author Alfredo Braunstein
8  * \author André Pönitz
9  *
10  * Full author contact details are available in file CREDITS.
11  */
12
13 #include <config.h>
14
15 #include "buffer.h"
16 #include "BufferView.h"
17 #include "cursor.h"
18 #include "debug.h"
19 #include "dispatchresult.h"
20 #include "funcrequest.h"
21 #include "iterators.h"
22 #include "lfuns.h"
23 #include "lyxfunc.h" // only for setMessage()
24 #include "lyxrc.h"
25 #include "lyxrow.h"
26 #include "lyxtext.h"
27 #include "paragraph.h"
28
29 #include "insets/updatableinset.h"
30 #include "insets/insettabular.h"
31 #include "insets/insettext.h"
32
33 #include "mathed/math_data.h"
34 #include "mathed/math_hullinset.h"
35 #include "mathed/math_support.h"
36
37 #include "support/limited_stack.h"
38 #include "frontends/LyXView.h"
39
40 #include <boost/assert.hpp>
41
42 using std::string;
43 using std::vector;
44 using std::endl;
45 #ifndef CXX_GLOBAL_CSTD
46 using std::isalpha;
47 #endif
48 using std::min;
49 using std::swap;
50
51
52
53 // our own cut buffer
54 limited_stack<string> theCutBuffer;
55
56
57 LCursor::LCursor(BufferView & bv)
58         : cursor_(1), anchor_(1), bv_(&bv), current_(0),
59           cached_y_(0), x_target_(-1),
60           selection_(false), mark_(false)
61 {}
62
63
64 void LCursor::reset()
65 {
66         cursor_.clear();
67         anchor_.clear();
68         cursor_.push_back(CursorSlice());
69         anchor_.push_back(CursorSlice());
70         current_ = 0;
71         cached_y_ = 0;
72         clearTargetX();
73         selection_ = false;
74         mark_ = false;
75 }
76
77
78 DispatchResult LCursor::dispatch(FuncRequest const & cmd0)
79 {
80         lyxerr << "\nLCursor::dispatch: cmd: " << cmd0 << endl << *this << endl;
81         FuncRequest cmd = cmd0;
82         for (current_ = cursor_.size() - 1; current_ >= 1; --current_) {
83                 lyxerr << "trying to dispatch to inset " << inset() << endl;
84                 DispatchResult res = inset()->dispatch(*this, cmd);
85                 if (res.dispatched()) {
86                         lyxerr << " successfully dispatched to inset " << inset() << endl;
87                         return DispatchResult(true, true);
88                 }
89                 // "Mutate" the request for semi-handled requests that need
90                 // additional handling in outer levels.
91                 switch (res.val()) {
92                         case FINISHED:
93                                 cmd = FuncRequest(LFUN_FINISHED_LEFT);
94                                 break;
95                         case FINISHED_RIGHT:
96                                 cmd = FuncRequest(LFUN_FINISHED_RIGHT);
97                                 break;
98                         case FINISHED_UP:
99                                 cmd = FuncRequest(LFUN_FINISHED_UP);
100                                 break;
101                         case FINISHED_DOWN:
102                                 cmd = FuncRequest(LFUN_FINISHED_DOWN);
103                                 break;
104                         default:
105                                 //lyxerr << "not handled on level " << current_
106                                 //      << " val: " << res.val() << endl;
107                                 break;
108                 }
109         }
110         BOOST_ASSERT(current_ == 0);
111         //lyxerr << "trying to dispatch to main text " << bv_->text()
112         //      << " with cursor: " << *this << endl;
113         DispatchResult res = bv_->text()->dispatch(*this, cmd);
114         //lyxerr << "   result: " << res.val() << endl;
115         return res;
116 }
117
118
119 void LCursor::push(InsetBase * inset)
120 {
121         lyxerr << "LCursor::push()  inset: " << inset << endl;
122         cursor_.push_back(CursorSlice(inset));
123         anchor_.push_back(CursorSlice(inset));
124         ++current_;
125         updatePos();
126 }
127
128
129 void LCursor::pop(int depth)
130 {
131         while (int(cursor_.size()) > depth + 1)
132                 pop();
133         lyxerr << "LCursor::pop() result: " << *this << endl;
134 }
135
136
137 void LCursor::pop()
138 {
139         BOOST_ASSERT(cursor_.size() >= 1);
140         cursor_.pop_back();
141         anchor_.pop_back();
142         current_ = cursor_.size() - 1;
143 }
144
145
146 void LCursor::pushLeft(InsetBase * p)
147 {
148         BOOST_ASSERT(!cursor_.empty());
149         //lyxerr << "Entering inset " << t << " left" << endl;
150         push(p);
151         p->idxFirst(*this);
152 }
153
154
155 bool LCursor::popLeft()
156 {
157         BOOST_ASSERT(!cursor_.empty());
158         //lyxerr << "Leaving inset to the left" << endl;
159         if (depth() <= 1) {
160                 if (depth() == 1)
161                         inset()->notifyCursorLeaves(idx());
162                 return false;
163         }
164         inset()->notifyCursorLeaves(idx());
165         pop();
166         return true;
167 }
168
169
170 bool LCursor::popRight()
171 {
172         BOOST_ASSERT(!cursor_.empty());
173         //lyxerr << "Leaving inset to the right" << endl;
174         if (depth() <= 1) {
175                 if (depth() == 1)
176                         inset()->notifyCursorLeaves(idx());
177                 return false;
178         }
179         inset()->notifyCursorLeaves(idx());
180         pop();
181         posRight();
182         return true;
183 }
184
185
186 CursorSlice & LCursor::current()
187 {
188         BOOST_ASSERT(!cursor_.empty());
189         //lyxerr << "accessing cursor slice " << current_
190         //      << ": " << cursor_[current_] << endl;
191         return cursor_[current_];
192 }
193
194
195 CursorSlice const & LCursor::current() const
196 {
197         //lyxerr << "accessing cursor slice " << current_
198         //      << ": " << cursor_[current_] << endl;
199         return cursor_[current_];
200 }
201
202
203 int LCursor::currentMode()
204 {
205         BOOST_ASSERT(!cursor_.empty());
206         for (int i = cursor_.size() - 1; i >= 1; --i) {
207                 int res = cursor_[i].inset()->currentMode();
208                 if (res != MathInset::UNDECIDED_MODE)
209                         return res;
210         }
211         return MathInset::TEXT_MODE;
212 }
213
214
215 LyXText * LCursor::innerText() const
216 {
217         BOOST_ASSERT(!cursor_.empty());
218         if (cursor_.size() > 1) {
219                 // go up until first non-0 text is hit
220                 // (innermost text is 0 in mathed)
221                 for (int i = cursor_.size() - 1; i >= 1; --i)
222                         if (cursor_[i].text())
223                                 return cursor_[i].text();
224         }
225         return bv_->text();
226 }
227
228
229 CursorSlice const & LCursor::innerTextSlice() const
230 {
231         BOOST_ASSERT(!cursor_.empty());
232         if (cursor_.size() > 1) {
233                 // go up until first non-0 text is hit
234                 // (innermost text is 0 in mathed)
235                 for (int i = cursor_.size() - 1; i >= 1; --i)
236                         if (cursor_[i].text())
237                                 return cursor_[i];
238         }
239         return cursor_[0];
240 }
241
242
243 void LCursor::updatePos()
244 {
245         BOOST_ASSERT(!cursor_.empty());
246         if (cursor_.size() > 1)
247                 cached_y_ = bv_->top_y() + cursor_.back().inset()->yo();
248                 //cached_y_ = cursor_.back().inset()->yo();
249 }
250
251
252 void LCursor::getDim(int & asc, int & des) const
253 {
254         BOOST_ASSERT(!cursor_.empty());
255         if (inMathed()) {
256                 //inset()->asMathInset()->getCursorDim(asc, des);
257                 asc = 10;
258                 des = 10;
259         } else {
260                 Row const & row = *text()->cursorRow();
261                 asc = row.baseline();
262                 des = row.height() - asc;
263         }
264 }
265
266
267 void LCursor::getPos(int & x, int & y) const
268 {
269         BOOST_ASSERT(!cursor_.empty());
270         x = 0;
271         y = 0;
272         if (cursor_.size() <= 1) {
273                 x = bv_->text()->cursorX(cursor_.front());
274                 y = bv_->text()->cursorY(cursor_.front());
275         } else {
276                 inset()->getCursorPos(cursor_.back(), x, y);
277                 // getCursorPos gives _screen_ coordinates. We need to add
278                 // top_y to get document coordinates. This is hidden in cached_y_.
279                 //y += cached_y_ - inset()->yo();
280                 // The rest is non-obvious. The reason we have to have these
281                 // extra computation is that the getCursorPos() calls rely
282                 // on the inset's own knowledge of its screen position.
283                 // If we scroll up or down in a big enough increment,
284                 // inset->draw() is not called: this doesn't update
285                 // inset.yo_, so getCursor() returns an old value.
286                 // Ugly as you like.
287         }
288         //lyxerr << "#### LCursor::getPos: " << *this 
289         // << " x: " << x << " y: " << y << endl;
290 }
291
292
293 void LCursor::paste(string const & data)
294 {
295         dispatch(FuncRequest(LFUN_PASTE, data));
296 }
297
298
299 InsetBase * LCursor::innerInsetOfType(int code) const
300 {
301         for (int i = cursor_.size() - 1; i >= 1; --i)
302                 if (cursor_[i].inset_->lyxCode() == code)
303                         return cursor_[i].inset_;
304         return 0;
305 }
306
307
308 InsetTabular * LCursor::innerInsetTabular() const
309 {
310         return static_cast<InsetTabular *>(innerInsetOfType(InsetBase::TABULAR_CODE));
311 }
312
313
314 void LCursor::resetAnchor()
315 {
316         anchor_ = cursor_;
317 }
318
319
320 BufferView & LCursor::bv() const
321 {
322         return *bv_;
323 }
324
325
326 MathAtom const & LCursor::prevAtom() const
327 {
328         BOOST_ASSERT(pos() > 0);
329         return cell()[pos() - 1];
330 }
331
332
333 MathAtom & LCursor::prevAtom()
334 {
335         BOOST_ASSERT(pos() > 0);
336         return cell()[pos() - 1];
337 }
338
339
340 MathAtom const & LCursor::nextAtom() const
341 {
342         BOOST_ASSERT(pos() < lastpos());
343         return cell()[pos()];
344 }
345
346
347 MathAtom & LCursor::nextAtom()
348 {
349         BOOST_ASSERT(pos() < lastpos());
350         return cell()[pos()];
351 }
352
353
354 bool LCursor::posLeft()
355 {
356         if (pos() == 0)
357                 return false;
358         --pos();
359         return true;
360 }
361
362
363 bool LCursor::posRight()
364 {
365         if (pos() == lastpos())
366                 return false;
367         ++pos();
368         return true;
369 }
370
371
372 CursorSlice & LCursor::anchor()
373 {
374         return anchor_.back();
375 }
376
377
378 CursorSlice const & LCursor::anchor() const
379 {
380         return anchor_.back();
381 }
382
383
384 CursorSlice const & LCursor::selBegin() const
385 {
386         if (!selection())
387                 return cursor_.back();
388         // can't use std::min as this creates a new object
389         return anchor() < cursor_.back() ? anchor() : cursor_.back();
390 }
391
392
393 CursorSlice & LCursor::selBegin()
394 {
395         if (!selection())
396                 return cursor_.back();
397         return anchor() < cursor_.back() ? anchor() : cursor_.back();
398 }
399
400
401 CursorSlice const & LCursor::selEnd() const
402 {
403         if (!selection())
404                 return cursor_.back();
405         return anchor() > cursor_.back() ? anchor() : cursor_.back();
406 }
407
408
409 CursorSlice & LCursor::selEnd()
410 {
411         if (selection())
412                 return cursor_.back();
413         return anchor() > cursor_.back() ? anchor() : cursor_.back();
414 }
415
416
417 void LCursor::setSelection()
418 {
419         selection() = true;
420         // a selection with no contents is not a selection
421         if (par() == anchor().par() && pos() == anchor().pos())
422                 selection() = false;
423 }
424
425
426 void LCursor::setSelection(CursorBase const & where, size_t n)
427 {
428         selection() = true;
429         cursor_ = where;
430         anchor_ = where;
431         pos() += n;
432 }
433
434
435 void LCursor::clearSelection()
436 {
437         selection() = false;
438         mark() = false;
439         resetAnchor();
440         bv().unsetXSel();
441 }
442
443
444 int & LCursor::x_target()
445 {
446         return x_target_;
447 }
448
449
450 int LCursor::x_target() const
451 {
452         return x_target_;
453 }
454
455
456 void LCursor::clearTargetX()
457 {
458         x_target_ = -1;
459 }
460
461
462 LyXText * LCursor::text() const
463 {
464         return current_ ? current().text() : bv_->text();
465 }
466
467
468 Paragraph & LCursor::paragraph()
469 {
470         BOOST_ASSERT(!inMathed());
471         return current_ ? current().paragraph() : *bv_->text()->getPar(par());
472 }
473
474
475 Paragraph const & LCursor::paragraph() const
476 {
477         BOOST_ASSERT(!inMathed());
478         return current_ ? current().paragraph() : *bv_->text()->getPar(par());
479 }
480
481
482 LCursor::par_type LCursor::lastpar() const
483 {
484         return inMathed() ? 0 : text()->paragraphs().size() - 1;
485 }
486
487
488 LCursor::pos_type LCursor::lastpos() const
489 {
490         InsetBase * inset = current().inset();
491         return inset && inset->asMathInset() ? cell().size() : paragraph().size();
492 }
493
494
495 LCursor::row_type LCursor::crow() const
496 {
497         return paragraph().row(pos());
498 }
499
500
501 LCursor::row_type LCursor::lastcrow() const
502 {
503         return paragraph().rows.size();
504 }
505
506
507 size_t LCursor::nargs() const
508 {
509         // assume 1x1 grid for 'plain text'
510         return current_ ? current().nargs() : 1;
511 }
512
513
514 size_t LCursor::ncols() const
515 {
516         // assume 1x1 grid for 'plain text'
517         return current_ ? current().ncols() : 1;
518 }
519
520
521 size_t LCursor::nrows() const
522 {
523         // assume 1x1 grid for 'plain text'
524         return current_ ? current().nrows() : 1;
525 }
526
527
528 LCursor::row_type LCursor::row() const
529 {
530         BOOST_ASSERT(current_ > 0);
531         return current().row();
532 }
533
534
535 LCursor::col_type LCursor::col() const
536 {
537         BOOST_ASSERT(current_ > 0);
538         return current().col();
539 }
540
541
542 MathArray const & LCursor::cell() const
543 {
544         BOOST_ASSERT(current_ > 0);
545         return current().cell();
546 }
547
548
549 MathArray & LCursor::cell()
550 {
551         BOOST_ASSERT(current_ > 0);
552         return current().cell();
553 }
554
555
556 void LCursor::info(std::ostream & os)
557 {
558         for (int i = 1, n = depth(); i < n; ++i) {
559                 cursor_[i].inset()->infoize(os);
560                 os << "  ";
561         }
562         if (pos() != 0)
563                 prevInset()->infoize2(os);
564         // overwite old message
565         os << "                    ";
566 }
567
568
569 namespace {
570
571 void region(CursorSlice const & i1, CursorSlice const & i2,
572         LCursor::row_type & r1, LCursor::row_type & r2,
573         LCursor::col_type & c1, LCursor::col_type & c2)
574 {
575         InsetBase * p = i1.inset();
576         c1 = p->col(i1.idx_);
577         c2 = p->col(i2.idx_);
578         if (c1 > c2)
579                 swap(c1, c2);
580         r1 = p->row(i1.idx_);
581         r2 = p->row(i2.idx_);
582         if (r1 > r2)
583                 swap(r1, r2);
584 }
585
586 }
587
588
589 string LCursor::grabSelection()
590 {
591         if (!selection())
592                 return string();
593
594         CursorSlice i1 = selBegin();
595         CursorSlice i2 = selEnd();
596
597         if (i1.idx_ == i2.idx_) {
598                 if (i1.inset()->asMathInset()) {
599                         MathArray::const_iterator it = i1.cell().begin();
600                         return asString(MathArray(it + i1.pos_, it + i2.pos_));
601                 } else {
602                         return "unknown selection 1";
603                 }
604         }
605
606         row_type r1, r2;
607         col_type c1, c2;
608         region(i1, i2, r1, r2, c1, c2);
609
610         string data;
611         if (i1.inset()->asMathInset()) {
612                 for (row_type row = r1; row <= r2; ++row) {
613                         if (row > r1)
614                                 data += "\\\\";
615                         for (col_type col = c1; col <= c2; ++col) {
616                                 if (col > c1)
617                                         data += '&';
618                                 data += asString(i1.asMathInset()->cell(i1.asMathInset()->index(row, col)));
619                         }
620                 }
621         } else {
622                 data = "unknown selection 2";
623         }
624         return data;
625 }
626
627
628 void LCursor::eraseSelection()
629 {
630         CursorSlice i1 = selBegin();
631         CursorSlice i2 = selEnd();
632 #warning FIXME
633         if (i1.inset()->asMathInset()) {
634                 if (i1.idx_ == i2.idx_) {
635                         i1.cell().erase(i1.pos_, i2.pos_);
636                 } else {
637                         MathInset * p = i1.asMathInset();
638                         row_type r1, r2;
639                         col_type c1, c2;
640                         region(i1, i2, r1, r2, c1, c2);
641                         for (row_type row = r1; row <= r2; ++row)
642                                 for (col_type col = c1; col <= c2; ++col)
643                                         p->cell(p->index(row, col)).clear();
644                 }
645                 current() = i1;
646         } else {
647                 lyxerr << "can't erase this selection 1" << endl;
648         }
649 }
650
651
652 string LCursor::grabAndEraseSelection()
653 {
654         if (!selection())
655                 return string();
656         string res = grabSelection();
657         eraseSelection();
658         selection() = false;
659         return res;
660 }
661
662
663 void LCursor::selClear()
664 {
665         resetAnchor();
666         clearSelection();
667 }
668
669
670 void LCursor::selCopy()
671 {
672         if (selection()) {
673                 theCutBuffer.push(grabSelection());
674                 selection() = false;
675         } else {
676                 //theCutBuffer.erase();
677         }
678 }
679
680
681 void LCursor::selCut()
682 {
683         theCutBuffer.push(grabAndEraseSelection());
684 }
685
686
687 void LCursor::selDel()
688 {
689         if (selection()) {
690                 eraseSelection();
691                 selection() = false;
692         }
693 }
694
695
696 void LCursor::selPaste(size_t n)
697 {
698         selClearOrDel();
699         if (n < theCutBuffer.size())
700                 paste(theCutBuffer[n]);
701         //grabSelection();
702         selection() = false;
703 }
704
705
706 void LCursor::selHandle(bool sel)
707 {
708         if (sel == selection())
709                 return;
710         resetAnchor();
711         selection() = sel;
712 }
713
714
715 void LCursor::selStart()
716 {
717         resetAnchor();
718         selection() = true;
719 }
720
721
722 void LCursor::selClearOrDel()
723 {
724         if (lyxrc.auto_region_delete)
725                 selDel();
726         else
727                 selection() = false;
728 }
729
730
731 std::ostream & operator<<(std::ostream & os, LCursor const & cur)
732 {
733         os << "\n";
734         for (size_t i = 0, n = cur.cursor_.size(); i != n; ++i)
735                 os << "  (" << cur.cursor_[i] << " | " << cur.anchor_[i] << "\n";
736         return os << "current: " << cur.current_ << endl;
737 }
738
739
740
741
742 //
743 // CursorBase
744 //
745
746
747 void increment(CursorBase & it)
748 {
749         CursorSlice & top = it.back();
750         MathArray & ar = top.asMathInset()->cell(top.idx_);
751
752         // move into the current inset if possible
753         // it is impossible for pos() == size()!
754         MathInset * n = 0;
755         if (top.pos() != top.lastpos())
756                 n = (ar.begin() + top.pos_)->nucleus();
757         if (n && n->isActive()) {
758                 it.push_back(CursorSlice(n));
759                 return;
760         }
761
762         // otherwise move on one cell back if possible
763         if (top.pos() < top.lastpos()) {
764                 // pos() == lastpos() is valid!
765                 ++top.pos_;
766                 return;
767         }
768
769         // otherwise try to move on one cell if possible
770         while (top.idx() < top.lastidx()) {
771                 ++top.idx_;
772                 if (top.asMathInset()->validCell(top.idx_)) {
773                         top.pos_ = 0;
774                         return;
775                 }
776         }
777
778         // otherwise leave array, move on one back
779         // this might yield pos() == size(), but that's a ok.
780         it.pop_back();
781         // it certainly invalidates top
782         ++it.back().pos_;
783 }
784
785
786 CursorBase ibegin(InsetBase * p)
787 {
788         CursorBase it;
789         it.push_back(CursorSlice(p));
790         return it;
791 }
792
793
794 CursorBase iend(InsetBase * p)
795 {
796         CursorBase it;
797         it.push_back(CursorSlice(p));
798         CursorSlice & cur = it.back();
799         cur.idx() = cur.lastidx();
800         cur.pos() = cur.lastpos();
801         return it;
802 }
803
804
805
806
807 ///////////////////////////////////////////////////////////////////
808 //
809 // The part below is the non-integrated rest of the original math
810 // cursor. This should be either generalized for texted or moved
811 // back to the math insets.
812 //
813 ///////////////////////////////////////////////////////////////////
814
815 #include "mathed/math_braceinset.h"
816 #include "mathed/math_charinset.h"
817 #include "mathed/math_commentinset.h"
818 #include "mathed/math_factory.h"
819 #include "mathed/math_gridinset.h"
820 #include "mathed/math_macroarg.h"
821 #include "mathed/math_macrotemplate.h"
822 #include "mathed/math_mathmlstream.h"
823 #include "mathed/math_scriptinset.h"
824 #include "mathed/math_spaceinset.h"
825 #include "mathed/math_support.h"
826 #include "mathed/math_unknowninset.h"
827
828 //#define FILEDEBUG 1
829
830
831 bool LCursor::isInside(InsetBase const * p)
832 {
833         for (unsigned i = 0; i < depth(); ++i)
834                 if (cursor_[i].inset() == p)
835                         return true;
836         return false;
837 }
838
839
840 bool LCursor::openable(MathAtom const & t)
841 {
842         if (!t->isActive())
843                 return false;
844
845         if (t->lock())
846                 return false;
847
848         if (!selection())
849                 return true;
850
851         // we can't move into anything new during selection
852         if (depth() == anchor_.size())
853                 return false;
854         if (!ptr_cmp(t.nucleus(), anchor_[depth()].inset()))
855                 return false;
856
857         return true;
858 }
859
860
861 bool LCursor::inNucleus()
862 {
863         return inset()->asMathInset()->asScriptInset() && idx() == 2;
864 }
865
866
867 bool LCursor::left()
868 {
869         autocorrect() = false;
870         clearTargetX();
871         if (inMacroMode()) {
872                 macroModeClose();
873                 return true;
874         }
875
876         if (pos() != 0 && openable(prevAtom())) {
877                 posLeft();
878                 push(nextAtom().nucleus());
879                 inset()->idxLast(*this);
880                 return true;
881         }
882
883         return posLeft() || idxLeft() || popLeft() || selection();
884 }
885
886
887 bool LCursor::right()
888 {
889         autocorrect() = false;
890         clearTargetX();
891         if (inMacroMode()) {
892                 macroModeClose();
893                 return true;
894         }
895
896         if (pos() != lastpos() && openable(nextAtom())) {
897                 pushLeft(nextAtom().nucleus());
898                 inset()->idxFirst(*this);
899                 return true;
900         }
901
902         return posRight() || idxRight() || popRight() || selection();
903 }
904
905
906 bool positionable(CursorBase const & cursor, CursorBase const & anchor)
907 {
908         // avoid deeper nested insets when selecting
909         if (cursor.size() > anchor.size())
910                 return false;
911
912         // anchor might be deeper, should have same path then
913         for (size_t i = 0; i < cursor.size(); ++i)
914                 if (cursor[i].inset() != anchor[i].inset())
915                         return false;
916
917         // position should be ok.
918         return true;
919 }
920
921
922 void LCursor::setScreenPos(int x, int y)
923 {
924         bool res = bruteFind(x, y, formula()->xlow(), formula()->xhigh(),
925                 formula()->ylow(), formula()->yhigh());
926         if (!res) {
927                 // this can happen on creation of "math-display"
928                 idx() = 0;
929                 pos() = 0;
930         }
931         clearTargetX();
932 }
933
934
935
936 bool LCursor::home()
937 {
938         autocorrect() = false;
939         macroModeClose();
940         if (!inset()->idxHome(*this))
941                 return popLeft();
942         clearTargetX();
943         return true;
944 }
945
946
947 bool LCursor::end()
948 {
949         autocorrect() = false;
950         macroModeClose();
951         if (!inset()->idxEnd(*this))
952                 return popRight();
953         clearTargetX();
954         return true;
955 }
956
957
958 void LCursor::plainErase()
959 {
960         cell().erase(pos());
961 }
962
963
964 void LCursor::markInsert()
965 {
966         cell().insert(pos(), MathAtom(new MathCharInset(0)));
967 }
968
969
970 void LCursor::markErase()
971 {
972         cell().erase(pos());
973 }
974
975
976 void LCursor::plainInsert(MathAtom const & t)
977 {
978         cell().insert(pos(), t);
979         ++pos();
980 }
981
982
983 void LCursor::insert2(string const & str)
984 {
985         MathArray ar;
986         asArray(str, ar);
987         insert(ar);
988 }
989
990
991 void LCursor::insert(string const & str)
992 {
993         lyxerr << "inserting '" << str << "'" << endl;
994         selClearOrDel();
995         for (string::const_iterator it = str.begin(); it != str.end(); ++it)
996                 plainInsert(MathAtom(new MathCharInset(*it)));
997 }
998
999
1000 void LCursor::insert(char c)
1001 {
1002         lyxerr << "inserting '" << c << "'" << endl;
1003         selClearOrDel();
1004         plainInsert(MathAtom(new MathCharInset(c)));
1005 }
1006
1007
1008 void LCursor::insert(MathAtom const & t)
1009 {
1010         macroModeClose();
1011         selClearOrDel();
1012         plainInsert(t);
1013 }
1014
1015
1016 void LCursor::niceInsert(string const & t)
1017 {
1018         lyxerr << "*** LCursor::niceInsert 1: " << t << endl;
1019         MathArray ar;
1020         asArray(t, ar);
1021         if (ar.size() == 1)
1022                 niceInsert(ar[0]);
1023         else
1024                 insert(ar);
1025 }
1026
1027
1028 void LCursor::niceInsert(MathAtom const & t)
1029 {
1030         lyxerr << "*** LCursor::niceInsert 2: " << t << endl;
1031         macroModeClose();
1032         string safe = grabAndEraseSelection();
1033         plainInsert(t);
1034         // enter the new inset and move the contents of the selection if possible
1035         if (t->isActive()) {
1036                 posLeft();
1037                 pushLeft(nextAtom().nucleus());
1038                 paste(safe);
1039         }
1040         lyxerr << "*** LCursor::niceInsert 3: " << t << endl;
1041 }
1042
1043
1044 void LCursor::insert(MathArray const & ar)
1045 {
1046         macroModeClose();
1047         if (selection())
1048                 eraseSelection();
1049         cell().insert(pos(), ar);
1050         pos() += ar.size();
1051 }
1052
1053
1054 bool LCursor::backspace()
1055 {
1056         autocorrect() = false;
1057
1058         if (selection()) {
1059                 selDel();
1060                 return true;
1061         }
1062
1063         if (pos() == 0) {
1064                 if (inset()->nargs() == 1 && depth() == 1 && lastpos() == 0)
1065                         return false;
1066                 pullArg();
1067                 return true;
1068         }
1069
1070         if (inMacroMode()) {
1071                 MathUnknownInset * p = activeMacro();
1072                 if (p->name().size() > 1) {
1073                         p->setName(p->name().substr(0, p->name().size() - 1));
1074                         return true;
1075                 }
1076         }
1077
1078         if (pos() != 0 && prevAtom()->nargs() > 0) {
1079                 // let's require two backspaces for 'big stuff' and
1080                 // highlight on the first
1081                 selection() = true;
1082                 left();
1083         } else {
1084                 --pos();
1085                 plainErase();
1086         }
1087         return true;
1088 }
1089
1090
1091 bool LCursor::erase()
1092 {
1093         autocorrect() = false;
1094         if (inMacroMode())
1095                 return true;
1096
1097         if (selection()) {
1098                 selDel();
1099                 return true;
1100         }
1101
1102         // delete empty cells if possible
1103         if (pos() == lastpos() && inset()->idxDelete(idx()))
1104                 return true;
1105
1106         // special behaviour when in last position of cell
1107         if (pos() == lastpos()) {
1108                 bool one_cell = inset()->nargs() == 1;
1109                 if (one_cell && depth() == 1 && lastpos() == 0)
1110                         return false;
1111                 // remove markup
1112                 if (one_cell)
1113                         pullArg();
1114                 else
1115                         inset()->idxGlue(idx());
1116                 return true;
1117         }
1118
1119         if (pos() != lastpos() && inset()->nargs() > 0) {
1120                 selection() = true;
1121                 right();
1122         } else {
1123                 plainErase();
1124         }
1125
1126         return true;
1127 }
1128
1129
1130 bool LCursor::up()
1131 {
1132         macroModeClose();
1133         CursorBase save = cursor_;
1134         if (goUpDown(true))
1135                 return true;
1136         cursor_ = save;
1137         autocorrect() = false;
1138         return selection();
1139 }
1140
1141
1142 bool LCursor::down()
1143 {
1144         macroModeClose();
1145         CursorBase save = cursor_;
1146         if (goUpDown(false))
1147                 return true;
1148         cursor_ = save;
1149         autocorrect() = false;
1150         return selection();
1151 }
1152
1153
1154 void LCursor::macroModeClose()
1155 {
1156         if (!inMacroMode())
1157                 return;
1158         MathUnknownInset * p = activeMacro();
1159         p->finalize();
1160         string s = p->name();
1161         --pos();
1162         cell().erase(pos());
1163
1164         // do nothing if the macro name is empty
1165         if (s == "\\")
1166                 return;
1167
1168         string const name = s.substr(1);
1169
1170         // prevent entering of recursive macros
1171         if (formula()->lyxCode() == InsetOld::MATHMACRO_CODE
1172                         && formula()->getInsetName() == name)
1173                 lyxerr << "can't enter recursive macro" << endl;
1174
1175         niceInsert(createMathInset(name));
1176 }
1177
1178
1179 string LCursor::macroName()
1180 {
1181         return inMacroMode() ? activeMacro()->name() : string();
1182 }
1183
1184
1185 void LCursor::handleNest(MathAtom const & a, int c)
1186 {
1187         MathAtom t = a;
1188         asArray(grabAndEraseSelection(), t.nucleus()->cell(c));
1189         insert(t);
1190         posLeft();
1191         pushLeft(t.nucleus());
1192 }
1193
1194
1195 int LCursor::targetX() const
1196 {
1197         if (x_target() != -1)
1198                 return x_target();
1199         int x = 0;
1200         int y = 0;
1201         getPos(x, y);
1202         return x;
1203 }
1204
1205
1206 MathHullInset * LCursor::formula() const
1207 {
1208         for (int i = cursor_.size() - 1; i >= 1; --i)
1209                 if (cursor_[i].inset()->lyxCode() == InsetBase::MATH_CODE)
1210                         return static_cast<MathHullInset *>(cursor_[i].inset());
1211         return 0;
1212 }
1213
1214
1215 void LCursor::adjust(pos_type from, int diff)
1216 {
1217         if (pos() > from)
1218                 pos() += diff;
1219         if (anchor().pos_ > from)
1220                 anchor().pos_ += diff;
1221         // just to be on the safe side
1222         // theoretically unecessary
1223         normalize();
1224 }
1225
1226
1227 bool LCursor::inMacroMode() const
1228 {
1229         if (!pos() != 0)
1230                 return false;
1231         MathUnknownInset const * p = prevAtom()->asUnknownInset();
1232         return p && !p->final();
1233 }
1234
1235
1236 MathUnknownInset * LCursor::activeMacro()
1237 {
1238         return inMacroMode() ? prevAtom().nucleus()->asUnknownInset() : 0;
1239 }
1240
1241
1242 bool LCursor::inMacroArgMode() const
1243 {
1244         return pos() > 0 && prevAtom()->getChar() == '#';
1245 }
1246
1247
1248 MathGridInset * LCursor::enclosingGrid(idx_type & idx) const
1249 {
1250         for (MathInset::difference_type i = depth() - 1; i >= 0; --i) {
1251                 MathInset * m = cursor_[i].inset()->asMathInset();
1252                 if (!m)
1253                         return 0;
1254                 MathGridInset * p = m->asGridInset();
1255                 if (p) {
1256                         idx = cursor_[i].idx_;
1257                         return p;
1258                 }
1259         }
1260         return 0;
1261 }
1262
1263
1264 void LCursor::pullArg()
1265 {
1266 #warning look here
1267 #if 0
1268         MathArray ar = cell();
1269         if (popLeft()) {
1270                 plainErase();
1271                 cell().insert(pos(), ar);
1272                 resetAnchor();
1273         } else {
1274                 formula()->mutateToText();
1275         }
1276 #endif
1277 }
1278
1279
1280 void LCursor::touch()
1281 {
1282 #warning look here
1283 #if 0
1284         CursorBase::const_iterator it = cursor_.begin();
1285         CursorBase::const_iterator et = cursor_.end();
1286         for ( ; it != et; ++it)
1287                 it->cell().touch();
1288 #endif
1289 }
1290
1291
1292 void LCursor::normalize()
1293 {
1294         if (idx() >= nargs()) {
1295                 lyxerr << "this should not really happen - 1: "
1296                        << idx() << ' ' << nargs()
1297                        << " in: " << inset() << endl;
1298         }
1299         idx() = min(idx(), lastidx());
1300
1301         if (pos() > lastpos()) {
1302                 lyxerr << "this should not really happen - 2: "
1303                         << pos() << ' ' << lastpos() <<  " in idx: " << idx()
1304                        << " in atom: '";
1305                 WriteStream wi(lyxerr, false, true);
1306                 inset()->asMathInset()->write(wi);
1307                 lyxerr << endl;
1308         }
1309         pos() = min(pos(), lastpos());
1310 }
1311
1312
1313 char LCursor::valign()
1314 {
1315         idx_type idx;
1316         MathGridInset * p = enclosingGrid(idx);
1317         return p ? p->valign() : '\0';
1318 }
1319
1320
1321 char LCursor::halign()
1322 {
1323         idx_type idx;
1324         MathGridInset * p = enclosingGrid(idx);
1325         return p ? p->halign(idx % p->ncols()) : '\0';
1326 }
1327
1328
1329 bool LCursor::goUpDown(bool up)
1330 {
1331         // Be warned: The 'logic' implemented in this function is highly fragile.
1332         // A distance of one pixel or a '<' vs '<=' _really_ matters.
1333         // So fiddle around with it only if you know what you are doing!
1334   int xo = 0;
1335         int yo = 0;
1336         getPos(xo, yo);
1337
1338         // check if we had something else in mind, if not, this is the future goal
1339         if (x_target() == -1)
1340                 x_target() = xo;
1341         else
1342                 xo = x_target();
1343
1344         // try neigbouring script insets
1345         if (!selection()) {
1346                 // try left
1347                 if (pos() != 0) {
1348                         MathScriptInset const * p = prevAtom()->asScriptInset();
1349                         if (p && p->has(up)) {
1350                                 --pos();
1351                                 push(inset());
1352                                 idx() = up; // the superscript has index 1
1353                                 pos() = lastpos();
1354                                 //lyxerr << "updown: handled by scriptinset to the left" << endl;
1355                                 return true;
1356                         }
1357                 }
1358
1359                 // try right
1360                 if (pos() != lastpos()) {
1361                         MathScriptInset const * p = nextAtom()->asScriptInset();
1362                         if (p && p->has(up)) {
1363                                 push(inset());
1364                                 idx() = up;
1365                                 pos() = 0;
1366                                 //lyxerr << "updown: handled by scriptinset to the right" << endl;
1367                                 return true;
1368                         }
1369                 }
1370         }
1371
1372         // try current cell for e.g. text insets
1373         if (inset()->idxUpDown2(*this, up))
1374                 return true;
1375
1376         //xarray().boundingBox(xlow, xhigh, ylow, yhigh);
1377         //if (up)
1378         //      yhigh = yo - 4;
1379         //else
1380         //      ylow = yo + 4;
1381         //if (bruteFind(xo, yo, xlow, xhigh, ylow, yhigh)) {
1382         //      lyxerr << "updown: handled by brute find in the same cell" << endl;
1383         //      return true;
1384         //}
1385
1386         // try to find an inset that knows better then we
1387         while (1) {
1388                 //lyxerr << "updown: We are in " << inset() << " idx: " << idx() << endl;
1389                 // ask inset first
1390                 if (inset()->idxUpDown(*this, up)) {
1391                         // try to find best position within this inset
1392                         if (!selection())
1393                                 bruteFind2(xo, yo);
1394                         return true;
1395                 }
1396
1397                 // no such inset found, just take something "above"
1398                 //lyxerr << "updown: handled by strange case" << endl;
1399                 if (!popLeft()) {
1400                         return
1401                                 bruteFind(xo, yo,
1402                                         formula()->xlow(),
1403                                         formula()->xhigh(),
1404                                         up ? formula()->ylow() : yo + 4,
1405                                         up ? yo - 4 : formula()->yhigh()
1406                                 );
1407                 }
1408
1409                 // any improvement so far?
1410                 int xnew, ynew;
1411                 getPos(xnew, ynew);
1412                 if (up ? ynew < yo : ynew > yo)
1413                         return true;
1414         }
1415 }
1416
1417
1418 bool LCursor::bruteFind(int x, int y, int xlow, int xhigh, int ylow, int yhigh)
1419 {
1420         CursorBase best_cursor;
1421         double best_dist = 1e10;
1422
1423         CursorBase it = ibegin(formula());
1424         CursorBase et = iend(formula());
1425         while (1) {
1426                 // avoid invalid nesting when selecting
1427                 if (!selection() || positionable(it, anchor_)) {
1428                         int xo, yo;
1429                         CursorSlice & cur = it.back();
1430                         cur.inset()->getCursorPos(cur, xo, yo);
1431                         if (xlow <= xo && xo <= xhigh && ylow <= yo && yo <= yhigh) {
1432                                 double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
1433                                 //lyxerr << "x: " << x << " y: " << y << " d: " << endl;
1434                                 // '<=' in order to take the last possible position
1435                                 // this is important for clicking behind \sum in e.g. '\sum_i a'
1436                                 if (d <= best_dist) {
1437                                         best_dist   = d;
1438                                         best_cursor = it;
1439                                 }
1440                         }
1441                 }
1442
1443                 if (it == et)
1444                         break;
1445                 increment(it);
1446         }
1447
1448         if (best_dist < 1e10)
1449                 cursor_ = best_cursor;
1450         return best_dist < 1e10;
1451 }
1452
1453
1454 void LCursor::bruteFind2(int x, int y)
1455 {
1456         double best_dist = 1e10;
1457
1458         CursorBase it = cursor_;
1459         it.back().pos(0);
1460         CursorBase et = cursor_;
1461         int n = et.back().asMathInset()->cell(et.back().idx_).size();
1462         et.back().pos(n);
1463         for (int i = 0; ; ++i) {
1464                 int xo, yo;
1465                 CursorSlice & cur = it.back();
1466                 cur.inset()->getCursorPos(cur, xo, yo);
1467                 double d = (x - xo) * (x - xo) + (y - yo) * (y - yo);
1468                 // '<=' in order to take the last possible position
1469                 // this is important for clicking behind \sum in e.g. '\sum_i a'
1470                 lyxerr << "i: " << i << " d: " << d << " best: " << best_dist << endl;
1471                 if (d <= best_dist) {
1472                         best_dist = d;
1473                         cursor_ = it;
1474                 }
1475                 if (it == et)
1476                         break;
1477                 increment(it);
1478         }
1479 }
1480
1481
1482 bool LCursor::idxLineLast()
1483 {
1484         idx() -= idx() % ncols();
1485         idx() += ncols() - 1;
1486         pos() = lastpos();
1487         return true;
1488 }
1489
1490
1491 bool LCursor::idxLeft()
1492 {
1493         return inset()->idxLeft(*this);
1494 }
1495
1496
1497 bool LCursor::idxRight()
1498 {
1499         return inset()->idxRight(*this);
1500 }
1501
1502
1503 bool LCursor::script(bool up)
1504 {
1505         // Hack to get \\^ and \\_ working
1506         lyxerr << "handling script: up: " << up << endl;
1507         if (inMacroMode() && macroName() == "\\") {
1508                 if (up)
1509                         niceInsert(createMathInset("mathcircumflex"));
1510                 else
1511                         interpret('_');
1512                 return true;
1513         }
1514
1515         macroModeClose();
1516         string safe = grabAndEraseSelection();
1517         if (inNucleus()) {
1518                 // we are in a nucleus of a script inset, move to _our_ script
1519                 inset()->asMathInset()->asScriptInset()->ensure(up);
1520                 idx() = up;
1521                 pos() = 0;
1522         } else if (pos() != 0 && prevAtom()->asScriptInset()) {
1523                 --pos();
1524                 nextAtom().nucleus()->asScriptInset()->ensure(up);
1525                 push(nextInset());
1526                 idx() = up;
1527                 pos() = lastpos();
1528         } else if (pos() != 0) {
1529                 --pos();
1530                 cell()[pos()] = MathAtom(new MathScriptInset(nextAtom(), up));
1531                 push(nextInset());
1532                 idx() = up;
1533                 pos() = 0;
1534         } else {
1535                 plainInsert(MathAtom(new MathScriptInset(up)));
1536                 --pos();
1537                 nextAtom().nucleus()->asScriptInset()->ensure(up);
1538                 push(nextInset());
1539                 idx() = up;
1540                 pos() = 0;
1541         }
1542         paste(safe);
1543         return true;
1544 }
1545
1546
1547 bool LCursor::interpret(char c)
1548 {
1549         //lyxerr << "interpret 2: '" << c << "'" << endl;
1550         clearTargetX();
1551         if (inMacroArgMode()) {
1552                 posLeft();
1553                 plainErase();
1554 #warning FIXME
1555 #if 0
1556                 int n = c - '0';
1557                 MathMacroTemplate const * p = formula()->asMacroTemplate();
1558                 if (p && 1 <= n && n <= p->numargs())
1559                         insert(MathAtom(new MathMacroArgument(c - '0')));
1560                 else {
1561                         insert(createMathInset("#"));
1562                         interpret(c); // try again
1563                 }
1564 #endif
1565                 return true;
1566         }
1567
1568         // handle macroMode
1569         if (inMacroMode()) {
1570                 string name = macroName();
1571                 //lyxerr << "interpret name: '" << name << "'" << endl;
1572
1573                 if (isalpha(c)) {
1574                         activeMacro()->setName(activeMacro()->name() + c);
1575                         return true;
1576                 }
1577
1578                 // handle 'special char' macros
1579                 if (name == "\\") {
1580                         // remove the '\\'
1581                         backspace();
1582                         if (c == '\\') {
1583                                 if (currentMode() == MathInset::TEXT_MODE)
1584                                         niceInsert(createMathInset("textbackslash"));
1585                                 else
1586                                         niceInsert(createMathInset("backslash"));
1587                         } else if (c == '{') {
1588                                 niceInsert(MathAtom(new MathBraceInset));
1589                         } else {
1590                                 niceInsert(createMathInset(string(1, c)));
1591                         }
1592                         return true;
1593                 }
1594
1595                 // leave macro mode and try again if necessary
1596                 macroModeClose();
1597                 if (c == '{')
1598                         niceInsert(MathAtom(new MathBraceInset));
1599                 else if (c != ' ')
1600                         interpret(c);
1601                 return true;
1602         }
1603
1604         // This is annoying as one has to press <space> far too often.
1605         // Disable it.
1606
1607         if (0) {
1608                 // leave autocorrect mode if necessary
1609                 if (autocorrect() && c == ' ') {
1610                         autocorrect() = false;
1611                         return true;
1612                 }
1613         }
1614
1615         // just clear selection on pressing the space bar
1616         if (selection() && c == ' ') {
1617                 selection() = false;
1618                 return true;
1619         }
1620
1621         selClearOrDel();
1622
1623         if (c == '\\') {
1624                 //lyxerr << "starting with macro" << endl;
1625                 insert(MathAtom(new MathUnknownInset("\\", false)));
1626                 return true;
1627         }
1628
1629         if (c == '\n') {
1630                 if (currentMode() == MathInset::TEXT_MODE)
1631                         insert(c);
1632                 return true;
1633         }
1634
1635         if (c == ' ') {
1636                 if (currentMode() == MathInset::TEXT_MODE) {
1637                         // insert spaces in text mode,
1638                         // but suppress direct insertion of two spaces in a row
1639                         // the still allows typing  '<space>a<space>' and deleting the 'a', but
1640                         // it is better than nothing...
1641                         if (!pos() != 0 || prevAtom()->getChar() != ' ')
1642                                 insert(c);
1643                         return true;
1644                 }
1645                 if (pos() != 0 && prevAtom()->asSpaceInset()) {
1646                         prevAtom().nucleus()->asSpaceInset()->incSpace();
1647                         return true;
1648                 }
1649                 if (popRight())
1650                         return true;
1651                 // if are at the very end, leave the formula
1652                 return pos() != lastpos();
1653         }
1654
1655         if (c == '_') {
1656                 script(false);
1657                 return true;
1658         }
1659
1660         if (c == '^') {
1661                 script(true);
1662                 return true;
1663         }
1664
1665         if (c == '{' || c == '}' || c == '#' || c == '&' || c == '$') {
1666                 niceInsert(createMathInset(string(1, c)));
1667                 return true;
1668         }
1669
1670         if (c == '%') {
1671                 niceInsert(MathAtom(new MathCommentInset));
1672                 return true;
1673         }
1674
1675         // try auto-correction
1676         //if (autocorrect() && hasPrevAtom() && math_autocorrect(prevAtom(), c))
1677         //      return true;
1678
1679         // no special circumstances, so insert the character without any fuss
1680         insert(c);
1681         autocorrect() = true;
1682         return true;
1683 }
1684
1685
1686 void LCursor::lockToggle()
1687 {
1688         if (pos() != lastpos()) {
1689                 // toggle previous inset ...
1690                 nextAtom().nucleus()->lock(!nextAtom()->lock());
1691         } else if (popLeft() && pos() != lastpos()) {
1692                 // ... or enclosing inset if we are in the last inset position
1693                 nextAtom().nucleus()->lock(!nextAtom()->lock());
1694                 posRight();
1695         }
1696 }
1697
1698
1699 CursorSlice LCursor::normalAnchor()
1700 {
1701         if (anchor_.size() < depth()) {
1702                 resetAnchor();
1703                 lyxerr << "unusual Anchor size" << endl;
1704         }
1705         //lyx::BOOST_ASSERT(Anchor_.size() >= cursor.depth());
1706         // use Anchor on the same level as Cursor
1707         CursorSlice normal = anchor_[current_];
1708 #if 0
1709         if (depth() < anchor_.size() && !(normal < xx())) {
1710                 // anchor is behind cursor -> move anchor behind the inset
1711                 ++normal.pos_;
1712         }
1713 #endif
1714         return normal;
1715 }
1716
1717
1718 /*
1719 DispatchResult dispatch(LCursor & cur, FuncRequest const & cmd)
1720 {
1721         // mouse clicks are somewhat special
1722         // check
1723         switch (cmd.action) {
1724         case LFUN_MOUSE_PRESS:
1725         case LFUN_MOUSE_MOTION:
1726         case LFUN_MOUSE_RELEASE:
1727         case LFUN_MOUSE_DOUBLE: {
1728                 CursorSlice & pos = cursor_.back();
1729                 int x = 0;
1730                 int y = 0;
1731                 getPos(x, y);
1732                 if (x < cmd.x && pos() != 0) {
1733                         DispatchResult const res = prevAtom().nucleus()->dispatch(cmd);
1734                         if (res.dispatched())
1735                                 return res;
1736                 }
1737                 if (x > cmd.x && pos() != lastpos()) {
1738                         DispatchResult const res = inset()->dispatch(cmd);
1739                         if (res.dispatched())
1740                                 return res;
1741                 }
1742         }
1743         default:
1744         break;
1745         }
1746 }
1747 */
1748
1749
1750 void LCursor::handleFont(string const & font)
1751 {
1752         string safe;
1753         if (selection()) {
1754                 macroModeClose();
1755                 safe = grabAndEraseSelection();
1756         }
1757
1758         if (lastpos() != 0) {
1759                 // something left in the cell
1760                 if (pos() == 0) {
1761                         // cursor in first position
1762                         popLeft();
1763                 } else if (pos() == lastpos()) {
1764                         // cursor in last position
1765                         popRight();
1766                 } else {
1767                         // cursor in between. split cell
1768                         MathArray::iterator bt = cell().begin();
1769                         MathAtom at = createMathInset(font);
1770                         at.nucleus()->cell(0) = MathArray(bt, bt + pos());
1771                         cell().erase(bt, bt + pos());
1772                         popLeft();
1773                         plainInsert(at);
1774                 }
1775         } else {
1776                 // nothing left in the cell
1777                 pullArg();
1778                 plainErase();
1779         }
1780         insert(safe);
1781 }
1782
1783
1784 void LCursor::releaseMathCursor()
1785 {
1786         if (inMathed())
1787                 formula()->insetUnlock(bv());
1788 }
1789
1790
1791 bool LCursor::inMathed() const
1792 {
1793         return formula();
1794 }
1795
1796
1797 InsetBase * LCursor::nextInset()
1798 {
1799         if (pos() == lastpos())
1800                 return 0;
1801         if (inMathed()) 
1802                 return nextAtom().nucleus();
1803         Paragraph & par = paragraph();
1804         return par.isInset(pos()) ? par.getInset(pos()) : 0;
1805 }
1806
1807
1808 InsetBase * LCursor::prevInset()
1809 {
1810         if (pos() == 0)
1811                 return 0;
1812         if (inMathed()) 
1813                 return prevAtom().nucleus();
1814         Paragraph & par = paragraph();
1815         return par.isInset(pos() - 1) ? par.getInset(pos() - 1) : 0;
1816 }
1817
1818
1819 void LCursor::message(string const & msg) const
1820 {
1821         bv().owner()->getLyXFunc().setMessage(msg);
1822 }
1823
1824
1825 void LCursor::errorMessage(string const & msg) const
1826 {
1827         bv().owner()->getLyXFunc().setErrorMessage(msg);
1828 }