mirror of
https://github.com/overleaf/overleaf.git
synced 2024-11-21 20:47:08 -05:00
[cm6] Only swallow text in autocomplete insertion if node is well-formed (#12562)
* [cm6] Only swallow text in autocomplete insertion if node is well-formed * [cm6] Use longest common prefix heuristic for autocompletion in ill-formed nodes GitOrigin-RevId: 5adf3dc0314d86b267e2142a1250dece3ab29ef8
This commit is contained in:
parent
73191f56e1
commit
7d237d0103
1 changed files with 36 additions and 4 deletions
|
@ -7,6 +7,7 @@ import {
|
|||
} from '@codemirror/autocomplete'
|
||||
import { EditorView } from '@codemirror/view'
|
||||
import { prepareSnippetTemplate } from '../snippets'
|
||||
import { ancestorNodeOfType } from '../../../utils/tree-query'
|
||||
|
||||
// from https://github.com/codemirror/autocomplete/blob/main/src/closebrackets.ts
|
||||
export const nextChar = (doc: Text, pos: number) => {
|
||||
|
@ -39,11 +40,31 @@ export const createCommandApplier =
|
|||
view.dispatch(insertCompletionText(view.state, text, from, to))
|
||||
}
|
||||
|
||||
const longestCommonPrefix = (...strs: string[]) => {
|
||||
if (strs.length === 0) {
|
||||
return 0
|
||||
}
|
||||
const minLength = Math.min(...strs.map(str => str.length))
|
||||
for (let i = 0; i < minLength; ++i) {
|
||||
for (let j = 1; j < strs.length; ++j) {
|
||||
if (strs[j][i] !== strs[0][i]) {
|
||||
return i
|
||||
}
|
||||
}
|
||||
}
|
||||
return minLength
|
||||
}
|
||||
|
||||
// apply a completed required parameter, adding a closing brace and extending the range if needed
|
||||
export const createRequiredParameterApplier =
|
||||
(text: string) =>
|
||||
(view: EditorView, completion: Completion, from: number, to: number) => {
|
||||
const { doc } = view.state
|
||||
const argumentNode = ancestorNodeOfType(view.state, from, '$Argument')
|
||||
const isWellFormedArgumentNode =
|
||||
argumentNode &&
|
||||
argumentNode.getChild('OpenBrace') &&
|
||||
argumentNode.getChild('CloseBrace')
|
||||
|
||||
// add a closing brace if needed
|
||||
if (nextChar(doc, to) !== '}') {
|
||||
|
@ -51,11 +72,22 @@ export const createRequiredParameterApplier =
|
|||
text += '}'
|
||||
}
|
||||
|
||||
if (isWellFormedArgumentNode) {
|
||||
// extend over subsequent text that isn't a brace, space, or comma
|
||||
const match = doc.sliceString(to, doc.lineAt(from).to).match(/^[^}\s,]+/)
|
||||
const match = doc
|
||||
.sliceString(to, Math.min(doc.lineAt(from).to, argumentNode.to))
|
||||
.match(/^[^}\s,]+/)
|
||||
if (match) {
|
||||
to += match[0].length
|
||||
}
|
||||
} else {
|
||||
// Ensure we don't swallow a closing brace
|
||||
const restOfLine = doc
|
||||
.sliceString(to, Math.min(doc.lineAt(from).to, from + text.length))
|
||||
.split('}')[0]
|
||||
|
||||
to += longestCommonPrefix(text.slice(to - from), restOfLine)
|
||||
}
|
||||
}
|
||||
|
||||
view.dispatch(insertCompletionText(view.state, text, from, to))
|
||||
|
|
Loading…
Reference in a new issue