Merge pull request #1257 from hackmdio/feature/markdownlint

Support markdownlint
This commit is contained in:
Max Wu 2019-09-08 01:09:00 +08:00 committed by GitHub
commit 8452da1676
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 186 additions and 2 deletions

View File

@ -93,6 +93,7 @@
"markdown-it-sub": "~1.0.0",
"markdown-it-sup": "~1.0.0",
"markdown-pdf": "~9.0.0",
"markdownlint": "^0.16.0",
"mathjax": "~2.7.5",
"mattermost-redux": "~5.13.0",
"mermaid": "~8.2.3",

View File

@ -513,6 +513,7 @@ div[contenteditable]:empty:not(:focus):before{
.status-bar .status-indicators .status-keymap > a,
.status-bar .status-indicators .status-theme > a,
.status-bar .status-indicators .status-spellcheck > a,
.status-bar .status-indicators .status-linter > a,
.status-bar .status-indicators .status-preferences > a {
color: inherit;
text-decoration: none;
@ -520,6 +521,7 @@ div[contenteditable]:empty:not(:focus):before{
.status-bar .status-indicators .status-theme,
.status-bar .status-indicators .status-spellcheck,
.status-bar .status-indicators .status-linter,
.status-bar .status-indicators .status-preferences {
padding: 0 4.3px;
}
@ -540,17 +542,20 @@ div[contenteditable]:empty:not(:focus):before{
}
.ui-theme-toggle,
.ui-linter-toggle,
.ui-spellcheck-toggle {
opacity: 0.2;
cursor: pointer;
}
.ui-theme-toggle.active,
.ui-linter-toggle.active,
.ui-spellcheck-toggle.active {
opacity: 1;
}
.ui-theme-toggle:hover,
.ui-linter-toggle:hover,
.ui-spellcheck-toggle:hover {
opacity: 0.8;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

View File

@ -3,6 +3,7 @@ import * as utils from './utils'
import config from './config'
import statusBarTemplate from './statusbar.html'
import toolBarTemplate from './toolbar.html'
import './markdown-lint'
/* config section */
const isMac = CodeMirror.keyMap.default === CodeMirror.keyMap.macDefault
@ -231,6 +232,7 @@ export default class Editor {
this.statusLength = this.statusBar.find('.status-length')
this.statusTheme = this.statusBar.find('.status-theme')
this.statusSpellcheck = this.statusBar.find('.status-spellcheck')
this.statusLinter = this.statusBar.find('.status-linter')
this.statusPreferences = this.statusBar.find('.status-preferences')
this.statusPanel = this.editor.addPanel(this.statusBar[0], {
position: 'bottom'
@ -240,6 +242,7 @@ export default class Editor {
this.setKeymap()
this.setTheme()
this.setSpellcheck()
this.setLinter()
this.setPreferences()
}
@ -498,6 +501,42 @@ export default class Editor {
}
}
toggleLinter (enable) {
const gutters = this.editor.getOption('gutters')
const lintGutter = 'CodeMirror-lint-markers'
if (enable) {
if (!gutters.includes(lintGutter)) {
this.editor.setOption('gutters', [lintGutter, ...gutters])
}
Cookies.set('linter', true, {
expires: 365
})
} else {
this.editor.setOption('gutters', gutters.filter(g => g !== lintGutter))
Cookies.remove('linter')
}
this.editor.setOption('lint', enable)
}
setLinter () {
const linterToggle = this.statusLinter.find('.ui-linter-toggle')
const updateLinterStatus = (enable) => {
linterToggle.toggleClass('active', enable)
}
linterToggle.click(() => {
const lintEnable = this.editor.getOption('lint')
this.toggleLinter.bind(this)(!lintEnable)
updateLinterStatus(!lintEnable)
})
const enable = !!Cookies.get('linter')
this.toggleLinter.bind(this)(enable)
updateLinterStatus(enable)
}
resetEditorKeymapToBrowserKeymap () {
var keymap = this.editor.getOption('keyMap')
if (!this.jumpToAddressBarKeymapValue) {

View File

@ -0,0 +1,45 @@
/* global CodeMirror */
import markdownlint from 'markdownlint'
// load CM lint plugin explicitly
import '@hackmd/codemirror/addon/lint/lint'
import './lint.css'
(function (mod) {
mod(CodeMirror)
})(function (CodeMirror) {
function validator (text) {
return lint(text).map(error => {
const {
ruleNames,
ruleDescription,
lineNumber: ln,
errorRange
} = error
const lineNumber = ln - 1
let start = 0; let end = -1
if (errorRange) {
[start, end] = errorRange.map(r => r - 1)
}
return {
messageHTML: `${ruleNames.join('/')}: ${ruleDescription}`,
severity: 'error',
from: CodeMirror.Pos(lineNumber, start),
to: CodeMirror.Pos(lineNumber, end)
}
})
}
CodeMirror.registerHelper('lint', 'markdown', validator)
})
function lint (content) {
const { content: errors } = markdownlint.sync({
strings: {
content
}
})
return errors
}

View File

@ -0,0 +1,73 @@
/* The lint marker gutter */
.CodeMirror-lint-markers {
width: 16px;
}
.CodeMirror-lint-tooltip {
background-color: #333333;
border: 1px solid #eeeeee;
border-radius: 4px;
color: white;
font-family: "Source Code Pro", Consolas, monaco, monospace;
font-size: 10pt;
overflow: hidden;
padding: 2px 5px;
position: fixed;
white-space: pre;
white-space: pre-wrap;
z-index: 100;
max-width: 600px;
opacity: 0;
transition: opacity .4s;
-moz-transition: opacity .4s;
-webkit-transition: opacity .4s;
-o-transition: opacity .4s;
-ms-transition: opacity .4s;
}
.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning {
background-position: left bottom;
background-repeat: repeat-x;
}
.CodeMirror-lint-mark-error {
background-image: url(/images/lint/mark-error.png);
}
.CodeMirror-lint-mark-warning {
background-image: url(/images/lint/mark-warning.png);
}
.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning {
background-position: center center;
background-repeat: no-repeat;
cursor: pointer;
display: inline-block;
height: 16px;
width: 16px;
vertical-align: middle;
position: relative;
margin-left: 5px;
}
.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning {
padding-left: 20px;
background-position: top left;
background-repeat: no-repeat;
background-position-y: 2px;
}
.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error {
background-image: url(/images/lint/message-error.png);
}
.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning {
background-image: url(/images/lint/message-warning.png);
}
.CodeMirror-lint-marker-multiple {
background-image: url(/images/lint/mark-multiple.png);
background-repeat: no-repeat;
background-position: right bottom;
width: 100%; height: 100%;
}

View File

@ -37,5 +37,8 @@
<div class="status-spellcheck">
<a class="ui-spellcheck-toggle" title="Toggle spellcheck"><i class="fa fa-check fa-fw"></i></a>
</div>
<div class="status-linter">
<a class="ui-linter-toggle" title="Toggle linter"><i class="fa fa-lightbulb-o fa-fw"></i></a>
</div>
</div>
</div>

1
public/js/url.js Normal file
View File

@ -0,0 +1 @@
exports.URL = window.URL

View File

@ -167,7 +167,11 @@ module.exports = {
to: 'reveal.js/plugin'
}
]),
new MiniCssExtractPlugin()
new MiniCssExtractPlugin(),
new webpack.NormalModuleReplacementPlugin(
/^url$/,
path.resolve(__dirname, './public/js/url.js')
)
],
entry: {
@ -376,6 +380,7 @@ module.exports = {
'vega-lite': path.join(__dirname, 'node_modules/vega-lite/build/vega-lite.min.js'),
'vega-embed': path.join(__dirname, 'node_modules/vega-embed/build/vega-embed.min.js'),
'emojify.js': path.join(__dirname, 'node_modules/@hackmd/emojify.js/dist/js/emojify-browser.min.js'),
'markdown-it': path.join(__dirname, 'node_modules/markdown-it/dist/markdown-it.js')
}
},
@ -460,6 +465,11 @@ module.exports = {
loader: 'url-loader',
options: { limit: '10000', mimetype: 'image/gif' }
}]
}, {
test: /@hackmd\/codemirror\/addon\/lint\/lint/,
use: [{
loader: 'script-loader'
}]
}]
},
node: {

View File

@ -7890,7 +7890,7 @@ markdown-it-sup@~1.0.0:
resolved "https://registry.yarnpkg.com/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz#cb9c9ff91a5255ac08f3fd3d63286e15df0a1fc3"
integrity sha1-y5yf+RpSVawI8/09YyhuFd8KH8M=
markdown-it@~9.0.1:
markdown-it@9.0.1, markdown-it@~9.0.1:
version "9.0.1"
resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-9.0.1.tgz#aafe363c43718720b6575fd10625cde6e4ff2d47"
integrity sha512-XC9dMBHg28Xi7y5dPuLjM61upIGPJG8AiHNHYqIaXER2KNnn7eKnM5/sF0ImNnyoV224Ogn9b1Pck8VH4k0bxw==
@ -7921,6 +7921,13 @@ markdown-table@^1.1.0:
resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-1.1.3.tgz#9fcb69bcfdb8717bfd0398c6ec2d93036ef8de60"
integrity sha512-1RUZVgQlpJSPWYbFSpmudq5nHY1doEIv89gBtF0s4gW1GF2XorxcA/70M5vq7rLv0a6mhOUccRsqkwhwLCIQ2Q==
markdownlint@^0.16.0:
version "0.16.0"
resolved "https://registry.yarnpkg.com/markdownlint/-/markdownlint-0.16.0.tgz#69f73cc755a44231fbe5dc7c37a5909cedc0ac6e"
integrity sha512-Zo+iPezP3eM6lLhKepkUw+X98H44lipIdx4d6faaugfB0+7VuDB3R0hXmx7z9F1N3/ypn46oOFgAD9iF++Ie6A==
dependencies:
markdown-it "9.0.1"
marked@~0.6.2:
version "0.6.3"
resolved "https://registry.yarnpkg.com/marked/-/marked-0.6.3.tgz#79babad78af638ba4d522a9e715cdfdd2429e946"