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

Line highlight plugin highlights the line on last rendered code block only on a page with multiple code blocks. #3762

Open
webzille opened this issue Jan 12, 2024 · 5 comments

Comments

@webzille
Copy link

webzille commented Jan 12, 2024

Information:

  • Prism version: PrismJS 1.29.0
  • Plugins: line-highlight and line-numbers
  • Environment: Browser

Description
I'm using the latest JavaScript and CSS for Prism I got off the website after selecting the theme I wanted (prism-tomorrow) and selected all the languages I wanted to include with prism. I've encountered some problems along the way specifically with the line-highlight plugin and I don't think it's the error with how I'm implementing it. (It's a custom error page where it shows portions of my code for debug).

On one page I have multiple code blocks that gets the same configuration for their highlighting but for some reason only the last code block gets any of it's line highlighted.

Why don't the other code blocks get their lines highlighted?

Example
All the other code blocks (that are not last) don't get any love from the line-highlighting plug-in
No lines highlighted in any other code block

The last code block is the only block that gets highlighted
The last code block

This is the code that generates the code block that does the highlighting

protected function getCodeSnippet($file, $line, $linesBefore = 10, $linesAfter = 10)
{
    $code = '<pre data-line="' . $line . '" class="line-numbers brad-3" data-start="' . ($line - $linesBefore) . '"><code class="language-php">';
    if (is_readable($file)) {
        $lines = file($file);
        $startLine = max(1, $line - $linesBefore);
        $endLine = min(count($lines), $line + $linesAfter);

        for ($i = $startLine; $i <= $endLine; $i++) {
            $code .= htmlspecialchars($lines[$i - 1]);
        }
    }
    $code .= '</code></pre>';

    return $code;
}
@elken
Copy link

elken commented Jan 12, 2024

I might not be following the issue but I have multiple blocks here and they're all highlighted fine, even linkable works.
image

@webzille
Copy link
Author

Odd, maybe I'm implementing it wrong somehow.

@elken
Copy link

elken commented Jan 13, 2024

All I can suggest is make sure they've got different IDs

@webzille
Copy link
Author

webzille commented Jan 13, 2024

    protected function includeCodeInResponse($exception)
    {
        $codeSnippets = [];
    
        foreach ($exception->getTrace() as $traceItem) {
            if (isset($traceItem['file'])) {
                $codeSnippets[] = [
                    'class'     => $traceItem['class'] ?? null,
                    'function'  => $traceItem['function'] ?? null,
                    'file'      => $traceItem['file'],
                    'line'      => $traceItem['line'],
                    'snippet'   => $this->getCodeSnippet($traceItem['file'], $traceItem['line']),
                ];
            }
        }
    
        return $codeSnippets;
    }

    protected function getCodeSnippet($file, $line, $linesBefore = 10, $linesAfter = 10)
    {
        $id = preg_replace('/[^a-zA-Z0-9]/', '', crypt(basename($file) . $line, md5(rand(1, 99999999))));
        $code = "<pre id=\"{$id}\" data-line=\"{$line}\" class=\"line-numbers brad-3\" data-start=\"".($line - $linesBefore)."\"><code id=\"{$id}2\" class=\"language-php\">";
        if (is_readable($file)) {
            $lines = file($file);
            $startLine = max(1, $line - $linesBefore);
            $endLine = min(count($lines), $line + $linesAfter);

            for ($i = $startLine; $i <= $endLine; $i++) {
                $code .= htmlspecialchars($lines[$i - 1]);
            }
        }
        $code .= "\n</code>\n</pre>\n";

        return $code;
    }

I tried to ensure that the IDs are fairly guaranteed to be unique, but regardless of how many times I try, only the last code block has the line highlighted.

@webzille
Copy link
Author

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link rel="stylesheet" href="/assets/prism/themes/prism-tomorrow.css" data-noprefix />
    <link rel="stylesheet" href="/assets/prism/plugins/line-highlight/prism-line-highlight.css" data-noprefix />
    <link rel="stylesheet" href="/assets/prism/plugins/line-numbers/prism-line-numbers.css" data-noprefix />
    <title>Errors Encountered</title>
</head>
<body>
<main class="row flex-center g-1 stretch-y">
    <section class="col-10 body brad-3 double-border drop-shadow">
        <h1>Error Occurred</h1>
        <p>Errors encountered while trying to fulfill the request.</p>

        <div style="margin-inline: 10%;">
            <h2>Error Details:</h2>
            <pre>
                <strong>Message:</strong>call_user_func_array(): Argument #1 ($callback) must be a valid callback, class App\Controllers\Auth\AuthController does not have a method &quot;register&quot;<br>
                <strong>Code:</strong>0<br>
                <strong>File:</strong>C:\laragon\www\mysite\Core\Router.php<br>
                <strong>Line:</strong>149<br>
            </pre>
            <pre id="bfU8rQEXBpF4c" data-line="149" class="brad-3 line-numbers" data-start="139"><code id="bfU8rQEXBpF4c2" class="language-php">                return new Response($pipeline-&gt;handle($request, function ($request) use ($class, $method, $matches) {
                    $params = array_filter($matches, function ($key) {
                        return !is_int($key);
                    }, ARRAY_FILTER_USE_KEY);

                    if (!empty($request-&gt;request)) {
                        $params[&#039;request&#039;] = $request;
                    }

                    $classInstance = new $class();
                    return call_user_func_array([$classInstance, $method], $params);
                }));
            }
        }

        return (new Response(&#039;&#039;))-&gt;statusCode(404)-&gt;abort(404);
    }
}

