View Issue Details

IDProjectCategoryView StatusLast Update
0002424Far ManagerEditorpublic2013-06-28 15:26
Reporterxarx Assigned ToDrKnS  
PrioritynormalSeverityminorReproducibilityalways
Status closedResolutionfixed 
Product Version3.0 
Fixed in Version3.0 
Summary0002424: Undo не восстанавливает закладки
DescriptionUndo (CtrlZ) удаленного текста в редакторе не восстанавливает удаленные закладки (созданные через BM.add).

http://forum.farmanager.com/viewtopic.php?f=9&t=8003

Patch fixing the issue is available.
Steps To Reproduce1. Create several bookmarks via BM.Add(), on different lines
2. Delete several lines including some of those, where bookmarks were created
3. Undo (CtrlZ)

Now you see that the bookmarks that were on the deleted lines are not navigable, they were deleted permanently in step 2.
Additional InformationЭто проблема прежде всего при частом использовании плагинов FilterLines, BlockProcessor,... Потому что каждый раз, когда я выполняю фильтрацию, все закладки в редакторе удаляют.
Tagsbookmarks, editor
Build3450

Activities

xarx

2013-06-06 19:35

reporter  

undo_bookmarks.diff (11,767 bytes)   
diff -ur orig/unicode_far/editor.cpp new/unicode_far/editor.cpp
--- orig/unicode_far/editor.cpp	2013-06-01 05:47:05.226023900 +0200
+++ new/unicode_far/editor.cpp	2013-06-06 21:20:47.581933600 +0200
@@ -3188,35 +3188,6 @@
 		return;
 	}
 
-	std::for_each(RANGE(SavePos, i)
-	{
-		if (i.Line != POS_NONE && UndoLine < static_cast<int>(i.Line))
-			--i.Line;
-	});
-
-	if (SessionPos)
-	{
-		InternalEditorSessionBookMark *sb_temp = SessionPos, *sb_new;
-
-		while (sb_temp->prev)
-			sb_temp=sb_temp->prev;
-
-		while (sb_temp)
-		{
-			sb_new = sb_temp->next;
-
-			if (UndoLine < static_cast<int>(sb_temp->Line))
-				sb_temp->Line--;
-			else
-			{
-				if (UndoLine == static_cast<int>(sb_temp->Line))
-					DeleteSessionBookmark(sb_temp);
-			}
-
-			sb_temp = sb_new;
-		}
-	}
-
 	NumLastLine--;
 
 	if(LastGetLine)
@@ -3289,6 +3260,40 @@
 	if (UndoLine!=-1)
 		AddUndoData(UNDO_DELSTR,DelPtr->GetStringAddr(),DelPtr->GetEOL(),UndoLine,0,DelPtr->GetLength());
 
+	std::for_each(RANGE(SavePos, i)
+	{
+		//FIXME: it would be better to add the bookmarks for deleted line to UndoData
+		if (i.Line != POS_NONE && UndoLine < static_cast<int>(i.Line))
+			--i.Line;
+	});
+
+	if (SessionPos)
+	{
+		InternalEditorSessionBookMark *sb_temp = SessionPos, *sb_new;
+
+		while (sb_temp->prev)
+			sb_temp=sb_temp->prev;
+
+		while (sb_temp)
+		{
+			sb_new = sb_temp->next;
+
+			if (UndoLine < static_cast<int>(sb_temp->Line))
+				sb_temp->Line--;
+			else
+			{
+				if (UndoLine == static_cast<int>(sb_temp->Line))
+				{
+					if (UndoLine!=-1)
+						AddUndoData(sb_temp);
+					DeleteSessionBookmark(sb_temp);
+				}
+			}
+
+			sb_temp = sb_new;
+		}
+	}
+
 	delete DelPtr;
 
 	Change(ECTYPE_DELETED,UndoLine);
@@ -4998,6 +5003,16 @@
 	}
 }
 
