rasendubi / uniorg

An accurate Org-mode parser for JavaScript/TypeScript
https://oleksii.shmalko.com/uniorg
GNU General Public License v3.0
256 stars 24 forks source link

Which backend does uniorg use? #76

Open frankjonen opened 1 year ago

frankjonen commented 1 year ago

I'm trying to get Org-Roam UI to recognise a link setup.

:follow just works as expected, :export to 'html works as well. In Roam UI, nothing show up rendered. Since they're using uniorg it seemed prudent to ask here directly what I can do so uniorg recognises added link types.

rasendubi commented 1 year ago

Hi. Uniorg is an org-mode parser/org-to-html converter implemented in typescript. Therefore, it doesn't use any org backend (or any elisp code) but tries to follow html.

I'm not sure I fully understand what you're trying to achieve. Could you share your example org file and desired html output?

frankjonen commented 1 year ago

Hi,

The org link is

[[obsidian:Vaultname:Example_file]]

It ends up dangling around in a span tag as obsidian:Vaultname:Example_file

The link the 'html exports comes out as

obsidian://open?vault=Vaultname&file=Examplefile

this is the link type setup:

(org-link-set-parameters
 "obsidian"
 :follow
 (lambda (path)
   (cl-destructuring-bind
       (vault file) (split-string path ":")
     (browse-url (format "obsidian://open?vault=%s&file=%s" vault file))
   )
   )
 :export
   (lambda (path description backend info)
     (cl-destructuring-bind
         (vault file) (split-string path ":")
       (format (pcase backend
                 ('html "<a href=\"obsidian://open?vault=%s&file=%s\">%s</a>"))
               vault file description)))
)

When you say "it tries to follow html", does that mean I can add to html and it follows what's in that or that it's set up to follow org's basic html "factory settings"?

rasendubi commented 1 year ago

"It tries to follow html" means that when implementing features I try to re-implement html backend behavior as close as makes sense. It mostly follows defaults but there are some configuration variables it re-implements as well (again, trying to follow elisp implementation if it makes sense).

The behavior you want to achieve can be implemented with a small unified plugin (you would need to modify org-roam-ui):

const processor = unified()
  ...
  .use(uniorgRehype)
  // the plugin must be applied after uniorg-rehype
  .use(inspectUrls, { // inspectUrls from rehype-url-inspector
    inspectEach: ({ url, node, propertyName }) => {
      if (url.startsWith('obsidian:')) {
        const [obsidian, vault, file] = url.split(':');
        node[propertyName] = `obsidian://open?vault=${vault}&file=${file}`;
      }
    },
  });

It might be possible to implement this in a more generic way but you would still need to hack org-roam-ui to add your conversion function (as uniorg cannot call into elisp functions)

frankjonen commented 1 year ago

Thank you. I'll give that a shot and see what happens.

frankjonen commented 1 year ago

OK I've tried to find where something like that could be put. And the Sidebar/Link.tsx could be a candidate. No Idea how to implement it though, there's nothing resembling your example.

rasendubi commented 1 year ago

This is the place: util/processOrg.tsx

frankjonen commented 1 year ago

Thanks again for your help.

I've now modified it to this

  const orgProcessor = unified()
    .use(uniorgParse)
    .use(extractKeywords)
    .use(attachments, {
      idDir: attachDir || undefined,
      useInheritance,
    })
    .use(uniorgSlug)
    .use(uniorg2rehype, { useSections: true })
    .use(inspectUrls, {
        inspectEach: ({ url, node, propertyName }) => {
            if (url.startsWith('obsidian:')) {
                const [obsidian, vault, file] = url.split(':');
                node[propertyName] = `obsidian://open?vault=${vault}&file=${file}`;
                }
        },
    })

And it made no difference. Instead of links, it still renders as <span class"chakra-text obsidian:vaultname:filename css-1wobba0">Description</span>

tefkah commented 1 year ago

This wont really work, org-roam-ui is not setup to handle foreign non-http links.

Here is where http(s) links are handled, all other links get converted to spans. https://github.com/org-roam/org-roam-ui/blob/5ac74960231db0bf7783c2ba7a19a60f582e91ab/components/Sidebar/Link.tsx#L187-L189

If you want to manually add support for this, you can change it to something like

  if (type.replaceAll(/(http)?.*/g, '$1') || /^obsidian/.test(type)) {
    return <NormalLink href={href}>{children}</NormalLink>
  }
rasendubi commented 1 year ago

@tefkah oh, is there any reason why they are converted to spans?

tefkah commented 1 year ago

Hmmm I think it was to filter out bad links, e.g. to nonexisting nodes. Didn't think people would be using non-http/non-org-roam links in org-roam!