.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.40) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Markdent::Manual 3pm" .TH Markdent::Manual 3pm "2021-02-24" "perl v5.32.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Markdent::Manual \- Using and Extending Markdent .SH "DESCRIPTION" .IX Header "DESCRIPTION" Markdent is an event-driven parser toolkit for Markdown. That's a mouthful, so let's go through that piece by piece, starting at the end. .PP Markdown is a wiki-esque plain text markup format that is easy to read and easy to write. It draws inspiration from how people have communicated in plain text email for a long time. For example, some text like \*(L"*really*\*(R" is parsed as emphasis around the word \*(L"really\*(R". .PP Existing Markdown tools in Perl (and in most other languages) are only able to convert Markdown directly to \s-1HTML.\s0 They are not really parsers, they're combined parser/converters. This is problematic if you want to do something with the document besides turn it into \s-1HTML.\s0 Maybe you'd like to parse it and cache an intermediate representation. Maybe you want to turn into markup-free text. Maybe you want to pull out just the links. .PP With Markdent, you can do any and all of those things (and you can turn Markdown into \s-1HTML\s0 too). .PP An event-driven parser like Markdown generates a \fIsequence of events\fR as the result of parsing a document. If you're familiar with the \s-1SAX API,\s0 that is another event-driven parser \s-1API.\s0 .PP With Markdent, these events can be things like \*(L"StartEmphasis\*(R", \*(L"StartLink\*(R", \&\*(L"EndCode\*(R", \*(L"Text\*(R", etc. .PP The parser feeds these events into a handler, and the handler can decide what to do with them. By decoupling parsing from other tasks, it gives you great power in dealing with the parse results. .PP When I call Markdent a parser \fItoolkit\fR, that means it is designed to be part of a larger ecosystem. You can write your handlers, and you can even write your own parser dialects as roles. .SH "HANDLERS" .IX Header "HANDLERS" A handler object receives events with the parser and does something with them. All handlers implement the Markdent::Role::Handler role, which simply requires a single method, \f(CW\*(C`$handler\->handle_event($event)\*(C'\fR. .PP If you're writing your own handler, you may find it convenient to consume the Markdent::Role::EventsAsMethods role. This provides a \f(CW\*(C`handle_event()\*(C'\fR implementation that calls a different method for each type of event. .PP This is used by the Markdent::Handler::HTMLStream::Document and Markdent::Handler::HTMLStream::Fragment handlers, for example. Since it generates a different tag for each event, it makes sense to have one method per event which knows what tag to generate. .PP On the other hand, the CaptureEvents handler doesn't care what type of event it receives, it just stores it for later use. It only needs to implement a \&\f(CW\*(C`handle_event()\*(C'\fR method to do its job. .SH "WHAT CAN YOU DO WITH MARKDENT?" .IX Header "WHAT CAN YOU DO WITH MARKDENT?" Markdent has a lot of parts, but you don't need to learn about all of them. .PP Here are some pointers for common tasks ... .SS "Converting Markdown to \s-1HTML\s0" .IX Subsection "Converting Markdown to HTML" Take a look at the Markdent::Handler::HTMLStream::Document. This turns the event stream into a stream of \s-1HTML\s0 output. You can send the output to any filehandle. Open a filehandle to a scalar to capture the output in memory. .PP You can use Markdent::Handler::HTMLStream::Fragment if you don't want to generate a complete \s-1HTML\s0 document. .SS "Cache Parse Results" .IX Subsection "Cache Parse Results" Use the Markdent::Handler::CaptureEvents handler to capture events for caching. You can then store the generated Markdent::CapturedEvents object using Storable. .SS "Do Both" .IX Subsection "Do Both" Use the Markdent::Handler::Multiplexer handler to do more than one thing at a time with the event stream. .SS "Write Your Own Handler" .IX Subsection "Write Your Own Handler" Writing a handler is pretty easy. Take a look at any of the existing handler classes for ideas. .SH "PARSER" .IX Header "PARSER" The core of the Markdent parser system is the Markdent::Parser module. This module doesn't actually do any parsing itself. Instead, it hooks together a block parser and a span parser, and lets the block parser start the real parsing process. .PP Markdent divides parsing into blocks and spans. The block parser looks for block-level constructs like paragraphs, lists, blockquotes, etc. For most of these constructs, it passes the contents of the block on to the span parser. The span parser looks for things like strong and emphasis markup, links, \s-1HTML\s0 entities, and so on. .PP Separating these two makes creating a Markdown dialect a bit easier, as you may find yourself just needing to alter the behavior of just the block \fIor\fR the span parser. .PP For example, the Theory dialect shipped with this distribution is mostly implemented as a role applied to the Standard dialect's block parser. .PP See the Theory dialect for an example of how to modify the core Markdown dialect. .SH "WHAT DOES THE NAME MEAN?" .IX Header "WHAT DOES THE NAME MEAN?" It's a combination of \*(L"Markdown\*(R" and \*(L"event\*(R".