Skip to content

Commit

Permalink
Complete HTML tags in Markdown context
Browse files Browse the repository at this point in the history
FEATURE: The markdown package now installs a completion source that completes
HTML tags when in Markdown context.

Closes codemirror/dev#1181
  • Loading branch information
marijnh committed Jun 12, 2023
1 parent a57a30b commit cea3ed7
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 6 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
"sideEffects": false,
"license": "MIT",
"dependencies": {
"@codemirror/autocomplete": "^6.7.1",
"@codemirror/lang-html": "^6.0.0",
"@codemirror/language": "^6.3.0",
"@codemirror/state": "^6.0.0",
Expand Down
47 changes: 41 additions & 6 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {Prec} from "@codemirror/state"
import {Prec, EditorState} from "@codemirror/state"
import {KeyBinding, keymap} from "@codemirror/view"
import {Language, LanguageSupport, LanguageDescription} from "@codemirror/language"
import {Language, LanguageSupport, LanguageDescription, syntaxTree} from "@codemirror/language"
import {Completion, CompletionContext} from "@codemirror/autocomplete"
import {MarkdownExtension, MarkdownParser, parseCode} from "@lezer/markdown"
import {html} from "@codemirror/lang-html"
import {html, htmlCompletionSource} from "@codemirror/lang-html"
import {commonmarkLanguage, markdownLanguage, mkLang, getCodeParser} from "./markdown"
import {insertNewlineContinueMarkup, deleteMarkupBackward} from "./commands"
export {commonmarkLanguage, markdownLanguage, insertNewlineContinueMarkup, deleteMarkupBackward}
Expand Down Expand Up @@ -39,9 +40,17 @@ export function markdown(config: {
extensions?: MarkdownExtension,
/// The base language to use. Defaults to
/// [`commonmarkLanguage`](#lang-markdown.commonmarkLanguage).
base?: Language
base?: Language,
/// By default, the extension installs an autocompletion source that
/// completes HTML tags when a `<` is typed. Set this to false to
/// disable this.
completeHTMLTags?: boolean
} = {}) {
let {codeLanguages, defaultCodeLanguage, addKeymap = true, base: {parser} = commonmarkLanguage} = config
let {codeLanguages,
defaultCodeLanguage,
addKeymap = true,
base: {parser} = commonmarkLanguage,
completeHTMLTags = true} = config
if (!(parser instanceof MarkdownParser)) throw new RangeError("Base parser provided to `markdown` should be a Markdown parser")
let extensions = config.extensions ? [config.extensions] : []
let support = [htmlNoMatch.support], defaultCode
Expand All @@ -54,5 +63,31 @@ export function markdown(config: {
let codeParser = codeLanguages || defaultCode ? getCodeParser(codeLanguages, defaultCode) : undefined
extensions.push(parseCode({codeParser, htmlParser: htmlNoMatch.language.parser}))
if (addKeymap) support.push(Prec.high(keymap.of(markdownKeymap)))
return new LanguageSupport(mkLang(parser.configure(extensions)), support)
let lang = mkLang(parser.configure(extensions))
if (completeHTMLTags) support.push(lang.data.of({autocomplete: htmlTagCompletion}))
return new LanguageSupport(lang, support)
}

function htmlTagCompletion(context: CompletionContext) {
let {state, pos} = context, m = /<[:\-\.\w\u00b7-\uffff]*$/.exec(state.sliceDoc(pos - 25, pos))
if (!m) return null
let tree = syntaxTree(state).resolveInner(pos, -1)
while (tree && !tree.type.isTop) {
if (tree.name == "CodeBlock" || tree.name == "FencedCode" || tree.name == "ProcessingInstructionBlock" ||
tree.name == "CommentBlock" || tree.name == "Link" || tree.name == "Image") return null
tree = tree.parent!
}

return {
from: pos - m[0].length, to: pos,
options: htmlTagCompletions(),
validFor: /^<[:\-\.\w\u00b7-\uffff]*$/
}
}

let _tagCompletions: readonly Completion[] | null = null
function htmlTagCompletions() {
if (_tagCompletions) return _tagCompletions
let result = htmlCompletionSource(new CompletionContext(EditorState.create({extensions: htmlNoMatch}), 0, true))
return _tagCompletions = result ? result.options : []
}

0 comments on commit cea3ed7

Please sign in to comment.