{ /*************************************************************************** encloseselectiondlg.pas ----------------------- ***************************************************************************/ *************************************************************************** * * * This source is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This code is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * A copy of the GNU General Public License is available on the World * * Wide Web at . You can also * * obtain it by writing to the Free Software Foundation, * * Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1335, USA. * * * *************************************************************************** Author: Mattias Gaertner Abstract: Dialog to setup parameters of the enclose selection function } unit EncloseSelectionDlg; {$mode objfpc}{$H+} interface uses Classes, SysUtils, // LCL Forms, Controls, Graphics, Dialogs, ExtCtrls, ButtonPanel, // LazUtils LazUTF8, LazTracer, LazStringUtils, // CodeTools BasicCodeTools, CodeToolManager, SourceChanger, // IDE LazarusIDEStrConsts; type TEncloseSelectionType = ( estTryFinally, estTryExcept, estBeginEnd, estForBeginEnd, estWhileDoBeginEnd, estRepeatUntil, estWith, estPascalComment, estRegionArea ); { TEncloseSelectionDialog } TEncloseSelectionDialog = class(TForm) ButtonPanel: TButtonPanel; TypeRadiogroup: TRADIOGROUP; procedure EncloseSelectionDialogCREATE(Sender: TObject); private public function GetEncloseType: TEncloseSelectionType; end; function ShowEncloseSelectionDialog(out TheType: TEncloseSelectionType ): TModalResult; function EncloseSelectionTypeDescription(TheType: TEncloseSelectionType ): string; procedure GetEncloseSelectionParams(TheType: TEncloseSelectionType; out Template: string); procedure EncloseTextSelection(const Template: string; Source: TStrings; SelectionStart, SelectionEnd: TPoint; out NewSelection: string; out NewCursor: TPoint); implementation {$R *.lfm} function EncloseSelectionTypeDescription(TheType: TEncloseSelectionType): string; begin Result:=''; case TheType of estTryFinally: Result:='Try..Finally'; estTryExcept: Result:='Try..Except'; estBeginEnd: Result:='Begin..End'; estForBeginEnd: Result:='For | do begin..end'; estWhileDoBeginEnd: Result:='While | do begin..end'; estRepeatUntil: Result:='Repeat..Until |'; estWith: Result:='With | do begin..end'; estPascalComment: Result:='{..}'; estRegionArea: Result:='{$REGION ''|''}..{$ENDREGION}'; else RaiseGDBException('EncloseSelectionTypeDescription'); end; end; function ShowEncloseSelectionDialog(out TheType: TEncloseSelectionType ): TModalResult; var TheDialog: TEncloseSelectionDialog; begin TheType:=estBeginEnd; TheDialog:=TEncloseSelectionDialog.Create(nil); Result:=TheDialog.ShowModal; if Result=mrOk then TheType:=TheDialog.GetEncloseType; TheDialog.Free; end; procedure GetEncloseSelectionParams(TheType: TEncloseSelectionType; out Template: string); begin case TheType of estTryFinally: Template:='try'+LineEnding +' '+LineEnding +'finally'+LineEnding +' |'+LineEnding +'end;'+LineEnding; estTryExcept: Template:='try'+LineEnding +' '+LineEnding +'except'+LineEnding +' |'+LineEnding +'end;'+LineEnding; estBeginEnd: Template:='begin'+LineEnding +' |'+LineEnding +'end;'+LineEnding; estForBeginEnd: Template:='for | do begin'+LineEnding +' '+LineEnding +'end;'+LineEnding; estWhileDoBeginEnd: Template:='while | do begin'+LineEnding +' '+LineEnding +'end;'+LineEnding; estRepeatUntil: Template:='repeat'+LineEnding +' '+LineEnding +'until |;'+LineEnding; estWith: Template:='with | do begin'+LineEnding +' '+LineEnding +'end;'+LineEnding; estPascalComment: Template:='{'+LineEnding +' |'+LineEnding +'}'+LineEnding; estRegionArea: Template:='{$REGION ''|''}'+LineEnding +' '+LineEnding +'{$ENDREGION}'+LineEnding; else RaiseGDBException('GetEnclosedSelectionParams'); end; end; procedure EncloseTextSelection(const Template: string; Source: TStrings; SelectionStart, SelectionEnd: TPoint; out NewSelection: string; out NewCursor: TPoint); var TemplateLen: Integer; TemplatePos: Integer; LastWrittenTemplatePos: Integer; NewSelect: TMemoryStream; Y: Integer; X: Integer; OldSelectionIndent: Integer; TemplateIndent: Integer; CutLastLineBreak: Boolean; CutPos: Integer; procedure AddBeautified(const s: string); var NewStr: String; LengthOfLastLine: integer; LineEndCnt: Integer; CurIndent: Integer; FirstLineIndent: Integer; EndPos: Integer; begin if s='' then exit; NewStr:=s; CurIndent:=OldSelectionIndent; if NewSelect.Position=0 then begin FirstLineIndent:=OldSelectionIndent-SelectionStart.X+1; if FirstLineIndent<0 then FirstLineIndent:=0; NewStr:=GetIndentStr(FirstLineIndent)+NewStr; dec(CurIndent,FirstLineIndent); if CurIndent<0 then CurIndent:=0; end; //debugln('AddBeautified A X=',X,' Y=',Y,' CurIndent=',CurIndent,' NewStr="',NewStr,'"'); dec(CurIndent,GetLineIndent(NewStr,1)); if CurIndent<0 then CurIndent:=0; NewStr:=CodeToolBoss.SourceChangeCache.BeautifyCodeOptions.BeautifyStatement( NewStr,CurIndent, [bcfIndentExistingLineBreaks,bcfDoNotIndentFirstLine]); LineEndCnt:=LineEndCount(NewStr,LengthOfLastLine); if (TemplatePos>TemplateLen) then begin // cut indent at end of template if LineEndCnt>0 then begin EndPos:=length(NewStr); while (EndPos>=1) and (NewStr[EndPos]=' ') do dec(EndPos); NewStr:=copy(NewStr,1,length(NewStr)-CurIndent); LineEndCnt:=LineEndCount(NewStr,LengthOfLastLine); end; end; inc(Y,LineEndCnt); if LineEndCnt=0 then inc(X,LengthOfLastLine) else X:=LengthOfLastLine+1; if (LineEndCnt>0) or (NewSelect.Position=0) then TemplateIndent:=GetLineIndent(NewStr,length(NewStr)+1); //debugln('AddBeautified B X=',X,' Y=',Y,' TemplateIndent=',TemplateIndent,' LengthOfLastLine=',LengthOfLastLine,' NewStr="',NewSTr,'"'); NewSelect.Write(NewStr[1],length(NewStr)); end; procedure FlushTemplate; var FromPos: Integer; ToPos: Integer; begin FromPos:=LastWrittenTemplatePos+1; ToPos:=TemplatePos-1; if ToPos>TemplateLen then ToPos:=TemplateLen; if FromPos<=ToPos then AddBeautified(copy(Template,FromPos,ToPos-FromPos+1)); LastWrittenTemplatePos:=ToPos; end; procedure CalculateCursorPos; begin NewCursor:=Point(X,Y); end; procedure InsertSelection; var CurY: Integer; CurLine: string; IndentStr: String; MinX: Integer; MaxX: Integer; l: Integer; begin IndentStr:=GetIndentStr(TemplateIndent-OldSelectionIndent); for CurY:=SelectionStart.Y to SelectionEnd.Y do begin CurLine:=Source[CurY-1]; //debugln(['InsertSelection CurY=',CurY,' CurLine="',dbgstr(CurLine),'"']); MinX:=1; MaxX:=length(CurLine)+1; if (CurY=SelectionStart.Y) then begin MinX:=SelectionStart.X; if MinX<=OldSelectionIndent then MinX:=OldSelectionIndent+1; if MinX>MaxX then MinX:=MaxX; end; if (CurY=SelectionEnd.Y) and (MaxX>SelectionEnd.X) then MaxX:=SelectionEnd.X; //debugln(['InsertSelection CurY=',CurY,' Range=',MinX,'-',MaxX,' Indent="',length(IndentStr),'" "',copy(CurLine,MinX,MaxX-MinX),'"']); X:=1; // write indent if (IndentStr<>'') and (CurY<>SelectionStart.Y) then begin NewSelect.Write(IndentStr[1],length(IndentStr)); inc(X,length(IndentStr)); end; // write line l:=MaxX-MinX; if l>0 then begin NewSelect.Write(CurLine[MinX],l); inc(X,l); end; // write line break and adjust cursor if CurYSelectionStart.Y) then begin CutLastLineBreak:=false; dec(SelectionEnd.Y); if SelectionEnd.Y'' then begin NewSelect.Position:=0; NewSelect.Read(NewSelection[1],length(NewSelection)); //debugln(['EncloseTextSelection CutLastLineBreak=',CutLastLineBreak,' NewSelection="',NewSelection,'"']); if CutLastLineBreak then begin CutPos:=length(NewSelection); if NewSelection[CutPos] in [#10,#13] then begin dec(CutPos); if (CutPos>=1) and (NewSelection[CutPos] in [#10,#13]) and (NewSelection[CutPos]<>NewSelection[CutPos+1]) then begin dec(CutPos); end; NewSelection:=copy(NewSelection,1,CutPos); end; end; end; NewSelect.Free; end; end; { TEncloseSelectionDialog } procedure TEncloseSelectionDialog.EncloseSelectionDialogCREATE(Sender: TObject); var t: TEncloseSelectionType; begin Caption:=lisKMEncloseSelection; TypeRadiogroup.Caption:=lisChooseStructureToEncloseSelection; with TypeRadiogroup.Items do begin BeginUpdate; for t:=Low(TEncloseSelectionType) to High(TEncloseSelectionType) do Add(EncloseSelectionTypeDescription(t)); EndUpdate; end; TypeRadiogroup.ItemIndex:=0; end; function TEncloseSelectionDialog.GetEncloseType: TEncloseSelectionType; var i: Integer; begin i:=TypeRadiogroup.ItemIndex; for Result:=Low(TEncloseSelectionType) to High(TEncloseSelectionType) do if UTF8CompareLatinTextFast(TypeRadiogroup.Items[i], EncloseSelectionTypeDescription(Result))=0 then exit; RaiseGDBException('TEncloseSelectionDialog.GetEncloseType'); end; end.