Hyppää sisältöön

Rivimerkit ja marginaalin napsautus

Rivimerkki on symboli editorin kirjanmerkkisarakkeessa ja/tai koko rivin kattava sävytys, joka on kiinnitetty asiakirjan riviin ja kulkee sen mukana käyttäjän muokatessa. Keskeytyskohdat (täytetyt, ontot, ehdolliset), nykyisen lauseen nuoli ja versionhallinnan muutospalkit ovat kaikki rivimerkkejä. Palveluun pääsee kutsulla IPluginContext::lineMarkers() (PluginApi/ILineMarkerService.h).

Liitännäinen kuvaa, miltä merkkilaji näyttää ja missä sen lajin merkit ovat; piirtäminen, marginaali ja muokkausmoottorin merkkipaikat kuuluvat editorille. Mikään pikselikoko, moottorin numero tai Qt-tyyppi ei ylitä rajaa.

Lajit

Rekisteröi jokainen merkkilaji kerran, funktiossa initialize(), ja säilytä tunnus:

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 */ }
  • Värit ovat sellaisten teemaluokkien tunnisteita, jotka olet itse rekisteröinyt kutsulla ctx.themePalette(), joten merkit seuraavat aktiivista teemaa ja käyttäjä voi värittää ne uudelleen Teemaeditorissa; editori ottaa ne uudelleen käyttöön jokaisen teemanvaihdon yhteydessä.
  • Symbolit ovat pieni, kiinteä joukko, jonka jokainen isäntä osaa piirtää kapeaan marginaaliin millä tahansa zoomauksella: Circle (keskeytyskohta), CircleHollow (pois käytöstä oleva tai vahvistamaton keskeytyskohta), CircleBar (ehdollinen keskeytyskohta), Arrow (nykyinen lause), Strip (muuttunut rivi). None tekee lajin, joka vain sävyttää.
  • zOrder ratkaisee, mikä merkki piirretään päällimmäiseksi, kun useampi jakaa saman rivin (nykyisen lauseen nuoli keskeytyskohdan päällä, keskeytyskohta muutospalkin päällä); samoilla arvoilla myöhemmin rekisteröity laji tulee päälle. Järjestys pätee myös liitännäisten välillä.
  • Rekisteröinti voi epäonnistua. Muokkausmoottorissa on pieni, kiinteä määrä merkkipaikkoja, jotka kaikki liitännäiset jakavat — yhdeksän; laji, jolla on symboli ja sävytys, käyttää kaksi. Kun ne loppuvat, tunnus palaa tyhjänä ja loki kertoo syyn. Rekisteröi tarvitsemasi lajit kerran ja säilytä ne; älä koskaan rekisteröi lajia asiakirjaa tai merkkiä kohti.
  • Tunnuksen tuhoaminen poistaa kaikki kyseisen lajin merkit kaikista asiakirjoista ja vetää lajin pois käytöstä.

Merkit

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 palauttaa 0 — eikä sijoita mitään — kun laji ei ole elossa, asiakirja ei ole auki tai rivi on asiakirjan ulkopuolella. Riviä ei rajata: väärällä rivillä oleva keskeytyskohta on pahempi kuin ei mitään. Kahva on pelkkä arvo, ei tunnus; pidä niitä niin monta kuin tarvitset.

Mitä merkille tapahtuu sen jälkeen:

  • Muokkaukset siirtävät sitä rivinsä mukana: yläpuolelle lisätyt tai sieltä poistetut rivit siirtävät sitä, rivillä kirjoittaminen pitää sen paikallaan — näin keskeytyskohta seuraa koodia.
  • Sen rivi poistetaan (osa poistettua aluetta): merkki säilyy ja siirtyy riville, josta poistettu alue alkoi. Kaksi merkkiä voi näin päätyä samalle riville.
  • Koko puskuri korvataan (uudelleenlataus ulkopuolisen muutoksen jälkeen, IEditorService::setText): jokainen merkki pysyy samalla rivinumerolla; merkki, jonka riviä ei enää ole, poistetaan. Editori ei vertaa vanhaa ja uutta tekstiä.
  • Asiakirja suljetaan: sen merkit poistetaan ja niiden kahvat lakkaavat toimimasta. Editori ei koskaan tallenna merkkejä — liitännäinen, joka säilyttää merkkejä sulkemisen yli (keskeytyskohdat), pitää ne omassa mallissaan ja lisää ne uudelleen tapahtumassa DocumentOpened (uudelleen avattu tiedosto on uusi DocumentId).

Merkit kuuluvat asiakirjalle: kerran sijoitettuina ne näkyvät jaetun asiakirjan jokaisessa ruudussa. Pienoiskartta, sen osoitusesikatselu ja vertailunäkymä eivät koskaan näytä niitä. Kirjanmerkit eivät ole tämän palvelun merkkejä; niillä on omat IEditorService-kutsunsa.

Marginaalin napsautus

Jokainen vasemman painikkeen napsautus editorin kirjanmerkkisarakkeessa julkaistaan tapahtumana 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
};

Muuntonäppäinten nimet noudattavat siirrettäviä pikanäppäinmerkkijonoja: kControl on Ctrl Windowsissa ja Linuxissa ja Komento (⌘) macOS:ssä, kAlt on Alt / Optio (⌥), kMeta on Windows-näppäin / Control (⌃) macOS:ssä. Laskostussarakkeen napsautukset laskostavat ja rivinumeroiden napsautukset valitsevat; kumpaakaan ei julkaista.

Oletuksena editori myös lisää tai poistaa kirjanmerkin napsautetulta riviltä, kuten aina ennenkin. Liitännäinen, joka antaa napsautukselle oman merkityksen — debuggeri, joka tavallisella napsautuksella lisää tai poistaa keskeytyskohdan ja muuntonäppäimen kanssa muokkaa sen ehtoa — varaa sen:

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

Niin kauan kuin vähintään yksi varaus on elossa — mistä tahansa liitännäisestä — editori jättää napsautuksen liitännäisille ja vain julkaisee tapahtuman; viimeisen tunnuksen tuhoaminen palauttaa kirjanmerkkien lisäämisen ja poistamisen. Tapahtuma julkaistaan, oli varausta tai ei, joten liitännäinen, joka vain seuraa napsautuksia, ei tarvitse varausta. Kirjanmerkkikomentoihin ja niiden pikanäppäimiin tämä ei vaikuta. Varaukset lasketaan, niitä ei aseteta jonoon: kaksi liitännäistä, jotka molemmat varaavat napsautuksen, saavat sen molemmat eivätkä saa molemmat reagoida siihen.

Python

Sama palvelu on ctx.line_markers Python-liitännäisille, ja napsautus on @ctx.events.on_margin_clicked.