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).Nonegiver 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 nytDocumentId).
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.