Browse Source

Автодок: создание перечня модулей

Arthur Yefimov 2 years ago
parent
commit
eb9c94ac81

+ 45 - 10
src/Autodoc/Autodoc.Mod

@@ -11,6 +11,10 @@ CONST
 TYPE
   Module* = P.Module;
 
+VAR
+  indexTitle: ARRAY 256 OF CHAR;
+  indexComment: P.LongStr;
+
 PROCEDURE OpenFile(fname: ARRAY OF CHAR; VAR r: Files.Rider): BOOLEAN;
 VAR F: Files.File;
 BEGIN F := Files.Old(fname);
@@ -25,6 +29,10 @@ BEGIN
   IF OpenFile(in, r) THEN
     P.SetFname(in);
     module := P.ParseModule(r, err);
+    IF indexTitle[0] = 0X THEN Strings.Copy(module.name, indexTitle) END;
+    IF indexComment[0] = 0X THEN
+      Strings.Copy(module.comment, indexComment)
+    END;
     IF module # NIL THEN
       IF H.Save(module, out) THEN
         Out.String('## Created "'); Out.String(out);
@@ -69,10 +77,8 @@ BEGIN
     Strings.Append(delim, out)
   END;
   GetBaseName(in, name);
-  (*Out.String(' (name=');Out.String(name);Out.Ln;*)
   Strings.Append(name, out);
   Strings.Append('.html', out);
-  (*Out.String(in);Out.Ln;  Out.String('   -> ');Out.String(out);Out.Ln;*)
   HandleFile(in, out)
 END HandleFileToDir;
 
@@ -170,17 +176,38 @@ BEGIN Strings.Copy(s, z); ok := TRUE; ext := '.Mod';
   END
 END ParseLinkDir;
 
