Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Completed
Pull Request — master (#52)
by Der Mundschenk
04:20
created

Dewidow_Fix::apply()   B

Complexity

Conditions 5
Paths 3

Size

Total Lines 12
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 5

Importance

Changes 0
Metric Value
dl 0
loc 12
ccs 6
cts 6
cp 1
rs 8.8571
c 0
b 0
f 0
cc 5
eloc 5
nc 3
nop 3
crap 5
1
<?php
2
/**
3
 *  This file is part of PHP-Typography.
4
 *
5
 *  Copyright 2014-2017 Peter Putzer.
6
 *  Copyright 2009-2011 KINGdesk, LLC.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  (at your option) any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License along
19
 *  with this program; if not, write to the Free Software Foundation, Inc.,
20
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
 *
22
 *  ***
23
 *
24
 *  @package mundschenk-at/php-typography
25
 *  @license http://www.gnu.org/licenses/gpl-2.0.html
26
 */
27
28
namespace PHP_Typography\Fixes\Node_Fixes;
29
30
use PHP_Typography\DOM;
31
use PHP_Typography\RE;
32
use PHP_Typography\Settings;
33
use PHP_Typography\Strings;
34
use PHP_Typography\U;
35
36
/**
37
 * Prevents widows (if enabled).
38
 *
39
 * @author Peter Putzer <[email protected]>
40
 *
41
 * @since 5.0.0
42
 */
43
class Dewidow_Fix extends Abstract_Node_Fix {
44
	const SPACE_BETWEEN = '[\s]+'; // \s includes all special spaces (but not ZWSP) with the u flag.
45
	const WIDOW         = '[\w\p{M}\-' . U::ZERO_WIDTH_SPACE . U::SOFT_HYPHEN . ']+?'; // \w includes all alphanumeric Unicode characters but not composed characters.
46
47
	// Mandatory UTF-8 modifer.
48
	const REGEX_START = '/
49
		(?:
50
			\A
51
			|
52
			(?:
53
				(?<space_before>            # subpattern 1: space before (note: ZWSP is not a space)
54
					[\s' . U::ZERO_WIDTH_SPACE . U::SOFT_HYPHEN . ']+
55
				)
56
				(?<neighbor>                # subpattern 2: neighbors widow (short as possible)
57
					[^\s' . U::ZERO_WIDTH_SPACE . U::SOFT_HYPHEN . ']+?
58
				)
59
			)
60
		)
61
		(?<space_between>                   # subpattern 3: space between
62
			' . self::SPACE_BETWEEN . '
63
		)
64
		(?<widow>                           # subpattern 4: widow
65
			' . self::WIDOW . '
66
			(?:
67
				' . self::SPACE_BETWEEN . self::WIDOW . '
68
			){0,'; // The maximum number of repetitions is missing.
69
70
	const REGEX_END =
71
		'})
72
		(?<trailing>                       # subpattern 5: any trailing punctuation or spaces
73
			[^\w\p{M}]*
74
		)
75
		\Z
76
	/Sxu';
77
78
	const MASKED_NARROW_SPACE = '__NO_BREAK_NARROW_SPACE__';
79
80
	/**
81
	 * Apply the fix to a given textnode.
82
	 *
83
	 * @param \DOMText $textnode Required.
84
	 * @param Settings $settings Required.
85
	 * @param bool     $is_title Optional. Default false.
86
	 */
87 56
	public function apply( \DOMText $textnode, Settings $settings, $is_title = false ) {
88
		// Intervening inline tags may interfere with widow identification, but that is a sacrifice of using the parser.
89
		// Intervening tags will only interfere if they separate the widow from previous or preceding whitespace.
90 56
		if ( empty( $settings['dewidow'] ) || empty( $settings['dewidowMaxPull'] ) || empty( $settings['dewidowMaxLength'] ) ) {
91 28
			return;
92
		}
93
94 28
		if ( '' === DOM::get_next_chr( $textnode ) ) {
95
			// We have the last type "text" child of a block level element.
96 28
			$textnode->data = $this->dewidow( $textnode->data, Strings::functions( $textnode->data ), $settings['dewidowMaxPull'], $settings['dewidowMaxLength'], $settings['dewidowWordNumber'], $settings->no_break_narrow_space() );
97
		}
98 28
	}
99
100
	/**
101
	 * Dewidow a given text fragment.
102
	 *
103
	 * @param  string $text         The text fragment to dewidow.
104
	 * @param  array  $func         An array of string functions.
105
	 * @param  int    $max_pull     Maximum number of characters pulled from previous line.
106
	 * @param  int    $max_length   Maximum widow length.
107
	 * @param  int    $word_number  Maximum number of words allowed in widow.
108
	 * @param  string $narrow_space The narrow no-break space character.
109
	 *
110
	 * @return string
111
	 */
112 28
	protected function dewidow( $text, array $func, $max_pull, $max_length, $word_number, $narrow_space ) {
113 28
		if ( $word_number < 1 ) {
114 5
			return $text; // We are done.
115
		}
116
117
		// Do what we have to do.
118 28
		return preg_replace_callback( self::REGEX_START . ( $word_number - 1 ) . self::REGEX_END, function( array $widow ) use ( $func, $max_pull, $max_length, $word_number, $narrow_space ) {
119
120
			// If we are here, we know that widows are being protected in some fashion
121
			// with that, we will assert that widows should never be hyphenated or wrapped
122
			// as such, we will strip soft hyphens and zero-width-spaces.
123 27
			$widow['widow']    = self::strip_breaking_characters( $widow['widow'] );
124 27
			$widow['trailing'] = self::strip_breaking_characters( self::make_space_nonbreaking( $widow['trailing'], $narrow_space, $func['u'] ) );
125
126
			if (
127
				// Eject if widows neighbor is proceeded by a no break space (the pulled text would be too long).
128 27
				'' === $widow['space_before'] || false !== \strpos( $widow['space_before'], U::NO_BREAK_SPACE ) ||
129
130
				// Eject if widows neighbor length exceeds the max allowed or widow length exceeds max allowed.
131 26
				$func['strlen']( $widow['neighbor'] ) > $max_pull || $func['strlen']( $widow['widow'] ) > $max_length ||
132
133
				// Never replace thin and hair spaces with &nbsp;.
134 27
				self::is_narrow_space( $widow['space_between'] )
135
			) {
136 7
				return $widow['space_before'] . $widow['neighbor'] . $this->dewidow( $widow['space_between'] . $widow['widow'] . $widow['trailing'], $func, $max_pull, $max_length, $word_number - 1, $narrow_space );
137
			}
138
139
			// Let's protect some widows!
140 22
			return $widow['space_before'] . $widow['neighbor'] . U::NO_BREAK_SPACE . self::make_space_nonbreaking( $widow['widow'], $narrow_space, $func['u'] ) . $widow['trailing'];
141 28
		}, $text );
142
	}
143
144
	/**
145
	 * Strip zero-width space and soft hyphens from the given string.
146
	 *
147
	 * @param  string $string Required.
148
	 *
149
	 * @return string
150
	 */
151 1
	protected static function strip_breaking_characters( $string ) {
152 1
		return str_replace( [ U::ZERO_WIDTH_SPACE, U::SOFT_HYPHEN ], '', $string );
153
	}
154
155
	/**
156
	 * Is the given string one of the narrow space characters?
157
	 *
158
	 * @since 6.0.0
159
	 *
160
	 * @param  string $string The whitespace to test.
161
	 *
162
	 * @return bool
163
	 */
164 1
	protected static function is_narrow_space( $string ) {
165 1
		return U::THIN_SPACE === $string || U::HAIR_SPACE === $string || U::NO_BREAK_NARROW_SPACE === $string;
166
	}
167
168
	/**
169
	 * Strip zero-width space and soft hyphens from the given string.
170
	 *
171
	 * @param  string $string       Required.
172
	 * @param  string $narrow_space The narrow no-break space character.
173
	 * @param  string $u            Either 'u' or the empty string.
174
	 *
175
	 * @return string
176
	 */
177 1
	protected static function make_space_nonbreaking( $string, $narrow_space, $u ) {
178 1
		return preg_replace(
179
			[
180 1
				'/\s*' . U::THIN_SPACE . '\s*/u',
181
				'/\s*' . U::NO_BREAK_NARROW_SPACE . '\s*/u',
182 1
				"/\\s+/$u",
183 1
				'/' . self::MASKED_NARROW_SPACE . "/$u",
184
			], [
185 1
				self::MASKED_NARROW_SPACE,
186 1
				self::MASKED_NARROW_SPACE,
187
				U::NO_BREAK_SPACE,
188 1
				$narrow_space,
189 1
			], $string
190
		);
191
	}
192
}
193