• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

dg / texy / 22262497275

21 Feb 2026 07:01PM UTC coverage: 93.057% (+0.7%) from 92.367%
22262497275

push

github

dg
added CLAUDE.md

2426 of 2607 relevant lines covered (93.06%)

0.93 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.37
/src/Texy/Modules/EmoticonModule.php
1
<?php declare(strict_types=1);
2

3
/**
4
 * This file is part of the Texy! (https://texy.nette.org)
5
 * Copyright (c) 2004 David Grudl (https://davidgrudl.com)
6
 */
7

8
namespace Texy\Modules;
9

10
use Texy;
11
use function getimagesize, implode, is_array, is_file, krsort, preg_quote, rtrim, str_contains;
12

13

14
/**
15
 * Replaces emoticons with images or Unicode characters.
16
 */
17
final class EmoticonModule extends Texy\Module
18
{
19
        /** @var array<string, string>  supported emoticons and image files / chars */
20
        public array $icons = [
21
                ':-)' => '🙂',
22
                ':-(' => '☹',
23
                ';-)' => '😉',
24
                ':-D' => '😁',
25
                '8-O' => '😮',
26
                '8-)' => '😄',
27
                ':-?' => '😕',
28
                ':-x' => '😶',
29
                ':-P' => '😛',
30
                ':-|' => '😐',
31
        ];
32

33
        /** CSS class for emoticons */
34
        public ?string $class = null;
35

36
        /** @deprecated */
37
        public ?string $root = null;
38

39
        /** @deprecated */
40
        public ?string $fileRoot = null;
41

42

43
        public function __construct(Texy\Texy $texy)
1✔
44
        {
45
                $this->texy = $texy;
1✔
46
                $texy->allowed['emoticon'] = false;
1✔
47
                $texy->addHandler('emoticon', $this->solve(...));
1✔
48
                $texy->addHandler('beforeParse', $this->beforeParse(...));
1✔
49
        }
1✔
50

51

52
        private function beforeParse(): void
53
        {
54
                if (empty($this->texy->allowed['emoticon'])) {
1✔
55
                        return;
1✔
56
                }
57

58
                krsort($this->icons);
1✔
59

60
                $pattern = [];
1✔
61
                foreach ($this->icons as $key => $foo) {
1✔
62
                        $pattern[] = preg_quote($key, '#') . '+'; // last char can be repeated
1✔
63
                }
64

65
                $this->texy->registerLinePattern(
1✔
66
                        $this->pattern(...),
1✔
67
                        '#(?<=^|[\x00-\x20])(' . implode('|', $pattern) . ')#',
1✔
68
                        'emoticon',
1✔
69
                        '#' . implode('|', $pattern) . '#',
1✔
70
                );
71
        }
1✔
72

73

74
        /**
75
         * Callback for: :-))).
76
         * @param  string[]  $matches
77
         */
78
        public function pattern(Texy\LineParser $parser, array $matches): Texy\HtmlElement|string|null
1✔
79
        {
80
                $match = $matches[0];
1✔
81

82
                // find the closest match
83
                foreach ($this->icons as $emoticon => $foo) {
1✔
84
                        if (str_starts_with($match, $emoticon)) {
1✔
85
                                return $this->texy->invokeAroundHandlers('emoticon', $parser, [$emoticon, $match]);
1✔
86
                        }
87
                }
88

89
                return null;
×
90
        }
91

92

93
        /**
94
         * Finish invocation.
95
         */
96
        private function solve(Texy\HandlerInvocation $invocation, string $emoticon, string $raw): Texy\HtmlElement|string
1✔
97
        {
98
                $texy = $this->texy;
1✔
99
                $file = $this->icons[$emoticon];
1✔
100
                if (!str_contains($file, '.')) {
1✔
101
                        return $file;
1✔
102
                }
103

104
                $el = new Texy\HtmlElement('img');
1✔
105
                $el->attrs['src'] = Texy\Helpers::prependRoot($file, $this->root ?? $texy->imageModule->root);
1✔
106
                $el->attrs['alt'] = $raw;
1✔
107
                if ($this->class !== null) {
1✔
108
                        $el->attrs['class'] = (array) ($el->attrs['class'] ?? []);
1✔
109
                        $el->attrs['class'][] = $this->class;
1✔
110
                }
111

112
                // file path
113
                $file = rtrim($this->fileRoot ?? (string) $texy->imageModule->fileRoot, '/\\') . '/' . $file;
1✔
114
                if (@is_file($file)) { // intentionally @
1✔
115
                        $size = @getimagesize($file); // intentionally @
×
116
                        if (is_array($size)) {
×
117
                                $el->attrs['width'] = $size[0];
×
118
                                $el->attrs['height'] = $size[1];
×
119
                        }
120
                }
121

122
                $texy->summary['images'][] = $el->attrs['src'];
1✔
123
                return $el;
1✔
124
        }
125
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc