-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from kairlec/dev
release v1.0.0
- Loading branch information
Showing
12 changed files
with
1,141 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.DS_Store | ||
Thumbs.db | ||
db.json | ||
*.log | ||
node_modules/ | ||
public/ | ||
.deploy*/ | ||
test.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
const { initPreConfig, isPluginDisabled, rendererFilterFunction, makeBodyEndInjectContent, makeHeadEndInjectContent } = require('./lib/index') | ||
|
||
initPreConfig(hexo.config.kotlin_playground || {}) | ||
|
||
if (!isPluginDisabled()) { | ||
hexo.extend.injector.register('head_end', makeHeadEndInjectContent(), 'default') | ||
|
||
hexo.extend.injector.register('body_end', makeBodyEndInjectContent(), 'default') | ||
|
||
hexo.extend.filter.register('marked:renderer', rendererFilterFunction) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
const specialKeyValueMap = new Map() | ||
|
||
class SpecialKeyValue { | ||
constructor (targetKey, setFunction = function (value) { return value }, getFunction = function (value) { return value }) { | ||
this.targetKey = targetKey | ||
this.setFunction = setFunction | ||
this.getFunction = getFunction | ||
} | ||
} | ||
|
||
function registerSpecialKeyValue (srcKey, targetKey, setFunction, getFunction) { | ||
specialKeyValueMap.set(srcKey, new SpecialKeyValue(targetKey, setFunction, getFunction)) | ||
} | ||
|
||
function getRealKey (key) { | ||
if (specialKeyValueMap.has(key)) { | ||
return getRealKey(specialKeyValueMap.get(key).targetKey) | ||
} | ||
return key | ||
} | ||
|
||
function getSpecialKeyValue (key, getValueFunction, applyTarget) { | ||
if (specialKeyValueMap.has(key)) { | ||
const special = specialKeyValueMap.get(key) | ||
return special.getFunction(getSpecialKeyValue(special.targetKey, getValueFunction, applyTarget)) | ||
} else { | ||
return getValueFunction.apply(applyTarget, [key]) | ||
} | ||
} | ||
|
||
function setSpecialKeyValue (key, value, setValueFunction, applyTarget) { | ||
if (specialKeyValueMap.has(key)) { | ||
const special = specialKeyValueMap.get(key) | ||
setSpecialKeyValue(special.targetKey, special.setFunction(value), setValueFunction, applyTarget) | ||
} else { | ||
setValueFunction.apply(applyTarget, [key, value]) | ||
} | ||
} | ||
|
||
exports.registerSpecialKeyValue = registerSpecialKeyValue | ||
exports.getSpecialKeyValue = getSpecialKeyValue | ||
exports.setSpecialKeyValue = setSpecialKeyValue | ||
exports.getRealKey = getRealKey |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
const { toHorizontalLine, deepCopy } = require('./util') | ||
const { registerSpecialKeyValue, getSpecialKeyValue, setSpecialKeyValue, getRealKey } = require('./SpecialKeyValue') | ||
|
||
function makeSpecialConfigKey (srcKey, targetKey, setFunction, getFunction) { | ||
if (getFunction === undefined) { | ||
if (typeof targetKey === 'function') { | ||
registerSpecialKeyValue(toHorizontalLine(srcKey), srcKey, targetKey, setFunction) | ||
} else if (typeof targetKey === 'undefined') { | ||
registerSpecialKeyValue(toHorizontalLine(srcKey), srcKey, setFunction, getFunction) | ||
} else { | ||
registerSpecialKeyValue(toHorizontalLine(srcKey), targetKey, setFunction, getFunction) | ||
} | ||
} else { | ||
registerSpecialKeyValue(toHorizontalLine(srcKey), toHorizontalLine(targetKey), setFunction, getFunction) | ||
} | ||
} | ||
|
||
function parseAttribute (str, pre) { | ||
const config = new Config(pre) | ||
while (true) { | ||
// eslint-disable-next-line | ||
let result = /([a-zA-Z_:][-a-zA-Z0-9_:.]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/.exec(str) | ||
if (result === null) { | ||
break | ||
} | ||
config.set(result[1], result[2] || result[3] || result[4]) | ||
str = str.slice(result.index + result[0].length) | ||
} | ||
return config | ||
} | ||
|
||
function getCodeBlockConfig (sourceCode, pre) { | ||
// 获取第一行注释 | ||
const firstLineIndex = sourceCode.indexOf('\n') | ||
if (firstLineIndex === -1) { | ||
return { config: new Config(pre), code: sourceCode } | ||
} | ||
const firstLine = sourceCode.slice(0, firstLineIndex) | ||
const comment = /^\s*\/{2,}@playground *(.*)$/m.exec(firstLine) | ||
if (comment !== null && comment[1].length > 0) { | ||
return { config: parseAttribute(comment[1], pre), code: sourceCode.slice(firstLineIndex + 1) } | ||
} else { | ||
return { config: new Config(pre), code: sourceCode } | ||
} | ||
} | ||
|
||
function __getRealKey (key) { | ||
return getRealKey(toHorizontalLine(key)) | ||
} | ||
|
||
function Config (obj) { | ||
if (obj instanceof Config) { | ||
this.enabled = obj.enabled | ||
this.config = deepCopy(obj.config) | ||
} else { | ||
this.config = {} | ||
if (obj) { | ||
for (const key in obj) { | ||
this.set(__getRealKey(key), obj[key]) | ||
} | ||
this.enabled = !!obj.enabled | ||
} else { | ||
this.enabled = true | ||
} | ||
} | ||
|
||
this.__set = function (key, value) { | ||
if (key === 'enabled') { | ||
if (typeof value === 'string') { | ||
this.enable(value.toLowerCase() !== 'false') | ||
} else { | ||
this.enable(value) | ||
} | ||
} else { | ||
this.config[key] = value | ||
} | ||
} | ||
|
||
this.__get = function (key) { | ||
return this.config[key] | ||
} | ||
|
||
this.set = function (key, ...value) { | ||
if (typeof key !== 'string') { | ||
throw TypeError('key type must be string') | ||
} | ||
let realValue | ||
for (const v of value) { | ||
if (v !== undefined) { | ||
realValue = v | ||
break | ||
} | ||
} | ||
setSpecialKeyValue(key, realValue, this.__set, this) | ||
} | ||
|
||
this.has = function (key) { | ||
return __getRealKey(key) in this.config | ||
} | ||
|
||
this.remove = function (key) { | ||
delete this.config[__getRealKey(key)] | ||
} | ||
|
||
this.get = function (key, defaultValue) { | ||
if (typeof key !== 'string') { | ||
throw TypeError('key type must be string') | ||
} | ||
const value = getSpecialKeyValue(key, this.__get, this) | ||
if (value === undefined) { | ||
return defaultValue | ||
} else { | ||
return value | ||
} | ||
} | ||
|
||
this.enable = function (enabled) { | ||
if (enabled === undefined) { | ||
this.enabled = true | ||
} else { | ||
this.enabled = !!enabled | ||
} | ||
} | ||
|
||
this.disable = function (disabled) { | ||
if (disabled === undefined) { | ||
this.enabled = false | ||
} else { | ||
this.enabled = !disabled | ||
} | ||
} | ||
|
||
this.toString = function (ifNull = (item) => ` ${item}`) { | ||
let str = '' | ||
for (const item in this.config) { | ||
if (this.config[item] === null) { | ||
str += ifNull(item) | ||
} else if (this.config[item] === undefined) { | ||
str += ` ${item}` | ||
} else { | ||
str += ` ${item}="${this.config[item]}"` | ||
} | ||
} | ||
return str | ||
} | ||
} | ||
|
||
exports.getCodeBlockConfig = getCodeBlockConfig | ||
exports.makeSpecialConfigKey = makeSpecialConfigKey | ||
exports.Config = Config |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,147 @@ | ||
const { highlight, escapeHTML, prismHighlight } = require('hexo-util') | ||
const stripIndent = require('strip-indent') | ||
const fs = require('fs') | ||
const { Config, getCodeBlockConfig, makeSpecialConfigKey } = require('./config') | ||
const { parseHide } = require('./parse') | ||
|
||
makeSpecialConfigKey('line-numbers', 'lines') | ||
makeSpecialConfigKey('lines-numbers', 'lines') | ||
makeSpecialConfigKey('line', 'lines') | ||
makeSpecialConfigKey('gutter', 'lines') | ||
makeSpecialConfigKey('disable-all', 'enable-all', value => !JSON.parse(value || 'true'), value => !value) | ||
|
||
makeSpecialConfigKey('min-version', 'data-min-compiler-version') | ||
makeSpecialConfigKey('autocomplete', 'data-autocomplete') | ||
makeSpecialConfigKey('auto-complete', 'data-autocomplete') | ||
makeSpecialConfigKey('readonly', 'data-highlight-only') | ||
makeSpecialConfigKey('read-only', 'data-highlight-only') | ||
makeSpecialConfigKey('runable', 'data-highlight-only', value => !JSON.parse(value || 'true'), value => !value) | ||
makeSpecialConfigKey('platform', 'data-target-platform') | ||
makeSpecialConfigKey('version', 'data-version') | ||
makeSpecialConfigKey('enable', 'enabled') | ||
makeSpecialConfigKey('disable', 'enabled', value => !JSON.parse(value || 'true'), value => !value) | ||
makeSpecialConfigKey('disabled', 'enabled', value => !JSON.parse(value || 'true'), value => !value) | ||
makeSpecialConfigKey('auto-check', 'highlight-on-fly') | ||
makeSpecialConfigKey('brackets', 'match-brackets') | ||
|
||
const preCodeBlockConfig = new Config() | ||
const preConfig = new Config() | ||
const scriptIntroduceConfig = new Config() | ||
|
||
function initPreConfig (kotlinPlaygroundConfig) { | ||
preConfig.set('html-tag', kotlinPlaygroundConfig.html_tag, 'code') | ||
preConfig.set('html-tag-class', kotlinPlaygroundConfig.html_tag_class, 'kotlin-code') | ||
preConfig.set('other-highlight', kotlinPlaygroundConfig.other_highlight, 'highlight') | ||
preConfig.set('other-highlight-config', kotlinPlaygroundConfig.other_highlight_config, {}) | ||
preConfig.set('css', kotlinPlaygroundConfig.css, {}) | ||
preConfig.set('tab', kotlinPlaygroundConfig.tab, ' ') | ||
preConfig.set('ext', kotlinPlaygroundConfig.extend, {}) | ||
preConfig.set('disabled-plugin', kotlinPlaygroundConfig.disable_plugin, false) | ||
preConfig.set('data-selector', kotlinPlaygroundConfig.data_selector, '.kotlin-code') | ||
scriptIntroduceConfig.set('src', kotlinPlaygroundConfig.src, 'https://unpkg.com/kotlin-playground@1') | ||
scriptIntroduceConfig.set('data-server', kotlinPlaygroundConfig.data_server, null) | ||
scriptIntroduceConfig.set('data-version', kotlinPlaygroundConfig.data_version, null) | ||
if (kotlinPlaygroundConfig.custom_pre) { | ||
for (const key in kotlinPlaygroundConfig.custom_pre) { | ||
preConfig.set(key, kotlinPlaygroundConfig.custom_pre[key]) | ||
} | ||
} | ||
|
||
preCodeBlockConfig.set('lines', kotlinPlaygroundConfig.line_numbers, true) | ||
preCodeBlockConfig.set('auto-indent', kotlinPlaygroundConfig.auto_indent, true) | ||
preCodeBlockConfig.set('indent', kotlinPlaygroundConfig.indent, 4) | ||
preCodeBlockConfig.set('theme', kotlinPlaygroundConfig.theme, 'default') | ||
preCodeBlockConfig.enable(kotlinPlaygroundConfig.enable_all) | ||
if (kotlinPlaygroundConfig.custom_cb_pre) { | ||
for (const key in kotlinPlaygroundConfig.custom_cb_pre) { | ||
preCodeBlockConfig.set(key, kotlinPlaygroundConfig.custom_cb_pre[key]) | ||
} | ||
} | ||
} | ||
|
||
function isPluginDisabled () { | ||
return preConfig.get('disabled-plugin') | ||
} | ||
|
||
function tryHighLightKotlin (wrapCode) { | ||
const { config, code } = getCodeBlockConfig(wrapCode.sourceCode, preCodeBlockConfig) | ||
if (config.enabled) { | ||
const tag = preConfig.get('html-tag') | ||
const tagClass = preConfig.get('html-tag-class') | ||
const _code = parseHide(code, escapeHTML, hidden => `<textarea class="hidden-dependency">${hidden}</textarea>`) | ||
return `<pre class="language-kotlin"><${tag} class="${tagClass}"${config.toString()}>${_code}</${tag}></pre>` | ||
} else { | ||
wrapCode.sourceCode = code | ||
return null | ||
} | ||
} | ||
|
||
function makeHeadEndInjectContent () { | ||
// 统一highlight.js,playground,prismjs的样式 | ||
return `<style type="text/css"> | ||
.CodeMirror-lines,.line,.code-output,.code,.token { | ||
font-size: ${preConfig.get('css').font_size || '16px'}; | ||
line-height: ${preConfig.get('css').line_height || '22px'}; | ||
} | ||
</style>` | ||
} | ||
|
||
function makeBodyEndInjectContent () { | ||
const dataSelector = preConfig.get('data-selector') | ||
let jsCode = '' | ||
const ext = preConfig.get('ext') | ||
if (ext.js && fs.existsSync(ext.js)) { | ||
jsCode = fs.readFileSync(ext.js, { encoding: 'utf-8' }) | ||
} | ||
|
||
return `<script${scriptIntroduceConfig.toString(item => '')}></script> | ||
<script> | ||
${jsCode} | ||
if(typeof ktpgOptions !== 'undefined'){ | ||
KotlinPlayground('${dataSelector}',ktpgOptions) | ||
}else{ | ||
KotlinPlayground('${dataSelector}') | ||
} | ||
window.addEventListener('pjax:complete', event => { | ||
if(typeof ktpgOptions !== 'undefined'){ | ||
KotlinPlayground('${dataSelector}',ktpgOptions) | ||
}else{ | ||
KotlinPlayground('${dataSelector}') | ||
} | ||
}); | ||
</script>` | ||
} | ||
|
||
function rendererFilterFunction (renderer) { | ||
renderer.__code = renderer.code | ||
renderer.code = (sourceCode, language) => { | ||
const wrapCode = { sourceCode: stripIndent(sourceCode).replace(/\t/mg, preConfig.tab) } | ||
if (language.toLowerCase() === 'kotlin') { | ||
const data = tryHighLightKotlin(wrapCode) | ||
if (!data) { | ||
return otherHighLightCode(wrapCode.sourceCode, language, () => renderer.__code(wrapCode.sourceCode, language)) | ||
} | ||
return `<figure class="highlight kotlin">${data}</figure>` | ||
} | ||
return otherHighLightCode(wrapCode.sourceCode, language, () => renderer.__code(wrapCode.sourceCode, language)) | ||
} | ||
} | ||
|
||
function otherHighLightCode (code, _lang, els) { | ||
const line = preCodeBlockConfig.get('lines') | ||
const tab = preCodeBlockConfig.get('tab') | ||
const engine = preConfig.get('other-highlight') | ||
const engineConfig = preConfig.get('other-highlight-config') | ||
if (engine === 'highlight') { | ||
return highlight(code, { hljs: engineConfig.hljs, gutter: line, tab: tab, lang: _lang, ...engineConfig }) | ||
} else if (engine === 'prismjs') { | ||
return prismHighlight(code, { lineNumber: line, tab: tab, lang: _lang, ...engineConfig }) | ||
} else { | ||
return els() | ||
} | ||
} | ||
exports.initPreConfig = initPreConfig | ||
exports.isPluginDisabled = isPluginDisabled | ||
exports.rendererFilterFunction = rendererFilterFunction | ||
exports.makeBodyEndInjectContent = makeBodyEndInjectContent | ||
exports.makeHeadEndInjectContent = makeHeadEndInjectContent |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
function parseHide (code, preHandler, hiddenHandler) { | ||
const hideStart = /[^\n]*^\/{2,}\s*@hidestart[^\n]*$\n?/mg.exec(code) | ||
const hideEnd = /[^\n]*^\/{2,}\s*@hideend[^\n]*$\n?/mg.exec(code) | ||
if (hideStart && hideEnd) { | ||
return preHandler(code.substr(0, hideStart.index - 1)) + hiddenHandler(preHandler(code.slice(hideStart.index + hideStart[0].length, hideEnd.index - 1))) + preHandler(code.slice(hideEnd.index + hideEnd[0].length)) | ||
} else { | ||
return preHandler(code) | ||
} | ||
} | ||
|
||
exports.parseHide = parseHide |
Oops, something went wrong.