1
0
silverbullet/web/smart_quotes.ts

63 lines
1.6 KiB
TypeScript
Raw Normal View History

import { KeyBinding } from "./deps.ts";
import { syntaxTree } from "../common/deps.ts";
2022-04-24 16:06:34 +00:00
const straightQuoteContexts = [
"CommentBlock",
"FencedCode",
"InlineCode",
"FrontMatterCode",
];
// TODO: Add support for selection (put quotes around or create blockquote block?)
function keyBindingForQuote(
quote: string,
left: string,
right: string,
): KeyBinding {
return {
2022-11-09 08:35:26 +00:00
any: (target, event): boolean => {
// Moving this check here rather than using the regular "key" property because
// for some reason the "ä" key is not recognized as a quote key by CodeMirror.
if (event.key !== quote) {
return false;
}
const cursorPos = target.state.selection.main.from;
const chBefore = target.state.sliceDoc(cursorPos - 1, cursorPos);
2022-04-24 16:06:34 +00:00
// Figure out the context, if in some sort of code/comment fragment don't be smart
let node = syntaxTree(target.state).resolveInner(cursorPos);
while (node) {
if (straightQuoteContexts.includes(node.type.name)) {
return false;
}
if (node.parent) {
node = node.parent;
} else {
break;
}
}
// Ok, still here, let's use a smart quote
2022-11-09 08:35:26 +00:00
let q = right;
if (/\W/.exec(chBefore) && !/[!\?,\.\-=“]/.exec(chBefore)) {
2022-11-09 08:35:26 +00:00
q = left;
}
target.dispatch({
changes: {
2022-11-09 08:35:26 +00:00
insert: q,
from: cursorPos,
},
selection: {
anchor: cursorPos + 1,
},
});
return true;
},
};
}
export const smartQuoteKeymap: KeyBinding[] = [
keyBindingForQuote('"', "“", "”"),
keyBindingForQuote("'", "", ""),
];