Re: erl-complete ...

[email protected] Sat, 15 Sep 2007 05:49:46 +0100
Newsgroups gmane.comp.lang.erlang.distel.devel
Message-ID <[email protected]>
--=-=-=

Bill,

Bill Clementson <[email protected]> writes:

> I was asking about a patch for the Call Graph code that you wrote
> previously. At the moment, the "who calls" support doesn't work for
> BIF's.

Oh I see. Is it really that useful to have that? I don't often find
myself wondering who calls a particular BIF.

I added builtins to the call graph xref server - see attached patch -
but it doesn't seem to make a difference. I suspect BIFs are only added
as unconnected vertices.

>>>> (except distel's completion currently isn't using xref, but it should)
> Does the attached patch do what you wanted?

Thanks for the patch. I've made the following changes:

- don't add otp release - the otp modules are part of the code path and
hence get loaded anyway

- filter duplicates (due to different arity) from function completion

- avoid duplication of code between who_calls and completion

- add rebuild_{completions, call_graph} functions - there is nothing on
the emacs side that calls them, but you can call them manually

- minor cosmetic changes

See attachment for the revised patch.

One remaining problem with this code is that it doesn't automatically
handle the addition/removal of modules or changes to the code load
path - you have to invoke the aforementioned rebuild functions manually
for this.


Matthias.

--=-=-=
Content-Type: text/x-diff
Content-Disposition: attachment; filename=distel_xref_complete.patch

Index: distel.erl
===================================================================
--- distel.erl	(revision 38)
+++ distel.erl	(working copy)
@@ -20,6 +20,7 @@
          debug_toggle/2, debug_subscribe/1, debug_add/1,
          break_toggle/2, break_delete/2, break_add/2, break_restore/1,
          modules/1, functions/2, who_calls/3,
+         rebuild_completions/0, rebuild_call_graph/0,
          free_vars/1, free_vars/2,
          apropos/1, apropos/2, describe/3, describe/4]).
 
@@ -647,44 +648,33 @@
 %% ----------------------------------------------------------------------
 %% Completion support
 %% ----------------------------------------------------------------------
+-define(COMPLETION_SERVER, distel_complete).
+-define(COMPLETION_SERVER_OPTS, {xref_mode, modules}).
 
+rebuild_completions() ->
+    rebuild(?COMPLETION_SERVER, ?COMPLETION_SERVER_OPTS).
+
 %% Returns: [ModName] of all modules starting with Prefix.
 %% ModName = Prefix = string()
 modules(Prefix) ->
-%  FIXME: have to decide which approach is better - all loaded or all in path
-%         i, of course, prefer all in path (mbj)
-    Dirs = code:get_path(),
-    {ok, sort(foldl(fun(Dir, Acc) -> fm_dir(Dir, Prefix, Acc) end, [], Dirs))}.
-
-fm_dir(Dir, Prefix, Acc) ->
-    case file:list_dir(Dir) of
-	{ok, Files} ->
-	    Mods = [basename(F, ".beam") || F <- Files,
-					    lists:prefix(Prefix, F),
-					    lists:suffix(".beam", F)],
-	    Mods ++ Acc;
+    case  xref_q(?COMPLETION_SERVER, ?COMPLETION_SERVER_OPTS,
+                 '"~s.*" : Mod', [Prefix]) of
+	{ok, Mods} ->
+	    {ok, [atom_to_list(Mod) || Mod <- Mods]};
 	_ ->
-	    Acc
+	    {error, fmt("Can't find any matches for ~p", [Prefix])}
     end.
 
 %% Returns: [FunName] of all exported functions of Mod starting with Prefix.
 %% Mod = atom()
 %% Prefix = string()
 functions(Mod, _Prefix) ->
-%  FIXME: have to decide which approach is better - all loaded or all in path
-%         i, of course, prefer all in path (mbj)
-    case beamfile(Mod) of
-	{ok, BeamFile} ->
-	    case get_exports(BeamFile) of
-		{ok, Exports0} ->
-		    Exports = Exports0 -- [{"module_info",0},{"module_info",1}],
-		    Fns = [Fun || {Fun, _Arity} <- Exports],
-		    {ok, ordsets:to_list(ordsets:from_list(Fns))};
-		error ->
-		    {error, fmt("Can't get export list for ~p", [Mod])}
-	    end;
+    case  xref_q(?COMPLETION_SERVER, ?COMPLETION_SERVER_OPTS,
+                 "(X+B) * ~p:_/_", [Mod]) of
+	{ok, Res} ->
+	    {ok, lists:usort([atom_to_list(Fun) || {_Mod, Fun, _Arity} <- Res])};
 	_ ->
-	    {error, fmt("Can't find beam file for ~p", [Mod])}
+	    {error, fmt("Can't find module ~p", [Mod])}
     end.
 
 %% ----------------------------------------------------------------------
@@ -995,8 +985,12 @@
 %%-----------------------------------------------------------------
 %% Call graph
 %%-----------------------------------------------------------------
--define(SERVER, distel_xref).
+-define(CALL_GRAPH_SERVER, distel_call_graph).
+-define(CALL_GRAPH_SERVER_OPTS, []).
 
+rebuild_call_graph() ->
+    rebuild(?CALL_GRAPH_SERVER, ?CALL_GRAPH_SERVER_OPTS).
+
 %% Ret: [{M,F,A,Line}], M = F = binary()
 who_calls(M, F, A) ->
     [{fmt("~p", [Mod]), fmt("~p", [Fun]), Aa, Line}
@@ -1004,33 +998,41 @@
 
 %% {M,F,A} -> [{{M,F,A},Line}]
 calls_to(MFA) ->
-    ensure_started(),
-    {ok, Res} =
-        xref:q(?SERVER, string_format("(Lin)(domain (E || ~p))", [MFA])),
+    {ok, Res} =  xref_q(?CALL_GRAPH_SERVER, ?CALL_GRAPH_SERVER_OPTS,
+                        "(Lin)(domain (E || ~p))", [MFA]),
     Res.
 
 string_format(S) -> S.
 string_format(S, A) -> lists:flatten(io_lib:fwrite(S, A)).
 
-rebuild() ->
-    stop(),
-    ensure_started().
+%%-----------------------------------------------------------------
+%% Support code for completion and call graph
+%%-----------------------------------------------------------------
 
-stop() ->
-    case whereis(?SERVER) of
+rebuild(Server, Opts) ->
+    stop(Server),
+    ensure_started(Server, Opts).
+
+stop(Server) ->
+    case whereis(Server) of
         undefined -> ok;
-        _ -> xref:stop(?SERVER),
+        _ -> xref:stop(Server),
              ok
     end.
 
-ensure_started() ->
-    case whereis(?SERVER) of
+xref_q(Server, Opts, Query, Args) ->
+    ensure_started(Server, Opts),
+    xref:q(Server, string_format(Query, Args)).
+
+ensure_started(Server, Opts) ->
+    case whereis(Server) of
 	undefined ->
-            xref:start(?SERVER),
-            foreach(fun (Dir) -> xref:add_directory(?SERVER, Dir) end,
+            xref:start(Server, Opts),
+	    xref:set_default(Server, builtins, true),
+            foreach(fun (Dir) -> xref:add_directory(Server, Dir) end,
                     get_code_path());
 	_ ->
-	    xref:update(?SERVER),
+	    xref:update(Server),
             ok
     end.
 

--=-=-=
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
--=-=-=
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline

_______________________________________________
Distel-hackers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/distel-hackers

--=-=-=--