This (dirty) patch gives paragraphs a uuid. It also changes the session code to use this uuid, and thus the cursor can be left inside insets and we are still able to recover the cursor position on restart.
A couple of dirty spots: - the resulting .lyx format change - all the #if 0, but they will of course we removed before commit - due to lack in uuid generation, linux only. - I kindo like it. I think this can be usable for "label-less" references as well. Perhaps also for some of the xdvi reverse lookup? (the id might be a bit too long) All comments appreciated. (but don't dwell to much on the dirty spots please)
Index: src/paragraph.h =================================================================== --- src/paragraph.h (revision 13609) +++ src/paragraph.h (working copy) @@ -21,6 +21,7 @@ #include "InsetList.h" #include "lyxlayout_ptr_fwd.h" #include "RowList_fwd.h" +#include "uuid.h" #include "insets/insetbase.h" // only for InsetBase::Code @@ -88,8 +89,12 @@ /// ~Paragraph(); /// +#if 0 int id() const; - +#else + Uuid const & id() const; + Uuid & id(); +#endif /// Language const * getParLanguage(BufferParams const &) const; Index: src/BufferView_pimpl.C =================================================================== --- src/BufferView_pimpl.C (revision 13609) +++ src/BufferView_pimpl.C (working copy) @@ -305,11 +305,12 @@ // scroll to the position when the file was last closed if (lyxrc.use_lastfilepos) { +#if 0 lyx::pit_type pit; lyx::pos_type pos; boost::tie(pit, pos) = LyX::ref().session().loadFilePosition(s); - // I am not sure how to separate the following part to a function - // so I will leave this to Lars. + // I am not sure how to separate the following part to + // a function so I will leave this to Lars. // // check pit since the document may be externally changed. if ( static_cast<size_t>(pit) < b->paragraphs().size() ) { @@ -323,6 +324,20 @@ break; } } +#else + Uuid pid; + lyx::pos_type pos; + boost::tie(pid, pos) = + LyX::ref().session().loadFilePosition(s); + if (bv_->buffer()->hasParWithID(pid)) { + lyxerr << "Yes we have id: " << pid.asString() << endl; + ParIterator pit = bv_->buffer()->getParFromID(pid); + bv_->setCursor(makeDocIterator(pit, min(pos, pit->size()))); + bv_->update(Update::FitCursor); + } else { + lyxerr << "Sorry no such id: " << pid.asString() << endl; + } +#endif } if (tolastfiles) @@ -363,8 +378,15 @@ buffer_->saveCursor(cursor_.selectionBegin(), cursor_.selectionEnd()); // current buffer is going to be switched-off, save cursor pos +#if 0 LyX::ref().session().saveFilePosition(buffer_->fileName(), boost::tie(cursor_.pit(), cursor_.pos()) ); +#else + LyX::ref().session() + .saveFilePosition(buffer_->fileName(), + boost::tie(cursor_.paragraph().id(), + cursor_.pos())); +#endif } // If we are closing current buffer, switch to the first in @@ -1229,7 +1251,11 @@ } case LFUN_GOTO_PARAGRAPH: { +#if 0 int const id = convert<int>(cmd.argument); +#else + Uuid id(cmd.argument); +#endif ParIterator par = buffer_->getParFromID(id); if (par == buffer_->par_iterator_end()) { lyxerr[Debug::INFO] << "No matching paragraph found! [" Index: src/paragraph_pimpl.C =================================================================== --- src/paragraph_pimpl.C (revision 13609) +++ src/paragraph_pimpl.C (working copy) @@ -37,8 +37,10 @@ using std::ostream; +#if 0 // Initialization of the counter for the paragraph id's, unsigned int Paragraph::Pimpl::paragraph_id = 0; +#endif namespace { @@ -64,7 +66,11 @@ : owner_(owner) { inset_owner = 0; +#if 0 id_ = paragraph_id++; +#else + id_.set(); +#endif } @@ -73,8 +79,11 @@ { inset_owner = p.inset_owner; fontlist = p.fontlist; +#if 0 id_ = paragraph_id++; - +#else + id_.set(); +#endif if (p.tracking()) changes_.reset(new Changes(*p.changes_.get())); } Index: src/buffer.C =================================================================== --- src/buffer.C (revision 13609) +++ src/buffer.C (working copy) @@ -446,14 +446,23 @@ "%1$s %2$s\n"), token, lex.getString()); +#if 0 error(ErrorItem(_("Document header error"), s, -1, 0, 0)); +#else + error(ErrorItem(_("Document header error"), s, + Uuid(), 0, 0)); +#endif } } } if (begin_header_line) { string const s = _("\\begin_header is missing"); +#if 0 error(ErrorItem(_("Document header error"), s, -1, 0, 0)); +#else + error(ErrorItem(_("Document header error"), s, Uuid(), 0, 0)); +#endif } return unknown_tokens; } @@ -468,7 +477,11 @@ string const token = lex.getString(); if (token != "\\begin_document") { string const s = _("\\begin_document is missing"); +#if 0 error(ErrorItem(_("Document header error"), s, -1, 0, 0)); +#else + error(ErrorItem(_("Document header error"), s, Uuid(), 0, 0)); +#endif } // we are reading in a brand new document @@ -1331,6 +1344,7 @@ } +#if 0 ParIterator Buffer::getParFromID(int const id) const { ParConstIterator it = par_iterator_begin(); @@ -1348,14 +1362,39 @@ return end; } +#else +ParIterator Buffer::getParFromID(Uuid const & id) const +{ + ParConstIterator it = par_iterator_begin(); + ParConstIterator const end = par_iterator_end(); + + if (id.isCleared()) { + // John says this is called with id == -1 from undo + lyxerr << "getParFromID(), id: " << id << endl; + return end; + } + + for (; it != end; ++it) + if (it->id() == id) + return it; + return end; +} +#endif +#if 0 bool Buffer::hasParWithID(int const id) const { ParConstIterator const it = getParFromID(id); return it != par_iterator_end(); } - +#else +bool Buffer::hasParWithID(Uuid const & id) const +{ + ParConstIterator const it = getParFromID(id); + return it != par_iterator_end(); +} +#endif ParIterator Buffer::par_iterator_begin() { Index: src/BufferView_pimpl.h =================================================================== --- src/BufferView_pimpl.h (revision 13609) +++ src/BufferView_pimpl.h (working copy) @@ -21,6 +21,7 @@ #include "BufferView.h" #include "cursor.h" #include "errorlist.h" +#include "uuid.h" #include "insets/inset.h" @@ -167,14 +168,28 @@ /// Filename std::string filename; /// Cursor paragraph Id +#if 0 int par_id; +#else + Uuid par_id; +#endif /// Cursor position lyx::pos_type par_pos; +#if 0 /// Position() : par_id(0), par_pos(0) {} /// Position(std::string const & f, int id, lyx::pos_type pos) : filename(f), par_id(id), par_pos(pos) {} +#else + /// + Position() : par_pos(0) {} + /// + Position(std::string const & f, + Uuid const & id, + lyx::pos_type pos) + : filename(f), par_id(id), par_pos(pos) {} +#endif }; /// std::vector<Position> saved_positions; Index: src/paragraph_pimpl.h =================================================================== --- src/paragraph_pimpl.h (revision 13609) +++ src/paragraph_pimpl.h (working copy) @@ -160,10 +160,15 @@ void validate(LaTeXFeatures & features, LyXLayout const & layout) const; +#if 0 /// unsigned int id_; /// static unsigned int paragraph_id; +#else + /// + Uuid id_; +#endif /// ParagraphParameters params; Index: src/session.C =================================================================== --- src/session.C (revision 13609) +++ src/session.C (working copy) @@ -119,18 +119,36 @@ } else if (section == id_lastfilepos) { // read lastfilepos // pos, file\n - lyx::pit_type pit; - lyx::pos_type pos; - string fname; istringstream itmp(tmp); + +#if 0 + lyx::pit_type pit; itmp >> pit; itmp.ignore(2); // ignore ", " +#else + string tmpid; + itmp >> tmpid; + tmpid.erase(tmpid.length() - 1); + lyxerr << "Read filepos uid: " << tmpid << endl; + Uuid id(tmpid); + lyxerr << "After conversion: " << id.asString() << endl; + itmp.ignore(1); // ignore " " +#endif + + lyx::pos_type pos; itmp >> pos; itmp.ignore(2); // ignore ", " + + string fname; itmp >> fname; + if (!fs::exists(fname) || lastfilepos.size() >= num_lastfilepos) continue; +#if 0 lastfilepos[fname] = boost::tie(pit, pos); +#else + lastfilepos[fname] = boost::tie(id, pos); +#endif } else if (section == id_lastopened) { // read lastopened // files @@ -140,17 +158,31 @@ } else if (section == id_bookmarks) { // read bookmarks // bookmarkid, id, pos, file\n - unsigned int num; - unsigned int id; - lyx::pos_type pos; - string fname; istringstream itmp(tmp); + + unsigned int num; itmp >> num; itmp.ignore(2); // ignore ", " + +#if 0 + unsigned int id; itmp >> id; itmp.ignore(2); // ignore ", " +#else + string tmpid; + itmp >> tmpid; + tmpid.erase(tmpid.length() - 1); + lyxerr << "Read filepos uid: " << tmpid << endl; + Uuid id(tmpid); + lyxerr << "After conversion: " << id.asString() << endl; + itmp.ignore(1); // ignore " " +#endif + + lyx::pos_type pos; itmp >> pos; itmp.ignore(2); // ignore ", " + + string fname; itmp >> fname; // only load valid bookmarks if (fs::exists(fname)) @@ -237,7 +269,7 @@ return entry->second; // Not found, return the first paragraph else - return 0; + return Session::FilePos(); } Index: src/errorlist.C =================================================================== --- src/errorlist.C (revision 13609) +++ src/errorlist.C (working copy) @@ -16,6 +16,7 @@ using std::string; +#if 0 ErrorItem::ErrorItem(string const & error_, string const & description_, int par_id_, pos_type pos_start_, pos_type pos_end_) : error(error_), description(description_), par_id(par_id_), @@ -26,3 +27,16 @@ ErrorItem::ErrorItem() : par_id(-1), pos_start(0), pos_end(0) {} +#else +ErrorItem::ErrorItem(string const & error_, string const & description_, + Uuid const & par_id_, + pos_type pos_start_, pos_type pos_end_) + : error(error_), description(description_), par_id(par_id_), + pos_start(pos_start_), pos_end(pos_end_) +{} + + +ErrorItem::ErrorItem() + : pos_start(0), pos_end(0) +{} +#endif Index: src/lyxfunc.C =================================================================== --- src/lyxfunc.C (revision 13609) +++ src/lyxfunc.C (working copy) @@ -1000,8 +1000,13 @@ case LFUN_QUIT: if (view()->available()) { // save cursor Position for opened files to .lyx/session +#if 0 LyX::ref().session().saveFilePosition(owner->buffer()->fileName(), boost::tie(view()->cursor().pit(), view()->cursor().pos()) ); +#else + LyX::ref().session().saveFilePosition(owner->buffer()->fileName(), + boost::tie(view()->cursor().paragraph().id(), view()->cursor().pos()) ); +#endif // save opened file name to .lyx/session LyX::ref().session().setLastOpenedFiles( bufferlist.getFileNames()); // save bookmarks to .lyx/session @@ -1892,8 +1897,15 @@ void LyXFunc::closeBuffer() { // save current cursor position +#if 0 LyX::ref().session().saveFilePosition(owner->buffer()->fileName(), boost::tie(view()->cursor().pit(), view()->cursor().pos()) ); +#else + LyX::ref().session() + .saveFilePosition(owner->buffer()->fileName(), + boost::tie(view()->cursor().paragraph().id(), + view()->cursor().pos())); +#endif if (bufferlist.close(owner->buffer(), true) && !quitting) { if (bufferlist.empty()) { // need this otherwise SEGV may occur while Index: src/buffer.h =================================================================== --- src/buffer.h (revision 13609) +++ src/buffer.h (working copy) @@ -16,6 +16,7 @@ #include "dociterator.h" #include "ParagraphList_fwd.h" +#include "uuid.h" #include "support/limited_stack.h" #include "support/types.h" @@ -106,11 +107,17 @@ void insertStringAsLines(ParagraphList & plist, lyx::pit_type &, lyx::pos_type &, LyXFont const &, std::string const &, bool); +#if 0 /// ParIterator getParFromID(int id) const; /// do we have a paragraph with this id? bool hasParWithID(int id) const; - +#else + /// + ParIterator getParFromID(Uuid const & id) const; + /// do we have a paragraph with this id? + bool hasParWithID(Uuid const & id) const; +#endif /// This signal is emitted when a parsing error shows up. boost::signal<void(ErrorItem)> error; /// This signal is emitted when some message shows up. Index: src/frontends/gtk/GtkLengthEntry.C =================================================================== Index: src/frontends/controllers/ControlErrorList.C =================================================================== --- src/frontends/controllers/ControlErrorList.C (revision 13609) +++ src/frontends/controllers/ControlErrorList.C (working copy) @@ -57,9 +57,13 @@ { ErrorItem const & err = errorlist_[item]; +#if 0 if (err.par_id == -1) return; - +#else + if (err.par_id.isCleared()) + return; +#endif Buffer & buf = kernel().buffer(); ParIterator pit = buf.getParFromID(err.par_id); Index: src/session.h =================================================================== --- src/session.h (revision 13609) +++ src/session.h (working copy) @@ -13,7 +13,9 @@ #ifndef SESSION_H #define SESSION_H -#include <support/types.h> +#include "uuid.h" + +#include "support/types.h" #include <boost/utility.hpp> #include <boost/tuple/tuple.hpp> @@ -38,16 +40,26 @@ class Session : boost::noncopyable { public: +#if 0 /// typedef boost::tuple<lyx::pit_type, lyx::pos_type> FilePos; +#else + /// + typedef boost::tuple<Uuid, lyx::pos_type> FilePos; +#endif /// typedef std::map<std::string, FilePos> FilePosMap; /// typedef std::deque<std::string> LastFiles; /// typedef std::vector<std::string> LastOpened; +#if 0 /// typedef boost::tuple<unsigned int, std::string, unsigned int, lyx::pos_type> Bookmark; +#else + /// + typedef boost::tuple<unsigned int, std::string, Uuid, lyx::pos_type> Bookmark; +#endif /// typedef std::vector<Bookmark> BookmarkList; /// Index: src/texrow.C =================================================================== --- src/texrow.C (revision 13609) +++ src/texrow.C (working copy) @@ -41,26 +41,43 @@ { rowlist.clear(); count = 0; +#if 0 lastid = -1; +#else + lastid.clear(); +#endif lastpos = -1; } +#if 0 void TexRow::start(int id, int pos) { lastid = id; lastpos = pos; } +#else +void TexRow::start(Uuid const & id, int pos) +{ + lastid = id; + lastpos = pos; +} +#endif void TexRow::newline() { +#if 0 int const id = lastid; +#else + Uuid const id = lastid; +#endif RowList::value_type tmp(id, lastpos, ++count); rowlist.push_back(tmp); } +#if 0 bool TexRow::getIdFromRow(int row, int & id, int & pos) const { RowList::const_iterator cit = @@ -76,6 +93,23 @@ pos = 0; return false; } +#else +bool TexRow::getIdFromRow(int row, Uuid & id, int & pos) const +{ + RowList::const_iterator cit = + find_if(rowlist.begin(), rowlist.end(), + same_rownumber(row)); + + if (cit != rowlist.end()) { + id = cit->id(); + pos = cit->pos(); + return true; + } + id.clear(); + pos = 0; + return false; +} +#endif TexRow & TexRow::operator+=(TexRow const & tr) Index: src/Makefile.am =================================================================== --- src/Makefile.am (revision 13609) +++ src/Makefile.am (working copy) @@ -27,7 +27,7 @@ BOOST_LIBS = $(BOOST_REGEX) $(BOOST_SIGNALS) $(BOOST_FILESYSTEM) -OTHERLIBS = $(BOOST_LIBS) $(INTLLIBS) $(AIKSAURUS_LIBS) @LIBS@ $(SOCKET_LIBS) +OTHERLIBS = $(BOOST_LIBS) $(INTLLIBS) $(AIKSAURUS_LIBS) @LIBS@ $(SOCKET_LIBS) -luuid bin_PROGRAMS = lyx noinst_PROGRAMS = $(FRONTENDS_PROGS) @@ -289,6 +289,8 @@ trans_mgr.h \ undo.C \ undo.h \ + uuid.C \ + uuid.h \ vc-backend.C \ vc-backend.h \ version.C \ Index: src/errorlist.h =================================================================== --- src/errorlist.h (revision 13609) +++ src/errorlist.h (working copy) @@ -12,6 +12,8 @@ #ifndef ERRORLIST_H #define ERRORLIST_H +#include "uuid.h" + #include "support/types.h" #include <vector> @@ -24,11 +26,22 @@ public: std::string error; std::string description; +#if 0 int par_id; +#else + Uuid par_id; +#endif lyx::pos_type pos_start; lyx::pos_type pos_end; +#if 0 ErrorItem(std::string const & error, std::string const & description, int parid, lyx::pos_type posstart, lyx::pos_type posend); +#else + ErrorItem(std::string const & error, + std::string const & description, + Uuid const & parid, + lyx::pos_type posstart, lyx::pos_type posend); +#endif ErrorItem(); }; Index: src/texrow.h =================================================================== --- src/texrow.h (revision 13609) +++ src/texrow.h (working copy) @@ -14,22 +14,34 @@ #ifndef TEXROW_H #define TEXROW_H +#include "uuid.h" + #include <list> /// Represents the correspondence between paragraphs and the generated LaTeX file class TexRow { public: +#if 0 /// TexRow() : count(0), lastid(-1), lastpos(-1) {} +#else + /// + TexRow() : count(0), lastpos(-1) {} +#endif TexRow & operator+= (TexRow const &); /// Clears structure void reset(); +#if 0 /// Define what paragraph and position the next row will represent void start(int id, int pos); +#else + /// Define what paragraph and position the next row will represent + void start(Uuid const & id, int pos); +#endif /// Insert node when line is completed void newline(); @@ -44,23 +56,38 @@ * If the row could not be found, pos is set to zero and * id is set to -1 */ +#if 0 bool getIdFromRow(int row, int & id, int & pos) const; - +#else + bool getIdFromRow(int row, Uuid & id, int & pos) const; +#endif /// Returns the number of rows contained int rows() const { return count; } /// an individual id/pos <=> row mapping class RowItem { public: +#if 0 RowItem(int id, int pos, int row) : id_(id), pos_(pos), rownumber_(row) {} +#else + RowItem(Uuid const & id, int pos, int row) + : id_(id), pos_(pos), rownumber_(row) + {} +#endif +#if 0 /// paragraph id int id() const { return id_; } - +#else + Uuid const & id() const + { + return id_; + } +#endif /// set paragraph position void pos(int p) { pos_ = p; @@ -76,7 +103,11 @@ return rownumber_; } private: +#if 0 int id_; +#else + Uuid id_; +#endif int pos_; int rownumber_; }; @@ -87,8 +118,13 @@ unsigned int count; /// container of id/pos <=> row mapping RowList rowlist; +#if 0 /// Last paragraph int lastid; +#else + /// Last paragraph + Uuid lastid; +#endif /// Last position int lastpos; }; Index: src/BufferView.C =================================================================== --- src/BufferView.C (revision 13609) +++ src/BufferView.C (working copy) @@ -260,15 +260,26 @@ void BufferView::setCursorFromRow(int row) { +#if 0 int tmpid = -1; +#else + Uuid tmpid; +#endif int tmppos = -1; buffer()->texrow().getIdFromRow(row, tmpid, tmppos); +#if 0 if (tmpid == -1) text()->setCursor(cursor(), 0, 0); else text()->setCursor(cursor(), buffer()->getParFromID(tmpid).pit(), tmppos); +#else + if (tmpid.isCleared()) + text()->setCursor(cursor(), 0, 0); + else + text()->setCursor(cursor(), buffer()->getParFromID(tmpid).pit(), tmppos); +#endif } Index: src/toc.C =================================================================== --- src/toc.C (revision 13609) +++ src/toc.C (working copy) @@ -44,14 +44,23 @@ void TocItem::goTo(LyXView & lv_) const { +#if 0 string const tmp = convert<string>(id_); +#else + string const tmp = id_.asString(); +#endif lv_.dispatch(FuncRequest(LFUN_GOTO_PARAGRAPH, tmp)); } FuncRequest TocItem::action() const { +#if 0 return FuncRequest(LFUN_GOTO_PARAGRAPH, convert<string>(id_)); +#else + string const tmp = id_.asString(); + return FuncRequest(LFUN_GOTO_PARAGRAPH, tmp); +#endif } Index: src/paragraph.C =================================================================== --- src/paragraph.C (revision 13609) +++ src/paragraph.C (working copy) @@ -144,9 +144,13 @@ } } +#if 0 // First write the layout os << "\n\\begin_layout " << layout()->name() << '\n'; - +#else + // First write the layout + os << "\n\\begin_layout " << layout()->name() << ' ' << id().asString() << '\n'; +#endif params().write(os); LyXFont font1(LyXFont::ALL_INHERIT, bparams.language); @@ -1682,10 +1686,21 @@ } +#if 0 int Paragraph::id() const { return pimpl_->id_; } +#else +Uuid const & Paragraph::id() const +{ + return pimpl_->id_; +} +Uuid & Paragraph::id() +{ + return pimpl_->id_; +} +#endif LyXLayout_ptr const & Paragraph::layout() const Index: src/buffer_funcs.C =================================================================== --- src/buffer_funcs.C (revision 13609) +++ src/buffer_funcs.C (working copy) @@ -212,12 +212,20 @@ TeXErrors::Errors::const_iterator end = terr.end(); for (; cit != end; ++cit) { +#if 0 int id_start = -1; +#else + Uuid id_start; +#endif int pos_start = -1; int errorrow = cit->error_in_line; bool found = buf.texrow().getIdFromRow(errorrow, id_start, pos_start); +#if 0 int id_end = -1; +#else + Uuid id_end; +#endif int pos_end = -1; do { ++errorrow; Index: src/text.C =================================================================== --- src/text.C (revision 13609) +++ src/text.C (working copy) @@ -165,9 +165,30 @@ for (; cit != token.end(); ++cit) par.insertChar(par.size(), (*cit), font, change); } else if (token == "\\begin_layout") { +#if 0 lex.eatLine(); string layoutname = lex.getString(); - +#else + lex.eatLine(); + string line = lex.getString(); + string layoutname; + string parid; + string::size_type pos; + if ((pos = line.find(' ')) != string::npos) { + layoutname = line.substr(0, pos); + parid = line.substr(pos + 1, string::npos); + } else { + layoutname = line; + } + lyxerr << "Read layout: " << layoutname << endl; + lyxerr << "Read parid: '" << parid << "'" << endl; + if (parid.empty()) { + par.id().set(); + } else { + par.id() = Uuid(parid); + } + lyxerr << "Parid after conversion: '" << par.id().asString() << "'" << endl; +#endif font = LyXFont(LyXFont::ALL_INHERIT, bp.language); change = Change(); Index: src/toc.h =================================================================== --- src/toc.h (revision 13609) +++ src/toc.h (working copy) @@ -21,6 +21,7 @@ #include <string> #include "pariterator.h" +#include "uuid.h" class Buffer; class LyXView; @@ -33,8 +34,13 @@ /// class TocItem { public: +#if 0 TocItem(int par_id, int d, std::string const & s) : id_(par_id), depth(d), str(s) {} +#else + TocItem(Uuid const & par_id, int d, std::string const & s) + : id_(par_id), depth(d), str(s) {} +#endif /// std::string const asString() const; /// set cursor in LyXView to this TocItem @@ -42,7 +48,7 @@ /// the action corresponding to the goTo above FuncRequest action() const; /// Paragraph ID containing this item - int id_; + Uuid id_; /// nesting depth int depth; /// Index: boost/boost/tuple/detail/tuple_basic.hpp ===================================================================
-- Lgb