mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-12-09 17:57:09 +01:00
491 lines
12 KiB
PHP
491 lines
12 KiB
PHP
{
|
|
|
|
"SHEdit" - Text editor with syntax highlighting
|
|
Copyright (C) 1999-2000 by Sebastian Guenther (sg@freepascal.org)
|
|
|
|
See the file COPYING.FPC, included in this distribution,
|
|
for details about the copyright.
|
|
|
|
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.
|
|
}
|
|
|
|
|
|
// TSHTextEdit: Implementation of keyboard handling methods
|
|
|
|
|
|
function TSHTextEdit.AddKeyboardAction(AMethod: TKeyboardActionProc;ASelectionAction:TSelectionAction;ADescr: String): TKeyboardActionDescr;
|
|
begin
|
|
Result := TKeyboardActionDescr(KeyboardActions.Add);
|
|
Result.Descr := ADescr;
|
|
Result.Method := AMethod;
|
|
Result.SelectionAction := ASelectionAction;
|
|
end;
|
|
|
|
|
|
function TSHTextEdit.AddKeyboardAssignment(AKeyCode: Integer; AShiftState: TShiftState; AAction: TKeyboardActionDescr): TShortcut;
|
|
begin
|
|
Result := TShortcut(Shortcuts.Add);
|
|
Result.KeyCode := AKeyCode;
|
|
Result.ShiftState := AShiftState;
|
|
Result.Action := AAction;
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.AddKeyDef(AMethod: TKeyboardActionProc; ASelectionAction:TSelectionAction; ADescr: String; AKeyCode: Integer; AShiftState: TShiftState);
|
|
begin
|
|
AddKeyboardAssignment(AKeyCode, AShiftState,AddKeyboardAction(AMethod, ASelectionAction, ADescr));
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.ToggleOverwriteMode;
|
|
begin
|
|
OverwriteMode := not OverwriteMode; // *** specify signal for change
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.AdjustCursorToRange;
|
|
begin
|
|
if FCursorY < FWidget.VertPos then begin
|
|
HideCursor;
|
|
FCursorY := FWidget.VertPos;
|
|
ShowCursor;
|
|
end else if FCursorY > FWidget.VertPos + FWidget.PageHeight then begin
|
|
HideCursor;
|
|
FCursorY := FWidget.VertPos + FWidget.PageHeight - 1;
|
|
ShowCursor;
|
|
end;
|
|
|
|
if FCursorX < FWidget.HorzPos then begin
|
|
HideCursor;
|
|
FCursorX := FWidget.HorzPos;
|
|
ShowCursor;
|
|
end else if FCursorX > FWidget.HorzPos + FWidget.PageWidth then begin
|
|
HideCursor;
|
|
FCursorX := FWidget.HorzPos + FWidget.PageWidth - 1;
|
|
ShowCursor;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.AdjustRangeToCursor;
|
|
var
|
|
py : integer;
|
|
begin
|
|
if FCursorY < FWidget.VertPos then
|
|
FWidget.VertPos := FCursorY
|
|
else if FCursorY >= FWidget.VertPos + FWidget.PageHeight then begin
|
|
py := FCursorY - FWidget.PageHeight + 1;
|
|
if py < 0 then
|
|
FWidget.VertPos:=0
|
|
else
|
|
FWidget.VertPos:=py;
|
|
end;
|
|
if FCursorX < FWidget.HorzPos then
|
|
FWidget.HorzPos := FCursorX
|
|
else if FCursorX >= FWidget.HorzPos + FWidget.PageWidth then begin
|
|
py := FCursorX - FWidget.PageWidth + 1;
|
|
if py < 0 then
|
|
FWidget.HorzPos := 0
|
|
else
|
|
FWidget.HorzPos := py;
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorUp;
|
|
begin
|
|
if FCursorY > 0 then
|
|
Dec(FCursorY);
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorDown;
|
|
begin
|
|
if FCursorY < FDoc.LineCount - 1 then
|
|
Inc(FCursorY);
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorLeft;
|
|
begin
|
|
Dec(FCursorX);
|
|
if FCursorX < 0 then
|
|
if FCursorY>0 then begin
|
|
Dec(FCursorY);
|
|
FCursorX := FDoc.LineLen[FCursorY];
|
|
end else
|
|
FCursorX := 0;
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorRight;
|
|
begin
|
|
Inc(FCursorX);
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorDocBegin;
|
|
begin
|
|
FCursorX := 0;
|
|
FCursorY := 0;
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorDocEnd;
|
|
begin
|
|
FCursorY := FDoc.LineCount-1;
|
|
FCursorX := FDoc.LineLen[FCursorY];
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorHome;
|
|
begin
|
|
FCursorX := 0;
|
|
AdjustRangeToCursor;
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorEnd;
|
|
begin
|
|
FCursorX := FDoc.LineLen[FCursorY];
|
|
AdjustRangeToCursor;
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorPageUp;
|
|
begin
|
|
Dec(FCursorY, FWidget.PageHeight);
|
|
if FCursorY < 0 then
|
|
FCursorY := 0;
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.CursorPageDown;
|
|
begin
|
|
Inc(FCursorY, FWidget.PageHeight);
|
|
if FCursorY > FDoc.LineCount - 1 then
|
|
FCursorY := FDoc.LineCount - 1;
|
|
end;
|
|
|
|
|
|
procedure TSHTextEdit.EditDelLeft;
|
|
var
|
|
s: String;
|
|
begin
|
|
if FCursorX > 0 then begin
|
|
s := FDoc.LineText[FCursorY];
|
|
Dec(FCursorX);
|
|
AddUndoInfo(TUndoDelLeft.Create(s[FCursorX + 1]), True);
|
|
s := Copy(s, 1, FCursorX) + Copy(s, FCursorX + 2, Length(s));
|
|
FDoc.LineText[FCursorY] := s;
|
|
ChangeInLine(FCursorY);
|
|
end else if FCursorY > 0 then begin
|
|
FCursorX := FDoc.LineLen[FCursorY - 1];
|
|
FDoc.LineText[FCursorY - 1] := FDoc.LineText[FCursorY - 1] +
|
|
FDoc.LineText[FCursorY];
|
|
Dec(FCursorY);
|
|
FDoc.RemoveLine(FCursorY + 1);
|
|
AddUndoInfo(TUndoDelLeft.Create(#13), True);
|
|
end;
|
|
end;
|
|
|
|
procedure TSHTextEdit.EditDelRight;
|
|
var
|
|
s: String;
|
|
begin
|
|
if FCursorX < FDoc.LineLen[FCursorY] then begin
|
|
s := FDoc.LineText[FCursorY];
|
|
AddUndoInfo(TUndoDelRight.Create(s[FCursorX + 1]), True);
|
|
s := Copy(s, 1, FCursorX) + Copy(s, FCursorX + 2, Length(s));
|
|
FDoc.LineText[FCursorY] := s;
|
|
ChangeInLine(FCursorY);
|
|
end else if FCursorY < FDoc.LineCount - 1 then begin
|
|
FDoc.LineText[FCursorY] := FDoc.LineText[FCursorY] +
|
|
FDoc.LineText[FCursorY + 1];
|
|
FDoc.RemoveLine(FCursorY + 1);
|
|
AddUndoInfo(TUndoDelRight.Create(#13), True);
|
|
end;
|
|
end;
|
|
|
|
procedure TSHTextEdit.EditDelLine;
|
|
var
|
|
DeletedText: String;
|
|
begin
|
|
DeletedText := FDoc.LineText[FCursorY];
|
|
if FDoc.LineCount = 1 then
|
|
FDoc.LineText[FCursorY] := ''
|
|
else
|
|
FDoc.RemoveLine(FCursorY);
|
|
|
|
if FCursorY >= FDoc.LineCount then
|
|
FCursorY := FDoc.LineCount - 1;
|
|
FCursorX := 0;
|
|
|
|
AddUndoInfo(TUndoDelRight.Create(DeletedText + #13), True);
|
|
|
|
ChangeInLine(FCursorY);
|
|
end;
|
|
|
|
procedure TSHTextEdit.EditUndo;
|
|
var
|
|
info: TUndoInfo;
|
|
begin
|
|
if LastUndoInfo = nil then exit;
|
|
|
|
info := LastUndoInfo;
|
|
LastUndoInfo := LastRedoInfo;
|
|
info.DoUndo(Self);
|
|
LastRedoInfo := LastUndoInfo;
|
|
LastUndoInfo := info;
|
|
|
|
// Free undo info
|
|
if info.Prev <> nil then
|
|
info.Prev.Next := info.Next
|
|
else
|
|
FDoc.Modified := False;
|
|
LastUndoInfo := info.Prev;
|
|
info.Free;
|
|
end;
|
|
|
|
procedure TSHTextEdit.EditRedo;
|
|
var
|
|
info: TUndoInfo;
|
|
begin
|
|
if LastRedoInfo = nil then exit;
|
|
|
|
info := LastRedoInfo;
|
|
info.DoUndo(Self);
|
|
|
|
// Free redo info
|
|
if info.Prev <> nil then
|
|
info.Prev.Next := info.Next;
|
|
LastRedoInfo := info.Prev;
|
|
info.Free;
|
|
end;
|
|
|
|
procedure TSHTextEdit.ClipboardCut;
|
|
begin
|
|
WriteLn('ClipboardCut: Not implemented yet');
|
|
ClipboardCopy;
|
|
end;
|
|
|
|
procedure TSHTextEdit.ClipboardCopy;
|
|
var
|
|
cbtext: String;
|
|
y: Integer;
|
|
begin
|
|
if FSel.OStartY = FSel.OEndY then
|
|
cbtext := Copy(FDoc.LineText[FSel.OStartY],
|
|
FSel.OStartX + 1, FSel.OEndX - FSel.OStartX)
|
|
else begin
|
|
cbtext := Copy(FDoc.LineText[FSel.OStartY],
|
|
FSel.OStartX + 1, FDoc.LineLen[FSel.OStartY]) + #10;
|
|
for y := FSel.OStartY + 1 to FSel.OEndY - 1 do
|
|
cbtext := cbtext + FDoc.LineText[y] + #10;
|
|
cbtext := cbtext + Copy(FDoc.LineText[FSel.OEndY], 1, FSel.OEndX);
|
|
end;
|
|
|
|
FWidget.SetClipboard(cbtext);
|
|
end;
|
|
|
|
procedure TSHTextEdit.ClipboardPaste;
|
|
var
|
|
cbtext: String;
|
|
begin
|
|
cbtext := FWidget.GetClipboard;
|
|
ExecKeys(cbtext, True);
|
|
end;
|
|
|
|
procedure TSHTextEdit.KeyReturn; begin end;
|
|
|
|
function TSHTextEdit.ExecKey(Key: Char; BlockMode: Boolean): Boolean;
|
|
var
|
|
s, s2: String;
|
|
i: Integer;
|
|
begin
|
|
Result := True;
|
|
case Key of
|
|
#9: begin
|
|
s := FDoc.LineText[FCursorY];
|
|
s2 := ' ';
|
|
i := 1;
|
|
while ((FCursorX + i) mod 4) <> 0 do begin
|
|
s2 := s2 + ' ';
|
|
Inc(i);
|
|
end;
|
|
s := Copy(s, 1, FCursorX) + s2 + Copy(s, FCursorX + 1, Length(s));
|
|
FDoc.LineText[FCursorY] := s;
|
|
Inc(FCursorX, i);
|
|
AddUndoInfo(TUndoEdit.Create(i), True);
|
|
ChangeInLine(FCursorY);
|
|
end;
|
|
#13: begin
|
|
s := FDoc.LineText[FCursorY];
|
|
FDoc.LineText[FCursorY] := Copy(s, 1, FCursorX);
|
|
FDoc.InsertLine(FCursorY + 1, Copy(s, FCursorX + 1, Length(s)));
|
|
CursorX := 0;
|
|
Inc(FCursorY);
|
|
AddUndoInfo(TUndoEdit.Create, True);
|
|
if not BlockMode then KeyReturn;
|
|
end;
|
|
#32..#255:
|
|
begin
|
|
s := FDoc.LineText[FCursorY];
|
|
if FCursorX>=Length(s) then
|
|
s := s + Space(FCursorX-length(s)) + Key
|
|
else
|
|
if OverwriteMode then
|
|
s := Copy(s, 1, FCursorX) + Key + Copy(s, FCursorX + 2, Length(s))
|
|
else
|
|
s := Copy(s, 1, FCursorX) + Key + Copy(s, FCursorX + 1, Length(s));
|
|
FDoc.LineText[FCursorY] := s;
|
|
Inc(FCursorX);
|
|
AddUndoInfo(TUndoEdit.Create, True);
|
|
ChangeInLine(FCursorY);
|
|
end;
|
|
else Result := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TSHTextEdit.ExecKeys(Keys: String; BlockMode: Boolean);
|
|
var
|
|
s, s2: String;
|
|
KeysPos, i: Integer;
|
|
Key: Char;
|
|
begin
|
|
if BlockMode then
|
|
AddUndoInfo(TUndoEdit.Create(0), False); // Initialize new undo block
|
|
|
|
KeysPos := 1;
|
|
while KeysPos <= Length(Keys) do begin
|
|
case Keys[KeysPos] of
|
|
#9: begin
|
|
s := FDoc.LineText[FCursorY];
|
|
s2 := ' ';
|
|
i := 1;
|
|
while ((FCursorX + i) mod 4) <> 0 do begin
|
|
s2 := s2 + ' ';
|
|
Inc(i);
|
|
end;
|
|
s := Copy(s, 1, FCursorX) + s2 + Copy(s, FCursorX + 1, Length(s));
|
|
FDoc.LineText[FCursorY] := s;
|
|
Inc(FCursorX, i);
|
|
AddUndoInfo(TUndoEdit.Create(i), True);
|
|
ChangeInLine(FCursorY);
|
|
Inc(KeysPos);
|
|
end;
|
|
#13, #10: begin
|
|
s := FDoc.LineText[FCursorY];
|
|
FDoc.LineText[FCursorY] := Copy(s, 1, FCursorX);
|
|
FDoc.InsertLine(FCursorY + 1, Copy(s, FCursorX + 1, Length(s)));
|
|
CursorX := 0;
|
|
Inc(FCursorY);
|
|
AddUndoInfo(TUndoEdit.Create, True);
|
|
if not BlockMode then KeyReturn;
|
|
Inc(KeysPos);
|
|
end;
|
|
#32..#255: begin
|
|
i := 0;
|
|
while (KeysPos <= Length(Keys)) and (Keys[KeysPos] >= #32) do begin
|
|
Key := Keys[KeysPos];
|
|
s := FDoc.LineText[FCursorY];
|
|
if FCursorX>=Length(s) then
|
|
s := s + Space(FCursorX-length(s)) + Key
|
|
else
|
|
s := Copy(s, 1, FCursorX) + Key + Copy(s, FCursorX + 1 + Ord(OverwriteMode), Length(s));
|
|
FDoc.LineText[FCursorY] := s;
|
|
Inc(FCursorX);
|
|
Inc(i);
|
|
Inc(KeysPos);
|
|
end;
|
|
AddUndoInfo(TUndoEdit.Create(i), True);
|
|
|
|
ChangeInLine(FCursorY);
|
|
end;
|
|
else Inc(KeysPos);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TSHTextEdit.MultiDelLeft(count: Integer);
|
|
var
|
|
s: String;
|
|
begin
|
|
while count > 0 do begin
|
|
if FCursorX > 0 then begin
|
|
while (FCursorX > 0) and (count > 0) do begin
|
|
s := FDoc.LineText[FCursorY];
|
|
Dec(FCursorX);
|
|
AddUndoInfo(TUndoDelLeft.Create(s[FCursorX + 1]), True);
|
|
s := Copy(s, 1, FCursorX) + Copy(s, FCursorX + 2, Length(s));
|
|
FDoc.LineText[FCursorY] := s;
|
|
Dec(count);
|
|
end;
|
|
ChangeInLine(FCursorY);
|
|
end else if FCursorY > 0 then begin
|
|
FCursorX := FDoc.LineLen[FCursorY - 1];
|
|
FDoc.LineText[FCursorY - 1] := FDoc.LineText[FCursorY - 1] +
|
|
FDoc.LineText[FCursorY];
|
|
Dec(FCursorY);
|
|
FDoc.RemoveLine(FCursorY + 1);
|
|
AddUndoInfo(TUndoDelLeft.Create(#13), True);
|
|
Dec(count);
|
|
end else break;
|
|
end;
|
|
end;
|
|
|
|
function TSHTextEdit.KeyPressed(KeyCode: LongWord; ShiftState: TShiftState): Boolean;
|
|
var
|
|
i: Integer;
|
|
shortcut: TShortcut;
|
|
ShortcutFound: Boolean;
|
|
begin
|
|
// WriteLn('TSHTextEdit: Key pressed: ', KeyCode);
|
|
LastCursorX := FCursorX;
|
|
LastCursorY := FCursorY;
|
|
StartSelectionChange;
|
|
|
|
// Check for keyboard shortcuts
|
|
ShortcutFound := False;
|
|
for i := 0 to Shortcuts.Count - 1 do begin
|
|
shortcut := TShortcut(Shortcuts.Items[i]);
|
|
if (KeyCode = shortcut.KeyCode) and
|
|
(ShiftState * [ssShift, ssCtrl, ssAlt] = shortcut.ShiftState) then begin
|
|
ShortcutFound := True;
|
|
break;
|
|
end;
|
|
end;
|
|
|
|
Result := True;
|
|
|
|
if ShortcutFound then begin
|
|
// WriteLn(shortcut.Action.Descr);
|
|
shortcut.Action.Method; // Execute associated action
|
|
// Handle the selection extending
|
|
case shortcut.Action.SelectionAction of
|
|
selNothing: ;
|
|
selExtend: begin
|
|
if not FSel.IsValid then begin
|
|
FSel.StartX:=LastCursorX;
|
|
FSel.StartY:=LastCursorY;
|
|
end;
|
|
FSel.EndX:=FCursorX;
|
|
FSel.EndY:=FCursorY;
|
|
end;
|
|
selClear:
|
|
FSel.Clear;
|
|
end;
|
|
end else
|
|
if (KeyCode <= 255) and (ShiftState * [ssCtrl, ssAlt] = []) then
|
|
ExecKey(Chr(KeyCode), False)
|
|
else
|
|
Result := False; // Key has not been processed
|
|
|
|
EndSelectionChange;
|
|
AdjustRangeToCursor;
|
|
end;
|
|
|
|
|