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

What is the idiomatic way to extend the module? #1

Open
wanradt opened this issue May 15, 2024 · 13 comments
Open

What is the idiomatic way to extend the module? #1

wanradt opened this issue May 15, 2024 · 13 comments
Assignees
Labels
feature request New feature or request

Comments

@wanradt
Copy link

wanradt commented May 15, 2024

Hi!

It is so good to see a fresh module for MD processing.

I need to extend MD syntax a bit for my own needs. For example, I need to define <span>-blocks inside some block level elements. MD standard syntax does not have tools for this occasion.

What is the best way to extend Markdown::Perl

Wbr,

Gunnar

@mkende
Copy link
Owner

mkende commented May 15, 2024

Hi Gunnar,

For now this module is not extensible from the outside. But for this particular use case I was planning to extend the inline_delimiters option so that instead of mapping delimiters to tag names, delimiters could also be mapped to class names which would result in a span created with this class. You could use any symbol (including any unicode symbol) to trigger this behaviour.

Would this work for your use case?

Mathias

@wanradt
Copy link
Author

wanradt commented May 15, 2024

I think it would work. In the current situation, I don't need classes, but they don't bother me either.

What mechanism do you see for delimiter<->class mapping?

Another use case I am looking extending for is mapping inner links: I use markup like [some_id] which should processed to URL (edit: actually link) like https://www.example.com/product/some_id

So if I can't extend the module I use some preprocessor and everything is still fine. Just looking which way to go.

Thank you!

@mkende
Copy link
Owner

mkende commented May 15, 2024

Well, if you just need a span without any class, this is already supported through the inline_modifiers option that you can pass either on the command line or programmatically depending on the interface that you are using.

The option itself is not documented currently (I'll fix that) but, meanwhile, you can look at the tests in t/400-opt-inline_delimiters.t to see how to set it.

Regarding you links question, what your want sounds like collapsed reference link, but where the definition would not be in the document itself, right? In that case I can trivially add an option to specify a set of predefined link references that can be used in a document. Would that work for you?

@wanradt
Copy link
Author

wanradt commented May 16, 2024

Yes, the inline_delimiters option to convert solves my case very well.

As for the inner links part: the converting could benefit from some possible pre- or postprocessing callback. In my case, I need to make database calls to resolve my links. Callbacks would add simple extendability to the converting process. But this is simply manageable in the program flow anyway.

Thank you for your great work and prompt responses!

@mkende
Copy link
Owner

mkende commented May 16, 2024

Can you query your database to collect all the possible links in advance or do you need to do that when you see a link reference or after all the link references have been seen?

(by the way, I have pushed a new version with some documentation for the inline_delimiters option and the improved support for emitting <span> elements with arbitrary class)

@wanradt
Copy link
Author

wanradt commented May 17, 2024

Querieng beforehand is not an option, possible ID-s are hundreds of thousands but some of these are needed in just for ~5% of cases. Or something like that. So accessing the database is certainly better only on a need basis.

@mkende
Copy link
Owner

mkende commented May 17, 2024

Ok, I have just pushed a new version (1.06) that adds a set_hooks method with, for now, a single resolve_link_ref hook that is called when a link ref cannot be resolved within the document. You should be able to use it to query your database (you can use the t/500-hooks-resolve_link_ref.t test as an example, although everything is documented too).

Let me know if this works for your use case. I would also be interested in knowing what it is that you want to use this module for if you can share some details.

@mkende mkende self-assigned this May 17, 2024
@mkende mkende added the feature request New feature or request label May 17, 2024
@wanradt
Copy link
Author

wanradt commented May 22, 2024

Hi!

I had no time to test your new version so far. Today I made it.

set hook is halfway for my situation, because I don't see the possibility of setting link text from the hook, I have target and title, but no way to set link text programmatically from the hook. I'd prefer more flexible hook, anyway. In the current situation it is for just one case solution.

Background: for now we have some quasi-HTML product descriptions, but for better manageability, I'd like to convert them into markdown. These descriptions contain many inner links in the form of [123], [i:123] or [k:123] which are converted on the fly onto correct links. I made a simple test script (which also gives some warnings) if you have time to look into that. Real output is best seen on our old web (in Estonian): https://villu.raamatukoi.ee/cgi-bin/raamat?287256

Thank you!

use strict; use warnings; use utf8;
use Markdown::Perl;

my %options = (
    inline_delimiters => { '..' => 'span' },
);
my $converter = Markdown::Perl->new(%options);
$converter->set_hooks(resolve_link_ref => \&hook);

my $links = {
  14846 => 'Ketlin Priilinn',
  1155 => 'Maimu Berg',
  4779 => 'Jan Kaus',
};

my $markdown;
while (<DATA>) {
  $markdown .= $_;
}

my $html = $converter->convert($markdown);
print $html;

sub hook {
  my ($ref) = @_;

  if ($ref =~ /i:(\d+)/i ) {
    return { target => "isik?$1", title => $links->{ $1 }  };
  } elsif ($ref =~ /k:(\d+)/i ) {
    return { target => "kirjastus?$1", title => $links->{ $1 }  };
  } elsif ($ref =~ /^(\d+)/i ) {
    return { target => "raamat?$1", title => $links->{ $1 }  };
  } elsif ($ref eq 'bar') {
    return { target => '/', title => 'BAR' };
  }
  return { target => '/something' };
}

__DATA__
Sume suveöö on vaevu jõudnud mõisaperemehe sünnipäevale sametise joone alla tõmmata, kui majas kärgatab lask. Otto Müller, keda kõik teadsid, aga vähesed armastasid, on surnud.

Juhtumiga asuvad tegelema kogenud politseiuurija Gabriel Vanem ja tema verivärske paariline Agnes Maramaa. Perekonna ja uurijate omavahelistest suhetest kujuneb pinev kassi ja hiire mäng, kus igaühel on oma tõde ja õigus ning midagi maailma eest varjata.

Raamat «Kes tappis Otto Mülleri?» juhatab sisse uue kodumaise krimisarja, kus põnevust ei paku üksnes kuritegude lahendamine, vaid ka inimsuhted. Sarja läbivaks teemaks kujuneb uurijate Agnese ja Gabrieli lugu. Esimese raamatu põhjal valmib 2021. aasta teises pooles Eesti esimene Viaplay originaalseriaal, mille režissöör on René Vilbre ja peategelastena astuvad üles eesti tippnäitlejad Märt Avandi, Jaan Rekkor, Tambet Tuisk jt.

> Birk Rohelend seob raamatus peenekoeliselt humaansuse ja vastutuse keerulistes inimsuhetes, mis loob mitmetahulise fooni kulmineeruvaks salapäraks ja ootamatuteks lahendusteks. Tegemist on autori äärmiselt küpse ja võimsa jutustusega mastaapsest perekonnast Eestis. ..Filmiprodutsent Ingrid Eloranta.

> Kriipivalt ehe mõrvamüsteerium. ..Kirjanik [i:14846]..

> «Kui sul on selline maja, siis on kõik kogu aeg hästi,» ütleb raamatus Anneken. Otto Mülleri mõis on taust suurepärasele põnevikule, mis hakkab tegelaste haaval hargnema, pakkudes psühholoogilist pinget hingele, filmilikku naudingut fantaasiale ning üllatavat puänti. Suurepärane tegelaste galerii! Vaimustav! Agathe Christie vääriline! ..Kirjanik [i:1155]..

> Kui kõigil pereliikmetel on olemas motiiv tappa perepea, kes neile head elu võimaldab, siis millisest perekonnast me räägime? Isegi mõrva uurivatel detektiividel on motiiv... Selline huvitav lugu! ..Filmirežissöör René Vilbre..

> Tegelaskujude eestlastele ebatüüpiline avameelsus ülekuulamisruumis paljastab midagi olulist mitte ainult nende endi, vaid kogu Eesti elus: kuidas eristada välimist ja sisemist? Millisel määral määratlevad meie suhteid näivused ja muljed, olgu need siis soolised või seisuslikud? Üks võimalik vastus kõlab nii: kõik pole kuld, mis kiiskab. Vahel isegi mitte kassikuld, pestagu seda kas või verega. Küsimuse «Kes?» tagant ilmub veel olulisem küsimus: «Miks?». Vastus on ühtaegu lihtne ja lahendamatu. ..Kirjanik [i:4779]..

Autor **Birk Rohelend** (s. 1981) on kirjutanud mitmeid auhinnatud romaane ja loonud armastatud telesarju nagu «Padjaklubi», «Nurjatud tüdrukud» ja «Restart»; ta on ka filmi «Vasaku jala reede» üks kaasstsenariste. «Minu suurim õnn on see, et sündisin Nõukogude Liidus ja kasvasin vabariiki. Olen saanud lähedalt näha nii absoluutset vireluse põhja kui ka rikaste ja ilusate glamuurset elustiili. Tee on viinud mind Eesti väikelinnast õppima USAsse parima stsenaristikamentori **Lew Hunteri** juurde. Mind huvitavad psühholoogilised mustrid, vaatenurga vahetamine ning suhtedünaamika inimeste vahel – need kõik on leidnud selles teoses uue väljundi.»

@mkende
Copy link
Owner

mkende commented May 22, 2024

Adding support for setting the link text in the hook is easy and I can do that (it’s not there because you can’t set the link text using the normal link reference mechanism).

Regarding more flexible hook, can you provide other scenarios where you would need them? This can be added but there are a couple of issues:

  • the internal API for the document tree is not very clean and a more generic hook would need to expose it.
  • in the case of your example with the links, I don’t think that it would be super interesting because there wouldn’t be much more to do in term of the document tree than a textual rewriting where a high level api would not offer much.

But if you can provide a couple of example of use-case for a more generic hook I can see how they could be exposed.

@mkende
Copy link
Owner

mkende commented May 25, 2024

Fyi I pushed a new version where the hook can also set the link content.

@wanradt
Copy link
Author

wanradt commented May 27, 2024

Maybe this is not a good idea, but how I see a more generic approach is through adding pre- or postprocessing to the whole MD string/document. For example, in the same case: I need to programmatically add link text too. One more generic way would be if I in preprocessing phase substitute my specific [i:123] notation with standard [JohnDoe](/person/123) notation, and then in MD->HTML processing it is converted as it is. This pre/postprocessing does not have to be part of Markdown::Perl, but if you see it fitting in, I would use it.

In my view, this processing works as a hook, which gets the whole md-string as input and should return it after processing. I mean, there may be a need to expand MD for someone's needs. For example, you may need to add some metadata. You may need to parse existing metadata somehow. Or process some specific notation.

Thank you for your work!

@mkende
Copy link
Owner

mkende commented May 29, 2024

If you want to process the input markdown string, why do you prefer doing this as a hook inside convert rather than outside, before passing the string to the method?

@wanradt
Copy link
Author

wanradt commented May 29, 2024

I don't know. My point is worn so thin already, I can't see it even myself. Thank you for your time and great work!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants