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 + -
显示快捷键?