Skip to content

Commit

Permalink
Merge pull request #791 from alanz/dap-vscode
Browse files Browse the repository at this point in the history
[DAP] add ability to launch in integrated terminal
  • Loading branch information
alanz authored Oct 19, 2020
2 parents d8b663c + cd3153c commit 7dcbad1
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 14 deletions.
58 changes: 58 additions & 0 deletions SPAWNFEST.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,64 @@ While working on the project, we noticed a few issues with third-party projects
;; Erlang DAP ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(require 'dap-mode)
;; Log io to *Messages*. Seems to be the only option at the moment. Optional
(setq dap-inhibit-io nil)
(setq dap-print-io t)
(defun dap-erlang--populate-start-file-args (conf)
"Populate CONF with the required arguments."
(-> conf
(dap--put-if-absent :dap-server-path '("els_dap"))
(dap--put-if-absent :request "launch")
(dap--put-if-absent :projectDir (lsp-find-session-folder (lsp-session) (buffer-file-name)))
(dap--put-if-absent :cwd (lsp-find-session-folder (lsp-session) (buffer-file-name)))
))
;; Add a Run Configuration for running 'rebar3 shell'
(dap-register-debug-provider "Erlang" 'dap-erlang--populate-start-file-args)
(dap-register-debug-template "Erlang rebar3 shell"
(list :type "Erlang"
:program "rebar3"
:args "shell"
:name "Erlang::Run"))
;; Add a Run Configuration for executing a given MFA
(dap-register-debug-template "Erlang MFA"
(list :type "Erlang"
:module "daptoy_fact"
:function "fact"
;; :function "dummy"
:args "[3]"
:name "Erlang::Run MFA"))
;; Add a Run Configuration for running 'rebar3 shell'
;; in an integrated terminal in the client
;; NOTE: set the projectnode hostname in two places
(dap-register-debug-template "Erlang Terminal"
(list :type "Erlang"
:runinterminal '("rebar3" "shell" "--name" "dapnode@alanzimm-mbp")
:projectnode "dapnode@alanzimm-mbp"
:name "Erlang::Terminal"))
;; Add a Run Configuration for running 'rebar3 shell'
;; in an integrated terminal in the client, running a given MFA
;; NOTE: set the projectnode hostname in two places
(dap-register-debug-template "Erlang Terminal MFA"
(list :type "Erlang"
:runinterminal '("rebar3" "shell" "--name" "dapnode@alanzimm-mbp")
:projectnode "dapnode@alanzimm-mbp"
:module "daptoy_fact"
:function "fact"
;; :function "dummy"
:args "[4]"
:name "Erlang::Terminal MFA"))
(require 'dap-mode)
;; Show debug logs
Expand Down
47 changes: 42 additions & 5 deletions src/els_dap_general_provider.erl
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,31 @@ handle_request({<<"launch">>, Params}, State) ->
#{<<"cwd">> := Cwd} = Params,
ok = file:set_cwd(Cwd),

ProjectNode = node_name("dap_project_", Cwd),
spawn(fun() -> els_utils:cmd("rebar3", ["shell", "--name", ProjectNode]) end),
ProjectNode = case Params of
#{ <<"projectnode">> := Node } -> binary_to_atom(Node, utf8);
_ -> node_name("dap_project_", Cwd)
end,
case Params of
#{ <<"runinterminal">> := Cmd
} ->
ParamsR
= #{ <<"kind">> => <<"integrated">>
, <<"title">> => ProjectNode
, <<"cwd">> => Cwd
, <<"args">> => Cmd
},
lager:info("Sending runinterminal request: [~p]", [ParamsR]),
els_dap_server:send_request(<<"runInTerminal">>, ParamsR),
ok;
_ ->
lager:info("launching 'rebar3 shell`", []),
spawn(fun() ->
els_utils:cmd("rebar3", ["shell", "--name", ProjectNode]) end)
end,

LocalNode = node_name("dap_", Cwd),
els_distribution_server:start_distribution(LocalNode),

els_distribution_server:wait_connect_and_monitor(ProjectNode, 5),
lager:info("Distribution up on: [~p]", [LocalNode]),

els_dap_server:send_event(<<"initialized">>, #{}),

Expand All @@ -79,6 +97,9 @@ handle_request( {<<"configurationDone">>, _Params}
, #{ project_node := ProjectNode
, launch_params := LaunchParams} = State
) ->
lager:info("Connecting to: [~p]", [ProjectNode]),
els_distribution_server:wait_connect_and_monitor(ProjectNode),

inject_dap_agent(ProjectNode),

%% TODO: Fetch stack_trace mode from Launch Config
Expand Down Expand Up @@ -107,6 +128,10 @@ handle_request( {<<"setBreakpoints">>, Params}
_SourceModified = maps:get(<<"sourceModified">>, Params, false),
Module = els_uri:module(els_uri:uri(Path)),

%% AZ: we should have something like `ensure_connected`
lager:info("Connecting to: [~p]", [ProjectNode]),
els_distribution_server:wait_connect_and_monitor(ProjectNode),

%% TODO: Keep a list of interpreted modules, not to re-interpret them
els_dap_rpc:i(ProjectNode, Module),
[els_dap_rpc:break(ProjectNode, Module, Line) ||
Expand Down Expand Up @@ -174,6 +199,15 @@ handle_request( {<<"stepIn">>, Params}
Pid = to_pid(ThreadId, Threads),
ok = els_dap_rpc:step(ProjectNode, Pid),
{#{}, State};
handle_request( {<<"stepOut">>, Params}
, #{ threads := Threads
, project_node := ProjectNode
} = State
) ->
#{<<"threadId">> := ThreadId} = Params,
Pid = to_pid(ThreadId, Threads),
ok = els_dap_rpc:next(ProjectNode, Pid),
{#{}, State};
handle_request({<<"evaluate">>, #{ <<"context">> := <<"hover">>
, <<"frameId">> := FrameId
, <<"expression">> := Input
Expand All @@ -189,7 +223,10 @@ handle_request({<<"evaluate">>, #{ <<"context">> := <<"hover">>
{#{<<"result">> => Result}, State};
handle_request({<<"variables">>, _Params}, State) ->
%% TODO: Return variables
{#{<<"variables">> => []}, State}.
{#{<<"variables">> => []}, State};
handle_request({<<"disconnect">>, _Params}, State) ->
els_utils:halt(0),
{#{}, State}.

-spec handle_info(any(), state()) -> state().
handle_info( {int_cb, ThreadPid}
Expand Down
14 changes: 7 additions & 7 deletions src/els_dap_protocol.erl
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,19 @@
-spec event(number(), binary(), any()) -> binary().
%% TODO: Body is optional
event(Seq, EventType, Body) ->
Message = #{ seq => Seq
, type => <<"event">>
Message = #{ type => <<"event">>
, seq => Seq
, event => EventType
, body => Body
},
content(jsx:encode(Message)).

-spec request(number(), binary(), any()) -> binary().
request(RequestId, Method, Params) ->
Message = #{ jsonrpc => ?JSONRPC_VSN
, method => Method
, id => RequestId
, params => Params
request(RequestSeq, Method, Params) ->
Message = #{ type => <<"request">>
, seq => RequestSeq
, command => Method
, arguments => Params
},
content(jsx:encode(Message)).

Expand Down
2 changes: 1 addition & 1 deletion src/els_dap_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ do_send_event(EventType, Body, #state{seq = Seq0} = State0) ->
-spec do_send_request(binary(), map(), state()) -> state().
do_send_request(Method, Params, #state{seq = RequestId0} = State0) ->
RequestId = RequestId0 + 1,
Request = els_protocol:request(RequestId, Method, Params),
Request = els_dap_protocol:request(RequestId, Method, Params),
lager:debug( "[SERVER] Sending request [request=~p]"
, [Request]
),
Expand Down
5 changes: 4 additions & 1 deletion src/els_distribution_server.erl
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,10 @@ start_distribution(Name) ->
{ok, _Pid} ->
lager:info("Distribution enabled [name=~p]", [Name]);
{error, {already_started, _Pid}} ->
lager:info("Distribution already enabled [name=~p]", [Name])
lager:info("Distribution already enabled [name=~p]", [Name]);
{error, {{shutdown, {failed_to_start_child, net_kernel, E1}}, E2}} ->
lager:info("Distribution shutdown [errs=~p]", [{E1, E2}]),
lager:info("Distribution shut down [name=~p]", [Name])
end.

%% @doc Connect to an existing runtime node, if available, or start one.
Expand Down

0 comments on commit 7dcbad1

Please sign in to comment.