citation_tooltips_for_jupyterlab-myst
A patch to the jupyterlab_myst 2.4.2 release that adds a custom rfg role which displays the associated citation in a popup tooltip.
https://github.com/ast79/citation_tooltips_for_jupyterlab-myst
Science Score: 31.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
✓CITATION.cff file
Found CITATION.cff file -
✓codemeta.json file
Found codemeta.json file -
○.zenodo.json file
-
○DOI references
-
○Academic publication links
-
○Academic email domains
-
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (11.7%) to scientific vocabulary
Repository
A patch to the jupyterlab_myst 2.4.2 release that adds a custom rfg role which displays the associated citation in a popup tooltip.
Basic Info
- Host: GitHub
- Owner: ast79
- License: bsd-3-clause
- Default Branch: main
- Size: 36.1 KB
Statistics
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
- Releases: 2
Metadata Files
README.md
citation tooltips for jupyterlab-myst
A patch to the jupyterlab_myst 2.4.2 release that adds a custom rfg MyST role which displays the associated citation in a popup tooltip. Their hover link counters operate seperately from those of the cite role and use the red color. Mouse clicks on the hover link freeze or unfreeze the display of its tooltip and a displayed tooltip is draggable. Notes can be added to these citation tooltips by associating MyST footnote definitions to the rfg role.
The install instructions below end by orienting towards an example notebook that illustrates these features.
The software is at a pre-alpha release stage and should have bugs. The core functionality kinda seems to work, but the code remains hacky and not intended for publication beyond this step for now. It should see only minor corrections for bugs until the projected backend additions will be operational.
jupyterlab_myst doesn't yet render MyST citations in notebooks or in Markdown file previews, it doesn't even read in Bibtex files, and displays a "Citation Not Found" message when the pointer hovers over the citation. The 'myst build' commands will parse rfg role instances and render no output upon completion.
Requirements
- JupyterLab >= 4.0.0
Install
To install the extension inside a virtual environment, a download of the citation-tooltips-jupyterlab_myst-2.4.2.patch file from the repository is needed, and so are the following commands in a code shell starting at the download directory:
```bash wget https://github.com/jupyter-book/jupyterlab-myst/releases/download/v2.4.2/jupyterlab_myst-2.4.2.tar.gz
tar xfz jupyterlab_myst-2.4.2.tar.gz
cd jupyterlab_myst-2.4.2
patch -p1 < ../citation-tooltips-jupyterlab_myst-2.4.2.patch
The remainder corresponds to the development install steps for jupyterlab-myst
at https://github.com/jupyter-book/jupyterlab-myst#development-install
Activate the local JupyterLab environment
Install package in development mode
pip install -e ".[test]"
Link your development version of the extension with JupyterLab
jupyter labextension develop . --overwrite
Server extension must be manually installed in develop mode
jupyter server extension enable jupyterlab_myst
An example notebook can be found at ./tests/notebook/citation-tooltips.ipynb
cd tests/notebooks jupyter lab ```
Owner
- Login: ast79
- Kind: user
- Repositories: 1
- Profile: https://github.com/ast79
Citation (citation-tooltips-jupyterlab_myst-2.4.2.patch)
diff -urN jupyterlab_myst-2.4.2/README.md jupyterlab_myst-2.4.2-patched/README.md
--- jupyterlab_myst-2.4.2/README.md 2020-02-02 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/README.md 2024-11-26 13:56:11.948115048 +0100
@@ -1,21 +1,12 @@
-# JupyterLab MyST Extension
+# citation tooltips for jupyterlab-myst
-[![Made with MyST][myst-badge]][myst-link]
-[![GitHub Actions Status][actions-badge]][actions-link]
-[![Launch on Binder][binder-badge]][binder-link]
-[![PyPI][pypi-badge]][pypi-link]
+A patch to the jupyterlab_myst 2.4.2 release that adds a custom rfg [MyST role](https://mystmd.org/guide/quickstart-myst-markdown#directives-and-roles) which displays the associated citation in a popup tooltip. Their hover link counters operate seperately from those of the cite role and use the red color. Mouse clicks on the hover link freeze or unfreeze the display of its tooltip and a displayed tooltip is draggable. Notes can be added to these citation tooltips by associating [MyST footnote definitions](https://mystmd.org/guide/typography#footnotes) to the rfg role.
-Render markdown cells using [MyST Markdown](https://mystmd.org/), including support for rich frontmatter, interactive references, admonitions, figure numbering, tabs, proofs, exercises, glossaries, cards, and grids!
+The install instructions below end by orienting towards an example notebook that illustrates these features.
-
+The software is at a pre-alpha release stage and should have bugs. The core functionality kinda seems to work, but the code remains hacky and not intended for publication beyond this step for now. It should see only minor corrections for bugs until the projected backend additions will be operational.
-> **Note**: If you are looking for the version of this repository based on jupyterlab-markup,
-> see the [`v0 branch`](https://github.com/executablebooks/jupyterlab-myst/tree/v0).
-
-> **Info**
-> This extension is composed of a Python package named `jupyterlab_myst`
-> for the server extension and a NPM package named `jupyterlab-myst`
-> for the frontend extension.
+jupyterlab_myst doesn't yet render MyST citations in notebooks or in Markdown file previews, it doesn't even read in Bibtex files, and displays a "Citation Not Found" message when the pointer hovers over the citation. The 'myst build' commands will parse rfg role instances and render no output upon completion.
## Requirements
@@ -23,200 +14,29 @@
## Install
-To install the extension, execute:
+To install the extension inside a virtual environment, a download of the citation-tooltips-jupyterlab_myst-2.4.2.patch file from the repository is needed, and so are the following commands in a code shell starting at the download directory:
```bash
-pip install jupyterlab_myst
-```
-
-## Features
-
-`jupyterlab-myst` is a fully featured markdown renderer for technical documents, [get started with MyST Markdown](https://mystmd.org/guide/quickstart-myst-markdown). It supports the MyST `{eval}` inline role, which facilitates the interweaving of code outputs and prose. For example, we can use inline expressions to explore the properties of a NumPy array.
-
-In the code cell:
-
-```python
-import numpy as np
-array = np.arange(4)
-```
-
-In the markdown cell:
-
-```markdown
-Let's consider the following array: {eval}`array`.
-
-We can compute the total: {eval}`array.sum()` and the maximum value is {eval}`array.max()`.
-```
-
-This will evaluate inline, and show:
-
-```text
-Let's consider the following array: array([0, 1, 2, 3]).
-
-We can compute the total: 6 and the maximum value is 3.
-```
-
-You can also use this with `ipywidgets`, and have inline interactive text:
-
-
-
-Or with `matplotlib` to show inline spark-lines:
-
-
-
-You can also edit task lists directly in the rendered markdown.
-
-
-
-## Usage
+wget https://github.com/jupyter-book/jupyterlab-myst/releases/download/v2.4.2/jupyterlab_myst-2.4.2.tar.gz
-[MyST][myst-quickstart] is a flavour of Markdown, which combines the fluid experience of writing Markdown with the programmable extensibility of reStructuredText. This extension for JupyterLab makes it easier to develop rich, computational narratives, technical documentation, and open scientific communication.
+tar xfz jupyterlab_myst-2.4.2.tar.gz
-### Execution 🚀
-
-To facilitate inline expressions, `jupyterlab-myst` defines a `jupyterlab-myst:executor` plugin. This plugin sends expression code fragments to the active kernel when the user "executes" a Markdown cell. To disable this functionality, disable the `jupyterlab-myst:executor` plugin with:
-
-```bash
-jupyter labextension disable jupyterlab-myst:executor
-```
-
-### Trust 🔎
-
-Jupyter Notebooks implement a [trust-based security model](https://jupyter-server.readthedocs.io/en/stable/operators/security.html). With the addition of inline expressions, Markdown cells are now considered when determining whether a given notebook is "trusted". Any Markdown cell with inline-expression metadata (with display data) is considered "untrusted". Like outputs, expression results are rendered using safe renderers if the cell is not considered trusted.
-Executing the notebook will cause each cell to be considered trusted.
-
-To facilitate this extension of the trust model, the `jupyterlab_myst` server extension replaces the `NotebookNotary` from `nbformat` with `MySTNotebookNotary`. This can be disabled with
-
-```bash
-jupyter server extension disable jupyterlab-myst
-```
-
-By disabling this extension, it will not be possible to render unsafe expression results from inline expressions; the `MySTNotebookNotary` adds additional code that makes it possible to mark Markdown cells as trusted.
-
-## Uninstall
-
-To remove the extension, execute:
-
-```bash
-pip uninstall jupyterlab_myst
-```
-
-## Troubleshoot
-
-If you are seeing the frontend extension, but it is not working, check
-that the server extension is enabled:
-
-```bash
-jupyter server extension list
-```
+cd jupyterlab_myst-2.4.2
+
+patch -p1 < ../citation-tooltips-jupyterlab_myst-2.4.2.patch
-If the server extension is installed and enabled, but you are not seeing
-the frontend extension, check the frontend extension is installed:
+# The remainder corresponds to the development install steps for jupyterlab-myst
+# at https://github.com/jupyter-book/jupyterlab-myst#development-install
-```bash
-jupyter labextension list
-```
-
-## Contributing
-
-### Development install
-
-Note: You will need NodeJS to build the extension package.
-
-The `jlpm` command is JupyterLab's pinned version of
-[yarn](https://yarnpkg.com/) that is installed with JupyterLab. You may use
-`yarn` or `npm` in lieu of `jlpm` below.
-
-```bash
-# Clone the repo to your local environment
-# Change directory to the jupyterlab_myst directory
+# Activate the local JupyterLab environment
# Install package in development mode
pip install -e ".[test]"
# Link your development version of the extension with JupyterLab
jupyter labextension develop . --overwrite
# Server extension must be manually installed in develop mode
jupyter server extension enable jupyterlab_myst
-# Rebuild extension Typescript source after making changes
-jlpm build
-```
-You can watch the source directory and run JupyterLab at the same time in different terminals to watch for changes in the extension's source and automatically rebuild the extension.
-
-```bash
-# Watch the source directory in one terminal, automatically rebuilding when needed
-jlpm watch
-# Run JupyterLab in another terminal
+# An example notebook can be found at ./tests/notebook/citation-tooltips.ipynb
+cd tests/notebooks
jupyter lab
```
-
-With the watch command running, every saved change will immediately be built locally and available in your running JupyterLab. Refresh JupyterLab to load the change in your browser (you may need to wait several seconds for the extension to be rebuilt).
-
-By default, the `jlpm build` command generates the source maps for this extension to make it easier to debug using the browser dev tools. To also generate source maps for the JupyterLab core extensions, you can run the following command:
-
-```bash
-jupyter lab build --minimize=False
-```
-
-### Development uninstall
-
-```bash
-# Server extension must be manually disabled in develop mode
-jupyter server extension disable jupyterlab_myst
-pip uninstall jupyterlab_myst
-```
-
-In development mode, you will also need to remove the symlink created by `jupyter labextension develop`
-command. To find its location, you can run `jupyter labextension list` to figure out where the `labextensions`
-folder is located. Then you can remove the symlink named `jupyterlab-myst` within that folder.
-
-### Testing the extension
-
-#### Server tests
-
-This extension is using [Pytest](https://docs.pytest.org/) for Python code testing.
-
-Install test dependencies (needed only once):
-
-```sh
-pip install -e ".[test]"
-# Each time you install the Python package, you need to restore the front-end extension link
-jupyter labextension develop . --overwrite
-```
-
-To execute them, run:
-
-```sh
-pytest -vv -r ap --cov jupyterlab_myst
-```
-
-#### Frontend tests
-
-This extension is using [Jest](https://jestjs.io/) for JavaScript code testing.
-
-To execute them, execute:
-
-```sh
-jlpm
-jlpm test
-```
-
-#### Integration tests
-
-This extension uses [Playwright](https://playwright.dev/docs/intro) for the integration tests (aka user level tests).
-More precisely, the JupyterLab helper [Galata](https://github.com/jupyterlab/jupyterlab/tree/master/galata) is used to handle testing the extension in JupyterLab.
-
-More information are provided within the [ui-tests](./ui-tests/README.md) README.
-
-### Packaging the extension
-
-See [RELEASE](RELEASE.md)
-
-[myst-badge]: https://img.shields.io/badge/made%20with-myst-orange
-[myst-link]: https://mystmd.org
-[myst-quickstart]: https://mystmd.org/guide/quickstart-myst-markdown
-[actions-badge]: https://github.com/executablebooks/jupyterlab-myst/workflows/Build/badge.svg
-[actions-link]: https://github.com/executablebooks/jupyterlab-myst/actions/workflows/build.yml
-[binder-badge]: https://mybinder.org/badge_logo.svg
-[binder-link]: https://mybinder.org/v2/gh/executablebooks/jupyterlab-myst/main?urlpath=lab
-[pypi-badge]: https://img.shields.io/pypi/v/jupyterlab-myst.svg
-[pypi-link]: https://pypi.org/project/jupyterlab-myst
diff -urN jupyterlab_myst-2.4.2/src/components/footnotes.tsx jupyterlab_myst-2.4.2-patched/src/components/footnotes.tsx
--- jupyterlab_myst-2.4.2/src/components/footnotes.tsx 1970-01-01 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/src/components/footnotes.tsx 2024-11-23 15:14:19.092750677 +0100
@@ -0,0 +1,156 @@
+import React, { useState } from 'react';
+import { MyST } from 'myst-to-react';
+import * as HoverCard from '@radix-ui/react-hover-card';
+import { XRefProvider, useReferences } from '@myst-theme/providers';
+import type { NodeRenderer } from '@myst-theme/providers';
+import { select } from 'unist-util-select';
+
+// Cloned from 'myst-to-react 0.9.0' because it isn't reexported by the module
+function FootnoteDefinition({ identifier }: { identifier: string }) {
+ const references = useReferences();
+ const node =
+ (references as any)?.footnotes?.[identifier] ??
+ select(`footnoteDefinition[identifier=${identifier}]`, references?.article);
+ return (
+ <XRefProvider>
+ <div className="hover-document article w-[500px] sm:max-w-[500px] px-3">
+ <MyST ast={node.children} />
+ </div>
+ </XRefProvider>
+ );
+}
+
+function HoverPopover({
+ children,
+ openDelay = 400,
+ card,
+ side,
+ arrowClass = 'fill-white',
+}: {
+ children: React.ReactNode;
+ openDelay?: number;
+ arrowClass?: string;
+ side?: 'top' | 'right' | 'bottom' | 'left';
+ card: React.ReactNode | ((args: { load: boolean }) => React.ReactNode);
+}) {
+ const [load, setLoad] = useState(false);
+
+ return (
+ <HoverCard.Root openDelay={openDelay}>
+ <HoverCard.Trigger asChild onMouseEnter={() => setLoad(true)}>
+ {children}
+ </HoverCard.Trigger>
+ <HoverCard.Portal>
+ <HoverCard.Content
+ className="exclude-from-outline hover-card-content"
+ sideOffset={5}
+ side={side}
+ >
+ {typeof card === 'function' ? load && card({ load }) : card}
+ <HoverCard.Arrow className={arrowClass} />
+ </HoverCard.Content>
+ </HoverCard.Portal>
+ </HoverCard.Root>
+ );
+}
+
+// Cloned from 'myst-to-react 0.9.0' because it isn't reexported by the module
+export const FootnoteReference: NodeRenderer = ({ node }) => {
+ const references = useReferences();
+ // const id = {node.identifier as string};
+ console.log('references:', references);
+ const c = <FootnoteDefinition identifier={node.identifier as string} />;
+ return (
+ <HoverPopover openDelay={0} card={c}>
+ <span>
+ <sup className="hover-link">[{node.number ?? node.identifier}]</sup>
+ </span>
+ </HoverPopover>
+ );
+};
+
+function HoverPopoverHook({
+ children,
+ openDelay = 400,
+ card,
+ side,
+ arrowClass = 'fill-white'
+}: {
+ children: React.ReactNode;
+ openDelay?: number;
+ arrowClass?: string;
+ side?: 'top' | 'right' | 'bottom' | 'left';
+ card: React.ReactNode | ((args: { load: boolean }) => React.ReactNode);
+}) {
+ const [load, setLoad] = useState(false);
+ const [isOpen, setOpen] = useState(false);
+ const [isContentMouseDown, setContentMouseDown] = useState(false);
+ const [hoverClick, setHoverClick] = useState(false);
+ const triggerMouseEnter = () => {
+ setLoad(true);
+ setOpen(true);
+ };
+ const contentMouseMove = (event: any) => {
+ if (isContentMouseDown) {
+ const t = event.currentTarget.parentElement;
+ const leftval = parseInt(t.style.left);
+ const topval = parseInt(t.style.top);
+ t.style.left = leftval + event.movementX + 'px';
+ t.style.top = topval + event.movementY + 'px';
+ }
+ };
+ const pStyle = {
+ display: 'inline-block'
+ };
+
+ return (
+ <HoverCard.Root
+ openDelay={openDelay}
+ open={isOpen}
+ // onOpenChange={() => setOpen(isOpen)}
+ >
+ <HoverCard.Trigger
+ asChild
+ onMouseEnter={triggerMouseEnter}
+ onClick={() => setHoverClick(!hoverClick)}
+ onMouseLeave={() => setOpen(hoverClick)}
+ >
+ {children}
+ </HoverCard.Trigger>
+ <HoverCard.Portal>
+ <HoverCard.Content
+ className="exclude-from-outline hover-card-content"
+ sideOffset={5}
+ side={side}
+ onMouseLeave={() => setOpen(hoverClick)}
+ onMouseDown={() => setContentMouseDown(true)}
+ onMouseMove={contentMouseMove}
+ onMouseUp={() => setContentMouseDown(false)}
+ >
+ {children}
+ <span style={pStyle}>
+ {typeof card === 'function' ? load && card({ load }) : card}
+ </span>
+ <HoverCard.Arrow className={arrowClass} />
+ </HoverCard.Content>
+ </HoverCard.Portal>
+ </HoverCard.Root>
+ );
+}
+
+export const FootnoteReferenceHook: NodeRenderer = ({ node }) => {
+ return (
+ <HoverPopoverHook
+ openDelay={0}
+ card={<FootnoteDefinition identifier={node.identifier as string} />}
+ >
+ <span>
+ <sup className="hover-link">
+ <span style={{ color: 'red' }}>
+ [{node.number ?? node.identifier}]
+ </span>
+ </sup>
+ </span>
+ </HoverPopoverHook>
+ );
+};
diff -urN jupyterlab_myst-2.4.2/src/components/index.ts jupyterlab_myst-2.4.2-patched/src/components/index.ts
--- jupyterlab_myst-2.4.2/src/components/index.ts 1970-01-01 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/src/components/index.ts 2024-11-26 13:08:28.604551495 +0100
@@ -0,0 +1,4 @@
+export * from './inlineExpression';
+export * from './listItem';
+export * from './footnotes';
+
diff -urN jupyterlab_myst-2.4.2/src/components/index.tsx jupyterlab_myst-2.4.2-patched/src/components/index.tsx
--- jupyterlab_myst-2.4.2/src/components/index.tsx 2020-02-02 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/src/components/index.tsx 1970-01-01 01:00:00.000000000 +0100
@@ -1,2 +0,0 @@
-export * from './inlineExpression';
-export * from './listItem';
diff -urN jupyterlab_myst-2.4.2/src/myst.ts jupyterlab_myst-2.4.2-patched/src/myst.ts
--- jupyterlab_myst-2.4.2/src/myst.ts 2020-02-02 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/src/myst.ts 2024-11-25 16:13:08.129539019 +0100
@@ -1,4 +1,5 @@
-import { mystParse } from 'myst-parser';
+import { mystParse, createTokenizer, defaultOptions } from 'myst-parser';
+import type { AllOptions } from 'myst-parser';
import { copyNode, References } from 'myst-common';
import {
abbreviationPlugin,
@@ -51,7 +52,53 @@
trusted: boolean;
}
+type Options = Partial<AllOptions>;
+
+function parseOptions(opts?: Options): AllOptions {
+ const parsedOpts = {
+ vfile: opts?.vfile ?? new VFile(),
+ mdast: { ...defaultOptions.mdast, ...opts?.mdast },
+ markdownit: { ...defaultOptions.markdownit, ...opts?.markdownit },
+ extensions: { ...defaultOptions.extensions, ...opts?.extensions },
+ directives: [...defaultOptions.directives, ...(opts?.directives ?? [])],
+ roles: [...defaultOptions.roles, ...(opts?.roles ?? [])]
+ };
+ return parsedOpts;
+}
+
export function markdownParse(text: string): Root {
+ const opts = {
+ markdownit: { linkify: true },
+ directives: [
+ cardDirective,
+ ...gridDirectives,
+ proofDirective,
+ ...exerciseDirectives,
+ ...tabDirectives
+ ],
+ roles: []
+ };
+ const tokenizer = createTokenizer(parseOptions(opts));
+ const state = new tokenizer.core.State(text, tokenizer, { opts });
+ tokenizer.core.process(state);
+ const footnotes = state.env.footnotes;
+ const refs = Object.getOwnPropertyNames(footnotes.refs);
+ const labels = [];
+ let rfgNotes = false;
+ for (let i = 0; i < footnotes.list.length; i++) {
+ labels[i] = footnotes.list[i].label;
+ }
+ for (let l, i = 0; i < refs.length; i++) {
+ l = refs[i].slice(1, refs[i].length);
+ if (!labels.includes(l)) {
+ if (!rfgNotes) {
+ text = text + '\n';
+ rfgNotes = true;
+ }
+ text = text + '\n' + '[' + '^' + l + ']';
+ }
+ }
+
const parseMyst = (content: string) => {
return mystParse(content, {
markdownit: { linkify: true },
@@ -67,6 +114,10 @@
};
const mdast = parseMyst(text);
+ if (rfgNotes) {
+ mdast.children.splice(mdast.children.length - 1 - refs.length, 1);
+ }
+
// Parsing individually here requires that link and footnote references are contained to the cell
// This is consistent with the current Jupyter markdown renderer
unified()
@@ -222,6 +273,7 @@
cell => cell.fragmentMDAST !== undefined
);
const mdast = buildNotebookMDAST(mystCells);
+ console.log('mdast:', mdast);
const {
references,
frontmatter,
diff -urN jupyterlab_myst-2.4.2/src/renderers.tsx jupyterlab_myst-2.4.2-patched/src/renderers.tsx
--- jupyterlab_myst-2.4.2/src/renderers.tsx 2020-02-02 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/src/renderers.tsx 2024-10-15 14:12:56.003292588 +0200
@@ -1,8 +1,13 @@
import React from 'react';
+import { NodeRenderer } from '@myst-theme/providers';
import { DEFAULT_RENDERERS } from 'myst-to-react';
import { MermaidNodeRenderer } from '@myst-theme/diagrams';
-import { NodeRenderer } from '@myst-theme/providers';
-import { InlineExpression, ListItem } from './components';
+import {
+ InlineExpression,
+ ListItem,
+ FootnoteReference,
+ FootnoteReferenceHook
+} from './components';
import { useSanitizer } from './providers';
export const renderers: Record<string, NodeRenderer> = {
@@ -20,6 +25,12 @@
/>
);
},
+ footnoteReference: ({ node }) => {
+ if (node.kind !== 'rfg') {
+ return <FootnoteReference node={node} />;
+ }
+ return <FootnoteReferenceHook node={node} />;
+ },
html: ({ node }, children) => {
const { sanitizer } = useSanitizer();
if (sanitizer !== undefined) {
diff -urN jupyterlab_myst-2.4.2/src/transforms/citations.ts jupyterlab_myst-2.4.2-patched/src/transforms/citations.ts
--- jupyterlab_myst-2.4.2/src/transforms/citations.ts 2020-02-02 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/src/transforms/citations.ts 2024-11-25 09:42:03.846525390 +0100
@@ -1,12 +1,17 @@
import type { Plugin } from 'unified';
+import type { VFile } from 'vfile';
import type { Root } from 'myst-spec';
import type { GenericNode } from 'myst-common';
import { selectAll } from 'unist-util-select';
+import { RuleId, fileWarn } from 'myst-common';
/**
* Add fake children to the citations
*/
-export async function addCiteChildrenTransform(tree: Root): Promise<void> {
+export async function addCiteChildrenTransform(
+ tree: Root,
+ file: VFile
+): Promise<void> {
const links = selectAll('cite', tree) as GenericNode[];
links.forEach(async cite => {
if (cite.children && cite.children.length > 0) {
@@ -17,6 +22,150 @@
});
}
-export const addCiteChildrenPlugin: Plugin<[], Root, Root> = () => tree => {
- addCiteChildrenTransform(tree);
-};
+function nextNumber(current: number, reserved: Set<number>): number {
+ do {
+ current += 1;
+ } while (reserved.has(current));
+ return current;
+}
+
+const TRANSFORM_SOURCE = 'jupyterlab-transforms:rfg';
+
+export async function rfgRolesTransform(
+ tree: Root,
+ file: VFile
+): Promise<void> {
+ const links = selectAll('mystRole', tree) as GenericNode[];
+ if (links.length === 0) {
+ return;
+ }
+ const reserved = new Set(
+ links
+ .map(r => Number(r.identifier))
+ .filter(num => !Number.isNaN(num) && num > 0)
+ );
+ let rfgCount = 0;
+ for (let cell = 0, nb_cells = tree.children.length; cell < nb_cells; cell++) {
+ const paragraphs = selectAll(
+ 'paragraph',
+ tree.children[cell]
+ ) as GenericNode[];
+ const fds = selectAll(
+ 'footnoteDefinition',
+ tree.children[cell]
+ ) as GenericNode[];
+ const defs = [] as GenericNode[];
+ paragraphs.forEach(async paragraph => {
+ const roles = selectAll('mystRole', paragraph) as GenericNode[];
+ roles.forEach(async node => {
+ if (node.name === 'rfg') {
+ if (!node.value) {
+ fileWarn(file, 'rfgReference does not have an identifier', {
+ node,
+ source: TRANSFORM_SOURCE,
+ ruleId: RuleId.roleRegistered
+ });
+ return;
+ }
+
+ const kids = paragraph.children ?? undefined;
+ let i = kids?.length ?? 1;
+ if (kids) {
+ for (let n = kids.indexOf(node); i > n; i--) {
+ kids[i] = kids[i - 1];
+ }
+ const i1 = i + 1;
+ const position = node.position;
+ if (position) {
+ kids[i1] = {
+ type: 'footnoteReference',
+ identifier: node.value,
+ label: node.value,
+ kind: 'rfg',
+ position: {
+ end: { column: 1, line: position.end.line },
+ start: { column: 1, line: position.start.line }
+ }
+ } as unknown as GenericNode;
+ const identifierNumber = Number(kids[i1].identifier);
+ if (!Number.isNaN(identifierNumber) && identifierNumber > 0) {
+ kids[i1].number = identifierNumber;
+ kids[i1].enumerator = String(identifierNumber);
+ } else {
+ rfgCount = nextNumber(rfgCount, reserved);
+ kids[i1].number = rfgCount;
+ kids[i1].enumerator = String(rfgCount);
+ }
+ if (node.children && node.children.length > 0) {
+ return;
+ }
+ const parb = {
+ type: 'paragraph',
+ children: [node],
+ position: {
+ end: { column: 1, line: position.end.line },
+ start: { column: 1, line: position.start.line }
+ }
+ } as unknown as GenericNode;
+ const def = {
+ type: 'footnoteDefinition',
+ identifier: node.value,
+ label: node.value,
+ children: [parb],
+ position: {
+ end: { column: 1, line: position.end.line },
+ start: { column: 1, line: position.start.line }
+ }
+ } as unknown as GenericNode;
+ def.number = kids[i1].number;
+ def.enumerator = kids[i1].enumerator;
+ defs[defs.length] = def;
+ for (let j = 0; j < fds.length; j++) {
+ if (node.value === fds[j].identifier) {
+ fds[j].children?.splice(0, 0, node);
+ //const fd_kids = fds[j].children;
+ //if (fd_kids) {
+ // for (let k = fd_kids.length; k > 0; k--) {
+ // fd_kids[k] = fd_kids[k - 1];
+ // }
+ // fd_kids[0] = node;
+ //}
+ }
+ }
+ }
+ }
+ node.type = 'cite';
+ node.label = node.value;
+ node.identifier = node.value;
+ node.kind = 'parenthetical';
+ node.error = true;
+ delete node.value;
+ delete node.name;
+ delete node.position;
+ node.children = [{ type: 'text', value: node.label }];
+ }
+ });
+ });
+
+ const kid = tree.children[cell] as GenericNode;
+ if (kid) {
+ const kid1 = kid.children?.[0];
+ if (kid1) {
+ const kid2 = kid1.children;
+ if (kid2) {
+ const l = kid2.length;
+ const n = defs.length;
+ for (let i = 0; i < n; i++) {
+ kid2[l + i] = defs[i];
+ }
+ }
+ }
+ }
+ }
+}
+
+export const addCiteChildrenPlugin: Plugin<[], Root, Root> =
+ () => (tree, file) => {
+ addCiteChildrenTransform(tree, file);
+ rfgRolesTransform(tree, file);
+ };
diff -urN jupyterlab_myst-2.4.2/style/base.css jupyterlab_myst-2.4.2-patched/style/base.css
--- jupyterlab_myst-2.4.2/style/base.css 2020-02-02 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/style/base.css 2024-11-26 13:08:28.604551495 +0100
@@ -40,3 +40,16 @@
padding: var(--jp-private-markdownviewer-padding);
overflow: auto;
}
+
+.hover-card-content {
+ postion: absolute;
+ animation-duration: 0.6s;
+ animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
+ z-index: 10;
+}
+.hover-card-content[data-side='top'] {
+ animation-name: slideUp;
+}
+.hover-card-content[data-side='bottom'] {
+ animation-name: slideDown;
+}
diff -urN jupyterlab_myst-2.4.2/tests/notebooks/book.bib jupyterlab_myst-2.4.2-patched/tests/notebooks/book.bib
--- jupyterlab_myst-2.4.2/tests/notebooks/book.bib 1970-01-01 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/tests/notebooks/book.bib 2024-11-26 13:08:28.604551495 +0100
@@ -0,0 +1,108 @@
+%%
+%% This is file `book.bib',
+%% generated with the docstrip utility.
+%%
+%% The original source files were:
+%%
+%% jurabib.dtx (with options: `book')
+%% ----------------------------------------
+%% Example BibTeX file for the documentation
+%% of the jurabib package v0.6
+%% Copyright (C) 1999-2004 Jens Berger (http://www.jurabib.org)
+%% See jurabib.ins for the copyright details.
+%%
+@BOOK{broxbgb,
+ author = {Hans Brox},
+ title = {Allgemeiner Teil des B{\"u}rgerlichen Gesetzbuches},
+ shorttitle = {BGB~AT},
+ year = 1996,
+ language = {german},
+ address = {K{\"o}ln, Berlin, Bonn, M{\"u}nchen},
+ edition = 20,
+ annote = {This is a senseless test for testing the annote field.\par If
+ you are reading this text now, note that you can switch
+ off the output of this field by removing the \texttt{annote} option
+ \begin{itemize}\item You are able to use lists inside the annote field\end{itemize}}
+}
+@BOOK{broxschr,
+ author = {Hans Brox},
+ title = {Besonderes Schuldrecht},
+ shorttitle = {SchR~BT},
+ year = 1995,
+ language = {german},
+ address = {M{\"u}nchen},
+ edition = 20
+}
+@BOOK{canaris,
+ author = {Claus Wilhelm Cannabis},
+ title = {Die Vertrauenshaftung im deutschen Privatrecht},
+ shorttitle = {Vertrauenshaftung},
+ year = 1971,
+ language = {german},
+ address = {M{\"u}nchen}
+}
+@BOOK{ennenipp,
+ author = {Ludwig Enneccerus and Hans Carl Nipperdey},
+ title = {Allgemeiner Teil des B{\"u}rgerlichen Rechts},
+ year = 1960,
+ volume = {1},
+ language = {german},
+ volumetitle = {zweiter Halbband},
+ address = {T{\"u}bingen},
+ edition = 15
+}
+@BOOK{huebner,
+ author = {Heinz H{\"u}bner},
+ title = {Allgemeiner Teil des B{\"u}rgerlichen Gesetzbuches},
+ shorttitle = {BGB~AT},
+ year = 1996,
+ language = {german},
+ address = {Berlin, New York},
+ edition = 2
+}
+@BOOK{koehler,
+ author = {Helmut K{\"o}hler},
+ title = {BGB Allgemeiner Teil},
+ shorttitle = {BGB~AT},
+ language = {german},
+ year = 1996,
+ address = {M{\"u}nchen},
+ edition = 23
+}
+@BOOK{medicus,
+ author = {Dieter Medicus},
+ title = {Allgemeiner Teil des BGB},
+ shorttitle = {BGB~AT},
+ year = 1995,
+ howcited = 1,
+ address = {M{\"u}nchen},
+ edition = {6}
+}
+@BOOK{musielak,
+ author = {Hans-Joachim Musielak},
+ title = {Grundkurs BGB},
+ shorttitle = {BGB~GK},
+ language = {german},
+ year = 1994,
+ address = {M{\"u}nchen}
+}
+@BOOK{alexy,
+ author = {Alexy, Robert},
+ title = {Theorie der Grundrechte},
+ year = 1985,
+ address = {Baden-Baden},
+ school = {G{\"o}ttingen},
+ dissyear = 1984
+}
+@BOOK{kkstrr,
+ author = {Kurt Kodal and Joachim Kr{\"a}mer},
+ title = {Stra{\ss}enrecht},
+ shorttitle = {StrR},
+ year = 1995,
+ address = {M{\"u}nchen},
+ edition = {5},
+ pages = {30--34, \S~24}
+}
+%%
+%%
+%% End of file `book.bib'.
diff -urN jupyterlab_myst-2.4.2/tests/notebooks/citation-tooltips.ipynb jupyterlab_myst-2.4.2-patched/tests/notebooks/citation-tooltips.ipynb
--- jupyterlab_myst-2.4.2/tests/notebooks/citation-tooltips.ipynb 1970-01-01 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/tests/notebooks/citation-tooltips.ipynb 2024-11-26 15:05:29.500900343 +0100
@@ -0,0 +1,112 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "fcf153d4-5a07-4b1d-91b1-3085926a11ea",
+ "metadata": {
+ "citation-manager": {
+ "citations": {
+ "cite2c-29383/R7MVWURF": []
+ }
+ }
+ },
+ "source": [
+ "{rfg}`book-minimal`\n",
+ "\n",
+ "[^book-minimal]: Sometimes, you need to explain a point\n",
+ "\n",
+ " with some extra text!\n",
+ "\n",
+ " - and some *serious* points 💥\n",
+ " - and even images!\n",
+ "\n",
+ " \n",
+ "\n",
+ " Plus any preceding unindented lines,\n",
+ "that are not separated by a blank line\n",
+ "\n",
+ "text1 {cite:p}`alexy,article-full`\n",
+ "\n",
+ "[^wondering]: footnote wonder\n",
+ "\n",
+ "tx1[^third_note] txt2\n",
+ "\n",
+ "[^third_note]: Testing {cite}`broxbgb` that\n",
+ "\n",
+ "text2 {rfg}`koehler,huebner` text3\n",
+ "\n",
+ "patati [^bkpttst]\n",
+ "\n",
+ "[^bkpttst]: Breakpointtest\n",
+ "\n",
+ "% Todo: tooltips for citations from https://github.com/krassowski/jupyterlab-citation-manager\n",
+ "% {rfg:cm}`kluyver13{<cite id=\"cite2c-29383/R7MVWURF\"><a href=\"#cite2c%7C29383%2FR7MVWURF\">(Kluyver & Osborne, 2013)</a></cite>}`\n",
+ "%\n",
+ "% [^kluyver13]: no tooltips 4 citation manager yet"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ed0e13e4-a018-405a-b6f1-d63717e646ca",
+ "metadata": {},
+ "source": [
+ "% Fails to resolve the dynamic parts in the cross-references taken from\n",
+ "% https://mystmd.org/guide/quickstart-myst-markdown#links-cross-references\n",
+ "% (after adding the required installs and tidbits from the mystmc docs folder)\n",
+ "\n",
+ "As you have seen in the links in MyST (e.g. [](./frontmatter.md)), there is information that is pulled forward into your reading context on hover or click. We believe it is important to provide as much possible context when you are reading on elements like links to other pages, cross-references to figures, tables and equations as well as traditional academic citations {rfg}`article-full` (**👈 see the footnote!**). Additionally, all of these have fallbacks in static PDF or Word documents.\n",
+ "\n",
+ "[^article-full]:\n",
+ " For example, in [](doi:10.1145/3411764.3445648) the authors showed you can speed up comprehension of a paper by 26% when showing information in context, rather than requiring researchers to scroll back and forth to find figures and equations.\n",
+ "\n",
+ " Imagine if all of science was ⚡️ 26% faster ⚡️[^3]!! (**👈💥**)\\\n",
+ " Designing the user-experience of scientific communication is _really_ important.\n",
+ "\n",
+ "[^3]:\n",
+ " Just as an example of having lots of helpful information at your finger-tips, it would be nice to see the video of that article, _right_? Well here it is:\n",
+ "\n",
+ " :::{iframe} https://www.youtube.com/embed/yYcQf-Yq8B0\n",
+ " :::\n",
+ "\n",
+ " Can't do that in a PDF! [^4] (**👈💥**)\n",
+ "\n",
+ "[^4]:\n",
+ " I mean, now that you are down the rabbit-hole, we can get you back on track with a demo of [referencing equations](#example-equation-targets) (**👈💥**)\n",
+ "\n",
+ " Or maybe you want to explore an [💥 interactive figure 💥](#fig-altair-horsepower)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": null,
+ "id": "0976b2ab-f512-46b8-a6ef-d37ef956f5c7",
+ "metadata": {},
+ "outputs": [],
+ "source": []
+ }
+ ],
+ "metadata": {
+ "citation-manager": {
+ "items": {}
+ },
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "language": "python",
+ "name": "python3"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.12.5"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff -urN jupyterlab_myst-2.4.2/tests/notebooks/xampl.bib jupyterlab_myst-2.4.2-patched/tests/notebooks/xampl.bib
--- jupyterlab_myst-2.4.2/tests/notebooks/xampl.bib 1970-01-01 01:00:00.000000000 +0100
+++ jupyterlab_myst-2.4.2-patched/tests/notebooks/xampl.bib 2024-11-26 13:08:28.604551495 +0100
@@ -0,0 +1,361 @@
+% Copyright (C) 1988, 2010 Oren Patashnik.
+% Unlimited copying and redistribution of this file are permitted if it
+% is unmodified. Modifications (and their redistribution) are also
+% permitted, as long as the resulting file is renamed.
+
+@preamble{ "\newcommand{\noopsort}[1]{} "
+ # "\newcommand{\printfirst}[2]{#1} "
+ # "\newcommand{\singleletter}[1]{#1} "
+ # "\newcommand{\switchargs}[2]{#2#1} " }
+
+@ARTICLE{article-minimal,
+ author = {L[eslie] A. Aamport},
+ title = {The Gnats and Gnus Document Preparation System},
+ journal = {\mbox{G-Animal's} Journal},
+ year = 1986,
+}
+
+@ARTICLE{article-full,
+ author = {L[eslie] A. Aamport},
+ title = {The Gnats and Gnus Document Preparation System},
+ journal = {\mbox{G-Animal's} Journal},
+ year = 1986,
+ volume = 41,
+ number = 7,
+ pages = "73+",
+ month = jul,
+ note = "This is a full ARTICLE entry",
+}
+
+The KEY field is here to override the KEY field in the journal being
+cross referenced (so is the NOTE field, in addition to its imparting
+information).
+
+@ARTICLE{article-crossref,
+ crossref = {WHOLE-JOURNAL},
+ key = "",
+ author = {L[eslie] A. Aamport},
+ title = {The Gnats and Gnus Document Preparation System},
+ pages = "73+",
+ note = "This is a cross-referencing ARTICLE entry",
+}
+
+@ARTICLE{whole-journal,
+ key = "GAJ",
+ journal = {\mbox{G-Animal's} Journal},
+ year = 1986,
+ volume = 41,
+ number = 7,
+ month = jul,
+ note = {The entire issue is devoted to gnats and gnus
+ (this entry is a cross-referenced ARTICLE (journal))},
+}
+
+@INBOOK{inbook-minimal,
+ author = "Donald E. Knuth",
+ title = "Fundamental Algorithms",
+ publisher = "Addison-Wesley",
+ year = "{\noopsort{1973b}}1973",
+ chapter = "1.2",
+}
+
+@INBOOK{inbook-full,
+ author = "Donald E. Knuth",
+ title = "Fundamental Algorithms",
+ volume = 1,
+ series = "The Art of Computer Programming",
+ publisher = "Addison-Wesley",
+ address = "Reading, Massachusetts",
+ edition = "Second",
+ month = "10~" # jan,
+ year = "{\noopsort{1973b}}1973",
+ type = "Section",
+ chapter = "1.2",
+ pages = "10--119",
+ note = "This is a full INBOOK entry",
+}
+
+@INBOOK{inbook-crossref,
+ crossref = "whole-set",
+ title = "Fundamental Algorithms",
+ volume = 1,
+ series = "The Art of Computer Programming",
+ edition = "Second",
+ year = "{\noopsort{1973b}}1973",
+ type = "Section",
+ chapter = "1.2",
+ note = "This is a cross-referencing INBOOK entry",
+}
+
+@BOOK{book-minimal,
+ author = "Donald E. Knuth",
+ title = "Seminumerical Algorithms",
+ publisher = "Addison-Wesley",
+ year = "{\noopsort{1973c}}1981",
+}
+
+@BOOK{book-full,
+ author = "Donald E. Knuth",
+ title = "Seminumerical Algorithms",
+ volume = 2,
+ series = "The Art of Computer Programming",
+ publisher = "Addison-Wesley",
+ address = "Reading, Massachusetts",
+ edition = "Second",
+ month = "10~" # jan,
+ year = "{\noopsort{1973c}}1981",
+ note = "This is a full BOOK entry",
+}
+
+@BOOK{book-crossref,
+ crossref = "whole-set",
+ title = "Seminumerical Algorithms",
+ volume = 2,
+ series = "The Art of Computer Programming",
+ edition = "Second",
+ year = "{\noopsort{1973c}}1981",
+ note = "This is a cross-referencing BOOK entry",
+}
+
+@BOOK{whole-set,
+ author = "Donald E. Knuth",
+ publisher = "Addison-Wesley",
+ title = "The Art of Computer Programming",
+ series = "Four volumes",
+ year = "{\noopsort{1973a}}{\switchargs{--90}{1968}}",
+ note = "Seven volumes planned (this is a cross-referenced set of BOOKs)",
+}
+
+@BOOKLET{booklet-minimal,
+ key = "Kn{\printfirst{v}{1987}}",
+ title = "The Programming of Computer Art",
+}
+
+@BOOKLET{booklet-full,
+ author = "Jill C. Knvth",
+ title = "The Programming of Computer Art",
+ howpublished = "Vernier Art Center",
+ address = "Stanford, California",
+ month = feb,
+ year = 1988,
+ note = "This is a full BOOKLET entry",
+}
+
+@INCOLLECTION{incollection-minimal,
+ author = "Daniel D. Lincoll",
+ title = "Semigroups of Recurrences",
+ booktitle = "High Speed Computer and Algorithm Organization",
+ publisher = "Academic Press",
+ year = 1977,
+}
+
+@INCOLLECTION{incollection-full,
+ author = "Daniel D. Lincoll",
+ title = "Semigroups of Recurrences",
+ editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh",
+ booktitle = "High Speed Computer and Algorithm Organization",
+ number = 23,
+ series = "Fast Computers",
+ chapter = 3,
+ type = "Part",
+ pages = "179--183",
+ publisher = "Academic Press",
+ address = "New York",
+ edition = "Third",
+ month = sep,
+ year = 1977,
+ note = "This is a full INCOLLECTION entry",
+}
+
+@INCOLLECTION{incollection-crossref,
+ crossref = "whole-collection",
+ author = "Daniel D. Lincoll",
+ title = "Semigroups of Recurrences",
+ pages = "179--183",
+ note = "This is a cross-referencing INCOLLECTION entry",
+}
+
+@BOOK{whole-collection,
+ editor = "David J. Lipcoll and D. H. Lawrie and A. H. Sameh",
+ title = "High Speed Computer and Algorithm Organization",
+ booktitle = "High Speed Computer and Algorithm Organization",
+ number = 23,
+ series = "Fast Computers",
+ publisher = "Academic Press",
+ address = "New York",
+ edition = "Third",
+ month = sep,
+ year = 1977,
+ note = "This is a cross-referenced BOOK (collection) entry",
+}
+
+@MANUAL{manual-minimal,
+ key = "Manmaker",
+ title = "The Definitive Computer Manual",
+}
+
+@MANUAL{manual-full,
+ author = "Larry Manmaker",
+ title = "The Definitive Computer Manual",
+ organization = "Chips-R-Us",
+ address = "Silicon Valley",
+ edition = "Silver",
+ month = apr # "-" # may,
+ year = 1986,
+ note = "This is a full MANUAL entry",
+}
+
+@MASTERSTHESIS{mastersthesis-minimal,
+ author = "{\'{E}}douard Masterly",
+ title = "Mastering Thesis Writing",
+ school = "Stanford University",
+ year = 1988,
+}
+
+@MASTERSTHESIS{mastersthesis-full,
+ author = "{\'{E}}douard Masterly",
+ title = "Mastering Thesis Writing",
+ school = "Stanford University",
+ type = "Master's project",
+ address = "English Department",
+ month = jun # "-" # aug,
+ year = 1988,
+ note = "This is a full MASTERSTHESIS entry",
+}
+
+@MISC{misc-minimal,
+ key = "Missilany",
+ note = "This is a minimal MISC entry",
+}
+
+@MISC{misc-full,
+ author = "Joe-Bob Missilany",
+ title = "Handing out random pamphlets in airports",
+ howpublished = "Handed out at O'Hare",
+ month = oct,
+ year = 1984,
+ note = "This is a full MISC entry",
+}
+
+@STRING{STOC-key = "OX{\singleletter{stoc}}"}
+
+@STRING{ACM = "The OX Association for Computing Machinery"}
+
+@STRING{STOC = " Symposium on the Theory of Computing"}
+
+@INPROCEEDINGS{inproceedings-minimal,
+ author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis",
+ title = "On Notions of Information Transfer in {VLSI} Circuits",
+ booktitle = "Proc. Fifteenth Annual ACM" # STOC,
+ year = 1983,
+}
+
+@INPROCEEDINGS{inproceedings-full,
+ author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis",
+ title = "On Notions of Information Transfer in {VLSI} Circuits",
+ editor = "Wizard V. Oz and Mihalis Yannakakis",
+ booktitle = "Proc. Fifteenth Annual ACM" # STOC,
+ number = 17,
+ series = "All ACM Conferences",
+ pages = "133--139",
+ month = mar,
+ year = 1983,
+ address = "Boston",
+ organization = ACM,
+ publisher = "Academic Press",
+ note = "This is a full INPROCEDINGS entry",
+}
+
+@INPROCEEDINGS{inproceedings-crossref,
+ crossref = "whole-proceedings",
+ author = "Alfred V. Oaho and Jeffrey D. Ullman and Mihalis Yannakakis",
+ title = "On Notions of Information Transfer in {VLSI} Circuits",
+ organization = "",
+ pages = "133--139",
+ note = "This is a cross-referencing INPROCEEDINGS entry",
+}
+
+@PROCEEDINGS{proceedings-minimal,
+ key = STOC-key,
+ title = "Proc. Fifteenth Annual" # STOC,
+ year = 1983,
+}
+
+@PROCEEDINGS{proceedings-full,
+ editor = "Wizard V. Oz and Mihalis Yannakakis",
+ title = "Proc. Fifteenth Annual" # STOC,
+ number = 17,
+ series = "All ACM Conferences",
+ month = mar,
+ year = 1983,
+ address = "Boston",
+ organization = ACM,
+ publisher = "Academic Press",
+ note = "This is a full PROCEEDINGS entry",
+}
+
+@PROCEEDINGS{whole-proceedings,
+ key = STOC-key,
+ organization = ACM,
+ title = "Proc. Fifteenth Annual" # STOC,
+ address = "Boston",
+ year = 1983,
+ booktitle = "Proc. Fifteenth Annual ACM" # STOC,
+ note = "This is a cross-referenced PROCEEDINGS",
+}
+
+@PHDTHESIS{phdthesis-minimal,
+ author = "F. Phidias Phony-Baloney",
+ title = "Fighting Fire with Fire: Festooning {F}rench Phrases",
+ school = "Fanstord University",
+ year = 1988,
+}
+
+@PHDTHESIS{phdthesis-full,
+ author = "F. Phidias Phony-Baloney",
+ title = "Fighting Fire with Fire: Festooning {F}rench Phrases",
+ school = "Fanstord University",
+ type = "{PhD} Dissertation",
+ address = "Department of French",
+ month = jun # "-" # aug,
+ year = 1988,
+ note = "This is a full PHDTHESIS entry",
+}
+
+@TECHREPORT{techreport-minimal,
+ author = "Tom Terrific",
+ title = "An {$O(n \log n / \! \log\log n)$} Sorting Algorithm",
+ institution = "Fanstord University",
+ year = 1988,
+}
+
+@TECHREPORT{techreport-full,
+ author = "Tom T{\'{e}}rrific",
+ title = "An {$O(n \log n / \! \log\log n)$} Sorting Algorithm",
+ institution = "Fanstord University",
+ type = "Wishful Research Result",
+ number = "7",
+ address = "Computer Science Department, Fanstord, California",
+ month = oct,
+ year = 1988,
+ note = "This is a full TECHREPORT entry",
+}
+
+@UNPUBLISHED{unpublished-minimal,
+ author = "Ulrich {\"{U}}nderwood and Ned {\~N}et and Paul {\={P}}ot",
+ title = "Lower Bounds for Wishful Research Results",
+ note = "Talk at Fanstord University (this is a minimal UNPUBLISHED entry)",
+}
+
+@UNPUBLISHED{unpublished-full,
+ author = "Ulrich {\"{U}}nderwood and Ned {\~N}et and Paul {\={P}}ot",
+ title = "Lower Bounds for Wishful Research Results",
+ month = nov # ", " # dec,
+ year = 1988,
+ note = "Talk at Fanstord University (this is a full UNPUBLISHED entry)",
+}
+
+@MISC{random-note-crossref,
+ key = {Volume-2},
+ note = "Volume~2 is listed under Knuth \cite{book-full}"
+}
GitHub Events
Total
- Release event: 1
- Push event: 3
- Create event: 1
Last Year
- Release event: 1
- Push event: 3
- Create event: 1