Thursday, March 25, 2021

Introducing Delphi Uses Helper

I just wanted to share a small IDE plugin I wrote some time ago which helps adding units to your uses clause and/or navigating through code without having to rely on the faulty "Find declaration" feature.

Installation and configuration

After installation go to Tools->Options in the IDE and then to Third Party->UsesHelper (or just hit F6, type "UsesHelper" and hit Enter)

Add any directories whose source you want to have indexed (recursively) and add directories that should be excluded from the indexing - one directory per line, no extra separators. Variables are supported like they are in other places in the IDE such as library path - as you can see with the already present entry for the Delphi sources.

Under "Unit scope names" you can add those unit scopes you want to omit when adding units to the uses clause - so if you for example like me write code that has to work with versions before XE2 this might be handy to add just Classes rather than System.Classes.

If any changes were made it will automatically start indexing the source upon hitting save - indexing will only happen at that point or when you hit the button, not on starting the IDE or at any other point (I may add this at some point in the future).

Supported versions: XE and higher

What it does internally

Indexed are: types, consts, global variables, routines, enums - did I miss anything? Well, basically everything inside the interface section of every unit it finds.

For the parsing of the files DelphiAST is being used. Any errors that might occur are being printed out in the messages panel - I am not giving support for any source code that might not be parsed properly - if you have some issue please verify it with the demo project coming with DelphiAST and report the issue over there. Also be aware that parsing might fail if you have units that are littered with custom compiler defines as the parsing mechanism is not aware of them - it just operates with the defines that DelphiAST uses (which are those of a standard Win32 application).

Indexing may take a while - it will print out when it's done.

The index is being stored in a file per Delphi version you have the plugin installed in (the settings are also per Delphi version) that is stored in the installation directory which is %localappdata%\programs\useshelper but loaded into memory by the plugin. Additionally it will index files within the currently opened project on the fly when being invoked.

Exception: System and SysInit are not being indexed as you cannot add those units to uses clause anyway but this will avoid navigating to any identifier in those units.

Format of the index.dat

If you fancy you can write that file yourself - the format is fairly simple:

<symbolname>=<unitname>|<int32> - the upper 8bit of that number are the column and the lower 24bit are the line number

Now lets try it out

When you are in the code and have the caret on some identifier you can hit Ctrl+Shift+A - which usually invokes a similar but way worse feature of the IDE - or whatever hotkey you set this to.

You will see list of units where this identifier is found in - the match has to be exact, no fuzzy matching, no guessing. It you type TSrtingList it won't find anything I guess. (implementing any kind of more sophisticated search is not planned)

Now you can navigate with the up/down keys if there are multiple units to chose from or switch between interface/implementation with the left/right keys (it currently does not detect in which section you currently are to make a best guess).

If you then hit enter the unit will get added to the appropriate uses clause - it will get added at the end and it will in a new line - no configuration to control that behavior and I will not go into the mess of doing so.

If you hit Shift+Enter the unit you selected will be opened and you will navigate to the declaration. This works even if you have no project open which "find declaration" does not.

Yes, the dialog is modal - leaving it without doing anything only works with the Esc key at this point.

Currently moving a unit between interface and implementation is not supported.

Anyhow enjoy free stuff as some selected people and me did for quite a while now and don't pester me with feature requests. ;)

Download here

1 comment: