2009-04-24 23:35:41 +00:00
|
|
|
/** @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>
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
#include <stdexcept>
|
|
|
|
#include <string_view>
|
|
|
|
#include <vector>
|
2022-01-04 23:07:50 +00:00
|
|
|
#include <optional>
|
2013-08-28 00:44:27 +00:00
|
|
|
#include <algorithm>
|
2019-05-04 18:14:48 +00:00
|
|
|
#include <memory>
|
2013-08-28 00:44:27 +00:00
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
#include "ScintillaTypes.h"
|
|
|
|
|
|
|
|
#include "Debugging.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
#include "Position.h"
|
2009-04-24 23:35:41 +00:00
|
|
|
#include "SplitVector.h"
|
|
|
|
#include "Partitioning.h"
|
|
|
|
#include "RunStyles.h"
|
|
|
|
#include "Decoration.h"
|
|
|
|
|
2022-01-04 23:07:50 +00:00
|
|
|
using namespace Scintilla::Internal;
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
namespace {
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
|
|
|
class Decoration : public IDecoration {
|
|
|
|
int indicator;
|
|
|
|
public:
|
|
|
|
RunStyles<POS, int> rs;
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
explicit Decoration(int indicator_) : indicator(indicator_) {
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
bool Empty() const noexcept override {
|
2019-05-04 18:14:48 +00:00
|
|
|
return (rs.Runs() == 1) && (rs.AllSameAs(0));
|
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
int Indicator() const noexcept override {
|
2019-05-04 18:14:48 +00:00
|
|
|
return indicator;
|
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
Sci::Position Length() const noexcept override {
|
2019-05-04 18:14:48 +00:00
|
|
|
return rs.Length();
|
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
int ValueAt(Sci::Position position) const noexcept override {
|
2019-05-04 18:14:48 +00:00
|
|
|
return rs.ValueAt(static_cast<POS>(position));
|
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
Sci::Position StartRun(Sci::Position position) const noexcept override {
|
2019-05-04 18:14:48 +00:00
|
|
|
return rs.StartRun(static_cast<POS>(position));
|
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
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));
|
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
Sci::Position Runs() const noexcept override {
|
2019-05-04 18:14:48 +00:00
|
|
|
return rs.Runs();
|
|
|
|
}
|
|
|
|
};
|
2009-04-24 23:35:41 +00:00
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
|
|
|
class DecorationList : public IDecorationList {
|
|
|
|
int currentIndicator;
|
|
|
|
int currentValue;
|
2022-01-04 23:07:50 +00:00
|
|
|
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;
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
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();
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
const std::vector<const IDecoration*> &View() const noexcept override {
|
2019-05-04 18:14:48 +00:00
|
|
|
return decorationView;
|
|
|
|
}
|
|
|
|
|
|
|
|
void SetCurrentIndicator(int indicator) override;
|
2021-02-21 04:53:09 +00:00
|
|
|
int GetCurrentIndicator() const noexcept override { return currentIndicator; }
|
2019-05-04 18:14:48 +00:00
|
|
|
|
|
|
|
void SetCurrentValue(int value) override;
|
2021-02-21 04:53:09 +00:00
|
|
|
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;
|
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
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
|
|
|
|
2021-02-21 04:53:09 +00:00
|
|
|
bool ClickNotified() const noexcept override {
|
2019-05-04 18:14:48 +00:00
|
|
|
return clickNotified;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
2021-02-21 04:53:09 +00:00
|
|
|
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>
|
2021-02-21 04:53:09 +00:00
|
|
|
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();
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
return nullptr;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
|
|
|
Decoration<POS> *DecorationList<POS>::Create(int indicator, Sci::Position length) {
|
2009-04-24 23:35:41 +00:00
|
|
|
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));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
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,
|
2021-02-21 04:53:09 +00:00
|
|
|
[](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));
|
2009-04-24 23:35:41 +00:00
|
|
|
|
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(),
|
2021-02-21 04:53:09 +00:00
|
|
|
[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();
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
|
|
|
void DecorationList<POS>::SetCurrentIndicator(int indicator) {
|
2009-04-24 23:35:41 +00:00
|
|
|
currentIndicator = indicator;
|
|
|
|
current = DecorationFromIndicator(indicator);
|
|
|
|
currentValue = 1;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
|
|
|
void DecorationList<POS>::SetCurrentValue(int value) {
|
2009-04-24 23:35:41 +00:00
|
|
|
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) {
|
2009-04-24 23:35:41 +00:00
|
|
|
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()) {
|
2009-04-24 23:35:41 +00:00
|
|
|
Delete(currentIndicator);
|
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
return fr;
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
|
|
|
void DecorationList<POS>::InsertSpace(Sci::Position position, Sci::Position insertLength) {
|
2013-08-28 00:44:27 +00:00
|
|
|
const bool atEnd = position == lengthDocument;
|
2009-04-24 23:35:41 +00:00
|
|
|
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));
|
2013-08-28 00:44:27 +00:00
|
|
|
if (atEnd) {
|
2019-05-04 18:14:48 +00:00
|
|
|
deco->rs.FillRange(static_cast<POS>(position), 0, static_cast<POS>(insertLength));
|
2013-08-28 00:44:27 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
|
|
|
void DecorationList<POS>::DeleteRange(Sci::Position position, Sci::Position deleteLength) {
|
2009-04-24 23:35:41 +00:00
|
|
|
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));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
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();
|
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
|
|
|
void DecorationList<POS>::DeleteLexerDecorations() {
|
|
|
|
decorationList.erase(std::remove_if(decorationList.begin(), decorationList.end(),
|
2021-02-21 04:53:09 +00:00
|
|
|
[](const std::unique_ptr<Decoration<POS>> &deco) noexcept {
|
2022-01-04 23:07:50 +00:00
|
|
|
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(),
|
2021-02-21 04:53:09 +00:00
|
|
|
[](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());
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
2021-02-21 04:53:09 +00:00
|
|
|
int DecorationList<POS>::AllOnFor(Sci::Position position) const noexcept {
|
2009-04-24 23:35:41 +00:00
|
|
|
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))) {
|
2022-01-04 23:07:50 +00:00
|
|
|
if (deco->Indicator() < static_cast<int>(Scintilla::IndicatorNumbers::Ime)) {
|
|
|
|
mask |= 1u << deco->Indicator();
|
2015-06-07 21:19:26 +00:00
|
|
|
}
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return mask;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
2021-02-21 04:53:09 +00:00
|
|
|
int DecorationList<POS>::ValueAt(int indicator, Sci::Position position) noexcept {
|
2019-05-04 18:14:48 +00:00
|
|
|
const Decoration<POS> *deco = DecorationFromIndicator(indicator);
|
2009-04-24 23:35:41 +00:00
|
|
|
if (deco) {
|
2019-05-04 18:14:48 +00:00
|
|
|
return deco->rs.ValueAt(static_cast<POS>(position));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
2021-02-21 04:53:09 +00:00
|
|
|
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);
|
2009-04-24 23:35:41 +00:00
|
|
|
if (deco) {
|
2019-05-04 18:14:48 +00:00
|
|
|
return deco->rs.StartRun(static_cast<POS>(position));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-05-04 18:14:48 +00:00
|
|
|
template <typename POS>
|
2021-02-21 04:53:09 +00:00
|
|
|
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);
|
2009-04-24 23:35:41 +00:00
|
|
|
if (deco) {
|
2019-05-04 18:14:48 +00:00
|
|
|
return deco->rs.EndRun(static_cast<POS>(position));
|
2009-04-24 23:35:41 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2019-05-04 18:14:48 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-01-04 23:07:50 +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>>();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|