Skip to content

Commit

Permalink
feat: add support for Wiki Links in Markdown syntax
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
purocean committed Jun 14, 2024
1 parent 5491df6 commit 485822e
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 3 deletions.
2 changes: 2 additions & 0 deletions src/renderer/plugins/editor-md-syntax.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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}' },
Expand All @@ -211,6 +212,7 @@ export default {
ctx.editor.tapMarkdownMonarchLanguage(mdLanguage => {
mdLanguage.tokenizer.root.unshift(
[/==\S.*\S?==/, 'keyword'],
[/\[\[[^[\]]+\]\]/, 'string'],
[/~\S[^~]*\S?~/, 'string'],
[/\^\S[^^]*\S?\^/, 'string'],
)
Expand Down
32 changes: 29 additions & 3 deletions src/renderer/plugins/editor-path-completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import type Token from 'markdown-it/lib/token'
enum CompletionContextKind {
Link, // [...](|)

WikiLink, // [[|]]

ReferenceLink, // [...][|]

LinkDefinition, // []: | // TODO: not implemented
Expand Down Expand Up @@ -89,6 +91,7 @@ class CompletionProvider implements Monaco.languages.CompletionItemProvider {
}

case CompletionContextKind.LinkDefinition:
case CompletionContextKind.WikiLink:
case CompletionContextKind.Link: {
const items: Monaco.languages.CompletionItem[] = []

Expand Down Expand Up @@ -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[\]]*)$/

Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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) {
Expand All @@ -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)
Expand Down
31 changes: 31 additions & 0 deletions src/renderer/services/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
})

0 comments on commit 485822e

Please sign in to comment.