29-09-2026, Saat: 08:30
This expert for the Delphi IDE brings back some refactoring based on the DelphiLSP
A design-time package for Delphi 13 that connects to the built-in Delphi Language Server (DelphiLSP.exe) to provide a broad set of refactoring and code-analysis features directly in the editor:
Shortcut Feature
Ctrl+Alt+Shift+R Rename — rename an identifier project-wide, semantically (including interface implementations)
Ctrl+Alt+Shift+U Find References — list every occurrence of an identifier
Ctrl+Alt+Shift+F Find Unit References (project-wide) — list every file in the project that imports the current unit, with each identifier of that unit it actually uses
Ctrl+Alt+Shift+I Find Implementations — list all class implementations of an interface/virtual method
Ctrl+Alt+Shift+G Find original symbol — jump to the declaration via the plugin's own LSP session, as a reliable alternative to Ctrl+Click (which is flaky in Delphi 13.1). Based on PR #9 by Dumach; rebind to plain Ctrl+G in Tools → Options → Refactoring Light if you prefer the PR's original chord (the default avoids shadowing the IDE's own Ctrl+G)
Ctrl+Alt+Shift+Space Code Completion — suggestions via DelphiLSP
Ctrl+Alt+Shift+M Extract Method — move the selected block into a new method
Ctrl+Alt+Shift+V / T Extract variable — turn the selected expression into an inline var declared right before its statement, and Wrap in try..finally (T) with the cleanup inferred from the preceding statement (.Free, .EndUpdate, .Leave, ...)
Ctrl+Alt+Shift+P Convert properties — switch the selected properties between direct field access and getter / setter methods, in both directions
(menu only) Expand include files — write the content of {$I} files into their units (current unit, selected units, a directory or the whole project) so the code can be debugged where it runs
Ctrl+Alt+Shift+S Change signature — add, remove, reorder or rename parameters, change their type, modifier or default value; every header of the method's family (interfaces, implementing classes, overrides) and every call site verified via DelphiLSP change with it
Ctrl+Alt+Shift+D Safe delete — delete a method, routine, field, property, variable or constant only after proving that nothing uses it (every occurrence checked via DelphiLSP, form files, interface implementations)
Ctrl+Alt+Shift+A Align method signature — compare a method's class/interface declaration with its implementation and highlight mismatches
Ctrl+Alt+Shift+W Remove with — rewrite a with statement as inline-vars + qualified accesses. Menu entry and shortcut open the same small dialog to pick the scope (at cursor / current unit / selected units / project-wide); the last choice is preselected
Ctrl+Shift+M Move identifier to other unit — move a type / class / routine / const / var to another existing unit and update consumer uses clauses
(menu only) Extract / extend interface — pick members of the class under the cursor and either extract them into a new interface (in its own Interfaces.<Name>.pas unit) or add them to an existing interface; the class is rewritten to implement the interface and missing accessors are synthesised
(menu only) Add IInterface support to class — turn a non-TInterfacedObject class (any TObject / TPersistent / TComponent descendant) into a refcount-managed class that frees itself when the last IInterface reference is dropped
(menu only) Semantic replace — apply project-wide find / replace rules loaded from a per-project JSON file; identifier-bounded matching, comment- and string-aware, optional local-var hoisting when a rule fires multiple times in the same routine, automatic uses-clause augmentation
(menu only) Find unit for identifier — type an identifier, see which unit(s) declare it (from a background-maintained index over the whole search path) and add the chosen unit to the current file's uses clause
(automatic + menu) Live quick fixes (lightbulb) — a VS-style lightbulb appears at the caret whenever the line has an applicable fix: add the missing uses entry (E2003 / H2443), "did you mean" typo correction against the identifier index (E2003), fix or remove a broken uses entry (F2613), align an implementation header with its declaration (E2037). Also reachable on demand via Add unit for identifier at cursor / Resolve missing units... (batch dialog), and by double-clicking an error in the IDE's Structure view
(menu only) Uses cleanup (current unit) — flags uses entries that are unused (remove) or only used from the implementation section (move down — helps against circular interface references). Conservative index-based analysis: ambiguous identifiers count as usage, qualified unit-name access counts as usage, units without indexed source and {$IFDEF}'d clauses are never touched, units whose only contribution is an initialization/finalization section are kept (side effects), and units the IDE manages itself (System.Actions, action-style and touch-keyboard units) are kept because the IDE would silently re-add them; unused entries come pre-ticked, Select all / Select none buttons cover the actionable rows, and rows the analysis cannot act on cannot be ticked at all (note: initialization side effects, class helpers and operator visibility are invisible to any textual analysis — review before applying)
(menu only) Project checks — three compiler-uncatchable checks: DFM event-handler signatures (with auto-fix incl. handler generation), interface GUID duplicates, and circular unit references
All actions are reachable from the IDE's top-level Refactor menu and from the editor's right-click menu. In the editor menu the plugin registers its entries through the official INTAEditorLocalMenu API (Delphi 12+), inserted right after the IDE's own Refactoring category, so the IDE keeps building its menu exactly as it always does. On older IDEs a fallback takes over the IDE's own Refactoring entry instead: the plugin takes over the IDE's own Refactoring entry in both places (same position, same localized caption, the IDE's own entries hidden) and fills it with its own, context-sensitively enabled entries. If the editor popup has no Refactoring entry to take over, a Refactoring Light submenu is appended at the end instead.
All dialogs follow the active IDE theme (dark mode included), every result table sorts by clicking a column header (numeric columns sort numerically, click again to reverse), and the DFM event-handler check additionally has a live filter box over its findings.
Unlike purely text-based tools, this package uses the actual LSP requests that DelphiLSP advertises in its initialize response: textDocument/definition, textDocument/declaration, textDocument/implementation, textDocument/documentSymbol, textDocument/hover, textDocument/completion, and publishDiagnostics push notifications (used to detect inactive {$IFDEF} regions — diagnostic code H2655/H2656 with tag Unnecessary — and undeclared identifiers — code E2003, feeding the auto-import quick fix). DelphiLSP does not implement textDocument/rename, textDocument/references, textDocument/foldingRange, textDocument/selectionRange or textDocument/documentHighlight — for rename and find-references the package therefore runs a project-wide text search and verifies every candidate semantically via textDocument/definition. Identifiers that happen to share a name but belong to different symbols are cleanly distinguished.
The package starts its own DelphiLSP session in single-process mode. An earlier version used serverType: controller (the same mode the IDE itself uses) to maximise the diagnostic coverage, but extensive testing showed that DelphiLSP's controller-mode sub-agents (Agent0/Agent1) need parent-process / COM-bridge context only BDS.exe can provide — spawned by anything else they crash silently and every subsequent textDocument/hover returns Internal server error. Single-process mode resolves hover reliably; the trade-off is that inactive-region diagnostics now depend on whatever DelphiLSP volunteers without the controller's returnDccFlags/returnHoverModel hints. By default the LSP is pre-warmed automatically when a project opens, so the first refactoring action does not have to pay the cold-start cost; this can be turned off in Tools → Options → Refactoring Light. Every refactoring dialog shows the current LSP warm-up status in its title bar.
In the last three weeks I tested with big projects and used it myself in real life. A few fixes were neccessary, but now it should be a good help though it might not work in all cases. Changes to files that are open in the IDE go through the editor, so they can be undone there (Ctrl+Z). Files that are NOT open in an editor are written directly to disk and are not on the IDE's undo stack - for a project-wide rename keep the "Create backup" option on (the previous state of every affected file is copied to %LOCALAPPDATA%\DelphiRefactoringLight\backup<timestamp>\ with its full path mirrored) or use version control.
If you encounter any problems, please let me now, so I can fix it.
https://github.com/jaenicke/DelphiRefactoringLight
https://codeload.github.com/jaenicke/Del...ags/1.11.2
A design-time package for Delphi 13 that connects to the built-in Delphi Language Server (DelphiLSP.exe) to provide a broad set of refactoring and code-analysis features directly in the editor:
Shortcut Feature
Ctrl+Alt+Shift+R Rename — rename an identifier project-wide, semantically (including interface implementations)
Ctrl+Alt+Shift+U Find References — list every occurrence of an identifier
Ctrl+Alt+Shift+F Find Unit References (project-wide) — list every file in the project that imports the current unit, with each identifier of that unit it actually uses
Ctrl+Alt+Shift+I Find Implementations — list all class implementations of an interface/virtual method
Ctrl+Alt+Shift+G Find original symbol — jump to the declaration via the plugin's own LSP session, as a reliable alternative to Ctrl+Click (which is flaky in Delphi 13.1). Based on PR #9 by Dumach; rebind to plain Ctrl+G in Tools → Options → Refactoring Light if you prefer the PR's original chord (the default avoids shadowing the IDE's own Ctrl+G)
Ctrl+Alt+Shift+Space Code Completion — suggestions via DelphiLSP
Ctrl+Alt+Shift+M Extract Method — move the selected block into a new method
Ctrl+Alt+Shift+V / T Extract variable — turn the selected expression into an inline var declared right before its statement, and Wrap in try..finally (T) with the cleanup inferred from the preceding statement (.Free, .EndUpdate, .Leave, ...)
Ctrl+Alt+Shift+P Convert properties — switch the selected properties between direct field access and getter / setter methods, in both directions
(menu only) Expand include files — write the content of {$I} files into their units (current unit, selected units, a directory or the whole project) so the code can be debugged where it runs
Ctrl+Alt+Shift+S Change signature — add, remove, reorder or rename parameters, change their type, modifier or default value; every header of the method's family (interfaces, implementing classes, overrides) and every call site verified via DelphiLSP change with it
Ctrl+Alt+Shift+D Safe delete — delete a method, routine, field, property, variable or constant only after proving that nothing uses it (every occurrence checked via DelphiLSP, form files, interface implementations)
Ctrl+Alt+Shift+A Align method signature — compare a method's class/interface declaration with its implementation and highlight mismatches
Ctrl+Alt+Shift+W Remove with — rewrite a with statement as inline-vars + qualified accesses. Menu entry and shortcut open the same small dialog to pick the scope (at cursor / current unit / selected units / project-wide); the last choice is preselected
Ctrl+Shift+M Move identifier to other unit — move a type / class / routine / const / var to another existing unit and update consumer uses clauses
(menu only) Extract / extend interface — pick members of the class under the cursor and either extract them into a new interface (in its own Interfaces.<Name>.pas unit) or add them to an existing interface; the class is rewritten to implement the interface and missing accessors are synthesised
(menu only) Add IInterface support to class — turn a non-TInterfacedObject class (any TObject / TPersistent / TComponent descendant) into a refcount-managed class that frees itself when the last IInterface reference is dropped
(menu only) Semantic replace — apply project-wide find / replace rules loaded from a per-project JSON file; identifier-bounded matching, comment- and string-aware, optional local-var hoisting when a rule fires multiple times in the same routine, automatic uses-clause augmentation
(menu only) Find unit for identifier — type an identifier, see which unit(s) declare it (from a background-maintained index over the whole search path) and add the chosen unit to the current file's uses clause
(automatic + menu) Live quick fixes (lightbulb) — a VS-style lightbulb appears at the caret whenever the line has an applicable fix: add the missing uses entry (E2003 / H2443), "did you mean" typo correction against the identifier index (E2003), fix or remove a broken uses entry (F2613), align an implementation header with its declaration (E2037). Also reachable on demand via Add unit for identifier at cursor / Resolve missing units... (batch dialog), and by double-clicking an error in the IDE's Structure view
(menu only) Uses cleanup (current unit) — flags uses entries that are unused (remove) or only used from the implementation section (move down — helps against circular interface references). Conservative index-based analysis: ambiguous identifiers count as usage, qualified unit-name access counts as usage, units without indexed source and {$IFDEF}'d clauses are never touched, units whose only contribution is an initialization/finalization section are kept (side effects), and units the IDE manages itself (System.Actions, action-style and touch-keyboard units) are kept because the IDE would silently re-add them; unused entries come pre-ticked, Select all / Select none buttons cover the actionable rows, and rows the analysis cannot act on cannot be ticked at all (note: initialization side effects, class helpers and operator visibility are invisible to any textual analysis — review before applying)
(menu only) Project checks — three compiler-uncatchable checks: DFM event-handler signatures (with auto-fix incl. handler generation), interface GUID duplicates, and circular unit references
All actions are reachable from the IDE's top-level Refactor menu and from the editor's right-click menu. In the editor menu the plugin registers its entries through the official INTAEditorLocalMenu API (Delphi 12+), inserted right after the IDE's own Refactoring category, so the IDE keeps building its menu exactly as it always does. On older IDEs a fallback takes over the IDE's own Refactoring entry instead: the plugin takes over the IDE's own Refactoring entry in both places (same position, same localized caption, the IDE's own entries hidden) and fills it with its own, context-sensitively enabled entries. If the editor popup has no Refactoring entry to take over, a Refactoring Light submenu is appended at the end instead.
All dialogs follow the active IDE theme (dark mode included), every result table sorts by clicking a column header (numeric columns sort numerically, click again to reverse), and the DFM event-handler check additionally has a live filter box over its findings.
Unlike purely text-based tools, this package uses the actual LSP requests that DelphiLSP advertises in its initialize response: textDocument/definition, textDocument/declaration, textDocument/implementation, textDocument/documentSymbol, textDocument/hover, textDocument/completion, and publishDiagnostics push notifications (used to detect inactive {$IFDEF} regions — diagnostic code H2655/H2656 with tag Unnecessary — and undeclared identifiers — code E2003, feeding the auto-import quick fix). DelphiLSP does not implement textDocument/rename, textDocument/references, textDocument/foldingRange, textDocument/selectionRange or textDocument/documentHighlight — for rename and find-references the package therefore runs a project-wide text search and verifies every candidate semantically via textDocument/definition. Identifiers that happen to share a name but belong to different symbols are cleanly distinguished.
The package starts its own DelphiLSP session in single-process mode. An earlier version used serverType: controller (the same mode the IDE itself uses) to maximise the diagnostic coverage, but extensive testing showed that DelphiLSP's controller-mode sub-agents (Agent0/Agent1) need parent-process / COM-bridge context only BDS.exe can provide — spawned by anything else they crash silently and every subsequent textDocument/hover returns Internal server error. Single-process mode resolves hover reliably; the trade-off is that inactive-region diagnostics now depend on whatever DelphiLSP volunteers without the controller's returnDccFlags/returnHoverModel hints. By default the LSP is pre-warmed automatically when a project opens, so the first refactoring action does not have to pay the cold-start cost; this can be turned off in Tools → Options → Refactoring Light. Every refactoring dialog shows the current LSP warm-up status in its title bar.
In the last three weeks I tested with big projects and used it myself in real life. A few fixes were neccessary, but now it should be a good help though it might not work in all cases. Changes to files that are open in the IDE go through the editor, so they can be undone there (Ctrl+Z). Files that are NOT open in an editor are written directly to disk and are not on the IDE's undo stack - for a project-wide rename keep the "Create backup" option on (the previous state of every affected file is copied to %LOCALAPPDATA%\DelphiRefactoringLight\backup<timestamp>\ with its full path mirrored) or use version control.
If you encounter any problems, please let me now, so I can fix it.
https://github.com/jaenicke/DelphiRefactoringLight
https://codeload.github.com/jaenicke/Del...ags/1.11.2