+void Editor::AddUndoData(const InternalEditorSessionBookMark *BM)
+{
+	if (Flags.Check(FEDITOR_DISABLEUNDO))
+		return;
+	if (UndoPos->Type != UNDO_DELSTR)
+		return;
+
+	UndoPos->AddSessionBM(BM);
+}
+
 void Editor::Undo(int redo)
 {
 	auto ustart = UndoPos;
@@ -5082,6 +5097,16 @@
 
 				Pasting--;
 
+				{
+					InternalEditorSessionBookMark *BM = ud->BM;
+					while (BM)
+					{
+						InsertSessionBookmarkBack(BM);
+						BM = BM->next;
+					}
+					ud->DeleteAllSessionBM();
+				}
+
 				if (ud->Str)
 				{
 					CurLine->SetString(ud->Str.get(),ud->Length);
@@ -6497,6 +6522,7 @@
 	return FALSE;
 }
 
+//Set the numbered bookmark (CtrlShift-0..9)
 int Editor::SetBookmark(int Pos)
 {
 	if (Pos < static_cast<int>(SavePos.size()))
@@ -6512,6 +6538,7 @@
 	return FALSE;
 }
 
+//Restore the numbered bookmark (LeftCtrl-0..9)
 int Editor::GotoBookmark(int Pos)
 {
 	if (Pos < static_cast<int>(SavePos.size()))
@@ -6539,6 +6566,8 @@
 	return FALSE;
 }
 
+//Remove all session bookmarks;
+// SessionPos will be NULL
 int Editor::ClearSessionBookmarks()
 {
 	NewSessionPos = FALSE;
@@ -6550,7 +6579,7 @@
 		while (SessionPos)
 		{
 			sb_next = SessionPos->next;
-			xf_free(SessionPos);
+			delete SessionPos;
 			SessionPos = sb_next;
 		}
 
@@ -6559,7 +6588,7 @@
 		while (SessionPos)
 		{
 			sb_prev = SessionPos->prev;
-			xf_free(SessionPos);
+			delete SessionPos;
 			SessionPos = sb_prev;
 		}
 	}
@@ -6567,6 +6596,8 @@
 	return TRUE;
 }
 
+//Remove a particular session bookmark
+// adjusts SessionPos if deleting the current bookmark
 int Editor::DeleteSessionBookmark(InternalEditorSessionBookMark *sb_delete)
 {
 	NewSessionPos=FALSE;
@@ -6589,10 +6620,11 @@
 	return FALSE;
 }
 
+//Restore the current session bookmark
 int Editor::RestoreSessionBookmark()
 {
 	NewSessionPos=FALSE;
-
+	//only if the cursor is elsewhere
 	if (SessionPos && ((int)SessionPos->Line!=NumLine || (int)SessionPos->Cursor!=CurLine->GetCurPos()))
 	{
 		GoToLine(SessionPos->Line);
@@ -6613,10 +6645,13 @@
 	return FALSE;
 }
 
+//Add current cursor pos to session bookmarks, after the current bookmark,
+// and adjust SessionPos to it
 int Editor::AddSessionBookmark(BOOL blNewPos)
 {
 	InternalEditorSessionBookMark *sb_old=SessionPos;
 
+	//remove all subsequent bookmarks
 	if (SessionPos && SessionPos->next)
 	{
 		SessionPos=SessionPos->next;
@@ -6626,8 +6661,8 @@
 		SessionPos->next=0;
 	}
 
+	//append new bookmark
 	auto sb_new = new InternalEditorSessionBookMark;
-
 	if (sb_new)
 	{
 		if (SessionPos)
@@ -6647,6 +6682,67 @@
 	return FALSE;
 }
 
+//Insert the session bookmark on its original position in the list of session bookmarks, if it still exists,
+// otherwise do nothing
+int Editor::InsertSessionBookmarkBack(InternalEditorSessionBookMark *sb_ins)
+{
+	//Search for the bookmark referred in sb_ins->prev. But it needs not exist already...
+
+	//look up forward
+	InternalEditorSessionBookMark *sb_new = NULL, *sb_temp=SessionPos;
+	while (sb_temp && sb_temp != sb_ins->prev)
+		sb_temp=sb_temp->next;
+
+	if (sb_temp)
+	{
+		//found, insert sb_ins immediately after sb_temp
+		sb_new = new InternalEditorSessionBookMark(*sb_ins);
+		if (sb_new)
+		{
+			sb_new->next = sb_temp->next;
+			sb_temp->next = sb_new;
+			if (sb_new->next)
+				sb_new->next->prev = sb_new;
+		}
+	}
+	else
+	{
+		//not found forward, look up backwards
+		sb_temp=SessionPos;
+		while (sb_temp && sb_temp->prev != sb_ins->prev)
+			sb_temp=sb_temp->prev;
+
+		if (sb_temp)
+		{
+			//found, insert sb_ins immediately before sb_temp
+			sb_new = new InternalEditorSessionBookMark(*sb_ins);
+			if (sb_new)
+			{
+				sb_new->next = sb_temp;
+				sb_temp->prev = sb_new;
+				if (sb_new->prev)
+					sb_new->prev->next = sb_new;
+			}
+		}
+		else if (!sb_ins->prev)
+		{
+			//SessionPos is NULL, but sb_ins was the first sb in the list
+			sb_new = new InternalEditorSessionBookMark(*sb_ins);
+			if (sb_new)
+			{
+				sb_new->next = NULL;
+				SessionPos = sb_new;
+			}
+		}
+		else
+			sb_new = sb_ins; //just to mark success
+	}
+
+	return sb_new?TRUE:FALSE;
+}
+
+//Return the first session bookmark (and do not change SessionPos);
+// On return, piCount will be set to the count of session bookmark preceding the current one
 InternalEditorSessionBookMark* Editor::PointerToFirstSessionBookmark(int *piCount)
 {
 	InternalEditorSessionBookMark *sb_temp=SessionPos;
@@ -6664,6 +6760,9 @@
 	return sb_temp;
 }
 
+//Return the last session bookmark (and do not change SessionPos);
+// piCount must be set to the count of session bookmarks preceding the current one
+// On return piCount will be set to the total count of session bookmarks
 InternalEditorSessionBookMark* Editor::PointerToLastSessionBookmark(int *piCount)
 {
 	InternalEditorSessionBookMark *sb_temp=SessionPos;
@@ -6682,6 +6781,8 @@
 	return sb_temp;
 }
 
+//Return the session bookmark of index iIdx (and do not change SessionPos); 
+// for iIdx==-1 the current bookmark is returned
 InternalEditorSessionBookMark* Editor::PointerToSessionBookmark(int iIdx) // Returns null_ptr if failed!
 {
 	InternalEditorSessionBookMark *sb_temp=SessionPos;
@@ -6717,6 +6818,7 @@
 	return FALSE;
 }
 
+//Restore the previous session bookmark, if there is any, the current one otherwise
 int Editor::PrevSessionBookmark()
 {
 	if (SessionPos)
@@ -6732,6 +6834,7 @@
 	return FALSE;
 }
 
+//Restore the next session bookmark, if there is any, the current one otherwise
 int Editor::NextSessionBookmark()
 {
 	if (SessionPos)
@@ -6747,6 +6850,7 @@
 	return FALSE;
 }
 
+//Restore the last session bookmark
 int Editor::LastSessionBookmark()
 {
 	if (SessionPos)
@@ -6758,6 +6862,8 @@
 	return FALSE;
 }
 
+//Restore the session bookmark at the specified index;
+// does nothing if there is no such index
 int Editor::GotoSessionBookmark(int iIdx)
 {
 	if (SessionPos)
@@ -6773,17 +6879,20 @@
 	return FALSE;
 }
 
+//Append new session bookmark as the last session bookmark, and move SessionPos to it
 int Editor::PushSessionBookMark()
 {
 	SessionPos=PointerToLastSessionBookmark();
 	return AddSessionBookmark(FALSE);
 }
 
+//Restore the last session bookmark and remove it
 int Editor::PopSessionBookMark()
 {
 	return (LastSessionBookmark() && DeleteSessionBookmark(SessionPos));
 }
 
+//Return index of the current session bookmark, -1 if there is none
 int Editor::CurrentSessionBookmarkIdx()
 {
 	int iIdx;
@@ -6792,6 +6901,7 @@
 	return -1;
 }
 
+//Get session bookmark at specified index into Param
 int Editor::GetSessionBookmark(int iIdx,InternalEditorBookmark *Param)
 {
 	InternalEditorSessionBookMark *sb_temp = PointerToSessionBookmark(iIdx);
@@ -6809,6 +6919,7 @@
 	return FALSE;
 }
 
+//Get all session bookmarks into the Param array
 int Editor::GetSessionBookmarks(EditorBookmarks *Param)
 {
 	int iCount=0;
diff -ur orig/unicode_far/editor.hpp new/unicode_far/editor.hpp
--- orig/unicode_far/editor.hpp	2013-06-01 05:47:04.599988100 +0200
+++ new/unicode_far/editor.hpp	2013-06-06 21:23:31.207292500 +0200
@@ -37,6 +37,7 @@
 #include "poscache.hpp"
 #include "bitflags.hpp"
 #include "config.hpp"
+#include <algorithm>
 
 class FileEditor;
 class KeyBar;
@@ -66,13 +67,15 @@
 	wchar_t EOL[10];
 	int Length;
 	wchar_t_ptr Str;
+	InternalEditorSessionBookMark *BM; //treat as uni-directional linked list
 	static size_t UndoDataSize;
 
 	EditorUndoData(int Type,const wchar_t *Str,const wchar_t *Eol,int StrNum,int StrPos,int Length=-1):
 		Type(0),
 		StrPos(0),
 		StrNum(0),
-		Length(0)
+		Length(0),
+		BM(0)
 	{
 		SetData(Type, Str, Eol, StrNum, StrPos, Length);
 	}
@@ -81,9 +84,11 @@
 	{
 		if (Length > 0)
 			UndoDataSize -= Length;
+		DeleteAllSessionBM();
 	}
 
-	EditorUndoData(EditorUndoData&& Right)
+	EditorUndoData(EditorUndoData&& Right):
+		BM(0)
 	{
 		*this = std::move(Right);
 		Right.Length = 0;
@@ -97,6 +102,7 @@
 		Length = Right.Length;
 		Str.swap(Right.Str);
 		wcscpy(EOL, Right.EOL);
+		std::swap(BM, Right.BM);
 		return *this;
 	}
 
@@ -124,6 +130,29 @@
 		}
 		else
 			this->Str.reset();
+		DeleteAllSessionBM();
+	}
+
+	void AddSessionBM(const InternalEditorSessionBookMark *BM)
+	{
+		InternalEditorSessionBookMark *BM_new = new InternalEditorSessionBookMark(*BM);
+		if (BM_new)
+		{
+			BM_new->next = this->BM;
+			this->BM = BM_new;
+		}
+	}
+
+	void DeleteAllSessionBM()
+	{
+		InternalEditorSessionBookMark *BM=this->BM, *BM_next;
+		this->BM = NULL;
+		while (BM)
+		{
+			BM_next = BM->next;
+			delete BM;
+			BM = BM_next;
+		}
 	}
 };
 
@@ -232,8 +261,9 @@
 		int StartLine;
 		int StartChar;
 
+		//numbered bookmarks (accessible by Ctrl-0..9)
 		Bookmarks<editor_bookmark> SavePos;
-
+		//pointer to the current "session" bookmark (in the list of "session" bookmarks accessible through BM.Goto(n))
 		InternalEditorSessionBookMark *SessionPos;
 		BOOL NewSessionPos;
 
@@ -279,6 +309,7 @@
 		void UnmarkMacroBlock();
 
 		void AddUndoData(int Type,const wchar_t *Str=nullptr,const wchar_t *Eol=nullptr,int StrNum=0,int StrPos=0,int Length=-1);
+		void AddUndoData(const InternalEditorSessionBookMark *BM);
 		void Undo(int redo);
 		void SelectAll();
 		//void SetStringsTable();
@@ -298,6 +329,7 @@
 		int DeleteSessionBookmark(InternalEditorSessionBookMark *sb_delete);
 		int RestoreSessionBookmark();
 		int AddSessionBookmark(BOOL blNewPos=TRUE);
+		int InsertSessionBookmarkBack(InternalEditorSessionBookMark *sb_ins);
 		InternalEditorSessionBookMark* PointerToFirstSessionBookmark(int *piCount=nullptr);
 		InternalEditorSessionBookMark* PointerToLastSessionBookmark(int *piCount=nullptr);
 		InternalEditorSessionBookMark* PointerToSessionBookmark(int iIdx);
undo_bookmarks.diff (11,767 bytes)   

xarx

2013-06-06 19:37

reporter   bugnote:0011111

Last edited: 2013-06-06 23:03

I have implemented the required functionality, and uploaded the patch (see above).

undo_bookmarks2.diff is the newest patch, it improves behaviour in some special situations.

xarx

2013-06-06 23:01

reporter  

undo_bookmarks2.diff (12,293 bytes)   
diff -ur orig/unicode_far/editor.cpp new/unicode_far/editor.cpp
--- orig/unicode_far/editor.cpp	2013-06-01 05:47:05.226023900 +0200
+++ new/unicode_far/editor.cpp	2013-06-07 00:46:08.848669800 +0200
@@ -3188,35 +3188,6 @@
 		return;
 	}
 
