Znaczniki wierszy i kliknięcie marginesu¶
Znacznik wiersza to glif w kolumnie zakładek edytora i/lub zabarwienie
całego wiersza, przypięte do wiersza dokumentu i przenoszone razem z nim, gdy
użytkownik edytuje. Punkty przerwania (pełne, puste, warunkowe), strzałka
bieżącej instrukcji i paski zmian z kontroli wersji to wszystko znaczniki
wierszy. Dostęp do usługi daje IPluginContext::lineMarkers()
(PluginApi/ILineMarkerService.h).
Wtyczka opisuje, jak wygląda dany rodzaj znacznika i gdzie stoją znaczniki tego rodzaju; rysowanie, margines i miejsca na znaczniki w silniku edycji należą do edytora. Przez granicę nie przechodzi żaden rozmiar w pikselach, numer silnika ani typ Qt.
Rodzaje¶
Każdy rodzaj znacznika zarejestruj raz, w initialize(), i zachowaj token:
enum class LineMarkerGlyph : std::int32_t {
None, Circle, CircleHollow, CircleBar, Arrow, Strip
};
struct LineMarkerKind {
LineMarkerGlyph glyph = LineMarkerGlyph::Circle;
std::string glyphColor; // a theme category you registered
std::string lineTint; // a theme category; empty = no tint
std::int32_t zOrder = 0; // higher draws above lower
};
m_breakpoint = ctx.lineMarkers().registerKind(kind); // LineMarkerKindToken
if (!m_breakpoint.valid()) { /* no slot left: see below */ }
- Kolory to identyfikatory kategorii motywu, które zarejestrowałeś sam
przez
ctx.themePalette(), więc znaczniki podążają za aktywnym motywem, a użytkownik może je przekolorować w Edytorze motywów; edytor stosuje je ponownie przy każdej zmianie motywu. - Glify to mały, stały zestaw, który każdy host potrafi narysować na
wąskim marginesie w dowolnym powiększeniu:
Circle(punkt przerwania),CircleHollow(wyłączony lub niepotwierdzony punkt przerwania),CircleBar(warunkowy punkt przerwania),Arrow(bieżąca instrukcja),Strip(zmieniony wiersz).Nonetworzy rodzaj z samym zabarwieniem. - zOrder decyduje, który znacznik jest rysowany na wierzchu, gdy kilka dzieli jeden wiersz (strzałka bieżącej instrukcji nad punktem przerwania, punkt przerwania nad paskiem zmian); przy równych wartościach na wierzchu jest rodzaj zarejestrowany później. Kolejność obowiązuje także między wtyczkami.
- Rejestracja może się nie udać. Silnik edycji ma małą, stałą liczbę miejsc na znaczniki, wspólną dla wszystkich wtyczek — dziewięć; rodzaj z glifem i zabarwieniem zajmuje dwa. Gdy się skończą, token wraca pusty, a log mówi dlaczego. Rejestruj potrzebne rodzaje raz i zachowuj je; nigdy nie rejestruj rodzaju per dokument ani per znacznik.
- Zniszczenie tokenu usuwa wszystkie znaczniki tego rodzaju ze wszystkich dokumentów i wycofuje rodzaj.
Znaczniki¶
using LineMarkerId = std::uint64_t; // 0 is never valid
LineMarkerId id = ctx.lineMarkers().addMarker(m_breakpoint.id(), doc, line);
std::int64_t now = ctx.lineMarkers().lineOf(id); // -1 = gone
auto all = ctx.lineMarkers().markers(m_breakpoint.id(), doc); // {id, line} by line
ctx.lineMarkers().removeMarker(id);
ctx.lineMarkers().clearMarkers(m_breakpoint.id(), 0); // 0 = every document
addMarker zwraca 0 — i niczego nie stawia — gdy rodzaj nie żyje, dokument
nie jest otwarty albo wiersz leży poza dokumentem. Wiersz nie jest
przycinany: punkt przerwania w złym wierszu jest gorszy niż żaden. Uchwyt to
zwykła wartość, a nie token; trzymaj ich tyle, ile potrzebujesz.
Co dzieje się ze znacznikiem potem:
- Edycje przesuwają go razem z jego wierszem: wiersze wstawione lub usunięte powyżej go przesuwają, pisanie w tym wierszu go nie rusza — tak punkt przerwania podąża za kodem.
- Jego wiersz zostaje usunięty (jest częścią usuniętego zakresu): znacznik przeżywa i dołącza do wiersza, w którym zaczynał się usunięty zakres. Dwa znaczniki mogą w ten sposób trafić do jednego wiersza.
- Cały bufor zostaje zastąpiony (ponowne wczytanie po zmianie z zewnątrz,
IEditorService::setText): każdy znacznik zostaje na tym samym numerze wiersza; ten, którego wiersz już nie istnieje, jest usuwany. Edytor nie porównuje starego i nowego tekstu. - Dokument zostaje zamknięty: jego znaczniki są usuwane, a ich uchwyty
przestają działać. Edytor nigdy nie zapisuje znaczników — wtyczka, która
zachowuje oznaczenia po zamknięciu (punkty przerwania), trzyma je we
własnym modelu i dodaje ponownie przy
DocumentOpened(ponownie otwarty plik to nowyDocumentId).
Znaczniki należą do dokumentu: postawione raz, pokazują się w każdym
panelu podzielonego dokumentu. Minimapa, jej
podgląd po najechaniu i widok porównania nigdy ich nie pokazują. Zakładki nie
są znacznikami tej usługi; zachowują własne wywołania IEditorService.
Kliknięcie marginesu¶
Każde kliknięcie lewym przyciskiem w kolumnie zakładek edytora jest
publikowane jako events::MarginClicked:
struct MarginClicked {
DocumentId doc;
std::int64_t line; // 0-based, level with the click
EditorMargin margin; // EditorMargin::Symbol
KeyModifiers modifiers; // key_modifier::kShift | kControl | kAlt | kMeta
};
Nazwy modyfikatorów odpowiadają przenośnym zapisom skrótów: kControl to
Ctrl w Windows i Linuksie, a Command (⌘) w macOS, kAlt to Alt / Option (⌥),
kMeta to klawisz Windows / Control (⌃) w macOS. Kliknięcia w kolumnie
zwijania zwijają, a kliknięcia w numerach wierszy zaznaczają; żadne z nich
nie jest publikowane.
Domyślnie edytor dodatkowo przełącza zakładkę w klikniętym wierszu, jak zawsze. Wtyczka, która nadaje kliknięciu własne znaczenie — debugger przełączający punkt przerwania zwykłym kliknięciem i edytujący jego warunek kliknięciem z modyfikatorem — przejmuje je:
m_marginClaim = ctx.lineMarkers().claimMarginClick(); // MarginClickToken
m_clicks = ctx.events().subscribe<events::MarginClicked>(
[this](const events::MarginClicked& e) { onMarginClick(e); });
Dopóki żyje choć jedno przejęcie — dowolnej wtyczki — edytor zostawia kliknięcie wtyczkom i tylko publikuje zdarzenie; zniszczenie ostatniego tokenu przywraca przełączanie zakładki. Zdarzenie jest publikowane niezależnie od tego, czy ktoś trzyma przejęcie, więc wtyczka, która tylko obserwuje kliknięcia, żadnego nie potrzebuje. Polecenia zakładek i ich skróty działają bez zmian. Przejęcia są liczone, a nie kolejkowane: dwie wtyczki, które obie przejmą kliknięcie, obie je dostaną i nie mogą obie na nie reagować.
Python¶
Ta sama usługa to ctx.line_markers dla
wtyczek w Pythonie, a
kliknięcie to @ctx.events.on_margin_clicked.