diff --git a/src/gd_con.erl b/src/gd_con.erl index 103668c..563da3d 100644 --- a/src/gd_con.erl +++ b/src/gd_con.erl @@ -339,7 +339,7 @@ init(none) -> NewState = do_show_ui(gd_v_wallman, State), ok = case FirstRun of - false -> ok; + false -> gd_v_wallman:to_front(); true -> gd_v_wallman:first_run() end, {ok, NewState}. diff --git a/src/gd_sophia_editor.erl b/src/gd_sophia_editor.erl index 1455ac7..9f0604f 100644 --- a/src/gd_sophia_editor.erl +++ b/src/gd_sophia_editor.erl @@ -1,6 +1,6 @@ -module(gd_sophia_editor). -vsn("0.8.0"). --export([new/1, update/2, +-export([new/1, update/1, update/2, get_text/1, set_text/2]). -include("$zx_include/zx_logger.hrl"). @@ -124,6 +124,9 @@ set_colors(STC) -> update(_Event, STC) -> + update(STC). + +update(STC) -> Text = wxStyledTextCtrl:getText(STC), case so_scan:scan(Text) of {ok, Tokens} -> diff --git a/src/gd_v_devman.erl b/src/gd_v_devman.erl index 4ca6291..a0cec25 100644 --- a/src/gd_v_devman.erl +++ b/src/gd_v_devman.erl @@ -15,7 +15,6 @@ -include("$zx_include/zx_logger.hrl"). -include("gd.hrl"). --define(editorMode, sophia). % Widgets -record(w, @@ -589,7 +588,7 @@ deploy(State = #s{code = {Codebook, Pages}}) -> State; Index -> #p{code = CodeTx} = lists:nth(Index + 1, Pages), - Source = get_source(CodeTx), + Source = gd_sophia_editor:get_text(CodeTx), deploy2(State, Source) end. @@ -597,26 +596,26 @@ deploy2(State, Source) -> case compile(Source) of % TODO: Make hz accept either the aaci or the aci, preferring the aaci if present {ok, Build} -> - {aaci, ContractName, Funs, NS} = maps:get(aaci, Build), + {aaci, ContractName, Funs, _} = maps:get(aaci, Build), ok = tell(info, "Deploying Contract: ~p", [ContractName]), InitSpec = maps:get("init", Funs), - deploy3(State, InitSpec, Build, NS); + deploy3(State, InitSpec, Build); Other -> ok = tell(info, "Compilation Failed!~n~tp", [Other]), State end. -deploy3(State, InitSpec, Build, NS) -> +deploy3(State, InitSpec, Build) -> case gd_con:list_keys() of {ok, 0, []} -> handle_troubling(State, "No keys exist in the current wallet."); {ok, Selected, Keys} -> - deploy4(State, InitSpec, Build, NS, Selected, Keys); + deploy4(State, InitSpec, Build, Selected, Keys); error -> handle_troubling(State, "No wallet is selected!") end. -deploy4(State = #s{frame = Frame, j = J}, InitSpec, Build, NS, Selected, Keys) -> +deploy4(State = #s{frame = Frame, j = J}, InitSpec, Build, Selected, Keys) -> InitArgs = element(1, InitSpec), Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Deploy Contract")), Sizer = wxBoxSizer:new(?wxVERTICAL), @@ -639,7 +638,7 @@ deploy4(State = #s{frame = Frame, j = J}, InitSpec, Build, NS, Selected, Keys) - GridSz = wxFlexGridSizer:new(2, 4, 4), ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - ArgFields = make_arg_fields(ScrollWin, GridSz, InitArgs, NS, J), + ArgFields = make_arg_fields(ScrollWin, GridSz, InitArgs), _ = wxStaticBoxSizer:add(FunSz, GridSz, zxw:flags(wide)), _ = wxStaticBoxSizer:add(ScrollSz, FunSz, [{proportion, 1}, {flag, ?wxEXPAND}]), _ = wxStaticBoxSizer:add(ScrollSz, KeySz, [{proportion, 0}, {flag, ?wxEXPAND}]), @@ -685,6 +684,19 @@ deploy5(State, Build, Params, Args) -> State. +make_arg_fields(ScrollWin, GridSz, Args) -> + MakeArgField = + fun({AN, T}) -> + tell(info, "~p: Arg: ~p, Type: ~p", [?LINE, AN, T]), + ANT = wxStaticText:new(ScrollWin, ?wxID_ANY, AN), + TCT = wxTextCtrl:new(ScrollWin, ?wxID_ANY), + _ = wxFlexGridSizer:add(GridSz, ANT, [{proportion, 0}, {flag, ?wxEXPAND}]), + _ = wxFlexGridSizer:add(GridSz, TCT, [{proportion, 0}, {flag, ?wxEXPAND}]), + {T, TCT} + end, + lists:map(MakeArgField, Args). + + open(State = #s{frame = Frame, j = J}) -> Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Open Contract Source")), Sizer = wxBoxSizer:new(?wxVERTICAL), @@ -894,7 +906,7 @@ save(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pages}}) _ -> Name ++ ".aes" end, Path = filename:join(Dir, File), - Source = get_source(Widget), + Source = gd_sophia_editor:get_text(Widget), case filelib:ensure_dir(Path) of ok -> case file:write_file(Path, Source) of @@ -922,35 +934,6 @@ save(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pages}}) end end. -make_plain_text_control(Parent) -> - CodeTxStyle = {style, ?wxTE_MULTILINE - bor ?wxTE_PROCESS_TAB - bor ?wxTE_DONTWRAP - bor ?wxTE_READONLY}, - CodeTx = wxTextCtrl:new(Parent, ?wxID_ANY, [CodeTxStyle]), - Mono = wxFont:new(10, ?wxMODERN, ?wxNORMAL, ?wxNORMAL, [{face, "Monospace"}]), - TextAt = wxTextAttr:new(), - ok = wxTextAttr:setFont(TextAt, Mono), - true = wxTextCtrl:setDefaultStyle(CodeTx, TextAt), - CodeTx. - -make_source_text_control(Parent) -> - case ?editorMode of - plain -> make_plain_text_control(Parent); - sophia -> gd_sophia_editor:new(Parent) - end. - -get_source(Widget) -> - case ?editorMode of - plain -> wxTextCtrl:getValue(Widget); - sophia -> gd_sophia_editor:get_text(Widget) - end. - -set_source(Widget, Src) -> - case ?editorMode of - plain -> wxTextCtrl:setValue(Widget, Src); - sophia -> gd_sophia_editor:set_text(Widget, Src) - end. % TODO: Break this down -- tons of things in here recur. rename(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pages}}) -> @@ -982,7 +965,7 @@ rename(State = #s{frame = Frame, j = J, prefs = Prefs, code = {Codebook, Pages}} _ -> Name ++ ".aes" end, NewPath = filename:join(Dir, File), - Source = get_source(Widget), + Source = gd_sophia_editor:get_text(Widget), case filelib:ensure_dir(NewPath) of ok -> case file:write_file(NewPath, Source) of @@ -1028,41 +1011,16 @@ load(State = #s{frame = Frame, j = J}) -> % TODO: Extract the exact compiler version, load it, and use only that or fail if % the specific version is unavailable. % TODO: Compile on load and verify the deployed hash for validity. - Dialog = wxDialog:new(Frame, ?wxID_ANY, J("Retrieve Contract Source")), - Sizer = wxBoxSizer:new(?wxVERTICAL), - AddressSz = wxStaticBoxSizer:new(?wxVERTICAL, Dialog, [{label, J("Address Hash")}]), - AddressTx = wxTextCtrl:new(Dialog, ?wxID_ANY), - _ = wxSizer:add(AddressSz, AddressTx, zxw:flags(wide)), - ButtSz = wxBoxSizer:new(?wxHORIZONTAL), - Affirm = wxButton:new(Dialog, ?wxID_OK), - Cancel = wxButton:new(Dialog, ?wxID_CANCEL), - _ = wxBoxSizer:add(ButtSz, Affirm, zxw:flags(wide)), - _ = wxBoxSizer:add(ButtSz, Cancel, zxw:flags(wide)), - _ = wxSizer:add(Sizer, AddressSz, zxw:flags(wide)), - _ = wxSizer:add(Sizer, ButtSz, zxw:flags(wide)), - ok = wxDialog:setSizer(Dialog, Sizer), - ok = wxBoxSizer:layout(Sizer), - ok = wxDialog:setSize(Dialog, {500, 200}), - ok = wxDialog:center(Dialog), - ok = wxTextCtrl:setFocus(AddressTx), - Choice = - case wxDialog:showModal(Dialog) of - ?wxID_OK -> - case wxTextCtrl:getValue(AddressTx) of - "" -> cancel; - A -> {ok, A} - end; - ?wxID_CANCEL -> - cancel - end, - ok = wxDialog:destroy(Dialog), - case Choice of + Title = J("Retrieve Contract Source"), + Label = J("Address Hash"), + case zxw_modal_text:show(Frame, Title, [{label, Label}]) of {ok, Address = "ct_" ++ _} -> load2(State, Address); {ok, Address = "th_" ++ _} -> load_from_tx(State, Address); {ok, Turd} -> handle_troubling(State, {bad_address, Turd}); cancel -> State end. + load_from_tx(State, Address) -> case hz:tx_info(Address) of {ok, #{"call_info" := #{"contract_id" := Contract}}} -> @@ -1089,8 +1047,9 @@ load3(State = #s{tabs = TopBook, cons = {Consbook, Pages}, buttons = Buttons, j PageSz = wxBoxSizer:new(?wxVERTICAL), ProgSz = wxBoxSizer:new(?wxHORIZONTAL), CodeSz = wxStaticBoxSizer:new(?wxVERTICAL, Window, [{label, J("Contract Source")}]), - CodeTx = make_source_text_control(Window), - ok = set_source(CodeTx, Source), + CodeTx = gd_sophia_editor:new(Window), + ok = gd_sophia_editor:set_text(CodeTx, Source), + ok = gd_sophia_editor:update(CodeTx), _ = wxSizer:add(CodeSz, CodeTx, zxw:flags(wide)), ScrollWin = wxScrolledWindow:new(Window), FunSz = wxStaticBoxSizer:new(?wxVERTICAL, ScrollWin, [{label, J("Function Interfaces")}]), @@ -1100,17 +1059,17 @@ load3(State = #s{tabs = TopBook, cons = {Consbook, Pages}, buttons = Buttons, j ConsTxStyle = {style, ?wxTE_MULTILINE bor ?wxTE_READONLY}, ConsTx = wxTextCtrl:new(Window, ?wxID_ANY, [ConsTxStyle]), _ = wxSizer:add(ConsSz, ConsTx, zxw:flags(wide)), - _ = wxSizer:add(ProgSz, CodeSz, [{proportion, 2}, {flag, ?wxEXPAND}]), + _ = wxSizer:add(ProgSz, CodeSz, [{proportion, 3}, {flag, ?wxEXPAND}]), _ = wxSizer:add(ProgSz, ScrollWin, [{proportion, 1}, {flag, ?wxEXPAND}]), _ = wxSizer:add(PageSz, ProgSz, [{proportion, 3}, {flag, ?wxEXPAND}]), _ = wxSizer:add(PageSz, ConsSz, [{proportion, 1}, {flag, ?wxEXPAND}]), {Out, IFaces, Build, NewButtons} = case compile(Source) of {ok, Output} -> - {aaci, _, Funs, NS} = maps:get(aaci, Output), + {aaci, _, Funs, _} = maps:get(aaci, Output), Callable = maps:remove("init", Funs), tell(info, "Callable: ~p", [Callable]), - {NB, IFs} = fun_interfaces(ScrollWin, FunSz, Buttons, Callable, NS, J), + {NB, IFs} = fun_interfaces(ScrollWin, FunSz, Buttons, Callable, J), O = io_lib:format("Compilation Succeeded!~n~tp~n~nDone!~n", [Output]), {O, IFs, Output, NB}; Other -> @@ -1147,126 +1106,26 @@ get_arg({_, TextCtrl}) -> get_record([{L, A} | T]) -> [{L, get_arg(A)} | get_record(T)]. -fun_interfaces(ScrollWin, FunSz, Buttons, Funs, NS, J) -> +fun_interfaces(ScrollWin, FunSz, Buttons, Funs, J) -> MakeIface = fun(Name, {Args, _}) -> - tell(info, "Fun: ~p, Args: ~p", [Name, Args]), FunName = unicode:characters_to_list([Name, "/", integer_to_list(length(Args))]), - FN = wxStaticBoxSizer:new(?wxVERTICAL, ScrollWin, [{label, FunName}]), - GridSz = wxFlexGridSizer:new(2, 4, 4), - ok = wxFlexGridSizer:setFlexibleDirection(GridSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(GridSz, 1), - ArgFields = make_arg_fields(ScrollWin, GridSz, Args, NS, J), - ButtSz = wxBoxSizer:new(?wxHORIZONTAL), + FS = wxBoxSizer:new(?wxHORIZONTAL), + FLabel = wxStaticText:new(ScrollWin, ?wxID_ANY, FunName), CallBn = wxButton:new(ScrollWin, ?wxID_ANY, [{label, J("Call")}]), DryRBn = wxButton:new(ScrollWin, ?wxID_ANY, [{label, J("Dry Run")}]), - _ = wxBoxSizer:add(ButtSz, CallBn, zxw:flags(wide)), - _ = wxBoxSizer:add(ButtSz, DryRBn, zxw:flags(wide)), + _ = wxBoxSizer:add(FS, FLabel, [{proportion, 1}, {flag, ?wxEXPAND}]), + _ = wxBoxSizer:add(FS, CallBn, [{proportion, 0}, {flag, ?wxEXPAND}]), + _ = wxBoxSizer:add(FS, DryRBn, [{proportion, 0}, {flag, ?wxEXPAND}]), CallButton = #w{name = {Name, call}, id = wxButton:getId(CallBn), wx = CallBn}, DryRButton = #w{name = {Name, dryr}, id = wxButton:getId(DryRBn), wx = DryRBn}, - _ = wxStaticBoxSizer:add(FN, GridSz, zxw:flags(wide)), - _ = wxStaticBoxSizer:add(FN, ButtSz, zxw:flags(base)), - _ = wxSizer:add(FunSz, FN, zxw:flags(base)), - #f{name = Name, call = CallButton, dryrun = DryRButton, args = ArgFields} + _ = wxSizer:add(FunSz, FS, zxw:flags(base)), + #f{name = Name, call = CallButton, dryrun = DryRButton, args = Args} end, IFaces = maps:map(MakeIface, Funs), - tell(info, "IFaces: ~p", [IFaces]), NewButtons = maps:fold(fun map_iface_buttons/3, Buttons, IFaces), {NewButtons, IFaces}. -% FIXME: This can be simplified and needs to provide better widgets for types. -% "variant" types should be wxChoice -% Booleans should either be wxChoice or check boxes -% The sizer expansion direction for vertical elements is stupid -% FIXME: We probably don't need the opaque type definitions 'NS', since the -% AACI already caches the useful expansions that might be needed for error -% messages. -make_arg_fields(ScrollWin, GridSz, Args, NS, J) -> - MakeArgField = - fun - ({AN, {_O, _N, T}}) when is_atom(T) -> -% tell(info, "~p Arg: ~p, Type: ~p", [?LINE, AN, T]), - ANT = wxStaticText:new(ScrollWin, ?wxID_ANY, AN), - TCT = wxTextCtrl:new(ScrollWin, ?wxID_ANY), - _ = wxFlexGridSizer:add(GridSz, ANT, fill()), - _ = wxFlexGridSizer:add(GridSz, TCT, fill()), - {T, TCT}; - ({AN, {_O, _N, {record, InnerArgs}}}) -> -% tell(info, "~p Arg: ~p, ~p: ~p", [?LINE, AN, TypeName, InnerArgs]), - ANT = wxStaticText:new(ScrollWin, ?wxID_ANY, AN), - InnerSz = wxFlexGridSizer:new(2, 4, 4), - ok = wxFlexGridSizer:setFlexibleDirection(InnerSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(InnerSz, 1), - AFs = make_arg_fields(ScrollWin, InnerSz, InnerArgs, NS, J), - _ = wxFlexGridSizer:add(GridSz, ANT, fill()), - _ = wxFlexGridSizer:add(GridSz, InnerSz, fill()), - {record, AFs}; - ({AN, {_O, _N, {tuple, InnerArgs}}}) -> -% tell(info, "~p Arg: ~p, ~p: ~p", [?LINE, AN, TypeName, InnerArgs]), - ANT = wxStaticText:new(ScrollWin, ?wxID_ANY, AN), - InnerSz = wxFlexGridSizer:new(2, 4, 4), - ok = wxFlexGridSizer:setFlexibleDirection(InnerSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(InnerSz, 1), - AFs = make_unnamed_fields(ScrollWin, InnerSz, InnerArgs, NS, J), - _ = wxFlexGridSizer:add(GridSz, ANT, fill()), - _ = wxFlexGridSizer:add(GridSz, InnerSz, fill()), - {tuple, AFs}; - ({AN, {_O, _N, {list, [InnerType]}}}) -> -% tell(info, "~p Arg: ~p, ~p: ~p", [?LINE, AN, TypeName, InnerArgs]), - ANT = wxStaticText:new(ScrollWin, ?wxID_ANY, AN), - ArgSz = wxBoxSizer:new(?wxVERTICAL), - InnerSz = wxFlexGridSizer:new(2, 4, 4), - ok = wxFlexGridSizer:setFlexibleDirection(InnerSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(InnerSz, 1), - AFs = make_unnamed_fields(ScrollWin, InnerSz, [InnerType], NS, J), - B = wxButton:new(ScrollWin, ?wxID_ANY, [{label, J("Add")}]), - AB = #w{name = {AN, add}, id = wxButton:getId(B), wx = B}, - _ = wxBoxSizer:add(ArgSz, InnerSz, fill()), - _ = wxBoxSizer:add(ArgSz, B, fill()), - _ = wxFlexGridSizer:add(GridSz, ANT, fill()), - _ = wxFlexGridSizer:add(GridSz, ArgSz, fill()), - {list, AFs, AB}; - ({AN, {_O, _N, {map, [Key, Value]}}}) -> -% tell(info, "~p Arg: ~p, ~p: ~p", [?LINE, AN, TypeName, T]), - ANT = wxStaticText:new(ScrollWin, ?wxID_ANY, AN), - InnerSz = wxFlexGridSizer:new(2, 4, 4), - ok = wxFlexGridSizer:setFlexibleDirection(InnerSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(InnerSz, 1), - AFs = make_unnamed_fields(ScrollWin, InnerSz, [Key, Value], NS, J), - _ = wxFlexGridSizer:add(GridSz, ANT, fill()), - _ = wxFlexGridSizer:add(GridSz, InnerSz, fill()), - {map, AFs}; - ({AN, {_O, _N, {variant, Variants = [{_, VariantElements} | _]}}}) -> -% tell(info, "~p Arg: ~p, ~p: ~p", [?LINE, AN, TypeName, InnerArgs]), - ANT = wxStaticText:new(ScrollWin, ?wxID_ANY, AN), - InnerSz = wxFlexGridSizer:new(2, 4, 4), - ok = wxFlexGridSizer:setFlexibleDirection(InnerSz, ?wxHORIZONTAL), - ok = wxFlexGridSizer:addGrowableCol(InnerSz, 1), - AFs = make_unnamed_fields(ScrollWin, InnerSz, VariantElements, NS, J), - _ = wxFlexGridSizer:add(GridSz, ANT, fill()), - _ = wxFlexGridSizer:add(GridSz, InnerSz, fill()), - VariantNames = lists:map(fun({Name, _}) -> Name end, Variants), - {variant, AFs, VariantNames} - end, - lists:map(MakeArgField, Args). - -make_unnamed_fields(ScrollWin, InnerSz, Elems, NS, J) -> - ChooseName = - fun - (Ann = {_, _, T}) when is_atom(T) -> - {atom_to_list(T), Ann}; - (Ann = {Name, _, {record, _}}) when is_list(Name) -> - io:format("record: ~p~n", [Ann]), - {Name, Ann}; - (Ann = {_, _, {T, _}}) when is_atom(T) -> - {atom_to_list(T), Ann} - end, - WithNames = lists:map(ChooseName, Elems), - make_arg_fields(ScrollWin, InnerSz, WithNames, NS, J). - -fill() -> - [{proportion, 0}, {flag, ?wxEXPAND}]. - map_iface_buttons(_, #f{call = C = #w{id = CID}, dryrun = D = #w{id = DID}}, A) -> maps:merge(#{CID => C, DID => D}, A); @@ -1281,7 +1140,7 @@ edit(State = #s{cons = {Consbook, Pages}}) -> Index -> #c{code = CodeTx} = lists:nth(Index + 1, Pages), Address = wxNotebook:getPageText(Consbook, Index), - Source = wxTextCtrl:getValue(CodeTx), + Source = gd_sophia_editor:get_text(CodeTx), add_code_page(State, {hash, Address}, Source) end.