SynEdit/pl
│
Deutsch (de) │
English (en) │
español (es) │
français (fr) │
日本語 (ja) │
polski (pl) │
русский (ru) │
中文(中国大陆) (zh_CN) │
SynEdit to pakiet edycji/notatek z podświetlaniem składni dostępny na karcie SynEdit obsługujący wiele języków/składni.
SynEdit zawarty w Lazarusie został utworzony na bazie SynEdit 1.0.3, i został w dużym stopniu zaadaptowany i rozszerzony. Zmiany są wymienione poniżej.
Pakiet Lazarus zawiera komponent edytora źródeł o nazwie TSynEdit, kilka podświetlaczy składni i inne komponenty używane do edycji źródeł.
Licencjonowany na tych samych warunkach, co oryginalny SynEdit (MPL lub GPL).
Wersja oryginalna a Lazarus
Wersją dla Lazarus opiekuje się głównie Martin Friebe. Martin napisał na forum, co zostało dodane do wersji Lazarusa od czasu pojawienia się tego forka:
Duże rzeczy dodane do wersji Lazarus:
- zwijanie bloków kodu
- konfigurowalny boczny margines i jego części (tzw. rynna)
- wspólny tekst pomiędzy kilkoma redaktorami
- obsługa kodowania utf-8
- wtyczka do edycji synchronizacji
- podstawowa obsługa RTL/LTR
- konfiguracja myszy za pomocą MouseActions
- przepisano różne moduły podświetlania/oznaczeń składni
Bazy kodu wersji Delphi/Lazarus zostały niezależnie przeprojektowane. Pozostało bardzo niewiele do zrobienia.
Port SynEdit 2.0
Istnieje alternatywny port wersji 2.0.x oryginalnego SynEdit. Nie jest aktywnie utrzymywany, ostatnie zatwierdzenie (obecnie jest marzec 2024) miało miejsce w 2023 roku, ale od 2011 roku ma on wersję 2.0.5.
SynEdit w IDE
SynEdit w Lazarusie jest pakietem wbudowanym, ponieważ samo IDE używa go do edycji kodów źródłowych. Z tego powodu nie można usunąć tego pakietu z listy instalacyjnej. Natomiast aby usunąć SynEdit z palety komponentów, można usunąć pakiet SynEditDsgn z instalacji.
Używanie SynEdit
Podświetlacze składni
- Istnieje kilka standardowych poświetlaczy składni (zobacz karta SynEdit w palecie komponentów)
- Istnieją podświetlacze skryptowe, które można dostosować do wielu innych formatów plików:
- TSynAnySyn (standardowy, jest domyślnie na palecie komponentów)
- TSynPositionHighlighter (standardowy, nie jest obecny palecie komponentów)
- TSynUniHighlighter (standardowy, nie jest obecny na palecie komponentów)
- SynFacilSyn (Github)
- Istnieje więcej podświetlaczy innych firm: SynCacheSyn, SynGeneralSyn, SynRCSyn, SynRubySyn, SynSDDSyn, SynSMLSyn, SynSTSyn, SynTclTkSyn, SynUnrealSyn, SynURISyn, SynVBScriptSyn, SynVrml97Syn, Spójrz tutaj.
- Możesz napisać nowy podświetlacz, zobacz informacje na SynEdit Highlighter.
Znaczniki
Znaczniki umożliwiają dodatkowe kolorowanie SynEdit Markup
Oznaczenia
Znaczniki zapewniają dodatkowe kolorowanie
Edycja istniejącego podświetlacza
Czasami możesz chcieć edytować istniejące podświetlacze składni (tak jak chciałem to zrobić kilka dni temu), które już istnieją. W tym przykładzie będziemy edytować podświetlacz dla kodu pascala (nazwa klasy: TSynPasSyn; pakiet: SynEdit V1.0; moduł: SynHighlighterPas.pas).
Powiedzmy, że chcemy osiągnąć to, aby nasza aplikacja (w tym przypadku Lazarus) rozróżniał trzy typy komentarzy, które istnieją w Pascalu:
(* standardowe *)
{ klamry }
// ukośniki
Może to być pomocne, jeśli chcesz rozróżnić różne typy swoich komentarzy (np. „Opis”, „Notatka”, „Referencja” itp.) i chcesz, aby każdy wyróżniony był innym kolorem.
- Najpierw otwórz moduł „SynHighlighterPas”, który powinien znajdować się w katalogu SynEdit.
- Ponieważ nie chcemy powodować niezgodności, tworzymy nowy rodzaj typu wyliczającego, który pomoże nam później zidentyfikować nasz komentarz:
Np. pod deklaracją „tkTokenKind” napisz:
{NEW}
TtckCommentKind = (tckAnsi, tckBor, tckSlash);
{/NEW}
- W deklaracji „TSynPasSyn” wyszukaj „FTokenID” i dodaj pomiędzy „FTokenID” a następnym polem
{NEW}
FCommentID: TtckCommentKind;
{/NEW}
//Tworzy to nowe pole, w którym możemy zapisać informację, jakiego rodzaju mamy komentarz
- W deklaracji „TSynPasSyn” wyszukaj „fCommentAttri” i dodaj następujący tekst między „fCommentAttri” a następnym polem
{NEW}
fCommentAttri_Ansi: TSynHighlighterAttributes;
fCommentAttri_Bor: TSynHighlighterAttributes;
fCommentAttri_Slash: TSynHighlighterAttributes;
{/NEW}
//Dzięki temu możemy zwrócić różne atrybuty dla każdego typu komentarza
- Następnie wyszukaj definicję konstruktora „TSynPasSyn”, która powinna brzmieć „constructor TSynPasSyn.Create(AOwner: TComponent);”.
- Musimy utworzyć nasze nowe atrybuty, dlatego dodajemy nasze atrybuty gdzieś w konstruktorze (sugeruję po domyślnym „fCommentAttri”)
(...)
AddAttribute(fCommentAttri);
{NEW}
fCommentAttri_Ansi := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Ansi', SYNS_XML_AttrComment+'_Ansi'); //Ostatnie dwa ciągi to podpis i przechowywana nazwa
//Jeśli chcesz mieć domyślne ustawienia swojego atrybutu, możesz np. dodać to:
//fCommentAttri_Ansi.Background := clBlack; //Ustawiłoby to „Tło” na „clBlack” jako domyślne
AddAttribute(fCommentAttri_Ansi);
fCommentAttri_Bor := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Bor', SYNS_XML_AttrComment+'_Bor');
AddAttribute(fCommentAttri_Bor);
fCommentAttri_Slash := TSynHighlighterAttributes.Create(SYNS_AttrComment+'_Slash', SYNS_XML_AttrComment+'_Slash');
AddAttribute(fCommentAttri_Slash);
{/NEW}
(...)
- Bardziej skomplikowane działanie polega teraz na wyszukaniu miejsc, w których „FTokenID” jest ustawione na „tkComment” i jednocześnie obsługuje nasz „podtyp” (oczywiście już je dla Ciebie znalazłem :)
procedure TSynPasSyn.BorProc;
(...)
fTokenID := tkComment;
{NEW}
FCommentID:=tckBor;
{/NEW}
if rsIDEDirective in fRange then
(...)
procedure TSynPasSyn.AnsiProc;
begin
fTokenID := tkComment;
{NEW}
FCommentID:=tckAnsi;
{/NEW}
(...)
procedure TSynPasSyn.RoundOpenProc;
(...)
fTokenID := tkComment;
{NEW}
FCommentID:=tckAnsi;
{/NEW}
fStringLen := 2; // długość "(*"
(...)
procedure TSynPasSyn.SlashProc;
begin
if fLine[Run+1] = '/' then begin
fTokenID := tkComment;
{NEW}
FCommentID:=tckSlash;
{/NEW}
if FAtLineStart then begin
(...)
procedure TSynPasSyn.SlashContinueProc;
(...)
fTokenID := tkComment;
{NEW}
FCommentID:=tckSlash;
{/NEW}
while not(fLine[Run] in [#0, #10, #13]) do
(...)
- Teraz musimy tylko pobrać informacje po wywołaniu „GetTokenAttribute” i zwrócić właściwy atrybut, dlatego edytujemy „GetTokenAttribute” w następujący sposób:
function TSynPasSyn.GetTokenAttribute: TSynHighlighterAttributes;
begin
case GetTokenID of
tkAsm: Result := fAsmAttri;
{OLD
tkComment: Result := fCommentAttri; //To jest komentarz i stanowi kopię zapasową, więc zostanie zignorowany
/OLD}
{NEW}
tkComment: begin
if (FCommentID = tckAnsi) then
Result := fCommentAttri_Ansi //To jest typ standardowy AnsiComment
else
if (FCommentID = tckBor) then
Result := fCommentAttri_Bor //To jest typ klamrowy BorComment
else
if (FCommentID = tckSlash) then
Result := fCommentAttri_Slash //To jest typ ukośnikowy SlashComment
else
Result := fCommentAttri //Jeśli nasz kod w jakiś sposób zawiódł, przywróć ustawienia domyślne
end;
{/NEW}
tkIDEDirective: begin
(...)
Jeśli używasz lazarusa, po prostu zainstaluj ponownie pakiet SynEdit, jeśli nie, przekompiluj swój projekt/pakiet.
GOTOWE ! Mówię poważnie! Twój kod jest teraz gotowy na rozróżnianie różnych typów komentarzy.
Lazarus-IDE automatycznie wykrywa, jakie atrybuty istnieją i pokazuje je w opcjach, na przykład zapisuje je, jeśli je zmienisz. Jeśli Twoja aplikacja/IDE tego nie robi, będziesz musiał ustawić Kolor/Czcionkę/itp. nowych atrybutów gdzieś ręcznie (np. w konstruktorze TSynPasSyn)
Realizacja wtyczek
Istnieją 3 wtyczki uzupełniające dla SynEdit:
- Oferuje listę słów w rozwijanym menu za pomocą kombinacji klawiszy skrótu (domyślnie: Ctrl-Spacja).
- Używane w IDE do uzupełniania identyfikatora.
- Zawarte w przykładach.
- Dostępne na palecie komponentów (od wersji 0.9.3x).
Przykładowy kod wywołujący programowo wyskakujące okienko uzupełniania (tj. bez naciskania skrótu klawiaturowego):
YourSynEdit.CommandProcessor(YourSynCompletion.ExecCommandID, '', nil)
- Zastępuje bieżący token fragmentem tekstu. Nie jest to interaktywne. Nie posiada menu rozwijanego.
- Zawarte w przykładach.
- Dostępne na palecie komponentów.
- Podstawowy moduł szablonów. Nie posiada menu rozwijanego.
- Używany przez IDE do szablonów kodu. IDE zawiera dodatkowy kod rozszerzający tę funkcję (rozwijane i synchronizujące makra dodawane są przez IDE).
- Nie ujęte w przykładach.
Todo: Należy udokumentować różnice pomiędzy 2. i 3. poziomem. Może uda się je połączyć.
Logiczna/fizyczna pozycja karetki
SynEdit oferuje położenie karetki (migającego kursora tekstowego) w 2 różnych formach:
- Fizyczne X/Y: Odpowiada pozycji wizualnej (na płótnie) karetki,
- Logiczne X/Y: Odpowiada przesunięciu bajtów tekstu.
Obydwa są oparte na 1. Obecnie współrzędne Y są zawsze takie same. To może się zmienić w przyszłości.
- Współrzędna fizyczna
- To pozycja w siatce wyświetlania (pomijająca przewijanie). Przy czym:
- litera „a” i „â” zajmują JEDNĄ komórkę w siatce, zwiększając fizyczne x o 1. Mimo że w utf8 kodowanie „a” zajmuje jeden bajt, a „â” zajmuje kilka bajtów.
- jednakże znak tabulacji (#9), poza tym, że jest tylko jednym bajtem i jednym znakiem, może zająć kilka komórek w siatce, zwiększając fizyczne x o więcej niż jeden. Istnieją również znaki w językach chińskim i wschodnim, które zajmują 2 pozycje siatki (znak Google o pełnej szerokości i o połowie szerokości)
- Współrzędna logiczna
- To przesunięcie bajtu w ciągu znaków przechowującym linię.
- litera „a” ma 1 bajt i zwiększa się o 1
- litera „â” ma 2 (lub 3) bajty i zwiększa się o tą wartość
- tab ma 1 bajt i zwiększa się o 1.
Żaden z tych współrzędnych nie podaje pozycji w znakach/punktach kodowych UTF8 (tak jak np. Utf8Copy czy Utf8Length).
Fizyczna współrzędna X jest zawsze liczona od lewej strony tekstu, nawet jeśli jest on przewijany. Aby uzyskać grid-x aktualnie przewijanej kontrolki, wykonaj:
- grid-X-in-visible-part-of-synedit := PhysicalX - SynEdit.LeftChar + 1
- grid-y-in-visible-part-of-synedit := SynEdit.RowToScreenRow(PhysicalY); // obejmuje zwijanie bloków
- użyj ScreenRowToRow do odwrotnych wyliczeń
Zmiana tekstu za pomocą kodu
Ostrzeżenie: Zmiana tekstu za pomocą właściwości SynEdit.Lines nie działa w przypadku funkcji cofnij/ponów.
Dostęp do tekstu można uzyskać za pośrednictwem SynEdit.Lines. Jest to właściwość oparta na TStrings oferująca dostęp do odczytu/zapisu dla każdej linii. Pierwszy wiersz ma index 0.
SynEdit.Lines[0] := 'Text'; // pierwsza line
Za pomocą SynEdit.Lines można ustawić początkową wersję tekstu (np. wczytaną z pliku). Należy pamiętać, że SynEdit.Lines.Add/SynEdit.Lines.Append nie obsługuje podziału wierszy wewnątrz dodanych ciągów. Należy dodawać linie jedna po drugiej.
Aby zmodyfikować zawartość SynEdit i pozwolić użytkownikowi na cofnięcie akcji, użyj następujących metod:
procedure InsertTextAtCaret(aText: String; aCaretMode: TSynCaretAdjustMode = scamEnd);
property TextBetweenPoints[aStartPoint, aEndPoint: TPoint]: String // Logiczna pozycja
read GetTextBetweenPoints write SetTextBetweenPointsSimple;
property TextBetweenPointsEx[aStartPoint, aEndPoint: TPoint; CaretMode: TSynCaretAdjustMode]: String
write SetTextBetweenPointsEx;
procedure SetTextBetweenPoints(aStartPoint, aEndPoint: TPoint;
const AValue: String;
aFlags: TSynEditTextFlags = [];
aCaretMode: TSynCaretAdjustMode = scamIgnore;
aMarksMode: TSynMarksAdjustMode = smaMoveUp;
aSelectionMode: TSynSelectionMode = smNormal );
Examples:
// Wstaw tekst w miejscu karetki
SynEdit.InsertTextAtCaret('Tekst');
// Zamień tekst od punktu (x=2,y=10) do punktu (x=4,y=20) na Str
SynEdit.TextBetweenPoints[Point(2,10), Point(4,20)] := Str;
// Usuń/zamień pojedynczy znak w pozycji karetki
var
p1, p2: TPoint;
begin
p1 := SynEdit.LogicalCaretXY;
p2 := p1;
// Oblicz pozycję bajtu następnego znaku
p2.x := p2.x + UTF8CharacterLength(@SynEdit.LineText[p2.x]);
// p1 wskazuje pierwszy bajt znaku, który ma zostać zastąpiony
// p2 wskazuje pierwszy bajt znaku po ostatnim znaku, który można zastąpić
// Zamień na „Tekst” (lub użyj pustego ciągu, aby usunąć)
SynEdit.TextBetweenPoints[p1, p2] := 'Tekst';
Zwiń/rozwiń za pomocą kodu
- To jest wciąż w budowie.
- Działa to tylko wtedy, gdy bieżący poddświetlacz składni obsługuje zwijanie kodu (szczegóły w SynEdit_Highlighter).
- Należy również pamiętać, że niektóre podświetlacze obsługują kilka niezależnych drzew zwijania. Np. w Pascalu możesz zwinąć słowa kluczowe (begin, end, class, procedura itp.), które jest głównym zwijaniem, ale możesz zwinąć też $ifdef lub $region, które jest zwijaniem drugorzędnym.
- Zwijanie bieżącego zaznaczenia różni się także od zwijania słów kluczowych.
Metody zwijania kodu:
1) TSynEdit.CodeFoldAction
Pasuje na podanej linii. Jeśli jest więcej niż jeden, zwija najbardziej do środka (najbardziej po prawej). Uwaga: to nie działa w przypadku zaznaczania ani w przypadku zakładek, które całkowicie się ukrywają / Wymagają przetestowania dla innych operacji zwijania.
2) TSynEdit.FindNextUnfoldedLine
3) TSynEdit.FoldAll / TSynEdit.UnfoldAll
Zakładki
Więcej informacji
Dyskusje na forum, które zawierają informacje o SynEdit:
- Wyszukaj/zamień; wstawka korektorska; pozycja logiczna/fizyczna
- Różnica między SynEdit/SynMemo
- Działania myszy; wyłącz wklejanie środkowym kliknięciem
- Informacje o TSynEditMarkup
Przykładowe aplikacje
Przykładowe zastosowania znajdziesz w folderze "lazarus/examples/synedit".
Dodawanie skrótów klawiszowych do wycinania/kopiowania/wklejania/itp
Skróty klawiszowe można wdrożyć za pomocą poleceń SynEdit.
uses
SynEdit, SynEditKeyCmds;
procedure TForm1.SynEdit1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
if (Shift = [ssCtrl]) then
case Key of
VK_C: SynEdit1.CommandProcessor(TSynEditorCommand(ecCopy), ' ', nil);
VK_V: SynEdit1.CommandProcessor(TSynEditorCommand(ecPaste), ' ', nil);
VK_X: SynEdit1.CommandProcessor(TSynEditorCommand(ecCut), ' ', nil);
end;
end;
Dalszy rozwój, dyskusje
- RTL (od prawej do lewej): rozpoczęty przez Mazena (częściowo zaimplementowany w systemie Windows)
- SynEdit używa tylko UTF8; wersja ASCII/ANSI już nie istnieje. Czcionka jest wstępnie wybrana w zależności od systemu. Użytkownik może wybrać inną czcionkę, ale musi wtedy wybrać czcionkę o stałej szerokości.
- automatyczny wybór czcionki o stałej szerokości: W tej chwili SynEdit zaczyna od czcionki „courier”. W tej chwili LCL TFont nie udostępnia właściwości umożliwiającej filtrowanie czcionek o stałej szerokości.
- automatyczny wybór czcionki UTF-8: To samo co powyżej o stałej szerokości, ale także z czcionką UTF-8, tak aby np. umlauty były wyświetlane poprawnie.
- Martwe klucze. Większość klawiatur obsługuje wpisywanie dwóch lub więcej klawiszy w celu utworzenia jednego znaku specjalnego (takiego jak znaki akcentowane lub umlaut). (Jest to obsługiwane przez zestaw widżetów LCL)
- Przeprojektowanie komponentu SynEdit. Podstawowym celem jest bardziej niezawodne wyświetlanie i nawigacja w tekście. Bardziej modułowe podejście pozwala również na lepszą integrację rozszerzeń i wyspecjalizowanych elementów sterujących do użytku poza Lazarusem.
- Zawijanie słów. Jest to eksperymentalna implementacja oparta na idei klas TextTrimmer/TabExpansion. Powiązany problem z bugtrakerem zawiera klasę i wyjaśnienie zmian wymaganych w innych plikach, aby działał.
- Haki w przetwarzaniu kluczy/poleceń SynEdit. Na forum: http://forum.lazarus-ide.org/index.php/topic,35592.msg243316.html#msg243316