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

File highlight+data range #1813

Merged
merged 7 commits into from Oct 4, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions plugins/file-highlight/index.html
Expand Up @@ -8,6 +8,7 @@
<base href="../.." />
<link rel="stylesheet" href="assets/style.css" />
<link rel="stylesheet" href="themes/prism.css" data-noprefix />
<link rel="stylesheet" href="plugins/line-numbers/prism-line-numbers.css" data-noprefix />
<script src="assets/vendor/prefixfree.min.js"></script>

<script>var _gaq = [['_setAccount', 'UA-33746269-1'], ['_trackPageview']];</script>
Expand All @@ -27,6 +28,14 @@ <h1>How to use</h1>
<p>You don’t need to specify the language, it’s automatically determined by the file extension.
If, however, the language cannot be determined from the file extension or the file extension is incorrect, you may specify a language as well (with the usual class name way).</p>

<p>Use the <code>data-range</code> attribute to display only a selected range of lines from the file, like so:</p>

<pre><code>&lt;pre data-src="myfile.js" data-range="1,5">&lt;/pre></code></pre>

<p>Lines start at 1, so <code>"1,5"</code> will display line 1 up to and including line 5. It's also possible to specify just a single line (e.g. <code>"5"</code> for just line 5) and open ranges (e.g. <code>"3,"</code> for all lines starting at line 3). Negative integers can be used to specify the n-th last line, e.g. -2 for the second last line.</p>

<p>When <code>data-range</code> is used in conjunction with the <a href="plugins/line-numbers">Line Numbers plugin</a>, this plugin will add the proper <code>data-start</code> according to the specified range. This behavior can be overridden by setting the <code>data-start</code> attribute manually.</p>

<p>Please note that the files are fetched with XMLHttpRequest. This means that if the file is on a different origin, fetching it will fail, unless CORS is enabled on that website.</p>
</section>

Expand All @@ -42,13 +51,17 @@ <h1>Examples</h1>
<p>File that doesn’t exist:</p>
<pre data-src="foobar.js"></pre>

<p>With line numbers, and <code>data-range="12,111"</code>:</p>
<pre data-src="plugins/file-highlight/prism-file-highlight.js" data-range="12,111" class="line-numbers"></pre>

<p>For more examples, browse around the Prism website. Most large code samples are actually files fetched with this plugin.</p>
</section>

<footer data-src="assets/templates/footer.html" data-type="text/html"></footer>

<script src="prism.js"></script>
<!-- The File Highlight plugin is already included into Prism.js build -->
<script src="plugins/line-numbers/prism-line-numbers.js"></script>
<script src="assets/vendor/utopia.js"></script>
<script src="components.js"></script>
<script src="assets/code.js"></script>
Expand Down
109 changes: 87 additions & 22 deletions plugins/file-highlight/prism-file-highlight.js
Expand Up @@ -50,6 +50,57 @@
element.className = className.replace(/\s+/g, ' ').trim();
}

/**
* Loads the given file.
*
* @param {string} src The URL or path of the source file to load.
* @param {(result: string) => void} success
* @param {(reason: string) => void} error
*/
function loadFile(src, success, error) {
var xhr = new XMLHttpRequest();
xhr.open('GET', src, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status < 400 && xhr.responseText) {
success(xhr.responseText);
} else {
if (xhr.status >= 400) {
error(FAILURE_MESSAGE(xhr.status, xhr.statusText));
} else {
error(FAILURE_EMPTY_MESSAGE);
}
}
}
};
xhr.send(null);
}

/**
* Parses the given range.
*
* This returns a range with inclusive ends.
*
* @param {string | null | undefined} range
* @returns {[number, number | undefined] | undefined}
*/
function parseRange(range) {
var m = /^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(range || '');
if (m) {
var start = Number(m[1]);
var comma = m[2];
var end = m[3];

if (!comma) {
return [start, start];
}
if (!end) {
return [start, undefined];
}
return [start, Number(end)];
}
return undefined;
}

