virt2/api/soft/CodeMirror/closebrackets/test/test-closebrackets.ts

122 lines
3.9 KiB
TypeScript
Raw Normal View History

import ist from "ist"
import {handleInsertion, handleBackspace} from "@codemirror/next/closebrackets"
import {EditorState, EditorSelection, languageData} from "@codemirror/next/state"
import {Text} from "@codemirror/next/text"
import {StreamSyntax} from "@codemirror/next/stream-syntax"
function s(doc = "", anchor = 0, head = anchor) {
return EditorState.create({doc, selection: EditorSelection.single(anchor, head)})
}
function same(s0: null | {doc: Text, selection: EditorSelection}, s1: {doc: Text, selection: EditorSelection}) {
ist(s0)
ist(s0!.doc.toString(), s1.doc.toString())
ist(JSON.stringify(s0!.selection), JSON.stringify(s1.selection))
}
describe("closeBrackets", () => {
it("closes brackets", () => {
same(handleInsertion(s(), "("), s("()", 1))
same(handleInsertion(s("foo", 3), "["), s("foo[]", 4))
same(handleInsertion(s(), "{"), s("{}", 1))
})
it("closes brackets before whitespace", () => {
same(handleInsertion(s("foo bar", 3), "("), s("foo() bar", 4))
same(handleInsertion(s("\t"), "{"), s("{}\t", 1))
})
it("doesn't close brackets before regular chars", () => {
ist(!handleInsertion(s("foo bar", 4), "("))
ist(!handleInsertion(s("foo bar", 5), "["))
ist(!handleInsertion(s("*"), "{"))
})
it("closes brackets before allowed chars", () => {
same(handleInsertion(s("foo }", 4), "("), s("foo ()}", 5))
same(handleInsertion(s("foo :", 4), "["), s("foo []:", 5))
})
it("surrounds selected content", () => {
same(handleInsertion(s("onetwothree", 3, 6), "("), s("one(two)three", 4, 7))
same(handleInsertion(s("okay", 4, 0), "["), s("[okay]", 5, 1))
})
it("skips matching close brackets", () => {
same(handleInsertion(s("foo()", 4), ")"), s("foo()", 5))
same(handleInsertion(s("[]x", 1), "]"), s("[]x", 2))
})
it("doesn't skip when there's a selection", () => {
ist(!handleInsertion(s("(a)", 1, 2), ")"))
})
it("doesn't skip when the next char doesn't match", () => {
ist(!handleInsertion(s("(a)", 1, 2), "]"))
})
it("closes quotes", () => {
same(handleInsertion(s(), "'"), s("''", 1))
same(handleInsertion(s("foo ", 4), "\""), s("foo \"\"", 5))
})
it("wraps quotes around the selection", () => {
same(handleInsertion(s("a b c", 2, 3), "'"), s("a 'b' c", 3, 4))
same(handleInsertion(s("boop", 3, 1), "'"), s("b'oo'p", 4, 2))
})
it("doesn't close quotes in words", () => {
ist(!handleInsertion(s("ab", 1), "'"))
ist(!handleInsertion(s("ab", 2), "'"))
ist(!handleInsertion(s("ab", 0), "'"))
})
const syntax = new StreamSyntax({
docProps: [[languageData, {closeBrackets: {brackets: ["(", "'", "'''"]}}]],
token(stream) {
if (stream.match("'''")) {
while (!stream.match("'''") && !stream.eol()) stream.next()
return "string"
} else if (stream.match("'")) {
while (!stream.match("'") && !stream.eol()) stream.next()
return "string"
} else {
stream.next()
return ""
}
}
})
function st(doc = "", anchor = 0, head = anchor) {
return EditorState.create({doc, selection: EditorSelection.single(anchor, head), extensions: [syntax.extension]})
}
it("skips closing quotes", () => {
same(handleInsertion(st("'foo'", 4), "'"), st("'foo'", 5))
})
it("closes triple-quotes", () => {
same(handleInsertion(st("''", 2), "'"), st("''''''", 3))
})
it("skips closing triple-quotes", () => {
same(handleInsertion(st("''''''", 3), "'"), st("''''''", 6))
})
it("closes quotes before another string", () => {
same(handleInsertion(st("foo ''", 4), "'"), st("foo ''''", 5))
})
it("backspaces out pairs of brackets", () => {
same(handleBackspace(st("()", 1)), st(""))
same(handleBackspace(st("okay ''", 6)), st("okay ", 5))
})
it("doesn't backspace out non-brackets", () => {
ist(!handleBackspace(st("(]", 1)))
ist(!handleBackspace(st("(", 1)))
ist(!handleBackspace(st("-]", 1)))
ist(!handleBackspace(st("", 0)))
})
})