Skip to content

Commit 56192f0

Browse files
authored
Merge pull request #3034 from AWolf81/enable-markdownlint-option
Enable Markdown lint option
2 parents aa4d06f + 63eb858 commit 56192f0

File tree

9 files changed

+154
-48
lines changed

9 files changed

+154
-48
lines changed

browser/components/CodeEditor.js

Lines changed: 79 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import {languageMaps} from '../lib/CMLanguageList'
2626
import snippetManager from '../lib/SnippetManager'
2727
import {generateInEditor, tocExistsInEditor} from 'browser/lib/markdown-toc-generator'
2828
import markdownlint from 'markdownlint'
29+
import Jsonlint from 'jsonlint-mod'
30+
import { DEFAULT_CONFIG } from '../main/lib/ConfigManager'
2931

3032
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
3133

@@ -38,38 +40,6 @@ function translateHotkey (hotkey) {
3840
return hotkey.replace(/\s*\+\s*/g, '-').replace(/Command/g, 'Cmd').replace(/Control/g, 'Ctrl')
3941
}
4042

41-
const validatorOfMarkdown = (text, updateLinting) => {
42-
const lintOptions = {
43-
'strings': {
44-
'content': text
45-
}
46-
}
47-
48-
return markdownlint(lintOptions, (err, result) => {
49-
if (!err) {
50-
const foundIssues = []
51-
result.content.map(item => {
52-
let ruleNames = ''
53-
item.ruleNames.map((ruleName, index) => {
54-
ruleNames += ruleName
55-
if (index === item.ruleNames.length - 1) {
56-
ruleNames += ': '
57-
} else {
58-
ruleNames += '/'
59-
}
60-
})
61-
foundIssues.push({
62-
from: CodeMirror.Pos(item.lineNumber, 0),
63-
to: CodeMirror.Pos(item.lineNumber, 1),
64-
message: ruleNames + item.ruleDescription,
65-
severity: 'warning'
66-
})
67-
})
68-
updateLinting(foundIssues)
69-
}
70-
})
71-
}
72-
7343
export default class CodeEditor extends React.Component {
7444
constructor (props) {
7545
super(props)
@@ -116,6 +86,8 @@ export default class CodeEditor extends React.Component {
11686
this.searchHandler = (e, msg) => this.handleSearch(msg)
11787
this.searchState = null
11888
this.scrollToLineHandeler = this.scrollToLine.bind(this)
89+
this.getCodeEditorLintConfig = this.getCodeEditorLintConfig.bind(this)
90+
this.validatorOfMarkdown = this.validatorOfMarkdown.bind(this)
11991

12092
this.formatTable = () => this.handleFormatTable()
12193

@@ -283,13 +255,12 @@ export default class CodeEditor extends React.Component {
283255
}
284256

285257
componentDidMount () {
286-
const { rulers, enableRulers } = this.props
258+
const { rulers, enableRulers, enableMarkdownLint } = this.props
287259
eventEmitter.on('line:jump', this.scrollToLineHandeler)
288260

289261
snippetManager.init()
290262
this.updateDefaultKeyMap()
291263

292-
const checkMarkdownNoteIsOpening = this.props.mode === 'Boost Flavored Markdown'
293264
this.value = this.props.value
294265
this.editor = CodeMirror(this.refs.root, {
295266
rulers: buildCMRulers(rulers, enableRulers),
@@ -306,10 +277,7 @@ export default class CodeEditor extends React.Component {
306277
inputStyle: 'textarea',
307278
dragDrop: false,
308279
foldGutter: true,
309-
lint: checkMarkdownNoteIsOpening ? {
310-
'getAnnotations': validatorOfMarkdown,
311-
'async': true
312-
} : false,
280+
lint: enableMarkdownLint ? this.getCodeEditorLintConfig() : false,
313281
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers'],
314282
autoCloseBrackets: {
315283
pairs: this.props.matchingPairs,
@@ -320,6 +288,8 @@ export default class CodeEditor extends React.Component {
320288
extraKeys: this.defaultKeyMap
321289
})
322290

291+
document.querySelector('.CodeMirror-lint-markers').style.display = enableMarkdownLint ? 'inline-block' : 'none'
292+
323293
if (!this.props.mode && this.props.value && this.props.autoDetect) {
324294
this.autoDetectLanguage(this.props.value)
325295
} else {
@@ -546,7 +516,9 @@ export default class CodeEditor extends React.Component {
546516
let needRefresh = false
547517
const {
548518
rulers,
549-
enableRulers
519+
enableRulers,
520+
enableMarkdownLint,
521+
customMarkdownLintConfig
550522
} = this.props
551523
if (prevProps.mode !== this.props.mode) {
552524
this.setMode(this.props.mode)
@@ -564,6 +536,16 @@ export default class CodeEditor extends React.Component {
564536
if (prevProps.keyMap !== this.props.keyMap) {
565537
needRefresh = true
566538
}
539+
if (prevProps.enableMarkdownLint !== enableMarkdownLint || prevProps.customMarkdownLintConfig !== customMarkdownLintConfig) {
540+
if (!enableMarkdownLint) {
541+
this.editor.setOption('lint', {default: false})
542+
document.querySelector('.CodeMirror-lint-markers').style.display = 'none'
543+
} else {
544+
this.editor.setOption('lint', this.getCodeEditorLintConfig())
545+
document.querySelector('.CodeMirror-lint-markers').style.display = 'inline-block'
546+
}
547+
needRefresh = true
548+
}
567549

568550
if (
569551
prevProps.enableRulers !== enableRulers ||
@@ -644,6 +626,56 @@ export default class CodeEditor extends React.Component {
644626
}
645627
}
646628

629+
getCodeEditorLintConfig () {
630+
const { mode } = this.props
631+
const checkMarkdownNoteIsOpen = mode === 'Boost Flavored Markdown'
632+
633+
return checkMarkdownNoteIsOpen ? {
634+
'getAnnotations': this.validatorOfMarkdown,
635+
'async': true
636+
} : false
637+
}
638+
639+
validatorOfMarkdown (text, updateLinting) {
640+
const { customMarkdownLintConfig } = this.props
641+
let lintConfigJson
642+
try {
643+
Jsonlint.parse(customMarkdownLintConfig)
644+
lintConfigJson = JSON.parse(customMarkdownLintConfig)
645+
} catch (err) {
646+
eventEmitter.emit('APP_SETTING_ERROR')
647+
return
648+
}
649+
const lintOptions = {
650+
'strings': {
651+
'content': text
652+
},
653+
'config': lintConfigJson
654+
}
655+
656+
return markdownlint(lintOptions, (err, result) => {
657+
if (!err) {
658+
const foundIssues = []
659+
const splitText = text.split('\n')
660+
result.content.map(item => {
661+
let ruleNames = ''
662+
item.ruleNames.map((ruleName, index) => {
663+
ruleNames += ruleName
664+
ruleNames += (index === item.ruleNames.length - 1) ? ': ' : '/'
665+
})
666+
const lineNumber = item.lineNumber - 1
667+
foundIssues.push({
668+
from: CodeMirror.Pos(lineNumber, 0),
669+
to: CodeMirror.Pos(lineNumber, splitText[lineNumber].length),
670+
message: ruleNames + item.ruleDescription,
671+
severity: 'warning'
672+
})
673+
})
674+
updateLinting(foundIssues)
675+
}
676+
})
677+
}
678+
647679
setMode (mode) {
648680
let syntax = CodeMirror.findModeByName(convertModeName(mode || 'text'))
649681
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
@@ -1105,13 +1137,11 @@ export default class CodeEditor extends React.Component {
11051137
}
11061138
ref='root'
11071139
tabIndex='-1'
1108-
style={
1109-
{
1140+
style={{
11101141
fontFamily,
11111142
fontSize: fontSize,
11121143
width: width
1113-
}
1114-
}
1144+
}}
11151145
onDrop={
11161146
e => this.handleDropImage(e)
11171147
}
@@ -1149,7 +1179,9 @@ CodeEditor.propTypes = {
11491179
onChange: PropTypes.func,
11501180
readOnly: PropTypes.bool,
11511181
autoDetect: PropTypes.bool,
1152-
spellCheck: PropTypes.bool
1182+
spellCheck: PropTypes.bool,
1183+
enableMarkdownLint: PropTypes.bool,
1184+
customMarkdownLintConfig: PropTypes.string
11531185
}
11541186

11551187
CodeEditor.defaultProps = {
@@ -1161,5 +1193,7 @@ CodeEditor.defaultProps = {
11611193
indentSize: 4,
11621194
indentType: 'space',
11631195
autoDetect: false,
1164-
spellCheck: false
1196+
spellCheck: false,
1197+
enableMarkdownLint: DEFAULT_CONFIG.editor.enableMarkdownLint,
1198+
customMarkdownLintConfig: DEFAULT_CONFIG.editor.customMarkdownLintConfig
11651199
}

browser/components/MarkdownEditor.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,8 @@ class MarkdownEditor extends React.Component {
319319
enableSmartPaste={config.editor.enableSmartPaste}
320320
hotkey={config.hotkey}
321321
switchPreview={config.editor.switchPreview}
322+
enableMarkdownLint={config.editor.enableMarkdownLint}
323+
customMarkdownLintConfig={config.editor.customMarkdownLintConfig}
322324
/>
323325
<MarkdownPreview styleName={this.state.status === 'PREVIEW'
324326
? 'preview'

browser/components/MarkdownSplitEditor.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,8 @@ class MarkdownSplitEditor extends React.Component {
179179
enableSmartPaste={config.editor.enableSmartPaste}
180180
hotkey={config.hotkey}
181181
switchPreview={config.editor.switchPreview}
182+
enableMarkdownLint={config.editor.enableMarkdownLint}
183+
customMarkdownLintConfig={config.editor.customMarkdownLintConfig}
182184
/>
183185
<div styleName='slider' style={{left: this.state.codeEditorWidthInPercent + '%'}} onMouseDown={e => this.handleMouseDown(e)} >
184186
<div styleName='slider-hitbox' />

browser/main/lib/ConfigManager.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ const consts = require('browser/lib/consts')
1111

1212
let isInitialized = false
1313

14+
const DEFAULT_MARKDOWN_LINT_CONFIG = `{
15+
"default": true
16+
}`
17+
1418
export const DEFAULT_CONFIG = {
1519
zoom: 1,
1620
isSideNavFolded: false,
@@ -59,7 +63,9 @@ export const DEFAULT_CONFIG = {
5963
enableFrontMatterTitle: true,
6064
frontMatterTitleField: 'title',
6165
spellcheck: false,
62-
enableSmartPaste: false
66+
enableSmartPaste: false,
67+
enableMarkdownLint: false,
68+
customMarkdownLintConfig: DEFAULT_MARKDOWN_LINT_CONFIG
6369
},
6470
preview: {
6571
fontSize: '14',

browser/main/modals/PreferencesModal/UiTab.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ class UiTab extends React.Component {
3030
componentDidMount () {
3131
CodeMirror.autoLoadMode(this.codeMirrorInstance.getCodeMirror(), 'javascript')
3232
CodeMirror.autoLoadMode(this.customCSSCM.getCodeMirror(), 'css')
33+
CodeMirror.autoLoadMode(this.customMarkdownLintConfigCM.getCodeMirror(), 'javascript')
3334
this.customCSSCM.getCodeMirror().setSize('400px', '400px')
35+
this.customMarkdownLintConfigCM.getCodeMirror().setSize('400px', '200px')
3436
this.handleSettingDone = () => {
3537
this.setState({UiAlert: {
3638
type: 'success',
@@ -101,7 +103,9 @@ class UiTab extends React.Component {
101103
matchingTriples: this.refs.matchingTriples.value,
102104
explodingPairs: this.refs.explodingPairs.value,
103105
spellcheck: this.refs.spellcheck.checked,
104-
enableSmartPaste: this.refs.enableSmartPaste.checked
106+
enableSmartPaste: this.refs.enableSmartPaste.checked,
107+
enableMarkdownLint: this.refs.enableMarkdownLint.checked,
108+
customMarkdownLintConfig: this.customMarkdownLintConfigCM.getCodeMirror().getValue()
105109
},
106110
preview: {
107111
fontSize: this.refs.previewFontSize.value,
@@ -637,6 +641,34 @@ class UiTab extends React.Component {
637641
/>
638642
</div>
639643
</div>
644+
<div styleName='group-section'>
645+
<div styleName='group-section-label'>
646+
{i18n.__('Custom MarkdownLint Rules')}
647+
</div>
648+
<div styleName='group-section-control'>
649+
<input onChange={(e) => this.handleUIChange(e)}
650+
checked={this.state.config.editor.enableMarkdownLint}
651+
ref='enableMarkdownLint'
652+
type='checkbox'
653+
/>&nbsp;
654+
{i18n.__('Enable MarkdownLint')}
655+
<div style={{fontFamily, display: this.state.config.editor.enableMarkdownLint ? 'block' : 'none'}}>
656+
<ReactCodeMirror
657+
width='400px'
658+
height='200px'
659+
onChange={e => this.handleUIChange(e)}
660+
ref={e => (this.customMarkdownLintConfigCM = e)}
661+
value={config.editor.customMarkdownLintConfig}
662+
options={{
663+
lineNumbers: true,
664+
mode: 'application/json',
665+
theme: codemirrorTheme,
666+
lint: true,
667+
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter', 'CodeMirror-lint-markers']
668+
}} />
669+
</div>
670+
</div>
671+
</div>
640672

641673
<div styleName='group-header2'>{i18n.__('Preview')}</div>
642674
<div styleName='group-section'>

lib/main.html

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,10 @@
7272
border-left-color: rgba(142, 142, 142, 0.5);
7373
mix-blend-mode: difference;
7474
}
75+
76+
.CodeMirror-lint-tooltip {
77+
z-index: 1003;
78+
}
7579
</style>
7680
</head>
7781

@@ -126,7 +130,9 @@
126130
<script src="../node_modules/codemirror/addon/dialog/dialog.js"></script>
127131
<script src="../node_modules/codemirror/addon/display/rulers.js"></script>
128132

133+
<script src="../node_modules/jsonlint-mod/lib/jsonlint.js"></script>
129134
<script src="../node_modules/codemirror/addon/lint/lint.js"></script>
135+
<script src="../node_modules/codemirror/addon/lint/json-lint.js"></script>
130136

131137
<script src="../node_modules/raphael/raphael.min.js"></script>
132138
<script src="../node_modules/flowchart.js/release/flowchart.min.js"></script>

locales/ja.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
"Matching character pairs": "自動補完する括弧ペアの列記",
8080
"Matching character triples": "自動補完する3文字括弧の列記",
8181
"Exploding character pairs": "改行時に空行を挿入する括弧ペアの列記",
82+
"Custom MarkdownLint Rules": "カスタムMarkdownLintルール",
8283
"Preview": "プレビュー",
8384
"Preview Font Size": "プレビュー時フォントサイズ",
8485
"Preview Font Family": "プレビュー時フォント",

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"immutable": "^3.8.1",
7575
"invert-color": "^2.0.0",
7676
"js-yaml": "^3.12.0",
77+
"jsonlint-mod": "^1.7.4",
7778
"katex": "^0.9.0",
7879
"lodash": "^4.11.1",
7980
"lodash-move": "^1.1.1",

0 commit comments

Comments
 (0)