![JAR search and dependency download from the Maven repository](/logo.png)
com.github.jlangch.venice.impl.docgen.cheatsheet.DocItemBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of venice Show documentation
Show all versions of venice Show documentation
Venice, a Lisp implemented in Java
/* __ __ _
* \ \ / /__ _ __ (_) ___ ___
* \ \/ / _ \ '_ \| |/ __/ _ \
* \ / __/ | | | | (_| __/
* \/ \___|_| |_|_|\___\___|
*
*
* Copyright 2017-2024 Venice
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.github.jlangch.venice.impl.docgen.cheatsheet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import com.github.jlangch.venice.Parameters;
import com.github.jlangch.venice.Venice;
import com.github.jlangch.venice.impl.docgen.util.CodeHighlighter;
import com.github.jlangch.venice.impl.env.Env;
import com.github.jlangch.venice.impl.specialforms.SpecialFormsDoc;
import com.github.jlangch.venice.impl.types.Constants;
import com.github.jlangch.venice.impl.types.VncFunction;
import com.github.jlangch.venice.impl.types.VncSpecialForm;
import com.github.jlangch.venice.impl.types.VncString;
import com.github.jlangch.venice.impl.types.VncSymbol;
import com.github.jlangch.venice.impl.types.VncVal;
import com.github.jlangch.venice.impl.types.collections.VncList;
import com.github.jlangch.venice.impl.types.custom.VncProtocol;
import com.github.jlangch.venice.impl.types.util.Types;
import com.github.jlangch.venice.impl.util.StringUtil;
import com.github.jlangch.venice.impl.util.markdown.Markdown;
import com.github.jlangch.venice.util.CapturingPrintStream;
public class DocItemBuilder {
public DocItemBuilder(
final Env env,
final CodeHighlighter codeHighlighter,
final List preloadedModules,
final boolean runExamples
) {
this.env = env;
this.codeHighlighter = codeHighlighter;
this.runExamples = runExamples;
this.preloadedModules.addAll(preloadedModules);
}
public DocItem getDocItem(final String name) {
return getDocItem(name, true, false);
}
public DocItem getDocItem(final String name, final boolean runExamples) {
return getDocItem(name, runExamples, false);
}
public DocItem getDocItem(final String name, final boolean runExamples, final boolean catchEx) {
final DocItem item = docItems.get(name);
if (item != null) {
return item;
}
else {
final DocItem item_ = getDocItem_(name, runExamples, catchEx);
if (item_ != null) {
docItems.put(name, item_);
}
return item_;
}
}
public String id() {
return idgen.id();
}
public String id(final String name) {
return idgen.id(name);
}
private DocItem getDocItem_(final String name, final boolean runExamples, final boolean catchEx) {
final VncProtocol crossRefProtocol = findProtocol(name);
if (crossRefProtocol != null) {
final String fnDescr = crossRefProtocol.getDoc() == Constants.Nil
? ""
: ((VncString)crossRefProtocol.getDoc()).getValue();
final String descr = MARKDOWN_FN_DESCR ? null : fnDescr;
final String descrTextStyled = MARKDOWN_FN_DESCR
? Markdown.parse(fnDescr).renderToText(120)
: null;
final String descrXmlStyled = MARKDOWN_FN_DESCR
? Markdown.parse(fnDescr).renderToHtml()
: null;
return new DocItem(
name,
new ArrayList<>(),
descr,
descrTextStyled,
descrXmlStyled,
runExamples(
name,
toStringList(crossRefProtocol.getExamples(), name, ":examples"),
runExamples,
catchEx),
createCrossRefs(name, crossRefProtocol.getSeeAlso()),
id(name));
}
else {
final VncFunction fn = findFunction(name);
if (fn != null) {
final String fnDescr = fn.getDoc() == Constants.Nil
? ""
: ((VncString)fn.getDoc()).getValue();
final String descr = MARKDOWN_FN_DESCR ? null : fnDescr;
final String descrTextStyled = MARKDOWN_FN_DESCR
? Markdown.parse(fnDescr).renderToText(120)
: null;
final String descrXmlStyled = MARKDOWN_FN_DESCR
? Markdown.parse(fnDescr).renderToHtml()
: null;
return new DocItem(
name,
toStringList(fn.getArgLists(), name, ":arglists"),
descr,
descrTextStyled,
descrXmlStyled,
runExamples(
name,
toStringList(fn.getExamples(), name, ":examples"),
runExamples,
catchEx),
createCrossRefs(name, fn.getSeeAlso()),
id(name));
}
else {
final VncSpecialForm sf = findSpecialForm(name);
if (sf != null) {
final String fnDescr = sf.getDoc() == Constants.Nil
? ""
: ((VncString)sf.getDoc()).getValue();
final String descr = MARKDOWN_FN_DESCR ? null : fnDescr;
final String descrTextStyled = MARKDOWN_FN_DESCR
? Markdown.parse(fnDescr).renderToText(120)
: null;
final String descrXmlStyled = MARKDOWN_FN_DESCR
? Markdown.parse(fnDescr).renderToHtml()
: null;
return new DocItem(
name,
toStringList(sf.getArgLists(), name, ":arglists"),
descr,
descrTextStyled,
descrXmlStyled,
runExamples(
name,
toStringList(sf.getExamples(), name, ":examples"),
runExamples,
catchEx),
createCrossRefs(name, sf.getSeeAlso()),
id(name));
}
else {
throw new RuntimeException(String.format("Unknown doc function %s", name));
}
}
}
}
private List runExamples(
final String name,
final List examples,
final boolean run,
final boolean catchEx
) {
if (runExamples) {
final Venice runner = new Venice();
final AtomicLong exampleNr = new AtomicLong(0);
try {
return examples
.stream()
.filter(e -> !StringUtil.isEmpty(e))
.map(e -> runExample(
runner,
exampleNr.incrementAndGet(),
name,
e,
run,
catchEx))
.collect(Collectors.toList());
}
catch(RuntimeException ex) {
throw new RuntimeException(
String.format(
"Failed to run examples #%d (of %d) for %s",
exampleNr.get(), examples.size(), name),
ex);
}
}
else {
return EMPTY_EXAMPLES;
}
}
private ExampleOutput runExample(
final Venice runner,
final long exampleNr,
final String name,
final String example,
final boolean run,
final boolean catchEx
) {
final String exampleHighlighted = codeHighlighter.highlight(example);
if (run) {
final CapturingPrintStream ps_out = new CapturingPrintStream();
final CapturingPrintStream ps_err = new CapturingPrintStream();
try {
final String modules = preloadedModules
.stream()
.map(m -> " (load-module :" + m + ")")
.collect(Collectors.joining("\n"));
final String script = "(do \n" + modules + "\n\n (pr-str " + example + "\n))";
final String result = (String)runner.eval(
"example",
script,
Parameters.of(
"*out*", ps_out,
"*err*", ps_err));
return new ExampleOutput(
name, example, exampleHighlighted,
ps_out.getOutput(), ps_err.getOutput(), result);
}
catch(RuntimeException ex) {
if (catchEx) {
return new ExampleOutput(
name, example, exampleHighlighted,
ps_out.getOutput(), ps_err.getOutput(), ex);
}
else {
throw new RuntimeException(
String.format("Failed to run example #%d for '%s'", exampleNr, name),
ex);
}
}
}
else {
return new ExampleOutput(name, example, exampleHighlighted);
}
}
private VncFunction findFunction(final String name) {
// Special forms
final VncFunction fn = (VncFunction)SpecialFormsDoc.ns.get(new VncSymbol(name));
if (fn != null) {
return fn;
}
// functions & macros
final VncVal val = env.getOrNil(new VncSymbol(name));
return Types.isVncFunction(val) ? (VncFunction)val : null;
}
private VncSpecialForm findSpecialForm(final String name) {
final VncVal val = env.getOrNil(new VncSymbol(name));
return Types.isVncSpecialForm(val) ? (VncSpecialForm)val : null;
}
private VncProtocol findProtocol(final String name) {
final VncVal val = env.getOrNil(new VncSymbol(name));
return val instanceof VncProtocol ? (VncProtocol)val : null;
}
private List createCrossRefs(final String parentName, final VncList seeAlso) {
final List crossRefs = new ArrayList<>();
seeAlso.forEach(v -> {
final String crossRefName = ((VncString)v).getValue();
final VncProtocol crossRefProtocol = findProtocol(crossRefName);
if (crossRefProtocol != null) {
String doc = crossRefProtocol.getDoc() == Constants.Nil
? null
: ((VncString)crossRefProtocol.getDoc()).getValue();
if (doc != null) {
crossRefs.add(
createCrossRef(crossRefName, getCrossRefDescr(doc)));
}
}
else {
final VncFunction crossRefFn = findFunction(crossRefName);
if (crossRefFn != null) {
String doc = crossRefFn.getDoc() == Constants.Nil
? null
: ((VncString)crossRefFn.getDoc()).getValue();
if (doc != null) {
crossRefs.add(
createCrossRef(crossRefName, getCrossRefDescr(doc)));
}
}
else {
final VncSpecialForm crossRefSf = findSpecialForm(crossRefName);
if (crossRefSf != null) {
String doc = crossRefSf.getDoc() == Constants.Nil
? null
: ((VncString)crossRefSf.getDoc()).getValue();
if (doc != null) {
crossRefs.add(
createCrossRef(crossRefName, getCrossRefDescr(doc)));
}
}
else {
throw new RuntimeException(String.format(
"Missing cross reference function %s -> %s",
parentName,
crossRefName));
}
}
}
});
return crossRefs;
}
private String getCrossRefDescr(final String descr) {
String crossRefDescr = Markdown.parse(descr).renderToText(CROSSREF_MAX_LEN * 2);
int posLF = crossRefDescr.indexOf('\n');
// the crossref description text is built from the first line only
String s = (posLF == -1) ? crossRefDescr.trim() : crossRefDescr.substring(0, posLF).trim();
// limit to at most CROSSREF_MAX_LEN chars
if (s.length() > CROSSREF_MAX_LEN) {
// do not cut in the middle of a word, cut at the first space in the last 15
// characters of the description, if no space is found remove the last 5 chars
// to get space for "..." marker
final int spacePos = s.indexOf(' ', CROSSREF_MAX_LEN - 15);
s = (spacePos != -1)
? s.substring(0, spacePos)
: s.substring(0, CROSSREF_MAX_LEN - 5).trim();
if (!s.endsWith(".")) {
s = s + " ...";
}
}
return s;
}
private CrossRef createCrossRef(final String name, final String descr) {
return new CrossRef(name, id(name), descr);
}
private List toStringList(final VncList list, final String name, final String helpType) {
final List tmpList = new ArrayList<>();
int index = 0;
for(VncVal item : list.getJavaList()) {
if (item instanceof VncString) {
tmpList.add(((VncString)item).getValue());
}
else {
throw new RuntimeException(
String.format(
"Failed on item '%s' (at index %d) while processing %s. " +
"Expected an item of type :core/string but got %s (%s)",
name,
index,
helpType,
item.getType().toString(true),
StringUtil.truncate(item.toString(true), 20, "...")));
}
index++;
}
return tmpList;
}
private static final boolean MARKDOWN_FN_DESCR = true;
private static final List EMPTY_EXAMPLES =
Collections.unmodifiableList(new ArrayList<>());
private static final int CROSSREF_MAX_LEN = 145;
private final Env env;
private final boolean runExamples;
private final List preloadedModules = new ArrayList<>();
private final Map docItems = new HashMap<>();
private final CodeHighlighter codeHighlighter;
private final IdGen idgen = new IdGen();
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy