mirror of
https://github.com/vale981/highlight-lisp
synced 2025-03-04 17:01:38 -05:00
more highlighting updates/comments, github theme updates, adding readme.
This commit is contained in:
parent
13821b414e
commit
3170af94ca
3 changed files with 205 additions and 26 deletions
130
README.md
Normal file
130
README.md
Normal file
|
@ -0,0 +1,130 @@
|
|||
highlight-lisp - Common Lisp syntax highlighter written in Javascript
|
||||
=====================================================================
|
||||
This is a syntax highlighter for Common Lisp written in Javascript. It is
|
||||
completely themable via CSS (themes included).
|
||||
|
||||
The purpose of this is to make it really easy to embed beautiful Common Lisp
|
||||
code into a website with minimal effort.
|
||||
|
||||
Usage
|
||||
-----
|
||||
Usage is simple. You include `highlight-lisp.js`, link to one of the CSS themes,
|
||||
and call one of highlight-lisp's highlighting functions:
|
||||
|
||||
```html
|
||||
<!-- Put these in your document somewhere, probably in the head, although the <script>
|
||||
tag can probably go anywhere -->
|
||||
<script type="text/javascript" src="/js/highlight-lisp/highlight-lisp.js"></script>
|
||||
<link rel="stylesheet" href="/js/highlight-lisp/themes/github.css">
|
||||
|
||||
...
|
||||
|
||||
<pre><code class="lisp">(defun test-syntax-highlighter ()
|
||||
"Docstring exaplaining what this function does."
|
||||
(let ((hash (make-hash-table :test #'equal)))
|
||||
...))</pre></code>
|
||||
```
|
||||
|
||||
Once the HTML is set up, there are a few ways to initialize highlighting:
|
||||
|
||||
```js
|
||||
// automatically highlight all <code class="lisp">...</code> blocks
|
||||
HighlightLisp.highlight_auto();
|
||||
|
||||
// specify a class name:
|
||||
HighlightLisp.highlight_auto({className: 'common-lisp'});
|
||||
|
||||
// highlight *every* code block
|
||||
HighlightLisp.highlight_auto({className: null});
|
||||
|
||||
// manually highlight a code block
|
||||
var code = document.getElementById('my-code-element');
|
||||
HighlightLisp.highlight_element(code);
|
||||
```
|
||||
|
||||
What gets highlighted
|
||||
---------------------
|
||||
- **Functions**. CSS class `function`
|
||||
Anything starting with `(`: `(my-function ...)`
|
||||
- **Known functions**. CSS class `function known`
|
||||
Any function known by the highlighter: things like `make-hash-table`, `when`,
|
||||
`format`, etc
|
||||
- **Special functions**. CSS class `function known special`
|
||||
Mainly `let`, `let\*`, `lambda`.
|
||||
- **Symbol functions**. CSS class `function symbol`
|
||||
Example: `#'my-function`
|
||||
- **Known symbol functions**. CSS class `function symbol known`
|
||||
Examples: `#'equalp`, `#'format`
|
||||
- **Keywords**. CSS class `keyword`
|
||||
Anything starting with `:` like `:this-is-a-keyword `
|
||||
- **Known keywords**. CSS class `keyword known`
|
||||
Known keywords are things like `:hash-keys`, `:supersede`, etc.
|
||||
- **Symbols**. CSS class `symbol`
|
||||
Anything starting with `'`: `'my-symbol`
|
||||
- **Lambda-list operators**. CSS class `lambda-list`
|
||||
Things like `&key`, `&body`, etc.
|
||||
- **Numbers**. CSS class `number`
|
||||
Any numbers: `69`, `-82.4`, `#xF047`, `#b11010`
|
||||
- **Integers**. CSS class `number integer`
|
||||
Simple numbers: `42`, `867`, etc. (no decimals)
|
||||
- **Floats**. CSS class `number float`
|
||||
Numbers with a decimal: `+47.82112`, `32.9` `3.` `.009`
|
||||
- **Hex**. CSS class `number hex`
|
||||
Hex numbers: `#x8090`, `#xc001`
|
||||
- **Binary**. CSS class `number binary`
|
||||
Example: `#b01101`
|
||||
- **Variables**. By themselves, variables remain unhighlighted
|
||||
- **Known variables**: CSS class `variable known`
|
||||
Examples: `*package*`, `*standard-output*`, etc
|
||||
- **Global variables**: CSS class `variable global`
|
||||
Any symbol surrounded by `\*`: `*main-datastore*`, `*my-thread-local*`, etc
|
||||
- **Constants**: CSS class `variable constant`
|
||||
Any symbol surrounded by `+`: `+dt+`, `+contant-time+`, etc
|
||||
- **nil/t**. CSS class `nil`
|
||||
Any standalone `nil` or `t` will get this class
|
||||
- **Comments**. CSS class `comment`
|
||||
Example: `; this is a comment`
|
||||
- **Strings**. CSS class `string`
|
||||
Anthing inside `"`: `"This is a string."`
|
||||
- **Parens**. CSS class `list`
|
||||
May be overkill, but any `(` or `)` characters are classified.
|
||||
|
||||
On that note, things that *don't get highlighted/aren't properly highlighted*:
|
||||
|
||||
- Variables...things like `let` bindings or other symols within code that would
|
||||
be interpreted as variables. Highlighting these would most likely be prohibitive
|
||||
in terms of time (not the mention the return on investment). Feel free to patch!
|
||||
- Some number notations. For instance `0.44d0`.
|
||||
- Multi-line comments `#| ... |#` are unsupported
|
||||
- Many constants (such as `pi`, `internal-time-units-per-second`) are classified
|
||||
as functions, not known variables. This is because I pulled the list out of my
|
||||
vim highlight script, and couldn't find a list of "Common Lisp standard
|
||||
variables" to cross reference with. I pulled out the ones I know of and put them
|
||||
into the known variables list, but there are no doubt more. If you see something
|
||||
that is a known variable but gets treated as a known function, please open a
|
||||
github issue.
|
||||
|
||||
Why
|
||||
---
|
||||
> Aren't there a bunch of Javascript syntax highlighters out there already?
|
||||
|
||||
Yes, but truth be told, most ignore lisp. You can write custom parsers for some
|
||||
of them, but the APIs they provide didn't work well enough for me. [highlight.js](http://softwaremaniacs.org/soft/highlight/en/)
|
||||
has a very nice lisp-highlighting mode, but I wanted more control over the
|
||||
process.
|
||||
|
||||
For instance, `highlight-lisp` started as a [SyntaxHighlighter](http://alexgorbatchev.com/SyntaxHighlighter/)
|
||||
brush, but I quickly realized that because of the limitations of Javascript not
|
||||
allowing real [lookbehind regular expressions](http://www.regular-expressions.info/lookaround.html),
|
||||
I needed more direct control over the search/replace process.
|
||||
|
||||
What I discovered was that given the proper tools, parsing lisp is *easy*
|
||||
(especially after just releasing [markdown.cl](https://github.com/orthecreedence/markdown.cl))
|
||||
and there's no need for a big highlighting framework. You plug in some regexes,
|
||||
slap some <span class="..."> tags around certain things, and call it a day.
|
||||
|
||||
License
|
||||
-------
|
||||
As always, MIT.
|
||||
|
||||
|
|
@ -7,10 +7,8 @@
|
|||
* @licence MIT
|
||||
*/
|
||||
var highlight_lisp = function() {
|
||||
// all of the following definitions were pulled straight from my syntax/lisp.vim
|
||||
// all of the following functions were pulled straight from my syntax/lisp.vim
|
||||
// file in my vim directory.
|
||||
//
|
||||
// this includes functions, known globals, known keywords, lambda list specials
|
||||
var funcs =
|
||||
'\\* find-method pprint-indent find-package pprint-linear find-restart ' +
|
||||
'pprint-logical-block \\+ find-symbol pprint-newline finish-output ' +
|
||||
|
@ -50,7 +48,7 @@ var highlight_lisp = function() {
|
|||
'int-char restart-name bit-vector integer return bit-vector-p ' +
|
||||
'integer-decode-float return-from bit-xor integer-length revappend block ' +
|
||||
'integerp reverse boole interactive-stream-p room boole-1 intern rotatef ' +
|
||||
'boole-2 internal-time-units-per-second round boole-and intersection ' +
|
||||
'boole-2 round boole-and intersection ' +
|
||||
'row-major-aref boole-andc1 invalid-method-error rplaca boole-andc2 ' +
|
||||
'invoke-debugger rplacd boole-c1 invoke-restart safety boole-c2 ' +
|
||||
'invoke-restart-interactively satisfies boole-clr isqrt sbit boole-eqv keyword ' +
|
||||
|
@ -175,13 +173,14 @@ var highlight_lisp = function() {
|
|||
'pathname-name with-output-to-string file-error pathname-type ' +
|
||||
'with-package-iterator file-error-pathname pathname-version with-simple-restart ' +
|
||||
'file-length pathnamep with-slots file-namestring peek-char ' +
|
||||
'with-standard-io-syntax file-position phase write file-stream pi write-byte ' +
|
||||
'with-standard-io-syntax file-position phase write file-stream write-byte ' +
|
||||
'file-string-length plusp write-char file-write-date pop write-line fill ' +
|
||||
'position write-sequence fill-pointer position-if write-string find ' +
|
||||
'position-if-not write-to-string find-all-symbols pprint y-or-n-p find-class ' +
|
||||
'pprint-dispatch yes-or-no-p find-if pprint-exit-if-list-exhausted zerop ' +
|
||||
'find-if-not pprint-fill';
|
||||
|
||||
// common lisp global variables. also from lisp.vim
|
||||
var standard_vars =
|
||||
'\\*applyhook\\* \\*load-pathname\\* \\*print-pprint-dispatch\\* \\*break-on-signals\\* ' +
|
||||
'\\*load-print\\* \\*print-pprint-dispatch\\* \\*break-on-signals\\* \\*load-truename\\* ' +
|
||||
|
@ -195,8 +194,10 @@ var highlight_lisp = function() {
|
|||
'\\*debugger-hook\\* \\*print-gensym\\* \\*read-suppress\\* \\*default-pathname-defaults\\* ' +
|
||||
'\\*print-length\\* \\*readtable\\* \\*error-output\\* \\*print-level\\* \\*standard-input\\* ' +
|
||||
'\\*evalhook\\* \\*print-lines\\* \\*standard-output\\* \\*features\\* \\*print-miser-width\\* ' +
|
||||
'\\*terminal-io\\* \\*gensym-counter\\* \\*print-miser-width\\* \\*trace-output\\*';
|
||||
'\\*terminal-io\\* \\*gensym-counter\\* \\*print-miser-width\\* \\*trace-output\\* ' +
|
||||
'pi internal-time-units-per-second';
|
||||
|
||||
// common lisp known keywords
|
||||
var keywords =
|
||||
':abort :from-end :overwrite :adjustable :gensym :predicate :append :host ' +
|
||||
':preserve-whitespace :array :if-does-not-exist :pretty :base :if-exists :print ' +
|
||||
|
@ -248,13 +249,19 @@ var highlight_lisp = function() {
|
|||
* Collections of search and replaces to make.
|
||||
*/
|
||||
var replace = [
|
||||
// ---------------------------------------------------------------------
|
||||
// strings (should !!ALWAYS!! be first, lest our <span> tags be destroyed...)
|
||||
// ---------------------------------------------------------------------
|
||||
{regex: /"([\s\S]*?)"/gm, replace: '<span class="string">"$1"</span>'},
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// comments
|
||||
// ---------------------------------------------------------------------
|
||||
{regex: /(;.*)(\n|$)/gm, replace: '<span class="comment">$1</span>$2'},
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// "special" (let/lambda)
|
||||
// ---------------------------------------------------------------------
|
||||
{
|
||||
regex: new RegExp('.'+list_to_regex(special)+'(\\s)', 'gm'),
|
||||
replace: function(fullmatch, fnname, whitespace) {
|
||||
|
@ -270,7 +277,10 @@ var highlight_lisp = function() {
|
|||
},
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// function matches
|
||||
// ---------------------------------------------------------------------
|
||||
// known functions
|
||||
{
|
||||
regex: new RegExp('.'+list_to_regex(funcs)+'(\\s)', 'gm'),
|
||||
replace: function(fullmatch, fnname, whitespace) {
|
||||
|
@ -284,6 +294,7 @@ var highlight_lisp = function() {
|
|||
}
|
||||
}
|
||||
},
|
||||
// symbol functions (#'my-fn)
|
||||
{
|
||||
regex: /(\s|[()])(#'(\w[\w_-]*))(\s|[()])/g,
|
||||
replace: function(fullmatch, delim1, symfun, sym, delim2)
|
||||
|
@ -293,14 +304,19 @@ var highlight_lisp = function() {
|
|||
{
|
||||
known = true;
|
||||
}
|
||||
return delim1 +'<span class="function'+ (known ? ' known' : '') +'">'+ symfun +'</span>'+ delim2;
|
||||
return delim1 +'<span class="function symbol'+ (known ? ' known' : '') +'">'+ symfun +'</span>'+ delim2;
|
||||
}
|
||||
},
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// lambda keywords
|
||||
// ---------------------------------------------------------------------
|
||||
{regex: new RegExp('(\\s)'+list_to_regex(lambda)+'(\\s)', 'gm'), replace: '$1<span class="lambda-list">$2</span>$3'},
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// symbols/keywords/variables
|
||||
// ---------------------------------------------------------------------
|
||||
// known keywords
|
||||
{regex: /(\s|[()])('\w[\w_-]*)(\s|[()])/g, replace: '$1<span class="symbol">$2</span>$3'},
|
||||
{
|
||||
regex: new RegExp('(\\s)'+list_to_regex(keywords)+'(\\s)', 'g'),
|
||||
|
@ -308,6 +324,7 @@ var highlight_lisp = function() {
|
|||
return whitespace + '<span class="keyword known">'+ keyword +'</span>'+ whitespace2;
|
||||
}
|
||||
},
|
||||
// generic keywords
|
||||
{
|
||||
regex: /(\s|[()])(:\w[\w_-]*)/g,
|
||||
replace: function(fullmatch, delim, keyword) {
|
||||
|
@ -318,21 +335,32 @@ var highlight_lisp = function() {
|
|||
return fullmatch;
|
||||
}
|
||||
},
|
||||
// known variables
|
||||
{
|
||||
regex: new RegExp('(\\s|[()])'+list_to_regex(standard_vars)+'(\\s|[()])', 'g'),
|
||||
replace: function(fullmatch, whitespace, varname, whitespace2) {
|
||||
return whitespace + '<span class="variable known">'+ varname +'</span>'+ whitespace2;
|
||||
}
|
||||
},
|
||||
// globals/constants
|
||||
{regex: /(\s|[()])(\*\w[\w_-]*\*)(\s|[()])/g, replace: '$1<span class="variable global">$2</span>$3'},
|
||||
{regex: /(\s|[()])(\+\w[\w_-]*\+)(\s|[()])/g, replace: '$1<span class="variable constant">$2</span>$3'},
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// numbers
|
||||
// ---------------------------------------------------------------------
|
||||
// binary
|
||||
{regex: /(\s|[()])(#b[01]+)(\s|[()])/gi, replace: '$1<span class="number binary">$2</span>$3'},
|
||||
// hex
|
||||
{regex: /(\s|[()])(#x[\da-f]+)(\s|[()])/gi, replace: '$1<span class="number hex">$2</span>$3'},
|
||||
// float
|
||||
{regex: /(\s|[()])([+-]{0,1}(?:\d+\.\d+|\d+\.|\.\d+))(\s|[()])/g, replace: '$1<span class="number float">$2</span>$3'},
|
||||
// integers
|
||||
{regex: /(\s|[()])([+-]{0,1}\d+)(\s|[()])/g, replace: '$1<span class="number integer">$2</span>$3'},
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// misc parsers
|
||||
// ---------------------------------------------------------------------
|
||||
// t/nil
|
||||
{regex: /(\s|[()])nil(\s|[()])/g, replace: '$1<span class="nil">nil</span>$2'},
|
||||
{regex: /(\s|[()])t(\s|[()])/g, replace: '$1<span class="nil">t</span>$2'},
|
||||
|
@ -341,13 +369,13 @@ var highlight_lisp = function() {
|
|||
{regex: /\((\w[\w_-]*)(\s)/g, replace: '(<span class="function">$1</span>$2'},
|
||||
|
||||
// ()'s (should most probably be last, unless there's a good reason)
|
||||
//{regex: /([()])/g, replace: '<span class="list">$1</span>'}
|
||||
{regex: /([()])/g, replace: '<span class="list">$1</span>'}
|
||||
];
|
||||
|
||||
/**
|
||||
* Main highlight function.
|
||||
*/
|
||||
this.highlight = function(code_el)
|
||||
this.highlight_element = function(code_el)
|
||||
{
|
||||
var html = code_el.innerHTML;
|
||||
// can't have &...;'s running wild like a pack of animals...
|
||||
|
@ -360,6 +388,27 @@ var highlight_lisp = function() {
|
|||
html = html.replace(rep.regex, rep.replace);
|
||||
}
|
||||
code_el.innerHTML = html;
|
||||
},
|
||||
|
||||
/**
|
||||
* Automatically highlight all <code class="lisp"> blocks
|
||||
*
|
||||
* Takes an options arg, which can be used to specify the classname of the
|
||||
* <code> tags you wish to highlight.
|
||||
*/
|
||||
this.highlight_auto = function(options)
|
||||
{
|
||||
options || (options = {});
|
||||
var classname = options.className ? options.className : 'lisp';
|
||||
var codes = document.getElementsByTagName('code');
|
||||
for(var i = 0, n = codes.length; i < n; i++)
|
||||
{
|
||||
var code = codes[i];
|
||||
if(code.className.match(classname))
|
||||
{
|
||||
this.highlight_element(code);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
pre { white-space: pre; background-color: #f8f8f8; border: 1px solid #ccc; font-size: 13px; line-height: 19px; overflow: auto; padding: 6px 10px; border-radius: 3px; }
|
||||
pre code {white-space: pre; margin: 0; padding: 0; background: none; border: none; overflow-x: auto; font-size: 13px;}
|
||||
code {margin: 0 2px; padding: 0 5px; white-space: nowrap; font-family: Consolas, "Liberation Mono", Courier, monospace; background: #f8f8f8; border: 1px solid #eaeaea; border-radius: 3px;}
|
||||
pre code.lisp {white-space: pre; margin: 0; padding: 0; background: none; border: none; overflow-x: auto; font-size: 13px;}
|
||||
code.lisp {margin: 0 2px; padding: 0 5px; white-space: nowrap; font-family: Consolas, "Liberation Mono", Courier, monospace; background: #f8f8f8; border: 1px solid #eaeaea; border-radius: 3px;}
|
||||
|
||||
pre {color: #008080;}
|
||||
pre .function {color: #008080;}
|
||||
pre .function.known {color: #800603;}
|
||||
pre .function.known.special {color: #2d2d2d; font-weight: bold;}
|
||||
pre .keyword {color: #990073;}
|
||||
pre .keyword.known {color: #990073;}
|
||||
pre .symbol {color: #75a;}
|
||||
pre .lambda-list {color: #966;}
|
||||
pre .number {color: #800;}
|
||||
pre .variable.known {color: #c3c;}
|
||||
pre .variable.global {color: #939;}
|
||||
pre .variable.constant {color: #229;}
|
||||
pre .nil {color: #f00;}
|
||||
pre code.lisp {color: #008080;}
|
||||
pre code.lisp .function {color: #008080;}
|
||||
pre code.lisp .function.known {color: #800603;}
|
||||
pre code.lisp .function.known.special {color: #2d2d2d; font-weight: bold;}
|
||||
pre code.lisp .keyword {color: #990073;}
|
||||
pre code.lisp .keyword.known {color: #990073;}
|
||||
pre code.lisp .symbol {color: #75a;}
|
||||
pre code.lisp .lambda-list {color: #966;}
|
||||
pre code.lisp .number {color: #800;}
|
||||
pre code.lisp .variable.known {color: #c3c;}
|
||||
pre code.lisp .variable.global {color: #939;}
|
||||
pre code.lisp .variable.constant {color: #229;}
|
||||
pre code.lisp .nil {color: #f00;}
|
||||
|
||||
pre .comment, pre .comment *, pre .comment .string {color: #aaa !important;}
|
||||
pre .string, pre .string * {color: #d14 !important;}
|
||||
pre code.lisp .comment, pre .comment *, pre .comment .string {color: #aaa !important;}
|
||||
pre code.lisp .string, pre .string * {color: #d14 !important;}
|
||||
|
|
Loading…
Add table
Reference in a new issue