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 ( ) ;
2023-03-03 12:53:08 +00:00
// Identify folding regions
Vector < Token > folding_region_start_tokens ;
Vector < GUI : : TextDocumentFoldingRegion > folding_regions ;
for ( auto & token : current_tokens ) {
if ( token . type ( ) = = Token : : Type : : LeftCurly ) {
folding_region_start_tokens . append ( token ) ;
} else if ( token . type ( ) = = Token : : Type : : RightCurly ) {
if ( ! folding_region_start_tokens . is_empty ( ) ) {
auto start_token = folding_region_start_tokens . take_last ( ) ;
GUI : : TextDocumentFoldingRegion folding_region ;
folding_region . range . set_start ( { start_token . end ( ) . line , start_token . end ( ) . column } ) ;
folding_region . range . set_end ( { token . start ( ) . line , token . start ( ) . column } ) ;
folding_regions . append ( move ( folding_region ) ) ;
}
}
}
m_client - > do_set_folding_regions ( move ( folding_regions ) ) ;
2022-02-06 23:02:34 +02:00
StringBuilder current_tokens_as_lines ;
StringBuilder previous_tokens_as_lines ;
for ( auto & token : current_tokens )
2023-12-16 17:49:34 +03:30
current_tokens_as_lines . appendff ( " {} \n " , token . type_as_byte_string ( ) ) ;
2022-02-06 23:02:34 +02:00
for ( Cpp : : Token const & token : m_saved_tokens )
2023-12-16 17:49:34 +03:30
previous_tokens_as_lines . appendff ( " {} \n " , token . type_as_byte_string ( ) ) ;
2022-02-06 23:02:34 +02:00
2023-12-16 17:49:34 +03:30
auto previous = previous_tokens_as_lines . to_byte_string ( ) ;
auto current = current_tokens_as_lines . to_byte_string ( ) ;
2022-02-06 23:02:34 +02:00
// 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.
2023-06-24 12:57:38 +12:00
auto diff_hunks = Diff : : from_text ( previous . view ( ) , current . view ( ) ) . release_value_but_fixme_should_propagate_errors ( ) ;
2022-02-06 23:02:34 +02:00
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 ) {
2023-06-24 17:33:04 +12:00
for ( ; previous_token_index < hunk . location . old_range . start_line ; + + previous_token_index ) {
2022-02-06 23:02:34 +02:00
new_tokens_info [ current_token_index ] . type = m_tokens_info [ previous_token_index ] . type ;
+ + current_token_index ;
}
2023-06-24 17:33:04 +12:00
for ( size_t i = 0 ; i < hunk . location . new_range . number_of_lines ; + + i ) {
2022-02-06 23:02:34 +02:00
+ + current_token_index ;
}
2023-06-24 17:33:04 +12:00
for ( size_t i = 0 ; i < hunk . location . old_range . number_of_lines ; + + i ) {
2022-02-06 23:02:34 +02:00
+ + 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 ) ;
}
2023-03-15 12:49:17 +00:00
static Gfx : : TextAttributes 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 :
2023-03-15 12:49:17 +00:00
return { palette . base_text ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Keyword :
2023-03-15 12:49:17 +00:00
return { palette . syntax_keyword ( ) , { } , true } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Type :
2023-03-15 12:49:17 +00:00
return { palette . syntax_type ( ) , { } , true } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Identifier :
2023-03-15 12:49:17 +00:00
return { palette . syntax_identifier ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : String :
2023-03-15 12:49:17 +00:00
return { palette . syntax_string ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Number :
2023-03-15 12:49:17 +00:00
return { palette . syntax_number ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : IncludePath :
2023-03-15 12:49:17 +00:00
return { palette . syntax_preprocessor_value ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : PreprocessorStatement :
2023-03-15 12:49:17 +00:00
return { palette . syntax_preprocessor_statement ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Comment :
2023-03-15 12:49:17 +00:00
return { palette . syntax_comment ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Function :
2023-03-15 12:49:17 +00:00
return { palette . syntax_function ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Variable :
2023-03-15 12:49:17 +00:00
return { palette . syntax_variable ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : CustomType :
2023-03-15 12:49:17 +00:00
return { palette . syntax_custom_type ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Namespace :
2023-03-15 12:49:17 +00:00
return { palette . syntax_namespace ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Member :
2023-03-15 12:49:17 +00:00
return { palette . syntax_member ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : Parameter :
2023-03-15 12:49:17 +00:00
return { palette . syntax_parameter ( ) } ;
2022-05-14 17:09:24 +03:00
case CodeComprehension : : TokenInfo : : SemanticType : : PreprocessorMacro :
2023-03-15 12:49:17 +00:00
return { palette . syntax_preprocessor_value ( ) } ;
2022-02-06 23:02:34 +02:00
default :
VERIFY_NOT_REACHED ( ) ;
2023-03-15 12:49:17 +00:00
return { palette . base_text ( ) } ;
2022-02-06 23:02:34 +02:00
}
}
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 } ) ;
2023-03-15 12:49:17 +00:00
span . attributes = style_for_token_type ( palette , token . type ) ;
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
}
}