+PROCEDURE CreateIndex*(title, comment, out: ARRAY OF CHAR): BOOLEAN;
+VAR len: INTEGER;
+  s: ARRAY 4096 OF CHAR;
+  ok: BOOLEAN;
+BEGIN
+  Strings.Copy(out, s);
+  len := Strings.Length(s);
+  IF (len # 0) & (s[len - 1] # '/') & (s[len - 1] # '\') THEN
+    Strings.Append(delim, s)
+  END;
+  Strings.Append('index.html', s);
+
+  IF H.CreateIndex(title, comment, s) THEN
+    ok := TRUE;
+    Out.String('## Created "'); Out.String(s); Out.String('".'); Out.Ln
+  ELSE ok := FALSE
+  END
+RETURN ok END CreateIndex;
+
 PROCEDURE Do;
 VAR i, len: INTEGER;
   out, s: ARRAY 256 OF CHAR;
   fnames: ARRAY 64, 256 OF CHAR;
   fnameCount: INTEGER;
+  createIndex: BOOLEAN;
 BEGIN
   IF Args.Count = 0 THEN
     Usage
   ELSE
     out[0] := 0X; i := 1; fnameCount := 0;
-    H.ClearLinkMods;
+    indexTitle[0] := 0X; indexComment[0] := 0X;
+    H.ClearLinkMods; createIndex := TRUE;
     WHILE i <= Args.Count DO
       Args.Get(i, s);
       IF s = '-o' THEN (* Output file or dir *)
@@ -195,26 +222,34 @@ BEGIN
         P.SetDebug(TRUE)
       ELSIF (s = '--external-style') OR (s = '-e') THEN
         H.SetExternalStyle(TRUE)
+      ELSIF (s = '--no-index') OR (s = '-n') THEN
+        createIndex := FALSE
+      ELSIF (s = '--title') OR (s = '-t') THEN
+        IF i < Args.Count THEN INC(i); Args.Get(i, indexTitle); END
       ELSIF s = '--pal' THEN
         IF i < Args.Count THEN INC(i); Args.Get(i, s); H.SetPalette(s) END
       ELSIF s = '--lang' THEN (* Output language *)
         IF i < Args.Count THEN INC(i); Args.Get(i, s); H.SetLang(s) END
-      ELSE (* On of the file names with Oberon modules *)
+      ELSE (* One of the Oberon module file names *)
         IF fnameCount < LEN(fnames) THEN
-          Strings.Copy(s, fnames[fnameCount]);
-          H.AddLinkModExt(s);
-          INC(fnameCount)
+          Strings.Copy(s, fnames[fnameCount]); INC(fnameCount);
+          H.AddLinkModExt(s)
         END
       END;
       INC(i)
     END;
     len := Strings.Length(out);
-    IF (fnameCount > 1) OR
-       (len # 0) & ((out[len - 1] = '/') OR (out[len - 1] = '\')) OR
-       Dir.IsDir(out)
+    IF fnameCount = 0 THEN
+      Out.String('No files supplied.'); Out.Ln
+    ELSIF (fnameCount > 1) OR
+          (len # 0) & ((out[len - 1] = '/') OR (out[len - 1] = '\')) OR
+          Dir.IsDir(out)
     THEN (* treat "-o" parameter as directory *)
       FOR i := 0 TO fnameCount - 1 DO
         HandleFileToDir(fnames[i], out)
+      END;
+      IF createIndex & ~CreateIndex(indexTitle, indexComment, out) THEN
+        Out.String('Could not create an index file.'); Out.Ln
       END
     ELSE (* Single file given and "-o" is a file name *)
       IF out[0] = 0X THEN FnameToHtml(fnames[0], out) END;

+ 98 - 33
src/Autodoc/AutodocHtml.Mod

@@ -220,13 +220,29 @@ END WriteStyle;
 
 (** HTML Printing Procedures **)
 
-PROCEDURE PrintComment(o: P.Object; marks: BOOLEAN);
+PROCEDURE PrintComment(comment: P.LongStr; marks: BOOLEAN);
 BEGIN
   Write('<section class="comment">');
-  WriteParagraphs(o.comment, marks);
+  WriteParagraphs(comment, marks);
   WriteLn('</section>')
 END PrintComment;
 
+PROCEDURE PrintModIndex(showIndex: BOOLEAN);
+VAR i: INTEGER;
+  s: ARRAY 64 OF CHAR;
+BEGIN
+  WriteLn('<ul class="modules-index">');
+  IF showIndex THEN
+    Write('<li><a href="index.html">');
+    Lang.Get('indexLink', s); Write(s); WriteLn('</a></li>')
+  END;
+  FOR i := 0 TO linkModCount - 1 DO
+    Write('<li><a href="'); Write(linkMods[i]); Write('.html">');
+    Write(linkMods[i]); WriteLn('</a></li>')
+  END;
+  WriteLn('</ul>')
+END PrintModIndex;
+
 PROCEDURE OpenGroup(G: P.Group; ordinalConsts: BOOLEAN);
 VAR s: ARRAY 256 OF CHAR;
 BEGIN
@@ -234,7 +250,7 @@ BEGIN
   Write('<h3 class="group-title">');
   IF G.name # '-' THEN Write(G.name) END;
   WriteLn('</h3>');
-  PrintComment(G, FALSE);
+  PrintComment(G.comment, FALSE);
   IF ordinalConsts THEN
     WriteLn('<div class="ordinal-consts">');
     WriteLn('<table>');
@@ -262,26 +278,25 @@ END CloseGroup;
 PROCEDURE IsAlphanum(c: CHAR): BOOLEAN;
 RETURN P.IsLetter(c) OR P.IsDec(c) END IsAlphanum;
 
+(** First i characters of s is a module name that exists in linkMods *)
+PROCEDURE IsLinkedMod(s: ARRAY OF CHAR; len: INTEGER): BOOLEAN;
+VAR i: INTEGER;
+z: ARRAY 256 OF CHAR;
+BEGIN Strings.Extract(s, 0, len, z); i := 0;
+WHILE (i # linkModCount) & (linkMods[i] # z) DO INC(i) END
+RETURN i # linkModCount END IsLinkedMod;
+
 (** Write s, but maybe add <a href> to another module *)
 PROCEDURE PrintLink(s: ARRAY OF CHAR);
 VAR i, j, k: INTEGER;
   written: BOOLEAN;
-
-  (** First i characters of s is a module name that exists in linkMods *)
-  PROCEDURE P(s: ARRAY OF CHAR; len: INTEGER): BOOLEAN;
-  VAR i: INTEGER;
-    z: ARRAY 256 OF CHAR;
-  BEGIN Strings.Extract(s, 0, len, z); i := 0;
-    WHILE (i # linkModCount) & (linkMods[i] # z) DO INC(i) END
-  RETURN i # linkModCount END P;
-
 BEGIN written := FALSE;
   (* Find first '.', put in i *)
   i := 0; WHILE IsAlphanum(s[i]) DO INC(i) END;
   IF s[i] = '.' THEN (* First '.' found *)
     (* Find second '.', put in j *)
     j := i + 1; WHILE IsAlphanum(s[j]) DO INC(j) END;
-    IF (s[j] = 0X) & P(s, i) THEN (* No second '.', all is alphanum *)
+    IF (s[j] = 0X) & IsLinkedMod(s, i) THEN (* No second '.', all is alphanum *)
       Write('<a href="');
       FOR k := 0 TO i - 1 DO WriteChar(s[k]) END;
       Write('.html#');
@@ -292,6 +307,17 @@ BEGIN written := FALSE;
   IF ~written THEN Write(s) END
 END PrintLink;
 
+(** Prints a href to a module name. *)
+PROCEDURE PrintModLink(s: ARRAY OF CHAR);
+VAR i: INTEGER;
+BEGIN
+  i := 0; WHILE IsAlphanum(s[i]) DO INC(i) END;
+  IF (s[i] = 0X) & IsLinkedMod(s, i) THEN
+    Write('<a href="'); Write(s); Write('.html">'); Write(s); Write('</a>')
+  ELSE Write(s)
+  END
+END PrintModLink;
+
 PROCEDURE PrintIndent(n: INTEGER);
 BEGIN
   WHILE n > 0 DO Write('&nbsp; '); DEC(n) END
@@ -303,7 +329,7 @@ BEGIN
   IF I.name # I.alias THEN
     Write('<span class="alias">'); Write(I.alias); Write('</span> := ')
   END;
-  Write('<span class="name">'); Write(I.name); Write('</span></span>');
+  Write('<span class="name">'); PrintModLink(I.name); Write('</span></span>');
   IF ~isLastListItem THEN WriteLn(', ') END;
   isLastListItem := FALSE
 END PrintImport;
@@ -313,7 +339,7 @@ BEGIN
   Write('<tr><td class="name">'); Write(C.name); WriteExport(C);
   WriteLn('</td><td class="value">');
   WriteExpr(C.value); WriteLn('</td><td class="desc">');
-  PrintComment(C, FALSE); WriteLn('</td></tr>')
+  PrintComment(C.comment, FALSE); WriteLn('</td></tr>')
 END PrintOrdinalConst;
 
 PROCEDURE PrintConst(C: P.Const; indent: INTEGER; inlined: BOOLEAN);
@@ -324,7 +350,7 @@ BEGIN
   Write   ('</span>'); WriteExport(C); WriteLn(' =');
   Write('    <span class="value">'); WriteExpr(C.value); WriteLn('</span>;');
   WriteLn ('  </div>');
-  PrintComment(C, FALSE);
+  PrintComment(C.comment, FALSE);
   WriteLn ('</article>')
 END PrintConst;
 
@@ -378,7 +404,7 @@ BEGIN tmp := isLastItem; isLastItem := FALSE;
     PrintObject(v.type, indent, TRUE);
     IF ~tmp THEN Write(';') END;
     Write(' &nbsp;</span></span>');
-    PrintComment(v, TRUE);
+    PrintComment(v.comment, TRUE);
   ELSE
     Write   ('<article class="object var" id="'); Write(v.name); WriteLn('">');
     WriteLn ('  <div class="def">');
@@ -387,7 +413,7 @@ BEGIN tmp := isLastItem; isLastItem := FALSE;
     WriteLn ('    <span class="type">');
     PrintObject(v.type, indent, TRUE); WriteLn('</span>;');
     WriteLn ('  </div>');
-    PrintComment(v, FALSE);
+    PrintComment(v.comment, FALSE);
     WriteLn ('</article>')
   END
 END PrintVar;
@@ -437,7 +463,7 @@ BEGIN
     WriteLn ('    <span class="typedef">');
     PrintObject(T.base, indent, TRUE); WriteLn('</span>;');
     WriteLn ('  </div>');
-    PrintComment(T, FALSE);
+    PrintComment(T.comment, FALSE);
     WriteLn ('</article>');
   END
 END PrintType;
@@ -464,7 +490,7 @@ BEGIN
     Write(': '); PrintType(p.returnType, indent, TRUE)
   END;
   WriteLn(';</span></div>');
-  PrintComment(p, FALSE);
+  PrintComment(p.comment, FALSE);
   WriteLn('</article>')
 END PrintProcedure;
 
@@ -472,7 +498,14 @@ PROCEDURE BigTitle(text: ARRAY OF CHAR);
 BEGIN WriteLn3('<h2 class="heading">', text, '</h2>')
 END BigTitle;
 
-PROCEDURE Header(modName: ARRAY OF CHAR);
+PROCEDURE PrintModMenu(showIndex: BOOLEAN);
+BEGIN
+  WriteLn('<nav class="module-menu">');
+  PrintModIndex(showIndex);
+  WriteLn('</nav>')
+END PrintModMenu;
+
+PROCEDURE Header(modName: ARRAY OF CHAR; index: BOOLEAN);
 VAR s: ARRAY 256 OF CHAR;
 BEGIN
   WriteLn('<!DOCTYPE html>');
@@ -480,21 +513,34 @@ BEGIN
   WriteLn('<head>');
   WriteLn('<meta charset="utf-8">');
   WriteLn('<title>');
-  Lang.Get('titleBefore', s); Write(s); Write(modName);
-  Lang.Get('titleAfter', s); Write(s);
+  IF index THEN
+    Lang.Get('indexTitleBefore', s); Write(s); Write(modName);
+    Lang.Get('indexTitleAfter', s); Write(s)
+  ELSE
+    Lang.Get('titleBefore', s); Write(s); Write(modName);
+    Lang.Get('titleAfter', s); Write(s)
+  END;
   WriteLn('</title>');
-  WriteLn('<meta name="viewport" content="width=device-width,initial-scale=1.0">');
+  Write  ('<meta name="viewport" content="');
+  WriteLn('width=device-width,initial-scale=1.0">');
   WriteLn('</head>');
-  WriteLn('<body>');
+  IF index THEN WriteLn('<body class="index">') ELSE WriteLn('<body>') END;
   WriteLn('<header class="header"><div class="inner">');
-  Write('<h1>'); Lang.Get('headingBefore', s); Write(s);
+
+  Write('<h1>');
+  IF ~index THEN Lang.Get('headingBefore', s); Write(s) END;
   Write('<span class="module-name">'); Write(modName);
-  Lang.Get('headingAfter', s); Write(s);
+  IF ~index THEN Lang.Get('headingAfter', s); Write(s) END;
   Write('</span> <span class="subtitle">');
-  Lang.Get('headingSubtitle', s); Write(s);
+
+  IF index THEN Lang.Get('indexHeadingSubtitle', s); Write(s)
+  ELSE Lang.Get('headingSubtitle', s); Write(s)
+  END;
+
   WriteLn('</span></h1>');
+  IF ~index THEN PrintModMenu(TRUE) END;
   WriteLn('</div></header>');
-  WriteLn('<main class="main"><div class="inner">');
+  WriteLn('<main class="main"><div class="inner">')
 END Header;
 
 PROCEDURE PrintColorValue(s: ARRAY OF CHAR);
@@ -572,8 +618,8 @@ PROCEDURE PrintModule(M: P.Module; indent: INTEGER; inlined: BOOLEAN);
 VAR s: ARRAY 64 OF CHAR;
 BEGIN
   showExportMarks := ~M.exportedOnly;
-  Header(M.name);
-  PrintComment(M, FALSE);
+  Header(M.name, FALSE);
+  PrintComment(M.comment, FALSE);
   PrintSection(M.imports, 'import');
   PrintSection(M.consts, 'constants');
   PrintSection(M.types, 'types');
@@ -647,8 +693,7 @@ BEGIN ClearColors;
   END
 END SetPalette;
 
-(** Main procedure **)
-
+(** Main procedure *)
 PROCEDURE Save*(module: P.Module; fname: ARRAY OF CHAR): BOOLEAN;
 BEGIN
   IF palette[0] = 0X THEN SetPalette(defPal) END;
@@ -658,6 +703,26 @@ BEGIN
   Texts.Append(TX, W.buf); Texts.Close(TX, fname)
 RETURN TRUE END Save;
 
+PROCEDURE CreateIndex*(title, comment, fname: ARRAY OF CHAR): BOOLEAN;
+VAR s: ARRAY 256 OF CHAR;
+BEGIN
+  NEW(TX); Texts.Open(TX, ''); Texts.OpenWriter(W);
+  Header(title, TRUE);
+
+  Write('<h2>');
+  Lang.Get('indexHeading', s); Write(s);
+  WriteLn('</h2>');
+  PrintModIndex(FALSE);
+
+  Write('<h2>');
+  Lang.Get('overview', s); Write(s);
+  WriteLn('</h2>');
+  PrintComment(comment, FALSE);
+
+  Footer;
+  Texts.Append(TX, W.buf); Texts.Close(TX, fname)
+RETURN TRUE END CreateIndex;
+
 BEGIN
   PrintObject := PrintObject0;
   externalStyle := FALSE;

+ 6 - 0
src/Autodoc/Data/Langs/en.dat

@@ -9,9 +9,15 @@ procedures "Procedures"
 
 titleBefore ""
 titleAfter " Module Reference"
+indexTitleBefore ""
+indexTitleAfter " Reference"
+indexHeading "Modules"
 headingBefore "Module "
 headingAfter ""
 headingSubtitle "Reference"
+indexHeadingSubtitle "Library Reference"
+overview "Overview"
+indexLink "Module Index"
 
 tableColName "Name"
 tableColValue "Value"

+ 6 - 0
src/Autodoc/Data/Langs/ru.dat

@@ -9,9 +9,15 @@ procedures "Процедуры"
 
 titleBefore ""
 titleAfter " &mdash; справка к модулю"
+indexTitleBefore ""
+indexTitleAfter " &mdash; документация"
+indexHeading "Модули"
 headingBefore "Модуль "
 headingAfter ""
 headingSubtitle "Справочный лист"
+indexHeadingSubtitle "Документация к библиотеке"
+overview "Введение"
+indexLink "Список модулей"
 
 tableColName "Имя"
 tableColValue "Значение"

+ 31 - 1
src/Autodoc/Data/style.css

@@ -42,13 +42,17 @@ a:hover {
 }
 
 .header {
-  padding: 30px 0;
+  padding: 30px 0 0;
   background: #12365D;
   background: var(--head-bg);
   color: #93B2D3;
   color: var(--head2-bg);
 }
 
+.index .header {
+  padding-bottom: 30px;
+}
+
 .header h1 .module-name {
   color: #FFF;
   color: var(--head-fg);
@@ -97,6 +101,32 @@ h2, h3, h4, h5, h6 {
   box-shadow: 6px 6px 1px var(--box-bg);
 }
 
+.module-menu {
+  padding: 6px 0;
+}
+
+.module-menu ul {
+  list-style: none;
+  margin: 0;
+  padding: 0;
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: flex-end;
+  gap: 10px;
+}
+
+.module-menu a {
+  display: block;
+  background: var(--head2-fg);
+  color: var(--head-fg);
+  padding: 4px 8px;
+}
+
+.module-menu a:hover {
+  background: var(--head2-bg);
+  color: var(--title-bg);
+}
+
 .group-title {
   padding: 0 2px;
   margin: 18px 0 8px;

+ 1 - 1
src/Autodoc/Makefile

@@ -5,7 +5,7 @@ Autodoc: Autodoc.Mod AutodocParser.Mod AutodocHtml.Mod
 	fob Autodoc.Mod
 
 run: Autodoc
-	clear;./Autodoc -o Test Test/A.Mod -a
+	clear;./Autodoc -o Test Test/*.Mod -a -t "Библиотека модулей"
 
 clean:
 	@rm -rf _Build Autodoc