diff --git a/package.json b/package.json
index 2f1c070..3100413 100644
--- a/package.json
+++ b/package.json
@@ -102,13 +102,18 @@
"clone-deep": "^4.0.1",
"electron-context-menu": "^2.4.0",
"electron-squirrel-startup": "^1.0.0",
+ "hast-util-from-string": "^1.0.4",
"hast-util-to-html": "^7.1.2",
+ "hast-util-to-mdast": "^7.1.3",
"immer": "^8.0.1",
"lit-element": "^2.4.0",
"lit-html": "^1.3.0",
+ "mdast-builder": "^1.1.1",
"mdast-util-compact": "^3.0.0",
"mdast-util-from-markdown": "^0.8.4",
+ "mdast-util-gfm": "^0.1.1",
"mdast-util-to-markdown": "^0.6.2",
+ "rehype-parse": "^7.0.1",
"remark-highlight.js": "^6.0.0",
"remark-html": "^13.0.1",
"remark-parse": "^9.0.0",
diff --git a/src/ast/backspace-paragraph.ts b/src/ast/backspace-paragraph.ts
index 559a22c..87ecb61 100644
--- a/src/ast/backspace-paragraph.ts
+++ b/src/ast/backspace-paragraph.ts
@@ -1,11 +1,11 @@
import {visit, EXIT} from "unist-utils-core"
import * as md from "mdast"
import compact from "mdast-util-compact"
+import {DataCaret} from "../caret"
export default function backspaceParagraph(
root: md.Parent,
- target: md.Paragraph,
- id?: string
+ target: md.Paragraph
): void {
visit(root, target, (node, index, parents) => {
let parent = parents[parents.length - 1]
@@ -19,13 +19,27 @@ export default function backspaceParagraph(
if (Array.isArray(previous.children)) {
let length = previous.children.length
+ let lastChildOfPrevious = previous.children[length - 1]
+ while (lastChildOfPrevious.children) {
+ let len = lastChildOfPrevious.children.length - 1
+ lastChildOfPrevious = lastChildOfPrevious.children[len]
+ }
+
previous.children.splice(length, 0, ...node.children)
- parent.children[index - 1] = compact(previous)
- // TODO come back and use merge
- if (id) {
- let child = previous.children[length - 1]
- child.id = id
+ parent.children[index - 1] = previous
+ let n = node.children[0]
+
+ while (n.children) {
+ n = n.children[0]
}
+
+ let caret: DataCaret = {
+ caretStart: 0,
+ caretEnd: 0,
+ }
+
+ n.data = {caret}
+ // TODO come back and use merge
} else {
throw new TypeError("line before somehow has no children?")
}
diff --git a/src/ast/convert-to-html.ts b/src/ast/convert-to-html.ts
deleted file mode 100644
index 75cf103..0000000
--- a/src/ast/convert-to-html.ts
+++ /dev/null
@@ -1,287 +0,0 @@
-import type * as md from "mdast"
-import {html, TemplateResult} from "lit-html"
-import {spread} from "@open-wc/lit-helpers"
-import * as is from "./is"
-import {DataCaret} from "../caret"
-
-type Handler = (node: md.Content) => any
-
-interface Handlers {
- [type: string]: Handler
-}
-
-export function spreadable(node: md.Content | md.Root) {
- let {data, position, children, ...spreadable} = node
- if (is.leaf(node.type)) {
- spreadable.leaf = true
- }
- if (is.block(node.type)) {
- spreadable.block = true
- }
- if (is.inline(node.type)) {
- spreadable.inline = true
- }
- if (is.container(node.type)) {
- spreadable.container = true
- }
- if (is.empty(node.type)) {
- spreadable.empty = true
- }
-
- if (data && data.caret) {
- let caret: DataCaret = data.caret as DataCaret
- spreadable.caret = caret.type
- spreadable.caretOffset = caret.offset
- }
- return spreadable
-}
-
-let handlers: Handlers = {
- blockquote(node) {
- node = node as md.Blockquote
- return html``
- },
-
- break(node) {
- node = node as md.Break
- return html``
- // return html`
`
- },
-
- code(node) {
- node = node as md.Code
- return html``
- },
-
- delete(node) {
- node = node as md.Delete
- return html``
- },
-
- emphasis(node) {
- node = node as md.Emphasis
- return html``
- },
-
- footnoteReference(node) {
- node = node as md.FootnoteReference
- return html``
- },
-
- footnote(node) {
- node = node as md.Footnote
- return html``
- },
-
- heading(node) {
- node = node as md.Heading
- let h
- switch (node.depth) {
- case 1:
- h = html`
`
- break
- case 2:
- h = html``
- break
- case 3:
- h = html``
- break
- case 4:
- h = html``
- break
- case 5:
- h = html``
- break
- case 6:
- h = html``
- break
- }
- return html``
- },
-
- html(node) {
- node = node as md.HTML
- return html``
- },
-
- imageReference(node) {
- node = node as md.ImageReference
- return html``
- },
-
- image(node) {
- node = node as md.Image
- return html``
- },
-
- inlineCode(node) {
- node = node as md.InlineCode
- return html``
- },
-
- linkReference(node) {
- node = node as md.LinkReference
- return html``
- },
-
- link(node) {
- node = node as md.Link
- return html``
- },
-
- listItem(node) {
- node = node as md.ListItem
- return html``
- },
-
- list(node) {
- node = node as md.List
- return html``
- },
-
- paragraph(node) {
- node = node as md.Paragraph
- return html``
- },
-
- // root(node) {
- //node = node as md.Root
- /* return html`
-
- ` */
- //return children(node)
- // },
-
- strong(node) {
- node = node as md.Strong
- return html``
- },
-
- table(node) {
- node = node as md.Table
- return html``
- },
-
- text(node) {
- // You probably don't want this.
- // remember: if you enable this, every text (including those inside an )
- // becomes a mayo- element
- // node = node as md.Text
- // if (parent.type == "emphasis") {
- // return node.value
- // } else {
- // return html`${node.value}`
- return node.value
- },
-
- thematicBreak(node) {
- node = node as md.ThematicBreak
- return html``
- },
-
- toml(node) {
- node = node as md.FrontmatterContent
- return html``
- },
-
- yaml(node) {
- node = node as md.FrontmatterContent
- return html``
- },
-
- definition(node) {
- node = node as md.Definition
- return html``
- },
-
- footnoteDefinition(node) {
- node = node as md.FootnoteDefinition
- return html``
- },
-}
-
-export default function convertToHtml(
- node: md.Content
-): TemplateResult | string {
- let handler = handlers[node.type]
- if (handler) {
- return handler(node)
- } else {
- throw new Error(node.type)
- }
-}
diff --git a/src/ast/insert-paragraph.ts b/src/ast/insert-paragraph.ts
index a42cd2b..40ea18f 100644
--- a/src/ast/insert-paragraph.ts
+++ b/src/ast/insert-paragraph.ts
@@ -5,12 +5,12 @@ import u from "unist-builder"
import * as is from "./is"
import {remove} from "./utils"
import split from "./split"
+import {DataCaret} from "../caret"
export default function insertParagraph(
root: md.Parent,
target: md.Text | md.InlineCode,
- offset: number,
- id?: string
+ offset: number
): void {
if (!target || (target.type != "text" && target.type != "inlineCode")) {
throw new Error(
@@ -18,24 +18,33 @@ export default function insertParagraph(
)
}
let [left, right] = split(root, target, offset)
+
let t = selectAll("text, inlineCode", right)
if (t.length == 1) {
let [node] = t
if (node.value.length == 0) {
node.type = "text"
- node.value = " "
+ node.value = ""
}
}
+ let caret: DataCaret = {
+ caretStart: 0,
+ caretEnd: 0,
+ }
+
+ t[0].data = {
+ caret,
+ }
visit(root, target, (node, index, parents) => {
node.value = left.value
- let firstp = parents[parents.length - 1]
- let prest = firstp.children.slice(index + 1)
+ let directParent = parents[parents.length - 1]
+ let directParentNodesAfter = directParent.children.slice(index + 1)
let rest: unist.Node[] = []
if (target.type == "text" || target.type == "inlineCode") {
parents.forEach((parent, index) => {
- if (is.inline(parent.type)) {
+ if (is.inline(parent)) {
let idx = parents[index - 1].children.indexOf(parent)
parents[index - 1].children.splice(idx, 1, left)
if (!rest.length) {
@@ -46,21 +55,21 @@ export default function insertParagraph(
})
}
parents.forEach((parent, index) => {
- if (is.block(parent.type) && is.leaf(parent.type)) {
+ if (is.block(parent) && is.leaf(parent)) {
let idx = parents[index - 1].children.indexOf(parent)
- let opts: {id?: string} = {}
- if (id) {
- opts.id = id
- }
- prest.forEach((n: unist.Node) => remove(parents[index - 1], {}, n))
- if (parent != firstp) {
- prest = []
+
+ directParentNodesAfter.forEach((n: unist.Node) =>
+ remove(parents[index - 1], {}, n)
+ )
+ if (parent != directParent) {
+ directParentNodesAfter = []
}
parents[index - 1].children.splice(
idx + 1,
0,
- u("paragraph", opts, [right, ...rest, ...prest])
+ u("paragraph", [right, ...rest, ...directParentNodesAfter])
)
+ return
}
})
return EXIT
diff --git a/src/ast/is.ts b/src/ast/is.ts
index 51fbe1f..8e7a6ed 100644
--- a/src/ast/is.ts
+++ b/src/ast/is.ts
@@ -1,3 +1,14 @@
+import * as md from "mdast"
+
+export type MarkdownLeafBlock =
+ | md.ThematicBreak
+ | md.Heading
+ | md.Code
+ | md.HTML
+ | md.LinkReference
+ | md.Paragraph
+ | md.Break
+
let leafBlock = [
"thematicBreak",
"heading",
@@ -8,6 +19,14 @@ let leafBlock = [
"break",
]
+export type MarkdownEmpty =
+ | md.Break
+ | md.ThematicBreak
+ | md.Link
+ | md.LinkReference
+ | md.Image
+ | md.ImageReference
+
let empties = [
"break",
"thematicBreak",
@@ -17,40 +36,68 @@ let empties = [
"imageReference",
]
-let leafInline = ["inlineCode"]
+export type MarkdownLeafInline = md.InlineCode | md.Text
+
+let leafInline = ["inlineCode", "text"]
+
+export type MarkdownContainerBlock = md.Blockquote | md.ListItem | md.List
let containerBlock = ["blockquote", "listItem", "list"]
+export type MarkdownContainerInline = md.Delete | md.Emphasis | md.Strong
+
let containerInline = ["delete", "emphasis", "strong"]
+export type MarkdownInline = MarkdownLeafInline | MarkdownContainerInline
+
let inlines = [...leafInline, ...containerInline]
-let leaves = [...leafBlock]
+export type MarkdownLeaf = MarkdownLeafBlock | MarkdownLeafInline
+
+let leaves = [...leafBlock, ...leafInline]
+
+export type MarkdownBlock = MarkdownLeafBlock | MarkdownContainerBlock
let blocks = [...leafBlock, ...containerBlock]
-let containers = [...containerBlock, "root"]
+export type MarkdownContainer =
+ | MarkdownContainerBlock
+ | MarkdownContainerInline
+ | md.Root
+
+let containers = [...containerInline, ...containerBlock, "root"]
+
+import type * as unist from "unist"
+import {Unwrappable} from "./unwrap"
+
+export function empty(node: unist.Node): node is MarkdownEmpty {
+ return empties.includes(node.type)
+}
+
+export function leaf(node: unist.Node): node is MarkdownLeaf {
+ return leaves.includes(node.type)
+}
-export function empty(type: string): boolean {
- return empties.includes(type)
+export function inline(node: unist.Node): node is MarkdownInline {
+ return inlines.includes(node.type)
}
-export function leaf(type: string): boolean {
- return leaves.includes(type)
+export function container(node: unist.Node): node is MarkdownContainer {
+ return containers.includes(node.type)
}
-export function inline(type: string): boolean {
- return inlines.includes(type)
+export function block(node: unist.Node): node is MarkdownBlock {
+ return blocks.includes(node.type)
}
-export function container(type: string): boolean {
- return containers.includes(type)
+export function list(node: unist.Node): node is md.List {
+ return node.type == "list"
}
-export function block(type: string): boolean {
- return blocks.includes(type)
+export function textish(node: unist.Node): node is md.Text | md.InlineCode {
+ return node.type == "text" || node.type == "inlineCode"
}
-export function list(type: string): boolean {
- return type == "list"
+export function unwrappable(node: unist.Node): node is Unwrappable {
+ return ["emphasis", "delete", "strong", "inlineCode"].includes(node.type)
}
diff --git a/src/ast/split.ts b/src/ast/split.ts
index 015d4f6..532cf15 100644
--- a/src/ast/split.ts
+++ b/src/ast/split.ts
@@ -25,13 +25,13 @@ export default function split(
let idx = highParent.children.indexOf(lowParent)
let pc = highParent.children.slice(0, idx)
let ac = highParent.children.slice(idx + 1)
- if (is.inline(lowParent.type)) {
+ if (is.inline(lowParent)) {
leftNode = u(lowParent.type, [...nextpc, leftNode])
rightNode = u(lowParent.type, [rightNode, ...nextac])
}
nextpc = pc
nextac = ac
- if (is.block(lowParent.type)) {
+ if (is.block(lowParent)) {
break
}
}
diff --git a/src/ast/transform/delete-content-backward.ts b/src/ast/transform/delete-content-backward.ts
new file mode 100644
index 0000000..64abc9c
--- /dev/null
+++ b/src/ast/transform/delete-content-backward.ts
@@ -0,0 +1,53 @@
+import type {TransformHandler} from "."
+import * as md from "mdast"
+import visitParents from "unist-util-visit-parents"
+import backspaceParagraph from "../backspace-paragraph"
+import * as is from "../is"
+import unwrap from "../unwrap"
+
+let deleteContentBackward: TransformHandler = (root, options) => {
+ let startNode = options.start.node
+ let endNode = options.end.node
+ if (is.leaf(startNode) && is.inline(startNode) && is.block(endNode)) {
+ backspaceParagraph(root, (endNode as unknown) as md.Paragraph)
+ return
+ }
+
+ visitParents(
+ root,
+ startNode as md.Text,
+ (node, parents) => {
+ let directParent = parents[parents.length - 1]
+
+ if (is.textish(endNode)) {
+ if (options.end.offset == endNode.value.length) {
+ if (is.unwrappable(endNode)) {
+ unwrap(root, endNode)
+ return
+ } else if (is.unwrappable(directParent)) {
+ unwrap(root, directParent)
+ return
+ }
+ }
+ }
+ if (
+ startNode == endNode &&
+ is.textish(startNode) &&
+ is.textish(endNode)
+ ) {
+ startNode.value =
+ startNode.value.slice(0, options.start.offset) +
+ startNode.value.slice(options.end.offset)
+
+ startNode.data = {
+ caret: {
+ caretStart: options.start.offset,
+ caretEnd: options.start.offset,
+ },
+ }
+ }
+ },
+ true
+ )
+}
+export default deleteContentBackward
diff --git a/src/ast/transform/index.ts b/src/ast/transform/index.ts
index 3ea2167..a513472 100644
--- a/src/ast/transform/index.ts
+++ b/src/ast/transform/index.ts
@@ -1,13 +1,17 @@
import * as md from "mdast"
-import {CaretIdInstruction} from "../caret"
-import BeforeInputEvent, {InputType} from "../before-input-event"
+import {InputType} from "../../events/before-input-event"
import insertText from "./insert-text"
+import insertParagraph from "./insert-paragraph"
import visit from "unist-util-visit"
import type * as unist from "unist"
-import {produce} from "immer"
+import {DataCaret} from "../../caret"
+import deleteContentBackward from "./delete-content-backward"
+import * as is from "../is"
+import visitParents from "unist-util-visit-parents"
+import {Data} from "electron/main"
export interface TransformOptions {
- data: string
+ detail: string | md.Root | md.Content
inputType: InputType
start: {
path: string
@@ -19,198 +23,190 @@ export interface TransformOptions {
}
}
-export let nothing = Symbol("@transform/don't-actually")
-
-type TransformResult = CaretIdInstruction | typeof nothing
-
interface TransformHandlers {
[key: string]: TransformHandler
}
+export let nothing = Symbol("@transform/don't-actually")
+
export interface TransformHandler {
- (root: md.Root, options: TransformHandlerOptions): TransformResult
+ (root: md.Root, options: TransformHandlerOptions): void | typeof nothing
+}
+
+function restoreCaret(options: TransformHandlerOptions): void {
+ if (!options.start.node.data?.caret) {
+ let caret: Partial = {}
+ options.start.node.data = {caret}
+ }
+ if (!options.end.node.data?.caret) {
+ let caret: Partial = {}
+ options.end.node.data = {caret}
+ }
+ let startCaret: Partial = options.start.node.data.caret
+ startCaret.caretStart = options.start.offset
+ let endCaret: Partial = options.end.node.data.caret
+ endCaret.caretEnd = options.end.offset
}
export let handlers: TransformHandlers = {
insertReplacementText(root, options) {
- console.error(`unhandled inputType`)
- return nothing
+ if (typeof options.start.node.value == "string") {
+ options.end.offset = options.start.offset = options.data.length
+ }
+ options.start.node.value = options.data
+ let caret: DataCaret = {
+ caretStart: options.data.length,
+ caretEnd: options.data.length,
+ }
+ options.start.node.data = {
+ caret,
+ }
},
insertText,
insertLineBreak(root, options) {
- console.error(`unhandled inputType`)
- return nothing
- },
- insertParagraph(root, options) {
- console.error(`unhandled inputType`)
- return nothing
- },
- deleteContentBackward(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
+ insertParagraph,
+ deleteContentBackward,
deleteContentForward(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteByCut(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertOrderedList(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertUnorderedList(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertHorizontalRule(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertFromYank(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertFromDrop(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertFromPaste(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertFromPasteAsQuotation(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertTranspose(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertCompositionText(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
insertLink(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteWordBackward(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteWordForward(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteSoftLineBackward(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteSoftLineForward(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteEntireSoftLine(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteHardLineBackward(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteHardLineForward(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteByDrag(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
deleteContent(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
historyUndo(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
historyRedo(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatBold(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatItalic(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatUnderline(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatStrikeThrough(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatSuperscript(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatSubscript(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatJustifyFull(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatJustifyCenter(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatJustifyRight(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatJustifyLeft(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatIndent(root, options) {
- console.error(`unhandled inputType`)
+ // TODO lists
+ visitParents(root, options.start.node, (node, parents) => {
+ for (let p of parents) {
+ if (p.type == "heading") {
+ if (p.depth < 6) p.depth += 1
+ restoreCaret(options)
+ }
+ }
+ })
return nothing
},
formatOutdent(root, options) {
- console.error(`unhandled inputType`)
+ // TODO lists
+ visitParents(root, options.start.node, (node, parents) => {
+ for (let p of parents) {
+ if (p.type == "heading") {
+ if (p.depth > 1) p.depth -= 1
+ restoreCaret(options)
+ }
+ }
+ })
return nothing
},
formatRemove(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatSetBlockTextDirection(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatSetInlineTextDirection(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatBackColor(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatFontColor(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
formatFontName(root, options) {
- console.error(`unhandled inputType`)
return nothing
},
}
@@ -218,15 +214,33 @@ export let handlers: TransformHandlers = {
export interface TransformHandlerOptions {
data: string
start: {
- node: md.Content
+ node: unist.Node
offset: number
}
end: {
- node: md.Content
+ node: unist.Node
offset: number
}
}
+function getFromPath(root: md.Root, path: string): md.Text | md.InlineCode {
+ let parts = path.slice(1).split(".").map(Number)
+ let node: unist.Node = root
+ while (parts.length) {
+ if (!Array.isArray(node.children)) {
+ throw new TypeError("no chilcren")
+ }
+ let idx = parts.shift()
+ node = node.children[idx]
+ }
+ if (node.type != "text" && node.type != "inlineCode") {
+ throw new Error(
+ `path must lead to text or inline code, led to: ${node.type}`
+ )
+ }
+ return node as md.Text | md.InlineCode
+}
+
export default function transform(
root: md.Root,
options: TransformOptions
@@ -246,9 +260,7 @@ export default function transform(
})
let startParts = options.start.path.slice(1).split(".").map(Number)
- console.log(startParts)
let startNode: unist.Node = root
-
while (startParts.length) {
if (!Array.isArray(startNode.children)) {
throw new TypeError("no chilcren")
@@ -256,6 +268,7 @@ export default function transform(
let idx = startParts.shift()
startNode = startNode.children[idx]
}
+
let endParts = options.end.path.slice(1).split(".").map(Number)
let endNode: unist.Node = root
while (endParts.length) {
@@ -265,17 +278,19 @@ export default function transform(
endNode = endNode.children[endParts.shift()]
}
- let opts = {
- data: options.data,
+ let handlerOptions = {
+ data: options.detail,
start: {
- node: startNode as md.Content,
+ node: startNode as md.Text | md.InlineCode,
offset: options.start.offset,
},
end: {
- node: endNode as md.Content,
+ node: endNode as md.Text | md.InlineCode,
offset: options.end.offset,
},
}
- handler(root, opts)
+ if (handler(root, handlerOptions) == nothing) {
+ console.error(`unhandled inputType: ${options.inputType}`)
+ }
}
diff --git a/src/ast/transform/insert-paragraph.ts b/src/ast/transform/insert-paragraph.ts
new file mode 100644
index 0000000..bbf88dd
--- /dev/null
+++ b/src/ast/transform/insert-paragraph.ts
@@ -0,0 +1,21 @@
+import type {TransformHandler} from "."
+// TODO move _insertParagraph in here :D
+import _insertParagraph from "../insert-paragraph"
+import * as md from "mdast"
+import visitParents from "unist-util-visit-parents"
+
+let insertParagraph: TransformHandler = (root, options) => {
+ let startNode = options.start.node
+ let endNode = options.end.node
+
+ visitParents(root, startNode as md.Text, (node, parents) => {
+ parents.reverse()
+ let list = parents.find(p => p.type == "list")
+ })
+
+ if (startNode == endNode && typeof startNode.value == "string") {
+ startNode = startNode as md.Text
+ _insertParagraph(root, startNode, options.start.offset)
+ }
+}
+export default insertParagraph
diff --git a/src/ast/transform/insert-text.ts b/src/ast/transform/insert-text.ts
index 89e22f9..64a1ad8 100644
--- a/src/ast/transform/insert-text.ts
+++ b/src/ast/transform/insert-text.ts
@@ -1,22 +1,82 @@
import type {TransformHandler} from "."
-import {visit} from "unist-utils-core"
-import {produce} from "immer"
+import inviteParentsOverForDinner from "unist-util-parents"
+import {find} from "unist-utils-core"
+import * as md from "mdast"
+import * as m from "mdast-builder"
+import {DataCaret} from "../../caret"
+import * as is from "../is"
let insertText: TransformHandler = (root, options) => {
let startNode = options.start.node
let endNode = options.end.node
- if (startNode == endNode && typeof startNode.value == "string") {
+ let treeWithParents = inviteParentsOverForDinner(root)
+ let node = find(treeWithParents, startNode)
+ let parent = node.parent
+ let index = parent.children.indexOf(node)
+
+ if (index == 0 && options.start.offset == 0) {
+ if (options.data == "#") {
+ if (parent.type == "paragraph") {
+ parent = parent as md.Heading
+ ;(parent.node as md.Heading).type = "heading"
+ ;(parent.node as md.Heading).depth = 1
+ return
+ } else if (parent.type == "heading") {
+ parent = parent as md.Heading
+ if (parent.depth < 6) {
+ ;(parent.node as md.Heading).depth += 1
+ return
+ }
+ }
+ }
+
+ if (options.data == "." || options.data == "-") {
+ if (parent.type == "paragraph") {
+ let pnode = parent.node as md.List
+ pnode.type = "list"
+ pnode.ordered = options.data == "."
+ pnode.children = [
+ m.listItem(m.paragraph(pnode.children)) as md.ListItem,
+ ]
+ return
+ }
+ }
+ }
+
+ // TODO this will involve splitting the text node and inserting an insertCode
+ // if (options.data == "`") {
+ // make up my own inputTypes? why not
+ // tranformHandlers.formatCode(options)
+ // }
+ // TODO this will involve splitting the text node and inserting an emphasis
+ // if (options.data == "_") {
+ // transformHandlers.formatItalic(options)
+ // }
+ // TODO this will involve splitting the text node and inserting a strong
+ // if (options.data == "*") {
+ // transformHandlers.formatBold(options)
+ //}
+
+ if (startNode == endNode) {
if (!startNode.data) {
startNode.data = {}
}
- startNode.data.caret = {
- type: "collapsed",
- offset: options.start.offset + 1,
+
+ let caret: DataCaret = {
+ caretStart: options.start.offset + options.data.length,
+ caretEnd: options.start.offset + options.data.length,
+ }
+
+ startNode.data.caret = caret
+
+ if (is.leaf(startNode) && is.inline(startNode)) {
+ startNode.value =
+ startNode.value.slice(0, options.start.offset) +
+ options.data +
+ startNode.value.slice(options.end.offset)
+ } else {
+ throw new Error("start node isn't inline??")
}
- startNode.value =
- startNode.value.slice(0, options.start.offset) +
- options.data +
- startNode.value.slice(options.end.offset)
}
}
export default insertText
diff --git a/src/ast/unwrap.ts b/src/ast/unwrap.ts
index fde5655..9d3a27d 100644
--- a/src/ast/unwrap.ts
+++ b/src/ast/unwrap.ts
@@ -3,43 +3,58 @@ import * as unist from "unist"
import * as md from "mdast"
import u from "unist-builder"
import * as is from "./is"
+import compact from "mdast-util-compact"
export type Unwrappable = md.Emphasis | md.Strong | md.Delete | md.InlineCode
-export default function unwrap(
- root: md.Parent,
- target: md.InlineCode,
- offset: number
-): [unist.Node, unist.Node] {
- let leftText = target.value.slice(0, offset)
- let rightText = target.value.slice(offset)
-
- let leftNode: unist.Node = u(target.type, leftText)
- let rightNode: unist.Node = u(target.type, rightText)
-
+export default function unwrap(root: md.Parent, target: Unwrappable): void {
visit(root, target, (node, index, parents) => {
- let firstp = parents[parents.length - 1]
- let nextpc = firstp.children.slice(0, index)
- let nextac = firstp.children.slice(index + 1)
- for (let i = parents.length - 1; i > 0; i--) {
- let highParent = parents[i - 1]
- let lowParent = parents[i]
- let idx = highParent.children.indexOf(lowParent)
- let pc = highParent.children.slice(0, idx)
- let ac = highParent.children.slice(idx + 1)
- if (is.inline(lowParent.type)) {
- leftNode = u(lowParent.type, [...nextpc, leftNode])
- rightNode = u(lowParent.type, [rightNode, ...nextac])
- }
- nextpc = pc
- nextac = ac
- if (is.block(lowParent.type)) {
- break
+ if (is.inline(node)) {
+ let directParent = parents[parents.length - 1]
+ if (is.container(node)) {
+ directParent.children.splice(index, 1, ...node.children)
+ node.children[node.children.length - 1].data = {
+ caret: {
+ caretStart: node.children[node.children.length - 1].value.length,
+ caretEnd: node.children[node.children.length - 1].value.length,
+ },
+ }
+ } else if (node.type == "inlineCode") {
+ ;((node as unknown) as md.Text).type = "text"
+ node.data = {
+ caret: {
+ caretStart: node.value.length,
+ caretEnd: node.value.length,
+ },
+ }
}
- }
- return EXIT
+ // TODO this flatten-text might be over the top, or needed elsewhere
+ directParent.children = directParent.children.reduce(
+ (children, next) => {
+ if (children.length) {
+ let previous = children[children.length - 1]
+ if (next.type == "text" && previous.type == "text") {
+ if (next.data?.caret) {
+ previous.data = {
+ caret: {
+ caretStart:
+ previous.value.length + next.data.caret.caretStart,
+ caretEnd: previous.value.length + next.data.caret.caretEnd,
+ },
+ }
+ }
+ previous.value += next.value
+ return children
+ } else {
+ return children.concat(next)
+ }
+ } else {
+ return children.concat(next)
+ }
+ },
+ []
+ )
+ }
})
-
- return [leftNode, rightNode]
}
diff --git a/src/caret.ts b/src/caret.ts
new file mode 100644
index 0000000..68b50c2
--- /dev/null
+++ b/src/caret.ts
@@ -0,0 +1,4 @@
+export interface DataCaret {
+ caretStart: number | null
+ caretEnd: number | null
+}
diff --git a/src/default-doc.ts b/src/default-doc.ts
index dc5176d..5d04b93 100644
--- a/src/default-doc.ts
+++ b/src/default-doc.ts
@@ -1,7 +1,8 @@
-export default `# hello \`this\` and _that_ (and \`others\`)
+import compact from "mdast-util-compact"
-this is an _ordinary **\`document\` about** ordinary_ things, there's **nothing _going_ on**
-here of _interest to you_, or me, or anybody else.
+export default compact(`# hello \`this\` and _that_ (and \`others\`)
+
+this is an _ordinary **\`document\` about** ordinary_ things, there's **nothing _going_ on** here of _interest to you_, or me, or anybody else.
## a list
@@ -32,4 +33,4 @@ auto sum(std::vector nums) {
return result;
}
\`\`\`
-`
+`)
diff --git a/src/dom/get-transform-options.ts b/src/dom/get-transform-options.ts
new file mode 100644
index 0000000..207612b
--- /dev/null
+++ b/src/dom/get-transform-options.ts
@@ -0,0 +1,71 @@
+import type {TransformOptions} from "../ast/transform"
+import {InputType} from "../events/before-input-event"
+import MayoNodeElement from "../elements/mayo-node"
+import htmlToHast from "rehype-parse"
+import hastToMdast from "hast-util-to-mdast"
+import unified from "unified"
+
+export interface GetTransformOptionsOptions {
+ inputType: InputType
+ range: StaticRange
+ data?: string
+ dataTransfer?: DataTransfer
+}
+
+export default async function getTransformOptions({
+ inputType,
+ range,
+ data,
+ dataTransfer,
+}: GetTransformOptionsOptions): Promise {
+ let start = range.startContainer.parentElement as MayoNodeElement
+ let end = range.endContainer.parentElement as MayoNodeElement
+ let detail = data
+ if (inputType == "insertReplacementText") {
+ // i'm going to regret this
+ // instead i should be creating a placeholder element
+ detail = await new Promise(yay => dataTransfer.items[0].getAsString(yay))
+ }
+
+ if (inputType == "insertFromPaste") {
+ let items = Array.from(dataTransfer.items)
+ let imageItem = items.find(item => item.type.startsWith("image"))
+ let htmlItem = items.find(item => item.type == "text/html")
+ let textItem = items.find(item => item.type == "text/plain")
+ if (imageItem) {
+ // TODO we copy the image
+ }
+
+ if (htmlItem) {
+ detail = await new Promise(yay => htmlItem.getAsString(yay)).then(
+ string => {
+ let hast = unified().use(htmlToHast).parse(string)
+ return hastToMdast(hast)
+ }
+ )
+ } else if (textItem) {
+ detail = await new Promise(yay => textItem.getAsString(yay))
+ inputType = "insertText"
+ }
+ }
+
+ if (start.tagName.toLowerCase() != "mayo-node") {
+ start = start.closest("mayo-node")
+ }
+ if (end.tagName.toLowerCase() != "mayo-node") {
+ end = end.closest("mayo-node")
+ }
+
+ return {
+ detail,
+ start: {
+ path: start.path,
+ offset: range.startOffset,
+ },
+ end: {
+ path: end.path,
+ offset: range.endOffset,
+ },
+ inputType: inputType,
+ }
+}
diff --git a/src/elements/index.ts b/src/elements/index.ts
deleted file mode 100644
index 9ace88d..0000000
--- a/src/elements/index.ts
+++ /dev/null
@@ -1,121 +0,0 @@
-import MayoBreakElement from "./markdown/mayo-break"
-import MayoCodeElement from "./markdown/mayo-code"
-import MayoInlineCodeElement from "./markdown/mayo-inline-code"
-import MayoDeleteElement from "./markdown/mayo-delete"
-import MayoEmphasisElement from "./markdown/mayo-emphasis"
-import MayoHeadingElement from "./markdown/mayo-heading"
-import MayoThematicBreakElement from "./markdown/mayo-thematic-break"
-import MayoHtmlElement from "./markdown/mayo-html"
-import MayoImageElement from "./markdown/mayo-image"
-import MayoImageReferenceElement from "./markdown/mayo-image-reference"
-import MayoListItemElement from "./markdown/mayo-list-item"
-import MayoLinkElement from "./markdown/mayo-link"
-import MayoLinkReferenceElement from "./markdown/mayo-link-reference"
-import MayoListElement from "./markdown/mayo-list"
-import MayoParagraphElement from "./markdown/mayo-paragraph"
-import MayoBlockquoteElement from "./markdown/mayo-blockquote"
-import MayoStrongElement from "./markdown/mayo-strong"
-import MayoTableElement from "./markdown/mayo-table"
-import MayoTextElement from "./markdown/mayo-text"
-import MayoTomlElement from "./markdown/mayo-toml"
-import MayoYamlElement from "./markdown/mayo-yaml"
-
-import MayoNodeElement from "./mayo-node"
-
-import MayoKillerElement from "./mayo-killer"
-
-import MayoAppElement from "./mayo-app"
-import MayoSidebarElement from "./mayo-sidebar"
-import MayoSidebarFileElement from "./mayo-sidebar-file"
-import MayoSidebarTreeElement from "./mayo-sidebar-tree"
-import MayoDocumentElement from "./mayo-document"
-
-export type MayoStaticPhrasingContentElement =
- | MayoBreakElement
- | MayoEmphasisElement
- | MayoHtmlElement
- | MayoImageElement
- | MayoImageReferenceElement
- | MayoInlineCodeElement
- | MayoStrongElement
- | MayoTextElement
-
-export type MayoPhrasingContentElement =
- | MayoLinkElement
- | MayoLinkReferenceElement
- | MayoStaticPhrasingContentElement
-
-export type MayoListContentElement = MayoListItemElement
-
-export type MayoFlowContentElement =
- | MayoBlockquoteElement
- | MayoCodeElement
- | MayoHeadingElement
- | MayoHtmlElement
- | MayoListElement
- | MayoThematicBreakElement
- | MayoParagraphElement
-
-export type MayoContentElement =
- | MayoFlowContentElement
- | MayoListContentElement
- | MayoPhrasingContentElement
-
-export type {
- MayoDocumentElement as MayoDocumentElement,
- MayoKillerElement,
- MayoSidebarElement,
- MayoSidebarFileElement,
- MayoSidebarTreeElement,
- MayoBreakElement,
- MayoCodeElement,
- MayoDeleteElement,
- MayoEmphasisElement,
- MayoHeadingElement,
- MayoInlineCodeElement,
- MayoThematicBreakElement,
- MayoHtmlElement,
- MayoImageElement,
- MayoImageReferenceElement,
- MayoListItemElement,
- MayoLinkElement,
- MayoLinkReferenceElement,
- MayoListElement,
- MayoParagraphElement,
- MayoBlockquoteElement,
- MayoStrongElement,
- MayoTableElement,
- MayoTextElement,
- MayoTomlElement,
- MayoYamlElement,
-}
-
-export default [
- MayoNodeElement,
- MayoAppElement,
- MayoDocumentElement,
- MayoSidebarElement,
- MayoSidebarFileElement,
- MayoSidebarTreeElement,
- MayoBreakElement,
- MayoCodeElement,
- MayoInlineCodeElement,
- MayoDeleteElement,
- MayoEmphasisElement,
- MayoHeadingElement,
- MayoThematicBreakElement,
- MayoHtmlElement,
- MayoImageElement,
- MayoImageReferenceElement,
- MayoListItemElement,
- MayoLinkElement,
- MayoLinkReferenceElement,
- MayoListElement,
- MayoParagraphElement,
- MayoBlockquoteElement,
- MayoStrongElement,
- MayoTableElement,
- MayoTextElement,
- MayoTomlElement,
- MayoYamlElement,
-]
diff --git a/src/elements/markdown/mayo-blockquote.ts b/src/elements/markdown/mayo-blockquote.ts
deleted file mode 100644
index 070cf7d..0000000
--- a/src/elements/markdown/mayo-blockquote.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import * as md from "mdast"
-import {MayoParentElement} from "./mayo-element"
-export default class MayoBlockquoteElement extends MayoParentElement {
- connectedCallback() {}
-}
diff --git a/src/elements/markdown/mayo-break.ts b/src/elements/markdown/mayo-break.ts
deleted file mode 100644
index df44eef..0000000
--- a/src/elements/markdown/mayo-break.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import * as md from "mdast"
-import {MayoEmptyElement} from "./mayo-element"
-export default class MayoBreakElement extends MayoEmptyElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-code.ts b/src/elements/markdown/mayo-code.ts
deleted file mode 100644
index 1e6fe3f..0000000
--- a/src/elements/markdown/mayo-code.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import * as md from "mdast"
-import {MayoLiteralElement} from "./mayo-element"
-
-export default class MayoCodeElement extends MayoLiteralElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-delete.ts b/src/elements/markdown/mayo-delete.ts
deleted file mode 100644
index aa132fa..0000000
--- a/src/elements/markdown/mayo-delete.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import * as md from "mdast"
-import {MayoParentElement} from "./mayo-element"
-
-export default class MayoDeleteElement extends MayoParentElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-element.ts b/src/elements/markdown/mayo-element.ts
deleted file mode 100644
index 23bd16d..0000000
--- a/src/elements/markdown/mayo-element.ts
+++ /dev/null
@@ -1,213 +0,0 @@
-import type * as md from "mdast"
-import type * as unist from "unist"
-import split from "../../ast/split"
-import {MayoContentElement} from ".."
-import {CaretInstruction} from "../../caret"
-export abstract class MayoElement<
- AstNodeType extends unist.Node
-> extends HTMLElement {
- node: AstNodeType
- get value(): string | undefined {
- return this.getAttribute("value")
- }
-
- get type(): string | undefined {
- return this.getAttribute("type")
- }
-
- get block(): boolean {
- return this.hasAttribute("block")
- }
-
- get leaf(): boolean {
- return this.hasAttribute("leaf")
- }
-
- get container(): boolean {
- return this.hasAttribute("container")
- }
-
- get inline(): boolean {
- return this.hasAttribute("inline")
- }
-
- get interestingChildren(): Node[] {
- return Array.from(this.childNodes).filter(
- n => "node" in n || n.nodeName == "#text"
- )
- }
- /**
- * Insert text when the range start and end are both in a single element
- * @param text the text to insert
- * @param range the selected range, which may be of interest
- */
- abstract selfInsertText(text: string, range: StaticRange): CaretInstruction
-
- connectedCallback(): void {
- return void void 0
- }
-}
-
-export class MayoEmptyElement<
- AstNodeType extends
- | md.ImageReference
- | md.LinkReference
- | md.Link
- | md.Break
- | md.ThematicBreak
- | md.Image
-> extends MayoElement {
- selfDeleteContentBackward(r: StaticRange): void {
- throw new TypeError()
- }
- selfInsertText(_text: string, _range: StaticRange): CaretInstruction {
- throw new Error("empty elements")
- }
-}
-
-export class MayoLiteralElement<
- AstNodeType extends md.Literal
-> extends MayoElement {
- insertText(selection: Selection, event: InputEvent) {
- let special = event.data!.match(/[~`*_]/)
- if (special) {
- console.log(this.nodeValue, this.node.value)
- } else {
- this.node.value = selection.focusNode!.nodeValue || ""
- return true
- }
- }
-
- selfInsertText(text: string, range: StaticRange): CaretInstruction {
- this.node.value =
- this.node.value.slice(0, range.startOffset) +
- text +
- this.node.value.slice(range.endOffset)
- return {
- type: "text",
- element: this.interestingChildren[0] as Text,
- startOffset: range.startOffset + 1,
- }
- }
-
- selfDeleteContentBackward(range: StaticRange): CaretInstruction {
- this.node.value =
- this.node.value.slice(0, range.startOffset) +
- this.node.value.slice(range.endOffset)
- return {
- type: "text",
- element: this.interestingChildren[0] as Text,
- startOffset: range.startOffset,
- }
- }
-}
-
-export class MayoParentElement<
- AstNodeType extends md.Parent
-> extends MayoElement {
- atBeginningOfBlock(range: StaticRange): boolean {
- return (
- range.collapsed &&
- this.interestingChildren.indexOf(range.startContainer) == 0 &&
- range.startOffset == 0
- )
- }
-
- selfInsertText(text: string, range: StaticRange): CaretInstruction {
- // TODO if the character is special, and the range is !caret then wrap the selected area
- let targetTextNode = range.startContainer
- let targetIndex = this.interestingChildren.indexOf(targetTextNode)
- if (targetIndex == -1) {
- throw new Error(`${targetTextNode} is not a child of ${this}`)
- }
-
- let targetAstNode = this.node.children[targetIndex]
- if (targetAstNode.type != "text") {
- throw new Error(
- `expected the ast node to be of type text, got ${targetAstNode.type}`
- )
- }
- targetAstNode.value =
- targetAstNode.value.slice(0, range.startOffset) +
- text +
- targetAstNode.value.slice(range.endOffset)
-
- let caret = {
- type: "parent" as const,
- parent: this,
- index: targetIndex,
- startOffset: range.startOffset + 1,
- }
-
- return caret
- }
-
- insertTextAsCommonAncestor(
- startElement: MayoContentElement,
- endElement: MayoContentElement,
- text: string,
- range: StaticRange
- ): CaretInstruction {
- // This is tricky for me right now
- // but, what i want to to i think is
- // to move the startNode and endNode (which are both text nodes) up to being direct
- // children of `this`, removing the other nodes between start and end
- // and then merging them if they're the same type...
- // i think.
- // i think.
- // TODO write a
-
- let startVal = range.startContainer.nodeValue?.slice(0, range.startOffset)
- let endVal = range.endContainer.nodeValue?.slice(range.endOffset)
-
- let startChildIndex = startElement.interestingChildren.indexOf(
- range.startContainer
- )
- let endChildIndex = endElement.interestingChildren.indexOf(
- range.endContainer
- )
- let startIndex = this.interestingChildren.indexOf(startElement)
- let endIndex = this.interestingChildren.indexOf(endElement)
- let snode
- if (startChildIndex != -1 && Array.isArray(startElement.node.children)) {
- snode = startElement.node.children[startChildIndex]
- } else {
- snode = startElement.node
- }
-
- let child = startElement.firstChild
- if (child.nodeName == "#text") {
- let element = child as Text
- return {type: "text", element, startOffset: 0}
- }
- }
-
- insertParagraph(range: StaticRange) {}
-
- selfDeleteContentBackward(range: StaticRange): CaretInstruction {
- let targetTextNode = range.startContainer
- let targetIndex = this.interestingChildren.indexOf(targetTextNode)
- if (targetIndex == -1) {
- throw new Error(`${targetTextNode} is not a child of ${this}`)
- }
-
- let targetAstNode = this.node.children[targetIndex]
- if (targetAstNode.type != "text") {
- throw new Error(
- `expected the ast node to be of type text, got ${targetAstNode.type}`
- )
- }
- targetAstNode.value =
- targetAstNode.value.slice(0, range.startOffset) +
- targetAstNode.value.slice(range.endOffset)
-
- let caret = {
- type: "parent" as const,
- parent: this,
- index: targetIndex,
- startOffset: range.startOffset,
- }
-
- return caret
- }
-}
diff --git a/src/elements/markdown/mayo-emphasis.ts b/src/elements/markdown/mayo-emphasis.ts
deleted file mode 100644
index be1eb8e..0000000
--- a/src/elements/markdown/mayo-emphasis.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import {MayoParentElement} from "./mayo-element"
-import type * as md from "mdast"
-
-export default class MayoEmphasisElement extends MayoParentElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-heading.ts b/src/elements/markdown/mayo-heading.ts
deleted file mode 100644
index b11c04d..0000000
--- a/src/elements/markdown/mayo-heading.ts
+++ /dev/null
@@ -1,50 +0,0 @@
-import {customElement, LitElement} from "lit-element"
-import {html} from "lit-html"
-
-@customElement("mayo-heading")
-export default class MayoHeadingElement extends LitElement {
- render() {
- return html`hello`
- }
- // get depth(): Depth {
- // return this.node.depth
- // }
- // set depth(val: Depth) {
- // this.node.depth = val
- // }
- // selfInsertText(text: string, range: StaticRange): CaretInstruction {
- // if (text == "#" && this.atBeginningOfBlock(range)) {
- // if (this.depth < 6) {
- // this.depth += 1
- // }
- // return {
- // type: "parent",
- // parent: this,
- // index: 0,
- // startOffset: 0,
- // }
- // }
- // return super.selfInsertText(text, range)
- // }
- // selfDeleteContentBackward(range: StaticRange): CaretInstruction {
- // if (this.atBeginningOfBlock(range)) {
- // let id = shortid()
- // this.node.id = id
- // if (this.depth > 1) {
- // this.depth -= 1
- // } else {
- // // @ts-ignore
- // this.node.type = "paragraph"
- // delete this.node.depth
- // }
- // return {
- // type: "id",
- // id,
- // index: 0,
- // startOffset: 0,
- // }
- // }
- // let caret = super.selfDeleteContentBackward(range)
- // return caret
- // }
-}
diff --git a/src/elements/markdown/mayo-html.ts b/src/elements/markdown/mayo-html.ts
deleted file mode 100644
index 3827fea..0000000
--- a/src/elements/markdown/mayo-html.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import type * as md from "mdast"
-import {MayoLiteralElement} from "./mayo-element"
-
-export default class MayoHtmlElement extends MayoLiteralElement {
- connectedCallback() {
- super.connectedCallback()
- this.innerHTML = this.textContent || ""
- }
-}
diff --git a/src/elements/markdown/mayo-image-reference.ts b/src/elements/markdown/mayo-image-reference.ts
deleted file mode 100644
index 493e43e..0000000
--- a/src/elements/markdown/mayo-image-reference.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import * as md from "mdast"
-import {MayoEmptyElement} from "./mayo-element"
-export default class MayoImageReferenceElement extends MayoEmptyElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-image.ts b/src/elements/markdown/mayo-image.ts
deleted file mode 100644
index 275315d..0000000
--- a/src/elements/markdown/mayo-image.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import * as md from "mdast"
-import {MayoEmptyElement} from "./mayo-element"
-export default class MayoImageElement extends MayoEmptyElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-inline-code.ts b/src/elements/markdown/mayo-inline-code.ts
deleted file mode 100644
index 57468ab..0000000
--- a/src/elements/markdown/mayo-inline-code.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import {MayoLiteralElement} from "./mayo-element"
-import * as md from "mdast"
-export default class MayoInlineCodeElement extends MayoLiteralElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-link-reference.ts b/src/elements/markdown/mayo-link-reference.ts
deleted file mode 100644
index 74ae3fa..0000000
--- a/src/elements/markdown/mayo-link-reference.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import * as md from "mdast"
-import {MayoEmptyElement} from "./mayo-element"
-export default class MayoLinkReferenceElement extends MayoEmptyElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-link.ts b/src/elements/markdown/mayo-link.ts
deleted file mode 100644
index 3aef3b5..0000000
--- a/src/elements/markdown/mayo-link.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import * as md from "mdast"
-import {MayoEmptyElement} from "./mayo-element"
-export default class MayoLinkElement extends MayoEmptyElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-list-item.ts b/src/elements/markdown/mayo-list-item.ts
deleted file mode 100644
index 3e44a23..0000000
--- a/src/elements/markdown/mayo-list-item.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import {MayoParentElement} from "./mayo-element"
-import * as md from "mdast"
-import shortid from "shortid"
-import {CaretInstruction} from "../../caret"
-
-export default class MayoListItemElement extends MayoParentElement {
- selfDeleteContentBackward(range: StaticRange): CaretInstruction {
- if (this.atBeginningOfBlock(range)) {
- let id = shortid()
- this.node.id = id
- return {
- type: "id",
- id,
- index: 0,
- startOffset: 0,
- }
- }
- let caret = super.selfDeleteContentBackward(range)
- return caret
- }
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-list.ts b/src/elements/markdown/mayo-list.ts
deleted file mode 100644
index 2252cfd..0000000
--- a/src/elements/markdown/mayo-list.ts
+++ /dev/null
@@ -1,45 +0,0 @@
-import {MayoParentElement} from "./mayo-element"
-import * as md from "mdast"
-import shortid from "shortid"
-import {CaretInstruction} from "../../caret"
-
-export default class MayoListElement extends MayoParentElement {
- selfDeleteContentBackward(range: StaticRange): CaretInstruction {
- let targetNode = range.startContainer
- let targetIndex = this.interestingChildren.indexOf(targetNode)
- if (targetIndex == -1) {
- throw new Error(`${targetNode} is not a child of ${this}`)
- }
-
- let targetAstNode = this.node.children[targetIndex]
- let previousAstNode = this.node.children[targetIndex - 1]
-
- if (previousAstNode) {
- let index = previousAstNode.children.length
- let [first] = targetAstNode.children
- previousAstNode.children.splice(Infinity, 0, ...targetAstNode.children)
- let id = shortid()
- first.id = id
-
- return {
- type: "id",
- id,
- index: 0,
- startOffset: 0,
- }
- } else {
- // hello
- return
- }
-
- if (this.atBeginningOfBlock(range)) {
- let id = shortid()
- this.node.id = id
- }
- let caret = super.selfDeleteContentBackward(range)
- return caret
- }
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-paragraph.ts b/src/elements/markdown/mayo-paragraph.ts
deleted file mode 100644
index da5c3cb..0000000
--- a/src/elements/markdown/mayo-paragraph.ts
+++ /dev/null
@@ -1,67 +0,0 @@
-import {MayoParentElement} from "./mayo-element"
-import * as md from "mdast"
-import u from "unist-builder"
-import {CaretInstruction} from "../../caret"
-import shortid from "shortid"
-
-export default class MayoParagraphElement extends MayoParentElement {
- selfInsertText(text: string, range: StaticRange): CaretInstruction {
- let atBeginning = this.atBeginningOfBlock(range)
-
- let id = shortid()
- let caret: CaretInstruction = {
- type: "id",
- id,
- index: 0,
- startOffset: 0,
- }
-
- if (atBeginning) {
- switch (text) {
- case "#": {
- this.node.depth = 1
- // @ts-ignore
- this.node.type = "heading"
- this.node.id = id
- return caret
- }
- case ">": {
- this.node.children = [
- // @ts-ignore
- {
- ...this.node,
- id,
- },
- ]
- // @ts-ignore
- this.node.type = "blockquote"
- return caret
- }
- case "-": {
- this.node.children = [
- // @ts-ignore
- u("listItem", [{...this.node, id}]),
- ]
- // @ts-ignore
- this.node.type = "list"
- this.node.ordered = false
- return caret
- }
- case ".": {
- this.node.children = [
- // @ts-ignore
- u("listItem", [{...this.node, id}]),
- ]
- // @ts-ignore
- this.node.type = "list"
- this.node.ordered = true
- return caret
- }
- }
- }
- return super.selfInsertText(text, range)
- }
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-strong.ts b/src/elements/markdown/mayo-strong.ts
deleted file mode 100644
index 8d98c73..0000000
--- a/src/elements/markdown/mayo-strong.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import {MayoParentElement} from "./mayo-element"
-import * as md from "mdast"
-
-export default class MayoStrongElement extends MayoParentElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-table.ts b/src/elements/markdown/mayo-table.ts
deleted file mode 100644
index 54a392b..0000000
--- a/src/elements/markdown/mayo-table.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import {MayoParentElement} from "./mayo-element"
-import * as md from "mdast"
-
-export default class MayoTableElement extends MayoParentElement {
- connectedCallback() {}
-}
diff --git a/src/elements/markdown/mayo-text.ts b/src/elements/markdown/mayo-text.ts
deleted file mode 100644
index 8dae180..0000000
--- a/src/elements/markdown/mayo-text.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import {MayoLiteralElement} from "./mayo-element"
-import * as md from "mdast"
-export default class MayoTextElement extends MayoLiteralElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-thematic-break.ts b/src/elements/markdown/mayo-thematic-break.ts
deleted file mode 100644
index 481e1bb..0000000
--- a/src/elements/markdown/mayo-thematic-break.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import * as md from "mdast"
-import {MayoEmptyElement} from "./mayo-element"
-
-export default class MayoThematicBreakElement extends MayoEmptyElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-toml.ts b/src/elements/markdown/mayo-toml.ts
deleted file mode 100644
index 0012490..0000000
--- a/src/elements/markdown/mayo-toml.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import {MayoLiteralElement} from "./mayo-element"
-import * as md from "mdast"
-export default class MayoTomlElement extends MayoLiteralElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/markdown/mayo-yaml.ts b/src/elements/markdown/mayo-yaml.ts
deleted file mode 100644
index cfc7475..0000000
--- a/src/elements/markdown/mayo-yaml.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-import {MayoLiteralElement} from "./mayo-element"
-import * as md from "mdast"
-
-export default class MayoYamlElement extends MayoLiteralElement {
- connectedCallback() {
- super.connectedCallback()
- }
-}
diff --git a/src/elements/mayo-app.ts b/src/elements/mayo-app.ts
index eb5016f..d18701a 100644
--- a/src/elements/mayo-app.ts
+++ b/src/elements/mayo-app.ts
@@ -1,8 +1,3 @@
-import type {
- MayoDocumentElement,
- MayoSidebarElement,
- MayoSidebarTreeElement,
-} from "."
import {promises as fs} from "fs"
import path from "path"
import {
@@ -15,6 +10,13 @@ import {
} from "lit-element"
import {html, TemplateResult} from "lit-html"
import defaultDoc from "../default-doc"
+import MayoSidebarElement from "./mayo-sidebar"
+import MayoSidebarTreeElement from "./mayo-sidebar-tree"
+import MayoDocumentElement from "./mayo-document"
+
+import "./mayo-document"
+import "./mayo-sidebar"
+
export interface GetFilesEvent extends CustomEvent {
detail: {
target: MayoSidebarTreeElement
@@ -58,6 +60,7 @@ export default class MayoAppElement extends LitElement {
mayo-document[dirty] {
border-left: 20px solid #ff2a50;
}
+
* {
box-sizing: border-box;
}
@@ -255,6 +258,11 @@ export default class MayoAppElement extends LitElement {
border-left: 5px solid #3399ff;
padding-left: 5px;
}
+ mayo-link {
+ color: #3399ff;
+ text-decoration: underline;
+ cursor: normal;
+ }
`
}
@@ -298,10 +306,10 @@ export default class MayoAppElement extends LitElement {
@open-file=${this.openFile}
>
`
}
diff --git a/src/elements/mayo-document.ts b/src/elements/mayo-document.ts
index a8629f7..1f90fee 100644
--- a/src/elements/mayo-document.ts
+++ b/src/elements/mayo-document.ts
@@ -1,65 +1,56 @@
-import parse from "mdast-util-from-markdown"
+import fromMarkdown from "mdast-util-from-markdown"
import type * as md from "mdast"
-import BeforeInputEvent from "../before-input-event"
-import {CaretInstruction} from "../caret"
-import {html} from "lit-html"
+import BeforeInputEvent from "../events/before-input-event"
+import {html, TemplateResult} from "lit-html"
// TODO learn how to declare types for this
// @ts-ignore
import compact from "mdast-util-compact"
import toMarkdown from "mdast-util-to-markdown"
import * as is from "../ast/is"
-import {css, CSSResult, customElement, LitElement, property} from "lit-element"
-import transform, {nothing} from "../ast/transform"
-import getTransformOptions from "../get-transform-options"
+import {customElement, LitElement, property} from "lit-element"
+import transform from "../ast/transform"
+import getTransformOptions, {
+ GetTransformOptionsOptions,
+} from "../dom/get-transform-options"
import "./mayo-node"
-import MayoNodeElement from "./mayo-node"
-import {produce, enableAllPlugins} from "immer"
-import {spread} from "@open-wc/lit-helpers"
-import {spreadable} from "../ast/convert-to-html"
+import * as gfm from "mdast-util-gfm"
-enableAllPlugins()
+import type {Patch} from "immer"
+import {
+ produceWithPatches,
+ enableAllPlugins as enableAllOfImmer,
+ applyPatches,
+} from "immer"
+
+enableAllOfImmer()
+
+function parse(contents: string): md.Root {
+ let root = fromMarkdown(contents, {mdastExtensions: [gfm.fromMarkdown]})
+ // addParents(root)
+ return root
+}
+
+enum modifiers {
+ control = 1,
+ shift = 2,
+ super = 4,
+ option = 8,
+ hyper = 16,
+}
@customElement("mayo-document")
-export default class MayoDocumentElement extends LitElement {
+class MayoDocumentElement extends LitElement {
@property()
contents: string
@property({type: Boolean})
dirty: boolean
node: md.Root
+ modifier: number
createRenderRoot(): this {
return this
}
- static get styles(): CSSResult {
- return css`
- article {
- white-space: pre-wrap;
- }
-
- article > * + * {
- margin-top: 1em;
- }
-
- article {
- width: 100%;
- height: 100%;
- font-size: 1.6em;
- font-family: avenir next, sans-serif;
- padding: 1em;
- color: #000;
- line-height: 1.2;
- max-width: 80ex;
- margin: auto;
- margin-bottom: 2em;
- }
-
- article:focus {
- outline: none;
- }
- `
- }
-
attributeChangedCallback(name: string, before: string, now: string): void {
super.attributeChangedCallback(name, before, now)
if (name == "contents") {
@@ -67,215 +58,156 @@ export default class MayoDocumentElement extends LitElement {
}
}
- updateSelection(caret: CaretInstruction | null): void {
- let selection = document.getSelection()
- if (caret) {
- let target: Text | null = null
- if (caret && caret.type == "id") {
- let parent = document.getElementById(
- caret.elementId
- ) as MayoNodeElement
- } else if (caret && caret.type == "parent") {
- target = caret.parentElement.interestingChildren[
- caret.textChildIndex
- ] as Text
- } else if (caret && caret.type == "text") {
- target = caret.element
- }
- if (target) {
- selection.removeAllRanges()
- let range = document.createRange()
- range.setStart(target, caret ? caret.startOffset : 0)
- selection.addRange(range)
- }
- }
- }
-
- async handleInput(event: BeforeInputEvent) {
- event.preventDefault()
- // TODO multiple ranges?
-
- let transformOptions = await getTransformOptions(event)
- this.node = produce(this.node, draft => transform(draft, transformOptions))
- this.setAttribute("dirty", "true")
- await this.requestUpdate()
- // await this.updateComplete
- // this.placeCaret()
- event.preventDefault()
- return
+ // history
+ history: Patch[][] = []
+ // future of the history
+ futures: Patch[][] = []
- // let startContainerElement = startElement.container
- // ? startElement
- // : (startElement.closest("[container]")! as MayoParentElement)
+ historyIndex = 0
- // let startBlockElement = startElement.block
- // ? startElement
- // : (startElement.closest("[block]")! as MayoParentElement)
-
- // let endBlockElement = endElement.block
- // ? endElement
- // : (endElement.closest("[block]")! as MayoParentElement)
-
- // // the index of the start element in the start block (x)
- // let startElementIndex = 0
- // if (startElement.inline) {
- // startElementIndex = startBlockElement.interestingChildren.indexOf(
- // startElement
- // )
- // } else if (startElement.block) {
- // startElementIndex = startBlockElement.interestingChildren.indexOf(
- // range.startContainer
- // )
- // }
-
- // let endElementIndex = 0
- // if (endElement.inline) {
- // endElementIndex = endBlockElement.interestingChildren.indexOf(endElement)
- // } else if (endElement.block) {
- // endElementIndex = endBlockElement.interestingChildren.indexOf(
- // range.endContainer
- // )
- // }
- // switch (event.inputType) {
- // case "insertReplacementText":
- // event.dataTransfer.items[0].getAsString(text => {
- // startElement.selfInsertText(text, range)
- // this.setAttribute("dirty", "true")
- // })
- // break
- // case "insertText": {
- // let caret: CaretInstruction | null = null
- // if (range.startContainer == range.endContainer) {
- // caret = startElement.selfInsertText(event.data || "", range)
- // event.preventDefault()
- // } else if (startBlockElement == endBlockElement) {
- // caret = (startBlockElement as MayoParentElement).insertTextAsCommonAncestor(
- // startElement,
- // endElement,
- // event.data || "",
- // range
- // )
- // } else {
- // // TODO this is a textInsert across blocks, sounds hard
- // }
-
- // this.setAttribute("dirty", "true")
-
- // this.updateSelection(caret)
- // break
- // }
- // case "insertLineBreak": {
- // let index = startBlockElement.interestingChildren.indexOf(startElement)
- // startBlockElement.node.children.splice(index + 1, 0, u("break"))
- // this.setAttribute("dirty", "true")
+ undo(): void {
+ this.node = applyPatches(this.node, this.history[this.historyIndex])
+ this.historyIndex += 1
+ this.requestUpdate()
+ }
- // event.preventDefault()
- // break
- // }
- // case "insertParagraph": {
- // let id = shortId()
- // if ("value" in startElement.node) {
- // if (isTextOrInlineCode(startElement)) {
- // insertParagraph(
- // this.node,
- // startElement.node,
- // range.startOffset,
- // id
- // )
- // }
- // } else if (startElement == startBlockElement) {
- // if (Array.isArray(startElement.node.children)) {
- // insertParagraph(
- // this.node,
- // startElement.node.children[startElementIndex],
- // range.startOffset,
- // id
- // )
- // }
- // } else {
- // let idx = startElement.interestingChildren.indexOf(
- // range.startContainer
- // )
- // if (Array.isArray(startElement.node.children)) {
- // insertParagraph(
- // this.node,
- // startElement.node.children[idx],
- // range.startOffset,
- // id
- // )
- // }
- // }
+ redo(): void {
+ this.node = applyPatches(this.node, this.futures[this.historyIndex])
+ this.historyIndex -= 1
+ this.requestUpdate()
+ }
- // this.setAttribute("dirty", "true")
+ async transform(options: GetTransformOptionsOptions): Promise {
+ let transformOptions = await getTransformOptions(options)
+ let [node, patches, inversePatches] = produceWithPatches(
+ this.node,
+ draft => {
+ transform(draft, transformOptions)
+ }
+ )
- // this.updateSelection({
- // type: "id" as const,
- // elementId: id,
- // textChildIndex: 0,
- // startOffset: 0,
- // })
- // break
- // }
- // case "deleteContentBackward": {
- // if (startElement.node.type == "paragraph") {
- // startElement = startElement as MayoParagraphElement
+ this.node = node
+ // TODO better undo/redoo
+ this.history.splice(this.historyIndex, 0, inversePatches)
+ this.futures.splice(this.historyIndex, 0, patches)
- // if (startElement.atBeginningOfBlock(range)) {
- // backspaceParagraph(this.node, startElement.node)
- // }
- // } else if (startElement != startBlockElement) {
- // if (is.container(startElement.node.type)) {
- // // go through the children and move the top-level text nodes out into the parent
- // let indexOfTextNode = startElement.interestingChildren.indexOf(
- // range.startContainer
- // )
- // if (Array.isArray(startElement.node.children)) {
- // let textNode = startElement.node.children[indexOfTextNode]
- // }
- // } else if (typeof startElement.node.value == "string") {
- // if (range.startOffset == startElement.node.value.length - 1) {
- // startElement.node.type = "text"
+ this.setAttribute("dirty", "true")
+ await this.requestUpdate()
+ }
- // // TODO fix caret position
- // // this.updateSelection()
- // event.preventDefault()
- // }
- // }
- // }
+ async handleInput(event: BeforeInputEvent): Promise {
+ let metaBindings = {
+ s: this.save,
+ "[": () => {
+ this.transform({
+ inputType: "formatOutdent",
+ range: event.getTargetRanges()[0],
+ })
+ },
+ "]": () => {
+ this.transform({
+ inputType: "formatIndent",
+ range: event.getTargetRanges()[0],
+ })
+ },
+ }
- // let caret = startElement.selfDeleteContentBackward(range)
+ if (
+ this.modifier & modifiers.super &&
+ event.inputType == "insertText" &&
+ Object.keys(metaBindings).includes(event.data)
+ ) {
+ event.preventDefault()
+ // @ts-ignore
+ metaBindings[event.data]()
+ return
+ }
- // this.setAttribute("dirty", "true")
+ event.preventDefault()
+ await this.transform({
+ inputType: event.inputType,
+ range: event.getTargetRanges()[0],
+ data: event.data,
+ dataTransfer: event.dataTransfer,
+ })
- // if (caret) {
- // this.updateSelection(caret)
- // }
- // break
- // }
- // }
+ return
+ }
- // event.preventDefault()
- //this.updateForTransform(event)
+ // this is messed up, but
+ handleKeydown(event: KeyboardEvent): void {
+ switch (event.key) {
+ case "Meta":
+ this.modifier |= modifiers.super
+ break
+ case "Alt":
+ this.modifier |= modifiers.option
+ break
+ case "Hyper":
+ this.modifier |= modifiers.hyper
+ break
+ case "Control":
+ this.modifier |= modifiers.control
+ break
+ case "Shift":
+ this.modifier |= modifiers.shift
+ }
}
- updateForTransform(caret: CaretInstruction) {
- this.setAttribute("dirty", "true")
- this.updateSelection(caret)
+ handleKeyup(event: KeyboardEvent): void {
+ switch (event.key) {
+ case "Meta":
+ this.modifier ^= modifiers.super
+ break
+ case "Alt":
+ this.modifier ^= modifiers.option
+ break
+ case "Hyper":
+ this.modifier ^= modifiers.hyper
+ break
+ case "Control":
+ this.modifier ^= modifiers.control
+ break
+ case "Shift":
+ this.modifier ^= modifiers.shift
+ }
}
- handleKeydown(event: KeyboardEvent) {
- if (event.key == "s" && (event.ctrlKey || event.metaKey)) {
- this.save()
- event.preventDefault()
+ getCurrentRange(): StaticRange {
+ let {
+ startContainer,
+ startOffset,
+ endContainer,
+ endOffset,
+ } = document.getSelection().getRangeAt(0).cloneRange()
+
+ return {
+ collapsed: startContainer == endContainer && startOffset == endOffset,
+ startContainer: startContainer,
+ startOffset: startOffset,
+ endContainer: endContainer,
+ endOffset: endOffset,
}
}
- save() {
- this.contents = toMarkdown(compact(this.node))
+ save(): void {
+ this.contents = toMarkdown(compact(this.node), {
+ bullet: "-",
+ fence: "`",
+ emphasis: "_",
+ strong: "*",
+ rule: "*",
+ setext: false,
+ fences: true,
+ listItemIndent: "tab",
+ incrementListMarker: true,
+ quote: '"',
+ extensions: [gfm.toMarkdown()],
+ })
this.dispatchEvent(new CustomEvent("save"))
}
- render() {
+ render(): TemplateResult {
return html``
+ // eslint-disable-next-line no-mixed-spaces-and-tabs
})
: ""}
`
@@ -307,10 +239,9 @@ export default class MayoDocumentElement extends LitElement {
constructor() {
super()
this.addEventListener("keydown", this.handleKeydown)
+ this.addEventListener("keyup", this.handleKeyup)
this.addEventListener("beforeinput", this.handleInput)
}
-
- connectedCallback() {
- super.connectedCallback()
- }
}
+
+export default MayoDocumentElement
diff --git a/src/elements/mayo-killer.ts b/src/elements/mayo-killer.ts
deleted file mode 100644
index e09eba6..0000000
--- a/src/elements/mayo-killer.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import {LitElement, html, css, customElement, property} from "lit-element"
-
-@customElement("mayo-killer")
-export default class MayoKillerElement extends LitElement {
- @property()
- symbol: string
-
- render() {
- return html`${this.symbol}`
- }
-}
diff --git a/src/elements/mayo-node.ts b/src/elements/mayo-node.ts
index 89378fd..46ca8b2 100644
--- a/src/elements/mayo-node.ts
+++ b/src/elements/mayo-node.ts
@@ -1,11 +1,39 @@
import {customElement, LitElement, property} from "lit-element"
-import {html, render, TemplateResult} from "lit-html"
+import {html, TemplateResult} from "lit-html"
import * as md from "mdast"
-import * as unist from "unist"
import * as is from "../ast/is"
-import {spread} from "@open-wc/lit-helpers"
-import {spreadable} from "../ast/convert-to-html"
-import {repeat} from "lit-html/directives/repeat"
+import {ifDefined} from "lit-html/directives/if-defined"
+
+interface Info {
+ leaf?: true
+ block?: true
+ inline?: true
+ container?: true
+ empty?: true
+ caretStart?: number
+ caretEnd?: number
+}
+
+export function info(node: md.Content | md.Root): Info {
+ let info: Info = {}
+ if (is.leaf(node)) {
+ info.leaf = true
+ }
+ if (is.block(node)) {
+ info.block = true
+ }
+ if (is.inline(node)) {
+ info.inline = true
+ }
+ if (is.container(node)) {
+ info.container = true
+ }
+ if (is.empty(node)) {
+ info.empty = true
+ }
+
+ return info
+}
@customElement("mayo-node")
class MayoNodeElement extends LitElement {
@@ -31,10 +59,10 @@ class MayoNodeElement extends LitElement {
block: boolean
@property()
value: string
- @property()
- caret: string
- @property({type: Number})
- caretoffset: number
+ @property({type: Number, attribute: "caret-start"})
+ caretStart?: number
+ @property({type: Number, attribute: "caret-end"})
+ caretEnd?: number
@property()
path: string
@@ -61,22 +89,22 @@ class MayoNodeElement extends LitElement {
return html``
}
return html`${this.node.children.map((child, index) => {
- let caret = child.data?.caret?.type
- let offset = child.data?.caret?.offset
+ let caret = child.data?.caret
return html``
})}`
}
@@ -174,21 +202,26 @@ class MayoNodeElement extends LitElement {
return html`${this.node.value}
`
} else if (this.node.type == "text") {
return html`${this.node.value}`
+ } else {
+ console.error(`unhandled node type: ${this.node.type}`)
}
}
- updated(props: Map) {
- if (this.caret) {
- console.log(this.caret, this.caretoffset)
+ updated(): void {
+ if (this.caretStart != null || this.caretEnd != null) {
+ if (!this.textNode) {
+ return console.error(`no text node in ${this.tagName}`)
+ }
let selection = document.getSelection()
let range = document.createRange()
selection.removeAllRanges()
- if (this.caret == "collapsed" || this.caret == "start") {
- range.setStart(this.textNode, this.caretoffset)
+
+ if (this.caretStart != null) {
+ range.setStart(this.textNode, this.caretStart)
}
- if (this.caret == "collapsed" || this.caret == "end") {
- range.setEnd(this.textNode, this.caretoffset)
+ if (this.caretEnd != null) {
+ range.setEnd(this.textNode, this.caretEnd)
}
selection.addRange(range)
diff --git a/src/elements/mayo-sidebar-file.ts b/src/elements/mayo-sidebar-file.ts
index 734b179..e872b63 100644
--- a/src/elements/mayo-sidebar-file.ts
+++ b/src/elements/mayo-sidebar-file.ts
@@ -10,7 +10,7 @@ import {TemplateResult} from "lit-html"
import type {OpenFileEvent} from "./mayo-app"
@customElement("mayo-sidebar-file")
-export default class MayoSidebarFileElement extends LitElement {
+class MayoSidebarFileElement extends LitElement {
@property()
name: string
@property()
@@ -69,3 +69,5 @@ export default class MayoSidebarFileElement extends LitElement {
}
}
}
+
+export default MayoSidebarFileElement
diff --git a/src/elements/mayo-sidebar-tree.ts b/src/elements/mayo-sidebar-tree.ts
index af6ad0c..00df6ef 100644
--- a/src/elements/mayo-sidebar-tree.ts
+++ b/src/elements/mayo-sidebar-tree.ts
@@ -11,7 +11,7 @@ import type {GetFilesEvent} from "./mayo-app"
import path from "path"
@customElement("mayo-sidebar-tree")
-export default class MayoSidebarTreeElement extends LitElement {
+class MayoSidebarTreeElement extends LitElement {
@property({type: Boolean})
open: boolean
@property({attribute: false})
@@ -108,3 +108,5 @@ export default class MayoSidebarTreeElement extends LitElement {
}
}
}
+
+export default MayoSidebarTreeElement
diff --git a/src/elements/mayo-sidebar.ts b/src/elements/mayo-sidebar.ts
index 7ca2ea2..65ea566 100644
--- a/src/elements/mayo-sidebar.ts
+++ b/src/elements/mayo-sidebar.ts
@@ -8,9 +8,11 @@ import {
} from "lit-element"
import {TemplateResult} from "lit-html"
import {basename} from "path"
+import "./mayo-sidebar-file"
+import "./mayo-sidebar-tree"
@customElement("mayo-sidebar")
-export default class MayoSidebarElement extends LitElement {
+class MayoSidebarElement extends LitElement {
@property()
cwd: string
@@ -54,3 +56,5 @@ export default class MayoSidebarElement extends LitElement {
`
}
}
+
+export default MayoSidebarElement
diff --git a/src/before-input-event.ts b/src/events/before-input-event.ts
similarity index 100%
rename from src/before-input-event.ts
rename to src/events/before-input-event.ts
diff --git a/src/get-transform-options.ts b/src/get-transform-options.ts
deleted file mode 100644
index ea1b3fd..0000000
--- a/src/get-transform-options.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import type {TransformOptions} from "./ast/transform"
-import BeforeInputEvent from "./before-input-event"
-import MayoNodeElement from "./elements/mayo-node"
-import type * as md from "mdast"
-import {find} from "unist-utils-core"
-
-export default async function getTransformOptions(
- event: BeforeInputEvent
-): Promise {
- let data = event.data
-
- if (event.inputType == "insertReplacementText") {
- // i'm going to regret this
- // instead i should be creating a placeholder element
- data = await new Promise(yay =>
- event.dataTransfer.items[0].getAsString(yay)
- )
- }
-
- let range = event.getTargetRanges()[0]
- let start = range.startContainer.parentElement as MayoNodeElement
- let end = range.endContainer.parentElement as MayoNodeElement
-
- if (start.tagName.toLowerCase() != "mayo-node") {
- start = start.closest("mayo-node")
- }
- if (end.tagName.toLowerCase() != "mayo-node") {
- end = end.closest("mayo-node")
- }
-
- return {
- data,
- start: {
- path: start.path,
- offset: range.startOffset,
- },
- end: {
- path: end.path,
- offset: range.endOffset,
- },
- inputType: event.inputType,
- }
-}
diff --git a/src/index.html b/src/index.html
index eaf9201..b5a31fe 100644
--- a/src/index.html
+++ b/src/index.html
@@ -1,16 +1,3 @@
mayonaise
-
-
-
-
+
diff --git a/src/mayo.ts b/src/mayo.ts
index 1fc503a..a446e6e 100644
--- a/src/mayo.ts
+++ b/src/mayo.ts
@@ -1 +1 @@
-import "./elements"
+import "./elements/mayo-app"
diff --git a/src/styles.css b/src/styles.css
index 6cae5a1..911b450 100644
--- a/src/styles.css
+++ b/src/styles.css
@@ -11,187 +11,3 @@ mayo-app {
display: flex;
height: 100vh;
}
-
-mayo-sidebar {
- height: 100vh;
- overflow: hidden;
-}
-
-mayo-document {
- flex: 1;
- border-left: 20px solid white;
- width: 100%;
- padding-bottom: 5em;
- height: 100vh;
- overflow: auto;
-}
-
-mayo-document[dirty] {
- border-left: 20px solid #ff2a50;
-}
-
-mayo-document {
- overflow: auto;
- height: 100%;
-}
-
-mayo-document article > * + * {
- margin-top: 1em;
-}
-
-mayo-document article {
- width: 100%;
- height: 100%;
- font-size: 1.4em;
- font-family: avenir next, sans-serif;
- padding: 1em;
- color: #000;
- line-height: 1.2;
- max-width: 80ex;
- margin: auto;
- margin-bottom: 2em;
-}
-
-mayo-document article:focus {
- outline: none;
-}
-
-mayo-heading {
- display: block;
- font-weight: bolder;
-}
-
-mayo-heading[depth="1"] {
- font-size: 2em;
-}
-
-mayo-heading[depth="2"] {
- font-size: 1.6em;
-}
-
-mayo-heading[depth="3"] {
- font-size: 1.4em;
-}
-
-mayo-heading[depth="4"] {
- font-size: 1.25em;
-}
-
-mayo-heading[depth="5"] {
- font-size: 1.15em;
-}
-
-mayo-heading[depth="6"] {
- font-size: 1em;
-}
-
-mayo-heading::before {
- font-family: ibm plex mono, monospace;
- font-style: italic;
- display: inline-block;
- font-size: 0.8em;
- color: #77c;
- margin-right: 0.5em;
-}
-
-[depth="1"]::before {
- content: "# ";
-}
-
-[depth="2"]::before {
- content: "## ";
-}
-
-[depth="3"]::before {
- content: "### ";
-}
-
-[depth="4"]::before {
- content: "#### ";
-}
-
-[depth="5"]::before {
- content: "##### ";
-}
-
-[depth="6"]::before {
- content: "###### ";
-}
-
-mayo-break {
- display: block;
-}
-
-mayo-paragraph {
- display: block;
-}
-
-mayo-paragraph + mayo-paragraph {
- margin-top: 1em;
-}
-
-mayo-list {
- list-style-type: disc;
- padding-left: 1em;
- display: block;
-}
-
-mayo-list[ordered="true"] {
- list-style-type: decimal;
- padding-left: 1em;
-}
-
-mayo-list-item {
- display: list-item;
-}
-
-[ordered="false"] > mayo-list-item::-moz-list-bullet {
- color: #af2af0;
-}
-
-[ordered="true"] > mayo-list-item::-moz-list-bullet {
- font-weight: 500;
-}
-
-mayo-code {
- display: block;
- white-space: pre;
- font-family: IBM Plex Mono, monospace;
- background: #ffe9ed;
- color: #c36;
- padding: 1em;
- font-size: 0.9em;
- margin-bottom: 1em;
- overflow-x: scroll;
-}
-
-mayo-inline-code {
- font-family: IBM Plex Mono, monospace;
- background: #ffe9ed;
-}
-
-/* mayo-inline-code:hover::before,
-mayo-inline-code:hover::after {
- content: "`";
-} */
-mayo-emphasis {
- font-style: oblique;
-}
-
-/* mayo-emphasis:hover::before,
-mayo-emphasis:hover::after {
- content: "_";
-} */
-mayo-strong {
- font-weight: bolder;
-}
-
-/* mayo-strong:hover::before,
-mayo-strong:hover::after {
- content: "**";
-} */
-blockquote {
- display: flex;
- border-left: 5px solid #3399ff;
- padding-left: 5px;
-}
diff --git a/tests/insert-paragraph.test.ts b/tests/insert-paragraph.test.ts
new file mode 100644
index 0000000..cb20f54
--- /dev/null
+++ b/tests/insert-paragraph.test.ts
@@ -0,0 +1,104 @@
+import insertParagraph from "../src/ast/insert-paragraph"
+import parse from "./parse"
+import toMarkdown from "mdast-util-to-markdown"
+import {select, selectAll} from "unist-utils-core"
+import * as md from "mdast"
+
+describe("insertParagraph", () => {
+ test("inserts a new paragraph where the cursor is", () => {
+ let tree = parse("hellothere")
+ let expected = parse(`hello
+
+there`)
+ let p = select("paragraph", tree)
+ let text = select("text", p)
+ insertParagraph(tree, text, 5)
+
+ expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
+ expect(tree).toEqual(expected)
+ })
+
+ test("inserts a new paragraph where the cursor is (in a code)", () => {
+ let tree = parse("`hellothere`")
+ let expected = parse(`\`hello\`
+
+\`there\``)
+ let p = select("paragraph", tree)
+ let text = select("inlineCode", p)
+ insertParagraph(tree, text, 5)
+
+ expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
+ expect(tree).toEqual(expected)
+ })
+
+ test("inserts a new paragraph where the cursor is (in a complex place)", () => {
+ let tree = parse(
+ "this is *story __all about how my life__ got flipped* turned up side down"
+ )
+ let expected = parse(
+ `this is *story __all ab__*
+
+*__out how my life__ got flipped* turned up side down`
+ )
+ let p = select("paragraph", tree)
+ let text = selectAll("text", p)[2]
+ insertParagraph(tree, text, 6)
+
+ expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
+ expect(tree).toEqual(expected)
+ })
+
+ test("inserts a new paragraph where the cursor is (in a complex place in a code)", () => {
+ let tree = parse(
+ "this is *story __all about `how` my life__ got flipped* turned up side down"
+ )
+ let expected = parse(
+ `this is *story __all about \`h\`__*
+
+*__\`ow\` my life__ got flipped* turned up side down`
+ )
+ let p = select("paragraph", tree)
+ let inlineCode = select("inlineCode", p)
+ insertParagraph(tree, inlineCode, 1)
+
+ expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
+ expect(tree).toEqual(expected)
+ })
+
+ test("inserts a new paragraph, maintaining whole nodes", () => {
+ let tree = parse("split __mein two__ please")
+ let expected = parse(`split __me__
+
+__in two__ please`)
+ let p = select("paragraph", tree)
+ let text = selectAll("text", p)[1]
+
+ insertParagraph(tree, text, 2)
+
+ expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
+ expect(tree).toEqual(expected)
+ })
+
+ it("works in a heading", () => {
+ let tree = parse("# well, well, well")
+ let expected = parse(`# well, well
+
+, well`)
+ let h1 = select("heading", tree)
+ let text = select("text", h1)
+ insertParagraph(tree, text, 10)
+ expect(tree).toEqual(expected)
+ })
+
+ it("works in a heading with special elements", () => {
+ let tree = parse("# well, _well_, well, well")
+ let expected = parse(`# we
+
+ll, _well_, well, well`)
+ let h1 = select("heading", tree)
+ let text = selectAll("text", h1)[0]
+ insertParagraph(tree, text, 2)
+ expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
+ expect(tree).toEqual(expected)
+ })
+})
diff --git a/tests/transform/split.test.ts b/tests/split.test.ts
similarity index 100%
rename from tests/transform/split.test.ts
rename to tests/split.test.ts
diff --git a/tests/transform/insert-paragraph.test.ts b/tests/transform/insert-paragraph.test.ts
index d0d4e6d..9303d4f 100644
--- a/tests/transform/insert-paragraph.test.ts
+++ b/tests/transform/insert-paragraph.test.ts
@@ -1,104 +1,31 @@
-import insertParagraph from "../../src/ast/insert-paragraph"
+import insertParagraph from "../../src/ast/transform/insert-paragraph"
import parse from "../parse"
-import toMarkdown from "mdast-util-to-markdown"
import {select, selectAll} from "unist-utils-core"
import * as md from "mdast"
-describe("insertParagraph", () => {
- test("inserts a new paragraph where the cursor is", () => {
- let tree = parse("hellothere")
+describe(insertParagraph, () => {
+ it("inserts paragraph in the correct place", () => {
+ let tree = parse("helloagain")
let expected = parse(`hello
-
-there`)
- let p = select("paragraph", tree)
- let text = select("text", p)
- insertParagraph(tree, text, 5)
-
- expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
- expect(tree).toEqual(expected)
- })
-
- test("inserts a new paragraph where the cursor is (in a code)", () => {
- let tree = parse("`hellothere`")
- let expected = parse(`\`hello\`
-
-\`there\``)
- let p = select("paragraph", tree)
- let text = select("inlineCode", p)
- insertParagraph(tree, text, 5)
-
- expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
- expect(tree).toEqual(expected)
- })
-
- test("inserts a new paragraph where the cursor is (in a complex place)", () => {
- let tree = parse(
- "this is *story __all about how my life__ got flipped* turned up side down"
- )
- let expected = parse(
- `this is *story __all ab__*
-
-*__out how my life__ got flipped* turned up side down`
- )
- let p = select("paragraph", tree)
- let text = selectAll("text", p)[2]
- insertParagraph(tree, text, 6)
-
- expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
- expect(tree).toEqual(expected)
- })
-
- test("inserts a new paragraph where the cursor is (in a complex place in a code)", () => {
- let tree = parse(
- "this is *story __all about `how` my life__ got flipped* turned up side down"
- )
- let expected = parse(
- `this is *story __all about \`h\`__*
-
-*__\`ow\` my life__ got flipped* turned up side down`
- )
- let p = select("paragraph", tree)
- let inlineCode = select("inlineCode", p)
- insertParagraph(tree, inlineCode, 1)
-
- expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
- expect(tree).toEqual(expected)
- })
-
- test("inserts a new paragraph, maintaining whole nodes", () => {
- let tree = parse("split __mein two__ please")
- let expected = parse(`split __me__
-__in two__ please`)
- let p = select("paragraph", tree)
- let text = selectAll("text", p)[1]
-
- insertParagraph(tree, text, 2)
-
- expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
- expect(tree).toEqual(expected)
- })
-
- it("works in a heading", () => {
- let tree = parse("# well, well, well")
- let expected = parse(`# well, well
-
-, well`)
- let h1 = select("heading", tree)
- let text = select("text", h1)
- insertParagraph(tree, text, 10)
- expect(tree).toEqual(expected)
- })
-
- it("works in a heading with special elements", () => {
- let tree = parse("# well, _well_, well, well")
- let expected = parse(`# we
-
-ll, _well_, well, well`)
- let h1 = select("heading", tree)
- let text = selectAll("text", h1)[0]
- insertParagraph(tree, text, 2)
- expect(toMarkdown(tree)).toEqual(toMarkdown(expected))
- expect(tree).toEqual(expected)
+again`)
+ selectAll("text", expected)[1].data = {
+ caret: {
+ type: "collapsed",
+ offset: 0,
+ },
+ }
+ insertParagraph(tree, {
+ data: null,
+ start: {
+ node: select("text", tree),
+ offset: 5,
+ },
+ end: {
+ node: select("text", tree),
+ offset: 5,
+ },
+ })
+ expect(expected).toEqual(tree)
})
})
diff --git a/tests/transform/insert-text.test.ts b/tests/transform/insert-text.test.ts
index 429d9f1..eb94106 100644
--- a/tests/transform/insert-text.test.ts
+++ b/tests/transform/insert-text.test.ts
@@ -1,19 +1,20 @@
-import type {TransformHandler} from "../../src/ast/transform"
-import {visit} from "unist-utils-core"
import insertText from "../../src/ast/transform/insert-text"
import parse from "../parse"
-import toMarkdown from "mdast-util-to-markdown"
import {select, selectAll} from "unist-utils-core"
import * as md from "mdast"
-import * as unist from "unist"
describe(insertText, () => {
it("inserts text in the correct place", () => {
let tree = parse("hello again")
let expected = parse("hello! again")
+ select("text", expected).data = {
+ caret: {
+ caretStart: 6,
+ caretEnd: 6,
+ },
+ }
insertText(tree, {
data: "!",
- inputType: "insertText",
start: {
node: select("text", tree),
offset: 5,
@@ -29,9 +30,14 @@ describe(insertText, () => {
it("inserts text in the correct in an inline code", () => {
let tree = parse("hello `code` again")
let expected = parse("hello `co-de` again")
+ select("inlineCode", expected).data = {
+ caret: {
+ caretStart: 3,
+ caretEnd: 3,
+ },
+ }
insertText(tree, {
data: "-",
- inputType: "insertText",
start: {
node: select("inlineCode", tree),
offset: 2,
@@ -47,9 +53,15 @@ describe(insertText, () => {
it("inserts text in a nested thing", () => {
let tree = parse("hello _**hey `wow` nice**_ again")
let expected = parse("hello _**hey `wow` niice**_ again")
+ selectAll("text", expected)[2].data = {
+ caret: {
+ caretStart: 3,
+ caretEnd: 3,
+ },
+ }
insertText(tree, {
data: "i",
- inputType: "insertText",
+
start: {
node: selectAll("text", tree)[2],
offset: 2,
@@ -65,9 +77,15 @@ describe(insertText, () => {
it("inserts text across a range", () => {
let tree = parse("hello _**hey nice**_ again")
let expected = parse("hello _**hehe**_ again")
+ selectAll("text", expected)[1].data = {
+ caret: {
+ caretStart: 3,
+ caretEnd: 3,
+ },
+ }
insertText(tree, {
data: "h",
- inputType: "insertText",
+
start: {
node: selectAll("text", tree)[1],
offset: 2,
@@ -83,9 +101,14 @@ describe(insertText, () => {
it("inserts text across a range as a common ancestor", () => {
let tree = parse("hello _**hey `code` nice**_ again")
let expected = parse("hello _**hehe**_ again")
+ selectAll("text", expected)[1].data = {
+ caret: {
+ caretStart: 3,
+ caretEnd: 3,
+ },
+ }
insertText(tree, {
data: "-",
- inputType: "insertText",
start: {
node: selectAll("text", tree)[1],
offset: 2,
diff --git a/tests/transform/unwrap.test.ts b/tests/unwrap.test.ts
similarity index 87%
rename from tests/transform/unwrap.test.ts
rename to tests/unwrap.test.ts
index af3c373..726ed8e 100644
--- a/tests/transform/unwrap.test.ts
+++ b/tests/unwrap.test.ts
@@ -1,6 +1,6 @@
import unwrap from "../src/ast/unwrap"
-import parse from "../parse"
+import parse from "./parse"
import toMarkdown from "mdast-util-to-markdown"
import {select, selectAll} from "unist-utils-core"
import * as md from "mdast"
diff --git a/tsconfig.json b/tsconfig.json
index fa6c2e6..d7b1983 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -26,7 +26,7 @@
},
"include": [
"src/**/*",
- "tests/transform/insert-paragraph.test.ts",
+ "tests/insert-paragraph.test.ts",
"tests/transform/split.test.ts"
]
}
diff --git a/yarn.lock b/yarn.lock
index 33436f2..1933b7f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1557,6 +1557,13 @@
dependencies:
"@types/node" "*"
+"@types/hast@^2.0.0":
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/@types/hast/-/hast-2.3.1.tgz#b16872f2a6144c7025f296fb9636a667ebb79cd9"
+ integrity sha512-viwwrB+6xGzw+G1eWpF9geV3fnsDgXqHG+cqgiHrvQfDUW5hzhCyV7Sy3UJxhfRFBsgky2SSW33qi/YrIkjX5Q==
+ dependencies:
+ "@types/unist" "*"
+
"@types/html-minifier-terser@^5.0.0":
version "5.1.1"
resolved "https://registry.yarnpkg.com/@types/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz#3c9ee980f1a10d6021ae6632ca3e79ca2ec4fb50"
@@ -1643,6 +1650,11 @@
resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
+"@types/parse5@^5.0.0":
+ version "5.0.3"
+ resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109"
+ integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==
+
"@types/prettier@^2.0.0":
version "2.1.6"
resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.1.6.tgz#f4b1efa784e8db479cdb8b14403e2144b1e9ff03"
@@ -5244,11 +5256,45 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
-hast-util-is-element@^1.0.0:
+hast-util-embedded@^1.0.0:
+ version "1.0.6"
+ resolved "https://registry.yarnpkg.com/hast-util-embedded/-/hast-util-embedded-1.0.6.tgz#ea7007323351cc43e19e1d6256b7cde66ad1aa03"
+ integrity sha512-JQMW+TJe0UAIXZMjCJ4Wf6ayDV9Yv3PBDPsHD4ExBpAspJ6MOcCX+nzVF+UJVv7OqPcg852WEMSHQPoRA+FVSw==
+ dependencies:
+ hast-util-is-element "^1.1.0"
+
+hast-util-from-parse5@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/hast-util-from-parse5/-/hast-util-from-parse5-6.0.1.tgz#554e34abdeea25ac76f5bd950a1f0180e0b3bc2a"
+ integrity sha512-jeJUWiN5pSxW12Rh01smtVkZgZr33wBokLzKLwinYOUfSzm1Nl/c3GUGebDyOKjdsRgMvoVbV0VpAcpjF4NrJA==
+ dependencies:
+ "@types/parse5" "^5.0.0"
+ hastscript "^6.0.0"
+ property-information "^5.0.0"
+ vfile "^4.0.0"
+ vfile-location "^3.2.0"
+ web-namespaces "^1.0.0"
+
+hast-util-from-string@^1.0.4:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/hast-util-from-string/-/hast-util-from-string-1.0.4.tgz#5f7f94c1522455e881405b37f953ebd68ab0aa05"
+ integrity sha512-SFLN+9wPgdXVTV300VUyFNJCIltRO6P9zSgmw3O+B0NMV32MoyBJ9Ca+cjzUu7qWjVHN8+tcLaoHHL9+y8jcMQ==
+
+hast-util-has-property@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/hast-util-has-property/-/hast-util-has-property-1.0.4.tgz#9f137565fad6082524b382c1e7d7d33ca5059f36"
+ integrity sha512-ghHup2voGfgFoHMGnaLHOjbYFACKrRh9KFttdCzMCbFoBMJXiNi2+XTrPP8+q6cDJM/RSqlCfVWrjp1H201rZg==
+
+hast-util-is-element@^1.0.0, hast-util-is-element@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/hast-util-is-element/-/hast-util-is-element-1.1.0.tgz#3b3ed5159a2707c6137b48637fbfe068e175a425"
integrity sha512-oUmNua0bFbdrD/ELDSSEadRVtWZOf3iF6Lbv81naqsIV99RnSCieTbWuWCY8BAeEfKJTKl0gRdokv+dELutHGQ==
+hast-util-parse-selector@^2.0.0:
+ version "2.2.5"
+ resolved "https://registry.yarnpkg.com/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz#d57c23f4da16ae3c63b3b6ca4616683313499c3a"
+ integrity sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==
+
hast-util-sanitize@^3.0.0:
version "3.0.2"
resolved "https://registry.yarnpkg.com/hast-util-sanitize/-/hast-util-sanitize-3.0.2.tgz#b0b783220af528ba8fe6999f092d138908678520"
@@ -5272,11 +5318,49 @@ hast-util-to-html@^7.0.0, hast-util-to-html@^7.1.2:
unist-util-is "^4.0.0"
xtend "^4.0.0"
-hast-util-whitespace@^1.0.0:
+hast-util-to-mdast@^7.1.3:
+ version "7.1.3"
+ resolved "https://registry.yarnpkg.com/hast-util-to-mdast/-/hast-util-to-mdast-7.1.3.tgz#e4ad9098929355501773aed5e66c8181559eee04"
+ integrity sha512-3vER9p8B8mCs5b2qzoBiWlC9VnTkFmr8Ufb1eKdcvhVY+nipt52YfMRshk5r9gOE1IZ9/xtlSxebGCv1ig9uKA==
+ dependencies:
+ extend "^3.0.0"
+ hast-util-has-property "^1.0.0"
+ hast-util-is-element "^1.1.0"
+ hast-util-to-text "^2.0.0"
+ mdast-util-phrasing "^2.0.0"
+ mdast-util-to-string "^1.0.0"
+ rehype-minify-whitespace "^4.0.3"
+ repeat-string "^1.6.1"
+ trim-trailing-lines "^1.1.0"
+ unist-util-is "^4.0.0"
+ unist-util-visit "^2.0.0"
+ xtend "^4.0.1"
+
+hast-util-to-text@^2.0.0:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/hast-util-to-text/-/hast-util-to-text-2.0.1.tgz#04f2e065642a0edb08341976084aa217624a0f8b"
+ integrity sha512-8nsgCARfs6VkwH2jJU9b8LNTuR4700na+0h3PqCaEk4MAnMDeu5P0tP8mjk9LLNGxIeQRLbiDbZVw6rku+pYsQ==
+ dependencies:
+ hast-util-is-element "^1.0.0"
+ repeat-string "^1.0.0"
+ unist-util-find-after "^3.0.0"
+
+hast-util-whitespace@^1.0.0, hast-util-whitespace@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/hast-util-whitespace/-/hast-util-whitespace-1.0.4.tgz#e4fe77c4a9ae1cb2e6c25e02df0043d0164f6e41"
integrity sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==
+hastscript@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/hastscript/-/hastscript-6.0.0.tgz#e8768d7eac56c3fdeac8a92830d58e811e5bf640"
+ integrity sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==
+ dependencies:
+ "@types/hast" "^2.0.0"
+ comma-separated-tokens "^1.0.0"
+ hast-util-parse-selector "^2.0.0"
+ property-information "^5.0.0"
+ space-separated-tokens "^1.0.0"
+
he@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
@@ -6768,6 +6852,13 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
+markdown-table@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/markdown-table/-/markdown-table-2.0.0.tgz#194a90ced26d31fe753d8b9434430214c011865b"
+ integrity sha512-Ezda85ToJUBhM6WGaG6veasyym+Tbs3cMAw/ZhOPqXiYsr0jgocBV3j3nx+4lk47plLlIqjwuTm/ywVI+zjJ/A==
+ dependencies:
+ repeat-string "^1.0.0"
+
matcher@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca"
@@ -6784,6 +6875,13 @@ md5.js@^1.3.4:
inherits "^2.0.1"
safe-buffer "^5.1.2"
+mdast-builder@^1.1.1:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/mdast-builder/-/mdast-builder-1.1.1.tgz#ccaaa5ead8ec9c69883ec87d289770569e4b49b2"
+ integrity sha512-a3KBk/LmYD6wKsWi8WJrGU/rXR4yuF4Men0JO0z6dSZCm5FrXXWTRDjqK0vGSqa+1M6p9edeuypZAZAzSehTUw==
+ dependencies:
+ "@types/unist" "^2.0.3"
+
mdast-util-compact@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/mdast-util-compact/-/mdast-util-compact-3.0.0.tgz#a5127d5473472a272686254e9b619fb8681e5d00"
@@ -6809,6 +6907,51 @@ mdast-util-from-markdown@^0.8.0, mdast-util-from-markdown@^0.8.4:
parse-entities "^2.0.0"
unist-util-stringify-position "^2.0.0"
+mdast-util-gfm-autolink-literal@^0.1.0:
+ version "0.1.2"
+ resolved "https://registry.yarnpkg.com/mdast-util-gfm-autolink-literal/-/mdast-util-gfm-autolink-literal-0.1.2.tgz#da69d700d42e0692a815292d47e8696926d70561"
+ integrity sha512-WFeIrcNNsfBety0gyWuiBIPing9UkVcl/m2iZOyW1uHEH2evjFocet2h77M24ub0WyZ4ucnQn/jWhO5Ozl6j4g==
+
+mdast-util-gfm-strikethrough@^0.2.0:
+ version "0.2.3"
+ resolved "https://registry.yarnpkg.com/mdast-util-gfm-strikethrough/-/mdast-util-gfm-strikethrough-0.2.3.tgz#45eea337b7fff0755a291844fbea79996c322890"
+ integrity sha512-5OQLXpt6qdbttcDG/UxYY7Yjj3e8P7X16LzvpX8pIQPYJ/C2Z1qFGMmcw+1PZMUM3Z8wt8NRfYTvCni93mgsgA==
+ dependencies:
+ mdast-util-to-markdown "^0.6.0"
+
+mdast-util-gfm-table@^0.1.0:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/mdast-util-gfm-table/-/mdast-util-gfm-table-0.1.6.tgz#af05aeadc8e5ee004eeddfb324b2ad8c029b6ecf"
+ integrity sha512-j4yDxQ66AJSBwGkbpFEp9uG/LS1tZV3P33fN1gkyRB2LoRL+RR3f76m0HPHaby6F4Z5xr9Fv1URmATlRRUIpRQ==
+ dependencies:
+ markdown-table "^2.0.0"
+ mdast-util-to-markdown "~0.6.0"
+
+mdast-util-gfm-task-list-item@^0.1.0:
+ version "0.1.6"
+ resolved "https://registry.yarnpkg.com/mdast-util-gfm-task-list-item/-/mdast-util-gfm-task-list-item-0.1.6.tgz#70c885e6b9f543ddd7e6b41f9703ee55b084af10"
+ integrity sha512-/d51FFIfPsSmCIRNp7E6pozM9z1GYPIkSy1urQ8s/o4TC22BZ7DqfHFWiqBD23bc7J3vV1Fc9O4QIHBlfuit8A==
+ dependencies:
+ mdast-util-to-markdown "~0.6.0"
+
+mdast-util-gfm@^0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/mdast-util-gfm/-/mdast-util-gfm-0.1.1.tgz#105095ae3e33bd489852579a205a9060414d35a5"
+ integrity sha512-oE1W1zSXU2L2LHg91V22HC3Z1fbsOZTBYUQq+kpM29f9297TbRm0C1l3bQ88RREl0WaUQaB49G7trvwy5utUKQ==
+ dependencies:
+ mdast-util-gfm-autolink-literal "^0.1.0"
+ mdast-util-gfm-strikethrough "^0.2.0"
+ mdast-util-gfm-table "^0.1.0"
+ mdast-util-gfm-task-list-item "^0.1.0"
+ mdast-util-to-markdown "^0.6.1"
+
+mdast-util-phrasing@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/mdast-util-phrasing/-/mdast-util-phrasing-2.0.0.tgz#57e61f2be908be9f5fce54fcc2fa593687986267"
+ integrity sha512-G1rNlW/sViwzbBYD7+k3mKGtoWV2v4GBFky66OYHfktHe7Hg9R+hH4xpeoOtjYiwTvle8C8wlKMpgqPCkaeK8Q==
+ dependencies:
+ unist-util-is "^4.0.0"
+
mdast-util-to-hast@^10.0.0:
version "10.1.1"
resolved "https://registry.yarnpkg.com/mdast-util-to-hast/-/mdast-util-to-hast-10.1.1.tgz#4dce367abdc57311a87cf95da54a4d115b9d25da"
@@ -6823,7 +6966,7 @@ mdast-util-to-hast@^10.0.0:
unist-util-position "^3.0.0"
unist-util-visit "^2.0.0"
-mdast-util-to-markdown@^0.6.2:
+mdast-util-to-markdown@^0.6.0, mdast-util-to-markdown@^0.6.1, mdast-util-to-markdown@^0.6.2, mdast-util-to-markdown@~0.6.0:
version "0.6.2"
resolved "https://registry.yarnpkg.com/mdast-util-to-markdown/-/mdast-util-to-markdown-0.6.2.tgz#8fe6f42a2683c43c5609dfb40407c095409c85b4"
integrity sha512-iRczns6WMvu0hUw02LXsPDJshBIwtUPbvHBWo19IQeU0YqmzlA8Pd30U8V7uiI0VPkxzS7A/NXBXH6u+HS87Zg==
@@ -6835,6 +6978,11 @@ mdast-util-to-markdown@^0.6.2:
repeat-string "^1.0.0"
zwitch "^1.0.0"
+mdast-util-to-string@^1.0.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-1.1.0.tgz#27055500103f51637bd07d01da01eb1967a43527"
+ integrity sha512-jVU0Nr2B9X3MU4tSK7JP1CMkSvOj7X5l/GboG1tKRw52lLF1x2Ju92Ms9tNetCcbfX3hzlM73zYo2NKkWSfF/A==
+
mdast-util-to-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/mdast-util-to-string/-/mdast-util-to-string-2.0.0.tgz#b8cfe6a713e1091cb5b728fc48885a4767f8b97b"
@@ -7801,6 +7949,11 @@ parse5@5.1.1:
resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178"
integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==
+parse5@^6.0.0:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
+ integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
+
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
@@ -8474,6 +8627,24 @@ regjsparser@^0.6.4:
dependencies:
jsesc "~0.5.0"
+rehype-minify-whitespace@^4.0.3:
+ version "4.0.5"
+ resolved "https://registry.yarnpkg.com/rehype-minify-whitespace/-/rehype-minify-whitespace-4.0.5.tgz#5b4781786116216f6d5d7ceadf84e2489dd7b3cd"
+ integrity sha512-QC3Z+bZ5wbv+jGYQewpAAYhXhzuH/TVRx7z08rurBmh9AbG8Nu8oJnvs9LWj43Fd/C7UIhXoQ7Wddgt+ThWK5g==
+ dependencies:
+ hast-util-embedded "^1.0.0"
+ hast-util-is-element "^1.0.0"
+ hast-util-whitespace "^1.0.4"
+ unist-util-is "^4.0.0"
+
+rehype-parse@^7.0.1:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/rehype-parse/-/rehype-parse-7.0.1.tgz#58900f6702b56767814afc2a9efa2d42b1c90c57"
+ integrity sha512-fOiR9a9xH+Le19i4fGzIEowAbwG7idy2Jzs4mOrFWBSJ0sNUgy0ev871dwWnbOo371SjgjG4pwzrbgSVrKxecw==
+ dependencies:
+ hast-util-from-parse5 "^6.0.0"
+ parse5 "^6.0.0"
+
relateurl@^0.2.7:
version "0.2.7"
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
@@ -9751,6 +9922,11 @@ trim-repeated@^1.0.0:
dependencies:
escape-string-regexp "^1.0.2"
+trim-trailing-lines@^1.1.0:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.4.tgz#bd4abbec7cc880462f10b2c8b5ce1d8d1ec7c2c0"
+ integrity sha512-rjUWSqnfTNrjbB9NQWfPMH/xRK1deHeGsHoVfpxJ++XeYXE0d6B1En37AHfw3jtfTU7dzMzZL2jjpe8Qb5gLIQ==
+
trough@^1.0.0:
version "1.0.5"
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.5.tgz#b8b639cefad7d0bb2abd37d433ff8293efa5f406"
@@ -9966,6 +10142,13 @@ unist-builder@^2.0.0, unist-builder@^2.0.3:
resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-2.0.3.tgz#77648711b5d86af0942f334397a33c5e91516436"
integrity sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==
+unist-util-find-after@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/unist-util-find-after/-/unist-util-find-after-3.0.0.tgz#5c65fcebf64d4f8f496db46fa8fd0fbf354b43e6"
+ integrity sha512-ojlBqfsBftYXExNu3+hHLfJQ/X1jYY/9vdm4yZWjIbf0VuWF6CRufci1ZyoD/wV2TYMKxXUoNuoqwy+CkgzAiQ==
+ dependencies:
+ unist-util-is "^4.0.0"
+
unist-util-find-all-between@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/unist-util-find-all-between/-/unist-util-find-all-between-2.1.0.tgz#18ddb51f7abc4e22c645b4321e82ab6a6decc640"
@@ -10250,6 +10433,11 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
+vfile-location@^3.2.0:
+ version "3.2.0"
+ resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-3.2.0.tgz#d8e41fbcbd406063669ebf6c33d56ae8721d0f3c"
+ integrity sha512-aLEIZKv/oxuCDZ8lkJGhuhztf/BW4M+iHdCwglA/eWc+vtuRFJj8EtgceYFX4LRjOhCAAiNHsKGssC6onJ+jbA==
+
vfile-message@^2.0.0:
version "2.0.4"
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
@@ -10327,6 +10515,11 @@ wcwidth@^1.0.1:
dependencies:
defaults "^1.0.3"
+web-namespaces@^1.0.0:
+ version "1.1.4"
+ resolved "https://registry.yarnpkg.com/web-namespaces/-/web-namespaces-1.1.4.tgz#bc98a3de60dadd7faefc403d1076d529f5e030ec"
+ integrity sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==
+
webidl-conversions@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
@@ -10578,7 +10771,7 @@ xmldom@0.1.x:
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff"
integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ==
-xtend@^4.0.0, xtend@~4.0.1:
+xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==