erusev / parsedown

Better Markdown Parser in PHP
https://parsedown.org
MIT License
14.79k stars 1.13k forks source link

Alerts: how to make it recognizes the next line of Markdown Alerts? #884

Open Meng-Heng opened 2 months ago

Meng-Heng commented 2 months ago

What I'm trying to convert:

> [!IMPORTANT] 
> 42

Start:

return $block = array(
                'element' => array(
                    'name' => 'div',
                    'attributes' => array('class' => "markdown-alert markdown-alert-$alertType"),
                    'handler' => 'elements',
                    'text' => array(
                        array(
                            'name' => 'p',
                            'attributes' => array('class' => "markdown-alert-title"),
                            'rawHtml' => $iconType
                        ),
                        array(
                            'name' => 'p',
                            'text' => '', // How to get the 42 to insert itself here?
                        )
                    )
                )

Continues:

protected function blockContinue($line, $block) {
if(preg_match('/^\>\s*(.*)$/', $line['text'], $matches)) {
            $block['element']['text'][1]['text'] = $matches[1];
        } else {
            $block['complete'] = true; 
        }
        $block['element']['text'][1]['text'] .= "\n" . $line['body'];
        return $block;
}

I'm trying to get whatever is in the new line to correctly go to the 'text' above. But when I run, this is the error:

TypeError: Parsedown::element(): Argument #1 ($Element) must be of type array, string given

Any help will be appreciated. Thank you!

Hi-ImKyle commented 1 month ago

I'd love something like this too

BenjaminHoegh commented 2 weeks ago

It would be someting like this.

protected function blockAlert($Line): ?array
    {
        // List alert types from the config (e.g., 'NOTE', 'WARNING')
        $alertTypes = ['NOTE', 'WARNING'];

        // Build the regex pattern dynamically based on the alert types
        $alertTypesPattern = implode('|', array_map('strtoupper', $alertTypes));

        // Create the full regex pattern for matching alert block syntax
        $pattern = '/^> \[!(' . $alertTypesPattern . ')\]/';

        // Check if the line matches the alert pattern
        if (preg_match($pattern, $Line['text'], $matches)) {
            $type = strtolower($matches[1]); // Extract the alert type and convert to lowercase
            $title = ucfirst($type); // Capitalize the first letter for the alert title

            // Get class name for alerts from the configuration
            $class = 'markdown-alert';

            // Build the alert block with appropriate HTML attributes and content
            $Block = [
                'element' => [
                    'name' => 'div',
                    'attributes' => [
                        'class' => "{$class} {$class}-{$type}", // Add alert type as a class (e.g., 'alert alert-note')
                    ],
                    'handler' => 'elements', // Use 'elements' because we'll be adding more content elements later
                    'text' => [
                        [
                            'name' => 'p',
                            'attributes' => [
                                'class' => "{$class}-title", // Assign title-specific class for the alert
                            ],
                            'text' => $title, // Set the alert title (e.g., "Note")
                        ],
                    ],
                ],
            ];

            return $Block; // Return the parsed alert block
        }

        return null; // Return null if the line does not match the alert pattern
    }

    protected function blockAlertContinue($Line, array $Block)
    {
        // List alert types from the config (e.g., 'NOTE', 'WARNING')
        $alertTypes = ['NOTE', 'WARNING'];

        // Build the regex pattern dynamically based on the alert types
        $alertTypesPattern = implode('|', array_map('strtoupper', $alertTypes));

        // Create the full regex pattern for identifying new alert blocks
        $pattern = '/^> \[!(' . $alertTypesPattern . ')\]/';

        // If the line matches a new alert block, terminate the current one
        if (preg_match($pattern, $Line['text'])) {
            return null; // Return null to terminate the current alert block
        }

        // Check if the line continues the current alert block with '>' followed by content
        if ($Line['text'][0] === '>' && preg_match('/^> ?(.*)/', $Line['text'], $matches)) {
            // If the block was interrupted, add an empty paragraph for spacing
            if (isset($Block['interrupted'])) {
                $Block['element']['text'][] = ['text' => ''];
                unset($Block['interrupted']); // Reset the interrupted status
            }

            // Append the new line content to the current block
            $Block['element']['text'][] = [
                'name' => 'p',
                'text' => $matches[1], // Add the text following the '>'
            ];

            return $Block; // Return the updated block
        }

        // If the line does not start with '>' and the block is not interrupted, append it
        if (!isset($Block['interrupted'])) {
            $Block['element']['text'][] = [
                'name' => 'p',
                'text' => $Line['text'], // Add the text directly to the alert block
            ];

            return $Block; // Return the updated block
        }

        return null; // Return null if the continuation conditions are not met
    }

    protected function blockAlertComplete($Block)
    {
        return $Block; // Finalize and return the alert block
    }

this is from my own code, I have tried to remove any unnecessary code for the example, but let me know if you need more help

Meng-Heng commented 2 weeks ago

Hi @BenjaminHoegh, I've seen your work on the ParsedownEntended extension when trying to launch my package. Although, I found a workaround without using the BlockContinue or Complete, your code looks promising. I will need to test it sometime.

Thanks for taking the time! I'll let you know.

BenjaminHoegh commented 2 weeks ago

Workaround? Interesting how did you achieve that?