Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

39 add option to only show specific lines #44

Merged
merged 13 commits into from
Oct 26, 2023
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Example:
Parameters:
* `lang`: (Optional) One of the [supported languages]. Only necessary if the language is not detected from the file extension.
* `line`: (Optional) Show line numbers.
* `specificLines`: (Optional) Show only specific lines. Can be a single line number or a range separated with a hyphen (-). Multiple line numbers or ranges can be separated by commas.

Examples:

Expand All @@ -74,6 +75,11 @@ Render PHP file with line numbers:
{{#embed:https://example.com/fluffy/kittens.php|lang=php|line}}
```

Render PHP file with specific lines:
```
{{#embed:https://example.com/fluffy/kittens.php|lang=php|specificLines=1-3,8}}
```

### Refreshing external content

To refresh all the pages containing one of the parser functions added by this extension, run
Expand Down
3 changes: 2 additions & 1 deletion extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@
"es6": true,
"scripts": [
"prism/prism.js",
"bitbucket-edit.js"
"bitbucket-edit.js",
"code-specific-lines.js"
]
},
"ext.external-content.code-renderer.styles": {
Expand Down
14 changes: 14 additions & 0 deletions resources/code-renderer.css
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,17 @@ pre[class*="language-"] {
.line-numbers-rows > span::before {
color: #72777d;
}

.hide-line {
display: none;
}

.line-numbers-rows .hide-line,
.line-numbers-rows .hide-line:before {
display: block;
height: 0px;
font-size: 1px;
background: #f0f0f0 !important;
color: #f0f0f0 !important;
text-shadow: none;
}
78 changes: 78 additions & 0 deletions resources/code-specific-lines.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
Prism.hooks.add( 'complete', function( env ) {
var showLineRanges = env.element.parentElement.getAttribute( 'data-show-lines' );

if (showLineRanges) {
var showLines = showLines( showLineRanges );

var tokenList = tokenList( env.element.innerHTML, showLines );

var lineNumbersActive = Prism.util.isActive( env.element, 'line-numbers' );

if ( lineNumbersActive ) {
var lineNumberList = lineNumberList( env.element.querySelectorAll( '.line-numbers-rows span' ), showLines );

env.element.innerHTML = tokenList.join( '' ) + '<span aria-hidden="true" class="line-numbers-rows">' + lineNumberList.join( '' ) + '</span>';
}
else {
env.element.innerHTML = tokenList.join( '' );
}
}

function showLines( showLineRanges ) {
var showLines = [];

showLineRanges.replace( /\s+/g, '' ).split( ',' ).filter( Boolean ).forEach( function( currentRange ) {
if (currentRange.includes( '-' )) {
var range = currentRange.split( '-' );

if ( range[0] > range[1] ) {
[range[0], range[1]] = [range[1], range[0]];
}

for ( var counter = range[0]; counter <= range[1]; counter++ ) {
showLines.push( Number( counter ) );
}
}
else {
showLines.push( Number( currentRange ) );
}
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could go into a nice pure-function with full unit-test coverage

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modified


return showLines;
}

function tokenList( HTML, showLines ) {
var tokenList = HTML.split( /\n(?!$)/g );
var tokenCount = tokenList.length;
const regex = /(<span aria-hidden="true" class="line-numbers-rows">(.*<\/span>))/gm;

tokenList.forEach( function( value, index ) {
if ( index === tokenCount - 1 ) {
value = value.replace (regex, '' );
}

if ( showLines.includes ( index + 1 ) ) {
tokenList[index] += '\n';
}
else {
tokenList[index] = '<span class="hide-line">' + value + '</span>';
}
});

return tokenList;
}

function lineNumberList( lineNumberRows, showLines ) {
var lineNumberList = [];

lineNumberRows.forEach( function( value, index ) {
if ( !showLines.includes( index + 1 ) ) {
lineNumberRows[index].classList.add( 'hide-line' );
}

lineNumberList[index] = lineNumberRows[index].outerHTML;
});

return lineNumberList;
}
});
22 changes: 22 additions & 0 deletions src/Domain/ContentRenderer/CodeRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ class CodeRenderer implements ContentRenderer {
public function __construct(
private string $language,
private bool $showLineNumbers,
private string $showSpecificLines,
private bool $showEditButton
) {
}
Expand Down Expand Up @@ -56,6 +57,10 @@ private function getWrapperAttributes( string $contentUrl ): array {

$attributes['class'] = $this->getWrapperClasses();

if ( !empty( $this->showSpecificLines ) ) {
$attributes['data-show-lines'] = $this->lineNormalizer( $this->showSpecificLines );
}

$attributes['data-toolbar-order'] = 'copy-to-clipboard';

if ( $this->showEditButton ) {
Expand All @@ -66,4 +71,21 @@ private function getWrapperAttributes( string $contentUrl ): array {
return $attributes;
}

/**
* @return string
*/
private function lineNormalizer( string $lines ) {
malberts marked this conversation as resolved.
Show resolved Hide resolved
malberts marked this conversation as resolved.
Show resolved Hide resolved
$exploded = explode( ',', preg_replace( '/\s+/', '', $lines ) );

$ranges = array_filter( $exploded, static function( $value ): bool {
if ( preg_match( '/^\d+$/', $value ) || preg_match( '/^(\d+)-(\d+)$/', $value ) ) {
return true;
}
else {
return false;
}
malberts marked this conversation as resolved.
Show resolved Hide resolved
} );

return implode( ',', $ranges );
}
}
1 change: 1 addition & 0 deletions src/Domain/ContentRenderer/RendererConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public function __construct(
public string $fileExtension,
public string $language,
public bool $showLineNumbers,
public string $showSpecificLines,
public bool $showEditButton
) {
}
Expand Down
2 changes: 2 additions & 0 deletions src/Domain/WikiContentRendererFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ public function createContentRenderer( RendererConfig $config ): ContentRenderer
return new CodeRenderer(
language: $config->language,
showLineNumbers: $config->showLineNumbers,
showSpecificLines: $config->showSpecificLines,
showEditButton: $config->showEditButton
);
}
Expand All @@ -27,6 +28,7 @@ public function createContentRenderer( RendererConfig $config ): ContentRenderer
return new CodeRenderer(
language: $config->fileExtension, // TODO: Use an extension-to-language map, although common extensions already work.
showLineNumbers: $config->showLineNumbers,
showSpecificLines: $config->showSpecificLines,
showEditButton: $config->showEditButton

);
Expand Down
1 change: 1 addition & 0 deletions src/UseCases/Embed/EmbedRequest.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ public function __construct(
public string $fileUrl,
public ?string $language,
public ?bool $showLineNumbers,
public ?string $showSpecificLines,
public bool $showEditButton
) {
}
Expand Down
2 changes: 2 additions & 0 deletions src/UseCases/Embed/EmbedRequestBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,13 @@ public static function argumentsToRequest( array $arguments, bool $showEditButto

$language = $normalizedArguments['lang'] ?? null;
$line = $normalizedArguments['line'] ?? null;
$specificLines = $normalizedArguments['specificLines'] ?? null;

return new EmbedRequest(
fileUrl: $arguments[0],
language: is_string( $language ) ? $language : null,
showLineNumbers: is_bool( $line ) ? $line : null,
showSpecificLines: is_string( $specificLines ) ? $specificLines : null,
showEditButton: $showEditButton
);
}
Expand Down
1 change: 1 addition & 0 deletions src/UseCases/Embed/EmbedUseCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ private function createRendererConfig( EmbedRequest $request ): RendererConfig {
),
language: $request->language ?? '',
showLineNumbers: $request->showLineNumbers ?? false,
showSpecificLines: $request->showSpecificLines ?? '',
showEditButton: $request->showEditButton
);
}
Expand Down
30 changes: 24 additions & 6 deletions tests/Integration/Domain/CodeRendererTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,60 @@ class CodeRendererTest extends TestCase {
public function testRendersSimplePhpWithoutLineNumbers(): void {
$this->assertSame(
'<pre class="external-content" data-toolbar-order="copy-to-clipboard"><code class="language-php">print( "Hello world" );</code></pre>',
( new CodeRenderer( language: 'php', showLineNumbers: false, showEditButton: false ) )->render( 'print( "Hello world" );', '' )
( new CodeRenderer( language: 'php', showLineNumbers: false, showSpecificLines: '', showEditButton: false ) )->render( 'print( "Hello world" );', '' )
);
}

public function testRendersSimpleTypescriptWithLineNumbers(): void {
$this->assertSame(
'<pre class="external-content line-numbers" data-toolbar-order="copy-to-clipboard"><code class="language-typescript">console.log( "Hello world" as string );</code></pre>',
( new CodeRenderer( language: 'typescript', showLineNumbers: true, showEditButton: false ) )->render( 'console.log( "Hello world" as string );', '' )
( new CodeRenderer( language: 'typescript', showLineNumbers: true, showSpecificLines: '', showEditButton: false ) )->render( 'console.log( "Hello world" as string );', '' )
);
}

public function testRendersEscapedHtml(): void {
$this->assertSame(
'<pre class="external-content" data-toolbar-order="copy-to-clipboard"><code class="language-html">&lt;script>alert( "HAX" );&lt;/script></code></pre>',
( new CodeRenderer( language: 'html', showLineNumbers: false, showEditButton: false ) )->render( '<script>alert( "HAX" );</script>', '' )
( new CodeRenderer( language: 'html', showLineNumbers: false, showSpecificLines: '', showEditButton: false ) )->render( '<script>alert( "HAX" );</script>', '' )
);
}

public function testRendersEscapedHtmlWithWrongLanguage(): void {
$this->assertSame(
'<pre class="external-content" data-toolbar-order="copy-to-clipboard"><code class="language-javascript">&lt;script>alert( "HAX" );&lt;/script></code></pre>',
( new CodeRenderer( language: 'javascript', showLineNumbers: false, showEditButton: false ) )->render( '<script>alert( "HAX" );</script>', '' )
( new CodeRenderer( language: 'javascript', showLineNumbers: false, showSpecificLines: '', showEditButton: false ) )->render( '<script>alert( "HAX" );</script>', '' )
);
}

public function testRendersEscapedPartialHtml(): void {
$this->assertSame(
'<pre class="external-content" data-toolbar-order="copy-to-clipboard"><code class="language-html">&lt;/code>&lt;/pre>FOO</code></pre>',
( new CodeRenderer( language: 'html', showLineNumbers: false, showEditButton: false ) )->render( '</code></pre>FOO', '' )
( new CodeRenderer( language: 'html', showLineNumbers: false, showSpecificLines: '', showEditButton: false ) )->render( '</code></pre>FOO', '' )
);
}

public function testRendersShowEditButton(): void {
$this->assertSame(
'<pre class="external-content" data-toolbar-order="bitbucket-edit,copy-to-clipboard" data-src="http://bitbucket:7990/projects/TEST/repos/test/browse/test.php"><code class="language-php">&lt;/code>&lt;/pre>FOO</code></pre>',
( new CodeRenderer( language: 'php', showLineNumbers: false, showEditButton: true ) )->render( '</code></pre>FOO', 'http://bitbucket:7990/projects/TEST/repos/test/browse/test.php' )
( new CodeRenderer( language: 'php', showLineNumbers: false, showSpecificLines: '', showEditButton: true ) )->render( '</code></pre>FOO', 'http://bitbucket:7990/projects/TEST/repos/test/browse/test.php' )
);
}

public function testRendersSpecificLineNumbers(): void {
$this->assertSame(
'<pre class="external-content line-numbers" data-show-lines="2-3,5" data-toolbar-order="copy-to-clipboard"><code class="language-php">&lt;?php
$a = "Hello";
$b = "World";

print( $a . " " . $b );
?></code></pre>',
( new CodeRenderer( language: 'php', showLineNumbers: true, showSpecificLines: '2-3,5', showEditButton: false ) )->render(
'<?php
$a = "Hello";
$b = "World";

print( $a . " " . $b );
?>', '' )
);
}

Expand Down
13 changes: 9 additions & 4 deletions tests/Unit/Domain/WikiContentRendererFactoryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public function testMarkdownFileAndConfigWithoutLanguageCreatesMarkdownRenderer(
fileExtension: 'md',
language: '',
showLineNumbers: false,
showSpecificLines: '',
showEditButton: false
)
)
Expand All @@ -29,12 +30,13 @@ public function testMarkdownFileAndConfigWithoutLanguageCreatesMarkdownRenderer(

public function testConfigWithoutLanguageCreatesCodeRenderer(): void {
$this->assertEquals(
new CodeRenderer( language: 'php', showLineNumbers: false, showEditButton: false ),
new CodeRenderer( language: 'php', showLineNumbers: false, showSpecificLines: '', showEditButton: false ),
( new WikiContentRendererFactory() )->createContentRenderer(
new RendererConfig(
fileExtension: 'php',
language: '',
showLineNumbers: false,
showSpecificLines: '',
showEditButton: false
)
)
Expand All @@ -43,12 +45,13 @@ public function testConfigWithoutLanguageCreatesCodeRenderer(): void {

public function testConfigWithLanguageCreatesCodeRenderer(): void {
$this->assertEquals(
new CodeRenderer( language: 'php', showLineNumbers: false, showEditButton: false ),
new CodeRenderer( language: 'php', showLineNumbers: false, showSpecificLines: '', showEditButton: false ),
( new WikiContentRendererFactory() )->createContentRenderer(
new RendererConfig(
fileExtension: 'php',
language: 'php',
showLineNumbers: false,
showSpecificLines: '',
showEditButton: false
)
)
Expand All @@ -57,12 +60,13 @@ public function testConfigWithLanguageCreatesCodeRenderer(): void {

public function testConfigWithLanguageAndLineNumbersCreatesCodeRenderer(): void {
$this->assertEquals(
new CodeRenderer( language: 'php', showLineNumbers: true, showEditButton: false ),
new CodeRenderer( language: 'php', showLineNumbers: true, showSpecificLines: '', showEditButton: false ),
( new WikiContentRendererFactory() )->createContentRenderer(
new RendererConfig(
fileExtension: 'php',
language: 'php',
showLineNumbers: true,
showSpecificLines: '',
showEditButton: false
)
)
Expand All @@ -71,12 +75,13 @@ public function testConfigWithLanguageAndLineNumbersCreatesCodeRenderer(): void

public function testConfigWithMarkdownLanguageCreatesCodeRenderer(): void {
$this->assertEquals(
new CodeRenderer( language: 'md', showLineNumbers: false, showEditButton: false ),
new CodeRenderer( language: 'md', showLineNumbers: false, showSpecificLines: '', showEditButton: false ),
( new WikiContentRendererFactory() )->createContentRenderer(
new RendererConfig(
fileExtension: 'md',
language: 'md',
showLineNumbers: false,
showSpecificLines: '',
showEditButton: false
)
)
Expand Down
1 change: 1 addition & 0 deletions tests/Unit/UseCases/Embed/EmbedUseCaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ private function createRequest( string $fileUrl ): EmbedRequest {
fileUrl: $fileUrl,
language: '',
showLineNumbers: false,
showSpecificLines: '',
showEditButton: false
);
}
Expand Down
Loading