hans / obsidian-citation-plugin

Obsidian plugin which integrates your academic reference manager with the Obsidian editor. Search your references from within Obsidian and automatically create and reference literature notes for papers and books.
MIT License
1.11k stars 83 forks source link

Access to Keywords #61

Open MartinBloedorn opened 3 years ago

MartinBloedorn commented 3 years ago

Great plugin! Thanks for the work!

Might I suggest, providing access to Biblatex' keywords? I categorize my entries with keywords - essentially tags -, and it would be very nice to have them be imported as (hash)tags into the generated Markdown file.

For example, from my Biblatex:

@article{Alcorn1966,
  title = {Conversion of Parahydrogen to Orthohydrogen Using Nickel/Alumina Catalysts},
  author = {Alcorn, W},
  year = {1966},
  keywords = {Al,Ni,OP-Katalysatoren},
}

With a Citation template:

# {{title}}
{{keywords}}

I'd get output such as

# Conversion of Parahydrogen to Orthohydrogen Using Nickel/Alumina Catalysts
#Al #Ni #OP-Katalysatoren

That way, references are also clustered with tags, and can be filtered in the graph view, for example.

Thanks for the attention!

markjholmes commented 3 years ago

Hello!

Firstly a disclaimer that I am not expert at this at all, I've just fiddled until something worked. I've solved this by just going into the Javascript file "main.js" (located in the .obsidian/plugins/obsidian-citation-plugin directory) and adding a few lines. I don't think that this is the proper way to go about this but it works for me, and hopefully I'm not breaking any licencing laws.

I opened the file using Notepad++, and, within the definition of Library where getTemplateVariablesForCitekey is defined, I have inserted:

keywords: entry.keywords,

within the list of similarly named shortcuts (I personally inserted following the alphabetical order at line 49528).

image

Then, within EntryBibLaTeXAdapter at line 49830, I added:

    Object.defineProperty(EntryBibLaTeXAdapter.prototype, "keywords", {
        get: function () {
            var _k;
            return (_k = this.data.fields.keywords) === null || _k === void 0 ? void 0 : '#' + _k.join(' #').toLowerCase();
            },
        enumerable: false,
        configurable: true
    });

After saving this modified "main.js" file and restarting Obsidian, I can insert {{keywords}} in the "Literature note content template" (in the Citation settings window) which will add keywords as hashtags automatically.

The approach works only for single-word keywords. Any multi-word keywords stop this from working, as the space breaks the hashtag. I imagine you could fix this quite easily if you had any knowledge of Javascript by just replacing any instances of " " with "_" or "-" in the keyword string using .map but I didn't get it to work.

Hope that helped a bit, Mark

Edit: immediately after posting this, I figured out how to make it all lower case to avoid "Fish" vs "fish" discrepencies

orionpilot commented 3 years ago

