notepad-plus-plus/scintilla/src/Decoration.cxx

312 lines
9.7 KiB
C++
Raw Normal View History

/** @file Decoration.cxx
** Visual elements added over text.
**/
// Copyright 1998-2007 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.
2019-05-04 18:14:48 +00:00
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cstdarg>
2019-05-04 18:14:48 +00:00
#include <stdexcept>
#include <string_view>
#include <vector>
#include <optional>
#include <algorithm>
2019-05-04 18:14:48 +00:00
#include <memory>
#include "ScintillaTypes.h"
#include "Debugging.h"
2019-05-04 18:14:48 +00:00
#include "Position.h"
#include "SplitVector.h"
#include "Partitioning.h"
#include "RunStyles.h"
#include "Decoration.h"
using namespace Scintilla::Internal;
2019-05-04 18:14:48 +00:00
namespace {
2019-05-04 18:14:48 +00:00
template <typename POS>
class Decoration : public IDecoration {
int indicator;
public:
RunStyles<POS, int> rs;
2019-05-04 18:14:48 +00:00
explicit Decoration(int indicator_) : indicator(indicator_) {
}
bool Empty() const noexcept override {
2019-05-04 18:14:48 +00:00
return (rs.Runs() == 1) && (rs.AllSameAs(0));
}
int Indicator() const noexcept override {
2019-05-04 18:14:48 +00:00
return indicator;
}
Sci::Position Length() const noexcept override {
2019-05-04 18:14:48 +00:00
return rs.Length();
}
int ValueAt(Sci::Position position) const noexcept override {
2019-05-04 18:14:48 +00:00
return rs.ValueAt(static_cast<POS>(position));
}
Sci::Position StartRun(Sci::Position position) const noexcept override {
2019-05-04 18:14:48 +00:00
return rs.StartRun(static_cast<POS>(position));
}
Sci::Position EndRun(Sci::Position position) const noexcept override {
2019-05-04 18:14:48 +00:00
return rs.EndRun(static_cast<POS>(position));
}
void SetValueAt(Sci::Position position, int value) override {
rs.SetValueAt(static_cast<POS>(position), value);
}
void InsertSpace(Sci::Position position, Sci::Position insertLength) override {
rs.InsertSpace(static_cast<POS>(position), static_cast<POS>(insertLength));
}
Sci::Position Runs() const noexcept override {
2019-05-04 18:14:48 +00:00
return rs.Runs();
}
};
2019-05-04 18:14:48 +00:00
template <typename POS>
class DecorationList : public IDecorationList {
int currentIndicator;
int currentValue;
Decoration<POS> *current; // Non-owning. Cached so FillRange doesn't have to search for each call.
2019-05-04 18:14:48 +00:00
Sci::Position lengthDocument;
// Ordered by indicator
std::vector<std::unique_ptr<Decoration<POS>>> decorationList;
std::vector<const IDecoration*> decorationView; // Read-only view of decorationList
bool clickNotified;
Decoration<POS> *DecorationFromIndicator(int indicator) noexcept;
2019-05-04 18:14:48 +00:00
Decoration<POS> *Create(int indicator, Sci::Position length);
void Delete(int indicator);
void DeleteAnyEmpty();
void SetView();
public:
DecorationList();
const std::vector<const IDecoration*> &View() const noexcept override {
2019-05-04 18:14:48 +00:00
return decorationView;
}
void SetCurrentIndicator(int indicator) override;
int GetCurrentIndicator() const noexcept override { return currentIndicator; }
2019-05-04 18:14:48 +00:00
void SetCurrentValue(int value) override;
int GetCurrentValue() const noexcept override { return currentValue; }
2019-05-04 18:14:48 +00:00
// Returns changed=true if some values may have changed
FillResult<Sci::Position> FillRange(Sci::Position position, int value, Sci::Position fillLength) override;
void InsertSpace(Sci::Position position, Sci::Position insertLength) override;
void DeleteRange(Sci::Position position, Sci::Position deleteLength) override;
void DeleteLexerDecorations() override;
int AllOnFor(Sci::Position position) const noexcept override;
int ValueAt(int indicator, Sci::Position position) noexcept override;
Sci::Position Start(int indicator, Sci::Position position) noexcept override;
Sci::Position End(int indicator, Sci::Position position) noexcept override;
2019-05-04 18:14:48 +00:00
bool ClickNotified() const noexcept override {
2019-05-04 18:14:48 +00:00
return clickNotified;
}
void SetClickNotified(bool notified) noexcept override {
2019-05-04 18:14:48 +00:00
clickNotified = notified;
}
};
template <typename POS>
DecorationList<POS>::DecorationList() : currentIndicator(0), currentValue(1), current(nullptr),
lengthDocument(0), clickNotified(false) {
}
template <typename POS>
Decoration<POS> *DecorationList<POS>::DecorationFromIndicator(int indicator) noexcept {
2019-05-04 18:14:48 +00:00
for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
if (deco->Indicator() == indicator) {
return deco.get();
}
}
2019-05-04 18:14:48 +00:00
return nullptr;
}
2019-05-04 18:14:48 +00:00
template <typename POS>
Decoration<POS> *DecorationList<POS>::Create(int indicator, Sci::Position length) {
currentIndicator = indicator;
2019-05-04 18:14:48 +00:00
std::unique_ptr<Decoration<POS>> decoNew = std::make_unique<Decoration<POS>>(indicator);
decoNew->rs.InsertSpace(0, static_cast<POS>(length));
2019-05-04 18:14:48 +00:00
typename std::vector<std::unique_ptr<Decoration<POS>>>::iterator it = std::lower_bound(
decorationList.begin(), decorationList.end(), decoNew,
[](const std::unique_ptr<Decoration<POS>> &a, const std::unique_ptr<Decoration<POS>> &b) noexcept {
2019-05-04 18:14:48 +00:00
return a->Indicator() < b->Indicator();
});
typename std::vector<std::unique_ptr<Decoration<POS>>>::iterator itAdded =
decorationList.insert(it, std::move(decoNew));
2019-05-04 18:14:48 +00:00
SetView();
return itAdded->get();
}
template <typename POS>
void DecorationList<POS>::Delete(int indicator) {
decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(),
[indicator](const std::unique_ptr<Decoration<POS>> &deco) noexcept {
2019-05-04 18:14:48 +00:00
return deco->Indicator() == indicator;
}), decorationList.end());
current = nullptr;
SetView();
}
2019-05-04 18:14:48 +00:00
template <typename POS>
void DecorationList<POS>::SetCurrentIndicator(int indicator) {
currentIndicator = indicator;
current = DecorationFromIndicator(indicator);
currentValue = 1;
}
2019-05-04 18:14:48 +00:00
template <typename POS>
void DecorationList<POS>::SetCurrentValue(int value) {
currentValue = value ? value : 1;
}
2019-05-04 18:14:48 +00:00
template <typename POS>
FillResult<Sci::Position> DecorationList<POS>::FillRange(Sci::Position position, int value, Sci::Position fillLength) {
if (!current) {
current = DecorationFromIndicator(currentIndicator);
if (!current) {
current = Create(currentIndicator, lengthDocument);
}
}
2019-05-04 18:14:48 +00:00
// Converting result from POS to Sci::Position as callers not polymorphic.
const FillResult<POS> frInPOS = current->rs.FillRange(static_cast<POS>(position), value, static_cast<POS>(fillLength));
const FillResult<Sci::Position> fr { frInPOS.changed, frInPOS.position, frInPOS.fillLength };
if (current->Empty()) {
Delete(currentIndicator);
}
2019-05-04 18:14:48 +00:00
return fr;
}
2019-05-04 18:14:48 +00:00
template <typename POS>
void DecorationList<POS>::InsertSpace(Sci::Position position, Sci::Position insertLength) {
const bool atEnd = position == lengthDocument;
lengthDocument += insertLength;
2019-05-04 18:14:48 +00:00
for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
deco->rs.InsertSpace(static_cast<POS>(position), static_cast<POS>(insertLength));
if (atEnd) {
2019-05-04 18:14:48 +00:00
deco->rs.FillRange(static_cast<POS>(position), 0, static_cast<POS>(insertLength));
}
}
}
2019-05-04 18:14:48 +00:00
template <typename POS>
void DecorationList<POS>::DeleteRange(Sci::Position position, Sci::Position deleteLength) {
lengthDocument -= deleteLength;
2019-05-04 18:14:48 +00:00
for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
deco->rs.DeleteRange(static_cast<POS>(position), static_cast<POS>(deleteLength));
}
DeleteAnyEmpty();
2019-05-04 18:14:48 +00:00
if (decorationList.size() != decorationView.size()) {
// One or more empty decorations deleted so update view.
current = nullptr;
SetView();
}
}
2019-05-04 18:14:48 +00:00
template <typename POS>
void DecorationList<POS>::DeleteLexerDecorations() {
decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(),
[](const std::unique_ptr<Decoration<POS>> &deco) noexcept {
return deco->Indicator() < static_cast<int>(Scintilla::IndicatorNumbers::Container);
2019-05-04 18:14:48 +00:00
}), decorationList.end());
current = nullptr;
SetView();
}
template <typename POS>
void DecorationList<POS>::DeleteAnyEmpty() {
if (lengthDocument == 0) {
decorationList.clear();
} else {
decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(),
[](const std::unique_ptr<Decoration<POS>> &deco) noexcept {
2019-05-04 18:14:48 +00:00
return deco->Empty();
}), decorationList.end());
}
}
template <typename POS>
void DecorationList<POS>::SetView() {
decorationView.clear();
for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
decorationView.push_back(deco.get());
}
}
2019-05-04 18:14:48 +00:00
template <typename POS>
int DecorationList<POS>::AllOnFor(Sci::Position position) const noexcept {
int mask = 0;
2019-05-04 18:14:48 +00:00
for (const std::unique_ptr<Decoration<POS>> &deco : decorationList) {
if (deco->rs.ValueAt(static_cast<POS>(position))) {
if (deco->Indicator() < static_cast<int>(Scintilla::IndicatorNumbers::Ime)) {
mask |= 1u << deco->Indicator();
}
}
}
return mask;
}
2019-05-04 18:14:48 +00:00
template <typename POS>
int DecorationList<POS>::ValueAt(int indicator, Sci::Position position) noexcept {
2019-05-04 18:14:48 +00:00
const Decoration<POS> *deco = DecorationFromIndicator(indicator);
if (deco) {
2019-05-04 18:14:48 +00:00
return deco->rs.ValueAt(static_cast<POS>(position));
}
return 0;
}
2019-05-04 18:14:48 +00:00
template <typename POS>
Sci::Position DecorationList<POS>::Start(int indicator, Sci::Position position) noexcept {
2019-05-04 18:14:48 +00:00
const Decoration<POS> *deco = DecorationFromIndicator(indicator);
if (deco) {
2019-05-04 18:14:48 +00:00
return deco->rs.StartRun(static_cast<POS>(position));
}
return 0;
}
2019-05-04 18:14:48 +00:00
template <typename POS>
Sci::Position DecorationList<POS>::End(int indicator, Sci::Position position) noexcept {
2019-05-04 18:14:48 +00:00
const Decoration<POS> *deco = DecorationFromIndicator(indicator);
if (deco) {
2019-05-04 18:14:48 +00:00
return deco->rs.EndRun(static_cast<POS>(position));
}
return 0;
}
2019-05-04 18:14:48 +00:00
}
namespace Scintilla::Internal {
2019-05-04 18:14:48 +00:00
std::unique_ptr<IDecoration> DecorationCreate(bool largeDocument, int indicator) {
if (largeDocument)
return std::make_unique<Decoration<Sci::Position>>(indicator);
else
return std::make_unique<Decoration<int>>(indicator);
}
std::unique_ptr<IDecorationList> DecorationListCreate(bool largeDocument) {
if (largeDocument)
return std::make_unique<DecorationList<Sci::Position>>();
else
return std::make_unique<DecorationList<int>>();
}
}