Skip to content

Commit

Permalink
feat: optimize wiki links use experience
Browse files Browse the repository at this point in the history
  • Loading branch information
purocean committed Jun 17, 2024
1 parent 8912808 commit 5db7f56
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 10 deletions.
1 change: 1 addition & 0 deletions help/FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ Type '/' in the editor to get prompts
*[HTML]: Hyper Text Markup Language
*[W3C]: World Wide Web Consortium
The HTML specification is maintained by the W3C.
+ Wiki Link: Supports using `[[filename#anchor|display text]]` syntax to link documents, such as [[README#Highlights|Highlights]]

## Github Alerts

Expand Down
1 change: 1 addition & 0 deletions help/FEATURES_ZH-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ define:
*[HTML]: Hyper Text Markup Language
*[W3C]: World Wide Web Consortium
The HTML specification is maintained by the W3C.
+ Wiki 链接:支持使用 `[[文件名#锚点|显示文本]]` 语法来链接文档,如 [[README#Highlights|特色功能]]

## Github Alerts

Expand Down
8 changes: 8 additions & 0 deletions src/renderer/others/setting-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,14 @@ const schema: SettingSchema = ({
group: 'render',
required: true,
},
'render.md-wiki-links': {
defaultValue: true,
title: 'T_setting-panel.schema.render.md-wiki-links',
type: 'boolean',
format: 'checkbox',
group: 'render',
required: true,
},
'render.md-typographer': {
defaultValue: false,
title: 'T_setting-panel.schema.render.md-typographer',
Expand Down
14 changes: 11 additions & 3 deletions src/renderer/plugins/editor-path-completion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class CompletionProvider implements Monaco.languages.CompletionItemProvider {
private readonly linkStartPattern = /\[([^\]]*?)\]\(\s*([^\s()]*)$/

/// [[...|
private readonly wikiLinkStartPattern = /\[\[\s*([^\s[\]]*)$/
private readonly wikiLinkStartPattern = /\[\[\s*([^[\]]*)$/

/// [...|
private readonly referenceLinkStartPattern = /\[\s*([^\s[\]]*)$/
Expand Down Expand Up @@ -297,10 +297,18 @@ class CompletionProvider implements Monaco.languages.CompletionItemProvider {
for (const item of items) {
i++
const isDir = item.type === 'dir'
const label = isDir ? item.name + '/' : item.name
let label = isDir ? item.name + '/' : item.name
let insertText = this.ctx.utils.encodeMarkdownLink(label)

// Remove extension for wiki links
if (context.kind === CompletionContextKind.WikiLink) {
label = label.replace(/\.(md|markdown)$/, '')
insertText = label.replaceAll(']', ']').replaceAll('[', '[')
}

yield {
label,
insertText: this.ctx.utils.encodeMarkdownLink(label),
insertText,
kind: isDir ? this.monaco.languages.CompletionItemKind.Folder : this.monaco.languages.CompletionItemKind.File,
range: {
insert: insertRange,
Expand Down
76 changes: 71 additions & 5 deletions src/renderer/plugins/markdown-link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { removeQuery, sleep } from '@fe/utils'
import { isElectron, isWindows } from '@fe/support/env'
import { useToast } from '@fe/support/ui/toast'
import { DOM_ATTR_NAME, DOM_CLASS_NAME } from '@fe/support/args'
import { basename, dirname, join, resolve } from '@fe/utils/path'
import { basename, dirname, join, normalizeSep, resolve } from '@fe/utils/path'
import { switchDoc } from '@fe/services/document'
import { getAttachmentURL, getRepo, openExternal, openPath } from '@fe/services/base'
import { getRenderIframe } from '@fe/services/view'
import { getAllCustomEditors } from '@fe/services/editor'
import { fetchTree } from '@fe/support/api'
import type { Doc } from '@share/types'
import type { Components } from '@fe/types'

async function getElement (id: string) {
id = id.replaceAll('%28', '(').replaceAll('%29', ')')
Expand All @@ -28,6 +30,55 @@ async function getElement (id: string) {
return _find(id) || _find(id.toUpperCase())
}

async function getFirstMatchPath (repo: string, dir: string, path: string) {
if (path.includes('/')) {
return path
}

const findInDir = (items: Components.Tree.Node[]): string | null => {
for (const item of items) {
const p = normalizeSep(item.path)
if (
item.type === 'file' &&
(p === normalizeSep(join(dir, path)) ||
p === normalizeSep(join(dir, `${path}.md`)))
) {
return item.path
}

if (item.children) {
const found = findInDir(item.children)
if (found) {
return found
}
}
}

return null
}

const findByName = (items: Components.Tree.Node[]): string | null => {
for (const item of items) {
if (item.type === 'file' && (item.name === path || item.name === `${path}.md`)) {
return item.path
}

if (item.children) {
const found = findByName(item.children)
if (found) {
return found
}
}
}

return null
}

const tree = await fetchTree(repo, { by: 'mtime', order: 'desc' })

return findInDir(tree) || findByName(tree)
}

function getAnchorElement (target: HTMLElement) {
let cur: HTMLElement | null = target
while (cur && cur.tagName !== 'A' && cur.tagName !== 'ARTICLE') {
Expand Down Expand Up @@ -92,18 +143,33 @@ function handleLink (link: HTMLAnchorElement): boolean {

const tmp = decodeURI(href).split('#')

let path = tmp[0]
if (!path.startsWith('/')) { // to absolute path
path = join(dirname(filePath || ''), path)
const _switchDoc = async () => {
let path = normalizeSep(tmp[0])

const dir = dirname(filePath || '')

// wiki link
if (link.getAttribute(DOM_ATTR_NAME.WIKI_LINK)) {
path = (await getFirstMatchPath(fileRepo, dir, path)) || path
}

if (!path.startsWith('/')) { // to absolute path
path = join(dir, path)
}

const file: Doc = { path, type: 'file', name: basename(path), repo: fileRepo }

return switchDoc(file)
}

const path = normalizeSep(tmp[0])
const file: Doc = { path, type: 'file', name: basename(path), repo: fileRepo }

const isMarkdownFile = /(\.md$|\.md#)/.test(href)
const supportOpenDirectly = isMarkdownFile || getAllCustomEditors().some(x => x.when?.({ doc: file }))

if (supportOpenDirectly) {
switchDoc(file).then(async () => {
_switchDoc().then(async () => {
const hash = tmp.slice(1).join('#')
// jump anchor
if (hash) {
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/plugins/markdown-wiki-links.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Plugin } from '@fe/context'
import ctx, { Plugin } from '@fe/context'
import type StateInline from 'markdown-it/lib/rules_inline/state_inline'

const reMatch = /^\s*([^[#|]*)?(?:#([^|]*))?(?:\|([^\]]*))?\s*$/
Expand Down Expand Up @@ -46,7 +46,7 @@ function wikiLinks (state: StateInline, silent?: boolean) {
}

if (!silent) {
state.push('link_open', 'a', 1).attrs = [['href', url]]
state.push('link_open', 'a', 1).attrs = [['href', url], [ctx.args.DOM_ATTR_NAME.WIKI_LINK, 'true']]
state.push('text', '', 0).content = text
state.push('link_close', 'a', -1)
}
Expand Down
1 change: 1 addition & 0 deletions src/renderer/services/markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ markdown.render = (src: string, env?: any) => {

;(getSetting('render.md-sup', true) ? enabledRules : disabledRules).push('sup')
;(getSetting('render.md-sub', true) ? enabledRules : disabledRules).push('sub')
;(getSetting('render.md-wiki-links', true) ? enabledRules : disabledRules).push('wiki-links')

markdown.enable(enabledRules, true)
markdown.disable(disabledRules, true)
Expand Down
1 change: 1 addition & 0 deletions src/renderer/support/args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const DOM_ATTR_NAME = {
ONLY_CHILD: 'auto-center',
TOKEN_IDX: 'data-token-idx',
DISPLAY_NONE: 'display-none',
WIKI_LINK: 'wiki-link',
}

export const DOM_CLASS_NAME = {
Expand Down
1 change: 1 addition & 0 deletions src/renderer/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ export interface BuildInSettings {
'render.md-html': boolean,
'render.md-breaks': boolean,
'render.md-linkify': boolean,
'render.md-wiki-links': boolean,
'render.md-typographer': boolean,
'render.md-emoji': boolean,
'render.md-sub': boolean,
Expand Down
1 change: 1 addition & 0 deletions src/share/i18n/languages/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,7 @@ const data = {
'md-html': 'Enable HTML',
'md-breaks': 'Convert \\n to <br>',
'md-linkify': 'Auto convert URL-like text to links',
'md-wiki-links': 'Enable Wiki Links - [[link]]',
'md-typographer': 'Enable some language-neutral replacement + quotes beautification',
'md-sup': 'Enable sup syntax: 29^th^',
'md-sub': 'Enable sub syntax: H~2~O',
Expand Down
1 change: 1 addition & 0 deletions src/share/i18n/languages/zh-CN.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ const data: BaseLanguage = {
'md-html': '启用 HTML',
'md-breaks': '将 \\n 转换为 <br>',
'md-linkify': '自动将类似 URL 的文本转换为链接',
'md-wiki-links': '启用 Wiki 链接 - [[link]]',
'md-typographer': '启用排版美化,如 (c) -> ©',
'md-sup': '启用上标语法: 29^th^',
'md-sub': '启用下标语法: H~2~O',
Expand Down
1 change: 1 addition & 0 deletions src/share/i18n/languages/zh-TW.ts
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,7 @@ const data: BaseLanguage = {
'md-html': '啟用 HTML',
'md-breaks': '將 \\n 轉換為 <br>',
'md-linkify': '自動將類似 URL 的文字轉換為連結',
'md-wiki-links': '啟用 Wiki 連結 - [[link]]',
'md-typographer': '啟用排版美化,如 (c) -> ©',
'md-sup': '啟用上標語法: 29^th^',
'md-sub': '啟用下標語法: H~2~O',
Expand Down

0 comments on commit 5db7f56

Please sign in to comment.