Here is a way to get the keywords in without rewriting part of the plugin (based on #100). Use {{entry.data.fields.keywords}} to get them in the template. In my (short) testing, spaces between tags are not kept though (so "tag1, tag2, tag3" in .bib becomes "tag1,tag2,tag3" in the file). Unsure if this is a bug or if its intended.

Doing it like that, if you have the # with the keywords in the .bib, then they'll transfer over automatically.

But if you want to add the # with the import, I would say to use the templater plugin and its ability to run a user script. Pass the keywords in, regex the expression the way you want, and return that string. That's close to what I do for a different part of my template.

Hope that helps!

markjholmes commented 3 years ago

entry.data.fields.keywords is the way! For adding the # with the import I think you can also avoid using templater and just put this in your content template:

{{#each entry.data.fields.keywords}}{{#if @last}}#{{this}}{{else}}#{{this}}, {{/if}}{{/each}}

which will tag them and separate them by a comma and also not put a comma after the last one. If you want notes instead of tags then it's:

{{#each entry.data.fields.keywords}}{{#if @last}}[[{{this}}]]{{else}}[[{{this}}]], {{/if}}{{/each}}

ilkerduymaz commented 3 years ago

entry.data.fields.keywords is the way! For adding the # with the import I think you can also avoid using templater and just put this in your content template:

{{#each entry.data.fields.keywords}}{{#if @last}}#{{this}}{{else}}#{{this}}, {{/if}}{{/each}}

which will tag them and separate them by a comma and also not put a comma after the last one. If you want notes instead of tags then it's:

{{#each entry.data.fields.keywords}}{{#if @last}}[[{{this}}]]{{else}}[[{{this}}]], {{/if}}{{/each}}

This works like a charm, thanks a lot! Would you also happen to know how I could replace the white spaces in my Zotero tags with an underscore? For instance, I want to import the tag "face perception" as "#face_perception".

Chris-mik commented 3 years ago

entry.data.fields.keywords is the way! For adding the # with the import I think you can also avoid using templater and just put this in your content template: {{#each entry.data.fields.keywords}}{{#if @last}}#{{this}}{{else}}#{{this}}, {{/if}}{{/each}} which will tag them and separate them by a comma and also not put a comma after the last one. If you want notes instead of tags then it's: {{#each entry.data.fields.keywords}}{{#if @last}}[[{{this}}]]{{else}}[[{{this}}]], {{/if}}{{/each}}

This works like a charm, thanks a lot! Would you also happen to know how I could replace the white spaces in my Zotero tags with an underscore? For instance, I want to import the tag "face perception" as "#face_perception".

This worked for me but the underscore solution for keywords containing more than one words would be even more powerful! @ilkerduymaz have you found any solution?

rsomani95 commented 2 years ago

Here's another way to do it:

Add the following in your Literature Note Content Template

---
tags: {{entry.data.fields.keywords}}
---

Here's a full screenshot showing how it may fit into a more complex setup:

Settings:

Screenshot 2022-03-02 at 3 06 58 PM

And an example of a Lit Note:

Screenshot 2022-03-02 at 3 17 03 PM

Would you also happen to know how I could replace the white spaces in my Zotero tags with an underscore? For instance, I want to import the tag "face perception" as "#face_perception" This would be a killer feature indeed!

cc @orionpilot @markjholmes @ilkerduymaz @MartinBloedorn

byteSamurai commented 2 years ago

Isn't this issue actually solved?

Chris-mik commented 2 years ago

I have used the following solutions provided by other users:

amrap030 commented 2 years ago

entry.data.fields.keywords is the way! For adding the # with the import I think you can also avoid using templater and just put this in your content template:

{{#each entry.data.fields.keywords}}{{#if @last}}#{{this}}{{else}}#{{this}}, {{/if}}{{/each}}

which will tag them and separate them by a comma and also not put a comma after the last one. If you want notes instead of tags then it's:

{{#each entry.data.fields.keywords}}{{#if @last}}[[{{this}}]]{{else}}[[{{this}}]], {{/if}}{{/each}}

I am also very interested in how to automatically put underscores between words. Otherwise I can only use this for one-worded keywords.

nb-e commented 2 years ago

I am also very interested in how to automatically put underscores between words. Otherwise I can only use this for one-worded keywords.

From my limited understanding we can't do this using handlebars in a template, which is how these are implemented. We would have to register a 'helper' function, which we can't do inside of the Citation Template. @markjholmes is this your understanding?

byteSamurai commented 2 years ago

@nb-e I did this here. I use it for the exact same use-case: https://github.com/hans/obsidian-citation-plugin/pull/165

I think this issue overlaps with others, right?

nb-e commented 2 years ago

Yeah @byteSamurai good stuff. Looks like @hans is a bit MIA on this project. Probably trying to finish his PhD (can relate)

byteSamurai commented 2 years ago

I wonder, how many PhDs are using his plugins.. (can relate too 😅 )

nonsciencemark commented 2 years ago

From my limited understanding we can't do this using handlebars in a template, which is how these are implemented. We would have to register a 'helper' function, which we can't do inside of the Citation Template. @markjholmes is this your understanding?

Yes, @nb-e, this was my understanding too. It's a bit frustrating that we seem to almost have the functionality to do this auto-underscoring but not quite.

I think that it may be something that we can do in Zotero without getting Obsidian and Handlebars involved using the Better BibTex postscript and something along the lines of:

if (Translator.BetterTeX) {
    tex.add({name: 'keywords', value: zotero.tags.map(function(item) {return item.replace(/\s+/g, "_")}), sep: ', ', enc: 'tags'});
}

but I cannot get it to work yet because I don't really know Javascript :( I'd be grateful if anyone else could figure this out!

dderom commented 1 year ago

A reply from the dev of zotero better bibtex provided me with a good solution, where I wanted to have a Camelcase for my tags.

In obsidian add the following (thanks @markjholmes): {{#each entry.data.fields.keywords}}{{#if @last}}#{{this}}{{else}}#{{this}}, {{/if}}{{/each}}

In Zotero in the export tab, select the postscript and add the following code (works flawlessly with me):

if (Translator.BetterTeX && zotero.tags) {
  const tags = zotero.tags
    .map(tag => (typeof tag === 'string' ? tag : tag.tag))
    .map(tag => tag.replace(/\b\w/g, letter => letter.toUpperCase()).replace(/\s/g, ''))
  entry.add({ name: 'keywords', value: tags, enc: 'tags' })
}

Adjust to whatever fields you are using.