! Layer 5 — Sovereign IDE Syntax Highlighting ! Query compiler + theme mapping ! Maps to: snapkitty-resonance-bridge token stream structure MODULE sovereign_syntax USE iso_c_binding USE sovereign_runtime, ONLY: runtime_panic, str_intern USE sovereign_parser, ONLY: parser_ctx_t, cst_node_t IMPLICIT NONE PRIVATE ! ── Color IDs (theme slots) ─────────────────────────────────────────────── INTEGER, PARAMETER :: COLOR_DEFAULT = 0 INTEGER, PARAMETER :: COLOR_KEYWORD = 1 INTEGER, PARAMETER :: COLOR_IDENTIFIER = 2 INTEGER, PARAMETER :: COLOR_STRING = 3 INTEGER, PARAMETER :: COLOR_NUMBER = 4 INTEGER, PARAMETER :: COLOR_COMMENT = 5 INTEGER, PARAMETER :: COLOR_OPERATOR = 6 INTEGER, PARAMETER :: COLOR_TYPE = 7 INTEGER, PARAMETER :: COLOR_FUNCTION = 8 INTEGER, PARAMETER :: COLOR_ERROR = 9 INTEGER, PARAMETER :: N_COLORS = 10 ! ── Theme ───────────────────────────────────────────────────────────────── ! RGBA packed as 0xRRGGBBAA TYPE :: theme_t INTEGER(C_INT32_T) :: colors(N_COLORS) LOGICAL :: worm_sealed = .FALSE. END TYPE theme_t ! ── Highlight span ──────────────────────────────────────────────────────── INTEGER, PARAMETER :: MAX_SPANS = 131072 TYPE :: span_t INTEGER :: start_byte = 0 INTEGER :: end_byte = 0 INTEGER :: color_id = COLOR_DEFAULT END TYPE span_t TYPE :: span_list_t TYPE(span_t) :: spans(MAX_SPANS) INTEGER :: count = 0 END TYPE span_list_t ! ── Query ───────────────────────────────────────────────────────────────── INTEGER, PARAMETER :: MAX_QUERY_PATTERNS = 256 TYPE :: query_pattern_t INTEGER(C_INT32_T) :: node_kind_id = 0 INTEGER :: color_id = COLOR_DEFAULT END TYPE query_pattern_t TYPE :: query_t TYPE(query_pattern_t) :: patterns(MAX_QUERY_PATTERNS) INTEGER :: pattern_count = 0 END TYPE query_t PUBLIC :: syntax_init PUBLIC :: syntax_load_theme PUBLIC :: syntax_highlight PUBLIC :: syntax_highlight_incremental PUBLIC :: theme_default_sovereign_dark CONTAINS ! --------------------------------------------------------------------------- SUBROUTINE syntax_init() WRITE(*,'(A)') '[syntax] init' END SUBROUTINE syntax_init ! --------------------------------------------------------------------------- ! Load a theme; WORM-seal after load SUBROUTINE syntax_load_theme(theme, path) TYPE(theme_t), INTENT(INOUT) :: theme CHARACTER(LEN=*), INTENT(IN) :: path ! TODO: parse theme file (JSON/TOML) CALL theme_default_sovereign_dark(theme) theme%worm_sealed = .TRUE. WRITE(*,'(A,A)') '[syntax] theme loaded from ', TRIM(path) END SUBROUTINE syntax_load_theme ! --------------------------------------------------------------------------- ! Sovereign dark theme — matches bob-ide color palette SUBROUTINE theme_default_sovereign_dark(theme) TYPE(theme_t), INTENT(INOUT) :: theme theme%colors(COLOR_DEFAULT+1) = INT(Z'D4D4D4FF', C_INT32_T) ! #D4D4D4 theme%colors(COLOR_KEYWORD+1) = INT(Z'569CD6FF', C_INT32_T) ! #569CD6 theme%colors(COLOR_IDENTIFIER+1) = INT(Z'9CDCFEFF', C_INT32_T) ! #9CDCFE theme%colors(COLOR_STRING+1) = INT(Z'CE9178FF', C_INT32_T) ! #CE9178 theme%colors(COLOR_NUMBER+1) = INT(Z'B5CEA8FF', C_INT32_T) ! #B5CEA8 theme%colors(COLOR_COMMENT+1) = INT(Z'6A9955FF', C_INT32_T) ! #6A9955 theme%colors(COLOR_OPERATOR+1) = INT(Z'D4D4D4FF', C_INT32_T) theme%colors(COLOR_TYPE+1) = INT(Z'4EC9B0FF', C_INT32_T) ! #4EC9B0 theme%colors(COLOR_FUNCTION+1) = INT(Z'DCDCAAFF', C_INT32_T) ! #DCDCAA theme%colors(COLOR_ERROR+1) = INT(Z'F44747FF', C_INT32_T) ! #F44747 theme%worm_sealed = .FALSE. END SUBROUTINE theme_default_sovereign_dark ! --------------------------------------------------------------------------- ! Full highlight pass over entire CST SUBROUTINE syntax_highlight(ctx, spans, query) TYPE(parser_ctx_t), INTENT(IN) :: ctx TYPE(span_list_t), INTENT(INOUT) :: spans TYPE(query_t), INTENT(IN) :: query spans%count = 0 CALL highlight_node(ctx, ctx%root, spans, query) WRITE(*,'(A,I0,A)') '[syntax] highlight: ', spans%count, ' spans' END SUBROUTINE syntax_highlight ! --------------------------------------------------------------------------- ! Incremental highlight — only reprocess changed CST subtree SUBROUTINE syntax_highlight_incremental(ctx, spans, query, from_node) TYPE(parser_ctx_t), INTENT(IN) :: ctx TYPE(span_list_t), INTENT(INOUT) :: spans TYPE(query_t), INTENT(IN) :: query INTEGER, INTENT(IN) :: from_node ! TODO: invalidate spans overlapping from_node range, re-run from there CALL highlight_node(ctx, from_node, spans, query) END SUBROUTINE syntax_highlight_incremental ! ── Internal ────────────────────────────────────────────────────────────── RECURSIVE SUBROUTINE highlight_node(ctx, idx, spans, query) TYPE(parser_ctx_t), INTENT(IN) :: ctx INTEGER, INTENT(IN) :: idx TYPE(span_list_t), INTENT(INOUT) :: spans TYPE(query_t), INTENT(IN) :: query INTEGER :: i, color, child IF (idx == 0) RETURN ! Match node kind against query patterns color = COLOR_DEFAULT IF (ctx%nodes(idx)%is_error) THEN color = COLOR_ERROR ELSE DO i = 1, query%pattern_count IF (query%patterns(i)%node_kind_id == ctx%nodes(idx)%kind) THEN color = query%patterns(i)%color_id EXIT END IF END DO END IF ! Emit span if leaf IF (ctx%nodes(idx)%n_children == 0) THEN IF (spans%count < MAX_SPANS) THEN spans%count = spans%count + 1 spans%spans(spans%count)%start_byte = ctx%nodes(idx)%start_byte spans%spans(spans%count)%end_byte = ctx%nodes(idx)%end_byte spans%spans(spans%count)%color_id = color END IF RETURN END IF ! Recurse into children DO i = 1, ctx%nodes(idx)%n_children child = ctx%nodes(idx)%children(i) CALL highlight_node(ctx, child, spans, query) END DO END SUBROUTINE highlight_node END MODULE sovereign_syntax