Browse Source

Markers move along with lines

Margers 9 months ago
parent
commit
b73bf4a811
2 changed files with 245 additions and 9 deletions
  1. 11 1
      packages/ide/fpdesk.pas
  2. 234 8
      packages/ide/weditor.pas

+ 11 - 1
packages/ide/fpdesk.pas

@@ -383,7 +383,7 @@ begin
     Begin
       Move(XData[XDataOfs],B,Size);
       Inc(XDataOfs,Size);
-    End;   
+    End;
 end;
 procedure ProcessWindowInfo;
 var W: PWindow;
@@ -396,6 +396,7 @@ var W: PWindow;
     ZZ: byte;
     Z: TRect;
     Len : Byte;
+    BM: TEditorBookMark;
 begin
   XDataOfs:=0;
   Desktop^.Lock;
@@ -427,6 +428,10 @@ begin
           SW^.Editor^.SetSelection(TP,TP2);
           GetData(TP,sizeof(TP)); SW^.Editor^.SetCurPtr(TP.X,TP.Y);
           GetData(TP,sizeof(TP)); SW^.Editor^.ScrollTo(TP.X,TP.Y);
+          for L:=0 to 9 do begin
+            GetData(BM,Sizeof(BM));
+            SW^.Editor^.SetBookmark(L,BM); {restore bookmarks}
+          end;
         end;
       end;
      hcClipboardWindow:
@@ -594,6 +599,7 @@ begin
         begin
           SetLength(Title,WI.TitleLen);
           S^.Read(Title[1],WI.TitleLen);
+          FillChar(XData,SizeOf(XData),0);
           if WI.ExtraDataSize>0 then
           S^.Read(XData,WI.ExtraDataSize);
           ProcessWindowInfo;
@@ -647,6 +653,7 @@ var W: PWindow;
     St: string;
     Ch: AnsiChar;
     TP: TPoint;
+    BM: TEditorBookMark;
     L: longint;
 procedure AddData(const B; Size: word);
 begin
@@ -696,6 +703,9 @@ begin
         TP:=SW^.Editor^.SelEnd; AddData(TP,sizeof(TP));
         TP:=SW^.Editor^.CurPos; AddData(TP,sizeof(TP));
         TP:=SW^.Editor^.Delta; AddData(TP,sizeof(TP));
+        for L:=0 to 9 do begin
+          BM:=SW^.Editor^.GetBookmark(L); AddData(BM,Sizeof(BM)); {save bookmarks}
+        end;
       end;
     hcAsciiTableWindow :
       begin

+ 234 - 8
packages/ide/weditor.pas

@@ -252,6 +252,17 @@ type
       function At(Index: sw_Integer): PFold;
     end;
 
+    PEditorBookMark = ^TEditorBookMark;
+    TEditorBookMark = packed record  {we save bookmarks in *.dsk file, so packed record it is}
+      Valid  : Boolean;
+      Pos    : TPoint;
+    end;
+
+    PEditorBookMarkCollection = ^TEditorBookMarkCollection;
+    TEditorBookMarkCollection = object(TCollection)
+      function At(Index: sw_Integer): PEditorBookMark;
+    end;
+
     TEditorLineInfo = object(TObject)
       Editor: PCustomCodeEditor;
 {$if sizeof(sw_astring)>8}
@@ -270,11 +281,17 @@ type
       BeginCommentDepth,EndCommentDepth : sw_integer;
       BeginNestedComments,EndNestedComments : byte;
       Fold: PFold;
+      BookMarks: PEditorBookMarkCollection;
       constructor Init(AEditor: PCustomCodeEditor);
       destructor  Done; virtual;
       function    GetFormat: sw_astring;
       procedure   SetFormat(const AFormat: sw_astring);
       procedure   SetFold(AFold: PFold);
