doublecmd/src/feditor.pas
2024-06-09 11:50:15 +03:00

1018 lines
28 KiB
ObjectPascal

{
Double Commander
-------------------------------------------------------------------------
Build-in Editor using SynEdit and his Highlighters
Copyright (C) 2006-2023 Alexander Koblov (alexx2000@mail.ru)
This program 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 program 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.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Legacy comment from its origin:
Build-in Editor for Seksi Commander
----------------------------
Licence : GNU GPL v 2.0
Author : radek.cervinka@centrum.cz
This form used SynEdit and his Highlighters
contributors:
Copyright (C) 2006-2015 Alexander Koblov (Alexx2000@mail.ru)
}
unit fEditor;
{$mode objfpc}{$H+}
interface
uses
SysUtils, Classes, Controls, Forms, ActnList, Menus, SynEdit, StdCtrls, LMessages,
ComCtrls, SynEditSearch, SynEditHighlighter, uDebug, uOSForms, uShowForm, types, Graphics,
uFormCommands, uHotkeyManager, LCLVersion, SynPluginMultiCaret, fEditSearch;
const
HotkeysCategory = 'Editor';
type
{ TfrmEditor }
TfrmEditor = class(TAloneForm,IFormCommands)
actEditCut: TAction;
actEditCopy: TAction;
actEditSelectAll: TAction;
actEditUndo: TAction;
actEditRedo: TAction;
actEditPaste: TAction;
actEditDelete: TAction;
actEditFindNext: TAction;
actEditLineEndCrLf: TAction;
actEditLineEndCr: TAction;
actEditLineEndLf: TAction;
actEditGotoLine: TAction;
actEditFindPrevious: TAction;
actFileReload: TAction;
ilBookmarks: TImageList;
MainMenu1: TMainMenu;
ActListEdit: TActionList;
actAbout: TAction;
actFileOpen: TAction;
actFileClose: TAction;
actFileSave: TAction;
actFileSaveAs: TAction;
actFileNew: TAction;
actFileExit: TAction;
MenuItem1: TMenuItem;
miFileReload: TMenuItem;
miFindPrevious: TMenuItem;
miGotoLine: TMenuItem;
miEditLineEndCr: TMenuItem;
miEditLineEndLf: TMenuItem;
miEditLineEndCrLf: TMenuItem;
miLineEndType: TMenuItem;
N5: TMenuItem;
miEncodingOut: TMenuItem;
miEncodingIn: TMenuItem;
miEncoding: TMenuItem;
miFindNext: TMenuItem;
miDelete: TMenuItem;
miSelectAll: TMenuItem;
miRedo: TMenuItem;
miDeleteContext: TMenuItem;
miSelectAllContext: TMenuItem;
miSeparator2: TMenuItem;
miPasteContext: TMenuItem;
miCopyContext: TMenuItem;
miCutContext: TMenuItem;
miSeparator1: TMenuItem;
miUndoContext: TMenuItem;
miFile: TMenuItem;
New1: TMenuItem;
Open1: TMenuItem;
pmContextMenu: TPopupMenu;
Save1: TMenuItem;
SaveAs1: TMenuItem;
N1: TMenuItem;
Exit1: TMenuItem;
miEdit: TMenuItem;
miUndo: TMenuItem;
N3: TMenuItem;
miCut: TMenuItem;
miCopy: TMenuItem;
miPaste: TMenuItem;
N4: TMenuItem;
miFind: TMenuItem;
miReplace: TMenuItem;
Help1: TMenuItem;
miAbout: TMenuItem;
StatusBar: TStatusBar;
Editor: TSynEdit;
miHighlight: TMenuItem;
actEditFind: TAction;
actEditRplc: TAction;
actConfHigh: TAction;
miDiv: TMenuItem;
miConfHigh: TMenuItem;
tbToolBar: TToolBar;
tbNew: TToolButton;
tbOpen: TToolButton;
tbSave: TToolButton;
tbSeparator1: TToolButton;
tbCut: TToolButton;
tbCopy: TToolButton;
tbPaste: TToolButton;
tbSeparator2: TToolButton;
tbUndo: TToolButton;
tbRedo: TToolButton;
tbSeparator3: TToolButton;
tbConfig: TToolButton;
tbHelp: TToolButton;
procedure actExecute(Sender: TObject);
procedure EditorMouseWheelDown(Sender: TObject; Shift: TShiftState;
{%H-}MousePos: TPoint; var Handled: Boolean);
procedure EditorMouseWheelUp(Sender: TObject; Shift: TShiftState;
{%H-}MousePos: TPoint; var Handled: Boolean);
procedure FormCreate(Sender: TObject);
procedure EditorReplaceText(Sender: TObject; const ASearch, AReplace: string;
{%H-}Line, {%H-}Column: integer; var ReplaceAction: TSynReplaceAction);
procedure EditorChange(Sender: TObject);
procedure EditorStatusChange(Sender: TObject;
{%H-}Changes: TSynStatusChanges);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure frmEditorClose(Sender: TObject; var CloseAction: TCloseAction);
private
{ Private declarations }
bNoName: Boolean;
FSearchOptions: TEditSearchOptions;
FFileName: String;
sEncodingIn,
sEncodingOut,
sEncodingStat,
sOriginalText: String;
FWaitData: TWaitData;
FElevate: TDuplicates;
FCommands: TFormCommands;
FMultiCaret: TSynPluginMultiCaret;
property Commands: TFormCommands read FCommands implements IFormCommands;
procedure ChooseEncoding(mnuMenuItem: TMenuItem; sEncoding: String);
{en
Saves editor content to a file.
@returns(@true if successful)
}
function SaveFile(const aFileName: String): Boolean;
procedure SetFileName(const AValue: String);
protected
procedure CMThemeChanged(var Message: TLMessage); message CM_THEMECHANGED;
public
{ Public declarations }
SynEditSearch: TSynEditSearch;
{
Function CreateNewTab:Integer; // return tab number
Function OpenFileNewTab(const sFileName:String):Integer;
}
destructor Destroy; override;
procedure AfterConstruction; override;
{en
Opens a file.
@returns(@true if successful)
}
function OpenFile(const aFileName: String): Boolean;
procedure UpdateStatus;
procedure SetEncodingIn(Sender:TObject);
procedure SetEncodingOut(Sender:TObject);
procedure SetHighLighter(Sender:TObject);
procedure UpdateHighlighter(Highlighter: TSynCustomHighlighter);
procedure LoadGlobalOptions;
property FileName: String read FFileName write SetFileName;
published
procedure cm_FileReload(const Params: array of string);
procedure cm_EditFind(const {%H-}Params:array of string);
procedure cm_EditFindNext(const {%H-}Params:array of string);
procedure cm_EditFindPrevious(const {%H-}Params:array of string);
procedure cm_EditGotoLine(const {%H-}Params:array of string);
procedure cm_EditLineEndCr(const {%H-}Params:array of string);
procedure cm_EditLineEndCrLf(const {%H-}Params:array of string);
procedure cm_EditLineEndLf(const {%H-}Params:array of string);
procedure cm_EditDelete(const {%H-}Params:array of string);
procedure cm_EditRedo(const {%H-}Params:array of string);
procedure cm_About(const {%H-}Params:array of string);
procedure cm_EditCopy(const {%H-}Params:array of string);
procedure cm_EditCut(const {%H-}Params:array of string);
procedure cm_EditPaste(const {%H-}Params:array of string);
procedure cm_EditSelectAll(const {%H-}Params:array of string);
procedure cm_FileNew(const {%H-}Params:array of string);
procedure cm_FileOpen(const {%H-}Params:array of string);
procedure cm_EditUndo(const {%H-}Params:array of string);
procedure cm_FileSave(const {%H-}Params:array of string);
procedure cm_FileSaveAs(const {%H-}Params:array of string);
procedure cm_FileExit(const {%H-}Params:array of string);
procedure cm_ConfHigh(const {%H-}Params:array of string);
procedure cm_EditRplc(const {%H-}Params:array of string);
end;
procedure ShowEditor(const sFileName: String; WaitData: TWaitData = nil);
var
LastEditorUsedForConfiguration: TfrmEditor = nil;
implementation
{$R *.lfm}
uses
Clipbrd, dmCommonData, dmHigh, SynEditTypes, LCLType, LConvEncoding,
uLng, uShowMsg, uGlobs, fOptions, DCClassesUtf8, uAdministrator, uHighlighters,
uOSUtils, uConvEncoding, fOptionsToolsEditor, uDCUtils, uClipboard, uFindFiles,
DCOSUtils;
procedure ShowEditor(const sFileName: String; WaitData: TWaitData = nil);
var
Editor: TfrmEditor;
begin
Editor := TfrmEditor.Create(Application);
Editor.FWaitData := WaitData;
if sFileName = '' then
Editor.cm_FileNew([''])
else
begin
if not Editor.OpenFile(sFileName) then
Exit;
end;
if (WaitData = nil) then
Editor.ShowOnTop
else begin
WaitData.ShowOnTop(Editor);
end;
LastEditorUsedForConfiguration := Editor;
end;
procedure TfrmEditor.FormCreate(Sender: TObject);
var
i:Integer;
mi:TMenuItem;
HMEditor: THMForm;
miOther: TMenuItem = nil;
EncodingsList: TStringList;
Options: TTextSearchOptions;
begin
InitPropStorage(Self);
Menu.Images:= dmComData.ilEditorImages;
LoadGlobalOptions;
// update menu highlighting
miHighlight.Clear;
for i:= 0 to dmHighl.SynHighlighterList.Count - 1 do
begin
mi:= TMenuItem.Create(miHighlight);
mi.Caption:= TSynCustomHighlighter(dmHighl.SynHighlighterList.Objects[i]).LanguageName;
mi.Tag:= i;
mi.Enabled:= True;
mi.OnClick:=@SetHighLighter;
if not TSynCustomHighlighter(dmHighl.SynHighlighterList.Objects[i]).Other then
miHighlight.Add(mi)
else begin
if (miOther = nil) then
begin
miOther:= TMenuItem.Create(miHighlight);
miOther.Caption:= rsDlgButtonOther;
end;
miOther.Add(mi);
end;
end;
if Assigned(miOther) then
miHighlight.Add(miOther);
// update menu encoding
miEncodingIn.Clear;
miEncodingOut.Clear;
EncodingsList:= TStringList.Create;
GetSupportedEncodings(EncodingsList);
for I:= 0 to EncodingsList.Count - 1 do
begin
mi:= TMenuItem.Create(miEncodingIn);
mi.Caption:= EncodingsList[I];
mi.AutoCheck:= True;
mi.RadioItem:= True;
mi.GroupIndex:= 1;
mi.OnClick:= @SetEncodingIn;
miEncodingIn.Add(mi);
end;
for I:= 0 to EncodingsList.Count - 1 do
begin
mi:= TMenuItem.Create(miEncodingOut);
mi.Caption:= EncodingsList[I];
mi.AutoCheck:= True;
mi.RadioItem:= True;
mi.GroupIndex:= 2;
mi.OnClick:= @SetEncodingOut;
miEncodingOut.Add(mi);
end;
EncodingsList.Free;
FSearchOptions.Flags := [ssoEntireScope];
// if we already search text then use last searched text
if not gFirstTextSearch then
begin
for I:= 0 to glsSearchHistory.Count - 1 do
begin
Options:= TTextSearchOptions(UInt32(UIntPtr(glsSearchHistory.Objects[I])));
if (tsoHex in Options) then
Continue;
if (tsoMatchCase in Options) then
FSearchOptions.Flags += [ssoMatchCase];
if (tsoRegExpr in Options) then
FSearchOptions.Flags += [ssoRegExpr];
FSearchOptions.SearchText:= glsSearchHistory[I];
Break;
end;
end;
FixFormIcon(Handle);
HMEditor := HotMan.Register(Self, HotkeysCategory);
HMEditor.RegisterActionList(ActListEdit);
FCommands := TFormCommands.Create(Self, ActListEdit);
FMultiCaret := TSynPluginMultiCaret.Create(Editor);
end;
procedure TfrmEditor.LoadGlobalOptions;
begin
Editor.Options:= gEditorSynEditOptions;
FontOptionsToFont(gFonts[dcfEditor], Editor.Font);
Editor.TabWidth := gEditorSynEditTabWidth;
Editor.RightEdge := gEditorSynEditRightEdge;
Editor.BlockIndent := gEditorSynEditBlockIndent;
end;
procedure TfrmEditor.actExecute(Sender: TObject);
var
cmd: string;
begin
cmd := (Sender as TAction).Name;
cmd := 'cm_' + Copy(cmd, 4, Length(cmd) - 3);
Commands.ExecuteCommand(cmd, []);
end;
procedure TfrmEditor.EditorMouseWheelDown(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
var
t:integer;
begin
if (Shift=[ssCtrl])and(gFonts[dcfEditor].Size > gFonts[dcfEditor].MinValue) then
begin
t:=Editor.TopLine;
gFonts[dcfEditor].Size:=gFonts[dcfEditor].Size-1;
FontOptionsToFont(gFonts[dcfEditor], Editor.Font);
Editor.TopLine:=t;
Editor.Refresh;
Handled:=True;
end;
end;
procedure TfrmEditor.EditorMouseWheelUp(Sender: TObject; Shift: TShiftState;
MousePos: TPoint; var Handled: Boolean);
var
t:integer;
begin
if (Shift=[ssCtrl])and(gFonts[dcfEditor].Size < gFonts[dcfEditor].MaxValue) then
begin
t:=Editor.TopLine;
gFonts[dcfEditor].Size:=gFonts[dcfEditor].Size+1;
FontOptionsToFont(gFonts[dcfEditor], Editor.Font);
Editor.TopLine:=t;
Editor.Refresh;
Handled:=True;
end;
end;
function TfrmEditor.OpenFile(const aFileName: String): Boolean;
var
Buffer: AnsiString;
Reader: TFileStreamUAC;
Highlighter: TSynCustomHighlighter;
begin
PushPop(FElevate);
try
Result := False;
try
Reader := TFileStreamUAC.Create(aFileName, fmOpenRead or fmShareDenyNone);
try
SetLength(sOriginalText, Reader.Size);
actFileSave.Enabled:= not FileIsReadOnlyEx(Reader.Handle);
Reader.Read(Pointer(sOriginalText)^, Length(sOriginalText));
finally
Reader.Free;
end;
// Try to detect encoding by first 4 kb of text
Buffer := Copy(sOriginalText, 1, 4096);
sEncodingIn := DetectEncoding(Buffer);
ChooseEncoding(miEncodingIn, sEncodingIn);
sEncodingOut := sEncodingIn; // by default
ChooseEncoding(miEncodingOut, sEncodingOut);
// Try to guess line break style
with Editor.Lines do
begin
if (sEncodingIn <> EncodingUTF16LE) and (sEncodingIn <> EncodingUTF16BE) then
TextLineBreakStyle := GuessLineBreakStyle(Buffer)
else begin
sOriginalText := Copy(sOriginalText, 3, MaxInt); // Skip BOM
TextLineBreakStyle := GuessLineBreakStyle(ConvertEncoding(Buffer, sEncodingIn, EncodingUTF8));
end;
case TextLineBreakStyle of
tlbsCRLF: actEditLineEndCrLf.Checked := True;
tlbsCR: actEditLineEndCr.Checked := True;
tlbsLF: actEditLineEndLf.Checked := True;
end;
end;
// Convert encoding if needed
if sEncodingIn = EncodingUTF8 then
Buffer := sOriginalText
else begin
Buffer := ConvertEncoding(sOriginalText, sEncodingIn, EncodingUTF8);
end;
// Load text into editor
Editor.Lines.Text := Buffer;
// Add empty line if needed
if (Length(Buffer) > 0) and (Buffer[Length(Buffer)] in [#10, #13]) then
Editor.Lines.Add(EmptyStr);
Result := True;
except
on E: EFCreateError do
begin
DCDebug(E.Message);
msgError(rsMsgErrECreate + ' ' + aFileName);
Exit;
end;
on E: EFOpenError do
begin
DCDebug(E.Message);
msgError(rsMsgErrEOpen + ' ' + aFileName);
Exit;
end;
on E: EReadError do
begin
DCDebug(E.Message);
msgError(rsMsgErrERead + ' ' + aFileName);
Exit;
end;
end;
// set up highlighter
Highlighter := dmHighl.GetHighlighter(Editor, ExtractFileExt(aFileName));
UpdateHighlighter(Highlighter);
FileName := aFileName;
Editor.Modified := False;
bNoname := False;
UpdateStatus;
finally
PushPop(FElevate);
end;
end;
function TfrmEditor.SaveFile(const aFileName: String): Boolean;
var
TextOut: String;
Encoding: String;
Writer: TFileStreamUAC;
begin
PushPop(FElevate);
try
Result := False;
try
Writer := TFileStreamUAC.Create(aFileName, fmCreate);
try
Encoding := NormalizeEncoding(sEncodingOut);
// If file is empty and encoding with BOM then write only BOM
if (Editor.Lines.Count = 0) then
begin
if (Encoding = EncodingUTF8BOM) then
Writer.WriteBuffer(UTF8BOM, SizeOf(UTF8BOM))
else if (Encoding = EncodingUTF16LE) then
Writer.WriteBuffer(UTF16LEBOM, SizeOf(UTF16LEBOM))
else if (Encoding = EncodingUTF16BE) then
Writer.WriteBuffer(UTF16BEBOM, SizeOf(UTF16BEBOM));
end
else begin
TextOut := EmptyStr;
if (Encoding = EncodingUTF16LE) then
TextOut := UTF16LEBOM
else if (Encoding = EncodingUTF16BE) then begin
TextOut := UTF16BEBOM
end;
TextOut += ConvertEncoding(Editor.Lines[0], EncodingUTF8, sEncodingOut);
Writer.WriteBuffer(Pointer(TextOut)^, Length(TextOut));
// If file has only one line then write it without line break
if Editor.Lines.Count > 1 then
begin
TextOut := TextLineBreakValue[Editor.Lines.TextLineBreakStyle];
TextOut += GetTextRange(Editor.Lines, 1, Editor.Lines.Count - 2);
// Special case for UTF-8 and UTF-8 with BOM
if (Encoding <> EncodingUTF8) and (Encoding <> EncodingUTF8BOM) then begin
TextOut:= ConvertEncoding(TextOut, EncodingUTF8, sEncodingOut);
end;
Writer.WriteBuffer(Pointer(TextOut)^, Length(TextOut));
// Write last line without line break
TextOut:= Editor.Lines[Editor.Lines.Count - 1];
// Special case for UTF-8 and UTF-8 with BOM
if (Encoding <> EncodingUTF8) and (Encoding <> EncodingUTF8BOM) then begin
TextOut:= ConvertEncoding(TextOut, EncodingUTF8, sEncodingOut);
end;
Writer.WriteBuffer(Pointer(TextOut)^, Length(TextOut));
end;
end;
// Refresh original text and encoding
if (sEncodingIn <> sEncodingOut) or (Length(sOriginalText) = 0) then
begin
sEncodingIn:= sEncodingOut;
ChooseEncoding(miEncodingIn, sEncodingIn);
if (sEncodingOut <> EncodingUTF16LE) and (sEncodingOut <> EncodingUTF16BE) then
begin
Writer.Seek(0, soBeginning);
SetLength(sOriginalText, Writer.Size);
end
else begin
Writer.Seek(2, soBeginning);
SetLength(sOriginalText, Writer.Size - 2);
end;
Writer.Read(Pointer(sOriginalText)^, Length(sOriginalText));
end;
finally
Writer.Free;
end;
Editor.Modified := False; // needed for the undo stack
Editor.MarkTextAsSaved;
Result := True;
except
on E: Exception do
msgError(rsMsgErrSaveFile + ' ' + aFileName + LineEnding + E.Message);
end;
finally
PushPop(FElevate);
end;
end;
procedure TfrmEditor.SetFileName(const AValue: String);
begin
if FFileName = AValue then
Exit;
FFileName := AValue;
Caption := ReplaceHome(FFileName);
end;
procedure TfrmEditor.CMThemeChanged(var Message: TLMessage);
var
Highlighter: TSynCustomHighlighter;
begin
Highlighter:= TSynCustomHighlighter(dmHighl.SynHighlighterHashList.Data[StatusBar.Panels[4].Text]);
if Assigned(Highlighter) then dmHighl.SetHighlighter(Editor, Highlighter);
end;
destructor TfrmEditor.Destroy;
begin
LastEditorUsedForConfiguration := nil;
HotMan.UnRegister(Self);
inherited Destroy;
if Assigned(FWaitData) then FWaitData.Done;
end;
procedure TfrmEditor.AfterConstruction;
begin
inherited AfterConstruction;
tbToolBar.ImagesWidth:= gToolIconsSize;
tbToolBar.SetButtonSize(gToolIconsSize + ScaleX(6, 96),
gToolIconsSize + ScaleY(6, 96));
end;
procedure TfrmEditor.EditorReplaceText(Sender: TObject; const ASearch,
AReplace: string; Line, Column: integer; var ReplaceAction: TSynReplaceAction );
begin
if ASearch = AReplace then
ReplaceAction := raSkip
else begin
case MsgBox(rsMsgReplaceThisText, [msmbYes, msmbNo, msmbCancel, msmbAll], msmbYes, msmbNo) of
mmrYes: ReplaceAction := raReplace;
mmrAll: ReplaceAction := raReplaceAll;
mmrNo: ReplaceAction := raSkip;
else
ReplaceAction := raCancel;
end;
end;
end;
procedure TfrmEditor.SetHighLighter(Sender:TObject);
var
Highlighter: TSynCustomHighlighter;
begin
Highlighter:= TSynCustomHighlighter(dmHighl.SynHighlighterList.Objects[TMenuItem(Sender).Tag]);
UpdateHighlighter(Highlighter);
end;
(*
This is code for multi tabs editor, it's buggy because
Synedit bad handle scrollbars in page control, maybe in
future, workaround: new tab must be visible and maybe must have focus
procedure TfrmEditor.cm_FileNewExecute(Sender: TObject);
var
iPageIndex:Integer;
begin
inherited;
iPageIndex:=CreateNewTab;
with pgEditor.Pages[iPageIndex] do
begin
Caption:='New'+IntToStr(iPageIndex);
Hint:=''; // filename
end;
end;
Function TfrmEditor.CreateNewTab:Integer; // return tab number
var
iPageIndex:Integer;
begin
with TTabSheet.Create(pgEditor) do // create Tab
begin
PageControl:=pgEditor;
iPageIndex:=PageIndex;
// now create Editor
with TSynEdit.Create(pgEditor.Pages[PageIndex]) do
begin
Parent:=pgEditor.Pages[PageIndex];
Align:=alClient;
Lines.Clear;
end;
end;
end;
procedure TfrmEditor.cm_FileOpenExecute(const Params:array of string);
var
iPageIndex:Integer;
begin
inherited;
dmDlg.OpenDialog.Filter:='*.*';
if dmDlg.OpenDialog.Execute then
OpenFileNewTab(dmDlg.OpenDialog.FileName);
end;
Function TfrmEditor.OpenFileNewTab(const sFileName:String):Integer;
var
iPageIndex:Integer;
begin
inherited;
iPageIndex:=CreateNewTab;
pgEditor.ActivePageIndex:=iPageIndex;
with pgEditor.Pages[iPageIndex] do
begin
Caption:=sFileName;
Hint:=sFileName;
TSynEdit(pgEditor.Pages[iPageIndex].Components[0]).Lines.LoadFromFile(sFileName);
end;
end;
procedure ShowEditor(lsFiles:TStringList);
var
i:Integer;
begin
with TfrmEditor.Create(Application) do
begin
try
for i:=0 to lsFiles.Count-1 do
OpenFileNewTab(lsFiles.Strings[i]);
ShowModal;
finally
Free;
end;
end;
end;
*)
procedure TfrmEditor.EditorChange(Sender: TObject);
begin
UpdateStatus;
end;
procedure TfrmEditor.UpdateStatus;
const
BreakStyle: array[TTextLineBreakStyle] of String = ('LF', 'CRLF', 'CR');
begin
if Editor.Modified then
StatusBar.Panels[0].Text:= '*'
else begin
StatusBar.Panels[0].Text:= '';
end;
StatusBar.Panels[1].Text:= Format('%d:%d',[Editor.CaretX, Editor.CaretY]);
StatusBar.Panels[2].Text:= sEncodingStat;
StatusBar.Panels[3].Text:= BreakStyle[Editor.Lines.TextLineBreakStyle];
end;
procedure TfrmEditor.SetEncodingIn(Sender: TObject);
begin
sEncodingStat:= (Sender as TMenuItem).Caption;
sEncodingIn:= sEncodingStat;
sEncodingOut:= sEncodingStat;
ChooseEncoding(miEncodingOut, sEncodingOut);
Editor.Lines.Text:= ConvertEncoding(sOriginalText, sEncodingIn, EncodingUTF8);
UpdateStatus;
end;
procedure TfrmEditor.SetEncodingOut(Sender: TObject);
begin
sEncodingOut:= (Sender as TMenuItem).Caption;
end;
procedure TfrmEditor.EditorStatusChange(Sender: TObject;
Changes: TSynStatusChanges);
begin
UpdateStatus;
miEncodingIn.Enabled := not Editor.Modified;
end;
procedure TfrmEditor.UpdateHighlighter(Highlighter: TSynCustomHighlighter);
begin
dmHighl.SetHighlighter(Editor, Highlighter);
StatusBar.Panels[4].Text:= Highlighter.LanguageName;
end;
procedure TfrmEditor.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
begin
if not Editor.Modified then
CanClose:= True
else begin
case msgYesNoCancel(Format(rsMsgFileChangedSave,[FileName])) of
mmrYes:
begin
cm_FileSave(['']);
CanClose:= not Editor.Modified;
end;
mmrNo: CanClose:= True;
else
CanClose:= False;
end;
end;
end;
procedure TfrmEditor.cm_FileReload(const Params: array of string);
begin
if Editor.Modified then
begin
if not msgYesNo(rsMsgFileReloadWarning) then
Exit;
end;
OpenFile(FFileName);
end;
procedure TfrmEditor.cm_EditFind(const Params: array of string);
begin
ShowSearchReplaceDialog(Self, Editor, cbUnchecked, FSearchOptions);
end;
procedure TfrmEditor.cm_EditFindNext(const Params:array of string);
begin
if gFirstTextSearch then
begin
FSearchOptions.Flags -= [ssoBackwards];
ShowSearchReplaceDialog(Self, Editor, cbUnchecked, FSearchOptions)
end
else if FSearchOptions.SearchText <> '' then
begin
DoSearchReplaceText(Editor, False, False, FSearchOptions);
FSearchOptions.Flags -= [ssoEntireScope];
end;
end;
procedure TfrmEditor.cm_EditFindPrevious(const Params: array of string);
begin
if gFirstTextSearch then
begin
FSearchOptions.Flags += [ssoBackwards];
ShowSearchReplaceDialog(Self, Editor, cbUnchecked, FSearchOptions);
end
else if FSearchOptions.SearchText <> '' then
begin
Editor.SelEnd := Editor.SelStart;
DoSearchReplaceText(Editor, False, True, FSearchOptions);
FSearchOptions.Flags -= [ssoEntireScope];
end;
end;
procedure TfrmEditor.cm_EditGotoLine(const Params:array of string);
var
P: TPoint;
Value: String;
NewTopLine: Integer;
begin
if ShowInputQuery(rsEditGotoLineTitle, rsEditGotoLineQuery, Value) then
begin
P.X := 1;
P.Y := StrToIntDef(Value, 1);
NewTopLine := P.Y - (Editor.LinesInWindow div 2);
if NewTopLine < 1 then NewTopLine:= 1;
Editor.CaretXY := P;
Editor.TopLine := NewTopLine;
Editor.SetFocus;
end;
end;
procedure TfrmEditor.cm_EditLineEndCr(const Params:array of string);
begin
Editor.Lines.TextLineBreakStyle:= tlbsCR;
UpdateStatus;
end;
procedure TfrmEditor.cm_EditLineEndCrLf(const Params:array of string);
begin
Editor.Lines.TextLineBreakStyle:= tlbsCRLF;
UpdateStatus;
end;
procedure TfrmEditor.cm_EditLineEndLf(const Params:array of string);
begin
Editor.Lines.TextLineBreakStyle:= tlbsLF;
UpdateStatus;
end;
procedure TfrmEditor.cm_About(const Params:array of string);
begin
msgOK(rsEditAboutText);
end;
procedure TfrmEditor.cm_EditCopy(const Params:array of string);
begin
editor.CopyToClipboard;
{$IF DEFINED(LCLGTK2) and (LCL_FULLVERSION < 1100000)}
// Workaround for Lazarus bug #0021453
ClipboardSetText(Clipboard.AsText);
{$ENDIF}
end;
procedure TfrmEditor.cm_EditCut(const Params:array of string);
begin
Editor.CutToClipboard;
{$IF DEFINED(LCLGTK2) and (LCL_FULLVERSION < 1100000)}
// Workaround for Lazarus bug #0021453
ClipboardSetText(Clipboard.AsText);
{$ENDIF}
end;
procedure TfrmEditor.cm_EditPaste(const Params:array of string);
begin
editor.PasteFromClipboard;
end;
procedure TfrmEditor.cm_EditDelete(const Params:array of string);
begin
Editor.ClearSelection;
end;
procedure TfrmEditor.cm_EditRedo(const Params:array of string);
begin
editor.Redo;
end;
procedure TfrmEditor.cm_EditSelectAll(const Params:array of string);
begin
editor.SelectAll;
end;
procedure TfrmEditor.cm_FileNew(const Params:array of string);
var
CanClose: Boolean = False;
begin
FormCloseQuery(Self, CanClose);
if not CanClose then Exit;
FileName := rsMsgNewFile;
Editor.Lines.Clear;
Editor.Modified:= False;
actFileSave.Enabled:= True;
bNoname:= True;
UpdateStatus;
end;
procedure TfrmEditor.cm_FileOpen(const Params:array of string);
var
CanClose: Boolean = False;
begin
FormCloseQuery(Self, CanClose);
if not CanClose then Exit;
dmComData.OpenDialog.Filter:= AllFilesMask;
if not dmComData.OpenDialog.Execute then Exit;
if OpenFile(dmComData.OpenDialog.FileName) then
UpdateStatus;
end;
procedure TfrmEditor.cm_EditUndo(const Params:array of string);
begin
Editor.Undo;
UpdateStatus;
end;
procedure TfrmEditor.cm_FileSave(const Params:array of string);
begin
if bNoname then
actFileSaveAs.Execute
else
begin
SaveFile(FileName);
UpdateStatus;
end;
end;
procedure TfrmEditor.cm_FileSaveAs(const Params:array of string);
var
Highlighter: TSynCustomHighlighter;
begin
dmComData.SaveDialog.FileName := FileName;
dmComData.SaveDialog.Filter:= AllFilesMask; // rewrite for highlighter
if not dmComData.SaveDialog.Execute then
Exit;
FileName := dmComData.SaveDialog.FileName;
if SaveFile(FileName) then
begin
actFileSave.Enabled:= True;
end;
bNoname:=False;
UpdateStatus;
Highlighter:= dmHighl.GetHighlighter(Editor, ExtractFileExt(FileName));
UpdateHighlighter(Highlighter);
end;
procedure TfrmEditor.cm_FileExit(const Params:array of string);
begin
Close;
end;
procedure TfrmEditor.cm_ConfHigh(const Params:array of string);
begin
LastEditorUsedForConfiguration := Self;
ShowOptions(TfrmOptionsEditor);
end;
procedure TfrmEditor.cm_EditRplc(const Params: array of string);
begin
ShowSearchReplaceDialog(Self, Editor, cbChecked, FSearchOptions)
end;
procedure TfrmEditor.frmEditorClose(Sender: TObject;
var CloseAction: TCloseAction);
begin
CloseAction:=caFree;
end;
procedure TfrmEditor.ChooseEncoding(mnuMenuItem: TMenuItem; sEncoding: String);
var
I: Integer;
begin
sEncoding:= NormalizeEncoding(sEncoding);
for I:= 0 to mnuMenuItem.Count - 1 do
begin
if SameText(NormalizeEncoding(mnuMenuItem.Items[I].Caption), sEncoding) then
begin
mnuMenuItem.Items[I].Checked:= True;
if (mnuMenuItem = miEncodingIn) then
sEncodingStat:= mnuMenuItem.Items[I].Caption;
end;
end;
end;
initialization
TFormCommands.RegisterCommandsForm(TfrmEditor, HotkeysCategory, @rsHotkeyCategoryEditor);
end.