org-roam / org-roam-ui

A graphical frontend for exploring your org-roam Zettelkasten
GNU General Public License v3.0
1.95k stars 108 forks source link

[MINOR] org-transclusion support #105

Open tefkah opened 2 years ago

tefkah commented 2 years ago

** Have you checked whether this feature is not already on the project board?

Yes

Is your feature request related to a problem? Please describe.

Org-roam-ui doesn't do anything with transclusion made with org-transclusion atm, which is a shame.

Describe the solution you'd like

a) Have these transclusions recognized by uniorg b) Show transclusions as a special link which can be expanded into the current text (probably should set it to auto-expand)

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

Additional context Add any other context or screenshots about the feature request here.

rasendubi commented 2 years ago

a) Have these transclusions recognized by uniorg

I think the easiest way to implement this is to add a unified plugin after uniorg-parse that would traverse all #+transclude: keywords and process them (keywords are already recognized by uniorg). Probably, convert them to hast element nodes. uniorg-rehype will pass them forward untouched. Then you can use a custom component in rehype-react to implement expansion.

I don’t think I can support this from uniorg side as uniorg does not have access to other org files (unfortunately). Looking through org-transclusion, one thing that is missing in uniorg parser is targets. I’ll try to add this soon.

tefkah commented 2 years ago

Wow that's a faster response than I could even hope for! Yes that would be my ideal solution as well, as long as I can have access to them after uniorg-rehype is done with them I will figure out the rest! Thank you so much!

rasendubi commented 2 years ago

The key is to add a unified plugin between uniorg-parse and uniorg-rehype.

Something like this:

unified()
  .use(parse)
  .use(() => (node) => {
    // visit from unist-util-visit
    visit(node, 'keyword', (keyword) => {
      if (keyword.key.toLowerCase() === 'transclusion') {
        // h from hastscript. or manually as { type: 'element', tagName: 'transclusion', properties: { value: keyword.value } }
        Object.assign(keyword, h('transclusion', { value: keyword.value }));
      }
    })
  })
  ...
  .use(uniorg2rehype);
meedstrom commented 2 years ago

I do not know what unified or uniorg are. I don't suppose someone could advise me on how to learn enough to implement this?

rasendubi commented 2 years ago

unified[1] is an ecosystem of tools for file processing (parsing file to AST, transforming AST, and converting AST to string). There are some tutorials on the unified website and online but basically it works as a pipe.

uniorg[2] is an org-mode parser compatible with unified.

In the above comment, there is a snippet to traverse all #+TRANSCLUSION: keywords and convert them to tags. This should probably also parse the transclusion specifier string—extract id, line numbers or anchors—and pass these as attributes to transclusion tag.

The last bit of the puzzle is rehype-react[3]—a unified plugin to transform rehype (unified's HTML AST) to React elements. We need a new Transclusion React component that loads the node, extracts the transcluded part, and renders it.

Hope this helps.

If you want to work on this, feel free to publish any WIP code you have—I can help with bits of code and provide more guidance.

[1] https://github.com/unifiedjs/unified [2] https://github.com/rasendubi/uniorg [3] https://github.com/rehypejs/rehype-react

Zerogaku commented 9 months ago

It's the only thing currently stopping me from fully using org-transclusion 😅, wouldn't org transclusion act as a reference node of sorts?