aboutsummaryrefslogtreecommitdiffstats
path: root/lib/edoc/src/edoc_refs.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/edoc/src/edoc_refs.erl')
-rw-r--r--lib/edoc/src/edoc_refs.erl217
1 files changed, 217 insertions, 0 deletions
diff --git a/lib/edoc/src/edoc_refs.erl b/lib/edoc/src/edoc_refs.erl
new file mode 100644
index 0000000000..c2146bbe02
--- /dev/null
+++ b/lib/edoc/src/edoc_refs.erl
@@ -0,0 +1,217 @@
+%% =====================================================================
+%% This library is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU Lesser General Public License as
+%% published by the Free Software Foundation; either version 2 of the
+%% License, or (at your option) any later version.
+%%
+%% This library is distributed in the hope that it will be useful, but
+%% WITHOUT ANY WARRANTY; without even the implied warranty of
+%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+%% Lesser General Public License for more details.
+%%
+%% You should have received a copy of the GNU Lesser General Public
+%% License along with this library; if not, write to the Free Software
+%% Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+%% USA
+%%
+%% $Id$
+%%
+%% @private
+%% @copyright 2003 Richard Carlsson
+%% @author Richard Carlsson <[email protected]>
+%% @see edoc
+%% @see edoc_parse_ref
+%% @end
+%% =====================================================================
+
+%% @doc Representation and handling of EDoc object references. See
+%% {@link edoc_parse_ref} for more details.
+
+-module(edoc_refs).
+
+-export([app/1, app/2, package/1, module/1, module/2, module/3,
+ function/2, function/3, function/4, type/1, type/2, type/3,
+ to_string/1, to_label/1, get_uri/2, is_top/2,
+ relative_module_path/2, relative_package_path/2]).
+
+-import(edoc_lib, [join_uri/2, escape_uri/1]).
+
+-include("edoc.hrl").
+
+-define(INDEX_FILE, "index.html").
+
+
+%% Creating references:
+
+app(App) ->
+ {app, App}.
+
+app(App, Ref) ->
+ {app, App, Ref}.
+
+module(M) ->
+ {module, M}.
+
+module(M, Ref) ->
+ {module, M, Ref}.
+
+module(App, M, Ref) ->
+ app(App, module(M, Ref)).
+
+package(P) ->
+ {package, P}.
+
+function(F, A) ->
+ {function, F, A}.
+
+function(M, F, A) ->
+ module(M, function(F, A)).
+
+function(App, M, F, A) ->
+ module(App, M, function(F, A)).
+
+type(T) ->
+ {type, T}.
+
+type(M, T) ->
+ module(M, type(T)).
+
+type(App, M, T) ->
+ module(App, M, type(T)).
+
+
+%% Creating a print string for a reference
+
+to_string({app, A}) ->
+ "//" ++ atom_to_list(A);
+to_string({app, A, Ref}) ->
+ "//" ++ atom_to_list(A) ++ "/" ++ to_string(Ref);
+to_string({module, M}) ->
+ atom_to_list(M) ;
+to_string({module, M, Ref}) ->
+ atom_to_list(M) ++ ":" ++ to_string(Ref);
+to_string({package, P}) ->
+ atom_to_list(P) ++ ".*";
+to_string({function, F, A}) ->
+ atom_to_list(F) ++ "/" ++ integer_to_list(A);
+to_string({type, T}) ->
+ atom_to_list(T) ++ "()".
+
+
+%% Creating URIs and anchors.
+
+to_label({function, F, A}) ->
+ escape_uri(atom_to_list(F)) ++ "-" ++ integer_to_list(A);
+to_label({type, T}) ->
+ "type-" ++ escape_uri(atom_to_list(T)).
+
+get_uri({app, App}, Env) ->
+ join_uri(app_ref(App, Env), ?INDEX_FILE);
+get_uri({app, App, Ref}, Env) ->
+ app_ref(App, Ref, Env);
+get_uri({module, M, Ref}, Env) ->
+ module_ref(M, Env) ++ "#" ++ to_label(Ref);
+get_uri({module, M}, Env) ->
+ module_ref(M, Env);
+get_uri({package, P}, Env) ->
+ package_ref(P, Env);
+get_uri(Ref, _Env) ->
+ "#" ++ to_label(Ref).
+
+abs_uri({module, M}, Env) ->
+ module_absref(M, Env);
+abs_uri({module, M, Ref}, Env) ->
+ module_absref(M, Env) ++ "#" ++ to_label(Ref);
+abs_uri({package, P}, Env) ->
+ package_absref(P, Env).
+
+module_ref(M, Env) ->
+ case (Env#env.modules)(M) of
+ "" ->
+ File = packages:last(M) ++ Env#env.file_suffix,
+ Path = relative_module_path(M, Env#env.package),
+ join_uri(Path, escape_uri(File));
+ Base ->
+ join_uri(Base, module_absref(M, Env))
+ end.
+
+module_absref(M, Env) ->
+ join_segments(packages:split(M))
+ ++ escape_uri(Env#env.file_suffix).
+
+package_ref(P, Env) ->
+ case (Env#env.packages)(P) of
+ "" ->
+ join_uri(relative_package_path(P, Env#env.package),
+ escape_uri(Env#env.package_summary));
+ Base ->
+ join_uri(Base, package_absref(P, Env))
+ end.
+
+package_absref(P, Env) ->
+ join_uri(join_segments(packages:split(P)),
+ escape_uri(Env#env.package_summary)).
+
+app_ref(A, Env) ->
+ case (Env#env.apps)(A) of
+ "" ->
+ join_uri(Env#env.app_default,
+ join_uri(escape_uri(atom_to_list(A)), ?EDOC_DIR));
+ Base ->
+ Base
+ end.
+
+app_ref(A, Ref, Env) ->
+ join_uri(app_ref(A, Env), abs_uri(Ref, Env)).
+
+is_top({app, _App}, _Env) ->
+ true;
+is_top(_Ref, _Env) ->
+ false.
+
+%% Each segment of a path must be separately escaped before joining.
+
+join_segments([S]) ->
+ escape_uri(S);
+join_segments([S | Ss]) ->
+ join_uri(escape_uri(S), join_segments(Ss)).
+
+%% 'From' is always the "current package" here:
+
+%% The empty string is returned if the To module has only one segment,
+%% implying a local reference.
+
+relative_module_path(To, From) ->
+ case first(packages:split(To)) of
+ [] -> "";
+ P -> relative_path(P, packages:split(From))
+ end.
+
+relative_package_path(To, From) ->
+ relative_path(packages:split(To), packages:split(From)).
+
+%% This takes two lists of path segments (From, To). Note that an empty
+%% string will be returned if the paths are the same. Empty leading
+%% segments are stripped from both paths.
+
+relative_path(Ts, ["" | Fs]) ->
+ relative_path(Ts, Fs);
+relative_path(["" | Ts], Fs) ->
+ relative_path(Ts, Fs);
+relative_path(Ts, Fs) ->
+ relative_path_1(Ts, Fs).
+
+relative_path_1([T | Ts], [F | Fs]) when F == T ->
+ relative_path_1(Ts, Fs);
+relative_path_1(Ts, Fs) ->
+ relative_path_2(Fs, Ts).
+
+relative_path_2([_F | Fs], Ts) ->
+ relative_path_2(Fs, [".." | Ts]);
+relative_path_2([], []) ->
+ "";
+relative_path_2([], Ts) ->
+ join_segments(Ts).
+
+first([H | T]) when T /= [] -> [H | first(T)];
+first(_) -> [].