Zeilenmarkierungen und der Randklick¶
Eine Zeilenmarkierung ist ein Symbol in der Lesezeichenspalte des Editors
und/oder eine Tönung über die ganze Zeile, die an einer Zeile eines Dokuments
hängt und beim Bearbeiten mitwandert. Haltepunkte (gefüllt, hohl, bedingt), ein
Pfeil für die aktuelle Anweisung und Änderungsstreifen der Versionsverwaltung
sind allesamt Zeilenmarkierungen. Den Dienst erreichen Sie über
IPluginContext::lineMarkers() (PluginApi/ILineMarkerService.h).
Das Plugin beschreibt, wie eine Art von Markierung aussieht und wo die Markierungen dieser Art sitzen; das Zeichnen, der Rand und die Markierungs-Slots der Bearbeitungs-Engine gehören dem Editor. Keine Pixelgröße, keine Engine-Nummer und kein Qt-Typ überquert die Grenze.
Arten¶
Registrieren Sie jede Art von Markierung einmal, in initialize(), und
behalten Sie das 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 */ }
- Farben sind IDs von Theme-Kategorien, die Sie selbst über
ctx.themePalette()registriert haben; Markierungen folgen so dem aktiven Theme, und der Benutzer kann sie im Theme-Editor umfärben; der Editor wendet sie bei jedem Theme-Wechsel neu an. - Symbole sind ein kleiner, fester Satz, den jeder Host in einem schmalen
Rand bei jedem Zoom zeichnen kann:
Circle(ein Haltepunkt),CircleHollow(ein deaktivierter oder nicht bestätigter Haltepunkt),CircleBar(ein bedingter Haltepunkt),Arrow(die aktuelle Anweisung),Strip(eine geänderte Zeile).Noneergibt eine Art, die nur tönt. - zOrder entscheidet, welche Markierung oben gezeichnet wird, wenn sich mehrere eine Zeile teilen (der Pfeil der aktuellen Anweisung über einem Haltepunkt, ein Haltepunkt über einem Änderungsstreifen); bei gleichen Werten liegt die später registrierte Art oben. Die Reihenfolge gilt über Plugins hinweg.
- Die Registrierung kann fehlschlagen. Die Bearbeitungs-Engine hat eine kleine, feste Anzahl von Markierungs-Slots, die sich alle Plugins teilen — neun; eine Art mit Symbol und Tönung belegt zwei. Sind sie aufgebraucht, kommt das Token leer zurück, und das Log sagt, warum. Registrieren Sie die benötigten Arten einmal und behalten Sie sie; registrieren Sie nie eine Art pro Dokument oder pro Markierung.
- Das Zerstören des Tokens entfernt alle Markierungen dieser Art aus allen Dokumenten und zieht die Art zurück.
Markierungen¶
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 liefert 0 — und setzt nichts —, wenn die Art nicht lebt, das
Dokument nicht geöffnet ist oder die Zeile außerhalb des Dokuments liegt. Eine
Zeile wird nicht begrenzt: Ein Haltepunkt in der falschen Zeile ist
schlimmer als keiner. Ein Handle ist ein einfacher Wert, kein Token; halten
Sie so viele, wie Sie brauchen.
Was danach mit einer Markierung geschieht:
- Bearbeitungen verschieben sie mit ihrer Zeile: Darüber eingefügte oder gelöschte Zeilen verschieben sie, Tippen in der Zeile behält sie bei — so folgt ein Haltepunkt dem Code.
- Ihre Zeile wird gelöscht (Teil eines entfernten Bereichs): Sie bleibt erhalten und wandert in die Zeile, in der der gelöschte Bereich begann. Zwei Markierungen können so in einer Zeile landen.
- Der ganze Puffer wird ersetzt (ein Neuladen nach einer Änderung von
außen,
IEditorService::setText): Jede Markierung bleibt auf derselben Zeilennummer; eine, deren Zeile nicht mehr existiert, wird entfernt. Der Editor vergleicht alten und neuen Text nicht. - Das Dokument wird geschlossen: Seine Markierungen werden entfernt und
ihre Handles werden ungültig. Der Editor speichert Markierungen nie — ein
Plugin, das Markierungen über ein Schließen hinweg behält (Haltepunkte),
hält sie in seinem eigenen Modell und fügt sie bei
DocumentOpenederneut hinzu (eine wieder geöffnete Datei ist eine neueDocumentId).
Markierungen gehören zum Dokument: Einmal gesetzt, erscheinen sie in jedem
Bereich eines geteilten Dokuments. Die
Minimap, ihre Hover-Vorschau und die Vergleichsansicht zeigen sie nie.
Lesezeichen sind keine Zeilenmarkierungen dieses Dienstes; sie behalten ihre
eigenen IEditorService-Aufrufe.
Der Randklick¶
Jeder Linksklick in die Lesezeichenspalte eines Editors wird als
events::MarginClicked veröffentlicht:
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
};
Die Namen der Modifikatoren folgen den portablen Kürzel-Strings: kControl
ist Strg unter Windows und Linux und Befehl (⌘) unter macOS, kAlt ist Alt /
Option (⌥), kMeta ist die Windows-Taste / Control (⌃) unter macOS. Klicks in
die Faltspalte falten und Klicks auf die Zeilennummern wählen aus; keines von
beiden wird veröffentlicht.
Standardmäßig schaltet der Editor außerdem ein Lesezeichen in der angeklickten Zeile um, wie schon immer. Ein Plugin, das dem Klick eine eigene Bedeutung gibt — ein Debugger, der mit einem einfachen Klick einen Haltepunkt umschaltet und mit einem Klick mit Modifikator dessen Bedingung bearbeitet —, beansprucht ihn:
m_marginClaim = ctx.lineMarkers().claimMarginClick(); // MarginClickToken
m_clicks = ctx.events().subscribe<events::MarginClicked>(
[this](const events::MarginClicked& e) { onMarginClick(e); });
Solange mindestens ein Anspruch lebt — von welchem Plugin auch immer —, überlässt der Editor den Klick den Plugins und veröffentlicht nur das Event; das Zerstören des letzten Tokens bringt das Umschalten der Lesezeichen zurück. Das Event wird veröffentlicht, ob jemand einen Anspruch hält oder nicht; ein Plugin, das Klicks nur beobachtet, braucht also keinen. Die Lesezeichen-Befehle und ihre Tastenkürzel sind nicht betroffen. Ansprüche werden gezählt, nicht eingereiht: Zwei Plugins, die beide den Klick beanspruchen, erhalten ihn beide und dürfen nicht beide darauf reagieren.
Python¶
Derselbe Dienst ist ctx.line_markers für
Python-Plugins, und der Klick ist
@ctx.events.on_margin_clicked.