ToDoList: Add/restore support for a separate .todo file for a project or package.

This commit is contained in:
Juha 2025-02-18 16:05:44 +02:00
parent 424b2527ef
commit 431f5187f4
2 changed files with 73 additions and 51 deletions

View File

@ -129,6 +129,7 @@ type
FIdleConnected: boolean; FIdleConnected: boolean;
FLoadingOptions: boolean; FLoadingOptions: boolean;
FStartFilename: String; FStartFilename: String;
FOwnerProjPack: TObject; // Project or package owning the FStartFilename.
FOnOpenFile : TOnOpenFile; FOnOpenFile : TOnOpenFile;
FScannedFiles: TAvlTree;// tree of TTLScannedFile FScannedFiles: TAvlTree;// tree of TTLScannedFile
FScannedIncFiles: TStringMap; FScannedIncFiles: TStringMap;
@ -190,7 +191,6 @@ procedure TIDETodoWindow.UpdateTodos(Immediately: boolean);
var var
i: integer; i: integer;
St : String; St : String;
CurOwner: TObject;
Node: TAvlTreeNode; Node: TAvlTreeNode;
CurFile: TTLScannedFile; CurFile: TTLScannedFile;
Units: TStrings; Units: TStrings;
@ -202,14 +202,14 @@ begin
exit; exit;
if not Immediately then if not Immediately then
begin begin
FUpdateNeeded:=true; FUpdateNeeded:=true;
IdleConnected:=true; IdleConnected:=true;
exit; exit;
end; end;
FUpdateNeeded:=false; FUpdateNeeded:=false;
if FUpdating then if FUpdating or (FOwnerProjPack=nil) then
Exit; Exit;
LazarusIDE.SaveSourceEditorChangesToCodeCache(nil); LazarusIDE.SaveSourceEditorChangesToCodeCache(nil);
Screen.BeginWaitCursor; Screen.BeginWaitCursor;
@ -233,10 +233,6 @@ begin
ScanFile(FStartFilename); ScanFile(FStartFilename);
end; end;
ResolveIDEItem(CurOwner,CurProject,CurPkg);
if CurOwner=nil then
Exit;
Flags:=[]; Flags:=[];
if chkListed.Checked then if chkListed.Checked then
Include(Flags, fuooListed); Include(Flags, fuooListed);
@ -247,7 +243,7 @@ begin
if chkSourceEditor.Checked then if chkSourceEditor.Checked then
Include(Flags, fuooSourceEditor); Include(Flags, fuooSourceEditor);
Units:=LazarusIDE.FindUnitsOfOwner(CurOwner,Flags); Units:=LazarusIDE.FindUnitsOfOwner(FOwnerProjPack,Flags);
for i:=0 to Units.Count-1 do for i:=0 to Units.Count-1 do
ScanFile(Units[i]); ScanFile(Units[i]);
@ -345,17 +341,17 @@ end;
function TIDETodoWindow.ProjectOpened(Sender: TObject; AProject: TLazProject): TModalResult; function TIDETodoWindow.ProjectOpened(Sender: TObject; AProject: TLazProject): TModalResult;
begin begin
Result:=mrOK; Result:=mrOK;
IDEItem:='';
UpdateTodos; UpdateTodos;
end; end;
procedure TIDETodoWindow.UpdateStartFilename; procedure TIDETodoWindow.UpdateStartFilename;
var var
NewStartFilename: String; NewStartFilename: String;
CurObject: TObject;
CurProject: TLazProject; CurProject: TLazProject;
CurPkg: TIDEPackage; CurPkg: TIDEPackage;
begin begin
ResolveIDEItem(CurObject,CurProject,CurPkg); ResolveIDEItem(FOwnerProjPack,CurProject,CurPkg);
NewStartFilename:=''; NewStartFilename:='';
if CurPkg<>nil then // package if CurPkg<>nil then // package
NewStartFilename:=CurPkg.Filename NewStartFilename:=CurPkg.Filename
@ -382,6 +378,7 @@ begin
// project // project
CurProject:=LazarusIDE.ActiveProject; CurProject:=LazarusIDE.ActiveProject;
CurOwner:=CurProject; CurOwner:=CurProject;
DebugLn(['TIDETodoWindow.ResolveIDEItem: Found project ', CurProject.MainFile.Filename]);
end; end;
end; end;
@ -397,7 +394,7 @@ end;
procedure TIDETodoWindow.SetIDEItem(AValue: string); procedure TIDETodoWindow.SetIDEItem(AValue: string);
begin begin
if FIDEItem=AValue then exit; //if FIDEItem=AValue then exit; // No check, trigger update in any case.
FIDEItem:=AValue; FIDEItem:=AValue;
UpdateStartFilename; UpdateStartFilename;
end; end;

