Passed
Push — master ( a2014d...22f24f )
by Kacper
03:29
created

LatexFormatter   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 89
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
dl 0
loc 89
ccs 0
cts 55
cp 0
rs 10
c 0
b 0
f 0
wmc 12
lcom 1
cbo 2

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 2
A format() 0 19 3
B escape() 0 29 1
B getOpenCloseTags() 0 24 5
A getStyle() 0 4 1
1
<?php
2
/**
3
 * Highlighter
4
 *
5
 * Copyright (C) 2016, Some right reserved.
6
 *
7
 * @author Kacper "Kadet" Donat <[email protected]>
8
 * @author Olgierd Grzyb <[email protected].me>
9
 *
10
 * Contact with author:
11
 * Xmpp:   [email protected]
12
 * E-mail: [email protected]
13
 *
14
 * From Kadet with love.
15
 */
16
17
namespace Kadet\Highlighter\Formatter;
18
19
use Kadet\Highlighter\Parser\Token\Token;
20
use Kadet\Highlighter\Parser\Tokens;
21
use Kadet\Highlighter\Utils\ArrayHelper;
22
23
/**
24
 * Class LatexFormatter
25
 *
26
 * @package Kadet\Highlighter\Formatter
27
 */
28
class LatexFormatter implements FormatterInterface
29
{
30
    private $_styles;
31
32
    public function __construct($styles = false)
33
    {
34
        $this->_styles = $styles ?: include __DIR__.'/../Styles/Latex/Default.php';
35
    }
36
37
    public function format(Tokens $tokens)
38
    {
39
        $source = $tokens->getSource();
40
41
        $result = '';
42
        $last   = 0;
43
44
        /** @var Token $token */
45
        foreach ($tokens as $token) {
46
            list($openTag, $closeTag) = $this->getOpenCloseTags($token);
47
            $result .= $this->escape(substr($source, $last, $token->pos - $last));
48
            $result .= $token->isStart() ? $openTag : $closeTag;
49
50
            $last = $token->pos;
51
        }
52
        $result .= substr($source, $last);
53
54
        return $result;
55
    }
56
57
    protected function escape($token)
58
    {
59
        $replace = [
60
            '\\' => '\\textbackslash{}',
61
            '{' => '\\{',
62
            '}' => '\\}',
63
            // When there is a \ in the source, it gets translated to
64
            // \textasciibackslash{}, but then the { and } are escaped to \{
65
            // and \}. This substitution reverts this.
66
            '\\textbackslash\\{\\}' => '\\textbackslash{}',
67
            '%' => '\\%',
68
            '_' => '\\_',
69
            '^' => '\\textasciicircum{}',
70
            '~' => '\\textasciitilde{}',
71
            '$' => '\\$',
72
            '&' => '\\&',
73
            '<' => '\\textless{}',
74
            '>' => '\\textgreater{}',
75
        ];
76
77
        // We can do just with a simple str_replace() because PHP promises to
78
        // process them sequentially:
79
        // https://secure.php.net/manual/en/function.str-replace.php#refsect1-function.str-replace-parameters
80
        return str_replace(
81
            array_keys($replace),
82
            array_values($replace),
83
            $token
84
        );
85
    }
86
87
    protected function getOpenCloseTags($token)
88
    {
89
        $openTag = $closeTag = '';
90
        $style = $this->getStyle($token);
91
92
        if (ArrayHelper::get($style, 'bold', false)) {
93
            $openTag .= '\\textbf{';
94
            $closeTag .= '}';
95
        }
96
        if (ArrayHelper::get($style, 'italic', false)) {
97
            $openTag .= '\\textsl{';
98
            $closeTag .= '}';
99
        }
100
        if (ArrayHelper::get($style, 'underline', false)) {
101
            $openTag .= '\\underline{';
102
            $closeTag .= '}';
103
        }
104
        if (($color = ArrayHelper::get($style, 'color', 'default')) !== 'default') {
105
            $openTag .= sprintf('\\textcolor{%s}{', $style['color']);
106
            $closeTag .= '}';
107
        }
108
109
        return [$openTag, $closeTag];
110
    }
111
112
    protected function getStyle($token)
113
    {
114
        return ArrayHelper::resolve($this->_styles, $token->name, []);
115
    }
116
}
117