Skip to content

Commit

Permalink
LibGUI: Move GTextDocument out of GTextEditor
Browse files Browse the repository at this point in the history
The idea here is to decouple the document from the editor widget so you
could have multiple editors being views onto the same document.

This doesn't work yet, since the document and editor are coupled in
various ways still (including a per-line back-pointer to the editor.)
  • Loading branch information
awesomekling committed Oct 27, 2019
1 parent 1bcbc3f commit f1c6193
Show file tree
Hide file tree
Showing 6 changed files with 303 additions and 241 deletions.
6 changes: 3 additions & 3 deletions DevTools/HackStudio/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -286,20 +286,20 @@ static void rehighlight()
CppLexer lexer(text);
auto tokens = lexer.lex();

Vector<GTextEditor::Span> spans;
Vector<GTextDocumentSpan> spans;
for (auto& token : tokens) {
#ifdef DEBUG_SYNTAX_HIGHLIGHTING
dbg() << token.to_string() << " @ " << token.m_start.line << ":" << token.m_start.column << " - " << token.m_end.line << ":" << token.m_end.column;
#endif
GTextEditor::Span span;
GTextDocumentSpan span;
span.range.set_start({ token.m_start.line, token.m_start.column });
span.range.set_end({ token.m_end.line, token.m_end.column });
auto style = style_for_token_type(token.m_type);
span.color = style.color;
span.font = style.font;
spans.append(span);
}
current_editor().set_spans(spans);
current_editor().document().set_spans(spans);
current_editor().update();
}

Expand Down
113 changes: 113 additions & 0 deletions Libraries/LibGUI/GTextDocument.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
#include <LibGUI/GTextDocument.h>
#include <ctype.h>

GTextDocument::GTextDocument(GTextEditor& editor)
: m_editor(editor)
{
m_lines.append(make<GTextDocumentLine>(m_editor));
}

void GTextDocument::set_text(const StringView& text)
{
m_spans.clear();
m_lines.clear();
int start_of_current_line = 0;

auto add_line = [&](int current_position) {
int line_length = current_position - start_of_current_line;
auto line = make<GTextDocumentLine>(m_editor);
if (line_length)
line->set_text(text.substring_view(start_of_current_line, current_position - start_of_current_line));
m_lines.append(move(line));
start_of_current_line = current_position + 1;
};
int i = 0;
for (i = 0; i < text.length(); ++i) {
if (text[i] == '\n')
add_line(i);
}
add_line(i);
}

int GTextDocumentLine::first_non_whitespace_column() const
{
for (int i = 0; i < length(); ++i) {
if (!isspace(m_text[i]))
return i;
}
return length();
}

GTextDocumentLine::GTextDocumentLine(GTextEditor& editor)
: m_editor(editor)
{
clear();
}

GTextDocumentLine::GTextDocumentLine(GTextEditor& editor, const StringView& text)
: m_editor(editor)
{
set_text(text);
}

void GTextDocumentLine::clear()
{
m_text.clear();
m_text.append(0);
}

void GTextDocumentLine::set_text(const StringView& text)
{
if (text.length() == length() && !memcmp(text.characters_without_null_termination(), characters(), length()))
return;
if (text.is_empty()) {
clear();
return;
}
m_text.resize(text.length() + 1);
memcpy(m_text.data(), text.characters_without_null_termination(), text.length() + 1);
}

void GTextDocumentLine::append(const char* characters, int length)
{
int old_length = m_text.size() - 1;
m_text.resize(m_text.size() + length);
memcpy(m_text.data() + old_length, characters, length);
m_text.last() = 0;
}

void GTextDocumentLine::append(char ch)
{
insert(length(), ch);
}

void GTextDocumentLine::prepend(char ch)
{
insert(0, ch);
}

void GTextDocumentLine::insert(int index, char ch)
{
if (index == length()) {
m_text.last() = ch;
m_text.append(0);
} else {
m_text.insert(index, move(ch));
}
}

void GTextDocumentLine::remove(int index)
{
if (index == length()) {
m_text.take_last();
m_text.last() = 0;
} else {
m_text.remove(index);
}
}

void GTextDocumentLine::truncate(int length)
{
m_text.resize(length + 1);
m_text.last() = 0;
}
83 changes: 83 additions & 0 deletions Libraries/LibGUI/GTextDocument.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#pragma once

#include <AK/NonnullOwnPtrVector.h>
#include <AK/NonnullRefPtr.h>
#include <AK/RefCounted.h>
#include <LibDraw/Color.h>
#include <LibDraw/Font.h>
#include <LibGUI/GTextRange.h>

class GTextEditor;
class GTextDocumentLine;

struct GTextDocumentSpan {
GTextRange range;
Color color;
const Font* font { nullptr };
};

class GTextDocument : public RefCounted<GTextDocument> {
public:
static NonnullRefPtr<GTextDocument> create(GTextEditor& editor)
{
return adopt(*new GTextDocument(editor));
}

int line_count() const { return m_lines.size(); }
const GTextDocumentLine& line(int line_index) const { return m_lines[line_index]; }
GTextDocumentLine& line(int line_index) { return m_lines[line_index]; }

void set_spans(const Vector<GTextDocumentSpan>& spans) { m_spans = spans; }

void set_text(const StringView&);

const NonnullOwnPtrVector<GTextDocumentLine>& lines() const { return m_lines; }
NonnullOwnPtrVector<GTextDocumentLine>& lines() { return m_lines; }

bool has_spans() const { return !m_spans.is_empty(); }
const Vector<GTextDocumentSpan>& spans() const { return m_spans; }

private:
explicit GTextDocument(GTextEditor&);

NonnullOwnPtrVector<GTextDocumentLine> m_lines;
Vector<GTextDocumentSpan> m_spans;

GTextEditor& m_editor;
};

class GTextDocumentLine {
friend class GTextEditor;
friend class GTextDocument;

public:
explicit GTextDocumentLine(GTextEditor&);
GTextDocumentLine(GTextEditor&, const StringView&);

StringView view() const { return { characters(), length() }; }
const char* characters() const { return m_text.data(); }
int length() const { return m_text.size() - 1; }
void set_text(const StringView&);
void append(char);
void prepend(char);
void insert(int index, char);
void remove(int index);
void append(const char*, int);
void truncate(int length);
void clear();
void recompute_visual_lines();
int visual_line_containing(int column) const;
int first_non_whitespace_column() const;

template<typename Callback>
void for_each_visual_line(Callback) const;

private:
GTextEditor& m_editor;

// NOTE: This vector is null terminated.
Vector<char> m_text;

Vector<int, 1> m_visual_line_breaks;
Rect m_visual_rect;
};
Loading

0 comments on commit f1c6193

Please sign in to comment.