mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-04-18 15:09:26 +02:00
JediCodeFormat: Add option to format only selected text. Issue #37652, patch from Domingo Galmés.
git-svn-id: trunk@63850 -
This commit is contained in:
parent
080e21106f
commit
eff8a039ba
components/jcf2
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user