<commit_before><?php

namespace Coyote\Services\Parser\Parsers;

use Coyote\Repositories\Contracts\UserRepositoryInterface as User;

// dziedziczymy po Parsedown a nie Parsedown Extra z uwagi na buga. Parsedown Extra wycina reszte linii jezeli
// w danej linii znajdzie sie tag. np. <ort>ktory</ort> w ogle => <ort>ktory</ort>
class Markdown extends \Parsedown implements ParserInterface
{
    /**
     * @var User
     */
    private $user;

    /**
     * @var bool
     */
    private $enableHashParser = false;

    /**
     * @var bool
     */
    private $enableUserTagParser = true;

    /**
     * @var string
     */
    private $hashRoute = 'microblog.tag';

    /**
     * @param User $user
     * @throws \Exception
     */
    public function __construct(User $user)
    {
        $this->InlineTypes['@'][] = 'UserTag';
        $this->inlineMarkerList .= '@';

        $this->InlineTypes['#'][] = 'Hash';
        $this->inlineMarkerList .= '#';

        $this->user = $user;
    }

    /**
     * @param bool $flag
     * @return Markdown
     */
    public function setEnableHashParser(bool $flag)
    {
        $this->enableHashParser = $flag;

        return $this;
    }

    /**
     * @param boolean $flag
     * @return Markdown
     */
    public function setEnableUserTagParser(bool $flag)
    {
        $this->enableUserTagParser = $flag;

        return $this;
    }

    /**
     * @param array $excerpt
     * @return array|void
     */
    protected function inlineHash($excerpt)
    {
        if (!$this->enableHashParser) {
            return null;
        }

        if (preg_match('~#([\p{L}\p{Mn}0-9\._+-]+)~u', $excerpt['text'], $matches)) {
            $tag = mb_strtolower($matches[1]);

            return [
                'extent' => strlen($matches[0]),
                'element' => [
                    'name' => 'a',
                    'text' => $matches[0],
                    'attributes' => [
                        'href' => route($this->hashRoute, [$tag])
                    ]
                ]
            ];
        }
    }

    /**
     * We don't want <h1> in our text
     *
     * @param $line
     * @return array|null
     */
    protected function blockHeader($line)
    {
        $block = parent::blockHeader($line);

        if (isset($block['element'])) {
            if ($block['element']['name'] == 'h1') {
                return null;
            }
        }

        return $block;
    }

    /**
     * Find the position of the first occurrence of a character in a string
     *
     * @param $haystack
     * @param string $needle
     * @param int $offset
     * @return bool|mixed
     */
    private function strpos($haystack, $needle, $offset = 0)
    {
        $result = [];

        foreach (str_split($needle) as $char) {
            if (($pos = strpos($haystack, $char, $offset)) !== false) {
                $result[] = $pos;
            }
        }

        return $result ? min($result) : false;
    }

    /**
     * Parse users login
     *
     * @param array $excerpt
     * @return array|void
     */
    protected function inlineUserTag($excerpt)
    {
        if (!$this->enableUserTagParser) {
            return null;
        }

        $text = &$excerpt['text'];
        $start = strpos($text, '@');

        if ($this->isNotEmail($excerpt)) {
            $exitChar = $text[$start + 1] === '{' ? '}' : ":,.\'\n) "; // <-- space at the end
            $end = $this->strpos($text, $exitChar, $start);

            if ($end === false) {
                $end = mb_strlen($text) - $start;
            }

            $length = $end - $start;
            $start += 1;
            $end -= 1;

            if ($exitChar == '}') {
                $start += 1;
                $end -= 1;

                $length += 1;
            }

            $name = substr($text, $start, $end);
            $user = $this->user->findByName($name);

            if ($user) {
                return [
                    'extent' => $length,
                    'element' => [
                        'name' => 'a',
                        'text' => '@' . $name,
                        'attributes' => [
                            'href' => route('profile', [$user->id]),
                            'data-user-id' => $user->id,
                            'class' => 'mention'
                        ]
                    ]
                ];
            }
        }
    }

    private function isNotEmail(&$excerpt)
    {
        // the whole text
        $context = &$excerpt['context'];
        // "@" position
        $start = mb_strpos($context, $excerpt['text']);
        // previous character (before "@")
        $preceding = mb_substr($context, $start - 1, 1);

        return mb_substr($excerpt['text'], $start + 1, 1) !== false
            && ($start === 0 || $preceding ===' ' || $preceding === '(');
    }

    /**
     * @param string $text
     * @return string
     */
    public function parse($text)
    {
        return $this->text($text);
    }
}
<commit_msg>spacing<commit_after><?php

namespace Coyote\Services\Parser\Parsers;

use Coyote\Repositories\Contracts\UserRepositoryInterface as User;

