Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * Copyright (c) 2022, the SerenityOS developers.
4 *
5 * SPDX-License-Identifier: BSD-2-Clause
6 */
7
8#pragma once
9
10#include <LibGUI/TextPosition.h>
11
12namespace GUI {
13
14class TextRange {
15public:
16 TextRange() = default;
17 TextRange(TextPosition const& start, TextPosition const& end)
18 : m_start(start)
19 , m_end(end)
20 {
21 }
22
23 bool is_valid() const { return m_start.is_valid() && m_end.is_valid() && m_start != m_end; }
24 void clear()
25 {
26 m_start = {};
27 m_end = {};
28 }
29
30 TextPosition& start() { return m_start; }
31 TextPosition& end() { return m_end; }
32 TextPosition const& start() const { return m_start; }
33 TextPosition const& end() const { return m_end; }
34
35 size_t line_count() const { return normalized_end().line() - normalized_start().line() + 1; }
36
37 TextRange normalized() const { return TextRange(normalized_start(), normalized_end()); }
38
39 void set_start(TextPosition const& position) { m_start = position; }
40 void set_end(TextPosition const& position) { m_end = position; }
41
42 void set(TextPosition const& start, TextPosition const& end)
43 {
44 m_start = start;
45 m_end = end;
46 }
47
48 bool operator==(TextRange const& other) const
49 {
50 return m_start == other.m_start && m_end == other.m_end;
51 }
52
53 bool contains(TextPosition const& position) const
54 {
55 if (!(position.line() > m_start.line() || (position.line() == m_start.line() && position.column() >= m_start.column())))
56 return false;
57 if (!(position.line() < m_end.line() || (position.line() == m_end.line() && position.column() <= m_end.column())))
58 return false;
59 return true;
60 }
61
62private:
63 TextPosition normalized_start() const { return m_start < m_end ? m_start : m_end; }
64 TextPosition normalized_end() const { return m_start < m_end ? m_end : m_start; }
65
66 TextPosition m_start {};
67 TextPosition m_end {};
68};
69
70}
71
72template<>
73struct AK::Formatter<GUI::TextRange> : AK::Formatter<FormatString> {
74 ErrorOr<void> format(FormatBuilder& builder, GUI::TextRange const& value)
75 {
76 if (value.is_valid())
77 return Formatter<FormatString>::format(builder, "{}-{}"sv, value.start(), value.end());
78 return builder.put_string("GUI::TextRange(Invalid)"sv);
79 }
80};