Skip to content

Commit

Permalink
Add GitLab math block support
Browse files Browse the repository at this point in the history
  • Loading branch information
fxha committed May 31, 2020
1 parent 6263d18 commit ad8ed0d
Show file tree
Hide file tree
Showing 18 changed files with 146 additions and 27 deletions.
5 changes: 5 additions & 0 deletions src/main/preferences/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": [
Expand Down
3 changes: 2 additions & 1 deletion src/muya/lib/config/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ export const MUYA_DEFAULT_OPTION = {

// Markdown extensions
superSubScript: false,
footnote: false
footnote: false,
isGitlabCompatibilityEnabled: false
}

// export const DIAGRAM_TEMPLATE = {
Expand Down
3 changes: 3 additions & 0 deletions src/muya/lib/contentState/codeBlockCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}

Expand Down
49 changes: 44 additions & 5 deletions src/muya/lib/contentState/containerCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand All @@ -84,11 +98,36 @@ const containerCtrl = ContentState => {
}

ContentState.prototype.updateMathBlock = function (block) {
const functionType = 'multiplemath'
const { type } = block
if (type !== 'p') return false

// 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]
const functionType = 'multiplemath'
return text.trim() === '$$' ? this.initContainerBlock(functionType, block) : false
return text.trim() === '$$' ? this.initContainerBlock(functionType, block, '') : false
}
}

Expand Down
12 changes: 7 additions & 5 deletions src/muya/lib/contentState/copyCutCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Expand All @@ -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
Expand Down
8 changes: 6 additions & 2 deletions src/muya/lib/contentState/paragraphCtrl.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/muya/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 () {
Expand Down
1 change: 1 addition & 0 deletions src/muya/lib/parser/marked/blockRules.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}[^ ]+|$)/
}

Expand Down
24 changes: 22 additions & 2 deletions src/muya/lib/parser/marked/lexer.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
}
}
}

if (footnote) {
Expand Down
3 changes: 2 additions & 1 deletion src/muya/lib/parser/marked/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ export default {
math: true,
frontMatter: true,
superSubScript: false,
footnote: false
footnote: false,
isGitlabCompatibilityEnabled: false
}
3 changes: 3 additions & 0 deletions src/muya/lib/prism/languages.json
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,9 @@
},
"latex": {
"title": "LaTeX",
"alias": [
"math"
],
"ext": [
"text",
"ltx",
Expand Down
1 change: 1 addition & 0 deletions src/muya/lib/utils/exportHtml.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
15 changes: 12 additions & 3 deletions src/muya/lib/utils/exportMarkdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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('')
}

Expand Down
22 changes: 16 additions & 6 deletions src/muya/lib/utils/importMarkdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,19 @@ const importRegister = ContentState => {
nextSibling: null,
children: []
}

const { trimUnnecessaryCodeBlockEmptyLines, footnote } = this.muya.options
const tokens = new Lexer({ disableInline: true, footnote }).lex(markdown)
const {
footnote,
isGitlabCompatibilityEnabled,
superSubScript,
trimUnnecessaryCodeBlockEmptyLines
} = this.muya.options

const tokens = new Lexer({
disableInline: true,
footnote,
isGitlabCompatibilityEnabled,
superSubScript
}).lex(markdown)

let token
let block
Expand Down Expand Up @@ -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
}
Expand Down Expand Up @@ -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)
Expand Down
10 changes: 10 additions & 0 deletions src/renderer/components/editorWithTabs/editor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -517,6 +525,7 @@ export default {
frontmatterType,
superSubScript,
footnote,
isGitlabCompatibilityEnabled,
hideQuickInsertHint,
editorLineWidth,
theme,
Expand Down Expand Up @@ -564,6 +573,7 @@ export default {
frontmatterType,
superSubScript,
footnote,
isGitlabCompatibilityEnabled,
hideQuickInsertHint,
hideLinkPopup,
autoCheck,
Expand Down
8 changes: 8 additions & 0 deletions src/renderer/prefComponents/markdown/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,13 @@
more="https://pandoc.org/MANUAL.html#footnotes"
></bool>
<separator></separator>
<h5>Compatibility</h5>
<bool
description="Enable GitLab compatibility mode."
:bool="isGitlabCompatibilityEnabled"
:onChange="value => onSelectChange('isGitlabCompatibilityEnabled', value)"
></bool>
<separator></separator>
<h5>Diagram theme</h5>
<cus-select
description="Sequence diagram theme"
Expand Down Expand Up @@ -114,6 +121,7 @@ export default {
frontmatterType: state => state.preferences.frontmatterType,
superSubScript: state => state.preferences.superSubScript,
footnote: state => state.preferences.footnote,
isGitlabCompatibilityEnabled: state => state.preferences.isGitlabCompatibilityEnabled,
sequenceTheme: state => state.preferences.sequenceTheme
})
},
Expand Down
1 change: 1 addition & 0 deletions src/renderer/store/preferences.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ const state = {
frontmatterType: '-',
superSubScript: false,
footnote: false,
isGitlabCompatibilityEnabled: false,
sequenceTheme: 'hand',

theme: 'light',
Expand Down

0 comments on commit ad8ed0d

Please sign in to comment.