Ga naar inhoud

Regelmarkeringen en de margeklik

Een regelmarkering is een symbool in de bladwijzerkolom van de editor en/of een kleuring over de hele regel, vastgemaakt aan een regel van een document en meegenomen terwijl de gebruiker bewerkt. Onderbrekingspunten (gevuld, hol, voorwaardelijk), een pijl voor de huidige instructie en de wijzigingsstroken van versiebeheer zijn allemaal regelmarkeringen. Je bereikt de dienst via IPluginContext::lineMarkers() (PluginApi/ILineMarkerService.h).

De plug-in beschrijft hoe een soort markering eruitziet en waar de markeringen van die soort staan; het tekenen, de marge en de markeringsplaatsen van de bewerkingsengine zijn van de editor. Geen pixelgrootte, enginenummer of Qt-type gaat over de grens.

Soorten

Registreer elke soort markering één keer, in initialize(), en bewaar het 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 */ }
  • Kleuren zijn id's van themacategorieën die je zelf hebt geregistreerd met ctx.themePalette(), zodat markeringen het actieve thema volgen en de gebruiker ze in de Thema-editor anders kan kleuren; de editor past ze bij elke themawissel opnieuw toe.
  • Symbolen zijn een kleine, vaste set die elke host in een smalle marge bij elke zoom kan tekenen: Circle (een onderbrekingspunt), CircleHollow (een uitgeschakeld of niet bevestigd onderbrekingspunt), CircleBar (een voorwaardelijk onderbrekingspunt), Arrow (de huidige instructie), Strip (een gewijzigde regel). None maakt een soort die alleen kleurt.
  • zOrder bepaalt welke markering bovenop wordt getekend als er meerdere op één regel staan (de pijl van de huidige instructie boven een onderbrekingspunt, een onderbrekingspunt boven een wijzigingsstrook); bij gelijke waarden komt de later geregistreerde soort bovenop. De volgorde geldt over plug-ins heen.
  • Registreren kan mislukken. De bewerkingsengine heeft een klein, vast aantal markeringsplaatsen dat alle plug-ins delen — negen; een soort met een symbool en een kleuring gebruikt er twee. Zijn ze op, dan komt het token leeg terug en zegt het logboek waarom. Registreer de soorten die je nodig hebt één keer en bewaar ze; registreer nooit een soort per document of per markering.
  • Het token vernietigen verwijdert alle markeringen van die soort uit alle documenten en trekt de soort in.

Markeringen

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 geeft 0 terug — en plaatst niets — als de soort niet leeft, het document niet geopend is of de regel buiten het document ligt. Een regel wordt niet begrensd: een onderbrekingspunt op de verkeerde regel is erger dan geen. Een handle is een gewone waarde, geen token; houd er zoveel vast als je nodig hebt.

Wat er daarna met een markering gebeurt:

  • Bewerkingen verplaatsen haar met haar regel: regels die erboven worden ingevoegd of verwijderd verschuiven haar, typen op de regel houdt haar op haar plaats — zo volgt een onderbrekingspunt de code.
  • Haar regel wordt verwijderd (onderdeel van een verwijderd bereik): ze blijft bestaan en schuift naar de regel waar het verwijderde bereik begon. Twee markeringen kunnen zo op één regel terechtkomen.
  • De hele buffer wordt vervangen (een herlading na een wijziging van buitenaf, IEditorService::setText): elke markering blijft op hetzelfde regelnummer; een markering waarvan de regel niet meer bestaat, wordt verwijderd. De editor vergelijkt oude en nieuwe tekst niet.
  • Het document wordt gesloten: de markeringen ervan worden verwijderd en hun handles worden ongeldig. De editor bewaart markeringen nooit — een plug-in die markeringen na het sluiten wil houden (onderbrekingspunten), houdt ze bij in zijn eigen model en voegt ze opnieuw toe bij DocumentOpened (een opnieuw geopend bestand is een nieuwe DocumentId).

Markeringen horen bij het document: één keer geplaatst, verschijnen ze in elk deelvenster van een gesplitst document. De minimap, haar voorvertoning bij aanwijzen en de vergelijkingsweergave tonen ze nooit. Bladwijzers zijn geen regelmarkeringen van deze dienst; ze houden hun eigen IEditorService-aanroepen.

De margeklik

Elke linkerklik in de bladwijzerkolom van een editor wordt gepubliceerd als 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
};

De namen van de modificatietoetsen volgen de draagbare sneltoetsteksten: kControl is Ctrl op Windows en Linux en Command (⌘) op macOS, kAlt is Alt / Option (⌥), kMeta is de Windows-toets / Control (⌃) op macOS. Klikken in de vouwkolom vouwen en klikken op de regelnummers selecteren; geen van beide wordt gepubliceerd.

Standaard schakelt de editor ook een bladwijzer om op de aangeklikte regel, zoals altijd. Een plug-in die de klik een eigen betekenis geeft — een debugger die met een gewone klik een onderbrekingspunt omschakelt en met een klik met modificatietoets de voorwaarde ervan bewerkt — claimt hem:

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

Zolang er minstens één claim leeft — van welke plug-in ook — laat de editor de klik aan de plug-ins over en publiceert hij alleen de gebeurtenis; het laatste token vernietigen brengt het omschakelen van bladwijzers terug. De gebeurtenis wordt gepubliceerd of iemand nu een claim heeft of niet, dus een plug-in die alleen naar klikken kijkt, heeft er geen nodig. De bladwijzeropdrachten en hun sneltoetsen blijven ongewijzigd. Claims worden geteld, niet in een wachtrij gezet: twee plug-ins die allebei de klik claimen, ontvangen hem allebei en mogen er niet allebei op reageren.

Python

Dezelfde dienst is ctx.line_markers voor Python-plug-ins, en de klik is @ctx.events.on_margin_clicked.