diff options
Diffstat (limited to 'Userland/Libraries/LibJS')
-rw-r--r-- | Userland/Libraries/LibJS/SourceCode.cpp | 41 | ||||
-rw-r--r-- | Userland/Libraries/LibJS/SourceCode.h | 5 |
2 files changed, 43 insertions, 3 deletions
diff --git a/Userland/Libraries/LibJS/SourceCode.cpp b/Userland/Libraries/LibJS/SourceCode.cpp index 89a844f3e3..f0700a1c2d 100644 --- a/Userland/Libraries/LibJS/SourceCode.cpp +++ b/Userland/Libraries/LibJS/SourceCode.cpp @@ -4,6 +4,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include <AK/BinarySearch.h> #include <AK/Utf8View.h> #include <LibJS/SourceCode.h> #include <LibJS/SourceRange.h> @@ -32,18 +33,52 @@ String const& SourceCode::code() const return m_code; } +void SourceCode::compute_line_break_offsets() const +{ + m_line_break_offsets = Vector<size_t> {}; + + if (m_code.is_empty()) + return; + + bool previous_code_point_was_carriage_return = false; + Utf8View view(m_code.view()); + for (auto it = view.begin(); it != view.end(); ++it) { + u32 code_point = *it; + bool is_line_terminator = code_point == '\r' || (code_point == '\n' && !previous_code_point_was_carriage_return) || code_point == LINE_SEPARATOR || code_point == PARAGRAPH_SEPARATOR; + previous_code_point_was_carriage_return = code_point == '\r'; + + if (is_line_terminator) + m_line_break_offsets->append(view.byte_offset_of(it)); + } +} + SourceRange SourceCode::range_from_offsets(u32 start_offset, u32 end_offset) const { + if (m_code.is_empty()) + return { *this, {}, {} }; + + if (!m_line_break_offsets.has_value()) + compute_line_break_offsets(); + + size_t line = 1; + size_t nearest_line_break_index = 0; + size_t nearest_preceding_line_break_offset = 0; + + if (!m_line_break_offsets->is_empty()) { + binary_search(*m_line_break_offsets, start_offset, &nearest_line_break_index); + line = 1 + nearest_line_break_index; + nearest_preceding_line_break_offset = (*m_line_break_offsets)[nearest_line_break_index]; + } + Position start; Position end; - size_t line = 1; size_t column = 1; bool previous_code_point_was_carriage_return = false; - Utf8View view(m_code); - for (auto it = view.begin(); it != view.end(); ++it) { + Utf8View view(m_code.view()); + for (auto it = view.iterator_at_byte_offset_without_validation(nearest_preceding_line_break_offset); it != view.end(); ++it) { if (start_offset == view.byte_offset_of(it)) { start = Position { diff --git a/Userland/Libraries/LibJS/SourceCode.h b/Userland/Libraries/LibJS/SourceCode.h index 3980efed69..1550c50c89 100644 --- a/Userland/Libraries/LibJS/SourceCode.h +++ b/Userland/Libraries/LibJS/SourceCode.h @@ -7,6 +7,7 @@ #pragma once #include <AK/String.h> +#include <AK/Vector.h> #include <LibJS/Forward.h> namespace JS { @@ -23,8 +24,12 @@ public: private: SourceCode(String filename, String code); + void compute_line_break_offsets() const; + String m_filename; String m_code; + + Optional<Vector<size_t>> mutable m_line_break_offsets; }; } |