diff --git a/src/main/preferences/schema.json b/src/main/preferences/schema.json
index b3b1053d..dd5d3bbb 100644
--- a/src/main/preferences/schema.json
+++ b/src/main/preferences/schema.json
@@ -289,6 +289,11 @@
"type": "boolean",
"default": false
},
+ "isGitlabCompatibilityEnabled": {
+ "description": "Markdown-Enable GitLab compatibility mode.",
+ "type": "boolean",
+ "default": false
+ },
"sequenceTheme": {
"description": "Markdown--Sequence diagram theme",
"enum": [
diff --git a/src/muya/lib/config/index.js b/src/muya/lib/config/index.js
index 42d1359a..300c192a 100644
--- a/src/muya/lib/config/index.js
+++ b/src/muya/lib/config/index.js
@@ -282,7 +282,8 @@ export const MUYA_DEFAULT_OPTION = {
// Markdown extensions
superSubScript: false,
- footnote: false
+ footnote: false,
+ isGitlabCompatibilityEnabled: false
}
// export const DIAGRAM_TEMPLATE = {
diff --git a/src/muya/lib/contentState/codeBlockCtrl.js b/src/muya/lib/contentState/codeBlockCtrl.js
index 3cd6ae1e..078dbc2b 100644
--- a/src/muya/lib/contentState/codeBlockCtrl.js
+++ b/src/muya/lib/contentState/codeBlockCtrl.js
@@ -35,6 +35,9 @@ const codeBlockCtrl = ContentState => {
ContentState.prototype.selectLanguage = function (paragraph, lang) {
const block = this.getBlock(paragraph.id)
+ if (lang === 'math' && this.isGitlabCompatibilityEnabled && this.updateMathBlock(block)) {
+ return
+ }
this.updateCodeLanguage(block, lang)
}
diff --git a/src/muya/lib/contentState/containerCtrl.js b/src/muya/lib/contentState/containerCtrl.js
index eebf0bff..0b0973b3 100644
--- a/src/muya/lib/contentState/containerCtrl.js
+++ b/src/muya/lib/contentState/containerCtrl.js
@@ -8,11 +8,18 @@ const FUNCTION_TYPE_LANG = {
}
const containerCtrl = ContentState => {
- ContentState.prototype.createContainerBlock = function (functionType, value = '') {
+ ContentState.prototype.createContainerBlock = function (functionType, value = '', style = undefined) {
const figureBlock = this.createBlock('figure', {
functionType
})
+ if (functionType === 'multiplemath') {
+ if (style === undefined) {
+ figureBlock.mathStyle = this.isGitlabCompatibilityEnabled ? 'gitlab' : ''
+ }
+ figureBlock.mathStyle = style
+ }
+
const { preBlock, preview } = this.createPreAndPreview(functionType, value)
this.appendChild(figureBlock, preBlock)
this.appendChild(figureBlock, preview)
@@ -56,11 +63,18 @@ const containerCtrl = ContentState => {
return { preBlock, preview }
}
- ContentState.prototype.initContainerBlock = function (functionType, block) { // p block
+ ContentState.prototype.initContainerBlock = function (functionType, block, style = undefined) { // p block
block.type = 'figure'
block.functionType = functionType
block.children = []
+ if (functionType === 'multiplemath') {
+ if (style === undefined) {
+ block.mathStyle = this.isGitlabCompatibilityEnabled ? 'gitlab' : ''
+ }
+ block.mathStyle = style
+ }
+
const { preBlock, preview } = this.createPreAndPreview(functionType)
this.appendChild(block, preBlock)
@@ -84,11 +98,36 @@ const containerCtrl = ContentState => {
}
ContentState.prototype.updateMathBlock = function (block) {
- const { type } = block
- if (type !== 'p') return false
- const { text } = block.children[0]
const functionType = 'multiplemath'
- return text.trim() === '$$' ? this.initContainerBlock(functionType, block) : false
+ const { type } = block
+
+ // TODO(GitLab): Allow "functionType" 'languageInput' to convert an existing
+ // code block into math block.
+ if (type === 'span' && block.functionType === 'paragraphContent') {
+ const isMathBlock = !!block.text.match(/^`{3,}math\s*/)
+ if (isMathBlock) {
+ const result = this.initContainerBlock(functionType, block, 'gitlab')
+ if (result) {
+ // Set cursor at the first line
+ const { key } = result
+ const offset = 0
+ this.cursor = {
+ start: { key, offset },
+ end: { key, offset }
+ }
+
+ // Force render
+ this.partialRender()
+ return result
+ }
+ }
+ return false
+ } else if (type !== 'p') {
+ return false
+ }
+
+ const { text } = block.children[0]
+ return text.trim() === '$$' ? this.initContainerBlock(functionType, block, '') : false
}
}
diff --git a/src/muya/lib/contentState/copyCutCtrl.js b/src/muya/lib/contentState/copyCutCtrl.js
index 3769e93a..a467c4af 100644
--- a/src/muya/lib/contentState/copyCutCtrl.js
+++ b/src/muya/lib/contentState/copyCutCtrl.js
@@ -244,8 +244,8 @@ const copyCutCtrl = ContentState => {
const table = this.createTableInFigure({ rows: row, columns: column }, tableContents)
this.appendChild(figureBlock, table)
- const listIndentation = this.listIndentation
- const markdown = new ExportMarkdown([figureBlock], listIndentation).generate()
+ const { isGitlabCompatibilityEnabled, listIndentation } = this
+ const markdown = new ExportMarkdown([figureBlock], listIndentation, isGitlabCompatibilityEnabled).generate()
event.clipboardData.setData('text/html', '')
event.clipboardData.setData('text/plain', markdown)
@@ -281,7 +281,9 @@ const copyCutCtrl = ContentState => {
case 'copyAsHtml': {
event.clipboardData.setData('text/html', '')
event.clipboardData.setData('text/plain', getSanitizeHtml(text, {
- superSubScript: this.muya.options.superSubScript
+ superSubScript: this.muya.options.superSubScript,
+ footnote: this.muya.options.footnote,
+ isGitlabCompatibilityEnabled: this.muya.options.isGitlabCompatibilityEnabled
}))
break
}
@@ -290,8 +292,8 @@ const copyCutCtrl = ContentState => {
const block = typeof copyInfo === 'string' ? this.getBlock(copyInfo) : copyInfo
if (!block) return
const anchor = this.getAnchor(block)
- const listIndentation = this.listIndentation
- const markdown = new ExportMarkdown([anchor], listIndentation).generate()
+ const { isGitlabCompatibilityEnabled, listIndentation } = this
+ const markdown = new ExportMarkdown([anchor], listIndentation, isGitlabCompatibilityEnabled).generate()
event.clipboardData.setData('text/html', '')
event.clipboardData.setData('text/plain', markdown)
break
diff --git a/src/muya/lib/contentState/paragraphCtrl.js b/src/muya/lib/contentState/paragraphCtrl.js
index dcdb9dd3..099df5c7 100644
--- a/src/muya/lib/contentState/paragraphCtrl.js
+++ b/src/muya/lib/contentState/paragraphCtrl.js
@@ -321,8 +321,12 @@ const paragraphCtrl = ContentState => {
lang
})
- const listIndentation = this.listIndentation
- const markdown = new ExportMarkdown(children.slice(startIndex, endIndex + 1), listIndentation).generate()
+ const { isGitlabCompatibilityEnabled, listIndentation } = this
+ const markdown = new ExportMarkdown(
+ children.slice(startIndex, endIndex + 1),
+ listIndentation,
+ isGitlabCompatibilityEnabled
+ ).generate()
const codeContent = this.createBlock('span', {
text: markdown,
lang,
diff --git a/src/muya/lib/index.js b/src/muya/lib/index.js
index 57e4d2e1..5fb130ed 100644
--- a/src/muya/lib/index.js
+++ b/src/muya/lib/index.js
@@ -127,8 +127,8 @@ class Muya {
getMarkdown () {
const blocks = this.contentState.getBlocks()
- const listIndentation = this.contentState.listIndentation
- return new ExportMarkdown(blocks, listIndentation).generate()
+ const { isGitlabCompatibilityEnabled, listIndentation } = this.contentState
+ return new ExportMarkdown(blocks, listIndentation, isGitlabCompatibilityEnabled).generate()
}
getHistory () {
diff --git a/src/muya/lib/parser/marked/blockRules.js b/src/muya/lib/parser/marked/blockRules.js
index 99774b2b..a9a26333 100644
--- a/src/muya/lib/parser/marked/blockRules.js
+++ b/src/muya/lib/parser/marked/blockRules.js
@@ -36,6 +36,7 @@ export const block = {
// extra
frontmatter: /^(?:(?:---\n([\s\S]+?)---)|(?:\+\+\+\n([\s\S]+?)\+\+\+)|(?:;;;\n([\s\S]+?);;;)|(?:\{\n([\s\S]+?)\}))(?:\n{2,}|\n{1,2}$)/,
multiplemath: /^\$\$\n([\s\S]+?)\n\$\$(?:\n+|$)/,
+ multiplemathGitlab: /^ {0,3}(`{3,})math\n(?:(|[\s\S]*?)\n)(?: {0,3}\1`* *(?:\n+|$)|$)/, // Math inside a code block (GitLab display math)
footnote: /^\[\^([^\^\[\]\s]+?)\]:[\s\S]+?(?=\n *\n {0,3}[^ ]+|$)/
}
diff --git a/src/muya/lib/parser/marked/lexer.js b/src/muya/lib/parser/marked/lexer.js
index c1d535e9..928061e5 100644
--- a/src/muya/lib/parser/marked/lexer.js
+++ b/src/muya/lib/parser/marked/lexer.js
@@ -64,7 +64,12 @@ Lexer.prototype.lex = function (src) {
*/
Lexer.prototype.token = function (src, top) {
- const { frontMatter, math, footnote } = this.options
+ const {
+ footnote,
+ frontMatter,
+ isGitlabCompatibilityEnabled,
+ math
+ } = this.options
src = src.replace(/^ +$/gm, '')
let loose
@@ -149,10 +154,25 @@ Lexer.prototype.token = function (src, top) {
src = src.substring(cap[0].length)
this.tokens.push({
type: 'multiplemath',
- text: cap[1]
+ text: cap[1],
+ mathStyle: ''
})
continue
}
+
+ // match GitLab display math blocks (```math)
+ if (isGitlabCompatibilityEnabled) {
+ cap = this.rules.multiplemathGitlab.exec(src)
+ if (cap) {
+ src = src.substring(cap[0].length)
+ this.tokens.push({
+ type: 'multiplemath',
+ text: cap[2] || '',
+ mathStyle: 'gitlab'
+ })
+ continue
+ }
+ }
}
// footnote
diff --git a/src/muya/lib/parser/marked/options.js b/src/muya/lib/parser/marked/options.js
index 3d3a8158..4c1399cd 100644
--- a/src/muya/lib/parser/marked/options.js
+++ b/src/muya/lib/parser/marked/options.js
@@ -29,5 +29,6 @@ export default {
math: true,
frontMatter: true,
superSubScript: false,
- footnote: false
+ footnote: false,
+ isGitlabCompatibilityEnabled: false
}
diff --git a/src/muya/lib/prism/languages.json b/src/muya/lib/prism/languages.json
index fabb18d0..c88bd7f7 100644
--- a/src/muya/lib/prism/languages.json
+++ b/src/muya/lib/prism/languages.json
@@ -564,6 +564,9 @@
},
"latex": {
"title": "LaTeX",
+ "alias": [
+ "math"
+ ],
"ext": [
"text",
"ltx",
diff --git a/src/muya/lib/utils/exportHtml.js b/src/muya/lib/utils/exportHtml.js
index 230f3d00..01a25938 100644
--- a/src/muya/lib/utils/exportHtml.js
+++ b/src/muya/lib/utils/exportHtml.js
@@ -114,6 +114,7 @@ class ExportHtml {
let html = marked(this.markdown, {
superSubScript: this.muya ? this.muya.options.superSubScript : false,
footnote: this.muya ? this.muya.options.footnote : false,
+ isGitlabCompatibilityEnabled: this.muya ? this.muya.options.isGitlabCompatibilityEnabled : false,
highlight (code, lang) {
// Language may be undefined (GH#591)
if (!lang) {
diff --git a/src/muya/lib/utils/exportMarkdown.js b/src/muya/lib/utils/exportMarkdown.js
index da445398..f6e63b69 100644
--- a/src/muya/lib/utils/exportMarkdown.js
+++ b/src/muya/lib/utils/exportMarkdown.js
@@ -10,11 +10,12 @@
*/
class ExportMarkdown {
- constructor (blocks, listIndentation = 1) {
+ constructor (blocks, listIndentation = 1, isGitlabCompatibilityEnabled = false) {
this.blocks = blocks
this.listType = [] // 'ul' or 'ol'
// helper to translate the first tight item in a nested list
this.isLooseParentList = true
+ this.isGitlabCompatibilityEnabled = !!isGitlabCompatibilityEnabled
// set and validate settings
this.listIndentation = 'number'
@@ -229,12 +230,20 @@ class ExportMarkdown {
}
normalizeMultipleMath (block, /* figure */ indent) {
+ const { isGitlabCompatibilityEnabled } = this
+ let startToken = '$$'
+ let endToken = '$$'
+ if (isGitlabCompatibilityEnabled && block.mathStyle === 'gitlab') {
+ startToken = '```math'
+ endToken = '```'
+ }
+
const result = []
- result.push(`${indent}$$\n`)
+ result.push(`${indent}${startToken}\n`)
for (const line of block.children[0].children[0].children) {
result.push(`${indent}${line.text}\n`)
}
- result.push(`${indent}$$\n`)
+ result.push(`${indent}${endToken}\n`)
return result.join('')
}
diff --git a/src/muya/lib/utils/importMarkdown.js b/src/muya/lib/utils/importMarkdown.js
index bb632b75..254be199 100644
--- a/src/muya/lib/utils/importMarkdown.js
+++ b/src/muya/lib/utils/importMarkdown.js
@@ -77,9 +77,19 @@ const importRegister = ContentState => {
nextSibling: null,
children: []
}
+ const {
+ footnote,
+ isGitlabCompatibilityEnabled,
+ superSubScript,
+ trimUnnecessaryCodeBlockEmptyLines
+ } = this.muya.options
- const { trimUnnecessaryCodeBlockEmptyLines, footnote } = this.muya.options
- const tokens = new Lexer({ disableInline: true, footnote }).lex(markdown)
+ const tokens = new Lexer({
+ disableInline: true,
+ footnote,
+ isGitlabCompatibilityEnabled,
+ superSubScript
+ }).lex(markdown)
let token
let block
@@ -152,7 +162,7 @@ const importRegister = ContentState => {
case 'multiplemath': {
value = token.text
- block = this.createContainerBlock(token.type, value)
+ block = this.createContainerBlock(token.type, value, token.mathStyle)
this.appendChild(parentList[0], block)
break
}
@@ -457,8 +467,8 @@ const importRegister = ContentState => {
focusBlock.text = focusText.substring(0, focus.offset) + CURSOR_FOCUS_DNA + focusText.substring(focus.offset)
}
- const listIndentation = this.listIndentation
- const markdown = new ExportMarkdown(blocks, listIndentation).generate()
+ const { isGitlabCompatibilityEnabled, listIndentation } = this
+ const markdown = new ExportMarkdown(blocks, listIndentation, isGitlabCompatibilityEnabled).generate()
const cursor = markdown.split('\n').reduce((acc, line, index) => {
const ach = line.indexOf(CURSOR_ANCHOR_DNA)
const fch = line.indexOf(CURSOR_FOCUS_DNA)
diff --git a/src/renderer/components/editorWithTabs/editor.vue b/src/renderer/components/editorWithTabs/editor.vue
index 68d28ae0..18d17fd8 100644
--- a/src/renderer/components/editorWithTabs/editor.vue
+++ b/src/renderer/components/editorWithTabs/editor.vue
@@ -140,6 +140,7 @@ export default {
frontmatterType: state => state.preferences.frontmatterType,
superSubScript: state => state.preferences.superSubScript,
footnote: state => state.preferences.footnote,
+ isGitlabCompatibilityEnabled: state => state.preferences.isGitlabCompatibilityEnabled,
lineHeight: state => state.preferences.lineHeight,
fontSize: state => state.preferences.fontSize,
codeFontSize: state => state.preferences.codeFontSize,
@@ -284,6 +285,13 @@ export default {
}
},
+ isGitlabCompatibilityEnabled: function (value, oldValue) {
+ const { editor } = this
+ if (value !== oldValue && editor) {
+ editor.setOptions({ isGitlabCompatibilityEnabled: value }, true)
+ }
+ },
+
hideQuickInsertHint: function (value, oldValue) {
const { editor } = this
if (value !== oldValue && editor) {
@@ -517,6 +525,7 @@ export default {
frontmatterType,
superSubScript,
footnote,
+ isGitlabCompatibilityEnabled,
hideQuickInsertHint,
editorLineWidth,
theme,
@@ -564,6 +573,7 @@ export default {
frontmatterType,
superSubScript,
footnote,
+ isGitlabCompatibilityEnabled,
hideQuickInsertHint,
hideLinkPopup,
autoCheck,
diff --git a/src/renderer/prefComponents/markdown/index.vue b/src/renderer/prefComponents/markdown/index.vue
index 572bfbe1..cd810aef 100644
--- a/src/renderer/prefComponents/markdown/index.vue
+++ b/src/renderer/prefComponents/markdown/index.vue
@@ -61,6 +61,13 @@
more="https://pandoc.org/MANUAL.html#footnotes"
>