mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 23:47:45 +00:00
LibGUI: INI file syntax highlighter
This commit is contained in:
parent
5267ccbc22
commit
5c022ac939
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 \
|
Icon.o \
|
||||||
InputBox.o \
|
InputBox.o \
|
||||||
ItemView.o \
|
ItemView.o \
|
||||||
|
INILexer.o \
|
||||||
|
INISyntaxHighlighter.o \
|
||||||
JsonArrayModel.o \
|
JsonArrayModel.o \
|
||||||
JSSyntaxHighlighter.o \
|
JSSyntaxHighlighter.o \
|
||||||
Label.o \
|
Label.o \
|
||||||
|
|
|
@ -36,7 +36,8 @@ namespace GUI {
|
||||||
enum class SyntaxLanguage {
|
enum class SyntaxLanguage {
|
||||||
PlainText,
|
PlainText,
|
||||||
Cpp,
|
Cpp,
|
||||||
Javascript
|
Javascript,
|
||||||
|
INI
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TextStyle {
|
struct TextStyle {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue