Skip to content

Commit

Permalink
File highlight+data range (#1813)
Browse files Browse the repository at this point in the history
Co-authored-by: atomize <[email protected]>
Co-authored-by: Michael Schmidt <[email protected]>
  • Loading branch information
3 people authored Oct 4, 2021
1 parent f053af1 commit d38592c
Show file tree
Hide file tree
Showing 4 changed files with 188 additions and 45 deletions.
13 changes: 13 additions & 0 deletions plugins/file-highlight/index.html
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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

0 comments on commit d38592c

Please sign in to comment.