-	std::for_each(RANGE(SavePos, i)
-	{
-		if (i.Line != POS_NONE && UndoLine < static_cast<int>(i.Line))
-			--i.Line;
-	});
-
-	if (SessionPos)
-	{
-		InternalEditorSessionBookMark *sb_temp = SessionPos, *sb_new;
-
-		while (sb_temp->prev)
-			sb_temp=sb_temp->prev;
-
-		while (sb_temp)
-		{
-			sb_new = sb_temp->next;
-
-			if (UndoLine < static_cast<int>(sb_temp->Line))
-				sb_temp->Line--;
-			else
-			{
-				if (UndoLine == static_cast<int>(sb_temp->Line))
-					DeleteSessionBookmark(sb_temp);
-			}
-
-			sb_temp = sb_new;
-		}
-	}
-
 	NumLastLine--;
 
 	if(LastGetLine)
@@ -3289,6 +3260,40 @@
 	if (UndoLine!=-1)
 		AddUndoData(UNDO_DELSTR,DelPtr->GetStringAddr(),DelPtr->GetEOL(),UndoLine,0,DelPtr->GetLength());
 
+	std::for_each(RANGE(SavePos, i)
+	{
+		//FIXME: it would be better to add the bookmarks for deleted line to UndoData
+		if (i.Line != POS_NONE && UndoLine < static_cast<int>(i.Line))
+			--i.Line;
+	});
+
+	if (SessionPos)
+	{
+		InternalEditorSessionBookMark *sb_temp = SessionPos, *sb_new;
+
+		while (sb_temp->prev)
+			sb_temp=sb_temp->prev;
+
+		while (sb_temp)
+		{
+			sb_new = sb_temp->next;
+
+			if (UndoLine < static_cast<int>(sb_temp->Line))
+				sb_temp->Line--;
+			else
+			{
+				if (UndoLine == static_cast<int>(sb_temp->Line))
+				{
+					if (UndoLine!=-1)
+						AddUndoData(sb_temp);
+					DeleteSessionBookmark(sb_temp);
+				}
+			}
+
+			sb_temp = sb_new;
+		}
+	}
+
 	delete DelPtr;
 
 	Change(ECTYPE_DELETED,UndoLine);
@@ -4998,6 +5003,16 @@
 	}
 }
 
+void Editor::AddUndoData(const InternalEditorSessionBookMark *BM)
+{
+	if (Flags.Check(FEDITOR_DISABLEUNDO))
+		return;
+	if (UndoPos->Type != UNDO_DELSTR)
+		return;
+
+	UndoPos->AddSessionBM(BM);
+}
+
 void Editor::Undo(int redo)
 {
 	auto ustart = UndoPos;
@@ -5082,6 +5097,16 @@
 
 				Pasting--;
 
+				{
+					InternalEditorSessionBookMark *BM = ud->BM;
+					while (BM)
+					{
+						InsertSessionBookmarkBack(BM);
+						BM = BM->next;
+					}
+					ud->DeleteAllSessionBM();
+				}
+
 				if (ud->Str)
 				{
 					CurLine->SetString(ud->Str.get(),ud->Length);
@@ -6497,6 +6522,7 @@
 	return FALSE;
 }
 
+//Set the numbered bookmark (CtrlShift-0..9)
 int Editor::SetBookmark(int Pos)
 {
 	if (Pos < static_cast<int>(SavePos.size()))
@@ -6512,6 +6538,7 @@
 	return FALSE;
 }
 
+//Restore the numbered bookmark (LeftCtrl-0..9)
 int Editor::GotoBookmark(int Pos)
 {
 	if (Pos < static_cast<int>(SavePos.size()))
@@ -6539,6 +6566,8 @@
 	return FALSE;
 }
 
+//Remove all session bookmarks;
+// SessionPos will be NULL
 int Editor::ClearSessionBookmarks()
 {
 	NewSessionPos = FALSE;
@@ -6550,7 +6579,7 @@
 		while (SessionPos)
 		{
 			sb_next = SessionPos->next;
-			xf_free(SessionPos);
+			delete SessionPos;
 			SessionPos = sb_next;
 		}
 
@@ -6559,7 +6588,7 @@
 		while (SessionPos)
 		{
 			sb_prev = SessionPos->prev;
-			xf_free(SessionPos);
+			delete SessionPos;
 			SessionPos = sb_prev;
 		}
 	}
@@ -6567,6 +6596,8 @@
 	return TRUE;
 }
 
+//Remove a particular session bookmark
+// adjusts SessionPos if deleting the current bookmark
 int Editor::DeleteSessionBookmark(InternalEditorSessionBookMark *sb_delete)
 {
 	NewSessionPos=FALSE;
@@ -6589,10 +6620,11 @@
 	return FALSE;
 }
 
+//Restore the current session bookmark
 int Editor::RestoreSessionBookmark()
 {
 	NewSessionPos=FALSE;
-
+	//only if the cursor is elsewhere
 	if (SessionPos && ((int)SessionPos->Line!=NumLine || (int)SessionPos->Cursor!=CurLine->GetCurPos()))
 	{
 		GoToLine(SessionPos->Line);
@@ -6613,10 +6645,13 @@
 	return FALSE;
 }
 
+//Add current cursor pos to session bookmarks, after the current bookmark,
+// and adjust SessionPos to it
 int Editor::AddSessionBookmark(BOOL blNewPos)
 {
 	InternalEditorSessionBookMark *sb_old=SessionPos;
 
+	//remove all subsequent bookmarks
 	if (SessionPos && SessionPos->next)
 	{
 		SessionPos=SessionPos->next;
@@ -6626,8 +6661,8 @@
 		SessionPos->next=0;
 	}
 
+	//append new bookmark
 	auto sb_new = new InternalEditorSessionBookMark;
-
 	if (sb_new)
 	{
 		if (SessionPos)
@@ -6647,6 +6682,69 @@
 	return FALSE;
 }
 
+//Insert the session bookmark on its original position in the list of session bookmarks, if it still exists,
+// otherwise do nothing; sb_ins->prev is hashed to better differentiate among session bookmarks
+int Editor::InsertSessionBookmarkBack(InternalEditorSessionBookMark *sb_ins)
+{
+	//Search for the bookmark referred in sb_ins->prev. But it needs not exist already...
+
+	//look up forward
+	InternalEditorSessionBookMark *sb_new = NULL, *sb_temp=SessionPos;
+	while (sb_temp && EditorUndoData::HashBM(sb_temp) != sb_ins->prev)
+		sb_temp=sb_temp->next;
+
+	if (sb_temp)
+	{
+		//found, insert sb_ins immediately after sb_temp
+		sb_new = new InternalEditorSessionBookMark(*sb_ins);
+		if (sb_new)
+		{
+			sb_new->prev = sb_temp;
+			sb_new->next = sb_temp->next;
+			sb_temp->next = sb_new;
+			if (sb_new->next)
+				sb_new->next->prev = sb_new;
+		}
+	}
+	else
+	{
+		//not found forward, look up backwards
+		sb_temp=SessionPos;
+		while (sb_temp && EditorUndoData::HashBM(sb_temp->prev) != sb_ins->prev)
+			sb_temp=sb_temp->prev;
+
+		if (sb_temp)
+		{
+			//found, insert sb_ins immediately before sb_temp
+			sb_new = new InternalEditorSessionBookMark(*sb_ins);
+			if (sb_new)
+			{
+				sb_new->prev = sb_temp->prev;
+				sb_new->next = sb_temp;
+				sb_temp->prev = sb_new;
+				if (sb_new->prev)
+					sb_new->prev->next = sb_new;
+			}
+		}
+		else if (!sb_ins->prev)
+		{
+			//SessionPos is NULL, but sb_ins was the first sb in the list
+			sb_new = new InternalEditorSessionBookMark(*sb_ins);
+			if (sb_new)
+			{
+				sb_new->next = NULL;
+				SessionPos = sb_new;
+			}
+		}
+		else
+			sb_new = sb_ins; //just to mark success
+	}
+
+	return sb_new?TRUE:FALSE;
+}
+
+//Return the first session bookmark (and do not change SessionPos);
+// On return, piCount will be set to the count of session bookmark preceding the current one
 InternalEditorSessionBookMark* Editor::PointerToFirstSessionBookmark(int *piCount)
 {
 	InternalEditorSessionBookMark *sb_temp=SessionPos;
@@ -6664,6 +6762,9 @@
 	return sb_temp;
 }
 
+//Return the last session bookmark (and do not change SessionPos);
+// piCount must be set to the count of session bookmarks preceding the current one
+// On return piCount will be set to the total count of session bookmarks
 InternalEditorSessionBookMark* Editor::PointerToLastSessionBookmark(int *piCount)
 {
 	InternalEditorSessionBookMark *sb_temp=SessionPos;
@@ -6682,6 +6783,8 @@
 	return sb_temp;
 }
 
+//Return the session bookmark of index iIdx (and do not change SessionPos); 
+// for iIdx==-1 the current bookmark is returned
 InternalEditorSessionBookMark* Editor::PointerToSessionBookmark(int iIdx) // Returns null_ptr if failed!
 {
 	InternalEditorSessionBookMark *sb_temp=SessionPos;
@@ -6717,6 +6820,7 @@
 	return FALSE;
 }
 
+//Restore the previous session bookmark, if there is any, the current one otherwise
 int Editor::PrevSessionBookmark()
 {
 	if (SessionPos)
@@ -6732,6 +6836,7 @@
 	return FALSE;
 }
 
+//Restore the next session bookmark, if there is any, the current one otherwise
 int Editor::NextSessionBookmark()
 {
 	if (SessionPos)
@@ -6747,6 +6852,7 @@
 	return FALSE;
 }
 
+//Restore the last session bookmark
 int Editor::LastSessionBookmark()
 {
 	if (SessionPos)
@@ -6758,6 +6864,8 @@
 	return FALSE;
 }
 
+//Restore the session bookmark at the specified index;
+// does nothing if there is no such index
 int Editor::GotoSessionBookmark(int iIdx)
 {
 	if (SessionPos)
@@ -6773,17 +6881,20 @@
 	return FALSE;
 }
 
+//Append new session bookmark as the last session bookmark, and move SessionPos to it
 int Editor::PushSessionBookMark()
 {
 	SessionPos=PointerToLastSessionBookmark();
 	return AddSessionBookmark(FALSE);
 }
 
+//Restore the last session bookmark and remove it
 int Editor::PopSessionBookMark()
 {
 	return (LastSessionBookmark() && DeleteSessionBookmark(SessionPos));
 }
 
+//Return index of the current session bookmark, -1 if there is none
 int Editor::CurrentSessionBookmarkIdx()
 {
 	int iIdx;
@@ -6792,6 +6903,7 @@
 	return -1;
 }
 
+//Get session bookmark at specified index into Param
 int Editor::GetSessionBookmark(int iIdx,InternalEditorBookmark *Param)
 {
 	InternalEditorSessionBookMark *sb_temp = PointerToSessionBookmark(iIdx);
@@ -6809,6 +6921,7 @@
 	return FALSE;
 }
 
+//Get all session bookmarks into the Param array
 int Editor::GetSessionBookmarks(EditorBookmarks *Param)
 {
 	int iCount=0;
diff -ur orig/unicode_far/editor.hpp new/unicode_far/editor.hpp
--- orig/unicode_far/editor.hpp	2013-06-01 05:47:04.599988100 +0200
+++ new/unicode_far/editor.hpp	2013-06-07 00:54:50.933531300 +0200
@@ -37,6 +37,7 @@
 #include "poscache.hpp"
 #include "bitflags.hpp"
 #include "config.hpp"
+#include <algorithm>
 
 class FileEditor;
 class KeyBar;
@@ -66,13 +67,15 @@
 	wchar_t EOL[10];
 	int Length;
 	wchar_t_ptr Str;
+	InternalEditorSessionBookMark *BM; //treat as uni-directional linked list
 	static size_t UndoDataSize;
 
 	EditorUndoData(int Type,const wchar_t *Str,const wchar_t *Eol,int StrNum,int StrPos,int Length=-1):
 		Type(0),
 		StrPos(0),
 		StrNum(0),
-		Length(0)
+		Length(0),
+		BM(0)
 	{
 		SetData(Type, Str, Eol, StrNum, StrPos, Length);
 	}
@@ -81,9 +84,11 @@
 	{
 		if (Length > 0)
 			UndoDataSize -= Length;
+		DeleteAllSessionBM();
 	}
 
-	EditorUndoData(EditorUndoData&& Right)
+	EditorUndoData(EditorUndoData&& Right):
+		BM(0)
 	{
 		*this = std::move(Right);
 		Right.Length = 0;
@@ -97,6 +102,7 @@
 		Length = Right.Length;
 		Str.swap(Right.Str);
 		wcscpy(EOL, Right.EOL);
+		std::swap(BM, Right.BM);
 		return *this;
 	}
 
@@ -124,6 +130,42 @@
 		}
 		else
 			this->Str.reset();
+		DeleteAllSessionBM();
+	}
+
+	void AddSessionBM(const InternalEditorSessionBookMark *BM)
+	{
+		InternalEditorSessionBookMark *BM_new = new InternalEditorSessionBookMark(*BM);
+		if (BM_new)
+		{
+			BM_new->prev = HashBM(BM->prev);
+			BM_new->next = this->BM;
+			this->BM = BM_new;
+		}
+	}
+
+	void DeleteAllSessionBM()
+	{
+		InternalEditorSessionBookMark *BM=this->BM, *BM_next;
+		this->BM = NULL;
+		while (BM)
+		{
+			BM_next = BM->next;
+			delete BM;
+			BM = BM_next;
+		}
+	}
+
+	static InternalEditorSessionBookMark *HashBM(InternalEditorSessionBookMark *BM)
+	{
+		if (BM)
+		{
+			size_t x = reinterpret_cast<size_t>(BM);
+			x = x ^ (BM->Line<<16) ^ (BM->Cursor);
+			return reinterpret_cast<InternalEditorSessionBookMark *>(x);
+		}
+		else
+			return NULL;
 	}
 };
 
