PeterPanettone 167 Posted August 3 Moving the current procedure to a new separate unit is a common desire when a unit starts to grow too large, and you realize a specific feature set could be broken out into its own module. It would be fantastic if MMX could have a ONE-STEP refactoring to achieve this. The Cumbersome, Manual, Tool-Assisted Refactoring Process: Let's assume you have UnitA.pas and you want to move ProcedureA and all its helper functions into a new UnitB.pas: Step 1: Create the New Unit First, create your new, empty unit. Go to File > New > Unit - Delphi. Save it as UnitB.pas. Decide on the structure. Will UnitB contain a class (TMyFeatureManager) or will it be a collection of standalone procedures? For this example, let's assume you're creating a new class, as that's the most common and robust approach. // In UnitB.pas: unit UnitB; interface type TMyFeatureManager = class private // Fields that were in UnitA's form will go here public procedure ProcedureA; // ... other public methods will go here end; implementation { TMyFeatureManager } procedure TMyFeatureManager.ProcedureA; begin // Code will go here end; end. Step 2: Use the "Find Usages" and "Go to Definition" Tools In UnitA.pas, right-click on ProcedureA and select Search For Usages. This will show you every place where ProcedureA is called. Inside ProcedureA, right-click on every single procedure it calls (e.g., Helper1, Helper2) and use Go to Definition (Ctrl+Click) to jump to their source. This helps you identify all the "connected procedures" you need to move. Make a list of all the procedures, functions, and private fields/variables that are part of this feature set. Step 3: Use the "Move" Refactoring (Safest Method) The Move refactoring is your best friend here. It will automatically update all references to the moved member. Move the Procedures: In UnitA.pas, right-click on a helper procedure (e.g., Helper1) that you want to move. Select Refactor > Move.... The "Move" dialog will appear. In the "Target Scope" or "Destination" field, select your new TMyFeatureManager class in UnitB. Click OK. What happens: Delphi will physically move the code for Helper1 into UnitB.pas, make it a method of TMyFeatureManager, and automatically add UnitB to the uses clause of UnitA if needed. It will also update any calls inside UnitA to correctly reference the method in the new class. Move the Fields: Do the same for any private fields from UnitA's form that are only used by these procedures. Right-click the field, choose Refactor > Move..., and select TMyFeatureManager as the destination. Repeat this process for every single procedure and field on your list. This is a painstaking but very safe process, as the IDE is managing all the references for you. Step 4: Handle Dependencies After moving the code, you will likely have some compiler errors. These are usually dependency-related. UnitA depends on UnitB: The Move refactoring should have already added UnitB to UnitA's uses clause. UnitB depends on UnitA (or other units): Your new TMyFeatureManager class will likely need to reference components or methods from the original form in UnitA. The Wrong Way (Causes Circular References): Do NOT add UnitA to the uses clause in the interface section of UnitB. This will almost certainly cause a circular unit reference. The Right Way: Add UnitA to the uses clause in the implementation section of UnitB. Pass a reference to the form from UnitA into your new class's constructor. Example of the Correct Dependency Handling: // In UnitB.pas: unit UnitB; interface uses Vcl.Forms; // Or whatever base class your form has type // Forward declare the form class from UnitA TFormA = class; TMyFeatureManager = class private FOwnerForm: TFormA; // A reference to the form that owns this manager public constructor Create(AOwnerForm: TFormA); procedure ProcedureA; end; implementation uses UnitA; // Now we can add the full unit reference here { TMyFeatureManager } constructor TMyFeatureManager.Create(AOwnerForm: TFormA); begin FOwnerForm := AOwnerForm; end; procedure TMyFeatureManager.ProcedureA; begin // Now you can safely access components on the original form FOwnerForm.Button1.Caption := 'Done'; end; end. // In UnitA.pas: procedure TFormA.FormCreate(Sender: TObject); begin // Create an instance of the manager and give it a reference to ourselves FMyFeatureManager := TMyFeatureManager.Create(Self); end; procedure TFormA.Button1Click(Sender: TObject); begin // Call the procedure in the new, separate unit FMyFeatureManager.ProcedureA; end; Share this post Link to post
Dave Novo 57 Posted August 22 Instead of adding complex features to modelMaker, this is exactly where AI shines. You simply setup Claude.ai and activate the Model Context Protocol that it can access files on your hard drive. Then tell the AI to read your units and tell it to move the relevant methods over. It can do this kind of stuff very easily, and understands much of Delphi and how do the refactorings. When I asked it to do similar things, it even filled in the uses clauses for me (even though I forgot to ask it specifically) and did the relevant initialization and finalization of the unit that was required. Share this post Link to post