Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Zotero): generate bib file for the cited references #398

Open
jooyoungseo opened this issue Feb 25, 2024 · 3 comments
Open

feat(Zotero): generate bib file for the cited references #398

jooyoungseo opened this issue Feb 25, 2024 · 3 comments
Labels
🤲 help wanted Send help, please

Comments

@jooyoungseo
Copy link

Type: Feature Request

Using Cite from Zotero command, people can easily insert citations from their Zotero libraries.

Once all the citations are inserted into tex file, could we generate a bib (default "./references.bib") file for the cited references?

I think this is technically possible as demonstrated in other extension, such as "XING.zotero-cite".

However, their extension does not support "vscode"citation method.

I believe this feature would be greatly appreciated by many Zotero+LaTeX users.

Extension version: 0.4.13
VS Code version: Code - Insiders 1.87.0-insider (c11a2dd4d52e38cb92b8c464f47a7b02bb7c8762, 2024-02-24T01:20:40.384Z)
OS version: Windows_NT x64 10.0.22631
Modes:

@leoleoasd
Copy link
Collaborator

Thank you for your suggestion, this indeed is an interesting and useful feature. However, currently, I don't have time to implement it. I'm putting this on my todo list, and if anyone can help with a PR I'll be happy to review and merge it.
In the meantime, in my current setup, I'm using better bibtex's auto export feature, which can automatically export the entire library to a single .bib file.

@leoleoasd leoleoasd added the 🤲 help wanted Send help, please label Feb 25, 2024
@volatile-static
Copy link

Here is a code sample for citing items in Zotero and adding them to bib. I hope this helps!

import * as vscode from "vscode";
import Client, {
  MultiReadResponse,
  SingleReadResponse,
} from "zotero-api-client";

const apiKey = "KDRPW", userId = 123;
const zotero = new Client(apiKey).library("user", userId);

class Collection {
  constructor(
    public key: string,
    public name: string,
    public parentCollection: string | false
  ) {}
}

class Item {
  constructor(
    public key: string,
    public name: string,
    public doi: string,
    public creators: object[]
  ) {}
}

type ZoteroObject = Collection | Item;

async function getTopCollections() {
  const collections = await zotero.collections().top().get(),
    data = (collections as MultiReadResponse).getData();
  return data.map(
    (c: any) => new Collection(c.key, c.name, c.parentCollection)
  );
}

async function getSubCollections(collectionKey: string) {
  const collections = await zotero
      .collections(collectionKey)
      .subcollections()
      .get(),
    data = (collections as MultiReadResponse).getData();
  return data.map(
    (c: any) => new Collection(c.key, c.name, c.parentCollection)
  );
}

async function getItems(collectionKey: string) {
  const items = await zotero.collections(collectionKey).items().top().get(),
    data = (items as MultiReadResponse).getData();
  return data.map((i: any) => new Item(i.key, i.title, i.doi, i.creators));
}

async function getItemInfo(itemKey: string) {
  const item = await zotero.items(itemKey).get({ include: "bibtex" });
  return (item as SingleReadResponse).getData();
}

function matchCiteKeys(bibtex: string) {
  const regex = /@\S*?{\S*?,/g;
  return bibtex.match(regex);
}

function getCiteKey(bibtex: string) {
  const regex = /@\S*?{(\S*?),/;
  return regex.exec(bibtex)?.[1];
}

async function citeItem(item: Item) {
  const editor = vscode.window.activeTextEditor;
  if (!editor) return;

  const file = await vscode.workspace.findFiles("zotero.bib");
  if (!file.length) return;

  const info = await getItemInfo(item.key),
    bibtex: string = (<any>info).bibtex,
    citeKey = matchCiteKeys(bibtex)!,
    doc = await vscode.workspace.openTextDocument(file[0]),
    citeKeys = matchCiteKeys(doc.getText());

  editor.edit((editBuilder) =>
    editBuilder.insert(editor.selection.active, `\\cite{${getCiteKey(bibtex)}}`)
  );
  if (!citeKeys || !citeKeys.includes(citeKey[0])) {
    const edit = new vscode.WorkspaceEdit(),
      position = new vscode.Position(0, 0);
    edit.insert(file[0], position, bibtex);
    vscode.workspace.applyEdit(edit);
  }
}

class SimpleTreeProvider implements vscode.TreeDataProvider<ZoteroObject> {
  private _onDidChangeTreeData = new vscode.EventEmitter<undefined>();
  readonly onDidChangeTreeData = this._onDidChangeTreeData.event;

  refresh(): void {
    this._onDidChangeTreeData.fire(undefined);
  }

  getTreeItem(element: ZoteroObject): vscode.TreeItem {
    const treeItem = new vscode.TreeItem(element.name);
    treeItem.contextValue = element instanceof Item ? "item" : "collection";
    treeItem.collapsibleState =
      element instanceof Item
        ? vscode.TreeItemCollapsibleState.None
        : vscode.TreeItemCollapsibleState.Collapsed;
    return treeItem;
  }

  getChildren(element?: Collection) {
    if (!element) return getTopCollections();
    else
      return Promise.all([
        getSubCollections(element.key),
        getItems(element.key),
      ]).then((arr) => arr.flat());
  }
}

export function activate(context: vscode.ExtensionContext) {
  const treeDataProvider = new SimpleTreeProvider();
  vscode.window.createTreeView("latero", {
    treeDataProvider,
    showCollapseAll: true,
    canSelectMany: true,
  });
  context.subscriptions.push(
    vscode.commands.registerCommand("latero.cite", citeItem),
    vscode.commands.registerCommand(
      "latero.refresh",
      treeDataProvider.refresh.bind(treeDataProvider)
    )
  );
}

@thebluepotato
Copy link

thebluepotato commented May 24, 2024

Since Better BibTex is required anyway, you could use the auto-export to your project. Wouldn't that help?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🤲 help wanted Send help, please
Projects
None yet
Development

No branches or pull requests

4 participants