From 5c186f30a84a75ef5446ee4f885aa20500c1bf30 Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Thu, 13 Sep 2018 12:00:08 +0200 Subject: [PATCH 1/3] add yaml format for chart --- browser/components/MarkdownPreview.js | 4 +++- browser/lib/markdown.js | 6 +++++- package.json | 1 + yarn.lock | 7 +++++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index 493b1fc4..5ddc7598 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -17,6 +17,7 @@ import copy from 'copy-to-clipboard' import mdurl from 'mdurl' import exportNote from 'browser/main/lib/dataApi/exportNote' import { escapeHtmlCharacters } from 'browser/lib/utils' +import yaml from 'js-yaml' const { remote } = require('electron') const attachmentManagement = require('../main/lib/dataApi/attachmentManagement') @@ -736,7 +737,8 @@ export default class MarkdownPreview extends React.Component { this.refs.root.contentWindow.document.querySelectorAll('.chart'), el => { try { - const chartConfig = JSON.parse(el.innerHTML) + const format = el.attributes.getNamedItem('data-format').value + const chartConfig = format === 'yaml' ? yaml.load(el.innerHTML) : JSON.parse(el.innerHTML) el.innerHTML = '' const canvas = document.createElement('canvas') diff --git a/browser/lib/markdown.js b/browser/lib/markdown.js index 40c47aac..87cf86aa 100644 --- a/browser/lib/markdown.js +++ b/browser/lib/markdown.js @@ -126,9 +126,13 @@ class Markdown { this.md.use(require('./markdown-it-fence'), { chart: token => { + if (token.parameters.hasOwnProperty('yaml')) { + token.parameters.format = 'yaml' + } + return `
           ${token.fileName}
-          
${token.content}
+
${token.content}
` }, flowchart: token => { diff --git a/package.json b/package.json index c9e22164..c6267cd7 100644 --- a/package.json +++ b/package.json @@ -67,6 +67,7 @@ "iconv-lite": "^0.4.19", "immutable": "^3.8.1", "js-sequence-diagrams": "^1000000.0.6", + "js-yaml": "^3.12.0", "katex": "^0.9.0", "lodash": "^4.11.1", "lodash-move": "^1.1.1", diff --git a/yarn.lock b/yarn.lock index 4ecfa51b..c155c8d4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5254,6 +5254,13 @@ js-yaml@^3.10.0, js-yaml@^3.5.1, js-yaml@^3.7.0: argparse "^1.0.7" esprima "^4.0.0" +js-yaml@^3.12.0: + version "3.12.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1" + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + js-yaml@~2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-2.0.5.tgz#a25ae6509999e97df278c6719da11bd0687743a8" From 4b0dc084265e00da6a5b35dd720396e2eba1f976 Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Fri, 14 Sep 2018 00:03:33 +0200 Subject: [PATCH 2/3] highlight code block for chart.js --- browser/components/MarkdownEditor.js | 2 +- browser/components/MarkdownSplitEditor.js | 2 +- browser/lib/markdown-it-fence.js | 4 +- extra_scripts/codemirror/mode/bfm/bfm.js | 107 ++++++++++++++++++++++ lib/main.html | 6 ++ 5 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 extra_scripts/codemirror/mode/bfm/bfm.js diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index ee80c887..63673583 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -250,7 +250,7 @@ class MarkdownEditor extends React.Component { : 'codeEditor--hide' } ref='code' - mode='GitHub Flavored Markdown' + mode='Boost Flavored Markdown' value={value} theme={config.editor.theme} keyMap={config.editor.keyMap} diff --git a/browser/components/MarkdownSplitEditor.js b/browser/components/MarkdownSplitEditor.js index 8fa3cc07..ce518a89 100644 --- a/browser/components/MarkdownSplitEditor.js +++ b/browser/components/MarkdownSplitEditor.js @@ -145,7 +145,7 @@ class MarkdownSplitEditor extends React.Component { styleName='codeEditor' ref='code' width={this.state.codeEditorWidthInPercent + '%'} - mode='GitHub Flavored Markdown' + mode='Boost Flavored Markdown' value={value} theme={config.editor.theme} keyMap={config.editor.keyMap} diff --git a/browser/lib/markdown-it-fence.js b/browser/lib/markdown-it-fence.js index 040ac540..983ed71e 100644 --- a/browser/lib/markdown-it-fence.js +++ b/browser/lib/markdown-it-fence.js @@ -1,6 +1,8 @@ 'use strict' module.exports = function (md, renderers, defaultRenderer) { + const paramsRE = /^[ \t]*([\w+#-]+)?(?:\(((?:\s*\w[-\w]*(?:=(?:'(?:.*?[^\\])?'|"(?:.*?[^\\])?"|(?:[^'"][^\s]*)))?)*)\))?(?::([^:]*)(?::(\d+))?)?\s*$/ + function fence (state, startLine, endLine) { let pos = state.bMarks[startLine] + state.tShift[startLine] let max = state.eMarks[startLine] @@ -66,7 +68,7 @@ module.exports = function (md, renderers, defaultRenderer) { let fileName = '' let firstLineNumber = 0 - let match = /^(\w[-\w]*)?(?:\(((?:\s*\w[-\w]*(?:=(?:'(?:.*?[^\\])?'|"(?:.*?[^\\])?"|(?:[^'"][^\s]*)))?)*)\))?(?::([^:]*)(?::(\d+))?)?\s*$/.exec(params) + let match = paramsRE.exec(params) if (match) { if (match[1]) { langType = match[1] diff --git a/extra_scripts/codemirror/mode/bfm/bfm.js b/extra_scripts/codemirror/mode/bfm/bfm.js new file mode 100644 index 00000000..21a1e25f --- /dev/null +++ b/extra_scripts/codemirror/mode/bfm/bfm.js @@ -0,0 +1,107 @@ +(function(mod) { + if (typeof exports == "object" && typeof module == "object") // CommonJS + mod(require("../codemirror/lib/codemirror"), require("../codemirror/mode/gfm/gfm"), require("../codemirror/mode/yaml-frontmatter/yaml-frontmatter")) + else if (typeof define == "function" && define.amd) // AMD + define(["../codemirror/lib/codemirror", "../codemirror/mode/gfm/gfm", "../codemirror/mode/yaml-frontmatter/yaml-frontmatter"], mod) + else // Plain browser env + mod(CodeMirror) +})(function(CodeMirror) { + 'use strict' + + const fencedCodeRE = /^(~~~+|```+)[ \t]*([\w+#-]+)?(?:\(((?:\s*\w[-\w]*(?:=(?:'(?:.*?[^\\])?'|"(?:.*?[^\\])?"|(?:[^'"][^\s]*)))?)*)\))?(?::([^:]*)(?::(\d+))?)?\s*$/ + + function getMode(name, params, config, cm) { + if (!name) { + return null + } + + const parameters = {} + if (params) { + const regex = /(\w[-\w]*)(?:=(?:'(.*?[^\\])?'|"(.*?[^\\])?"|([^'"][^\s]*)))?/g + + let match + while ((match = regex.exec(params))) { + parameters[match[1]] = match[2] || match[3] || match[4] || null + } + } + + if (name === 'chart') { + name = parameters.hasOwnProperty('yaml') ? 'yaml' : 'json' + } + + const found = CodeMirror.findModeByName(name) + if (!found) { + return null + } + + if (CodeMirror.modes.hasOwnProperty(found.mode)) { + const mode = CodeMirror.getMode(config, found.mode) + + return mode.name === 'null' ? null : mode + } else { + CodeMirror.requireMode(found.mode, () => { + cm.setOption('mode', cm.getOption('mode')) + }) + } + } + + CodeMirror.defineMode('bfm', function (config, baseConfig) { + var bfmOverlay = { + startState: function() { + return { + fencedEndRE: null + } + }, + copyState: function(s) { + return { + localMode: s.localMode, + localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null, + + fencedEndRE: s.fencedEndRE + } + }, + token: function(stream, state) { + state.combineTokens = false + + if (state.fencedEndRE && stream.match(state.fencedEndRE)) { + state.fencedEndRE = null + state.localMode = null + state.localState = null + + return null + } + + if (state.localMode) { + return state.localMode.token(stream, state.localState) || '' + } + + const match = stream.match(fencedCodeRE, true) + if (match) { + state.fencedEndRE = new RegExp(match[1] + '+ *$') + + state.localMode = getMode(match[2], match[3], config, stream.lineOracle.doc.cm) + if (state.localMode) { + state.localState = CodeMirror.startState(state.localMode) + } + + return null + } + + state.combineTokens = true + stream.next() + return null + }, + } + + baseConfig.name = 'yaml-frontmatter' + return CodeMirror.overlayMode(CodeMirror.getMode(config, baseConfig), bfmOverlay) + }, 'yaml-frontmatter') + + CodeMirror.defineMIME('text/x-bfm', 'bfm') + + CodeMirror.modeInfo.push({ + name: "Boost Flavored Markdown", + mime: "text/x-bfm", + mode: "bfm" + }) +}) \ No newline at end of file diff --git a/lib/main.html b/lib/main.html index 7366fa04..7a082f3a 100644 --- a/lib/main.html +++ b/lib/main.html @@ -93,8 +93,14 @@ + + + + + + From 44d6374cfe85def481045399f9ea4610bf37419d Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Fri, 14 Sep 2018 16:25:52 +0200 Subject: [PATCH 3/3] remove use of `overlayMode` to be able to detect YAML mode in `chart` code block --- extra_scripts/codemirror/mode/bfm/bfm.js | 63 +++++++++++++++++------- 1 file changed, 44 insertions(+), 19 deletions(-) diff --git a/extra_scripts/codemirror/mode/bfm/bfm.js b/extra_scripts/codemirror/mode/bfm/bfm.js index 21a1e25f..18eadffb 100644 --- a/extra_scripts/codemirror/mode/bfm/bfm.js +++ b/extra_scripts/codemirror/mode/bfm/bfm.js @@ -46,55 +46,80 @@ } CodeMirror.defineMode('bfm', function (config, baseConfig) { - var bfmOverlay = { + baseConfig.name = 'yaml-frontmatter' + const baseMode = CodeMirror.getMode(config, baseConfig) + + return { startState: function() { return { + baseState: CodeMirror.startState(baseMode), + fencedEndRE: null } }, copyState: function(s) { return { - localMode: s.localMode, - localState: s.localMode ? CodeMirror.copyState(s.localMode, s.localState) : null, + baseState: CodeMirror.copyState(baseMode, s.baseState), + + fencedMode: s.fencedMode, + fencedState: s.fencedMode ? CodeMirror.copyState(s.fencedMode, s.fencedState) : null, fencedEndRE: s.fencedEndRE } }, token: function(stream, state) { - state.combineTokens = false + const initialPos = stream.pos if (state.fencedEndRE && stream.match(state.fencedEndRE)) { state.fencedEndRE = null - state.localMode = null - state.localState = null + state.fencedMode = null + state.fencedState = null - return null + stream.pos = initialPos + return baseMode.token(stream, state.baseState) } - if (state.localMode) { - return state.localMode.token(stream, state.localState) || '' + if (state.fencedMode) { + return state.fencedMode.token(stream, state.fencedState) } const match = stream.match(fencedCodeRE, true) if (match) { state.fencedEndRE = new RegExp(match[1] + '+ *$') - state.localMode = getMode(match[2], match[3], config, stream.lineOracle.doc.cm) - if (state.localMode) { - state.localState = CodeMirror.startState(state.localMode) + state.fencedMode = getMode(match[2], match[3], config, stream.lineOracle.doc.cm) + if (state.fencedMode) { + state.fencedState = CodeMirror.startState(state.fencedMode) } - return null + stream.pos = initialPos + return baseMode.token(stream, state.baseState) } - state.combineTokens = true - stream.next() - return null + return baseMode.token(stream, state.baseState) }, + electricChars: baseMode.electricChars, + innerMode: function(state) { + if (state.fencedMode) { + return { + mode: state.fencedMode, + state: state.fencedState + } + } else { + return { + mode: baseMode, + state: state.baseState + } + } + }, + blankLine: function(state) { + if (state.fencedMode) { + return state.fencedMode.blankLine && state.fencedMode.blankLine(state.fencedState) + } else { + return baseMode.blankLine(state.baseState) + } + } } - - baseConfig.name = 'yaml-frontmatter' - return CodeMirror.overlayMode(CodeMirror.getMode(config, baseConfig), bfmOverlay) }, 'yaml-frontmatter') CodeMirror.defineMIME('text/x-bfm', 'bfm')