mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-04 05:20:30 +00:00
LibGUI: INI file syntax highlighter
This commit is contained in:
parent
5267ccbc22
commit
5c022ac939
Notes:
sideshowbarker
2024-07-19 07:08:01 +09:00
Author: https://github.com/asliturk Commit: https://github.com/SerenityOS/serenity/commit/5c022ac9392 Pull-request: https://github.com/SerenityOS/serenity/pull/2035
6 changed files with 407 additions and 1 deletions
160
Libraries/LibGUI/INILexer.cpp
Normal file
160
Libraries/LibGUI/INILexer.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "INILexer.h"
|
||||
#include <AK/Vector.h>
|
||||
#include <ctype.h>
|
||||
|
||||
namespace GUI {
|
||||
|
||||
IniLexer::IniLexer(const StringView& input)
|
||||
: m_input(input)
|
||||
{
|
||||
}
|
||||
|
||||
char IniLexer::peek(size_t offset) const
|
||||
{
|
||||
if ((m_index + offset) >= m_input.length())
|
||||
return 0;
|
||||
return m_input[m_index + offset];
|
||||
}
|
||||
|
||||
char IniLexer::consume()
|
||||
{
|
||||
ASSERT(m_index < m_input.length());
|
||||
char ch = m_input[m_index++];
|
||||
m_previous_position = m_position;
|
||||
if (ch == '\n') {
|
||||
m_position.line++;
|
||||
m_position.column = 0;
|
||||
} else {
|
||||
m_position.column++;
|
||||
}
|
||||
return ch;
|
||||
}
|
||||
|
||||
Vector<IniToken> IniLexer::lex()
|
||||
{
|
||||
Vector<IniToken> tokens;
|
||||
|
||||
size_t token_start_index = 0;
|
||||
IniPosition token_start_position;
|
||||
|
||||
auto emit_token = [&](auto type) {
|
||||
IniToken token;
|
||||
token.m_type = type;
|
||||
token.m_start = m_position;
|
||||
token.m_end = m_position;
|
||||
tokens.append(token);
|
||||
consume();
|
||||
};
|
||||
|
||||
auto begin_token = [&] {
|
||||
token_start_index = m_index;
|
||||
token_start_position = m_position;
|
||||
};
|
||||
|
||||
auto commit_token = [&](auto type) {
|
||||
IniToken token;
|
||||
token.m_type = type;
|
||||
token.m_start = token_start_position;
|
||||
token.m_end = m_previous_position;
|
||||
tokens.append(token);
|
||||
};
|
||||
|
||||
while (m_index < m_input.length()) {
|
||||
auto ch = peek();
|
||||
|
||||
if (isspace(ch)) {
|
||||
begin_token();
|
||||
while (isspace(peek()))
|
||||
consume();
|
||||
commit_token(IniToken::Type::Whitespace);
|
||||
continue;
|
||||
}
|
||||
|
||||
// ;Comment
|
||||
if (ch == ';') {
|
||||
begin_token();
|
||||
while (peek() && peek() != '\n')
|
||||
consume();
|
||||
commit_token(IniToken::Type::Comment);
|
||||
continue;
|
||||
}
|
||||
|
||||
// [Section]
|
||||
if (ch == '[') {
|
||||
// [ Token
|
||||
begin_token();
|
||||
consume();
|
||||
commit_token(IniToken::Type::LeftBracket);
|
||||
|
||||
// Section
|
||||
begin_token();
|
||||
while (peek() && !(peek() == ']' || peek() == '\n'))
|
||||
consume();
|
||||
commit_token(IniToken::Type::section);
|
||||
|
||||
// ] Token
|
||||
if (peek() && peek() == ']') {
|
||||
begin_token();
|
||||
consume();
|
||||
commit_token(IniToken::Type::RightBracket);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Empty Line
|
||||
if (ch == '\n') {
|
||||
consume();
|
||||
emit_token(IniToken::Type::Unknown);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Name=Value
|
||||
begin_token();
|
||||
while (peek() && !(peek() == '=' || peek() == '\n'))
|
||||
consume();
|
||||
commit_token(IniToken::Type::Name);
|
||||
|
||||
if (peek() && peek() == '=') {
|
||||
begin_token();
|
||||
consume();
|
||||
commit_token(IniToken::Type::Equal);
|
||||
}
|
||||
|
||||
if (peek()) {
|
||||
begin_token();
|
||||
while (peek() && peek() != '\n')
|
||||
consume();
|
||||
commit_token(IniToken::Type::Value);
|
||||
}
|
||||
}
|
||||
return tokens;
|
||||
}
|
||||
|
||||
}
|
89
Libraries/LibGUI/INILexer.h
Normal file
89
Libraries/LibGUI/INILexer.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/StringView.h>
|
||||
|
||||
namespace GUI {
|
||||
|
||||
#define FOR_EACH_TOKEN_TYPE \
|
||||
__TOKEN(Unknown) \
|
||||
__TOKEN(Comment) \
|
||||
__TOKEN(Whitespace) \
|
||||
__TOKEN(section) \
|
||||
__TOKEN(LeftBracket) \
|
||||
__TOKEN(RightBracket) \
|
||||
__TOKEN(Name) \
|
||||
__TOKEN(Value) \
|
||||
__TOKEN(Equal)
|
||||
|
||||
struct IniPosition {
|
||||
size_t line;
|
||||
size_t column;
|
||||
};
|
||||
|
||||
struct IniToken {
|
||||
enum class Type {
|
||||
#define __TOKEN(x) x,
|
||||
FOR_EACH_TOKEN_TYPE
|
||||
#undef __TOKEN
|
||||
};
|
||||
|
||||
const char* to_string() const
|
||||
{
|
||||
switch (m_type) {
|
||||
#define __TOKEN(x) \
|
||||
case Type::x: \
|
||||
return #x;
|
||||
FOR_EACH_TOKEN_TYPE
|
||||
#undef __TOKEN
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
Type m_type { Type::Unknown };
|
||||
IniPosition m_start;
|
||||
IniPosition m_end;
|
||||
};
|
||||
|
||||
class IniLexer {
|
||||
public:
|
||||
IniLexer(const StringView&);
|
||||
|
||||
Vector<IniToken> lex();
|
||||
|
||||
private:
|
||||
char peek(size_t offset = 0) const;
|
||||
char consume();
|
||||
|
||||
StringView m_input;
|
||||
size_t m_index { 0 };
|
||||
IniPosition m_previous_position { 0, 0 };
|
||||
IniPosition m_position { 0, 0 };
|
||||
};
|
||||
|
||||
}
|
106
Libraries/LibGUI/INISyntaxHighlighter.cpp
Normal file
106
Libraries/LibGUI/INISyntaxHighlighter.cpp
Normal file
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <LibGUI/INILexer.h>
|
||||
#include <LibGUI/INISyntaxHighlighter.h>
|
||||
#include <LibGUI/TextEditor.h>
|
||||
#include <LibGfx/Font.h>
|
||||
#include <LibGfx/Palette.h>
|
||||
|
||||
namespace GUI {
|
||||
|
||||
static TextStyle style_for_token_type(Gfx::Palette palette, IniToken::Type type)
|
||||
{
|
||||
switch (type) {
|
||||
case IniToken::Type::LeftBracket:
|
||||
case IniToken::Type::RightBracket:
|
||||
case IniToken::Type::section:
|
||||
return { palette.syntax_keyword(), &Gfx::Font::default_bold_fixed_width_font() };
|
||||
case IniToken::Type::Name:
|
||||
return { palette.syntax_identifier() };
|
||||
case IniToken::Type::Value:
|
||||
return { palette.syntax_string() };
|
||||
case IniToken::Type::Comment:
|
||||
return { palette.syntax_comment() };
|
||||
case IniToken::Type::Equal:
|
||||
return { palette.syntax_operator(), &Gfx::Font::default_bold_fixed_width_font() };
|
||||
default:
|
||||
return { palette.base_text() };
|
||||
}
|
||||
}
|
||||
|
||||
bool IniSyntaxHighlighter::is_identifier(void* token) const
|
||||
{
|
||||
auto ini_token = static_cast<GUI::IniToken::Type>(reinterpret_cast<size_t>(token));
|
||||
return ini_token == GUI::IniToken::Type::Name;
|
||||
}
|
||||
|
||||
void IniSyntaxHighlighter::rehighlight(Gfx::Palette palette)
|
||||
{
|
||||
ASSERT(m_editor);
|
||||
auto text = m_editor->text();
|
||||
IniLexer lexer(text);
|
||||
auto tokens = lexer.lex();
|
||||
|
||||
Vector<GUI::TextDocumentSpan> spans;
|
||||
for (auto& token : tokens) {
|
||||
GUI::TextDocumentSpan 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(palette, token.m_type);
|
||||
span.color = style.color;
|
||||
span.font = style.font;
|
||||
span.is_skippable = token.m_type == IniToken::Type::Whitespace;
|
||||
span.data = reinterpret_cast<void*>(token.m_type);
|
||||
spans.append(span);
|
||||
}
|
||||
m_editor->document().set_spans(spans);
|
||||
|
||||
m_has_brace_buddies = false;
|
||||
highlight_matching_token_pair();
|
||||
|
||||
m_editor->update();
|
||||
}
|
||||
|
||||
Vector<IniSyntaxHighlighter::MatchingTokenPair> IniSyntaxHighlighter::matching_token_pairs() const
|
||||
{
|
||||
static Vector<SyntaxHighlighter::MatchingTokenPair> pairs;
|
||||
if (pairs.is_empty()) {
|
||||
pairs.append({ reinterpret_cast<void*>(IniToken::Type::LeftBracket), reinterpret_cast<void*>(IniToken::Type::RightBracket) });
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
bool IniSyntaxHighlighter::token_types_equal(void* token1, void* token2) const
|
||||
{
|
||||
return static_cast<GUI::IniToken::Type>(reinterpret_cast<size_t>(token1)) == static_cast<GUI::IniToken::Type>(reinterpret_cast<size_t>(token2));
|
||||
}
|
||||
|
||||
IniSyntaxHighlighter::~IniSyntaxHighlighter()
|
||||
{
|
||||
}
|
||||
|
||||
}
|
48
Libraries/LibGUI/INISyntaxHighlighter.h
Normal file
48
Libraries/LibGUI/INISyntaxHighlighter.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <LibGUI/SyntaxHighlighter.h>
|
||||
|
||||
namespace GUI {
|
||||
|
||||
class IniSyntaxHighlighter final : public SyntaxHighlighter {
|
||||
public:
|
||||
IniSyntaxHighlighter() {}
|
||||
virtual ~IniSyntaxHighlighter() override;
|
||||
|
||||
virtual bool is_identifier(void*) const override;
|
||||
|
||||
virtual SyntaxLanguage language() const override { return SyntaxLanguage::INI; }
|
||||
virtual void rehighlight(Gfx::Palette) override;
|
||||
|
||||
protected:
|
||||
virtual Vector<MatchingTokenPair> matching_token_pairs() const override;
|
||||
virtual bool token_types_equal(void*, void*) const override;
|
||||
};
|
||||
|
||||
}
|
|
@ -30,6 +30,8 @@ OBJS = \
|
|||
Icon.o \
|
||||
InputBox.o \
|
||||
ItemView.o \
|
||||
INILexer.o \
|
||||
INISyntaxHighlighter.o \
|
||||
JsonArrayModel.o \
|
||||
JSSyntaxHighlighter.o \
|
||||
Label.o \
|
||||
|
|
|
@ -36,7 +36,8 @@ namespace GUI {
|
|||
enum class SyntaxLanguage {
|
||||
PlainText,
|
||||
Cpp,
|
||||
Javascript
|
||||
Javascript,
|
||||
INI
|
||||
};
|
||||
|
||||
struct TextStyle {
|
||||
|
|
Loading…
Reference in a new issue