common.ts 1.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. import { ensureSyntaxTree } from '@codemirror/language'
  2. import { EditorState } from '@codemirror/state'
  3. import { IterMode, SyntaxNode, SyntaxNodeRef, Tree } from '@lezer/common'
  4. const HUNDRED_MS = 100
  5. export function iterateDescendantsOf(
  6. tree: Tree,
  7. ancestors: (string | number)[],
  8. spec: {
  9. enter(node: SyntaxNodeRef): boolean | void
  10. leave?(node: SyntaxNodeRef): void
  11. from?: number | undefined
  12. to?: number | undefined
  13. mode?: IterMode | undefined
  14. }
  15. ) {
  16. const filteredEnter = (node: SyntaxNodeRef): boolean | void => {
  17. if (!ancestors.some(x => node.type.is(x))) {
  18. return false
  19. }
  20. return spec.enter(node)
  21. }
  22. tree.iterate({ ...spec, enter: filteredEnter })
  23. }
  24. export const previousSiblingIs = (
  25. state: EditorState,
  26. pos: number,
  27. expectedName: string
  28. ): boolean | null => {
  29. const tree = ensureSyntaxTree(state, pos, HUNDRED_MS)
  30. if (!tree) {
  31. return null
  32. }
  33. const thisNode = tree.resolve(pos)
  34. const previousNode = thisNode?.prevSibling
  35. return previousNode?.type.name === expectedName
  36. }
  37. export const nextSiblingIs = (
  38. state: EditorState,
  39. pos: number,
  40. expectedName: string
  41. ): boolean | null => {
  42. const tree = ensureSyntaxTree(state, pos, HUNDRED_MS)
  43. if (!tree) {
  44. return null
  45. }
  46. const thisNode = tree.resolve(pos)
  47. const previousNode = thisNode?.nextSibling
  48. return previousNode?.type.name === expectedName
  49. }
  50. export const getOptionalArgumentText = (
  51. state: EditorState,
  52. optionalArgumentNode: SyntaxNode
  53. ): string | undefined => {
  54. const shortArgNode = optionalArgumentNode.getChild('ShortOptionalArg')
  55. if (shortArgNode) {
  56. return state.doc.sliceString(shortArgNode.from, shortArgNode.to)
  57. }
  58. }
  59. export const nodeHasError = (node: SyntaxNode): boolean => {
  60. let hasError = false
  61. node.cursor().iterate(({ type }) => {
  62. if (hasError) return false
  63. if (type.isError) {
  64. hasError = true
  65. return false
  66. }
  67. return true
  68. })
  69. return hasError
  70. }