Skip to content

Commit

Permalink
Show filtered builtins documentation
Browse files Browse the repository at this point in the history
Also allows links to the builtins from autocomplete and signature
help where documentation is available.
  • Loading branch information
microbit-robert committed Apr 22, 2024
1 parent 027bb24 commit 5c239cc
Show file tree
Hide file tree
Showing 18 changed files with 148 additions and 56 deletions.
21 changes: 21 additions & 0 deletions src/documentation/api/apidocs-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,24 @@ export const moduleAndApiFromId = (id: string) => {
apiId,
};
};

export const filterOutUndocumentedBuiltins = (input: ApiDocsContent) => {
const recursiveFilter = (
entries: ApiDocsEntry[] | undefined
): ApiDocsEntry[] | undefined => {
if (!entries) {
return;
}
return entries.filter((entry) => {
const hasDocstring = !!entry.docString;
if (hasDocstring) {
entry.children = recursiveFilter(entry.children);
}
return hasDocstring;
});
};

input.content.builtins.children = recursiveFilter(
input.content.builtins.children
);
};
6 changes: 5 additions & 1 deletion src/documentation/documentation-hooks.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import { apiDocs, ApiDocsContent } from "../language-server/apidocs";
import { useLanguageServerClient } from "../language-server/language-server-hooks";
import { useLogging } from "../logging/logging-hooks";
import { useSettings } from "../settings/settings";
import { pullModulesToTop } from "./api/apidocs-util";
import {
filterOutUndocumentedBuiltins,
pullModulesToTop,
} from "./api/apidocs-util";
import dragImage from "./drag-image.svg";
import { fetchIdeas } from "./ideas/content";
import { Idea } from "./ideas/model";
Expand Down Expand Up @@ -72,6 +75,7 @@ const useApiDocumentation = (): ApiDocsContent | undefined => {
if (client) {
const docs = await apiDocs(client);
pullModulesToTop(docs);
filterOutUndocumentedBuiltins(docs);
if (!ignore) {
setApiDocs(docs);
}
Expand Down
38 changes: 34 additions & 4 deletions src/editor/codemirror/CodeMirror.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
lineNumbers,
ViewUpdate,
} from "@codemirror/view";
import { useEffect, useMemo, useRef } from "react";
import { useCallback, useEffect, useMemo, useRef } from "react";
import { useIntl } from "react-intl";
import { lineNumFromUint8Array } from "../../common/text-util";
import useActionFeedback from "../../common/use-action-feedback";
Expand Down Expand Up @@ -40,6 +40,7 @@ import { languageServer } from "./language-server/view";
import { lintGutter } from "./lint/lint";
import { codeStructure } from "./structure-highlighting";
import themeExtensions from "./themeExtensions";
import { ApiDocsEntry } from "../../language-server/apidocs";

interface CodeMirrorProps {
className?: string;
Expand Down Expand Up @@ -80,7 +81,32 @@ const CodeMirror = ({
const logging = useLogging();
const actionFeedback = useActionFeedback();
const [sessionSettings, setSessionSettings] = useSessionSettings();
const { apiReferenceMap } = useDocumentation();
const { apiReferenceMap, api } = useDocumentation();

const showLinkToBuiltins = useCallback(
(id: string) => {
const idParts = id.split(".");

const recursiveFind = (
entries: ApiDocsEntry[] | undefined,
index: number = 1
): ApiDocsEntry | undefined => {
if (!entries) {
return;
}
return entries.find((entry) => {
const match = entry.id === idParts.slice(0, index + 1).join(".");
if (match) {
recursiveFind(entry.children, index + 1);
}
return match;
});
};

return !!recursiveFind(api?.content.builtins.children);
},
[api?.content.builtins.children]
);

// Reset undo/redo events on file change.
useEffect(() => {
Expand Down Expand Up @@ -141,7 +167,8 @@ const CodeMirror = ({
signatureHelp: {
automatic: parameterHelpOption === "automatic",
},
}
},
showLinkToBuiltins
)
: [],
codeStructure(options.codeStructureOption),
Expand Down Expand Up @@ -172,6 +199,7 @@ const CodeMirror = ({
parameterHelpOption,
uri,
apiReferenceMap,
showLinkToBuiltins,
]);
useEffect(() => {
// Do this separately as we don't want to destroy the view whenever options needed for initialization change.
Expand Down Expand Up @@ -199,7 +227,8 @@ const CodeMirror = ({
signatureHelp: {
automatic: parameterHelpOption === "automatic",
},
}
},
showLinkToBuiltins
)
: [],
codeStructure(options.codeStructureOption),
Expand All @@ -215,6 +244,7 @@ const CodeMirror = ({
logging,
uri,
apiReferenceMap,
showLinkToBuiltins,
]);

const { location } = selection;
Expand Down
18 changes: 14 additions & 4 deletions src/editor/codemirror/language-server/autocompletion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
import { nameFromSignature, removeFullyQualifiedName } from "./names";
import { offsetToPosition } from "./positions";
import { escapeRegExp } from "./regexp-util";
import { ShowLinkToBuiltins } from "./view";

// Used to find the true start of the completion. Doesn't need to exactly match
// any language's identifier definition.
Expand All @@ -44,7 +45,8 @@ type AugmentedCompletion = Completion & { item: CompletionItem };
export const autocompletion = (
intl: IntlShape,
logging: Logging,
apiReferenceMap: ApiReferenceMap
apiReferenceMap: ApiReferenceMap,
showLinkToBuiltins: ShowLinkToBuiltins
) =>
cmAutocompletion({
override: [
Expand Down Expand Up @@ -76,7 +78,8 @@ export const autocompletion = (
const documentationResolver = createDocumentationResolver(
client,
intl,
apiReferenceMap
apiReferenceMap,
showLinkToBuiltins
);
const results = await client.completionRequest({
textDocument: {
Expand Down Expand Up @@ -145,7 +148,8 @@ const createDocumentationResolver =
(
client: LanguageServerClient,
intl: IntlShape,
apiReferenceMap: ApiReferenceMap
apiReferenceMap: ApiReferenceMap,
showLinkToBuiltins: ShowLinkToBuiltins
) =>
async (completion: Completion): Promise<Node> => {
let documentation: string | LSP.MarkupContent | undefined;
Expand All @@ -171,7 +175,13 @@ const createDocumentationResolver =
if (id) {
const referenceLink = getLinkToReference(id, apiReferenceMap);
code.innerText = removeFullyQualifiedName(code.innerText);
return wrapWithDocumentationButton(intl, node, id, referenceLink);
return wrapWithDocumentationButton(
intl,
node,
id,
referenceLink,
showLinkToBuiltins
);
}
}
return node;
Expand Down
9 changes: 7 additions & 2 deletions src/editor/codemirror/language-server/documentation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { moduleAndApiFromId } from "../../../documentation/api/apidocs-util";
import { ApiReferenceMap } from "../../../documentation/mapping/content";
import { splitDocString } from "./docstrings";
import "./documentation.css";
import { ShowLinkToBuiltins } from "./view";

export const enum DocSections {
Summary = 1 << 0,
Expand Down Expand Up @@ -118,7 +119,8 @@ export const wrapWithDocumentationButton = (
intl: IntlShape,
child: Element,
id: string,
referenceLink: string | undefined
referenceLink: string | undefined,
showLinkToBuiltins: ShowLinkToBuiltins
): Element => {
const docsAndActions = document.createElement("div");
docsAndActions.style.display = "flex";
Expand Down Expand Up @@ -154,7 +156,10 @@ export const wrapWithDocumentationButton = (
// We don't have documentation for builtins yet,
// so there is nothing to link to.
const { pythonModuleName } = moduleAndApiFromId(id);
if (pythonModuleName !== "builtins") {
if (
pythonModuleName !== "builtins" ||
(pythonModuleName === "builtins" && showLinkToBuiltins(id))
) {
const apiAnchor = createStyledAnchorElement();
apiAnchor.textContent = intl.formatMessage({ id: "api-tab" });
apiAnchor.onclick = (e) => {
Expand Down
25 changes: 19 additions & 6 deletions src/editor/codemirror/language-server/signatureHelp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
} from "./documentation";
import { nameFromSignature, removeFullyQualifiedName } from "./names";
import { offsetToPosition } from "./positions";
import { ShowLinkToBuiltins } from "./view";

export const setSignatureHelpRequestPosition = StateEffect.define<number>({});

Expand Down Expand Up @@ -121,7 +122,8 @@ const openSignatureHelp: Command = (view: EditorView) => {
export const signatureHelp = (
intl: IntlShape,
automatic: boolean,
apiReferenceMap: ApiReferenceMap
apiReferenceMap: ApiReferenceMap,
showLinkToBuiltins: ShowLinkToBuiltins
) => {
const signatureHelpTooltipField = StateField.define<SignatureHelpState>({
create: () => new SignatureHelpState(-1, null),
Expand Down Expand Up @@ -162,7 +164,9 @@ export const signatureHelp = (
create: () => {
const dom = document.createElement("div");
dom.className = "cm-signature-tooltip";
dom.appendChild(formatSignatureHelp(result, apiReferenceMap));
dom.appendChild(
formatSignatureHelp(result, apiReferenceMap, showLinkToBuiltins)
);
return { dom };
},
};
Expand Down Expand Up @@ -219,7 +223,8 @@ export const signatureHelp = (

const formatSignatureHelp = (
help: SignatureHelp,
apiReferenceMap: ApiReferenceMap
apiReferenceMap: ApiReferenceMap,
showLinkToBuiltins: ShowLinkToBuiltins
): Node => {
const { activeSignature: activeSignatureIndex, signatures } = help;
// We intentionally do something minimal here to minimise distraction.
Expand Down Expand Up @@ -253,7 +258,8 @@ export const signatureHelp = (
to,
signatureDoc,
activeParameterDoc,
apiReferenceMap
apiReferenceMap,
showLinkToBuiltins
);
};

Expand All @@ -263,7 +269,8 @@ export const signatureHelp = (
to: number,
signatureDoc: string | MarkupContent | undefined,
activeParameterDoc: string | MarkupContent | undefined,
apiReferenceMap: ApiReferenceMap
apiReferenceMap: ApiReferenceMap,
showLinkToBuiltins: ShowLinkToBuiltins
): Node => {
let before = label.substring(0, from);
const id = nameFromSignature(before);
Expand Down Expand Up @@ -301,7 +308,13 @@ export const signatureHelp = (
);
}
const referenceLink = getLinkToReference(id, apiReferenceMap);
return wrapWithDocumentationButton(intl, parent, id, referenceLink);
return wrapWithDocumentationButton(
intl,
parent,
id,
referenceLink,
showLinkToBuiltins
);
};

return [
Expand Down
14 changes: 11 additions & 3 deletions src/editor/codemirror/language-server/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ interface Options {
};
}

export type ShowLinkToBuiltins = (id: string) => boolean;

/**
* Extensions that make use of a language server client.
*
Expand All @@ -88,13 +90,19 @@ export function languageServer(
intl: IntlShape,
logging: Logging,
apiReferenceMap: ApiReferenceMap,
options: Options
options: Options,
showLinkToBuiltins: ShowLinkToBuiltins
) {
return [
uriFacet.of(uri),
clientFacet.of(client),
ViewPlugin.define((view) => new LanguageServerView(view)),
signatureHelp(intl, options.signatureHelp.automatic, apiReferenceMap),
autocompletion(intl, logging, apiReferenceMap),
signatureHelp(
intl,
options.signatureHelp.automatic,
apiReferenceMap,
showLinkToBuiltins
),
autocompletion(intl, logging, apiReferenceMap, showLinkToBuiltins),
];
}
1 change: 1 addition & 0 deletions src/language-server/apidocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ export const apiDocs = async (
// For now, this omits a lot of modules that have stubs
// derived from typeshed with no docs.
// Note: "audio" is covered under micro:bit.
"builtins",
"gc",
"log",
"machine",
Expand Down
4 changes: 2 additions & 2 deletions src/micropython/main/typeshed.ca.json

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions src/micropython/main/typeshed.de.json

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions src/micropython/main/typeshed.en.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions src/micropython/main/typeshed.es-es.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/micropython/main/typeshed.fr.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/micropython/main/typeshed.ja.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/micropython/main/typeshed.ko.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/micropython/main/typeshed.nl.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/micropython/main/typeshed.zh-cn.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions src/micropython/main/typeshed.zh-tw.json

Large diffs are not rendered by default.

0 comments on commit 5c239cc

Please sign in to comment.