First stab at supporting syntax highlighting via wxStyledTextCtrl

This commit is contained in:
Ulf Wiger
2025-03-30 21:16:21 +02:00
parent 8cb3065510
commit 27b78f8623
2 changed files with 142 additions and 6 deletions
+113
View File
@@ -0,0 +1,113 @@
-module(gd_sophia_editor).
-export([new/3, get_text/1, set_text/2]).
-include_lib("wx/include/wx.hrl").
new(Parent, Id, Opts) ->
STC = wxStyledTextCtrl:new(Parent, [{id, Id} | Opts]),
%% Set up the container lexer
wxStyledTextCtrl:setLexer(STC, ?wxSTC_LEX_CONTAINER),
%% Define styles
set_colors(STC),
%% Connect the styling event
wxStyledTextCtrl:connect(
STC, 'stc_styleneeded',
[{callback, fun(Event, _) -> style_needed(Event, STC) end}]),
STC.
get_text(STC) ->
wxStyledTextCtrl:getText(STC).
set_text(STC, Text) ->
wxStyledTextCtrl:setText(STC, Text),
%% Force Scintilla to request styling for the entire text
wxStyledTextCtrl:colourise(STC, 0, -1).
%% ======================================================================
set_colors(STC) ->
wxStyledTextCtrl:styleClearAll(STC),
wxStyledTextCtrl:styleSetForeground(STC, 0, {0, 0, 0}), % Default: Black
wxStyledTextCtrl:styleSetForeground(STC, 1, {0, 0, 192}), % Keywords: Deep Blue
wxStyledTextCtrl:styleSetForeground(STC, 2, {0, 0, 0}), % Identifiers: Black
wxStyledTextCtrl:styleSetForeground(STC, 3, {128, 128, 128}), % Comments: Gray
wxStyledTextCtrl:styleSetForeground(STC, 4, {163, 21, 21}), % Strings/Chars: Reddish
wxStyledTextCtrl:styleSetForeground(STC, 5, {128, 0, 128}), % Numbers: Purple
wxStyledTextCtrl:styleSetForeground(STC, 6, {0, 0, 0}). % Operators: Black
style_needed(_Event, STC) ->
try
StartPos = wxStyledTextCtrl:getEndStyled(STC),
EndPos = wxStyledTextCtrl:getLength(STC),
Text = wxStyledTextCtrl:getTextRange(STC, StartPos, EndPos),
case so_scan:scan(Text) of
{ok, Tokens} ->
wxStyledTextCtrl:startStyling(STC, StartPos),
apply_styles(STC, Tokens);
{error, _Reason} ->
wxStyledTextCtrl:startStyling(STC, StartPos),
wxStyledTextCtrl:setStyling(STC, EndPos - StartPos, 0)
end
catch
error:E:T ->
dbg("CAUGHT error:~p / ~p~n", [E, T])
end.
apply_styles(STC, Tokens) ->
lists:foreach(fun(Token) -> style_token(STC, Token) end, Tokens).
style_token(STC, Token) ->
{Type, Value} = type_and_value(Token),
{Line, Col} = element(2, Token),
Len = byte_size(to_binary(Value)),
Style = classify_style(Type, Value),
% Get exact position from Line and Column
Start = wxStyledTextCtrl:positionFromLine(STC, Line - 1) + (Col - 1),
wxStyledTextCtrl:startStyling(STC, Start),
wxStyledTextCtrl:setStyling(STC, Len, Style).
to_binary(S) when is_list(S) ->
unicode:characters_to_binary(S);
to_binary(S) when is_binary(S) ->
S;
to_binary(I) when is_integer(I) ->
integer_to_binary(I).
classify_style(Type, Value) ->
case Type of
symbol ->
case lists:member(Value, keywords()) of
true -> 1;
false -> 6
end;
id -> 2;
qid -> 2;
con -> 2;
qcon -> 2;
tvar -> 2;
string -> 4;
char -> 4;
int -> 5;
hex -> 5;
bytes -> 5;
skip -> 3;
_Other -> 1
end.
type_and_value({Type,_Line,Value}) -> {Type, Value};
type_and_value({Type, _}) -> {Type, atom_to_list(Type)}.
keywords() ->
["contract", "include", "let", "switch", "type", "record", "datatype", "if",
"elif", "else", "function", "stateful", "payable", "true", "false", "mod",
"public", "entrypoint", "private", "indexed", "namespace", "interface",
"main", "using", "as", "for", "hiding", "band", "bor", "bxor", "bnot"].
%% dbg(Fmt) ->
%% dbg(Fmt, []).
dbg(Fmt, Args) ->
io:format("~p: " ++ Fmt, [self()|Args]).