Gå til indholdet

Linjemærker og margenklikket

Et linjemærke er et symbol i editorens bogmærkekolonne og/eller en farvning over hele linjen, fæstnet til en linje i et dokument og ført med, mens brugeren redigerer. Stoppunkter (udfyldte, hule, betingede), en pil for den aktuelle sætning og versionsstyringens ændringsstriber er alle linjemærker. Du når tjenesten gennem IPluginContext::lineMarkers() (PluginApi/ILineMarkerService.h).

Udvidelsesmodulet beskriver, hvordan en type mærke ser ud, og hvor mærker af den type sidder; tegningen, margenen og redigeringsmotorens mærkepladser tilhører editoren. Ingen pixelstørrelse, intet motornummer og ingen Qt-type krydser grænsen.

Typer

Registrér hver type mærke én gang, i initialize(), og behold tokenet:

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 */ }
  • Farver er id'er på temakategorier, som du selv har registreret med ctx.themePalette(), så mærkerne følger det aktive tema, og brugeren kan farve dem om i Temaeditoren; editoren anvender dem igen ved hvert temaskift.
  • Symboler er et lille, fast sæt, som enhver vært kan tegne i en smal margen ved alle zoomniveauer: Circle (et stoppunkt), CircleHollow (et deaktiveret eller ubekræftet stoppunkt), CircleBar (et betinget stoppunkt), Arrow (den aktuelle sætning), Strip (en ændret linje). None giver en type, der kun farver.
  • zOrder afgør, hvilket mærke der tegnes øverst, når flere deler en linje (pilen for den aktuelle sætning over et stoppunkt, et stoppunkt over en ændringsstribe); ved ens værdier ligger den senest registrerede type øverst. Rækkefølgen gælder også på tværs af udvidelsesmoduler.
  • Registreringen kan mislykkes. Redigeringsmotoren har et lille, fast antal mærkepladser, som alle udvidelsesmoduler deler — ni; en type med symbol og farvning bruger to. Når de er opbrugt, kommer tokenet tomt tilbage, og loggen fortæller hvorfor. Registrér de typer, du har brug for, én gang, og behold dem; registrér aldrig en type pr. dokument eller pr. mærke.
  • At ødelægge tokenet fjerner alle mærker af den type fra alle dokumenter og trækker typen tilbage.

Mærker

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 returnerer 0 — og placerer intet — når typen ikke lever, dokumentet ikke er åbent, eller linjen ligger uden for dokumentet. En linje afgrænses ikke: et stoppunkt på den forkerte linje er værre end intet. Et håndtag er en simpel værdi, ikke et token; hold på så mange, du har brug for.

Hvad der derefter sker med et mærke:

  • Redigeringer flytter det med dets linje: linjer, der indsættes eller slettes ovenover, forskyder det, at skrive på linjen beholder det — sådan følger et stoppunkt koden.
  • Dets linje slettes (en del af et fjernet område): det overlever og lander på den linje, hvor det slettede område begyndte. To mærker kan således ende på én linje.
  • Hele bufferen udskiftes (en genindlæsning efter en ændring udefra, IEditorService::setText): hvert mærke bliver på samme linjenummer; et mærke, hvis linje ikke længere findes, fjernes. Editoren sammenligner ikke gammel og ny tekst.
  • Dokumentet lukkes: dets mærker fjernes, og deres håndtag holder op med at gælde. Editoren gemmer aldrig mærker — et udvidelsesmodul, der beholder mærker efter en lukning (stoppunkter), holder dem i sin egen model og tilføjer dem igen ved DocumentOpened (en genåbnet fil er et nyt DocumentId).

Mærker hører til dokumentet: placeret én gang vises de i hver rude i et opdelt dokument. Minikortet, dets forhåndsvisning ved pegning og sammenligningsvisningen viser dem aldrig. Bogmærker er ikke mærker i denne tjeneste; de beholder deres egne IEditorService-kald.

Margenklikket

Hvert venstreklik i en editors bogmærkekolonne udgives 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
};

Navnene på modifikatorerne følger de flytbare genvejsstrenge: kControl er Ctrl på Windows og Linux og Command (⌘) på macOS, kAlt er Alt / Option (⌥), kMeta er Windows-tasten / Control (⌃) på macOS. Klik i foldekolonnen folder, og klik på linjenumrene markerer; ingen af dem udgives.

Som standard slår editoren også et bogmærke til eller fra på den linje, der blev klikket på, sådan som den altid har gjort. Et udvidelsesmodul, der giver klikket sin egen betydning — en debugger, der slår et stoppunkt til eller fra med et almindeligt klik og redigerer dets betingelse med et klik med modifikator — gør krav 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 mindst ét krav lever — fra et hvilket som helst modul — overlader editoren klikket til udvidelsesmodulerne og udgiver kun hændelsen; når det sidste token ødelægges, slår klikket igen bogmærker til og fra. Hændelsen udgives, uanset om nogen har et krav eller ej, så et modul, der kun holder øje med klik, behøver intet. Bogmærkekommandoerne og deres genvejstaster påvirkes ikke. Krav tælles, de sættes ikke i kø: to moduler, der begge gør krav på klikket, modtager det begge og må ikke begge handle på det.

Python

Den samme tjeneste er ctx.line_markers for Python-udvidelsesmoduler, og klikket er @ctx.events.on_margin_clicked.