</code>
</pre>
        </div>
        <!-- Trace section -->
        <h2>Trace:</h2>
                    <div class="trace-item border brad-3">
                <p>
                    <strong>Step 1:</strong>
                                        <span class="trace-function">call_user_func_array</span>
                </p>
                                    <!-- Include the code snippet for each trace item -->
                    <p class="trace-file">File: C:\laragon\www\mysite\Core\Router.php</p>
                    <p>Line: 149</p>
                    <pre id="a6QZTGpGDEcv" data-line="149" class="brad-3 line-numbers" data-start="139"><code id="a6QZTGpGDEcv2" class="language-php">                return new Response($pipeline-&gt;handle($request, function ($request) use ($class, $method, $matches) {
                    $params = array_filter($matches, function ($key) {
                        return !is_int($key);
                    }, ARRAY_FILTER_USE_KEY);

                    if (!empty($request-&gt;request)) {
                        $params[&#039;request&#039;] = $request;
                    }

                    $classInstance = new $class();
                    return call_user_func_array([$classInstance, $method], $params);
                }));
            }
        }

        return (new Response(&#039;&#039;))-&gt;statusCode(404)-&gt;abort(404);
    }
}

</code>
</pre>
                            </div>
                    <div class="trace-item border brad-3">
                <p>
                    <strong>Step 2:</strong>
                    Core\Router->                    <span class="trace-function">Core\{closure}</span>
                </p>
                                    <!-- Include the code snippet for each trace item -->
                    <p class="trace-file">File: C:\laragon\www\mysite\Core\MiddlewarePipeline.php</p>
                    <p>Line: 30</p>
                    <pre id="f0e9UPtQ4ZArI" data-line="30" class="brad-3 line-numbers" data-start="20"><code id="f0e9UPtQ4ZArI2" class="language-php">            array_reverse($this-&gt;middlewares),
            function ($next, $middleware) {
                return function ($request) use ($middleware, $next) {
                    return $middleware-&gt;handle($request, $next);
                };
            },
            $controllerClosure  // Pass the controller closure as the initial &quot;next&quot;
        );

        // Execute the pipeline starting with the initial request
        return $pipeline($request);
    }
}
</code>
</pre>
                            </div>
                    <div class="trace-item border brad-3">
                <p>
                    <strong>Step 3:</strong>
                    Core\MiddlewarePipeline->                    <span class="trace-function">handle</span>
                </p>
                                    <!-- Include the code snippet for each trace item -->
                    <p class="trace-file">File: C:\laragon\www\mysite\Core\Router.php</p>
                    <p>Line: 139</p>
                    <pre id="4bI6qqXduwOyg" data-line="139" class="brad-3 line-numbers" data-start="129"><code id="4bI6qqXduwOyg2" class="language-php">                $class = &quot;App\Controllers\\{$handler[0]}&quot;;
                $method = $handler[1];

                $pipeline = new MiddlewarePipeline();
                foreach ($route[&#039;middleware&#039;] as $middlewareClass) {
                    $pipeline-&gt;addMiddleware(new $middlewareClass());
                }

                $request = new Request();

                return new Response($pipeline-&gt;handle($request, function ($request) use ($class, $method, $matches) {
                    $params = array_filter($matches, function ($key) {
                        return !is_int($key);
                    }, ARRAY_FILTER_USE_KEY);

                    if (!empty($request-&gt;request)) {
                        $params[&#039;request&#039;] = $request;
                    }

                    $classInstance = new $class();
                    return call_user_func_array([$classInstance, $method], $params);

</code>
</pre>
                            </div>
                    <div class="trace-item border brad-3">
                <p>
                    <strong>Step 4:</strong>
                    Core\Router->                    <span class="trace-function">dispatch</span>
                </p>
                                    <!-- Include the code snippet for each trace item -->
                    <p class="trace-file">File: C:\laragon\www\mysite\public\index.php</p>
                    <p>Line: 15</p>
                    <pre id="77A1QppD1v88c" data-line="15" class="brad-3 line-numbers" data-start="5"><code id="77A1QppD1v88c2" class="language-php">
try {
    require_once __DIR__ . &#039;/../vendor/autoload.php&#039;;
    require_once __DIR__ . &#039;/../core/helpers/helper.php&#039;;
    require_once baseDir(&#039;routes/web.php&#039;);

    $uri = parse_url($_SERVER[&#039;REQUEST_URI&#039;], PHP_URL_PATH);

    $method = $_POST[&#039;_method&#039;] ?? $_SERVER[&#039;REQUEST_METHOD&#039;];

    echo Router::dispatch($method, $uri)-&gt;prepare()-&gt;getContent();
} catch (\Throwable $exception) {
    ob_end_clean();
    $errorHandler = new ErrorHandler(true); // Set true for debug mode
    $response = $errorHandler-&gt;handleException($exception);
    echo $response-&gt;statusCode(500)-&gt;prepare()-&gt;getContent();
}

?&gt;
</code>
</pre>
                            </div>
            </section>
</main>
<script src="/assets/prism/prism.js"></script>
    <script src="/assets/prism/plugins/line-highlight/prism-line-highlight.js"></script>
    <script src="/assets/prism/plugins/line-numbers/prism-line-numbers.js"></script>
    <script src="/assets/prism/plugins/autoloader/prism-autoloader.js" data-autoloader-path="/assets/prism/components/"></script>
</body>
</html>

This is the generated HTML page... according to the docs, everything seems to be correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants