📄 fr_synmemo.pas
字号:
procedure TSyntaxMemo.AddUndo;
begin
if not FMoved then exit;
FUndo.Add(Format('%5d%5d', [FPos.X, FPos.Y]) + FText.Text);
if FUndo.Count > 32 then
FUndo.Delete(0);
end;
procedure TSyntaxMemo.Undo;
var
s: String;
begin
FMoved := True;
if FUndo.Count = 0 then exit;
s := FUndo[FUndo.Count - 1];
FPos.X := StrToInt(Copy(s, 1, 5));
FPos.Y := StrToInt(Copy(s, 6, 5));
FText.Text := Copy(s, 11, Length(s) - 10);
FUndo.Delete(FUndo.Count - 1);
SetPos(FPos.X, FPos.Y);
UpdateSyntax;
end;
function TSyntaxMemo.GetPlainTextPos(Pos: TPoint): Integer;
var
i: Integer;
begin
Result := 0;
for i := 0 to Pos.Y - 2 do
Result := Result + Length(FText[i]) + 2;
Result := Result + Pos.X;
end;
function TSyntaxMemo.GetPosPlainText(Pos: Integer): TPoint;
var
i: Integer;
s: String;
begin
Result := Point(0, 1);
s := FText.Text;
i := 1;
while i <= Pos do
if s[i] = #13 then
begin
Inc(i, 2);
if i <= Pos then
begin
Inc(Result.Y);
Result.X := 0;
end
else
Inc(Result.X);
end
else
begin
Inc(i);
Inc(Result.X);
end;
end;
function TSyntaxMemo.GetLineBegin(Index: Integer): Integer;
var
s: String;
begin
s := FText[Index];
Result := 1;
if Trim(s) <> '' then
for Result := 1 to Length(s) do
if s[Result] <> ' ' then
break;
end;
procedure TSyntaxMemo.TabIndent;
var
i, n, res: Integer;
s: String;
begin
res := FPos.X;
i := FPos.Y - 2;
while i >= 0 do
begin
res := FPos.X;
s := FText[i];
n := LineLength(i);
if res > n then
Dec(i)
else
begin
if s[res] = ' ' then
begin
while s[res] = ' ' do
Inc(res);
end
else
begin
while (res <= n) and (s[res] <> ' ') do
Inc(res);
while (res <= n) and (s[res] = ' ') do
Inc(res);
end;
break;
end;
end;
SelText := Pad(res - FPos.X);
end;
procedure TSyntaxMemo.EnterIndent;
var
res: Integer;
begin
if Trim(FText[FPos.Y - 1]) = '' then
res := FPos.X else
res := GetLineBegin(FPos.Y - 1);
FPos := Point(1, FPos.Y + 1);
SelText := Pad(res - 1);
end;
procedure TSyntaxMemo.UnIndent;
var
i, res: Integer;
begin
i := FPos.Y - 2;
res := FPos.X - 1;
while i >= 0 do
begin
res := GetLineBegin(i);
if (res < FPos.X) and (Trim(FText[i]) <> '') then
break else
Dec(i);
end;
FSelStart := FPos;
FSelEnd := FPos;
Dec(FSelEnd.X, FPos.X - res);
SelText := '';
end;
procedure TSyntaxMemo.ShiftSelected(ShiftRight: Boolean);
var
i, ib, ie: Integer;
s: String;
Shift: Integer;
begin
if FReadOnly then exit;
AddUndo;
if FSelStart.X + FSelStart.Y * FMaxLength < FSelEnd.X + FSelEnd.Y * FMaxLength then
begin
ib := FSelStart.Y - 1;
ie := FSelEnd.Y - 1;
end
else
begin
ib := FSelEnd.Y - 1;
ie := FSelStart.Y - 1;
end;
if FSelEnd.X = 1 then
Dec(ie);
Shift := 2;
if not ShiftRight then
for i := ib to ie do
begin
s := FText[i];
if (Trim(s) <> '') and (GetLineBegin(i) - 1 < Shift) then
Shift := GetLineBegin(i) - 1;
end;
for i := ib to ie do
begin
s := FText[i];
if ShiftRight then
s := Pad(Shift) + s
else if Trim(s) <> '' then
Delete(s, 1, Shift);
FText[i] := s;
end;
UpdateSyntax;
end;
function TSyntaxMemo.GetSelText: String;
var
p1, p2: TPoint;
i: Integer;
begin
if FSelStart.X + FSelStart.Y * FMaxLength < FSelEnd.X + FSelEnd.Y * FMaxLength then
begin
p1 := FSelStart;
p2 := FSelEnd;
Dec(p2.X);
end
else
begin
p1 := FSelEnd;
p2 := FSelStart;
Dec(p2.X);
end;
if LineLength(p1.Y - 1) < p1.X then
begin
Inc(p1.Y);
p1.X := 1;
end;
if LineLength(p2.Y - 1) < p2.X then
p2.X := LineLength(p2.Y - 1);
i := GetPlainTextPos(p1);
Result := Copy(FText.Text, i, GetPlainTextPos(p2) - i + 1);
end;
procedure TSyntaxMemo.SetSelText(Value: String);
var
p1, p2: TPoint;
i: Integer;
s: String;
begin
if FReadOnly then exit;
AddUndo;
if FSelStart.X = 0 then
begin
p1 := FPos;
p2 := p1;
Dec(p2.X);
end
else if FSelStart.X + FSelStart.Y * FMaxLength < FSelEnd.X + FSelEnd.Y * FMaxLength then
begin
p1 := FSelStart;
p2 := FSelEnd;
Dec(p2.X);
end
else
begin
p1 := FSelEnd;
p2 := FSelStart;
Dec(p2.X);
end;
if LineLength(p1.Y - 1) < p1.X then
FText[p1.Y - 1] := FText[p1.Y - 1] + Pad(p1.X - LineLength(p1.Y - 1) + 1);
if LineLength(p2.Y - 1) < p2.X then
p2.X := LineLength(p2.Y - 1);
i := GetPlainTextPos(p1);
s := FText.Text;
Delete(s, i, GetPlainTextPos(p2) - i + 1);
Insert(Value, s, i);
FText.Text := s;
p1 := GetPosPlainText(i + Length(Value));
SetPos(p1.X, p1.Y);
FSelStart.X := 0;
UpdateSyntax;
end;
procedure TSyntaxMemo.ClearSel;
begin
if FSelStart.X <> 0 then
begin
FSelStart := Point(0, 0);
Repaint;
end;
end;
procedure TSyntaxMemo.AddSel;
begin
if FSelStart.X = 0 then
FSelStart := FTempPos;
FSelEnd := FPos;
Repaint;
end;
procedure TSyntaxMemo.SetPos(x, y: Integer);
begin
if FMessage <> '' then
begin
FMessage := '';
Repaint;
end;
if x > FMaxLength then x := FMaxLength;
if x < 1 then x := 1;
if y > FText.Count then y := FText.Count;
if y < 1 then y := 1;
FPos := Point(x, y);
if (FWindowSize.X = 0) or (FWindowSize.Y = 0) then exit;
if FOffset.Y >= FText.Count then
FOffset.Y := FText.Count - 1;
if FPos.X > FOffset.X + FWindowSize.X then
begin
Inc(FOffset.X, FPos.X - (FOffset.X + FWindowSize.X));
Repaint;
end
else if FPos.X <= FOffset.X then
begin
Dec(FOffset.X, FOffset.X - FPos.X + 1);
Repaint;
end
else if FPos.Y > FOffset.Y + FWindowSize.Y then
begin
Inc(FOffset.Y, FPos.Y - (FOffset.Y + FWindowSize.Y));
Repaint;
end
else if FPos.Y <= FOffset.Y then
begin
Dec(FOffset.Y, FOffset.Y - FPos.Y + 1);
Repaint;
end;
ShowCaretPos;
UpdateScrollBar;
end;
procedure TSyntaxMemo.ScrollClick(Sender: TObject);
begin
if FBusy then exit;
FOffset.Y := FVScroll.Position;
if FOffset.Y > FText.Count then
FOffset.Y := FText.Count;
ShowCaretPos;
Repaint;
end;
procedure TSyntaxMemo.ScrollEnter(Sender: TObject);
begin
SetFocus;
end;
procedure TSyntaxMemo.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
FMoved := True;
if not Focused then
SetFocus;
FDown := True;
SetPos(X div FCharWidth + 1 + FOffset.X, Y div FCharHeight + 1 + FOffset.Y);
ClearSel;
end;
procedure TSyntaxMemo.MouseMove(Shift: TShiftState; X, Y: Integer);
begin
if FDown then
begin
FTempPos := FPos;
SetPos(X div FCharWidth + 1 + FOffset.X, Y div FCharHeight + 1 + FOffset.Y);
AddSel;
end;
end;
procedure TSyntaxMemo.MouseUp(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
FDown := False;
end;
procedure TSyntaxMemo.KeyDown(var Key: Word; Shift: TShiftState);
var
MyKey: Boolean;
begin
inherited;
FAllowLinesChange := False;
FTempPos := FPos;
MyKey := True;
case Key of
vk_Left:
DoLeft;
vk_Right:
DoRight;
vk_Up:
DoUp;
vk_Down:
DoDown;
vk_Home:
DoHome(ssCtrl in Shift);
vk_End:
DoEnd(ssCtrl in Shift);
vk_Prior:
DoPgUp;
vk_Next:
DoPgDn;
vk_Return:
if Shift = [] then
DoReturn;
vk_Delete:
if ssShift in Shift then
CutToClipboard else
DoDel;
vk_Back:
DoBackspace;
vk_Insert:
if ssCtrl in Shift then
CopyToClipboard
else if ssShift in Shift then
PasteFromClipboard;
vk_Tab:
TabIndent;
else
MyKey := False;
end;
if Key in [vk_Left, vk_Right, vk_Up, vk_Down, vk_Home, vk_End, vk_Prior, vk_Next] then
begin
FMoved := True;
if ssShift in Shift then
AddSel else
ClearSel;
end
else if Key in [vk_Return, vk_Delete, vk_Back, vk_Insert, vk_Tab] then
FMoved := False;
if MyKey then
Key := 0;
end;
procedure TSyntaxMemo.KeyPress(var Key: Char);
var
MyKey: Boolean;
begin
inherited;
MyKey := True;
case Key of
#3:
CopyToClipboard;
#9:
DoCtrlI;
#21:
DoCtrlU;
#22:
PasteFromClipboard;
#24:
CutToClipboard;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -