Radmärken och marginalklicket¶
Ett radmärke är en symbol i redigerarens bokmärkeskolumn och/eller en
toning över hela raden, fäst vid en rad i ett dokument och buren med den medan
användaren redigerar. Brytpunkter (fyllda, ihåliga, villkorliga), en pil för
aktuell sats och versionshanteringens ändringsremsor är alla radmärken. Du når
tjänsten via IPluginContext::lineMarkers() (PluginApi/ILineMarkerService.h).
Insticksmodulen beskriver hur en typ av märke ser ut och var märken av den typen sitter; ritandet, marginalen och redigeringsmotorns märkesplatser tillhör redigeraren. Ingen pixelstorlek, inget motornummer och ingen Qt-typ korsar gränsen.
Typer¶
Registrera varje typ av märke en gång, i initialize(), och behåll 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 */ }
- Färger är id:n för temakategorier som du själv har registrerat med
ctx.themePalette(), så märkena följer det aktiva temat och användaren kan färga om dem i Temaredigeraren; redigeraren tillämpar dem på nytt vid varje temabyte. - Symboler är en liten, fast uppsättning som varje värd kan rita i en smal
marginal vid alla zoomnivåer:
Circle(en brytpunkt),CircleHollow(en inaktiverad eller obekräftad brytpunkt),CircleBar(en villkorlig brytpunkt),Arrow(aktuell sats),Strip(en ändrad rad).Noneger en typ som bara tonar. - zOrder avgör vilket märke som ritas överst när flera delar en rad (pilen för aktuell sats ovanför en brytpunkt, en brytpunkt ovanför en ändringsremsa); vid lika värden hamnar den senare registrerade typen överst. Ordningen gäller även mellan insticksmoduler.
- Registreringen kan misslyckas. Redigeringsmotorn har ett litet, fast antal märkesplatser som alla insticksmoduler delar — nio; en typ med symbol och toning använder två. När de tar slut kommer token tillbaka tom, och loggen talar om varför. Registrera de typer du behöver en gång och behåll dem; registrera aldrig en typ per dokument eller per märke.
- Att förstöra token tar bort alla märken av den typen från alla dokument och drar tillbaka typen.
Märken¶
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 returnerar 0 — och placerar ingenting — när typen inte lever,
dokumentet inte är öppet eller raden ligger utanför dokumentet. En rad
begränsas inte: en brytpunkt på fel rad är värre än ingen. Ett handtag är
ett enkelt värde, inte en token; behåll så många du behöver.
Vad som sedan händer med ett märke:
- Redigeringar flyttar det med dess rad: rader som infogas eller tas bort ovanför förskjuter det, att skriva på raden behåller det — så följer en brytpunkt koden.
- Dess rad tas bort (del av ett borttaget intervall): det överlever och hamnar på raden där det borttagna intervallet började. Två märken kan på så sätt hamna på samma rad.
- Hela bufferten ersätts (en omläsning efter en ändring utifrån,
IEditorService::setText): varje märke stannar på samma radnummer; ett märke vars rad inte längre finns tas bort. Redigeraren jämför inte gammal och ny text. - Dokumentet stängs: dess märken tas bort och deras handtag slutar gälla.
Redigeraren sparar aldrig märken — en insticksmodul som behåller märken efter
en stängning (brytpunkter) håller dem i sin egen modell och lägger till dem
igen vid
DocumentOpened(en återöppnad fil är ett nyttDocumentId).
Märken tillhör dokumentet: placerade en gång syns de i varje ruta i ett
delat dokument. Minikartan, dess
förhandsvisning vid hovring och jämförelsevyn visar dem aldrig. Bokmärken är
inte märken i den här tjänsten; de behåller sina egna IEditorService-anrop.
Marginalklicket¶
Varje vänsterklick i en redigerares bokmärkeskolumn publiceras som
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
};
Modifierarnas namn följer de portabla kortkommandosträngarna: kControl är
Ctrl i Windows och Linux och Kommando (⌘) i macOS, kAlt är Alt / Option (⌥),
kMeta är Windows-tangenten / Kontroll (⌃) i macOS. Klick i vikningskolumnen
viker och klick på radnumren markerar; inget av dem publiceras.
Som standard växlar redigeraren också ett bokmärke på den klickade raden, som den alltid har gjort. En insticksmodul som ger klicket en egen betydelse — en felsökare som växlar en brytpunkt med ett vanligt klick och redigerar dess villkor med ett klick med modifierare — gör anspråk på det:
m_marginClaim = ctx.lineMarkers().claimMarginClick(); // MarginClickToken
m_clicks = ctx.events().subscribe<events::MarginClicked>(
[this](const events::MarginClicked& e) { onMarginClick(e); });
Så länge minst ett anspråk lever — från vilken modul som helst — lämnar redigeraren klicket åt insticksmodulerna och publicerar bara händelsen; att förstöra den sista token återställer bokmärkesväxlingen. Händelsen publiceras oavsett om någon har ett anspråk eller inte, så en modul som bara bevakar klick behöver inget. Bokmärkeskommandona och deras kortkommandon påverkas inte. Anspråk räknas, de köas inte: två moduler som båda gör anspråk på klicket får det båda och får inte båda agera på det.
Python¶
Samma tjänst är ctx.line_markers för
Python-insticksmoduler, och klicket
är @ctx.events.on_margin_clicked.