View File

@ -109,16 +109,19 @@ type
FFilename: string; // = Tool.MainFilename FFilename: string; // = Tool.MainFilename
FCodeChangeStep: integer; // = Tool.Scanner.ChangeStep FCodeChangeStep: integer; // = Tool.Scanner.ChangeStep
FTool: TCodeTool; FTool: TCodeTool;
FCode: TCodeBuffer;
FScannedIncFiles: TStringMap; FScannedIncFiles: TStringMap;
function GetCount: integer; function GetCount: integer;
function GetItems(Index: integer): TTodoItem; function GetItems(Index: integer): TTodoItem;
procedure CreateToDoItem(const aFileName, aStartComment, aEndComment, aTokenString: string; procedure CreateToDoItem(const aFileName, aStartComment, aEndComment, aTokenString: string;
aLineNumber: Integer); aLineNumber: Integer);
procedure ScanToDos(aCode: TCodeBuffer); procedure ScanPascalToDos;
procedure ScanToDoFile;
procedure AddToDoItemFromParts(aParts: TStrings; const aFileName: string; procedure AddToDoItemFromParts(aParts: TStrings; const aFileName: string;
aLineNumber: integer; aToDoType: TToDoType; aTokenStyle: TTokenStyle); aLineNumber: integer; aToDoType: TToDoType; aTokenStyle: TTokenStyle);
public public
constructor Create(const aFilename: string; aTool: TCodeTool; aScannedIncFiles: TStringMap); constructor Create(const aFilename: string; aTool: TCodeTool; aCode: TCodeBuffer;
aScannedIncFiles: TStringMap);
destructor Destroy; override; destructor Destroy; override;
procedure Clear; procedure Clear;
procedure Add(aItem: TTodoItem); procedure Add(aItem: TTodoItem);
@ -329,34 +332,35 @@ begin
DebugLn(['ScanFile failed loading ',FN]); DebugLn(['ScanFile failed loading ',FN]);
exit; exit;
end; end;
CodeToolBoss.Explore(Code,Tool,false,false); // ignore the result Assert(aFilename=Code.Filename, 'ScanFile: aFileName <> Code.Filename');
if (Tool=nil) or (Tool.Scanner=nil) then begin CodeToolBoss.Explore(Code,Tool,false,false); // Parse Pascal code, ignore Result
DebugLn(['ScanFile failed parsing ',Code.Filename]); AVLNode:=aScannedFiles.FindKey(Pointer(aFilename),
exit;
end;
Assert(aFileName=Tool.MainFilename, 'TToDoListCore.ScanFile: aFileName <> Tool.MainFilename');
AVLNode:=aScannedFiles.FindKey(Pointer(Tool.MainFilename),
@CompareAnsiStringWithTLScannedFile); @CompareAnsiStringWithTLScannedFile);
CurFile:=nil;
//DebugLn(['ScanFile ',aFilename,' AVLNode=',AVLNode<>nil]); //DebugLn(['ScanFile ',aFilename,' AVLNode=',AVLNode<>nil]);
if AVLNode<>nil then begin if AVLNode<>nil then begin
CurFile:=TTLScannedFile(AVLNode.Data); CurFile:=TTLScannedFile(AVLNode.Data);
Assert(Assigned(CurFile), 'ScanFile: CurFile=Nil');
// Abort if this file has already been scanned and has not changed // Abort if this file has already been scanned and has not changed
if CurFile.FCodeChangeStep=Tool.Scanner.ChangeStep then exit; if Assigned(Tool) and (CurFile.FCodeChangeStep=Tool.Scanner.ChangeStep) then
end; exit;
//DebugLn(['ScanFile SCANNING ... ']); CurFile.Clear; // clear old items
end
// Add file name to list of scanned files else begin
if CurFile=nil then begin // Add file name to list of scanned files
CurFile:=TTLScannedFile.Create(aFilename, Tool, aScannedIncFiles); CurFile:=TTLScannedFile.Create(aFilename, Tool, Code, aScannedIncFiles);
aScannedFiles.Add(CurFile); aScannedFiles.Add(CurFile);
end; end;
// save ChangeStep if (Tool=nil) or (Tool.Scanner=nil) then begin
CurFile.FCodeChangeStep:=Tool.Scanner.ChangeStep; // Not Pascal. Assume .todo textual file.
//DebugLn(['ScanFile saved ChangeStep ',CurFile.FCodeChangeStep,' ',Tool.Scanner.ChangeStep]); CurFile.ScanToDoFile;
// clear old items end
CurFile.Clear; else begin
CurFile.ScanToDos(Code); Assert(aFileName=Tool.MainFilename, 'ScanFile: aFileName <> Tool.MainFilename');
// save ChangeStep
CurFile.FCodeChangeStep:=Tool.Scanner.ChangeStep;
//DebugLn(['ScanFile saved ChangeStep ',CurFile.FCodeChangeStep,' ',Tool.Scanner.ChangeStep]);
CurFile.ScanPascalToDos;
end;
end; end;
{ TTLScannedFile } { TTLScannedFile }
@ -384,9 +388,10 @@ var
lParts: TStringList; lParts: TStringList;
begin begin
//DebugLn(['TTLScannedFile.CreateToDoItem aFileName=',aFileName,' LineNumber=',aLineNumber]); //DebugLn(['TTLScannedFile.CreateToDoItem aFileName=',aFileName,' LineNumber=',aLineNumber]);
lParsingString:= TextToSingleLine(aTokenString); lParsingString := TextToSingleLine(aTokenString);
// Remove the beginning comment chars from input string // Remove the beginning comment chars from input string
Delete(lParsingString, 1, Length(aStartComment)); if aStartComment <> '' then
Delete(lParsingString, 1, Length(aStartComment));
// Remove leading and trailing blanks from input // Remove leading and trailing blanks from input
lParsingString := Trim(lParsingString); lParsingString := Trim(lParsingString);
// See if it's a TODO or DONE item // See if it's a TODO or DONE item
@ -436,11 +441,12 @@ begin
end; end;
constructor TTLScannedFile.Create(const aFilename: string; aTool: TCodeTool; constructor TTLScannedFile.Create(const aFilename: string; aTool: TCodeTool;
aScannedIncFiles: TStringMap); aCode: TCodeBuffer; aScannedIncFiles: TStringMap);
begin begin
inherited Create; inherited Create;
FFilename:=aFilename; FFilename:=aFilename;
FTool:=aTool; FTool:=aTool;
FCode:=aCode;
FScannedIncFiles:=aScannedIncFiles; FScannedIncFiles:=aScannedIncFiles;
end; end;
@ -498,30 +504,30 @@ begin
Add(lNewToDoItem); Add(lNewToDoItem);
end; end;
procedure TTLScannedFile.ScanToDos(aCode: TCodeBuffer); procedure TTLScannedFile.ScanPascalToDos;
var var
FN, Src, CommentStr, LocationIncTodo: String; FN, Src, CommentStr, LocationIncTodo: String;
p, CommentEnd: Integer; p, CommentEnd: Integer;
NestedComment: Boolean; NestedComment: Boolean;
CodeXYPosition: TCodeXYPosition; CodePos: TCodeXYPosition;
begin begin
Src:=FTool.Src; Src:=FTool.Src;
Assert(aCode.Filename=FTool.MainFilename, 'TTLScannedFile.ScanToDos: aCode.Filename<>FTool.MainFilename'); Assert(FCode.Filename=FTool.MainFilename, 'TTLScannedFile.ScanPascalToDos: aCode.Filename<>FTool.MainFilename');
p:=1; p:=1;
NestedComment:=CodeToolBoss.GetNestedCommentsFlagForFile(aCode.Filename); NestedComment:=CodeToolBoss.GetNestedCommentsFlagForFile(FCode.Filename);
repeat repeat
p:=FindNextComment(Src,p); p:=FindNextComment(Src,p);
if p>length(Src) then // No more comments found, break loop if p>length(Src) then // No more comments found, break loop
break; break;
if not FTool.CleanPosToCaret(p,CodeXYPosition) then if not FTool.CleanPosToCaret(p,CodePos) then
begin begin
ShowMessageFmt(errScanFileFailed, [ExtractFileName(FFilename)]); ShowMessageFmt(errScanFileFailed, [ExtractFileName(FFilename)]);
Exit; Exit;
end; end;
// Study include file names. Use heuristics, assume name ends with ".inc". // Study include file names. Use heuristics, assume name ends with ".inc".
FN:=CodeXYPosition.Code.Filename; FN:=CodePos.Code.Filename;
if FilenameExtIs(FN, 'inc') then // Filename and location in an include file. if FilenameExtIs(FN, 'inc') then // Filename and location in an include file.
LocationIncTodo:=FN+'_'+IntToStr(CodeXYPosition.Y) LocationIncTodo:=FN+'_'+IntToStr(CodePos.Y)
else else
LocationIncTodo:=''; LocationIncTodo:='';
// Process a comment // Process a comment
@ -531,11 +537,11 @@ begin
if (LocationIncTodo='') or not FScannedIncFiles.Contains(LocationIncTodo) then if (LocationIncTodo='') or not FScannedIncFiles.Contains(LocationIncTodo) then
begin begin
if Src[p]='/' then if Src[p]='/' then
CreateToDoItem(FN, '//', '', CommentStr, CodeXYPosition.Y) CreateToDoItem(FN, '//', '', CommentStr, CodePos.Y)
else if Src[p]='{' then else if Src[p]='{' then
CreateToDoItem(FN, '{', '}', CommentStr, CodeXYPosition.Y) CreateToDoItem(FN, '{', '}', CommentStr, CodePos.Y)
else if Src[p]='(' then else if Src[p]='(' then
CreateToDoItem(FN, '(*', '*)', CommentStr, CodeXYPosition.Y); CreateToDoItem(FN, '(*', '*)', CommentStr, CodePos.Y);
if LocationIncTodo<>'' then // Store include file location for future. if LocationIncTodo<>'' then // Store include file location for future.
FScannedIncFiles.Add(LocationIncTodo); FScannedIncFiles.Add(LocationIncTodo);
end; end;
@ -543,6 +549,25 @@ begin
until false; until false;
end; end;
procedure TTLScannedFile.ScanToDoFile;
var
List: TStringList;
i: Integer;
CommentStr: String;
begin
List:=TStringList.Create;
try
List.Text:=FCode.Source;
for i:=0 to List.Count-1 do
begin
CommentStr:=List[i];
CreateToDoItem(FCode.Filename, '', '', CommentStr, i+1)
end;
finally
List.Free;
end;
end;
{ TTodoItem } { TTodoItem }
function TTodoItem.GetAsString: string; function TTodoItem.GetAsString: string;