JediCodeFormat: Add option to format only selected text. Issue , patch from Domingo Galmés.

git-svn-id: trunk@63850 -
This commit is contained in:
juha 2020-08-31 07:10:22 +00:00
parent 080e21106f
commit eff8a039ba
3 changed files with 166 additions and 59 deletions
components/jcf2

View File

@ -36,11 +36,16 @@ See http://www.gnu.org/licenses/gpl.html
interface
uses
{ freepascal }SysUtils, Classes,
{ lazarus design time }
LazIDEIntf, SrcEditorIntf, IDEMsgIntf, ProjectIntf, IDEExternToolIntf,
{ local}
EditorConverter, FileConverter, ConvertTypes, jcfuiconsts;
SysUtils, Classes,
// BuildIntf
ProjectIntf, IDEExternToolIntf,
// IdeIntf
LazIDEIntf, SrcEditorIntf, IDEMsgIntf,
// LCL
Menus, Dialogs, Controls,
// local
EditorConverter, FileConverter, Converter, ConvertTypes,
JcfUIConsts, JcfStringUtils, JcfSettings, fAbout, frFiles;
type
@ -67,6 +72,7 @@ type
constructor Create;
destructor Destroy; override;
procedure DoFormatSelection(Sender: TObject);
procedure DoFormatCurrentIDEWindow(Sender: TObject);
procedure DoFormatProject(Sender: TObject);
procedure DoFormatOpen(Sender: TObject);
@ -78,15 +84,6 @@ type
implementation
uses
{ lazarus }
Menus, Dialogs, Controls,
{ jcf }
JcfStringUtils,
{ local }
fAbout, frFiles, JcfSettings;
function FileIsAllowedType(const psFileName: string): boolean;
const
ALLOWED_FILE_TYPES: array[1..5] of string = ('.pas', '.pp', '.dpr', '.lpr', '.dpk');
@ -229,6 +226,108 @@ begin
LazarusIDE.DoOpenIDEOptions(TfFiles);
end;
//offset in bytes of first char of the lines. 1 based.
procedure FindLineOffsets(const aStr: string; aLineStart, aLineEnd: integer;
out aLineStartOffset: integer; out aLineEndOffset:integer);
var
lineCount:integer;
len:integer;
pC:PChar;
offset:integer;
begin
len:=length(aStr);
pC:=@aStr[1];
lineCount:=1;
offset:=1;
aLineStartOffset:=0;
aLineEndOffset:=0;
if len<1 then
exit;
if aLineStart=1 then
aLineStartOffset:=offset;
if (aLineEnd=1) then
aLineEndOffset:=offset;
while (offset<=len) and (lineCount<=aLineEnd) do
begin
while (offset<=len) and (pC^<>#10) do
begin
inc(offset);
inc(pC);
end;
if (pC^=#10) and (offset<len) then
begin
inc(pC);
inc(offset);
inc(lineCount);
if lineCount=aLineStart then
aLineStartOffset:=offset;
if lineCount=aLineEnd then
begin
aLineEndOffset:=offset;
exit;
end;
end
else
exit;
end;
end;
procedure TJcfIdeMain.DoFormatSelection(Sender: TObject);
var
srcEditor: TSourceEditorInterface;
procedure GetSelectedBlockFullLines(out p1: TPoint; out p2: TPoint);
begin
p1 := srcEditor.BlockBegin;
p2 := srcEditor.BlockEnd;
if (p1.y > p2.y) then
begin
p1 := srcEditor.BlockEnd;
p2 := srcEditor.BlockBegin;
end;
if p2.x<=1 then
begin
if p2.y>1 then
p2.y:=p2.y-1;
end;
p2.x:=Length(srcEditor.Lines[p2.y-1])+1; //last char
p1.x:=1;
end;
var
sourceCode: string;
BlockBegin, BlockEnd: TPoint;
fcConverter: TConverter;
lineStartOffset,lineEndOffset: integer;
wi: integer;
outputstr: string;
begin
if (SourceEditorManagerIntf = nil) or (SourceEditorManagerIntf.ActiveEditor = nil) then
begin
LogIdeMessage('', 'No current window', mtInputError, -1, -1);
exit;
end;
srcEditor := SourceEditorManagerIntf.ActiveEditor;
if (srcEditor.SelectionAvailable=false) or srcEditor.ReadOnly then
Exit;
sourceCode := srcEditor.GetText(False); //get ALL editor text.
GetSelectedBlockFullLines(BlockBegin,BlockEnd);
fcConverter := TConverter.Create;
try
fcConverter.OnStatusMessage := LogIDEMessage;
fcConverter.InputCode := sourceCode;
fcConverter.GuiMessages:=true;
FindLineOffsets(sourceCode,BlockBegin.Y,BlockEnd.Y,lineStartOffset,lineEndOffset);
fcConverter.ConvertPart(lineStartOffset,lineEndOffset,true);
wI:=length(fcConverter.OutputCode);
outputstr:=Copy(fcConverter.OutputCode,1,wI-4); // converter adds 2 line ends 0d0a 0d0a
if fcConverter.ConvertError=false then
srcEditor.ReplaceText(BlockBegin, BlockEnd, outputstr);
finally
fcConverter.Free;
end;
end;
procedure TJcfIdeMain.DoAbout(Sender: TObject);
var
lcAbout: TfrmAboutBox;

View File

@ -51,27 +51,30 @@ uses
JcfIdeMain, JcfRegistrySettings;
const
FORMAT_MENU_NAME = 'jcfJEDICodeFormat';
FORMAT_CURRENT_NAME = 'jcfCurrentEditorWindow';
FORMAT_PROJECT_MENU_NAME = 'jcfAllFilesinProject';
FORMAT_OPEN_MENU_NAME = 'jcfAllOpenWindows';
FORMAT_MENU_NAME = 'jcfJEDICodeFormat';
FORMAT_SELECTION_NAME = 'jcfSelectionText';
FORMAT_CURRENT_NAME = 'jcfCurrentEditorWindow';
FORMAT_PROJECT_MENU_NAME = 'jcfAllFilesinProject';
FORMAT_OPEN_MENU_NAME = 'jcfAllOpenWindows';
//FORMAT_REG_SETTINGS_MENU_NAME = 'jcfRegistrySettings';
FORMAT_SETTINGS_MENU_NAME = 'jcfFormatSettings';
FORMAT_ABOUT_MENU_NAME = 'jcfAbout';
FORMAT_ABOUT_MENU_NAME = 'jcfAbout';
FORMAT_CATEGORY_IDECMD_NAME = 'jcfFormat';
FORMAT_MENU_SECTION1 = 'jcfSection1';
FORMAT_MENU_SECTION2 = 'jcfSection2';
FORMAT_MENU_SECTION1 = 'jcfSection1';
FORMAT_MENU_SECTION2 = 'jcfSection2';
resourcestring
FORMAT_MENU = 'JEDI Code &Format';
FORMAT_CURRENT_MENU = '&Current Editor Window';
FORMAT_CURRENT_IDECMD = 'Format code in current editor window';
FORMAT_PROJECT_MENU = '&All Files in Project';
FORMAT_OPEN_MENU = 'All &Open Windows';
FORMAT_MENU = 'JEDI Code &Format';
FORMAT_SELECTION_MENU = 'Selection';
FORMAT_CURRENT_MENU = '&Current Editor Window';
FORMAT_SELECTION_IDECMD = 'Format code in Selection';
FORMAT_CURRENT_IDECMD = 'Format code in current editor window';
FORMAT_PROJECT_MENU = '&All Files in Project';
FORMAT_OPEN_MENU = 'All &Open Windows';
//FORMAT_REG_SETTINGS_MENU = '&Registry Settings';
FORMAT_SETTINGS_MENU = '&Format Settings';
FORMAT_ABOUT_MENU = '&About';
FORMAT_CATEGORY_IDECMD = 'JEDI Code Format';
FORMAT_SETTINGS_MENU = '&Format Settings';
FORMAT_ABOUT_MENU = '&About';
FORMAT_CATEGORY_IDECMD = 'JEDI Code Format';
const
DefaultJCFOptsFile = 'jcfsettings.cfg';
@ -109,24 +112,32 @@ end;
procedure Register;
var
Cat: TIDECommandCategory;
Key: TIDEShortCut;
fcMainMenu, SubSection: TIDEMenuSection;
CmdFormatFile: TIDECommand;
KeySelect, KeyUnit: TIDEShortCut;
CmdSelect, CmdUnit: TIDECommand;
begin
SetLazarusDefaultFileName;
GetDefaultSettingsFileName := IDEGetDefaultSettingsFileName;
Cat := IDECommandList.CreateCategory(nil, FORMAT_CATEGORY_IDECMD_NAME,
FORMAT_CATEGORY_IDECMD, IDECmdScopeSrcEditOnly);
// Ctrl + D ?
Key := IDEShortCut(VK_D, [SSctrl], VK_UNKNOWN, []);
CmdFormatFile := RegisterIDECommand(Cat, FORMAT_CURRENT_NAME, FORMAT_CURRENT_IDECMD, Key,
lcJCFIDE.DoFormatCurrentIDEWindow);
fcMainMenu := RegisterIDESubMenu(itmSourceTools, FORMAT_MENU_NAME, FORMAT_MENU);
KeySelect := IDEShortCut(VK_UNKNOWN, []);
// We are running out of free shortcut combinations. Ctrl+Shift+Alt+D is free.
//KeySelect := IDEShortCut(VK_D, [ssShift,ssAlt,SSctrl]);
CmdSelect := RegisterIDECommand(Cat, FORMAT_SELECTION_NAME, FORMAT_SELECTION_IDECMD,
KeySelect, lcJCFIDE.DoFormatSelection);
RegisterIDEMenuCommand(fcMainMenu, FORMAT_SELECTION_NAME, FORMAT_SELECTION_MENU,
lcJCFIDE.DoFormatSelection, nil, CmdSelect);
// Ctrl + D
KeyUnit := IDEShortCut(VK_D, [SSctrl]);
CmdUnit := RegisterIDECommand(Cat, FORMAT_CURRENT_NAME, FORMAT_CURRENT_IDECMD,
KeyUnit, lcJCFIDE.DoFormatCurrentIDEWindow);
RegisterIDEMenuCommand(fcMainMenu, FORMAT_CURRENT_NAME, FORMAT_CURRENT_MENU,
lcJCFIDE.DoFormatCurrentIDEWindow, nil, CmdFormatFile);
lcJCFIDE.DoFormatCurrentIDEWindow, nil, CmdUnit);
RegisterIDEMenuCommand(fcMainMenu, FORMAT_PROJECT_MENU_NAME, FORMAT_PROJECT_MENU,
lcJCFIDE.DoFormatProject);

View File

@ -37,10 +37,11 @@ unit Converter;
interface
uses
{ delphi } SysUtils, Controls, Forms,
{ local } ConvertTypes, ParseTreeNode,
BuildTokenList,
BuildParseTree, BaseVisitor;
SysUtils, strutils,
// LCL
Controls, Forms,
// local
ConvertTypes, ParseTreeNode, BuildTokenList, BuildParseTree, BaseVisitor;
type
@ -89,7 +90,8 @@ type
procedure Clear;
procedure Convert;
procedure ConvertPart(const piStartIndex, piEndIndex: Integer);
procedure ConvertPart(const piStartIndex, piEndIndex: Integer;
aOnlyOutputSelection: boolean=false);
procedure CollectOutput(const pcRoot: TParseTreeNode);
@ -298,17 +300,10 @@ begin
// is it a leaf with source?
if (pcRoot is TSourceToken) then
begin
fsOutputCode := fsOutputCode + TSourceToken(pcRoot).SourceCode;
end
else
begin
// recurse, write out all child nodes
fsOutputCode := fsOutputCode + TSourceToken(pcRoot).SourceCode
else // recurse, write out all child nodes
for liLoop := 0 to pcRoot.ChildNodeCount - 1 do
begin
CollectOutput(pcRoot.ChildNodes[liLoop]);
end;
end;
end;
function TConverter.GetOnStatusMessage: TStatusMessageProc;
@ -365,7 +360,8 @@ begin
fShowParseTree.ShowParseTree(fcBuildParseTree.Root);
end;
procedure TConverter.ConvertPart(const piStartIndex, piEndIndex: Integer);
procedure TConverter.ConvertPart(const piStartIndex, piEndIndex: Integer;
aOnlyOutputSelection: boolean);
const
FORMAT_START = '{<JCF_!*$>}';
FORMAT_END = '{</JCF_!*$>}';
@ -398,17 +394,18 @@ begin
Convert;
{ locate the markers in the output,
and replace before and after }
{ locate the markers in the output, and replace before and after }
liOutputStart := Pos(FORMAT_START, fsOutputCode) + Length(FORMAT_START);
liOutputEnd := Pos(FORMAT_END, fsOutputCode);
liOutputEnd := PosEx(FORMAT_END, fsOutputCode,liOutputStart);
{ splice }
lsNewOutput := StrLeft(fsInputCode, liRealInputStart - 1);
lsNewOutput := lsNewOutput + Copy(fsOutputCode, liOutputStart, (liOutputEnd - liOutputStart));
lsNewOutput := lsNewOutput + StrRestOf(fsInputCode, liRealInputEnd + Length(FORMAT_START) + Length(FORMAT_END));
if aOnlyOutputSelection then
lsNewOutput := Copy(fsOutputCode, liOutputStart, (liOutputEnd - liOutputStart))
else begin
lsNewOutput := StrLeft(fsInputCode, liRealInputStart - 1);
lsNewOutput := lsNewOutput + Copy(fsOutputCode, liOutputStart, (liOutputEnd - liOutputStart));
lsNewOutput := lsNewOutput + StrRestOf(fsInputCode, liRealInputEnd + Length(FORMAT_START) + Length(FORMAT_END));
end;
fsOutputCode := lsNewOutput;
end;