common.ts 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  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. }