// dziedziczymy po Parsedown a nie Parsedown Extra z uwagi na buga. Parsedown Extra wycina reszte linii jezeli
// w danej linii znajdzie sie tag. np. <ort>ktory</ort> w ogle => <ort>ktory</ort>
class Markdown extends \Parsedown implements ParserInterface
{
    /**
     * @var User
     */
    private $user;

    /**
     * @var bool
     */
    private $enableHashParser = false;

    /**
     * @var bool
     */
    private $enableUserTagParser = true;

    /**
     * @var string
     */
    private $hashRoute = 'microblog.tag';

    /**
     * @param User $user
     * @throws \Exception
     */
    public function __construct(User $user)
    {
        $this->InlineTypes['@'][] = 'UserTag';
        $this->inlineMarkerList .= '@';

        $this->InlineTypes['#'][] = 'Hash';
        $this->inlineMarkerList .= '#';

        $this->user = $user;
    }

    /**
     * @param bool $flag
     * @return Markdown
     */
    public function setEnableHashParser(bool $flag)
    {
        $this->enableHashParser = $flag;

        return $this;
    }

    /**
     * @param boolean $flag
     * @return Markdown
     */
    public function setEnableUserTagParser(bool $flag)
    {
        $this->enableUserTagParser = $flag;

        return $this;
    }

    /**
     * @param array $excerpt
     * @return array|void
     */
    protected function inlineHash($excerpt)
    {
        if (!$this->enableHashParser) {
            return null;
        }

        if (preg_match('~#([\p{L}\p{Mn}0-9\._+-]+)~u', $excerpt['text'], $matches)) {
            $tag = mb_strtolower($matches[1]);

            return [
                'extent' => strlen($matches[0]),
                'element' => [
                    'name' => 'a',
                    'text' => $matches[0],
                    'attributes' => [
                        'href' => route($this->hashRoute, [$tag])
                    ]
                ]
            ];
        }
    }

    /**
     * We don't want <h1> in our text
     *
     * @param $line
     * @return array|null
     */
    protected function blockHeader($line)
    {
        $block = parent::blockHeader($line);

        if (isset($block['element'])) {
            if ($block['element']['name'] == 'h1') {
                return null;
            }
        }

        return $block;
    }

    /**
     * Find the position of the first occurrence of a character in a string
     *
     * @param $haystack
     * @param string $needle
     * @param int $offset
     * @return bool|mixed
     */
    private function strpos($haystack, $needle, $offset = 0)
    {
        $result = [];

        foreach (str_split($needle) as $char) {
            if (($pos = strpos($haystack, $char, $offset)) !== false) {
                $result[] = $pos;
            }
        }

        return $result ? min($result) : false;
    }

    /**
     * Parse users login
     *
     * @param array $excerpt
     * @return array|void
     */
    protected function inlineUserTag($excerpt)
    {
        if (!$this->enableUserTagParser) {
            return null;
        }

        $text = &$excerpt['text'];
        $start = strpos($text, '@');

        if ($this->isNotEmail($excerpt)) {
            $exitChar = $text[$start + 1] === '{' ? '}' : ":,.\'\n) "; // <-- space at the end
            $end = $this->strpos($text, $exitChar, $start);

            if ($end === false) {
                $end = mb_strlen($text) - $start;
            }

            $length = $end - $start;
            $start += 1;
            $end -= 1;

            if ($exitChar == '}') {
                $start += 1;
                $end -= 1;

                $length += 1;
            }

            $name = substr($text, $start, $end);
            $user = $this->user->findByName($name);

            if ($user) {
                return [
                    'extent' => $length,
                    'element' => [
                        'name' => 'a',
                        'text' => '@' . $name,
                        'attributes' => [
                            'href' => route('profile', [$user->id]),
                            'data-user-id' => $user->id,
                            'class' => 'mention'
                        ]
                    ]
                ];
            }
        }
    }

    private function isNotEmail(&$excerpt)
    {
        // the whole text
        $context = &$excerpt['context'];
        // "@" position
        $start = mb_strpos($context, $excerpt['text']);
        // previous character (before "@")
        $preceding = mb_substr($context, $start - 1, 1);

        return mb_substr($excerpt['text'], $start + 1, 1) !== false
            && ($start === 0 || $preceding === ' ' || $preceding === '(');
    }

    /**
     * @param string $text
     * @return string
     */
    public function parse($text)
    {
        return $this->text($text);
    }
}

{'fraction_non_alphanumeric': 0.15997621171573, 'fraction_numerical': 0.003766478342749529, 'mean_word_length': 1.4161877394636015, 'pattern_counts': {'":': 2, '<': 17, '<?xml version=': 0, '>': 77, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '237652', 'n_tokens_mistral': 3122, 'n_tokens_neox': 2954, 'n_words': 644}