Přeskočit obsah

Značky řádků a kliknutí na okraj

Značka řádku je symbol ve sloupci záložek editoru a/nebo podbarvení přes celý řádek, připojené k řádku dokumentu a přenášené s ním, zatímco uživatel upravuje text. Zarážky (plné, prázdné, podmíněné), šipka aktuálního příkazu a pruhy změn ze správy verzí jsou všechno značky řádků. Ke službě se dostanete přes IPluginContext::lineMarkers() (PluginApi/ILineMarkerService.h).

Modul popisuje, jak druh značky vypadá a kde značky toho druhu stojí; vykreslování, okraj a sloty pro značky v editačním jádře patří editoru. Hranici nepřekračuje žádná velikost v pixelech, číslo jádra ani typ Qt.

Druhy

Každý druh značky zaregistrujte jednou, v initialize(), a token si ponechte:

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 */ }
  • Barvy jsou id kategorií motivu, které jste si sami zaregistrovali přes ctx.themePalette(), takže značky sledují aktivní motiv a uživatel je může přebarvit v Editoru motivů; editor je znovu použije při každé změně motivu.
  • Symboly jsou malá pevná sada, kterou umí každý hostitel vykreslit v úzkém okraji při jakémkoli přiblížení: Circle (zarážka), CircleHollow (vypnutá nebo neověřená zarážka), CircleBar (podmíněná zarážka), Arrow (aktuální příkaz), Strip (změněný řádek). None vytvoří druh, který jen podbarvuje.
  • zOrder rozhoduje, která značka se vykreslí nahoře, když jich několik sdílí jeden řádek (šipka aktuálního příkazu nad zarážkou, zarážka nad pruhem změn); při shodných hodnotách je nahoře druh zaregistrovaný později. Pořadí platí i napříč moduly.
  • Registrace může selhat. Editační jádro má malý pevný počet slotů pro značky, sdílený všemi moduly — devět; druh se symbolem i podbarvením zabírá dva. Když dojdou, token se vrátí prázdný a protokol řekne proč. Potřebné druhy registrujte jednou a ponechte si je; nikdy neregistrujte druh pro každý dokument nebo každou značku.
  • Zničení tokenu odstraní všechny značky toho druhu ze všech dokumentů a druh stáhne.

Značky

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 vrátí 0 — a nic neumístí — když druh nežije, dokument není otevřený nebo řádek leží mimo dokument. Řádek se neořezává: zarážka na špatném řádku je horší než žádná. Popisovač je obyčejná hodnota, ne token; držte jich, kolik potřebujete.

Co se se značkou děje potom:

  • Úpravy ji posouvají spolu s jejím řádkem: řádky vložené nebo smazané nad ní ji posunou, psaní na řádku ji ponechá — tak zarážka sleduje kód.
  • Její řádek se smaže (je součástí odstraněného rozsahu): značka přežije a přesune se na řádek, kde odstraněný rozsah začínal. Dvě značky tak mohou skončit na jednom řádku.
  • Nahradí se celý buffer (znovunačtení po změně zvenčí, IEditorService::setText): každá značka zůstane na stejném čísle řádku; značka, jejíž řádek už neexistuje, se odstraní. Editor starý a nový text neporovnává.
  • Dokument se zavře: jeho značky se odstraní a jejich popisovače přestanou platit. Editor značky nikdy neukládá — modul, který si značky ponechává i po zavření (zarážky), je drží ve vlastním modelu a při DocumentOpened je přidá znovu (znovu otevřený soubor má nové DocumentId).

Značky patří dokumentu: jednou umístěné se zobrazí v každém panelu rozděleného dokumentu. Minimapa, její náhled při najetí a zobrazení porovnání je nikdy neukazují. Záložky nejsou značkami této služby; ponechávají si vlastní volání IEditorService.

Kliknutí na okraj

Každé kliknutí levým tlačítkem do sloupce záložek editoru se publikuje 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
};

Názvy modifikátorů odpovídají přenositelným řetězcům zkratek: kControl je Ctrl ve Windows a Linuxu a Command (⌘) v macOS, kAlt je Alt / Option (⌥), kMeta je klávesa Windows / Control (⌃) v macOS. Kliknutí do sloupce sbalování sbalují a kliknutí na čísla řádků vybírají; ani jedno se nepublikuje.

Ve výchozím stavu editor navíc na kliknutém řádku přepne záložku, jako to dělal vždy. Modul, který kliknutí dává vlastní význam — ladicí program, který prostým kliknutím přepíná zarážku a kliknutím s modifikátorem upravuje její podmínku —, si ho nárokuje:

m_marginClaim = ctx.lineMarkers().claimMarginClick();   // MarginClickToken
m_clicks = ctx.events().subscribe<events::MarginClicked>(
    [this](const events::MarginClicked& e) { onMarginClick(e); });

Dokud žije aspoň jeden nárok — od kteréhokoli modulu —, editor kliknutí přenechá modulům a jen publikuje událost; zničení posledního tokenu vrátí přepínání záložek. Událost se publikuje bez ohledu na to, zda někdo drží nárok, takže modul, který kliknutí jen sleduje, žádný nepotřebuje. Příkazy záložek a jejich zkratky se nemění. Nároky se počítají, neřadí se do fronty: dva moduly, které si kliknutí oba nárokují, ho oba dostanou a nesmějí na něj oba reagovat.

Python

Tatáž služba je ctx.line_markers pro moduly v Pythonu a kliknutí je @ctx.events.on_margin_clicked.