mirror of
https://github.com/marktext/marktext.git
synced 2025-05-03 04:20:36 +08:00
Merge pull request #1572 from marktext/code-block-line-numbers
feat: add code block line numbers
This commit is contained in:
commit
dfc73900aa
@ -31,6 +31,7 @@ Preferences can be controlled and modified in the settings window or via the `pr
|
|||||||
| textDirection | String | ltr | The writing text direction, optional value: `ltr` or `rtl` |
|
| textDirection | String | ltr | The writing text direction, optional value: `ltr` or `rtl` |
|
||||||
| codeFontSize | Number | 14 | Font size on code block, the range is 12 ~ 28 |
|
| codeFontSize | Number | 14 | Font size on code block, the range is 12 ~ 28 |
|
||||||
| codeFontFamily | String | `DejaVu Sans Mono` | Code font family |
|
| codeFontFamily | String | `DejaVu Sans Mono` | Code font family |
|
||||||
|
| codeBlockLineNumbers | Boolean | true | Whether to show the line numbers in code block |
|
||||||
| trimUnnecessaryCodeBlockEmptyLines | Boolean | true | Whether to trim the beginning and end empty line in Code block |
|
| trimUnnecessaryCodeBlockEmptyLines | Boolean | true | Whether to trim the beginning and end empty line in Code block |
|
||||||
| hideQuickInsertHint | Boolean | false | Hide hint for quickly creating paragraphs |
|
| hideQuickInsertHint | Boolean | false | Hide hint for quickly creating paragraphs |
|
||||||
| imageDropAction | String | folder | The default behavior after paste or drag the image to Mark Text, upload it to the image cloud (if configured), move to the specified folder, insert the path |
|
| imageDropAction | String | folder | The default behavior after paste or drag the image to Mark Text, upload it to the image cloud (if configured), move to the specified folder, insert the path |
|
||||||
|
@ -94,6 +94,11 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"pattern": "^[_A-z0-9]+((-|\\s)*[_A-z0-9])*$"
|
"pattern": "^[_A-z0-9]+((-|\\s)*[_A-z0-9])*$"
|
||||||
},
|
},
|
||||||
|
"codeBlockLineNumbers": {
|
||||||
|
"description": "Editor--Whether to show the line numbers",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
"trimUnnecessaryCodeBlockEmptyLines": {
|
"trimUnnecessaryCodeBlockEmptyLines": {
|
||||||
"description": "Editor--Trim the beginning and ending empty lines in code block",
|
"description": "Editor--Trim the beginning and ending empty lines in code block",
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
@ -582,7 +582,7 @@ pre.ag-front-matter span.ag-code-content:first-of-type:empty::after {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pre[data-role$='code'] span.ag-language-input:empty::after {
|
pre[data-role$='code'] span.ag-language-input:empty::after {
|
||||||
content: 'Input Language...';
|
content: 'Input Language Identifier...';
|
||||||
color: var(--editorColor10);
|
color: var(--editorColor10);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -621,7 +621,7 @@ pre.ag-indent-code > code::before,
|
|||||||
pre.ag-fence-code > code::before {
|
pre.ag-fence-code > code::before {
|
||||||
content: '';
|
content: '';
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: -10px;
|
bottom: -1em;
|
||||||
right: -5px;
|
right: -5px;
|
||||||
color: var(--editorColor30);
|
color: var(--editorColor30);
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
@ -1157,6 +1157,97 @@ span.ag-reference-link {
|
|||||||
padding-right: 0;
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ag-code-copy {
|
||||||
|
position: absolute;
|
||||||
|
top: .5em;
|
||||||
|
right: .5em;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0;
|
||||||
|
z-index: 1;
|
||||||
|
transition: opacity .2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-active .ag-code-copy {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre:not(.ag-active):hover .ag-code-copy {
|
||||||
|
opacity: .5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-code-copy:hover {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-code-copy i.icon {
|
||||||
|
position: absolute;
|
||||||
|
top: 2px;
|
||||||
|
left: 2px;
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ag-code-copy i.icon > i[class^=icon-] {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
filter: drop-shadow(16px 0 var(--iconColor));
|
||||||
|
position: absolute;
|
||||||
|
left: -16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.ag-paragraph.line-numbers {
|
||||||
|
position: relative;
|
||||||
|
padding-left: 2.5em;
|
||||||
|
counter-reset: linenumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre.ag-paragraph.line-numbers > code {
|
||||||
|
position: relative;
|
||||||
|
white-space: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
figure:not(.ag-active) pre.ag-paragraph.line-numbers {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-numbers .line-numbers-rows {
|
||||||
|
position: absolute;
|
||||||
|
pointer-events: none;
|
||||||
|
top: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
left: -2.5em;
|
||||||
|
width: 2.5em; /* works for line-numbers below 1000 lines */
|
||||||
|
letter-spacing: -1px;
|
||||||
|
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-numbers-sizer {
|
||||||
|
white-space: pre-line;
|
||||||
|
word-break: break-all;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-numbers-rows > span {
|
||||||
|
pointer-events: none;
|
||||||
|
display: block;
|
||||||
|
counter-increment: linenumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
.line-numbers-rows > span:before {
|
||||||
|
content: counter(linenumber);
|
||||||
|
color: var(--editorColor30);
|
||||||
|
display: block;
|
||||||
|
padding-right: .8em;
|
||||||
|
text-align: right;
|
||||||
|
transform: scale(.8);
|
||||||
|
position: relative;
|
||||||
|
top: .05em;
|
||||||
|
}
|
||||||
|
|
||||||
.ag-inline-footnote-identifier {
|
.ag-inline-footnote-identifier {
|
||||||
background: var(--codeBlockBgColor);
|
background: var(--codeBlockBgColor);
|
||||||
padding: 0 0.4em;
|
padding: 0 0.4em;
|
||||||
|
@ -255,6 +255,7 @@ export const MUYA_DEFAULT_OPTION = {
|
|||||||
bulletListMarker: '-',
|
bulletListMarker: '-',
|
||||||
orderListDelimiter: '.',
|
orderListDelimiter: '.',
|
||||||
tabSize: 4,
|
tabSize: 4,
|
||||||
|
codeBlockLineNumbers: true,
|
||||||
// bullet/list marker width + listIndentation, tab or Daring Fireball Markdown (4 spaces) --> list indentation
|
// bullet/list marker width + listIndentation, tab or Daring Fireball Markdown (4 spaces) --> list indentation
|
||||||
listIndentation: 1,
|
listIndentation: 1,
|
||||||
frontmatterType: '-',
|
frontmatterType: '-',
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { loadLanguage } from '../prism/index'
|
import { loadLanguage } from '../prism/index'
|
||||||
|
import resizeCodeBlockLineNumber from '../utils/resizeCodeLineNumber'
|
||||||
import selection from '../selection'
|
import selection from '../selection'
|
||||||
|
|
||||||
const CODE_UPDATE_REP = /^`{3,}(.*)/
|
const CODE_UPDATE_REP = /^`{3,}(.*)/
|
||||||
@ -123,6 +124,32 @@ const codeBlockCtrl = ContentState => {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy the code block by click right-top copy icon in code block.
|
||||||
|
*/
|
||||||
|
ContentState.prototype.copyCodeBlock = function (event) {
|
||||||
|
const { target } = event
|
||||||
|
const preEle = target.closest('pre')
|
||||||
|
const preBlock = this.getBlock(preEle.id)
|
||||||
|
const codeBlock = preBlock.children.find(c => c.type === 'code')
|
||||||
|
const codeContent = codeBlock.children[0].text
|
||||||
|
this.muya.clipboard.copy('copyCodeContent', codeContent)
|
||||||
|
}
|
||||||
|
|
||||||
|
ContentState.prototype.resizeLineNumber = function () {
|
||||||
|
const { codeBlockLineNumbers } = this.muya.options
|
||||||
|
if (!codeBlockLineNumbers) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const codeBlocks = document.querySelectorAll('pre.line-numbers')
|
||||||
|
if (codeBlocks.length) {
|
||||||
|
for (const ele of codeBlocks) {
|
||||||
|
resizeCodeBlockLineNumber(ele)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default codeBlockCtrl
|
export default codeBlockCtrl
|
||||||
|
@ -47,6 +47,9 @@ const copyCutCtrl = ContentState => {
|
|||||||
|
|
||||||
ContentState.prototype.getClipBoradData = function () {
|
ContentState.prototype.getClipBoradData = function () {
|
||||||
const { start, end } = selection.getCursorRange()
|
const { start, end } = selection.getCursorRange()
|
||||||
|
if (!start || !end) {
|
||||||
|
return { html: '', text: '' }
|
||||||
|
}
|
||||||
if (start.key === end.key) {
|
if (start.key === end.key) {
|
||||||
const startBlock = this.getBlock(start.key)
|
const startBlock = this.getBlock(start.key)
|
||||||
const { type, text, functionType } = startBlock
|
const { type, text, functionType } = startBlock
|
||||||
@ -273,6 +276,15 @@ const copyCutCtrl = ContentState => {
|
|||||||
event.clipboardData.setData('text/plain', markdown)
|
event.clipboardData.setData('text/plain', markdown)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 'copyCodeContent': {
|
||||||
|
const codeContent = copyInfo
|
||||||
|
if (typeof codeContent !== 'string') {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
event.clipboardData.setData('text/html', '')
|
||||||
|
event.clipboardData.setData('text/plain', codeContent)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -205,7 +205,7 @@ class ContentState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
postRender () {
|
postRender () {
|
||||||
// do nothing.
|
this.resizeLineNumber()
|
||||||
}
|
}
|
||||||
|
|
||||||
render (isRenderCursor = true, clearCache = false) {
|
render (isRenderCursor = true, clearCache = false) {
|
||||||
|
@ -100,6 +100,7 @@ class ClickEvent {
|
|||||||
const mathRender = target.closest(`.${CLASS_OR_ID.AG_MATH_RENDER}`)
|
const mathRender = target.closest(`.${CLASS_OR_ID.AG_MATH_RENDER}`)
|
||||||
const rubyRender = target.closest(`.${CLASS_OR_ID.AG_RUBY_RENDER}`)
|
const rubyRender = target.closest(`.${CLASS_OR_ID.AG_RUBY_RENDER}`)
|
||||||
const imageWrapper = target.closest(`.${CLASS_OR_ID.AG_INLINE_IMAGE}`)
|
const imageWrapper = target.closest(`.${CLASS_OR_ID.AG_INLINE_IMAGE}`)
|
||||||
|
const codeCopy = target.closest('.ag-code-copy')
|
||||||
const footnoteBackLink = target.closest('.ag-footnote-backlink')
|
const footnoteBackLink = target.closest('.ag-footnote-backlink')
|
||||||
const imageDelete = target.closest('.ag-image-icon-delete') || target.closest('.ag-image-icon-close')
|
const imageDelete = target.closest('.ag-image-icon-delete') || target.closest('.ag-image-icon-close')
|
||||||
const mathText = mathRender && mathRender.previousElementSibling
|
const mathText = mathRender && mathRender.previousElementSibling
|
||||||
@ -116,6 +117,11 @@ class ClickEvent {
|
|||||||
} else if (rubyText) {
|
} else if (rubyText) {
|
||||||
selectionText(rubyText)
|
selectionText(rubyText)
|
||||||
}
|
}
|
||||||
|
if (codeCopy) {
|
||||||
|
event.stopPropagation()
|
||||||
|
event.preventDefault()
|
||||||
|
return this.muya.contentState.copyCodeBlock(event)
|
||||||
|
}
|
||||||
// Handle delete inline iamge by click delete icon.
|
// Handle delete inline iamge by click delete icon.
|
||||||
if (imageDelete && imageWrapper) {
|
if (imageDelete && imageWrapper) {
|
||||||
const imageInfo = getImageInfo(imageWrapper)
|
const imageInfo = getImageInfo(imageWrapper)
|
||||||
|
@ -60,10 +60,11 @@ class Clipboard {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Copy the anchor block(table, paragraph, math block etc) with the info
|
* Copy the anchor block(table, paragraph, math block etc) with the info
|
||||||
|
* @param {string|object} type copyBlock or copyCodeContent
|
||||||
* @param {string|object} info is the block key if it's string, or block if it's object
|
* @param {string|object} info is the block key if it's string, or block if it's object
|
||||||
*/
|
*/
|
||||||
copy (info) {
|
copy (type, info) {
|
||||||
this._copyType = 'copyBlock'
|
this._copyType = type
|
||||||
this._copyInfo = info
|
this._copyInfo = info
|
||||||
document.execCommand('copy')
|
document.execCommand('copy')
|
||||||
}
|
}
|
||||||
|
22
src/muya/lib/eventHandler/resize.js
Normal file
22
src/muya/lib/eventHandler/resize.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import resizeCodeBlockLineNumber from '../utils/resizeCodeLineNumber'
|
||||||
|
import { throttle } from '../utils'
|
||||||
|
|
||||||
|
class Resize {
|
||||||
|
constructor (muya) {
|
||||||
|
this.muya = muya
|
||||||
|
this.listen()
|
||||||
|
}
|
||||||
|
|
||||||
|
listen () {
|
||||||
|
window.addEventListener('resize', throttle(() => {
|
||||||
|
const codeBlocks = document.querySelectorAll('pre.line-numbers')
|
||||||
|
if (codeBlocks.length) {
|
||||||
|
for (const ele of codeBlocks) {
|
||||||
|
resizeCodeBlockLineNumber(ele)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 300))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Resize
|
@ -4,6 +4,7 @@ import MouseEvent from './eventHandler/mouseEvent'
|
|||||||
import Clipboard from './eventHandler/clipboard'
|
import Clipboard from './eventHandler/clipboard'
|
||||||
import Keyboard from './eventHandler/keyboard'
|
import Keyboard from './eventHandler/keyboard'
|
||||||
import DragDrop from './eventHandler/dragDrop'
|
import DragDrop from './eventHandler/dragDrop'
|
||||||
|
import Resize from './eventHandler/resize'
|
||||||
import ClickEvent from './eventHandler/clickEvent'
|
import ClickEvent from './eventHandler/clickEvent'
|
||||||
import { CLASS_OR_ID, MUYA_DEFAULT_OPTION } from './config'
|
import { CLASS_OR_ID, MUYA_DEFAULT_OPTION } from './config'
|
||||||
import { wordCount } from './utils'
|
import { wordCount } from './utils'
|
||||||
@ -41,6 +42,7 @@ class Muya {
|
|||||||
this.clickEvent = new ClickEvent(this)
|
this.clickEvent = new ClickEvent(this)
|
||||||
this.keyboard = new Keyboard(this)
|
this.keyboard = new Keyboard(this)
|
||||||
this.dragdrop = new DragDrop(this)
|
this.dragdrop = new DragDrop(this)
|
||||||
|
this.resize = new Resize(this)
|
||||||
this.mouseEvent = new MouseEvent(this)
|
this.mouseEvent = new MouseEvent(this)
|
||||||
this.init()
|
this.init()
|
||||||
}
|
}
|
||||||
@ -362,7 +364,7 @@ class Muya {
|
|||||||
* @param {string|object} key the block key or block
|
* @param {string|object} key the block key or block
|
||||||
*/
|
*/
|
||||||
copy (info) {
|
copy (info) {
|
||||||
return this.clipboard.copy(info)
|
return this.clipboard.copy('copyBlock', info)
|
||||||
}
|
}
|
||||||
|
|
||||||
setOptions (options, needRender = false) {
|
setOptions (options, needRender = false) {
|
||||||
|
@ -2,6 +2,8 @@ import { CLASS_OR_ID } from '../../../config'
|
|||||||
import { renderTableTools } from './renderToolBar'
|
import { renderTableTools } from './renderToolBar'
|
||||||
import { footnoteJumpIcon } from './renderFootnoteJump'
|
import { footnoteJumpIcon } from './renderFootnoteJump'
|
||||||
import { renderEditIcon } from './renderContainerEditIcon'
|
import { renderEditIcon } from './renderContainerEditIcon'
|
||||||
|
import renderLineNumberRows from './renderLineNumber'
|
||||||
|
import renderCopyButton from './renderCopyButton'
|
||||||
import { renderLeftBar, renderBottomBar } from './renderTableDargBar'
|
import { renderLeftBar, renderBottomBar } from './renderTableDargBar'
|
||||||
import { h } from '../snabbdom'
|
import { h } from '../snabbdom'
|
||||||
|
|
||||||
@ -46,8 +48,20 @@ export default function renderContainerBlock (parent, block, activeBlocks, match
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (/code|pre/.test(type) && typeof lang === 'string' && !!lang) {
|
if (/code|pre/.test(type)) {
|
||||||
selector += `.language-${lang.replace(/[#.]{1}/g, '')}`
|
if (typeof lang === 'string' && !!lang) {
|
||||||
|
selector += `.language-${lang.replace(/[#.]{1}/g, '')}`
|
||||||
|
}
|
||||||
|
if (type === 'pre') {
|
||||||
|
children.unshift(renderCopyButton())
|
||||||
|
}
|
||||||
|
if (this.muya.options.codeBlockLineNumbers) {
|
||||||
|
if (type === 'pre') {
|
||||||
|
selector += '.line-numbers'
|
||||||
|
} else {
|
||||||
|
children.unshift(renderLineNumberRows(block.children[0]))
|
||||||
|
}
|
||||||
|
}
|
||||||
Object.assign(data.attrs, { spellcheck: 'false' })
|
Object.assign(data.attrs, { spellcheck: 'false' })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
21
src/muya/lib/parser/render/renderBlock/renderCopyButton.js
Normal file
21
src/muya/lib/parser/render/renderBlock/renderCopyButton.js
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { h } from '../snabbdom'
|
||||||
|
import copyIcon from '../../../assets/pngicon/copy/2.png'
|
||||||
|
|
||||||
|
const renderCopyButton = () => {
|
||||||
|
const selector = 'a.ag-code-copy'
|
||||||
|
const iconVnode = h('i.icon', h('i.icon-inner', {
|
||||||
|
style: {
|
||||||
|
background: `url(${copyIcon}) no-repeat`,
|
||||||
|
'background-size': '100%'
|
||||||
|
}
|
||||||
|
}, ''))
|
||||||
|
|
||||||
|
return h(selector, {
|
||||||
|
attrs: {
|
||||||
|
title: 'Copy content',
|
||||||
|
contenteditable: 'false'
|
||||||
|
}
|
||||||
|
}, iconVnode)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default renderCopyButton
|
22
src/muya/lib/parser/render/renderBlock/renderLineNumber.js
Normal file
22
src/muya/lib/parser/render/renderBlock/renderLineNumber.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
import { h } from '../snabbdom'
|
||||||
|
|
||||||
|
const NEW_LINE_EXP = /\n(?!$)/g
|
||||||
|
|
||||||
|
const renderLineNumberRows = codeContent => {
|
||||||
|
const { text } = codeContent
|
||||||
|
const match = text.match(NEW_LINE_EXP)
|
||||||
|
let linesNum = match ? match.length + 1 : 1
|
||||||
|
if (text.endsWith('\n')) {
|
||||||
|
linesNum++
|
||||||
|
}
|
||||||
|
const data = {
|
||||||
|
attrs: {
|
||||||
|
'aria-hidden': true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const children = [...new Array(linesNum)].map(() => h('span'))
|
||||||
|
|
||||||
|
return h('span.line-numbers-rows', data, children)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default renderLineNumberRows
|
57
src/muya/lib/utils/resizeCodeLineNumber.js
Normal file
57
src/muya/lib/utils/resizeCodeLineNumber.js
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
/**
|
||||||
|
* This file copy from prismjs/plugins/prism-line-number
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Regular expression used for determining line breaks
|
||||||
|
* @type {RegExp}
|
||||||
|
*/
|
||||||
|
const NEW_LINE_EXP = /\n(?!$)/g
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns style declarations for the element
|
||||||
|
* @param {Element} element
|
||||||
|
*/
|
||||||
|
const getStyles = function (element) {
|
||||||
|
if (!element) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return window.getComputedStyle ? getComputedStyle(element) : (element.currentStyle || null)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resizes line numbers spans according to height of line of code
|
||||||
|
* @param {Element} element <pre> element
|
||||||
|
*/
|
||||||
|
const resizeCodeBlockLineNumber = function (element) {
|
||||||
|
const codeStyles = getStyles(element)
|
||||||
|
const whiteSpace = codeStyles['white-space']
|
||||||
|
|
||||||
|
if (whiteSpace === 'pre' || whiteSpace === 'pre-wrap' || whiteSpace === 'pre-line') {
|
||||||
|
const codeElement = element.querySelector('code')
|
||||||
|
const lineNumbersWrapper = element.querySelector('.line-numbers-rows')
|
||||||
|
let lineNumberSizer = element.querySelector('.line-numbers-sizer')
|
||||||
|
const codeLines = codeElement.textContent.split(NEW_LINE_EXP)
|
||||||
|
|
||||||
|
if (!lineNumberSizer) {
|
||||||
|
lineNumberSizer = document.createElement('span')
|
||||||
|
lineNumberSizer.className = 'line-numbers-sizer'
|
||||||
|
|
||||||
|
codeElement.appendChild(lineNumberSizer)
|
||||||
|
}
|
||||||
|
|
||||||
|
lineNumberSizer.style.display = 'block'
|
||||||
|
|
||||||
|
codeLines.forEach(function (line, lineNumber) {
|
||||||
|
lineNumberSizer.textContent = line || '\n'
|
||||||
|
const lineSize = lineNumberSizer.getBoundingClientRect().height
|
||||||
|
lineNumbersWrapper.children[lineNumber].style.height = lineSize + 'px'
|
||||||
|
})
|
||||||
|
|
||||||
|
lineNumberSizer.textContent = ''
|
||||||
|
lineNumberSizer.style.display = 'none'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default resizeCodeBlockLineNumber
|
@ -142,6 +142,7 @@ export default {
|
|||||||
fontSize: state => state.preferences.fontSize,
|
fontSize: state => state.preferences.fontSize,
|
||||||
codeFontSize: state => state.preferences.codeFontSize,
|
codeFontSize: state => state.preferences.codeFontSize,
|
||||||
codeFontFamily: state => state.preferences.codeFontFamily,
|
codeFontFamily: state => state.preferences.codeFontFamily,
|
||||||
|
codeBlockLineNumbers: state => state.preferences.codeBlockLineNumbers,
|
||||||
trimUnnecessaryCodeBlockEmptyLines: state => state.preferences.trimUnnecessaryCodeBlockEmptyLines,
|
trimUnnecessaryCodeBlockEmptyLines: state => state.preferences.trimUnnecessaryCodeBlockEmptyLines,
|
||||||
editorFontFamily: state => state.preferences.editorFontFamily,
|
editorFontFamily: state => state.preferences.editorFontFamily,
|
||||||
hideQuickInsertHint: state => state.preferences.hideQuickInsertHint,
|
hideQuickInsertHint: state => state.preferences.hideQuickInsertHint,
|
||||||
@ -320,6 +321,12 @@ export default {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
codeBlockLineNumbers: function (value, oldValue) {
|
||||||
|
const { editor } = this
|
||||||
|
if (value !== oldValue && editor) {
|
||||||
|
editor.setOptions({ codeBlockLineNumbers: value }, true)
|
||||||
|
}
|
||||||
|
},
|
||||||
codeFontFamily: function (value, oldValue) {
|
codeFontFamily: function (value, oldValue) {
|
||||||
if (value !== oldValue) {
|
if (value !== oldValue) {
|
||||||
addCommonStyle({
|
addCommonStyle({
|
||||||
@ -451,6 +458,7 @@ export default {
|
|||||||
tabSize,
|
tabSize,
|
||||||
fontSize,
|
fontSize,
|
||||||
lineHeight,
|
lineHeight,
|
||||||
|
codeBlockLineNumbers,
|
||||||
listIndentation,
|
listIndentation,
|
||||||
frontmatterType,
|
frontmatterType,
|
||||||
superSubScript,
|
superSubScript,
|
||||||
@ -495,6 +503,7 @@ export default {
|
|||||||
tabSize,
|
tabSize,
|
||||||
fontSize,
|
fontSize,
|
||||||
lineHeight,
|
lineHeight,
|
||||||
|
codeBlockLineNumbers,
|
||||||
listIndentation,
|
listIndentation,
|
||||||
frontmatterType,
|
frontmatterType,
|
||||||
superSubScript,
|
superSubScript,
|
||||||
|
@ -39,6 +39,11 @@
|
|||||||
:value="codeFontFamily"
|
:value="codeFontFamily"
|
||||||
:onChange="value => onSelectChange('codeFontFamily', value)"
|
:onChange="value => onSelectChange('codeFontFamily', value)"
|
||||||
></font-text-box>
|
></font-text-box>
|
||||||
|
<bool
|
||||||
|
description="Whether to show the code block line numbers."
|
||||||
|
:bool="codeBlockLineNumbers"
|
||||||
|
:onChange="value => onSelectChange('codeBlockLineNumbers', value)"
|
||||||
|
></bool>
|
||||||
<bool
|
<bool
|
||||||
description="Trim the beginning and ending empty lines in code block when open markdown."
|
description="Trim the beginning and ending empty lines in code block when open markdown."
|
||||||
:bool="trimUnnecessaryCodeBlockEmptyLines"
|
:bool="trimUnnecessaryCodeBlockEmptyLines"
|
||||||
@ -148,6 +153,7 @@ export default {
|
|||||||
textDirection: state => state.preferences.textDirection,
|
textDirection: state => state.preferences.textDirection,
|
||||||
codeFontSize: state => state.preferences.codeFontSize,
|
codeFontSize: state => state.preferences.codeFontSize,
|
||||||
codeFontFamily: state => state.preferences.codeFontFamily,
|
codeFontFamily: state => state.preferences.codeFontFamily,
|
||||||
|
codeBlockLineNumbers: state => state.preferences.codeBlockLineNumbers,
|
||||||
trimUnnecessaryCodeBlockEmptyLines: state => state.preferences.trimUnnecessaryCodeBlockEmptyLines,
|
trimUnnecessaryCodeBlockEmptyLines: state => state.preferences.trimUnnecessaryCodeBlockEmptyLines,
|
||||||
hideQuickInsertHint: state => state.preferences.hideQuickInsertHint,
|
hideQuickInsertHint: state => state.preferences.hideQuickInsertHint,
|
||||||
hideLinkPopup: state => state.preferences.hideLinkPopup,
|
hideLinkPopup: state => state.preferences.hideLinkPopup,
|
||||||
|
@ -20,6 +20,7 @@ const state = {
|
|||||||
lineHeight: 1.6,
|
lineHeight: 1.6,
|
||||||
codeFontSize: 14,
|
codeFontSize: 14,
|
||||||
codeFontFamily: 'DejaVu Sans Mono',
|
codeFontFamily: 'DejaVu Sans Mono',
|
||||||
|
codeBlockLineNumbers: true,
|
||||||
trimUnnecessaryCodeBlockEmptyLines: true,
|
trimUnnecessaryCodeBlockEmptyLines: true,
|
||||||
editorLineWidth: '',
|
editorLineWidth: '',
|
||||||
|
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
"lineHeight": 1.6,
|
"lineHeight": 1.6,
|
||||||
"codeFontSize": 14,
|
"codeFontSize": 14,
|
||||||
"codeFontFamily": "DejaVu Sans Mono",
|
"codeFontFamily": "DejaVu Sans Mono",
|
||||||
|
"codeBlockLineNumbers": true,
|
||||||
"trimUnnecessaryCodeBlockEmptyLines": true,
|
"trimUnnecessaryCodeBlockEmptyLines": true,
|
||||||
"editorLineWidth": "",
|
"editorLineWidth": "",
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user