~fd/ersei.net

6684a71978d9db171f19d9e0b6ac9ea63c4f59a7 — Ersei Saggi a month ago 49c8c60
Staticmath updates
M pages/03.blog/36.typst/item.en.md => pages/03.blog/36.typst/item.en.md +1 -1
@@ 106,7 106,7 @@ $$

The equivalent Typst code looks something like this:

```
```typ
mat(augment: #(-1),
  -2, 3, 1, 0;
   1, 0, 1, 3;

M plugins/highlight-php/highlight-php.php => plugins/highlight-php/highlight-php.php +60 -56
@@ 3,23 3,24 @@
namespace Grav\Plugin;

use Composer\Autoload\ClassLoader;
use Grav\Common\Grav;
use DomainException;
use Exception;
use Grav\Common\Filesystem\Folder;
use Grav\Common\Grav;
use Grav\Common\Inflector;
use Grav\Common\Plugin;
use Grav\Framework\File\File;
use RocketTheme\Toolbox\Event\Event;
use DomainException;
use Exception;

/**
 * Class HighlightPhpPlugin
 * @package Grav\Plugin
 */
class HighlightPhpPlugin extends Plugin
{
    private const BUILT_IN_STYLES_DIRECTORY = 'plugin://highlight-php/vendor/scrivo/highlight.php/styles/';

    private const CUSTOM_STYLES_DIRECTORY = 'user-data://highlight-php/';

    /**
     * @return array
     *


@@ 41,12 42,10 @@ class HighlightPhpPlugin extends Plugin

    /**
     * Composer autoload
     *
     * @return ClassLoader
     */
    public function autoload(): ClassLoader
    {
        return require __DIR__ . '/vendor/autoload.php';
        return require __DIR__.'/vendor/autoload.php';
    }

    public function onMarkdownInitialized(Event $event)


@@ 61,19 60,17 @@ class HighlightPhpPlugin extends Plugin
        $markdown->addBlockType('`', 'Highlight', true, true, 0);

        // Taken entirely from Parsedown with a few modifications to add the relevant classes and such
        $markdown->blockHighlight = function($Line) {
            if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches))
            {
                $Element = array(
        $markdown->blockHighlight = function ($Line) {
            if (preg_match('/^['.$Line['text'][0].']{3,}[ ]*([^`]+)?[ ]*$/', $Line['text'], $matches)) {
                $Element = [
                    'name' => 'code',
                    'handler' => 'line',
                    'text' => '',
                );
                ];

                $language = "";
                $language = '';

                if (isset($matches[1]))
                {
                if (isset($matches[1])) {
                    /**
                     * https://www.w3.org/TR/2011/WD-html5-20110525/elements.html#classes
                     * Every HTML element may have a class attribute specified.


@@ 90,43 87,40 @@ class HighlightPhpPlugin extends Plugin

                    $class = 'hljs language-'.$language;

                    $Element['attributes'] = array(
                    $Element['attributes'] = [
                        'class' => $class,
                    );
                    ];
                }

                $Block = array(
                $Block = [
                    'char' => $Line['text'][0],
                    'lang' => $language,
                    'element' => array(
                    'element' => [
                        'name' => 'pre',
                        'handler' => 'element',
                        'text' => $Element,
                        'attributes' => [
                            'class' => "hljs"
                        ]
                    ),
                );
                            'class' => 'hljs',
                        ],
                    ],
                ];

                return $Block;
            }
        };

        $markdown->blockHighlightContinue = function($Line, $Block) {
            if (isset($Block['complete']))
            {
        $markdown->blockHighlightContinue = function ($Line, $Block) {
            if (isset($Block['complete'])) {
                return;
            }

            if (isset($Block['interrupted']))
            {
            if (isset($Block['interrupted'])) {
                $Block['element']['text']['text'] .= "\n";

                unset($Block['interrupted']);
            }

            if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text']))
            {
            if (preg_match('/^'.$Block['char'].'{3,}[ ]*$/', $Line['text'])) {
                $Block['element']['text']['text'] = substr($Block['element']['text']['text'], 1);

                $Block['complete'] = true;


@@ 139,7 133,7 @@ class HighlightPhpPlugin extends Plugin
            return $Block;
        };

        $markdown->blockHighlightComplete = function($Block) {
        $markdown->blockHighlightComplete = function ($Block) {
            $text = $Block['element']['text']['text'];

            $Block['element']['text']['text'] = $this->render($text, $Block['lang']);


@@ 160,19 154,19 @@ class HighlightPhpPlugin extends Plugin

        // enable other required events
        $this->enable([
            'onPageInitialized' => ['onPageInitialized', 0]
            'onPageInitialized' => ['onPageInitialized', 0],
        ]);

        if (!(is_dir(self::CUSTOM_STYLES_DIRECTORY))) {
        if (! (is_dir(self::CUSTOM_STYLES_DIRECTORY))) {
            Folder::create(self::CUSTOM_STYLES_DIRECTORY);
            $demoCss = '.hljs { font-family: cursive; }';
            $file = new File(self::CUSTOM_STYLES_DIRECTORY . 'exampleOverrideCursiveFont.css');
            $file = new File(self::CUSTOM_STYLES_DIRECTORY.'exampleOverrideCursiveFont.css');
            $file->save($demoCss);
        }
    }

    /**
     * Check for per-page configuration settings 
     * Check for per-page configuration settings
     */
    public function onPageInitialized()
    {


@@ 190,13 184,13 @@ class HighlightPhpPlugin extends Plugin
        $config = $this->mergeConfig($page);

        // per-page strategy, no page override: don't load assets
        if (!$isSiteWide && !$pagePreferencesSet) {
        if (! $isSiteWide && ! $pagePreferencesSet) {
            return;
        }

        // two cases where we proceed to check against the style !== 'None' rules...
        if (
            !$pagePreferencesSet && $isSiteWide ||          // ➊ plugin defaults: no user override with site-wide strategy
            ! $pagePreferencesSet && $isSiteWide ||          // ➊ plugin defaults: no user override with site-wide strategy
            $pagePreferencesSet && $config['enabled']       // ➋ per-page preferences set and the user set 'enabled' to true
        ) {
            // set the configured theme, falling back to 'default' if unset somehow


@@ 216,7 210,8 @@ class HighlightPhpPlugin extends Plugin

    /**
     * Helper function to make other code's intent clearer
     * @param string $styleName basename of a CSS file
     *
     * @param  string  $styleName  basename of a CSS file
     * @return bool true if $styleName is not the string 'None'
     */
    private function shouldLoadAsset($styleName)


@@ 226,31 221,32 @@ class HighlightPhpPlugin extends Plugin

    /**
     * Adds a CSS file to Grav's asset pipeline
     * @param string $styleName basename of the CSS file
     * @param string $builtInOrCustom which directory to look for the file
     *
     * @param  string  $styleName  basename of the CSS file
     * @param  string  $builtInOrCustom  which directory to look for the file
     */
    private function addHighLightingAssets($styleName, $builtInOrCustom)
    {
        $locator = $this->grav['locator'];
        switch ($builtInOrCustom) {
            case 'builtIn':
                $themePath = $locator->findResource(self::BUILT_IN_STYLES_DIRECTORY . $styleName . '.css', false);
                $themePath = $locator->findResource(self::BUILT_IN_STYLES_DIRECTORY.$styleName.'.css', false);
                break;
            case 'custom':
                $themePath = $locator->findResource(self::CUSTOM_STYLES_DIRECTORY  . $styleName . '.css', false);
                $themePath = $locator->findResource(self::CUSTOM_STYLES_DIRECTORY.$styleName.'.css', false);
                break;
            default:
                $errorMsg = 'Highlight-PHP plugin error: Invalid parameter passed to `addHighLightingAssets`. Must be one of `builtIn` or `custom`. No syntax highlighting CSS will be loaded.';
                $this->grav['debugger']->addMessage($errorMsg);
                $this->grav['log']->error($errorMsg);

                return;
        }
        $this->grav['assets']->addCss($themePath);
    }

    /**
     * 
     * @param string $directory Input URI to search
     * @param  string  $directory  Input URI to search
     * @return string[] associative array of css filenames, plus a 'None' entry
     */
    private static function getThemesInDirectory($directory)


@@ 258,14 254,14 @@ class HighlightPhpPlugin extends Plugin
        /** @var UniformResourceLocator $locator */
        $locator = Grav::instance()['locator'];

        # initialize an array with our default
        $themes = array('None' => 'None');
        // initialize an array with our default
        $themes = ['None' => 'None'];

        # use the findResource method to resolve the plugin stream location; false returns a relative path
        // use the findResource method to resolve the plugin stream location; false returns a relative path
        $stylesPath = $locator->findResource($directory, false);

        # plain old PHP glob. See https://www.php.net/manual/en/function.glob.php
        $cssFiles = glob($stylesPath . '/*.css');
        // plain old PHP glob. See https://www.php.net/manual/en/function.glob.php
        $cssFiles = glob($stylesPath.'/*.css');

        foreach ($cssFiles as $cssFile) {
            $theme = basename($cssFile, '.css');


@@ 277,26 273,31 @@ class HighlightPhpPlugin extends Plugin

    /**
     * List of themes available that ship with the plugin
     *
     * @return string[]
     */
    public static function getBuiltInThemes()
    {
        $builtInThemes = HighlightPhpPlugin::getThemesInDirectory(self::BUILT_IN_STYLES_DIRECTORY);

        return $builtInThemes;
    }

    /**
     * List of themes available in the user/data/highlight-php directory
     *
     * @return string[] associative array of css filenames, plus a 'None' entry
     */
    public static function getCustomThemes()
    {
        $customThemes = HighlightPhpPlugin::getThemesInDirectory(self::CUSTOM_STYLES_DIRECTORY);

        return $customThemes;
    }

    /**
     * List of themes available in the user/data/highlight-php directory
     *
     * @return string[] associative array of css filenames, plus a 'None' entry
     */
    public static function getUserActivationPreference()


@@ 311,19 312,22 @@ class HighlightPhpPlugin extends Plugin
    }

    /**
     * Helper method to produce processed, syntax-highlightable HTML 
     * @param string $lang language or alias supported by highlight.php
     * @param string $code the code to tokenize and syntax highlight
     * @param bool $isInline true if the snippet is to be rendered inline, false if block
     * Helper method to produce processed, syntax-highlightable HTML
     *
     * @param  string  $lang  language or alias supported by highlight.php
     * @param  string  $code  the code to tokenize and syntax highlight
     * @param  bool  $isInline  true if the snippet is to be rendered inline, false if block
     * @return string the HTML with the appropriate classes to be rendered as highlighted in the browser
     * @throws DomainException 
     * @throws Exception 
     *
     * @throws DomainException
     * @throws Exception
     */
    private function render(string $code, string $lang)
    {
        try {
            $hl = new \Highlight\Highlighter();
            $hl = new \Highlight\Highlighter;
            $highlighted = $hl->highlight($lang, $code);

            return $highlighted->value;
        } catch (DomainException $e) {
            // if someone uses an unsupported language, we don't want to break the site

M plugins/staticmath/shortcodes/StaticMathShortcode.php => plugins/staticmath/shortcodes/StaticMathShortcode.php +24 -22
@@ 1,10 1,8 @@
<?php

namespace Grav\Plugin\Shortcodes;
use Grav\Common\Grav;

use DomainException;
use Exception;
use Grav\Common\Grav;
use Thunder\Shortcode\Shortcode\ShortcodeInterface;

class StaticMathShortcode extends Shortcode


@@ 15,29 13,33 @@ class StaticMathShortcode extends Shortcode

        $rawHandlers->add('tex', function (ShortcodeInterface $sc) {
            $content = $sc->getContent();
			return $this->render($content);

            return $this->render($content);
        });
        $rawHandlers->add('texi', function (ShortcodeInterface $sc) {
            $content = $sc->getContent();
			return $this->render($content, true);

            return $this->render($content, true);
        });
    }

	private function render($content, $inline = false) {
		$mode = $inline ? "inline" : "block";
		$staticmath_server = Grav::instance()['config']->get('plugins.staticmath.server');
		$postfield = "mode=" . urlencode($mode) . "&data=" . urlencode($content);
		$ch = curl_init($staticmath_server);
		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
		curl_setopt($ch, CURLOPT_POSTFIELDS, $postfield);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, [
			'Content-Length: ' . strlen($postfield)
		]);
		$result = curl_exec($ch);
		if (!$result) {
			return "<pre>" . $content . "</pre>";
		}
		return $result;
	}
    private function render($content, $inline = false)
    {
        $mode = $inline ? 'inline' : 'block';
        $staticmath_server = Grav::instance()['config']->get('plugins.staticmath.server');
        $postfield = 'mode='.urlencode($mode).'&data='.urlencode($content);
        $ch = curl_init($staticmath_server);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postfield);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Length: '.strlen($postfield),
        ]);
        $result = curl_exec($ch);
        if (! $result) {
            return '<pre>'.$content.'</pre>';
        }

        return $result;
    }
}

M plugins/staticmath/staticmath.php => plugins/staticmath/staticmath.php +169 -167
@@ 7,188 7,190 @@
 *
 * Based on the code from the Grav MathJax plugin: https://github.com/sommerregen/grav-plugin-mathjax
 *
 * @package		StaticMath
 * @version		2.0.1
 *
 * @link		<https://sr.ht/~fd/grav-plugin-staticmath>
 *
 * @author		Ersei Saggi <contact@ersei.net>
 * @copyright	2024, Ersei Saggi
 * @license		<http://opensource.org/licenses/MIT>		MIT
 */

namespace Grav\Plugin;

use Composer\Autoload\ClassLoader;
use Grav\Common\Grav;
use Grav\Common\Page\Page;
use Grav\Common\Plugin;
use RocketTheme\Toolbox\Event\Event;
use Grav\Common\Page\Page;
use Grav\Common\Grav;

/**
 * Class StaticmathPlugin
 * @package Grav\Plugin
 */
class StaticmathPlugin extends Plugin
{

	/**
	 * Instance of StaticMath class
	 *
	 * @var Grav\Plugin\StaticMath
	 */
	protected $staticmath;

	/**
	 * @return array
	 *
	 * The getSubscribedEvents() gives the core a list of events
	 *	 that the plugin wants to listen to. The key of each
	 *	 array section is the event that the plugin listens to
	 *	 and the value (in the form of an array) contains the
	 *	 callable (or function) as well as the priority. The
	 *	 higher the number the higher the priority.
	 */
	public static function getSubscribedEvents(): array
	{
		return [
			'onPluginsInitialized' => ['onPluginsInitialized', 0],
			'onGetPageBlueprints' => ['onGetPageBlueprints', 0],
			'onMarkdownInitialized' => ['onMarkdownInitialized', 0],
		];
	}

	/**
	 * Composer autoload
	 *
	 * @return ClassLoader
	 */
	public function autoload(): ClassLoader
	{
		return require __DIR__ . '/vendor/autoload.php';
	}

	/**
	 * Register shortcodes
	 */
	public function onShortcodeHandlers()
	{
		$this->grav['shortcode']->registerAllShortcodes(__DIR__ . '/shortcodes');
	}

	/**
	 * Initialize the plugin
	 */
	public function onPluginsInitialized(): void
	{
		// Don't proceed if we are in the admin plugin
		if ($this->isAdmin()) {
			$this->active = false;
			return;
		}

		$this->enable([
			'onShortcodeHandlers' => ['onShortcodeHandlers', 0],
			'onPageInitialized' => ['onPageInitialized', 0]
		]);
	}

	public function onMarkdownInitialized(Event $event)
	{
		$markdown = $event['markdown'];

		$page = $this->grav['page'];
		$config = $this->mergeConfig($page);
		if (!($config->get('enabled') && $config->get('active'))) {
			return;
		}
		$markdown->addBlockType('$', 'Staticmath', true, false);
		$markdown->addInlineType('$', 'Staticmath');

		$markdown->blockStaticmath = function($Line) {
			if (preg_match('/^\$\$$/', $Line['text'], $matches)) {
				$Block = [
					'element' => [
						'name' => 'div',
						'handler' => 'lines',
						'text' => [],
					],
				];

				return $Block;
			}
		};

		$markdown->blockStaticmathContinue = function($Line, array $Block) {
			if (isset($Block['interrupted'])) {
				return;
			}
			if (!preg_match('/^\$\$$/', $Line['text'])) {
				$Block['element']['text'][] = $Line['text'];
			} else {
				$text = implode(
					"\n",
					$Block['element']['text']
				);

				$Block['element']['text'] = (array) $this->render($text);
			}
			return $Block;
		};

		$markdown->inlineStaticmath = function($Line) {
			if (preg_match('/\$(.+?)\$/', $Line['text'], $matches)) {
				$Block = [
					'extent' => strlen($matches[0]),
					'element' => [
						'name' => 'span',
						'handler' => 'lines',
						'text' => (array) $this->render($matches[1], true),
					],
				];
				return $Block;
			}
		};
	}

	/**
	 * Initialize Twig configuration and filters.
	 */
	public function onPageInitialized()
	{
		/** @var Page $page */
		$page = $this->grav['page'];

		// Skip if active is set to false
		$config = $this->mergeConfig($page);
		if (!($config->get('enabled') && $config->get('active'))) {
			return;
		}

		if ($this->config->get('plugins.staticmath.built_in_css')) {
			$this->grav['assets']->add('plugins://staticmath/assets/css/Temml-Latin-Modern.css');
		}
	}

	public function onGetPageBlueprints($event)
	{
		$types = $event->types;
		$types->scanBlueprints('plugin://staticmath/blueprints');
	}

	private function render($content, $inline = false) {
		$mode = $inline ? "inline" : "block";
		$staticmath_server = Grav::instance()['config']->get('plugins.staticmath.server');
		$postfield = "mode=" . urlencode($mode) . "&data=" . urlencode($content);
		$ch = curl_init($staticmath_server);
		curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
		curl_setopt($ch, CURLOPT_POSTFIELDS, $postfield);
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_HTTPHEADER, [
			'Content-Length: ' . strlen($postfield)
		]);
		$result = curl_exec($ch);
		if (!$result) {
			return "<pre>" . $content . "</pre>";
		}
		return $result;
	}

    /**
     * Instance of StaticMath class
     *
     * @var Grav\Plugin\StaticMath
     */
    protected $staticmath;

    /**
     * @return array
     *
     * The getSubscribedEvents() gives the core a list of events
     *	 that the plugin wants to listen to. The key of each
     *	 array section is the event that the plugin listens to
     *	 and the value (in the form of an array) contains the
     *	 callable (or function) as well as the priority. The
     *	 higher the number the higher the priority.
     */
    public static function getSubscribedEvents(): array
    {
        return [
            'onPluginsInitialized' => ['onPluginsInitialized', 0],
            'onGetPageBlueprints' => ['onGetPageBlueprints', 0],
            'onMarkdownInitialized' => ['onMarkdownInitialized', 0],
        ];
    }

    /**
     * Composer autoload
     */
    public function autoload(): ClassLoader
    {
        return require __DIR__.'/vendor/autoload.php';
    }

    /**
     * Register shortcodes
     */
    public function onShortcodeHandlers()
    {
        $this->grav['shortcode']->registerAllShortcodes(__DIR__.'/shortcodes');
    }

    /**
     * Initialize the plugin
     */
    public function onPluginsInitialized(): void
    {
        // Don't proceed if we are in the admin plugin
        if ($this->isAdmin()) {
            $this->active = false;

            return;
        }

        $this->enable([
            'onShortcodeHandlers' => ['onShortcodeHandlers', 0],
            'onPageInitialized' => ['onPageInitialized', 0],
        ]);
    }

    public function onMarkdownInitialized(Event $event)
    {
        $markdown = $event['markdown'];
        $markdown->addBlockType('$', 'Staticmath', true, true);
        $markdown->addInlineType('$', 'Staticmath');

        $markdown->blockStaticmath = function ($Line) {
            if (preg_match('/^\$\$$/', $Line['text'], $matches)) {
                $Block = [
                    'element' => [
                        'name' => 'div',
                        'handler' => 'lines',
                        'text' => [],
                    ],
                ];

                return $Block;
            }
        };

        $markdown->blockStaticmathContinue = function ($Line, array $Block) {
            if (isset($Block['interrupted'])) {
                return;
            }
            if (! preg_match('/^\$\$$/', $Line['text'])) {
                $Block['element']['text'][] = $Line['text'];
            } else {
                $Block['complete'] = true;
            }

            return $Block;
        };

        $markdown->blockStaticmathComplete = function (array $Block) {
            $text = implode(
                "\n",
                $Block['element']['text']
            );

            $Block['element']['text'] = (array) $this->render($text);

            return $Block;
        };

        $markdown->inlineStaticmath = function ($Line) {
            if (preg_match('/\$(.+?)\$/', $Line['text'], $matches)) {
                $Block = [
                    'extent' => strlen($matches[0]),
                    'element' => [
                        'name' => 'span',
                        'handler' => 'lines',
                        'text' => (array) $this->render($matches[1], true),
                    ],
                ];

                return $Block;
            }
        };
    }

    /**
     * Initialize Twig configuration and filters.
     */
    public function onPageInitialized()
    {
        /** @var Page $page */
        $page = $this->grav['page'];

        // Skip if active is set to false
        $config = $this->mergeConfig($page);
        if (! ($config->get('enabled') && $config->get('active'))) {
            return;
        }

        if ($this->config->get('plugins.staticmath.built_in_css')) {
            $this->grav['assets']->add('plugins://staticmath/assets/css/Temml-Latin-Modern.css');
        }
    }

    public function onGetPageBlueprints($event)
    {
        $types = $event->types;
        $types->scanBlueprints('plugin://staticmath/blueprints');
    }

    private function render($content, $inline = false)
    {
        $mode = $inline ? 'inline' : 'block';
        $staticmath_server = Grav::instance()['config']->get('plugins.staticmath.server');
        $postfield = 'mode='.urlencode($mode).'&data='.urlencode($content);
        $ch = curl_init($staticmath_server);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postfield);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Length: '.strlen($postfield),
        ]);
        $result = curl_exec($ch);
        if (! $result) {
            return '<pre>'.$content.'</pre>';
        }

        return $result;
    }
}