Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
LilypondErrorMessageBeautifier
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 3
30
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 beautifyMessage
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
12
 formatErrorMatchLine
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2/*
3  Score, a MediaWiki extension for rendering musical scores with LilyPond.
4  Copyright © 2011 Alexander Klauer
5
6  This program is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15
16  You should have received a copy of the GNU General Public License
17  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18
19*/
20
21namespace MediaWiki\Extension\Score;
22
23/**
24 * Convert the std error output of lilypond into a concise html form.
25 */
26class LilypondErrorMessageBeautifier {
27    /**
28     * Lilyponds error reporting line regex, only the line with the error line, column and message.
29     */
30    private const LILYPOND_ERR_REGEX = '/\.ly:(?<line>\d+):(?<column>\d+): error: (?<message>.+)$/m';
31
32    private const BEAUTIFIED_ERR_FORMAT = "line %d - column %d:\n%s";
33    private const BEAUTIFIED_ERR_SEPARATOR = "\n--------\n";
34
35    /**
36     * @var int
37     *
38     * The line number where user's score input is inserted, within the final
39     * lilypond file that is passed to lilypond executable.
40     *
41     * The first line is assumed to start at the first column (no column offset).
42     */
43    private $scoreFirstLineOffset;
44
45    /**
46     * @param int $scoreFirstLineOffset
47     */
48    public function __construct( $scoreFirstLineOffset = 0 ) {
49        $this->scoreFirstLineOffset = $scoreFirstLineOffset;
50    }
51
52    /**
53     * Beautifies lilypond executable error messages by:
54     * - adjusting line numbers fit the user's input
55     * - stripping out all echoed erroneous code
56     * - stripping out unnecessary keywords
57     *
58     * @param string $message
59     *
60     * @return string
61     */
62    public function beautifyMessage( $message ) {
63        if ( !preg_match_all(
64            self::LILYPOND_ERR_REGEX,
65            $message,
66            $errorMatches,
67            PREG_SET_ORDER
68        ) ) {
69            return '';
70        }
71
72        $beautifiedMessages = [];
73
74        foreach ( $errorMatches as $errorMatch ) {
75            $beautifiedMessages[] = $this->formatErrorMatchLine( $errorMatch );
76        }
77
78        return implode( self::BEAUTIFIED_ERR_SEPARATOR, $beautifiedMessages );
79    }
80
81    /**
82     * @param array $errorMatch
83     * @return string
84     */
85    private function formatErrorMatchLine( array $errorMatch ) {
86        return sprintf(
87            self::BEAUTIFIED_ERR_FORMAT,
88            intval( $errorMatch[ 'line' ] ) - $this->scoreFirstLineOffset,
89            intval( $errorMatch[ 'column' ] ),
90            $errorMatch[ 'message' ]
91        );
92    }
93}