2022-02-06 23:02:34 +02:00
/*
* Copyright ( c ) 2022 , Itamar S . < itamar8910 @ gmail . com >
* Copyright ( c ) 2022 , the SerenityOS developers .
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
# include "SemanticSyntaxHighlighter.h"
# include "Lexer.h"
# include <LibDiff/Generator.h>
# include <LibGUI/AutocompleteProvider.h>
# include <LibGfx/Palette.h>
namespace Cpp {
void SemanticSyntaxHighlighter : : rehighlight ( Palette const & palette )
{
2022-05-14 17:09:24 +03:00
Vector < CodeComprehension : : TokenInfo > new_tokens_info ;
2022-02-06 23:02:34 +02:00
auto text = m_client - > get_text ( ) ;
{
Threading : : MutexLocker locker ( m_lock ) ;
Cpp : : Lexer lexer ( text ) ;
lexer . set_ignore_whitespace ( true ) ;
auto current_tokens = lexer . lex ( ) ;
StringBuilder current_tokens_as_lines ;
StringBuilder previous_tokens_as_lines ;
for ( auto & token : current_tokens )
current_tokens_as_lines . appendff ( " {} \n " , token . type_as_string ( ) ) ;
for ( Cpp : : Token const & token : m_saved_tokens )
previous_tokens_as_lines . appendff ( " {} \n " , token . type_as_string ( ) ) ;
auto previous = previous_tokens_as_lines . build ( ) ;
auto current = current_tokens_as_lines . build ( ) ;
// FIXME: Computing the diff on the entire document's tokens is quite inefficient.
// An improvement over this could be only including the tokens that are in edited text ranges in the diff.
auto diff_hunks = Diff : : from_text ( previous . view ( ) , current . view ( ) ) ;
for ( auto & token : current_tokens ) {
2022-05-14 17:09:24 +03:00
new_tokens_info . append ( CodeComprehension : : TokenInfo { CodeComprehension : : TokenInfo : : SemanticType : : Unknown ,
2022-02-06 23:02:34 +02:00
token . start ( ) . line , token . start ( ) . column , token . end ( ) . line , token . end ( ) . column } ) ;
}
size_t previous_token_index = 0 ;
size_t current_token_index = 0 ;
for ( auto const & hunk : diff_hunks ) {
for ( ; previous_token_index < hunk . original_start_line ; + + previous_token_index ) {
new_tokens_info [ current_token_index ] . type = m_tokens_info [ previous_token_index ] . type ;
+ + current_token_index ;
}
for ( size_t i = 0 ; i < hunk . added_lines . size ( ) ; + + i ) {
+ + current_token_index ;
}
for ( size_t i = 0 ; i < hunk . removed_lines . size ( ) ; + + i ) {
+ + previous_token_index ;
}
}
while ( current_token_index < new_tokens_info . size ( ) & & previous_token_index < m_tokens_info . size ( ) ) {
new_tokens_info [ current_token_index ] . type = m_tokens_info [ previous_token_index ] . type ;
+ + previous_token_index ;
+ + current_token_index ;
}
}
update_spans ( new_tokens_info , palette ) ;
}
2022-05-14 17:09:24 +03:00
static Syntax : : TextStyle style_for_token_type ( Gfx : : Palette const & palette , CodeComprehension : : TokenInfo : : SemanticType type )
2022-02-06 23:02:34 +02:00
{
switch ( type ) {
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Unknown :
2022-02-06 23:02:34 +02:00
return { palette . base_text ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Keyword :
2022-02-06 23:02:34 +02:00
return { palette . syntax_keyword ( ) , true } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Type :
2022-02-06 23:02:34 +02:00
return { palette . syntax_type ( ) , true } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Identifier :
2022-02-06 23:02:34 +02:00
return { palette . syntax_identifier ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : String :
2022-02-06 23:02:34 +02:00
return { palette . syntax_string ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Number :
2022-02-06 23:02:34 +02:00
return { palette . syntax_number ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : IncludePath :
2022-02-06 23:02:34 +02:00
return { palette . syntax_preprocessor_value ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : PreprocessorStatement :
2022-02-06 23:02:34 +02:00
return { palette . syntax_preprocessor_statement ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Comment :
2022-02-06 23:02:34 +02:00
return { palette . syntax_comment ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Function :
2022-02-06 23:02:34 +02:00
return { palette . syntax_function ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Variable :
2022-02-06 23:02:34 +02:00
return { palette . syntax_variable ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : CustomType :
2022-02-06 23:02:34 +02:00
return { palette . syntax_custom_type ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Namespace :
2022-02-06 23:02:34 +02:00
return { palette . syntax_namespace ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Member :
2022-02-06 23:02:34 +02:00
return { palette . syntax_member ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Parameter :
2022-02-06 23:02:34 +02:00
return { palette . syntax_parameter ( ) , false } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : PreprocessorMacro :
2022-03-31 19:09:29 +03:00
return { palette . syntax_preprocessor_value ( ) , false } ;
2022-02-06 23:02:34 +02:00
default :
VERIFY_NOT_REACHED ( ) ;
return { palette . base_text ( ) , false } ;
}
}
2022-05-29 11:50:10 +01:00
void SemanticSyntaxHighlighter : : update_spans ( Vector < CodeComprehension : : TokenInfo > const & tokens_info , Gfx : : Palette const & palette )
2022-02-06 23:02:34 +02:00
{
Vector < GUI : : TextDocumentSpan > spans ;
for ( auto & token : tokens_info ) {
// FIXME: The +1 for the token end column is a quick hack due to not wanting to modify the lexer (which is also used by the parser). Maybe there's a better way to do this.
GUI : : TextDocumentSpan span ;
span . range . set_start ( { token . start_line , token . start_column } ) ;
span . range . set_end ( { token . end_line , token . end_column + 1 } ) ;
2022-05-29 11:50:10 +01:00
auto style = style_for_token_type ( palette , token . type ) ;
2022-02-06 23:02:34 +02:00
span . attributes . color = style . color ;
span . attributes . bold = style . bold ;
2022-05-14 17:09:24 +03:00
span . is_skippable = token . type = = CodeComprehension : : TokenInfo : : SemanticType : : Whitespace ;
2022-02-06 23:02:34 +02:00
span . data = static_cast < u64 > ( token . type ) ;
spans . append ( span ) ;
}
m_client - > do_set_spans ( move ( spans ) ) ;
m_has_brace_buddies = false ;
highlight_matching_token_pair ( ) ;
m_client - > do_update ( ) ;
}
2022-05-14 17:09:24 +03:00
void SemanticSyntaxHighlighter : : update_tokens_info ( Vector < CodeComprehension : : TokenInfo > tokens_info )
2022-02-06 23:02:34 +02:00
{
{
Threading : : MutexLocker locker ( m_lock ) ;
m_tokens_info = move ( tokens_info ) ;
m_saved_tokens_text = m_client - > get_text ( ) ;
Cpp : : Lexer lexer ( m_saved_tokens_text ) ;
lexer . set_ignore_whitespace ( true ) ;
m_saved_tokens = lexer . lex ( ) ;
}
}
bool SemanticSyntaxHighlighter : : is_identifier ( u64 token_type ) const
{
2022-05-14 17:09:24 +03:00
auto type = static_cast < CodeComprehension : : TokenInfo : : SemanticType > ( token_type ) ;
return type = = CodeComprehension : : TokenInfo : : SemanticType : : Identifier
| | type = = CodeComprehension : : TokenInfo : : SemanticType : : Function
| | type = = CodeComprehension : : TokenInfo : : SemanticType : : Variable
| | type = = CodeComprehension : : TokenInfo : : SemanticType : : CustomType
| | type = = CodeComprehension : : TokenInfo : : SemanticType : : Namespace
| | type = = CodeComprehension : : TokenInfo : : SemanticType : : Member
| | type = = CodeComprehension : : TokenInfo : : SemanticType : : Parameter
| | type = = CodeComprehension : : TokenInfo : : SemanticType : : PreprocessorMacro ;
2022-02-06 23:02:34 +02:00
}
bool SemanticSyntaxHighlighter : : is_navigatable ( u64 token_type ) const
{
2022-05-14 17:09:24 +03:00
return static_cast < CodeComprehension : : TokenInfo : : SemanticType > ( token_type ) = = CodeComprehension : : TokenInfo : : SemanticType : : IncludePath ;
2022-02-06 23:02:34 +02:00
}
}