The Delphi Open Tools API by Ray Lischner Listing One unit Sort; { Sort selected lines of text in Delphi's source code editor. Copyright (c) 1997 Tempest Software, Inc. } interface uses Windows, SysUtils, Classes, Graphics, Controls, Dialogs, Forms, ExptIntf, ToolIntf, EditIntf, Etk; type TSortExpert = class(TEtkModule) EditSort: TEtkMenuItem; procedure EditSortClick(Sender: TObject); end; var SortExpert: TSortExpert; procedure Register; implementation {$R *.DFM} // Sort the selection in the current file. procedure SortSelection; var Module: TIModuleInterface; Editor: TIEditorInterface; View: TIEditView; Reader: TIEditReader; Writer: TIEditWriter; BlockStart: TCharPos; BlockAfter: TCharPos; StartPos, EndPos: LongInt; TopPos, CursorPos: TEditPos; Text: string; Strings: TStringList; begin // Get the module interface for the current file. with ToolServices do Module := GetModuleInterface(GetCurrentFile); // If no file is open, Module is nil. if Module = nil then Exit; try // Get the interface to the source editor. Editor := Module.GetEditorInterface; // If the file is not a source file, Editor is nil. if Editor = nil then Exit; // The expert cannot tell which view is active, so force // the user to have only one view at a time. if Editor.GetViewCount > 1 then raise Exception.Create('Close all views but one'); try // Get the limits of the selected text. BlockStart := Editor.BlockStart; BlockAfter := Editor.BlockAfter; // Sort entire lines, so modify the positions accordingly. BlockStart.CharIndex := 0; // start of line if BlockAfter.CharIndex > 0 then begin // Select the entire line by setting the After position // to the start of the next line. BlockAfter.CharIndex := 0; Inc(BlockAfter.Line); end; View := Editor.GetView(0); Assert(View <> nil); try // Convert the character positions to buffer positions. StartPos := View.CharPosToPos(BlockStart); EndPos := View.CharPosToPos(BlockAfter); // Get the selected text. Reader := Editor.CreateReader; try Assert(Reader <> nil); SetLength(Text, EndPos - StartPos - 1); Reader.GetText(StartPos, PChar(Text), Length(Text)); finally Reader.Free; end; // Sort the text. Use a TStringList because it's easy. Strings := TStringList.Create; try Strings.Text := Text; Strings.Sort; Text := Strings.Text; finally Strings.Free; end; // Replace the selection with the sorted text. Writer := Editor.CreateUndoableWriter; try Writer.CopyTo(StartPos); Writer.DeleteTo(EndPos); Writer.Insert(PChar(Text)); finally Writer.Free; end; // Set the cursor to the start of the sorted text. View.ConvertPos(False, CursorPos, BlockStart); View.CursorPos := CursorPos; // Make sure the top of the sorted text is visible. // Scroll the edit window if ncessary. if (BlockStart.Line < View.TopPos.Line) or (BlockAfter.Line >= View.TopPos.Line + View.ViewSize.CY) then begin View.ConvertPos(False, TopPos, BlockStart); View.TopPos := TopPos; end; finally View.Free; end; // Select the newly inserted, sorted text. Editor.BlockVisible := False; Editor.BlockType := btNonInclusive; Editor.BlockStart := BlockStart; Editor.BlockAfter := BlockAfter; Editor.BlockVisible := True; finally Editor.Free; end; // Bring the focus back to the source editor window. Module.ShowSource; finally Module.Free; end; end; // OnClick handler for the Edit|Sort menu item. procedure TSortExpert.EditSortClick(Sender: TObject); begin Screen.Cursor := crHourglass; try SortSelection; finally Screen.Cursor := crDefault; end; end; // You can also install this unit in a package. // The Register procedure creates and register the expert. procedure Register; begin TSortExpert.CreateAndRegister(SortExpert); end; end. 3