| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129 |
- import {
- CharCategory,
- EditorState,
- SelectionRange,
- Text,
- } from '@codemirror/state'
- import {
- CloseBracketConfig,
- nextChar,
- prevChar,
- } from '@codemirror/autocomplete'
- export const closeBracketConfig: CloseBracketConfig = {
- brackets: ['$', '$$', '[', '{', '('],
- buildInsert(
- state: EditorState,
- range: SelectionRange,
- open: string,
- close: string
- ): string {
- switch (open) {
- // close for $ or $$
- case '$': {
- const prev = prevChar(state.doc, range.head)
- if (prev === '\\') {
- const preprev = prevChar(state.doc, range.head - prev.length)
- // add an unprefixed closing dollar to \\$
- if (preprev === '\\') {
- return open + '$'
- }
- // don't auto-close \$
- return open
- }
- const next = nextChar(state.doc, range.head)
- if (next === '\\') {
- // avoid auto-closing $ before a TeX command
- const pos = range.head + prev.length
- const postnext = nextChar(state.doc, pos)
- if (state.charCategorizer(pos)(postnext) !== CharCategory.Word) {
- return open + '$'
- }
- // don't auto-close $\command
- return open
- }
- // avoid creating an odd number of dollar signs
- const count = countSurroundingCharacters(state.doc, range.from, open)
- if (count % 2 !== 0) {
- return open
- }
- return open + close
- }
- // close for [ or \[
- case '[': {
- const prev = prevChar(state.doc, range.head)
- if (prev === '\\') {
- const preprev = prevChar(state.doc, range.head - prev.length)
- // add an unprefixed closing bracket to \\[
- if (preprev === '\\') {
- return open + ']'
- }
- return open + '\\' + close
- }
- return open + close
- }
- // only close for \(
- case '(': {
- const prev = prevChar(state.doc, range.head)
- if (prev === '\\') {
- const preprev = prevChar(state.doc, range.head - prev.length)
- // don't auto-close \\(
- if (preprev === '\\') {
- return open
- }
- return open + '\\' + close
- }
- return open
- }
- // only close for {
- case '{': {
- const prev = prevChar(state.doc, range.head)
- if (prev === '\\') {
- const preprev = prevChar(state.doc, range.head - prev.length)
- // add an unprefixed closing bracket to \\{
- if (preprev === '\\') {
- return open + '}'
- }
- // don't auto-close \{
- return open
- }
- return open + close
- }
- default:
- return open + close
- }
- },
- }
- function countSurroundingCharacters(doc: Text, pos: number, insert: string) {
- let count = 0
- // count backwards
- let to = pos
- do {
- const char = doc.sliceString(to - insert.length, to)
- if (char !== insert) {
- break
- }
- count++
- to--
- } while (to > 1)
- // count forwards
- let from = pos
- do {
- const char = doc.sliceString(from, from + insert.length)
- if (char !== insert) {
- break
- }
- count++
- from++
- } while (from < doc.length)
- return count
- }
|