language.ts 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. import {
  2. Compartment,
  3. StateEffect,
  4. StateField,
  5. TransactionSpec,
  6. } from '@codemirror/state'
  7. import { languages } from '../languages'
  8. import { ViewPlugin } from '@codemirror/view'
  9. import { indentUnit, LanguageDescription } from '@codemirror/language'
  10. import { Metadata } from '../../../../../types/metadata'
  11. import { CurrentDoc } from '../../../../../types/current-doc'
  12. import { updateHasEffect } from '../utils/effects'
  13. export const languageLoadedEffect = StateEffect.define()
  14. export const hasLanguageLoadedEffect = updateHasEffect(languageLoadedEffect)
  15. const languageConf = new Compartment()
  16. type Options = {
  17. syntaxValidation: boolean
  18. }
  19. export const metadataState = StateField.define<Metadata | undefined>({
  20. create: () => undefined,
  21. update: (value, transaction) => {
  22. for (const effect of transaction.effects) {
  23. if (effect.is(setMetadataEffect)) {
  24. return effect.value
  25. }
  26. }
  27. return value
  28. },
  29. })
  30. export const language = (
  31. currentDoc: CurrentDoc,
  32. metadata: Metadata,
  33. { syntaxValidation }: Options
  34. ) => {
  35. const languageDescription = LanguageDescription.matchFilename(
  36. languages,
  37. currentDoc.docName
  38. )
  39. if (!languageDescription) {
  40. return []
  41. }
  42. return [
  43. // Default to four-space indentation, which prevents a shift in line
  44. // indentation markers when LaTeX loads
  45. languageConf.of(indentUnit.of(' ')),
  46. metadataState,
  47. ViewPlugin.define(view => {
  48. // load the language asynchronously
  49. languageDescription.load().then(support => {
  50. view.dispatch({
  51. effects: [
  52. languageConf.reconfigure(support),
  53. languageLoadedEffect.of(null),
  54. ],
  55. })
  56. // Wait until the previous effects have been processed
  57. view.dispatch({
  58. effects: [
  59. setMetadataEffect.of(metadata),
  60. setSyntaxValidationEffect.of(syntaxValidation),
  61. ],
  62. })
  63. })
  64. return {}
  65. }),
  66. metadataState,
  67. ]
  68. }
  69. export const setMetadataEffect = StateEffect.define<Metadata>()
  70. export const setMetadata = (values: Metadata): TransactionSpec => {
  71. return {
  72. effects: setMetadataEffect.of(values),
  73. }
  74. }
  75. export const setSyntaxValidationEffect = StateEffect.define<boolean>()
  76. export const setSyntaxValidation = (value: boolean): TransactionSpec => {
  77. return {
  78. effects: setSyntaxValidationEffect.of(value),
  79. }
  80. }