📄 fr_synmemo.pas
字号:
#26:
Undo;
#32..#255:
begin
DoChar(Key);
FMoved := False;
end;
else
MyKey := False;
end;
if MyKey then
Key := #0;
end;
procedure TSyntaxMemo.DoLeft;
begin
Dec(FPos.X);
if FPos.X < 1 then
FPos.X := 1;
SetPos(FPos.X, FPos.Y);
end;
procedure TSyntaxMemo.DoRight;
begin
Inc(FPos.X);
if FPos.X > FMaxLength then
FPos.X := FMaxLength;
SetPos(FPos.X, FPos.Y);
end;
procedure TSyntaxMemo.DoUp;
begin
Dec(FPos.Y);
if FPos.Y < 1 then
FPos.Y := 1;
SetPos(FPos.X, FPos.Y);
end;
procedure TSyntaxMemo.DoDown;
begin
Inc(FPos.Y);
if FPos.Y > FText.Count then
FPos.Y := FText.Count;
SetPos(FPos.X, FPos.Y);
end;
procedure TSyntaxMemo.DoHome(Ctrl: Boolean);
begin
if Ctrl then
SetPos(1, 1) else
SetPos(1, FPos.Y);
end;
procedure TSyntaxMemo.DoEnd(Ctrl: Boolean);
begin
if Ctrl then
SetPos(LineLength(FText.Count - 1) + 1, FText.Count) else
SetPos(LineLength(FPos.Y - 1) + 1, FPos.Y);
end;
procedure TSyntaxMemo.DoPgUp;
begin
if FOffset.Y > FWindowSize.Y then
begin
Dec(FOffset.Y, FWindowSize.Y - 1);
Dec(FPos.Y, FWindowSize.Y - 1);
end
else
begin
if FOffset.Y > 0 then
begin
Dec(FPos.Y, FOffset.Y);
FOffset.Y := 0;
end
else
FPos.Y := 1;
end;
SetPos(FPos.X, FPos.Y);
Repaint;
end;
procedure TSyntaxMemo.DoPgDn;
begin
if FOffset.Y + FWindowSize.Y < FText.Count then
begin
Inc(FOffset.Y, FWindowSize.Y - 1);
Inc(FPos.Y, FWindowSize.Y - 1);
end
else
begin
FOffset.Y := FText.Count;
FPos.Y := FText.Count;
end;
SetPos(FPos.X, FPos.Y);
Repaint;
end;
procedure TSyntaxMemo.DoReturn;
var
s: String;
begin
if FReadOnly then exit;
s := LineAt(FPos.Y - 1);
FText[FPos.Y - 1] := Copy(s, 1, FPos.X - 1);
FText.Insert(FPos.Y, Copy(s, FPos.X, FMaxLength));
EnterIndent;
end;
procedure TSyntaxMemo.DoDel;
var
s: String;
begin
if FReadOnly then exit;
FMessage := '';
if FSelStart.X <> 0 then
SelText := ''
else
begin
s := FText[FPos.Y - 1];
AddUndo;
if FPos.X <= LineLength(FPos.Y - 1) then
begin
Delete(s, FPos.X, 1);
FText[FPos.Y - 1] := s;
end
else if FPos.Y < FText.Count then
begin
s := s + Pad(FPos.X - Length(s) - 1) + LineAt(FPos.Y);
FText[FPos.Y - 1] := s;
FText.Delete(FPos.Y);
end;
UpdateScrollBar;
UpdateSyntax;
end;
end;
procedure TSyntaxMemo.DoBackspace;
var
s: String;
begin
if FReadOnly then exit;
FMessage := '';
if FSelStart.X <> 0 then
SelText := ''
else
begin
s := FText[FPos.Y - 1];
if FPos.X > 1 then
begin
if (GetLineBegin(FPos.Y - 1) = FPos.X) or (Trim(s) = '') then
UnIndent
else
begin
AddUndo;
if Trim(s) <> '' then
begin
Delete(s, FPos.X - 1, 1);
FText[FPos.Y - 1] := s;
DoLeft;
end
else
DoHome(False);
UpdateSyntax;
end;
end
else if FPos.Y > 1 then
begin
AddUndo;
s := LineAt(FPos.Y - 2);
FText[FPos.Y - 2] := s + FText[FPos.Y - 1];
FText.Delete(FPos.Y - 1);
SetPos(Length(s) + 1, FPos.Y - 1);
UpdateSyntax;
end;
end;
end;
procedure TSyntaxMemo.DoCtrlI;
begin
if FSelStart.X <> 0 then
ShiftSelected(True);
end;
procedure TSyntaxMemo.DoCtrlU;
begin
if FSelStart.X <> 0 then
ShiftSelected(False);
end;
procedure TSyntaxMemo.DoChar(Ch: Char);
begin
SelText := Ch;
end;
// need two parameters to speed up the work
function TSyntaxMemo.GetCharAttr(Pos: TPoint; Pos1: Integer): TCharAttributes;
function IsBlock: Boolean;
var
p1, p2, p3: Integer;
begin
Result := False;
if FSelStart.X = 0 then exit;
p1 := FSelStart.X + FSelStart.Y * FMaxLength;
p2 := FSelEnd.X + FSelEnd.Y * FMaxLength;
if p1 > p2 then
begin
p3 := p1;
p1 := p2;
p2 := p3;
end;
p3 := Pos.X + Pos.Y * FMaxLength;
Result := (p3 >= p1) and (p3 < p2);
end;
function CharAttr: TCharAttr;
begin
if Pos1 <= Length(FSyn) then
Result := TCharAttr(Ord(FSyn[Pos1])) else
Result := caText;
end;
begin
Result := [CharAttr];
if IsBlock then
Result := Result + [caBlock];
end;
procedure TSyntaxMemo.Paint;
var
i, j, j1, Pos1: Integer;
a, a1: TCharAttributes;
s: String;
procedure SetAttr(a: TCharAttributes);
begin
with Canvas do
begin
Brush.Color := Color;
if caText in a then
Font.Assign(FTextAttr);
if caComment in a then
Font.Assign(FCommentAttr);
if caKeyword in a then
Font.Assign(FKeywordAttr);
if caString in a then
Font.Assign(FStringAttr);
if caBlock in a then
begin
Brush.Color := FBlockColor;
Font.Color := FBlockFontColor;
end;
Font.Name := Self.Font.Name;
Font.Size := Self.Font.Size;
{$IFNDEF Delphi2}
Font.Charset := Self.Font.Charset;
{$ENDIF}
end;
end;
procedure MyTextOut(x, y: Integer; s: String);
var
i: Integer;
begin
if FIsMonoType then
Canvas.TextOut(x, y, s)
else
with Canvas do
begin
// FillRect(Rect(x, y, x + Length(s) * FCharWidth, y + FCharHeight));
// for i := 1 to Length(s) do
// TextOut(x + (i - 1) * FCharWidth, y, s[i]);
// MoveTo(x + Length(s) * FCharWidth, y);
TextOut(x, y, s);
end;
end;
begin
with Canvas do
begin
for i := FOffset.Y to FOffset.Y + FWindowSize.Y do
begin
if i >= FText.Count then break;
Pos1 := GetPlainTextPos(Point(1, i + 1)) - 1;
s := FText[i];
PenPos := Point(2, (i - FOffset.Y) * FCharHeight);
j1 := FOffset.X + 1;
a := GetCharAttr(Point(j1, i + 1), Pos1 + j1);
a1 := a;
for j := j1 to FOffset.X + FWindowSize.X do
begin
if j > Length(s) then break;
a1 := GetCharAttr(Point(j, i + 1), Pos1 + j);
if a1 <> a then
begin
SetAttr(a);
MyTextOut(PenPos.X, PenPos.Y, Copy(FText[i], j1, j - j1));
a := a1;
j1 := j;
end;
end;
SetAttr(a);
MyTextOut(PenPos.X, PenPos.Y, Copy(s, j1, FMaxLength));
if caBlock in GetCharAttr(Point(0, i + 2), 1) then
MyTextOut(PenPos.X, PenPos.Y, Pad(FWindowSize.X - Length(s) - FOffset.X + 3));
end;
if FMessage <> '' then
begin
Font.Name := 'MS Sans Serif';
Font.Color := clWhite;
Font.Style := [];
Brush.Color := clRed;
FillRect(Rect(0, Height - TextHeight('|') - 6, Width, Height));
TextOut(6, Height - TextHeight('|') - 5, FMessage);
end;
end;
end;
procedure TSyntaxMemo.CreateSynArray;
var
i, n, Pos: Integer;
ch: Char;
procedure SkipSpaces;
begin
while (Pos <= Length(FSyn)) and
((FSyn[Pos] in [#1..#32]) or
not (FSyn[Pos] in ['_', 'A'..'Z', 'a'..'z', '''', '"', '/', '{', '(', '-'])) do
Inc(Pos);
end;
function IsKeyWord(s: String): Boolean;
begin
Result := False;
if FKeywords = '' then exit;
if FKeywords[1] <> ',' then
FKeywords := ',' + FKeywords;
if FKeywords[Length(FKeywords)] <> ',' then
FKeywords := FKeywords + ',';
Result := System.Pos(',' + AnsiLowerCase(s) + ',', FKeywords) <> 0;
end;
function GetIdent: TCharAttr;
var
i: Integer;
cm1, cm2, cm3, cm4, st1: Char;
begin
i := Pos;
Result := caText;
if FSyntaxType = stPascal then
begin
cm1 := '/';
cm2 := '{';
cm3 := '(';
cm4 := ')';
st1 := '''';
end
else if FSyntaxType = stSQL then
begin
cm1 := '-';
cm2 := ' ';
cm3 := '/';
cm4 := '/';
st1 := '"';
end
else
begin
cm1 := ' ';
cm2 := ' ';
cm3 := ' ';
cm4 := ' ';
st1 := ' ';
end;
if FSyn[Pos] in ['_', 'A'..'Z', 'a'..'z'] then
begin
while FSyn[Pos] in ['_', 'A'..'Z', 'a'..'z', '0'..'9'] do
Inc(Pos);
if IsKeyWord(Copy(FSyn, i, Pos - i)) then
Result := caKeyword;
Dec(Pos);
end
else if (FSyn[Pos] = cm1) and (FSyn[Pos + 1] = cm1) then
begin
while (Pos <= Length(FSyn)) and not (FSyn[Pos] in [#10, #13]) do
Inc(Pos);
Result := caComment;
end
else if FSyn[Pos] = cm2 then
begin
while (Pos <= Length(FSyn)) and (FSyn[Pos] <> '}') do
Inc(Pos);
Result := caComment;
end
else if (FSyn[Pos] = cm3) and (FSyn[Pos + 1] = '*') then
begin
while (Pos < Length(FSyn)) and not ((FSyn[Pos] = '*') and (FSyn[Pos + 1] = cm4)) do
Inc(Pos);
Inc(Pos, 2);
Result := caComment;
end
else if (FSyn[Pos] = '''') or (FSyn[Pos] = st1) then
begin
Inc(Pos);
while (Pos < Length(FSyn)) and (FSyn[Pos] <> '''') and (FSyn[Pos] <> st1) and not (FSyn[Pos] in [#10, #13]) do
Inc(Pos);
Result := caString;
end;
Inc(Pos);
end;
begin
FSyn := GetText.Text + #0#0#0#0#0#0#0#0#0#0#0;
FAllowLinesChange := False;
Pos := 1;
while Pos < Length(FSyn) do
begin
n := Pos;
SkipSpaces;
for i := n to Pos - 1 do
if FSyn[i] > #31 then
FSyn[i] := Chr(Ord(caText));
n := Pos;
ch := Chr(Ord(GetIdent));
for i := n to Pos - 1 do
if FSyn[i] > #31 then
FSyn[i] := ch;
end;
end;
end.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -