otpsgml_layout.erl
来自「OTP是开放电信平台的简称」· ERL 代码 · 共 854 行 · 第 1/2 页
ERL
854 行
%% =====================================================================%% 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$%%%% @author Richard Carlsson <richardc@csd.uu.se>%% @author Kenneth Lundin <kenneth@erix.ericsson.se>%% @copyright 2001-2004 Richard Carlsson%% @see edoc_layout%% @end%% =====================================================================%% @doc The OTP SGML layout module for EDoc. See the module {@link edoc}%% for details on usage.%% Note that this is written so that it is *not* depending on edoc.hrl!-module(otpsgml_layout).-export([module/2, package/2, overview/2,type/1]).-import(edoc_report, [report/2]).-include("xmerl.hrl").-define(SGML_EXPORT, xmerl_otpsgml).-define(DEFAULT_XML_EXPORT, ?SGML_EXPORT).-define(STYLESHEET, "stylesheet.css").-define(NL, "\n").-define(DESCRIPTION_TITLE, "Description").-define(DESCRIPTION_LABEL, "description").-define(DATA_TYPES_TITLE, "Data Types").-define(DATA_TYPES_LABEL, "types").-define(FUNCTION_INDEX_TITLE, "Function Index").-define(FUNCTION_INDEX_LABEL, "index").-define(FUNCTIONS_TITLE, "Function Details").-define(FUNCTIONS_LABEL, "functions").%% @doc The layout function.%%%% Options:%% <dl>%% <dt>{@type {index_columns, integer()@}}%% </dt>%% <dd>Specifies the number of column pairs used for the function%% index tables. The default value is 1.%% </dd>%% <dt>{@type {stylesheet, string()@}}%% </dt>%% <dd>Specifies the URI used for referencing the stylesheet. The%% default value is `"stylesheet.css"'. If an empty string is%% specified, no stylesheet reference will be generated.%% </dd>%% <dt>{@type {xml_export, Module::atom()@}}%% </dt>%% <dd>Specifies an {@link //xmerl. `xmerl'} callback module to be%% used for exporting the documentation. See {@link%% //xmerl/xmerl:export_simple/3} for details.%% </dd>%% </dl>%%%% @see edoc:layout/2-record(opts, {root, stylesheet, index_columns}).module(Element, Options) -> XML = layout_module(Element, init_opts(Element, Options)), Export = proplists:get_value(xml_export, Options, ?DEFAULT_XML_EXPORT), xmerl:export_simple([XML], Export, []).% Put layout options in a data structure for easier access.init_opts(Element, Options) -> R = #opts{root = get_attrval(root, Element), index_columns = proplists:get_value(index_columns, Options, 1) }, case proplists:get_value(stylesheet, Options) of undefined -> S = edoc_lib:join_uri(R#opts.root, ?STYLESHEET), R#opts{stylesheet = S}; "" -> R; % don't use any stylesheet S when is_list(S) -> R#opts{stylesheet = S}; _ -> report("bad value for option `stylesheet'.", []), exit(error) end.%% =====================================================================%% XML-BASED LAYOUT ENGINE%% =====================================================================%% We assume that we have expanded XML data.%% <!ELEMENT module (moduleName, moduleFullName, behaviour*, description?,%% author*, version?, since?, copyright?, deprecated?,%% see*, reference*, typedecls?, functions)>%% <!ATTLIST module%% root CDATA #IMPLIED>%% <!ELEMENT moduleName (#PCDATA)>%% <!ELEMENT moduleFullName (#PCDATA)>%% <!ELEMENT behaviour (#PCDATA)>%% <!ATTLIST behaviour%% href CDATA #IMPLIED>%% <!ELEMENT description (briefDescription, fullDescription?)>%% <!ELEMENT briefDescription (#PCDATA)>%% <!ELEMENT fullDescription (#PCDATA)>%% <!ELEMENT author EMPTY>%% <!ATTLIST author%% name CDATA #REQUIRED%% email CDATA #IMPLIED%% website CDATA #IMPLIED>%% <!ELEMENT version (#PCDATA)>%% <!ELEMENT since (#PCDATA)>%% <!ELEMENT copyright (#PCDATA)>%% <!ELEMENT deprecated (description)>%% <!ELEMENT see (#PCDATA)>%% <!ATTLIST see%% name CDATA #REQUIRED%% href CDATA #IMPLIED>%% <!ELEMENT reference (#PCDATA)>%% <!ELEMENT typedecls (typedecl+)>%% <!ELEMENT functions (function+)>layout_module(#xmlElement{name = module, content = Es}=E, _Opts) -> Name = get_attrval(name, E), Desc = get_content(description, Es), ShortDesc = get_content(briefDescription, Desc), FullDesc = get_content(fullDescription, Desc), Functions = [E || E <- get_content(functions, Es)], SortedFs = lists:sort([{function_name(E), E} || E <- Functions]), Types = get_content(typedecls, Es), SortedTs = lists:sort([{type_name(E), E} || E <- Types]), Header = {header, [ ?NL,{title, [Name]}, ?NL,{prepared, [""]}, ?NL,{responsible, [""]}, ?NL,{docno, ["1"]}, ?NL,{approved, [""]}, ?NL,{checked, [""]}, ?NL,{date, [""]}, ?NL,{rev, ["A"]}, ?NL,{file, [Name++".sgml"]} ]}, Module = {module, [Name]}, ModuleSummary = {modulesummary, ShortDesc}, {Short,Long} = find_first_p(FullDesc,[]), Description = {description, [?NL,{p,Short}|Long]++[?NL|types(SortedTs)]}, Funcs = functions(SortedFs), Authors = {authors, authors(Es)}, See = sees1(Es), {erlref, [ ?NL,Header, ?NL,Module, ?NL,ModuleSummary, ?NL,Description, ?NL,Funcs, ?NL,See, ?NL,Authors ] }.stylesheet(Opts) -> case Opts#opts.stylesheet of undefined -> []; CSS -> [{link, [{rel, "stylesheet"}, {type, "text/css"}, {href, CSS}], []}, ?NL] end.% doc_index(FullDesc, Functions, Types) ->% case doc_index_rows(FullDesc, Functions, Types) of% [] -> [];% Rs ->% [{ul, [{li, [{a, [{href, local_label(R)}], [T]}]}% || {T, R} <- Rs]}]% end.% doc_index_rows(FullDesc, Functions, Types) ->% (if FullDesc == [] -> [];% true -> [{?DESCRIPTION_TITLE, ?DESCRIPTION_LABEL}]% end% ++ if Types == [] -> [];% true -> [{?DATA_TYPES_TITLE, ?DATA_TYPES_LABEL}]% end% ++ if Functions == [] -> [];% true -> [{?FUNCTION_INDEX_TITLE, ?FUNCTION_INDEX_LABEL},% {?FUNCTIONS_TITLE, ?FUNCTIONS_LABEL}]% end).% function_index(Fs, Cols) ->% case function_index_rows(Fs, Cols, []) of% [] -> [];% Rows ->% [?NL,% {h2, [{a, [{name, ?FUNCTION_INDEX_LABEL}],% [?FUNCTION_INDEX_TITLE]}]},% ?NL,% {table, [{width, "100%"}, {border, 1}], Rows},% ?NL]% end.% function_index_rows(Fs, Cols, Title) ->% Rows = (length(Fs) + (Cols - 1)) div Cols,% (if Title == [] -> [];% true -> [{tr, [{th, [{colspan, Cols * 2}, {align, left}],% [Title]}]},% ?NL]% end% ++ lists:flatmap(fun index_row/1,% edoc_lib:transpose(edoc_lib:segment(Fs, Rows)))).% index_row(Fs) ->% [{tr, lists:flatmap(fun index_col/1, Fs)}, ?NL].% index_col({Name, F=#xmlElement{content = Es}}) ->% [{td, [{valign, "top"}], label_href([Name], F)},% {td, index_desc(Es)}].index_desc(Es) -> Desc = get_content(description, Es), case get_content(briefDescription, Desc) of [] -> equiv(Es); % no description at all if no equiv ShortDesc -> ShortDesc end.% label_href(Content, F) ->% case get_attrval(label, F) of% "" -> Content;% Ref -> [{a, [{href, local_label(Ref)}], Content}]% end.%% <!ELEMENT function (args, typespec?, equiv?, description?, since?,%% deprecated?, see*)>%% <!ATTLIST function%% name CDATA #REQUIRED%% arity CDATA #REQUIRED%% exported NMTOKEN(yes | no) #REQUIRED%% label CDATA #IMPLIED>%% <!ELEMENT args (arg*)>%% <!ELEMENT arg description?>%% <!ATTLIST arg name CDATA #REQUIRED>%% <!ELEMENT equiv (expr, see?)>%% <!ELEMENT expr (#PCDATA)>% functions(Fs) ->% Es = lists:flatmap(fun ({Name, E}) -> function(Name, E) end, Fs),% if Es == [] -> [];% true ->% [?NL,% {h2, [{a, [{name, ?FUNCTIONS_LABEL}], [?FUNCTIONS_TITLE]}]},% ?NL | Es]% end.functions(Fs) -> Es = lists:flatmap(fun ({Name, E}) -> function(Name, E) end, Fs), if Es == [] -> []; true -> {funcs, Es} end.% is_exported(E) ->% case get_attrval(exported, E) of% "yes" -> true;% _ -> false% end.% function(Name, E=#xmlElement{content = Es}) ->% ([?NL, {h3, label_anchor([Name], E)}, ?NL]% ++ case typespec(get_content(typespec, Es)) of% [] ->% signature(get_content(arguments, Es),% get_text(functionName, Es));% Spec -> Spec% end% ++ equiv(Es)% ++ deprecated(Es, "function")% ++ fulldesc(Es)% ++ since(Es)% ++ sees(Es)).function(_Name, E=#xmlElement{content = Es}) -> TypeSpec = get_content(typespec, Es), [?NL,{func, [ ?NL, {name, % case typespec(get_content(typespec, Es)) of case funcheader(TypeSpec) of [] -> signature(get_content(args, Es), get_attrval(name, E)); Spec -> Spec end }, ?NL,{fsummary, fsummary(Es)},% ?NL,{type, local_types(TypeSpec)}, ?NL,local_types(TypeSpec), ?NL,{desc, label_anchor(E)++fulldesc(Es)++sees(Es)} ]}].fsummary([]) -> ["\s"];fsummary(Es) -> Desc = get_content(description, Es), case get_content(briefDescription, Desc) of [] -> fsummary_equiv(Es); % no description at all if no equiv ShortDesc -> ShortDesc end.fsummary_equiv(Es) -> case get_content(equiv, Es) of [] -> ["\s"]; Es1 -> case get_content(expr, Es1) of [] -> ["\s"]; [Expr] -> ["Equivalent to ", Expr, ".",?NL] end end.function_name(E) -> get_attrval(name, E) ++ "/" ++ get_attrval(arity, E).label_anchor(E) -> case get_attrval(label, E) of "" -> []; Ref -> [{marker, [{id, Ref}],[]},?NL] end.label_anchor(Content, E) -> case get_attrval(label, E) of "" -> Content; Ref -> {p,[{marker, [{id, Ref}],[]}, {em, Content}]} end.%% <!ELEMENT args (arg*)>%% <!ELEMENT arg (argName, description?)>%% <!ELEMENT argName (#PCDATA)>%% This is currently only done for functions without type spec.signature(Es, Name) -> % [{tt, [Name, "("] ++ seq(fun arg/1, Es) ++ [") -> term()", ?NL]}]. [Name, "("] ++ seq(fun arg/1, Es) ++ [") -> term()", ?NL].arg(#xmlElement{content = Es}) -> [get_text(argName, Es)].%% <!ELEMENT typespec (erlangName, type, localdef*)>% typespec([]) -> [];% typespec(Es) ->% [{p, ([{tt, ([t_name(get_elem(qualifiedName, Es))]% ++ t_type(get_content(type, Es)))}]% ++ local_defs(get_elem(definition, Es)))},% ?NL].funcheader([]) -> [];funcheader(Es) -> [t_name(get_elem(erlangName, Es))] ++ t_utype(get_elem(type, Es)).local_types([]) -> [];local_types(Es) -> local_defs2(get_elem(localdef, Es)).local_defs2([]) -> [];local_defs2(Es) -> {type,[?NL | [{v, localdef(E)} || E <- Es]]}.%% <!ELEMENT typedecl (typedef, description?)>%% <!ELEMENT typedef (erlangName, argtypes, type?, localdef*)>types([]) -> [];types(Ts) -> Es = lists:flatmap(fun ({Name, E}) -> typedecl(Name, E) end, Ts), [?NL,% {h2, [{a, [{name, ?DATA_TYPES_LABEL}],% [?DATA_TYPES_TITLE]}]},% ?NL | Es] {p,[{marker, [{id, ?DATA_TYPES_LABEL}],[]}, {em,[?DATA_TYPES_TITLE]}]}, ?NL, {taglist,[?NL|Es]}].%%type(Name, E=#xmlElement{content = Es}) ->%% ([?NL, {h3, label_anchor([Name, "()"], E)}, ?NL]%% ++ [{p, typedef(get_content(typedef, Es))}, ?NL]%% ++ fulldesc(Es)).typedecl(_Name, #xmlElement{content = Es}) -> [{tag, typedef(get_content(typedef, Es))},?NL,{item,fulldesc(Es)},?NL].type_name(#xmlElement{content = Es}) -> t_name(get_elem(erlangName, get_content(typedef, Es))).typedef(Es) -> Name = ([t_name(get_elem(erlangName, Es)), "("] ++ seq(fun t_utype_elem/1, get_content(argtypes, Es), [")"])), (case get_elem(type, Es) of
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?