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

View File

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