Prism.hooks.add('before-highlightall', function (env) {
env.selector += ', ' + SELECTOR;
Expand Down Expand Up @@ -87,31 +138,45 @@
}

// load file
var xhr = new XMLHttpRequest();
xhr.open('GET', src, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status < 400 && xhr.responseText) {
// mark as loaded
pre.setAttribute(STATUS_ATTR, STATUS_LOADED);

// highlight code
code.textContent = xhr.responseText;
Prism.highlightElement(code);

} else {
// mark as failed
pre.setAttribute(STATUS_ATTR, STATUS_FAILED);

if (xhr.status >= 400) {
code.textContent = FAILURE_MESSAGE(xhr.status, xhr.statusText);
} else {
code.textContent = FAILURE_EMPTY_MESSAGE;
loadFile(
src,
function (text) {
// mark as loaded
pre.setAttribute(STATUS_ATTR, STATUS_LOADED);

// handle data-range
var range = parseRange(pre.getAttribute('data-range'));
if (range) {
var lines = text.split(/\r\n?|\n/g);

// the range is one-based and inclusive on both ends
var start = range[0];
var end = range[1] == null ? lines.length : range[1];

if (start < 0) { start += lines.length; }
start = Math.max(0, Math.min(start - 1, lines.length));
if (end < 0) { end += lines.length; }
end = Math.max(0, Math.min(end, lines.length));

text = lines.slice(start, end).join('\n');

// add data-start for line numbers
if (!pre.hasAttribute('data-start')) {
pre.setAttribute('data-start', String(start + 1));
}
}

// highlight code
code.textContent = text;
Prism.highlightElement(code);
},
function (error) {
// mark as failed
pre.setAttribute(STATUS_ATTR, STATUS_FAILED);

code.textContent = error;
}
};
xhr.send(null);
);
}
});

Expand Down
2 changes: 1 addition & 1 deletion plugins/file-highlight/prism-file-highlight.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

109 changes: 87 additions & 22 deletions prism.js
Expand Up @@ -1720,6 +1720,57 @@ Prism.languages.js = Prism.languages.javascript;
element.className = className.replace(/\s+/g, ' ').trim();
}

/**
* Loads the given file.
*
* @param {string} src The URL or path of the source file to load.
* @param {(result: string) => void} success
* @param {(reason: string) => void} error
*/
function loadFile(src, success, error) {
var xhr = new XMLHttpRequest();
xhr.open('GET', src, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status < 400 && xhr.responseText) {
success(xhr.responseText);
} else {
if (xhr.status >= 400) {
error(FAILURE_MESSAGE(xhr.status, xhr.statusText));
} else {
error(FAILURE_EMPTY_MESSAGE);
}
}
}
};
xhr.send(null);
}

/**
* Parses the given range.
*
* This returns a range with inclusive ends.
*
* @param {string | null | undefined} range
* @returns {[number, number | undefined] | undefined}
*/
function parseRange(range) {
var m = /^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(range || '');
if (m) {
var start = Number(m[1]);
var comma = m[2];
var end = m[3];

if (!comma) {
return [start, start];
}
if (!end) {
return [start, undefined];
}
return [start, Number(end)];
}
return undefined;
}

Prism.hooks.add('before-highlightall', function (env) {
env.selector += ', ' + SELECTOR;
Expand Down Expand Up @@ -1757,31 +1808,45 @@ Prism.languages.js = Prism.languages.javascript;
}

// load file
var xhr = new XMLHttpRequest();
xhr.open('GET', src, true);
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status < 400 && xhr.responseText) {
// mark as loaded
pre.setAttribute(STATUS_ATTR, STATUS_LOADED);

// highlight code
code.textContent = xhr.responseText;
Prism.highlightElement(code);

} else {
// mark as failed
pre.setAttribute(STATUS_ATTR, STATUS_FAILED);

if (xhr.status >= 400) {
code.textContent = FAILURE_MESSAGE(xhr.status, xhr.statusText);
} else {
code.textContent = FAILURE_EMPTY_MESSAGE;
loadFile(
src,
function (text) {
// mark as loaded
pre.setAttribute(STATUS_ATTR, STATUS_LOADED);

// handle data-range
var range = parseRange(pre.getAttribute('data-range'));
if (range) {
var lines = text.split(/\r\n?|\n/g);

// the range is one-based and inclusive on both ends
var start = range[0];
var end = range[1] == null ? lines.length : range[1];

if (start < 0) { start += lines.length; }
start = Math.max(0, Math.min(start - 1, lines.length));
if (end < 0) { end += lines.length; }
end = Math.max(0, Math.min(end, lines.length));

text = lines.slice(start, end).join('\n');

// add data-start for line numbers
if (!pre.hasAttribute('data-start')) {
pre.setAttribute('data-start', String(start + 1));
}
}

// highlight code
code.textContent = text;
Prism.highlightElement(code);
},
function (error) {
// mark as failed
pre.setAttribute(STATUS_ATTR, STATUS_FAILED);

code.textContent = error;
}
};
xhr.send(null);
);
}
});

Expand Down