mirror of
https://github.com/purocean/yn.git
synced 2026-09-24 15:46:02 +08:00
feat: add support for Wiki Links in Markdown syntax
This commit modifies the Markdown syntax in the editor to support Wiki Links. It adds a new token pattern for [[...]] syntax and updates the completion provider to handle Wiki Link contexts. Now, when a user types [[, the editor will suggest Wiki Link completions. The changes include: - Adding a new token pattern for [[...]] syntax - Updating the completion provider to handle Wiki Link contexts These modifications enhance the editing experience by allowing users to easily create Wiki Links within their Markdown documents.
This commit is contained in:
@@ -199,6 +199,7 @@ export default {
|
||||
{ label: '/ __ Bold', insertText: '__$1__' },
|
||||
{ label: '/ ~~ Delete', insertText: '~~$1~~' },
|
||||
{ label: '/ == Mark', insertText: '==$1==' },
|
||||
{ label: '/ [[]] Wiki Link', insertText: '[[$1]]' },
|
||||
{ label: '/ ``` Fence', insertText: '```$1\n$2\n```\n' },
|
||||
{ label: '/ ||| Table', insertText: '| ${1:TH} | ${2:TH} | ${3:TH} |\n| -- | -- | -- |\n| TD | TD | TD |' },
|
||||
{ label: '/ ||| Small Table', insertText: '| ${1:TH} | ${2:TH} | ${3:TH} |\n| -- | -- | -- |\n| TD | TD | TD |\n{.small}' },
|
||||
@@ -211,6 +212,7 @@ export default {
|
||||
ctx.editor.tapMarkdownMonarchLanguage(mdLanguage => {
|
||||
mdLanguage.tokenizer.root.unshift(
|
||||
[/==\S.*\S?==/, 'keyword'],
|
||||
[/\[\[[^[\]]+\]\]/, 'string'],
|
||||
[/~\S[^~]*\S?~/, 'string'],
|
||||
[/\^\S[^^]*\S?\^/, 'string'],
|
||||
)
|
||||
|
||||
@@ -9,6 +9,8 @@ import type Token from 'markdown-it/lib/token'
|
||||
enum CompletionContextKind {
|
||||
Link, // [...](|)
|
||||
|
||||
WikiLink, // [[|]]
|
||||
|
||||
ReferenceLink, // [...][|]
|
||||
|
||||
LinkDefinition, // []: | // TODO: not implemented
|
||||
@@ -89,6 +91,7 @@ class CompletionProvider implements Monaco.languages.CompletionItemProvider {
|
||||
}
|
||||
|
||||
case CompletionContextKind.LinkDefinition:
|
||||
case CompletionContextKind.WikiLink:
|
||||
case CompletionContextKind.Link: {
|
||||
const items: Monaco.languages.CompletionItem[] = []
|
||||
|
||||
@@ -151,6 +154,9 @@ class CompletionProvider implements Monaco.languages.CompletionItemProvider {
|
||||
/// [...](...|
|
||||
private readonly linkStartPattern = /\[([^\]]*?)\]\(\s*([^\s()]*)$/
|
||||
|
||||
/// [[...|
|
||||
private readonly wikiLinkStartPattern = /\[\[\s*([^\s[\]]*)$/
|
||||
|
||||
/// [...|
|
||||
private readonly referenceLinkStartPattern = /\[\s*([^\s[\]]*)$/
|
||||
|
||||
@@ -186,6 +192,19 @@ class CompletionProvider implements Monaco.languages.CompletionItemProvider {
|
||||
}
|
||||
}
|
||||
|
||||
const wikiLinkPrefixMatch = linePrefixText.match(this.wikiLinkStartPattern)
|
||||
if (wikiLinkPrefixMatch) {
|
||||
const prefix = wikiLinkPrefixMatch[1]
|
||||
const suffix = lineSuffixText.match(/^[^\]]*/)
|
||||
return {
|
||||
kind: CompletionContextKind.WikiLink,
|
||||
linkPrefix: prefix,
|
||||
linkTextStartPosition: position.delta(0, -prefix.length),
|
||||
linkSuffix: suffix ? suffix[0] : '',
|
||||
anchorInfo: this.getAnchorContext(prefix),
|
||||
}
|
||||
}
|
||||
|
||||
const definitionLinkPrefixMatch = linePrefixText.match(this.definitionPattern)
|
||||
if (definitionLinkPrefixMatch) {
|
||||
const prefix = definitionLinkPrefixMatch[1]
|
||||
@@ -230,14 +249,21 @@ class CompletionProvider implements Monaco.languages.CompletionItemProvider {
|
||||
if (!anchorMatch) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
let beforeAnchor = anchorMatch[1]
|
||||
|
||||
if (anchorMatch[1] && !this.ctx.utils.path.extname(beforeAnchor)) {
|
||||
beforeAnchor += '.md'
|
||||
}
|
||||
|
||||
return {
|
||||
beforeAnchor: anchorMatch[1],
|
||||
beforeAnchor,
|
||||
anchorPrefix: anchorMatch[2],
|
||||
}
|
||||
}
|
||||
|
||||
private async * providePathSuggestions (position: Monaco.Position, context: CompletionContext): AsyncIterable<Monaco.languages.CompletionItem> {
|
||||
const valueBeforeLastSlash = context.linkPrefix.substring(0, context.linkPrefix.lastIndexOf('/') + 1) || '.' // keep the last slash
|
||||
const valueBeforeLastSlash = context.linkPrefix.substring(0, context.linkPrefix.lastIndexOf('/') + 1) // keep the last slash
|
||||
|
||||
const currentFile = this.ctx.store.state.currentFile
|
||||
if (!currentFile) {
|
||||
@@ -246,7 +272,7 @@ class CompletionProvider implements Monaco.languages.CompletionItemProvider {
|
||||
|
||||
const parentDir = this.ctx.utils.path.resolve(
|
||||
this.ctx.utils.path.dirname(currentFile.path),
|
||||
valueBeforeLastSlash
|
||||
valueBeforeLastSlash || '.'
|
||||
)
|
||||
|
||||
const pathSegmentStart = position.delta(0, valueBeforeLastSlash.length - context.linkPrefix.length)
|
||||
|
||||
@@ -73,3 +73,34 @@ markdown.core.ruler.after('normalize', 'after_normalize', state => {
|
||||
state.env.tokens = state.tokens
|
||||
return true
|
||||
})
|
||||
|
||||
markdown.linkify.add('[[', {
|
||||
validate: /^\s*([^[\]]+)\s*\]\]/,
|
||||
normalize: (match) => {
|
||||
const parts = match.raw.slice(2, -2).split('|')
|
||||
const url = parts[0].trim()
|
||||
|
||||
// external link
|
||||
if (/^[a-zA-Z]{1,8}:\/\/.*/.test(url)) {
|
||||
match.url = url
|
||||
match.text = parts[1] || url
|
||||
return
|
||||
}
|
||||
|
||||
const [path, hash] = url.split('#')
|
||||
const hashStr = hash ? `#${hash}` : ''
|
||||
|
||||
const name = parts[1] || (path.split('/').pop() + hashStr)
|
||||
match.text = name || url
|
||||
|
||||
// has extension name
|
||||
if (/\.[^/]+$/.test(path)) {
|
||||
match.url = url
|
||||
} else if (path) {
|
||||
match.url = `${path}.md${hashStr}`
|
||||
} else {
|
||||
match.url = hashStr
|
||||
match.text = name || hash || url
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user