You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
258 lines
4.8 KiB
258 lines
4.8 KiB
/** |
|
* @param {string} value |
|
* @returns {RegExp} |
|
* */ |
|
|
|
/** |
|
* @param {RegExp | string } re |
|
* @returns {string} |
|
*/ |
|
function source(re) { |
|
if (!re) return null; |
|
if (typeof re === "string") return re; |
|
|
|
return re.source; |
|
} |
|
|
|
/** |
|
* @param {...(RegExp | string) } args |
|
* @returns {string} |
|
*/ |
|
function concat(...args) { |
|
const joined = args.map((x) => source(x)).join(""); |
|
return joined; |
|
} |
|
|
|
/* |
|
Language: Markdown |
|
Requires: xml.js |
|
Author: John Crepezzi <john.crepezzi@gmail.com> |
|
Website: https://daringfireball.net/projects/markdown/ |
|
Category: common, markup |
|
*/ |
|
|
|
function markdown(hljs) { |
|
const INLINE_HTML = { |
|
begin: /<\/?[A-Za-z_]/, |
|
end: '>', |
|
subLanguage: 'xml', |
|
relevance: 0 |
|
}; |
|
const HORIZONTAL_RULE = { |
|
begin: '^[-\\*]{3,}', |
|
end: '$' |
|
}; |
|
const CODE = { |
|
className: 'code', |
|
variants: [ |
|
// TODO: fix to allow these to work with sublanguage also |
|
{ |
|
begin: '(`{3,})[^`](.|\\n)*?\\1`*[ ]*' |
|
}, |
|
{ |
|
begin: '(~{3,})[^~](.|\\n)*?\\1~*[ ]*' |
|
}, |
|
// needed to allow markdown as a sublanguage to work |
|
{ |
|
begin: '```', |
|
end: '```+[ ]*$' |
|
}, |
|
{ |
|
begin: '~~~', |
|
end: '~~~+[ ]*$' |
|
}, |
|
{ |
|
begin: '`.+?`' |
|
}, |
|
{ |
|
begin: '(?=^( {4}|\\t))', |
|
// use contains to gobble up multiple lines to allow the block to be whatever size |
|
// but only have a single open/close tag vs one per line |
|
contains: [ |
|
{ |
|
begin: '^( {4}|\\t)', |
|
end: '(\\n)$' |
|
} |
|
], |
|
relevance: 0 |
|
} |
|
] |
|
}; |
|
const LIST = { |
|
className: 'bullet', |
|
begin: '^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)', |
|
end: '\\s+', |
|
excludeEnd: true |
|
}; |
|
const LINK_REFERENCE = { |
|
begin: /^\[[^\n]+\]:/, |
|
returnBegin: true, |
|
contains: [ |
|
{ |
|
className: 'symbol', |
|
begin: /\[/, |
|
end: /\]/, |
|
excludeBegin: true, |
|
excludeEnd: true |
|
}, |
|
{ |
|
className: 'link', |
|
begin: /:\s*/, |
|
end: /$/, |
|
excludeBegin: true |
|
} |
|
] |
|
}; |
|
const URL_SCHEME = /[A-Za-z][A-Za-z0-9+.-]*/; |
|
const LINK = { |
|
variants: [ |
|
// too much like nested array access in so many languages |
|
// to have any real relevance |
|
{ |
|
begin: /\[.+?\]\[.*?\]/, |
|
relevance: 0 |
|
}, |
|
// popular internet URLs |
|
{ |
|
begin: /\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, |
|
relevance: 2 |
|
}, |
|
{ |
|
begin: concat(/\[.+?\]\(/, URL_SCHEME, /:\/\/.*?\)/), |
|
relevance: 2 |
|
}, |
|
// relative urls |
|
{ |
|
begin: /\[.+?\]\([./?&#].*?\)/, |
|
relevance: 1 |
|
}, |
|
// whatever else, lower relevance (might not be a link at all) |
|
{ |
|
begin: /\[.+?\]\(.*?\)/, |
|
relevance: 0 |
|
} |
|
], |
|
returnBegin: true, |
|
contains: [ |
|
{ |
|
className: 'string', |
|
relevance: 0, |
|
begin: '\\[', |
|
end: '\\]', |
|
excludeBegin: true, |
|
returnEnd: true |
|
}, |
|
{ |
|
className: 'link', |
|
relevance: 0, |
|
begin: '\\]\\(', |
|
end: '\\)', |
|
excludeBegin: true, |
|
excludeEnd: true |
|
}, |
|
{ |
|
className: 'symbol', |
|
relevance: 0, |
|
begin: '\\]\\[', |
|
end: '\\]', |
|
excludeBegin: true, |
|
excludeEnd: true |
|
} |
|
] |
|
}; |
|
const BOLD = { |
|
className: 'strong', |
|
contains: [], // defined later |
|
variants: [ |
|
{ |
|
begin: /_{2}/, |
|
end: /_{2}/ |
|
}, |
|
{ |
|
begin: /\*{2}/, |
|
end: /\*{2}/ |
|
} |
|
] |
|
}; |
|
const ITALIC = { |
|
className: 'emphasis', |
|
contains: [], // defined later |
|
variants: [ |
|
{ |
|
begin: /\*(?!\*)/, |
|
end: /\*/ |
|
}, |
|
{ |
|
begin: /_(?!_)/, |
|
end: /_/, |
|
relevance: 0 |
|
} |
|
] |
|
}; |
|
BOLD.contains.push(ITALIC); |
|
ITALIC.contains.push(BOLD); |
|
|
|
let CONTAINABLE = [ |
|
INLINE_HTML, |
|
LINK |
|
]; |
|
|
|
BOLD.contains = BOLD.contains.concat(CONTAINABLE); |
|
ITALIC.contains = ITALIC.contains.concat(CONTAINABLE); |
|
|
|
CONTAINABLE = CONTAINABLE.concat(BOLD, ITALIC); |
|
|
|
const HEADER = { |
|
className: 'section', |
|
variants: [ |
|
{ |
|
begin: '^#{1,6}', |
|
end: '$', |
|
contains: CONTAINABLE |
|
}, |
|
{ |
|
begin: '(?=^.+?\\n[=-]{2,}$)', |
|
contains: [ |
|
{ |
|
begin: '^[=-]*$' |
|
}, |
|
{ |
|
begin: '^', |
|
end: "\\n", |
|
contains: CONTAINABLE |
|
} |
|
] |
|
} |
|
] |
|
}; |
|
|
|
const BLOCKQUOTE = { |
|
className: 'quote', |
|
begin: '^>\\s+', |
|
contains: CONTAINABLE, |
|
end: '$' |
|
}; |
|
|
|
return { |
|
name: 'Markdown', |
|
aliases: [ |
|
'md', |
|
'mkdown', |
|
'mkd' |
|
], |
|
contains: [ |
|
HEADER, |
|
INLINE_HTML, |
|
LIST, |
|
BOLD, |
|
ITALIC, |
|
BLOCKQUOTE, |
|
CODE, |
|
HORIZONTAL_RULE, |
|
LINK, |
|
LINK_REFERENCE |
|
] |
|
}; |
|
} |
|
|
|
module.exports = markdown;
|
|
|