mirror of https://gitlab.com/basile.b/dexed.git
430 lines
11 KiB
Plaintext
430 lines
11 KiB
Plaintext
unit u_term;
|
|
|
|
{$I u_defines.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, LCLType,
|
|
ActnList, LMessages, ExtCtrls, Menus, StdCtrls,
|
|
u_widget, TerminalCtrls, u_interfaces, u_writableComponent, u_observer,
|
|
u_common, u_synmemo, u_dsgncontrols;
|
|
|
|
type
|
|
|
|
TTerminalShortcuts = class(TPersistent)
|
|
private
|
|
fCopy: TShortCut;
|
|
fPaste: TShortCut;
|
|
published
|
|
property copy: TShortCut read fCopy write fCopy;
|
|
property paste: TShortCut read fPaste write fPaste;
|
|
public
|
|
constructor create;
|
|
procedure assign(source: TPersistent); override;
|
|
end;
|
|
|
|
// Terminal options
|
|
TTerminalOptionsBase = class(TWritableLfmTextComponent)
|
|
private
|
|
fBackgroundColor: TColor;
|
|
fForegroundColor: TColor;
|
|
fSelectedColor: TColor;
|
|
fFollowEditors: boolean;
|
|
fFollowProjects: boolean;
|
|
fFollowExplorer: boolean;
|
|
fScrollbackLines: longword;
|
|
fFont: TFont;
|
|
fShortcuts: TTerminalShortcuts;
|
|
procedure setFont(value: TFont);
|
|
procedure setShortcuts(value: TTerminalShortcuts);
|
|
public
|
|
constructor create(AOwner: TComponent); override;
|
|
destructor destroy; override;
|
|
procedure assign(value: TPersistent); override;
|
|
published
|
|
property backgroundColor: TColor read fBackgroundColor write fBackgroundColor;
|
|
property foregroundColor: TColor read fForegroundColor write fForegroundColor;
|
|
property selectedColor: TColor (*read fSelectedColor*) write fSelectedColor stored false;
|
|
property font: TFont read fFont write setFont;
|
|
property followEditors: boolean read fFollowEditors write fFollowEditors;
|
|
property followProjects: boolean read fFollowProjects write fFollowProjects;
|
|
property followExplorer: boolean read fFollowExplorer write fFollowExplorer;
|
|
property scrollbackLines: longword read fScrollbackLines write fScrollbackLines default 10000;
|
|
property shortcuts: TTerminalShortcuts read fShortcuts write fShortcuts;
|
|
end;
|
|
|
|
// Editable and reversible Terminal options
|
|
TTerminalOptions = class(TTerminalOptionsBase, IEditableOptions)
|
|
private
|
|
fBackup: TTerminalOptionsBase;
|
|
function optionedWantCategory(): string;
|
|
function optionedWantEditorKind: TOptionEditorKind;
|
|
function optionedWantContainer: TPersistent;
|
|
procedure optionedEvent(event: TOptionEditorEvent);
|
|
function optionedOptionsModified: boolean;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
procedure applyChanges;
|
|
end;
|
|
|
|
{ TTermWidget }
|
|
|
|
TTermWidget = class(TDexedWidget, IDocumentObserver, IProjectObserver, IMiniExplorerObserver)
|
|
Panel1: TPanel;
|
|
ScrollBar1: TScrollBar;
|
|
procedure ContentPaint(Sender: TObject);
|
|
procedure FormShortCut(var Msg: TLMKey; var Handled: Boolean);
|
|
procedure ScrollBar1Scroll(Sender: TObject; ScrollCode: TScrollCode;
|
|
var ScrollPos: Integer);
|
|
private
|
|
fTerm: TTerminal;
|
|
fOpts: TTerminalOptions;
|
|
fLastCheckedDirectory: string;
|
|
fDisableScrollBarSync: boolean;
|
|
fNeedApplyChanges: boolean;
|
|
fPaintOnce: boolean;
|
|
procedure checkDirectory(const dir: string);
|
|
procedure updateScrollBar();
|
|
procedure terminalTextScrolled(sender: TObject; delta: integer);
|
|
|
|
procedure docNew(document: TDexedMemo);
|
|
procedure docFocused(document: TDexedMemo);
|
|
procedure docChanged(document: TDexedMemo);
|
|
procedure docClosing(document: TDexedMemo);
|
|
|
|
procedure mnexDirectoryChanged(const directory: string);
|
|
|
|
procedure projNew(project: ICommonProject);
|
|
procedure projChanged(project: ICommonProject);
|
|
procedure projClosing(project: ICommonProject);
|
|
procedure projFocused(project: ICommonProject);
|
|
procedure projCompiling(project: ICommonProject);
|
|
procedure projCompiled(project: ICommonProject; success: boolean);
|
|
|
|
protected
|
|
|
|
procedure DoShow; override;
|
|
procedure SetVisible(Value: boolean); override;
|
|
|
|
public
|
|
constructor create(aOwner: TComponent); override;
|
|
destructor destroy; override;
|
|
end;
|
|
|
|
implementation
|
|
{$R *.lfm}
|
|
|
|
const
|
|
optFname = 'terminal.txt';
|
|
|
|
constructor TTerminalShortcuts.create;
|
|
begin
|
|
fCopy := KeyToShortCut(word(char('C')), [ssCtrl, ssShift]);
|
|
fPaste:= KeyToShortCut(word(char('V')), [ssCtrl, ssShift]);
|
|
end;
|
|
|
|
procedure TTerminalShortcuts.assign(source: TPersistent);
|
|
var
|
|
s: TTerminalShortcuts;
|
|
begin
|
|
if source is TTerminalShortcuts then
|
|
begin
|
|
s := TTerminalShortcuts(source);
|
|
fCopy := s.fCopy;
|
|
fPaste:= s.fPaste;
|
|
end
|
|
else inherited;
|
|
end;
|
|
|
|
constructor TTerminalOptionsBase.create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
fFont := TFont.Create;
|
|
fBackgroundColor:= clWhite;
|
|
fForegroundColor:= clBlack;
|
|
fSelectedColor:= clBlack;
|
|
fFont.Name:= 'Monospace';
|
|
fFont.Size:= 12;
|
|
fScrollbackLines:=10000;
|
|
fShortcuts := TTerminalShortcuts.create;
|
|
end;
|
|
|
|
destructor TTerminalOptionsBase.destroy;
|
|
begin
|
|
fFont.Free;
|
|
fShortcuts.Free;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TTerminalOptionsBase.setFont(value: TFont);
|
|
begin
|
|
fFont.Assign(value);
|
|
end;
|
|
|
|
procedure TTerminalOptionsBase.setShortcuts(value: TTerminalShortcuts);
|
|
begin
|
|
fShortcuts.assign(value);
|
|
end;
|
|
|
|
procedure TTerminalOptionsBase.assign(value: TPersistent);
|
|
var
|
|
s: TTerminalOptionsBase;
|
|
begin
|
|
if value is TTerminalOptionsBase then
|
|
begin
|
|
s := TTerminalOptionsBase(value);
|
|
fBackgroundColor:=s.fbackgroundColor;
|
|
fForegroundColor:=s.fForegroundColor;
|
|
fSelectedColor:=s.fSelectedColor;
|
|
followEditors:=s.fFollowEditors;
|
|
fFont.BeginUpdate;
|
|
fFont.Height:=fFont.Height+1;
|
|
fFont.Height:=fFont.Height-1;
|
|
fFont.Assign(s.font);
|
|
fFont.EndUpdate;
|
|
fShortcuts.assign(s.fShortcuts);
|
|
fScrollbackLines := s.fScrollbackLines;
|
|
end
|
|
else inherited;
|
|
end;
|
|
|
|
constructor TTerminalOptions.Create(AOwner: TComponent);
|
|
begin
|
|
inherited;
|
|
fBackup := TTerminalOptionsBase.Create(self);
|
|
end;
|
|
|
|
procedure TTerminalOptions.applyChanges;
|
|
var
|
|
w: TTermWidget;
|
|
begin
|
|
w := TTermWidget(owner);
|
|
w.fTerm.backgroundColor:= backgroundColor;
|
|
w.fTerm.foregroundColor:= foregroundColor;
|
|
//w.fTerm.selectedColor:= selectedColor;
|
|
w.fTerm.Font.BeginUpdate;
|
|
w.fTerm.Font.Assign(fFont);
|
|
// force the change: assigning does always trigger TTerminal.FontChanged.
|
|
w.fTerm.Font.Size := w.fTerm.Font.Size +1;
|
|
w.fTerm.Font.Size := w.fTerm.Font.Size -1;
|
|
w.fTerm.Font.endUpdate;
|
|
w.fTerm.scrollbackLines:=fScrollbackLines;
|
|
end;
|
|
|
|
function TTerminalOptions.optionedWantCategory(): string;
|
|
begin
|
|
result := 'Terminal';
|
|
end;
|
|
|
|
function TTerminalOptions.optionedWantEditorKind: TOptionEditorKind;
|
|
begin
|
|
result := oekGeneric;
|
|
end;
|
|
|
|
function TTerminalOptions.optionedWantContainer: TPersistent;
|
|
begin
|
|
result := self;
|
|
end;
|
|
|
|
procedure TTerminalOptions.optionedEvent(event: TOptionEditorEvent);
|
|
begin
|
|
case event of
|
|
oeeAccept:
|
|
begin
|
|
fBackup.assign(self);
|
|
applyChanges;
|
|
end;
|
|
oeeCancel:
|
|
begin
|
|
self.assign(fBackup);
|
|
applyChanges;
|
|
end;
|
|
oeeChange:
|
|
begin
|
|
applyChanges;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
function TTerminalOptions.optionedOptionsModified: boolean;
|
|
begin
|
|
result := false;
|
|
end;
|
|
|
|
constructor TTermWidget.create(aOwner: TComponent);
|
|
var
|
|
f: string;
|
|
begin
|
|
inherited;
|
|
|
|
toolbarVisible:=false;
|
|
fTerm := TTerminal.Create(Panel1);
|
|
fTerm.Align:= alClient;
|
|
fTerm.BorderSpacing.Around:=4;
|
|
fterm.Parent := Panel1;
|
|
fTerm.OnTextScrolled:= @terminalTextScrolled;
|
|
|
|
fOpts:= TTerminalOptions.Create(self);
|
|
|
|
f := getDocPath + optFname;
|
|
if f.fileExists then
|
|
fOpts.loadFromFile(f);
|
|
|
|
EntitiesConnector.addObserver(fOpts);
|
|
end;
|
|
|
|
destructor TTermWidget.destroy;
|
|
begin
|
|
fOpts.saveToFile(getDocPath + optFname);
|
|
EntitiesConnector.removeObserver(fOpts);
|
|
inherited;
|
|
end;
|
|
|
|
procedure TTermWidget.DoShow;
|
|
begin
|
|
inherited;
|
|
fNeedApplyChanges := true;
|
|
end;
|
|
|
|
procedure TTermWidget.checkDirectory(const dir: string);
|
|
var
|
|
i: TTerminalScrollInfo;
|
|
begin
|
|
fDisableScrollBarSync := true;
|
|
fLastCheckedDirectory := dir;
|
|
fTerm.SendControlChar(TASCIIControlCharacter.HOME);
|
|
fTerm.SendControlChar(TASCIIControlCharacter.VT);
|
|
fTerm.SendControlChar(TASCIIControlCharacter.LF);
|
|
fTerm.Command('cd ' + dir);
|
|
i := fTerm.getVScrollInfo();
|
|
ScrollBar1.Max := i.max;
|
|
ScrollBar1.Position := ScrollBar1.Max;
|
|
fTerm.setVScrollPosition(ScrollBar1.Max);
|
|
fDisableScrollBarSync := false;
|
|
end;
|
|
|
|
procedure TTermWidget.SetVisible(Value: boolean);
|
|
begin
|
|
inherited;
|
|
if Value then
|
|
fNeedApplyChanges := true;
|
|
end;
|
|
|
|
procedure TTermWidget.ContentPaint(Sender: TObject);
|
|
var
|
|
s: string;
|
|
begin
|
|
if not fNeedApplyChanges then
|
|
exit;
|
|
fNeedApplyChanges:=false;
|
|
fOpts.applyChanges;
|
|
// ugly fix for https://gitlab.com/basile.b/dexed/-/issues/5
|
|
if not fPaintOnce then
|
|
begin
|
|
s := fLastCheckedDirectory;
|
|
fLastCheckedDirectory := '';
|
|
if s.isNotEmpty then
|
|
checkDirectory(s);
|
|
end;
|
|
fPaintOnce := true;
|
|
end;
|
|
|
|
procedure TTermWidget.terminalTextScrolled(sender: TObject; delta: integer);
|
|
begin
|
|
updateScrollBar();
|
|
end;
|
|
|
|
procedure TTermWidget.updateScrollBar();
|
|
var
|
|
i: TTerminalScrollInfo;
|
|
begin
|
|
if fDisableScrollBarSync or not visible or fTerm.isNotAssigned then
|
|
exit;
|
|
i := fTerm.getVScrollInfo();
|
|
ScrollBar1.SetParams(i.value, i.min, i.max, i.pageSize);
|
|
end;
|
|
|
|
procedure TTermWidget.FormShortCut(var Msg: TLMKey; var Handled: Boolean);
|
|
var
|
|
s: TShortCut;
|
|
begin
|
|
Handled := false;
|
|
s := KeyToShortCut(Msg.CharCode, KeyDataToShiftState(Msg.KeyData));
|
|
if s = fOpts.shortcuts.copy then
|
|
begin
|
|
fTerm.copyToClipboard();
|
|
handled := true;
|
|
end
|
|
else if s = fOpts.shortcuts.paste then
|
|
begin
|
|
fTerm.pasteFromClipboard();
|
|
handled := true;
|
|
end;
|
|
end;
|
|
|
|
procedure TTermWidget.ScrollBar1Scroll(Sender: TObject;
|
|
ScrollCode: TScrollCode; var ScrollPos: Integer);
|
|
begin
|
|
fTerm.setVScrollPosition(ScrollPos);
|
|
end;
|
|
|
|
procedure TTermWidget.mnexDirectoryChanged(const directory: string);
|
|
begin
|
|
if fOpts.followExplorer and directory.dirExists and
|
|
not SameText(directory, fLastCheckedDirectory) then
|
|
checkDirectory(directory);
|
|
end;
|
|
|
|
procedure TTermWidget.docNew(document: TDexedMemo);
|
|
begin
|
|
end;
|
|
|
|
procedure TTermWidget.docFocused(document: TDexedMemo);
|
|
var
|
|
s: string;
|
|
begin
|
|
s := document.fileName.extractFileDir;
|
|
if fOpts.followEditors and s.dirExists and not SameText(s, fLastCheckedDirectory) then
|
|
checkDirectory(s);
|
|
end;
|
|
|
|
procedure TTermWidget.docChanged(document: TDexedMemo);
|
|
begin
|
|
end;
|
|
|
|
procedure TTermWidget.docClosing(document: TDexedMemo);
|
|
begin
|
|
end;
|
|
|
|
procedure TTermWidget.projNew(project: ICommonProject);
|
|
begin
|
|
end;
|
|
|
|
procedure TTermWidget.projChanged(project: ICommonProject);
|
|
begin
|
|
end;
|
|
|
|
procedure TTermWidget.projClosing(project: ICommonProject);
|
|
begin
|
|
end;
|
|
|
|
procedure TTermWidget.projFocused(project: ICommonProject);
|
|
var
|
|
s: string;
|
|
begin
|
|
s := project.fileName.extractFileDir;
|
|
if fOpts.followProjects and s.dirExists and not SameText(s, fLastCheckedDirectory) then
|
|
checkDirectory(s);
|
|
end;
|
|
|
|
procedure TTermWidget.projCompiling(project: ICommonProject);
|
|
begin
|
|
end;
|
|
|
|
procedure TTermWidget.projCompiled(project: ICommonProject; success: boolean);
|
|
begin
|
|
end;
|
|
|
|
end.
|