@@ -232,8 +274,9 @@
 		int StartLine;
 		int StartChar;
 
+		//numbered bookmarks (accessible by Ctrl-0..9)
 		Bookmarks<editor_bookmark> SavePos;
-
+		//pointer to the current "session" bookmark (in the list of "session" bookmarks accessible through BM.Goto(n))
 		InternalEditorSessionBookMark *SessionPos;
 		BOOL NewSessionPos;
 
@@ -279,6 +322,7 @@
 		void UnmarkMacroBlock();
 
 		void AddUndoData(int Type,const wchar_t *Str=nullptr,const wchar_t *Eol=nullptr,int StrNum=0,int StrPos=0,int Length=-1);
+		void AddUndoData(const InternalEditorSessionBookMark *BM);
 		void Undo(int redo);
 		void SelectAll();
 		//void SetStringsTable();
@@ -298,6 +342,7 @@
 		int DeleteSessionBookmark(InternalEditorSessionBookMark *sb_delete);
 		int RestoreSessionBookmark();
 		int AddSessionBookmark(BOOL blNewPos=TRUE);
+		int InsertSessionBookmarkBack(InternalEditorSessionBookMark *sb_ins);
 		InternalEditorSessionBookMark* PointerToFirstSessionBookmark(int *piCount=nullptr);
 		InternalEditorSessionBookMark* PointerToLastSessionBookmark(int *piCount=nullptr);
 		InternalEditorSessionBookMark* PointerToSessionBookmark(int iIdx);
undo_bookmarks2.diff (12,293 bytes)   

DrKnS

2013-06-12 18:33

administrator   bugnote:0011131

3450.

xarx

2013-06-28 09:26

reporter   bugnote:0011209

Verified in build 3479.

Issue History

Date Modified Username Field Change
2013-06-06 19:35 xarx New Issue
2013-06-06 19:35 xarx File Added: undo_bookmarks.diff
2013-06-06 19:37 xarx Note Added: 0011111
2013-06-06 19:37 xarx Note Edited: 0011111
2013-06-06 19:38 xarx Note Edited: 0011111
2013-06-06 19:38 xarx Tag Attached: editor
2013-06-06 19:38 xarx Tag Attached: bookmarks
2013-06-06 23:01 xarx File Added: undo_bookmarks2.diff
2013-06-06 23:03 xarx Note Edited: 0011111
2013-06-12 18:33 DrKnS Note Added: 0011131
2013-06-12 18:33 DrKnS Assigned To => DrKnS
2013-06-12 18:33 DrKnS Status new => feedback
2013-06-28 09:26 xarx Note Added: 0011209
2013-06-28 09:26 xarx Status feedback => assigned
2013-06-28 09:26 xarx Status assigned => resolved
2013-06-28 15:26 DrKnS Build => 3450
2013-06-28 15:26 DrKnS Status resolved => closed
2013-06-28 15:26 DrKnS Resolution open => fixed
2013-06-28 15:26 DrKnS Fixed in Version => 3.0