+      procedure   InsertMark(Mark:PEditorBookMark); virtual;
+      procedure   DeleteMark(Mark:PEditorBookMark); virtual;
+      function    MarkCount:Sw_integer; virtual;
+      function    GetMark(Index:Sw_integer):PEditorBookMark; virtual;
+      procedure   AdjustMark(APosX,Adjustment:Sw_integer); virtual;
       { Syntax information is now generated separately for each editor instance.
         This is not neccessary for a one-language IDE, but this unit contains
         a _generic_ editor object, which should be (and is) as flexible as
@@ -298,6 +315,11 @@ type
    {a}procedure   SetFlags(AFlags: longint); virtual;
       function    IsFlagSet(AFlag: longint): boolean; {$ifdef USEINLINE}inline;{$endif}
       procedure   SetFlagState(AFlag: longint; ASet: boolean);
+      procedure   InsertMark(Editor: PCustomCodeEditor; Mark: PEditorBookMark); virtual;
+      procedure   DeleteMark(Editor: PCustomCodeEditor; Mark: PEditorBookMark); virtual;
+      function    MarkCount(Editor: PCustomCodeEditor):Sw_integer; virtual;
+      function    GetMark(Editor: PCustomCodeEditor; Index: Sw_integer):PEditorBookMark; virtual;
+      procedure   AdjustMark(Editor: PCustomCodeEditor; APosX,Adjustment: Sw_integer); virtual;
       destructor  Done; virtual;
     public { internal use only! }
    {a}procedure AddEditorInfo(Index: sw_integer; AEditor: PCustomCodeEditor); virtual;
@@ -350,11 +372,6 @@ type
       (ssCommentPrefix,ssCommentSingleLinePrefix,ssCommentSuffix,ssStringPrefix,ssStringSuffix,
        ssDirectivePrefix{,ssDirectiveSuffix},ssAsmPrefix,ssAsmSuffix);
 
-    TEditorBookMark = record
-      Valid  : boolean;
-      Pos    : TPoint;
-    end;
-
     TCompleteState = (csInactive,csOffering,csDenied);
 
     PEditorBinding = ^TEditorBinding;
@@ -569,6 +586,10 @@ type
    {a}function    SaveAreaToStream(Stream: PStream; StartP,EndP: TPoint): boolean;virtual;
       function    LoadFromFile(const AFileName: string): boolean; virtual;
       function    SaveToFile(const AFileName: string): boolean; virtual;
+      function    GetBookmark(MarkIdx: sw_integer):TEditorBookMark; virtual;
+      procedure   SetBookmark(MarkIdx: sw_integer; ABookmark: TEditorBookMark); virtual;
+      function    FindMarkLineNr(MarkIdx: sw_integer):sw_integer; virtual;
+      procedure   AdjustBookMark(X, NewX, Y, NewY: sw_integer); virtual;
     public
       function    InsertFrom(Editor: PCustomCodeEditor): Boolean; virtual;
    {a}function    InsertText(const S: sw_astring): Boolean; virtual;
@@ -1393,6 +1414,41 @@ begin
     SetFlags(N);
 end;
 
+procedure TCustomLine.InsertMark(Editor: PCustomCodeEditor; Mark: PEditorBookMark);
+var LI : PEditorLineInfo;
+begin
+  LI:=GetEditorInfo(@Editor);
+  if Assigned(LI) then LI^.InsertMark(Mark);
+end;
+
+procedure TCustomLine.DeleteMark(Editor: PCustomCodeEditor; Mark: PEditorBookMark);
+var LI : PEditorLineInfo;
+begin
+  LI:=GetEditorInfo(@Editor);
+  if Assigned(LI) then LI^.DeleteMark(Mark);
+end;
+
+function  TCustomLine.MarkCount(Editor: PCustomCodeEditor):Sw_integer;
+var LI : PEditorLineInfo;
+begin
+  LI:=GetEditorInfo(@Editor);
+  if Assigned(LI) then MarkCount:=LI^.MarkCount else MarkCount:=0;
+end;
+
+function  TCustomLine.GetMark(Editor: PCustomCodeEditor; Index: Sw_integer):PEditorBookMark;
+var LI : PEditorLineInfo;
+begin
+  LI:=GetEditorInfo(@Editor);
+  if Assigned(LI) then GetMark:=LI^.GetMark(Index) else GetMark:=nil;
+end;
+
+procedure TCustomLine.AdjustMark(Editor: PCustomCodeEditor; APosX,Adjustment: Sw_integer);
+var LI : PEditorLineInfo;
+begin
+  LI:=GetEditorInfo(@Editor);
+  if Assigned(LI) then LI^.AdjustMark(APosX,Adjustment);
+end;
+
 procedure TCustomLine.AddEditorInfo(Index: sw_integer; AEditor: PCustomCodeEditor);
 begin
   { Abstract }
@@ -1413,6 +1469,11 @@ begin
   At:=inherited At(Index);
 end;
 
+function TEditorBookMarkCollection.At(Index: sw_Integer): PEditorBookMark;
+begin
+  At:=inherited At(Index);
+end;
+
 constructor TFold.Init(AEditor: PCustomCodeEditor; AParentFold: PFold; ACollapsed: boolean);
 begin
   inherited Init;
@@ -1569,6 +1630,48 @@ begin
     Fold^.AddLineReference(@Self);
 end;
 
+procedure TEditorLineInfo.InsertMark(Mark:PEditorBookMark);
+begin
+  if not assigned(BookMarks) then
+    New(BookMarks, Init(2,2));
+  BookMarks^.Insert(Mark);
+end;
+
+procedure TEditorLineInfo.DeleteMark(Mark:PEditorBookMark);
+begin
+  if assigned(BookMarks) then BookMarks^.Delete(Mark);
+end;
+
+function TEditorLineInfo.MarkCount:Sw_integer;
+begin
+  if assigned(BookMarks) then
+    MarkCount:=BookMarks^.Count
+  else MarkCount:=0;
+end;
+
+function TEditorLineInfo.GetMark(Index:Sw_integer):PEditorBookMark;
+begin
+  if assigned(BookMarks) then
+    GetMark:=BookMarks^.at(Index)
+  else GetMark:=nil;
+end;
+
+procedure TEditorLineInfo.AdjustMark(APosX,Adjustment:Sw_integer);
+var Index : sw_integer;
+    Mark:PEditorBookMark;
+begin
+  if not assigned(BookMarks) then exit;
+  for Index:=1 to BookMarks^.Count do
+  begin
+    Mark:=BookMarks^.at(Index-1);
+    if Mark^.Pos.X >=APosX then
+       Mark^.Pos.X:=Mark^.Pos.X+Adjustment
+    else
+      if (Adjustment < 0) and (Mark^.Pos.X>(APosX+Adjustment)) then
+        Mark^.Pos.X:=APosX+Adjustment;
+  end;
+end;
+
 destructor TEditorLineInfo.Done;
 begin
 {$if sizeof(sw_astring)>8}
@@ -1579,6 +1682,12 @@ begin
   Format:='';
 {$endif}
   SetFold(nil);
+  if assigned(BookMarks) then
+  begin
+    BookMarks^.DeleteAll;
+    Dispose(BookMarks,Done);
+    BookMarks:=nil;
+  end;
   inherited Done;
 end;
 
@@ -3088,6 +3197,33 @@ begin
   SaveToFile:=OK;
 end;
 
+procedure TCustomCodeEditor.AdjustBookMark(X, NewX, Y, NewY: sw_integer);
+var P : PEditorBookMark;
+    Count,Index : sw_integer;
+    Line,NewLine : PCustomLine;
+begin
+  if NewY=Y then
+    GetLine(Y)^.AdjustMark(@Self,X,NewX-X)
+  else
+  begin
+    Line:=GetLine(Y);
+    Count:=Line^.MarkCount(@Self);
+    if Count > 0 then
+    begin
+      NewLine:=GetLine(NewY);
+      for Index:=Count-1 downto 0 do
+      begin
+        P:=Line^.GetMark(@Self,Index);
+        if P^.Pos.X>=X then
+        begin
+          P^.Pos.X:=Max(0,P^.Pos.X+(NewX-X));
+          Line^.DeleteMark(@Self,P);
+          NewLine^.InsertMark(@Self,P);
+        end;
+      end;
+    end;
+  end;
+end;
 
 function TCustomCodeEditor.InsertFrom(Editor: PCustomCodeEditor): Boolean;
 var OK: boolean;
@@ -4551,9 +4687,73 @@ begin
   SetCurPtr(SelEnd.X,SelEnd.Y);
 end;
 
+function TCustomCodeEditor.GetBookmark(MarkIdx: sw_integer):TEditorBookMark;
+var LineNr : sw_integer;
+begin
+  GetBookmark.Valid:=false;
+  if not (MarkIdx in [0..9]) then exit;
+  with Bookmarks[MarkIdx] do
+    if Valid=true then
+    begin
+      LineNr:=FindMarkLineNr(MarkIdx);
+      if LineNr>=0 then
+        Pos.Y:=LineNr
+      else
+        Valid:=false;
+    end;
+  GetBookmark:=Bookmarks[MarkIdx];
+end;
+
+procedure TCustomCodeEditor.SetBookmark(MarkIdx: sw_integer; ABookmark: TEditorBookMark);
+var Line : PCustomLine;
+begin
+  if not (MarkIdx in [0..9]) then exit;
+  Bookmarks[MarkIdx]:=ABookmark;
+  if ABookmark.Valid then
+  begin
+    {invalid Pos.Y will lead to crash check it beforehand }
+    if (ABookmark.Pos.X<0) or (ABookmark.Pos.X>MaxLineLength)
+       or (ABookmark.Pos.Y<0) or (ABookmark.Pos.Y>=GetLineCount) then
+    begin
+      Bookmarks[MarkIdx].Valid:=false;
+      exit;
+    end;
+    Line:=GetLine(ABookmark.Pos.Y);
+    if Assigned(Line) then
+      Line^.InsertMark(@Self,@Bookmarks[MarkIdx])
+    else
+      Bookmarks[MarkIdx].Valid:=false; {this should not be ever reached, but safty first}
+  end;
+end;
+
+function TCustomCodeEditor.FindMarkLineNr(MarkIdx: sw_integer):sw_integer;
+var Count, CurLineNr, CurMarkNr : sw_integer;
+    Line : PCustomLine;
+    LI : PEditorLineInfo;
+begin
+  Count:=GetLineCount;
+  FindMarkLineNr:=-1;
+  if Count>1 then
+    for CurLineNr:=0 to Count-1 do
+    begin
+      Line:=GetLine(CurLineNr);
+      if Assigned(Line) then LI:=Line^.GetEditorInfo(@Self) else LI:=nil;
+      if Assigned(LI) then
+        if Assigned(LI^.BookMarks) then
+        begin
+          CurMarkNr := LI^.BookMarks^.IndexOf(@Bookmarks[MarkIdx]);
+          if CurMarkNr>=0 then
+          begin
+            FindMarkLineNr:=CurLineNr;
+            break;
+          end;
+        end;
+    end;
+end;
+
 procedure TCustomCodeEditor.JumpMark(MarkIdx: integer);
+var LineNr : sw_integer;
 begin
-  DontConsiderShiftState:=true;
   if (MarkIdx<Low(Bookmarks)) or (MarkIdx>High(Bookmarks)) then
     begin ErrorBox(FormatStrInt(msg_invalidmarkindex,MarkIdx),nil); Exit; end;
 
@@ -4561,17 +4761,38 @@ begin
   if Valid=false then
     InformationBox(FormatStrInt(msg_marknotset,MarkIdx),nil)
   else
-    SetCurPtr(Pos.X,Pos.Y);
-  DontConsiderShiftState:=false;
+    begin
+      DontConsiderShiftState:=true;
+      LineNr:=FindMarkLineNr(MarkIdx); {Find current marked line}
+      if LineNr>=0 then
+        SetCurPtr(Pos.X,LineNr)
+      else
+        InformationBox(FormatStrInt(msg_marknotset,MarkIdx),nil);
+      DontConsiderShiftState:=false;
+    end;
 end;
 
 procedure TCustomCodeEditor.DefineMark(MarkIdx: integer);
+var Line : PCustomLine;
+    LI : PEditorLineInfo;
+    LineNr : sw_integer;
 begin
   if (MarkIdx<Low(Bookmarks)) or (MarkIdx>High(Bookmarks)) then
     begin
       ErrorBox(FormatStrInt(msg_invalidmarkindex,MarkIdx),nil);
       Exit;
     end;
+  if Bookmarks[MarkIdx].Valid then
+  begin
+    LineNr:=FindMarkLineNr(MarkIdx); {find current marked line}
+    if LineNr>=0 then
+    begin
+      Line:=GetLine(LineNr);
+      Line^.DeleteMark(@Self,@Bookmarks[MarkIdx]);
+    end;
+  end;
+  Line:=GetLine(CurPos.Y);
+  Line^.InsertMark(@Self,@Bookmarks[MarkIdx]);
   with Bookmarks[MarkIdx] do
    begin
      Pos:=CurPos;
@@ -4977,6 +5198,7 @@ begin
 (*    if PointOfs(SelStart)<>PointOfs(SelEnd) then { !!! check it - it's buggy !!! }
       begin SelEnd.Y:=CurPos.Y+1; SelEnd.X:=length(GetLineText(CurPos.Y+1))-SelBack; end;*)
     UpdateAttrs(CurPos.Y,attrAll);
+    AdjustBookMark(CurPos.X,Ind,CurPos.Y,CurPos.Y+1);
     SetCurPtr(Ind,CurPos.Y+1);
     NewEI:=NewL^.GetEditorInfo(@Self);
     if Assigned(EI) and Assigned(NewEI) then
@@ -5001,6 +5223,7 @@ begin
       LimitsChanged;
       SetStoreUndo(HoldUndo);
       UpdateAttrs(CurPos.Y,attrAll);
+      AdjustBookMark(CurPos.X,Ind,CurPos.Y,CurPos.Y+1);
       SetCurPtr(Ind,CurPos.Y+1);
       { obsolete IndentStr is taken care of by the Flags PM }
       Addaction(eaInsertLine,SCP,CurPos,''{IndentStr},GetFlags);
@@ -5010,6 +5233,7 @@ begin
     begin
       UpdateAttrs(CurPos.Y,attrAll);
       SetStoreUndo(HoldUndo);
+      AdjustBookMark(CurPos.X,Ind,CurPos.Y,CurPos.Y+1);
       SetCurPtr(Ind,CurPos.Y+1);
       AddAction(eaMoveCursor,SCP,CurPos,'',GetFlags);
       SetStoreUndo(false);
@@ -5047,6 +5271,7 @@ begin
      if CurPos.Y>0 then
       begin
         CI:=Length(GetDisplayText(CurPos.Y-1));
+        AdjustBookMark(0,CI,CurPos.Y,CurPos.Y-1);
         S:=GetLineText(CurPos.Y-1);
         SetLineText(CurPos.Y-1,S+GetLineText(CurPos.Y));
         SC1.X:=Length(S);SC1.Y:=CurPOS.Y-1;
@@ -5120,6 +5345,7 @@ begin
      if CurPos.Y<GetLineCount-1 then
       begin
         SetLineText(CurPos.Y,S+CharStr(' ',CurPOS.X-Length(S))+GetLineText(CurPos.Y+1));
+        AdjustBookMark(0,CurPos.X,CurPos.Y+1,CurPos.Y);
         SDX:=CurPos.X;
         SetStoreUndo(HoldUndo);
         SCP.X:=0;SCP.Y:=CurPos.Y+1;