UNPKG

reprism

Version:

Modular Syntax highlighting for the web

211 lines (202 loc) 6.2 kB
export default { language: 'lisp', init: Prism => { (function (Prism) { // Functions to construct regular expressions // simple form // e.g. (interactive ... or (interactive) function simple_form (name) { return new RegExp(`(\\()${name}(?=[\\s\\)])`) } // booleans and numbers function primitive (pattern) { return new RegExp(`([\\s([])${pattern}(?=[\\s)])`) } // Patterns in regular expressions // Symbol name. See https://www.gnu.org/software/emacs/manual/html_node/elisp/Symbol-Type.html // & and : are excluded as they are usually used for special purposes const symbol = '[-+*/_~!@$%^=<>{}\\w]+' // symbol starting with & used in function arguments const marker = `&${symbol}` // Open parenthesis for look-behind const par = '(\\()' const endpar = '(?=\\))' // End the pattern with look-ahead space const space = '(?=\\s)' const language = { // Three or four semicolons are considered a heading. // See https://www.gnu.org/software/emacs/manual/html_node/elisp/Comment-Tips.html heading: { pattern: /;;;.*/, alias: ['comment', 'title'], }, comment: /;.*/, string: { pattern: /"(?:[^"\\]*|\\.)*"/, greedy: true, inside: { argument: /[-A-Z]+(?=[.,\s])/, symbol: new RegExp(`\`${symbol}'`), }, }, 'quoted-symbol': { pattern: new RegExp(`#?'${symbol}`), alias: ['variable', 'symbol'], }, 'lisp-property': { pattern: new RegExp(`:${symbol}`), alias: 'property', }, splice: { pattern: new RegExp(`,@?${symbol}`), alias: ['symbol', 'variable'], }, keyword: [ { pattern: new RegExp( `${par }(?:(?:lexical-)?let\\*?|(?:cl-)?letf|if|when|while|unless|cons|cl-loop|and|or|not|cond|setq|error|message|null|require|provide|use-package)${ space}` ), lookbehind: true, }, { pattern: new RegExp( `${par }(?:for|do|collect|return|finally|append|concat|in|by)${ space}` ), lookbehind: true, }, ], declare: { pattern: simple_form('declare'), lookbehind: true, alias: 'keyword', }, interactive: { pattern: simple_form('interactive'), lookbehind: true, alias: 'keyword', }, boolean: { pattern: primitive('(?:t|nil)'), lookbehind: true, }, number: { pattern: primitive('[-+]?\\d+(?:\\.\\d*)?'), lookbehind: true, }, defvar: { pattern: new RegExp( `${par}def(?:var|const|custom|group)\\s+${symbol}` ), lookbehind: true, inside: { keyword: /^def[a-z]+/, variable: new RegExp(symbol), }, }, defun: { pattern: new RegExp( `${par }(?:cl-)?(?:defun\\*?|defmacro)\\s+${ symbol }\\s+\\([\\s\\S]*?\\)` ), lookbehind: true, inside: { keyword: /^(?:cl-)?def\S+/, // See below, this property needs to be defined later so that it can // reference the language object. arguments: null, function: { pattern: new RegExp(`(^\\s)${symbol}`), lookbehind: true, }, punctuation: /[()]/, }, }, lambda: { pattern: new RegExp( `${par}lambda\\s+\\((?:&?${symbol}\\s*)*\\)` ), lookbehind: true, inside: { keyword: /^lambda/, // See below, this property needs to be defined later so that it can // reference the language object. arguments: null, punctuation: /[()]/, }, }, car: { pattern: new RegExp(par + symbol), lookbehind: true, }, punctuation: [ // open paren, brackets, and close paren /(['`,]?\(|[)\[\]])/, // cons { pattern: /(\s)\.(?=\s)/, lookbehind: true, }, ], } const arg = { 'lisp-marker': new RegExp(marker), rest: { argument: { pattern: new RegExp(symbol), alias: 'variable', }, varform: { pattern: new RegExp(`${par + symbol}\\s+\\S[\\s\\S]*${endpar}`), lookbehind: true, inside: { string: language.string, boolean: language.boolean, number: language.number, symbol: language.symbol, punctuation: /[()]/, }, }, }, } const forms = '\\S+(?:\\s+\\S+)*' const arglist = { pattern: new RegExp(`${par}[\\s\\S]*${endpar}`), lookbehind: true, inside: { 'rest-vars': { pattern: new RegExp(`&(?:rest|body)\\s+${forms}`), inside: arg, }, 'other-marker-vars': { pattern: new RegExp(`&(?:optional|aux)\\s+${forms}`), inside: arg, }, keys: { pattern: new RegExp( `&key\\s+${forms}(?:\\s+&allow-other-keys)?` ), inside: arg, }, argument: { pattern: new RegExp(symbol), alias: 'variable', }, punctuation: /[()]/, }, } language.lambda.inside.arguments = arglist language.defun.inside.arguments = Prism.util.clone(arglist) language.defun.inside.arguments.inside.sublist = arglist Prism.languages.lisp = language Prism.languages.elisp = language Prism.languages.emacs = language Prism.languages['emacs-lisp'] = language }(Prism)) }, }