Completed
Pull Request — master (#5)
by
unknown
05:15 queued 02:03
created

LaTeXFormatter::escape()   B

Complexity

Conditions 1
Paths 1

Size

Total Lines 29
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

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