Uses the grammar marijn made :) (#2967)
* Add a Lezer KCL grammar * fmt Signed-off-by: Jess Frazelle <github@jessfraz.com> * make tsc happy Signed-off-by: Jess Frazelle <github@jessfraz.com> * turn off semantic tokens in favor of grammar Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * fixups Signed-off-by: Jess Frazelle <github@jessfraz.com> * A snapshot a day keeps the bugs away! 📷🐛 (OS: ubuntu) * empty --------- Signed-off-by: Jess Frazelle <github@jessfraz.com> Co-authored-by: Marijn Haverbeke <marijn@haverbeke.berlin> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
@ -560,6 +560,50 @@ test.describe('Testing Camera Movement', () => {
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
test.describe('Editor tests', () => {
 | 
			
		||||
  test('can comment out code with ctrl+/', async ({ page }) => {
 | 
			
		||||
    const u = await getUtils(page)
 | 
			
		||||
    await page.setViewportSize({ width: 1000, height: 500 })
 | 
			
		||||
 | 
			
		||||
    await u.waitForAuthSkipAppStart()
 | 
			
		||||
    const CtrlKey = process.platform === 'darwin' ? 'Meta' : 'Control'
 | 
			
		||||
 | 
			
		||||
    // check no error to begin with
 | 
			
		||||
    await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
 | 
			
		||||
 | 
			
		||||
    await u.codeLocator.click()
 | 
			
		||||
    await page.keyboard.type(`const sketch001 = startSketchOn('XY')
 | 
			
		||||
  |> startProfileAt([-10, -10], %)
 | 
			
		||||
  |> line([20, 0], %)
 | 
			
		||||
  |> line([0, 20], %)
 | 
			
		||||
  |> line([-20, 0], %)
 | 
			
		||||
  |> close(%)`)
 | 
			
		||||
 | 
			
		||||
    await page.keyboard.down(CtrlKey)
 | 
			
		||||
    await page.keyboard.press('/')
 | 
			
		||||
    await page.keyboard.up(CtrlKey)
 | 
			
		||||
 | 
			
		||||
    await expect(page.locator('.cm-content'))
 | 
			
		||||
      .toHaveText(`const sketch001 = startSketchOn('XY')
 | 
			
		||||
    |> startProfileAt([-10, -10], %)
 | 
			
		||||
    |> line([20, 0], %)
 | 
			
		||||
    |> line([0, 20], %)
 | 
			
		||||
    |> line([-20, 0], %)
 | 
			
		||||
    // |> close(%)`)
 | 
			
		||||
 | 
			
		||||
    // uncomment the code
 | 
			
		||||
    await page.keyboard.down(CtrlKey)
 | 
			
		||||
    await page.keyboard.press('/')
 | 
			
		||||
    await page.keyboard.up(CtrlKey)
 | 
			
		||||
 | 
			
		||||
    await expect(page.locator('.cm-content'))
 | 
			
		||||
      .toHaveText(`const sketch001 = startSketchOn('XY')
 | 
			
		||||
    |> startProfileAt([-10, -10], %)
 | 
			
		||||
    |> line([20, 0], %)
 | 
			
		||||
    |> line([0, 20], %)
 | 
			
		||||
    |> line([-20, 0], %)
 | 
			
		||||
    |> close(%)`)
 | 
			
		||||
  })
 | 
			
		||||
 | 
			
		||||
  test('if you click the format button it formats your code', async ({
 | 
			
		||||
    page,
 | 
			
		||||
  }) => {
 | 
			
		||||
 | 
			
		||||
| 
		 Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 44 KiB  | 
| 
		 Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB  | 
| 
		 Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB  | 
| 
		 Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 45 KiB  | 
| 
		 Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 36 KiB  | 
| 
		 Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 39 KiB  | 
| 
		 Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 71 KiB  | 
| 
		 Before Width: | Height: | Size: 43 KiB After Width: | Height: | Size: 43 KiB  | 
| 
		 Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB  | 
@ -18,6 +18,8 @@
 | 
			
		||||
    "@headlessui/react": "^1.7.19",
 | 
			
		||||
    "@headlessui/tailwindcss": "^0.2.0",
 | 
			
		||||
    "@kittycad/lib": "^0.0.70",
 | 
			
		||||
    "@lezer/highlight": "^1.2.0",
 | 
			
		||||
    "@lezer/lr": "^1.4.1",
 | 
			
		||||
    "@react-hook/resize-observer": "^2.0.1",
 | 
			
		||||
    "@replit/codemirror-interact": "^6.3.1",
 | 
			
		||||
    "@tauri-apps/api": "^2.0.0-beta.14",
 | 
			
		||||
@ -109,6 +111,7 @@
 | 
			
		||||
    "@babel/plugin-proposal-private-property-in-object": "^7.21.11",
 | 
			
		||||
    "@babel/preset-env": "^7.24.3",
 | 
			
		||||
    "@iarna/toml": "^2.2.5",
 | 
			
		||||
    "@lezer/generator": "^1.7.1",
 | 
			
		||||
    "@playwright/test": "^1.45.1",
 | 
			
		||||
    "@tauri-apps/cli": "==2.0.0-beta.13",
 | 
			
		||||
    "@testing-library/jest-dom": "^5.14.1",
 | 
			
		||||
 | 
			
		||||
@ -71,6 +71,9 @@ export interface LanguageServerOptions {
 | 
			
		||||
  ) => void
 | 
			
		||||
 | 
			
		||||
  changesDelay?: number
 | 
			
		||||
 | 
			
		||||
  doSemanticTokens?: boolean
 | 
			
		||||
  doFoldingRanges?: boolean
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export class LanguageServerPlugin implements PluginValue {
 | 
			
		||||
@ -87,6 +90,9 @@ export class LanguageServerPlugin implements PluginValue {
 | 
			
		||||
    notification: LSP.NotificationMessage
 | 
			
		||||
  ) => void
 | 
			
		||||
 | 
			
		||||
  private doSemanticTokens: boolean = false
 | 
			
		||||
  private doFoldingRanges: boolean = false
 | 
			
		||||
 | 
			
		||||
  private _defferer = deferExecution((code: string) => {
 | 
			
		||||
    try {
 | 
			
		||||
      // Update the state (not the editor) with the new code.
 | 
			
		||||
@ -109,6 +115,9 @@ export class LanguageServerPlugin implements PluginValue {
 | 
			
		||||
    this.client = options.client
 | 
			
		||||
    this.documentVersion = 0
 | 
			
		||||
 | 
			
		||||
    this.doSemanticTokens = options.doSemanticTokens ?? false
 | 
			
		||||
    this.doFoldingRanges = options.doFoldingRanges ?? false
 | 
			
		||||
 | 
			
		||||
    if (options.changesDelay) {
 | 
			
		||||
      this.changesDelay = options.changesDelay
 | 
			
		||||
    }
 | 
			
		||||
@ -220,6 +229,7 @@ export class LanguageServerPlugin implements PluginValue {
 | 
			
		||||
 | 
			
		||||
  async getFoldingRanges(): Promise<LSP.FoldingRange[] | null> {
 | 
			
		||||
    if (
 | 
			
		||||
      !this.doFoldingRanges ||
 | 
			
		||||
      !this.client.ready ||
 | 
			
		||||
      !this.client.getServerCapabilities().foldingRangeProvider
 | 
			
		||||
    )
 | 
			
		||||
@ -445,6 +455,7 @@ export class LanguageServerPlugin implements PluginValue {
 | 
			
		||||
 | 
			
		||||
  async requestSemanticTokens() {
 | 
			
		||||
    if (
 | 
			
		||||
      !this.doSemanticTokens ||
 | 
			
		||||
      !this.client.ready ||
 | 
			
		||||
      !this.client.getServerCapabilities().semanticTokensProvider
 | 
			
		||||
    ) {
 | 
			
		||||
 | 
			
		||||
@ -8,7 +8,7 @@ import {
 | 
			
		||||
  LanguageServerPlugin,
 | 
			
		||||
} from '@kittycad/codemirror-lsp-client'
 | 
			
		||||
import { TEST, VITE_KC_API_BASE_URL } from 'env'
 | 
			
		||||
import KclLanguageSupport from 'editor/plugins/lsp/kcl/language'
 | 
			
		||||
import { kcl } from 'editor/plugins/lsp/kcl/language'
 | 
			
		||||
import { copilotPlugin } from 'editor/plugins/lsp/copilot'
 | 
			
		||||
import { useSettingsAuthContext } from 'hooks/useSettingsAuthContext'
 | 
			
		||||
import { Extension } from '@codemirror/state'
 | 
			
		||||
@ -146,7 +146,7 @@ export const LspProvider = ({ children }: { children: React.ReactNode }) => {
 | 
			
		||||
    let plugin = null
 | 
			
		||||
    if (isKclLspReady && !TEST && kclLspClient) {
 | 
			
		||||
      // Set up the lsp plugin.
 | 
			
		||||
      const lsp = new KclLanguageSupport({
 | 
			
		||||
      const lsp = kcl({
 | 
			
		||||
        documentUri: `file:///${PROJECT_ENTRYPOINT}`,
 | 
			
		||||
        workspaceFolders: getWorkspaceFolders(),
 | 
			
		||||
        client: kclLspClient,
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										26
									
								
								src/editor/plugins/lsp/kcl/highlight.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,26 @@
 | 
			
		||||
import { styleTags, tags as t } from '@lezer/highlight'
 | 
			
		||||
 | 
			
		||||
export const klcHighlight = styleTags({
 | 
			
		||||
  'fn var let const': t.definitionKeyword,
 | 
			
		||||
  return: t.controlKeyword,
 | 
			
		||||
  'true false': t.bool,
 | 
			
		||||
  nil: t.null,
 | 
			
		||||
  'AddOp MultOp ExpOp': t.arithmeticOperator,
 | 
			
		||||
  CompOp: t.logicOperator,
 | 
			
		||||
  'Equals Arrow': t.definitionOperator,
 | 
			
		||||
  PipeOperator: t.controlOperator,
 | 
			
		||||
  String: t.string,
 | 
			
		||||
  Number: t.number,
 | 
			
		||||
  LineComment: t.lineComment,
 | 
			
		||||
  BlockComment: t.blockComment,
 | 
			
		||||
  Shebang: t.meta,
 | 
			
		||||
  PipeSubstitution: t.atom,
 | 
			
		||||
  VariableDefinition: t.definition(t.variableName),
 | 
			
		||||
  VariableName: t.variableName,
 | 
			
		||||
  PropertyName: t.propertyName,
 | 
			
		||||
  TagDeclarator: t.tagName,
 | 
			
		||||
  '( )': t.paren,
 | 
			
		||||
  '{ }': t.brace,
 | 
			
		||||
  '[ ]': t.bracket,
 | 
			
		||||
  ', . : ? ..': t.punctuation,
 | 
			
		||||
})
 | 
			
		||||
							
								
								
									
										113
									
								
								src/editor/plugins/lsp/kcl/kcl.grammar
									
									
									
									
									
										Normal file
									
								
							
							
						
						@ -0,0 +1,113 @@
 | 
			
		||||
@precedence {
 | 
			
		||||
  member
 | 
			
		||||
  call
 | 
			
		||||
  exp @left
 | 
			
		||||
  mult @left
 | 
			
		||||
  add @left
 | 
			
		||||
  comp @left
 | 
			
		||||
  pipe @left
 | 
			
		||||
  range
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@top Program {
 | 
			
		||||
  Shebang?
 | 
			
		||||
  statement*
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
statement[@isGroup=Statement] {
 | 
			
		||||
  FunctionDeclaration { kw<"fn"> VariableDefinition Equals ParamList Arrow Body } |
 | 
			
		||||
  VariableDeclaration { (kw<"var"> | kw<"let"> | kw<"const">) VariableDefinition Equals expression } |
 | 
			
		||||
  ReturnStatement { kw<"return"> expression } |
 | 
			
		||||
  ExpressionStatement { expression }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ParamList { "(" commaSep<Parameter { VariableDefinition "?"? (":" type)? }> ")" }
 | 
			
		||||
 | 
			
		||||
Body { "{" statement* "}" }
 | 
			
		||||
 | 
			
		||||
expression[@isGroup=Expression] {
 | 
			
		||||
  String |
 | 
			
		||||
  Number |
 | 
			
		||||
  VariableName |
 | 
			
		||||
  TagDeclarator |
 | 
			
		||||
  kw<"true"> | kw<"false"> | kw<"nil"> |
 | 
			
		||||
  PipeSubstitution |
 | 
			
		||||
  BinaryExpression {
 | 
			
		||||
    expression !add AddOp expression |
 | 
			
		||||
    expression !mult MultOp expression |
 | 
			
		||||
    expression !exp ExpOp expression |
 | 
			
		||||
    expression !comp CompOp expression
 | 
			
		||||
  } |
 | 
			
		||||
  UnaryExpression { AddOp expression } |
 | 
			
		||||
  ParenthesizedExpression { "(" expression ")" } |
 | 
			
		||||
  CallExpression { expression !call ArgumentList } |
 | 
			
		||||
  ArrayExpression { "[" commaSep<expression | IntegerRange { expression !range ".." expression }> "]" } |
 | 
			
		||||
  ObjectExpression { "{" commaSep<ObjectProperty> "}" } |
 | 
			
		||||
  MemberExpression { expression !member "." PropertyName } |
 | 
			
		||||
  SubscriptExpression { expression !member "[" expression "]" } |
 | 
			
		||||
  PipeExpression { expression (!pipe PipeOperator expression)+ }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ObjectProperty { PropertyName ":" expression }
 | 
			
		||||
 | 
			
		||||
ArgumentList { "(" commaSep<expression> ")" }
 | 
			
		||||
 | 
			
		||||
type[@isGroup=Type] {
 | 
			
		||||
  @specialize[@name=PrimitiveType]<
 | 
			
		||||
    identifier,
 | 
			
		||||
    "string" | "number" | "bool" | "sketch_group" | "sketch_surface" | "extrude_group"
 | 
			
		||||
  > |
 | 
			
		||||
  ArrayType { type !member "[" "]" } |
 | 
			
		||||
  ObjectType { "{" commaSep<ObjectProperty { PropertyName ":" type }> "}" }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
VariableDefinition { identifier }
 | 
			
		||||
 | 
			
		||||
VariableName { identifier }
 | 
			
		||||
 | 
			
		||||
@skip { whitespace | LineComment | BlockComment }
 | 
			
		||||
 | 
			
		||||
kw<term> { @specialize[@name={term}]<identifier, term> }
 | 
			
		||||
 | 
			
		||||
commaSep<term> { (term ("," term)*)? ","? }
 | 
			
		||||
 | 
			
		||||
@tokens {
 | 
			
		||||
  String[isolate] { "'" ("\\" _ | !['\\])* "'" | '"' ("\\" _ | !["\\])* '"' }
 | 
			
		||||
 | 
			
		||||
  Number { "." @digit+ | @digit+ ("." @digit*)? }
 | 
			
		||||
  @precedence { Number, "." }
 | 
			
		||||
 | 
			
		||||
  AddOp { "+" | "-" }
 | 
			
		||||
  MultOp { "/" | "*" | "\\" }
 | 
			
		||||
  ExpOp { "^" }
 | 
			
		||||
  CompOp { $[<>] "="? | "!=" | "==" }
 | 
			
		||||
  Equals { "=" }
 | 
			
		||||
  Arrow { "=>" }
 | 
			
		||||
  PipeOperator { "|>" }
 | 
			
		||||
 | 
			
		||||
  PipeSubstitution { "%" }
 | 
			
		||||
 | 
			
		||||
  identifier { (@asciiLetter | "_") (@asciiLetter | @digit | "_")* }
 | 
			
		||||
  PropertyName { identifier }
 | 
			
		||||
  TagDeclarator { "$" identifier }
 | 
			
		||||
 | 
			
		||||
  whitespace { @whitespace+ }
 | 
			
		||||
 | 
			
		||||
  LineComment[isolate] { "//" ![\n]* }
 | 
			
		||||
  BlockComment[isolate] { "/*" blockCommentRest }
 | 
			
		||||
  blockCommentRest { @eof | ![*] blockCommentRest | "*" blockCommentStar }
 | 
			
		||||
  blockCommentStar { @eof | "/" | ![/] blockCommentRest | "*" blockCommentStar }
 | 
			
		||||
 | 
			
		||||
  @precedence { LineComment, BlockComment, MultOp }
 | 
			
		||||
 | 
			
		||||
  Shebang { "#!" ![\n]* }
 | 
			
		||||
 | 
			
		||||
  "(" ")"
 | 
			
		||||
  "{" "}"
 | 
			
		||||
  "[" "]"
 | 
			
		||||
  "," "?" ":" "." ".."
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@external propSource klcHighlight from "./highlight"
 | 
			
		||||
 | 
			
		||||
@detectDelim
 | 
			
		||||
@ -1,9 +1,13 @@
 | 
			
		||||
// Code mirror language implementation for kcl.
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  Language,
 | 
			
		||||
  defineLanguageFacet,
 | 
			
		||||
  LRLanguage,
 | 
			
		||||
  LanguageSupport,
 | 
			
		||||
  indentNodeProp,
 | 
			
		||||
  continuedIndent,
 | 
			
		||||
  delimitedIndent,
 | 
			
		||||
  foldNodeProp,
 | 
			
		||||
  foldInside,
 | 
			
		||||
} from '@codemirror/language'
 | 
			
		||||
import {
 | 
			
		||||
  LanguageServerClient,
 | 
			
		||||
@ -11,18 +15,8 @@ import {
 | 
			
		||||
} from '@kittycad/codemirror-lsp-client'
 | 
			
		||||
import { kclPlugin } from '.'
 | 
			
		||||
import type * as LSP from 'vscode-languageserver-protocol'
 | 
			
		||||
import KclParser from './parser'
 | 
			
		||||
 | 
			
		||||
const data = defineLanguageFacet({
 | 
			
		||||
  // https://codemirror.net/docs/ref/#commands.CommentTokens
 | 
			
		||||
  commentTokens: {
 | 
			
		||||
    line: '//',
 | 
			
		||||
    block: {
 | 
			
		||||
      open: '/*',
 | 
			
		||||
      close: '*/',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
})
 | 
			
		||||
// @ts-ignore: No types available
 | 
			
		||||
import { parser } from './kcl.grammar'
 | 
			
		||||
 | 
			
		||||
export interface LanguageOptions {
 | 
			
		||||
  workspaceFolders: LSP.WorkspaceFolder[]
 | 
			
		||||
@ -34,26 +28,40 @@ export interface LanguageOptions {
 | 
			
		||||
  ) => void
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class KclLanguage extends Language {
 | 
			
		||||
  constructor(options: LanguageOptions) {
 | 
			
		||||
    const plugin = kclPlugin({
 | 
			
		||||
export const KclLanguage = LRLanguage.define({
 | 
			
		||||
  name: 'klc',
 | 
			
		||||
  parser: parser.configure({
 | 
			
		||||
    props: [
 | 
			
		||||
      indentNodeProp.add({
 | 
			
		||||
        Body: delimitedIndent({ closing: '}' }),
 | 
			
		||||
        BlockComment: () => null,
 | 
			
		||||
        'Statement Property': continuedIndent({ except: /^{/ }),
 | 
			
		||||
      }),
 | 
			
		||||
      foldNodeProp.add({
 | 
			
		||||
        'Body ArrayExpression ObjectExpression': foldInside,
 | 
			
		||||
        BlockComment(tree) {
 | 
			
		||||
          return { from: tree.from + 2, to: tree.to - 2 }
 | 
			
		||||
        },
 | 
			
		||||
        PipeExpression(tree) {
 | 
			
		||||
          return { from: tree.firstChild!.to, to: tree.to }
 | 
			
		||||
        },
 | 
			
		||||
      }),
 | 
			
		||||
    ],
 | 
			
		||||
  }),
 | 
			
		||||
  languageData: {
 | 
			
		||||
    commentTokens: { line: '//', block: { open: '/*', close: '*/' } },
 | 
			
		||||
  },
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
export function kcl(options: LanguageOptions) {
 | 
			
		||||
  return new LanguageSupport(
 | 
			
		||||
    KclLanguage,
 | 
			
		||||
    kclPlugin({
 | 
			
		||||
      documentUri: options.documentUri,
 | 
			
		||||
      workspaceFolders: options.workspaceFolders,
 | 
			
		||||
      allowHTMLContent: true,
 | 
			
		||||
      client: options.client,
 | 
			
		||||
      processLspNotification: options.processLspNotification,
 | 
			
		||||
    })
 | 
			
		||||
 | 
			
		||||
    const parser = new KclParser()
 | 
			
		||||
 | 
			
		||||
    super(data, parser, [plugin], 'kcl')
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class KclLanguageSupport extends LanguageSupport {
 | 
			
		||||
  constructor(options: LanguageOptions) {
 | 
			
		||||
    const lang = new KclLanguage(options)
 | 
			
		||||
 | 
			
		||||
    super(lang)
 | 
			
		||||
  }
 | 
			
		||||
  )
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,47 +0,0 @@
 | 
			
		||||
// Extends the codemirror Parser for kcl.
 | 
			
		||||
// This is really just a no-op parser since we use semantic tokens from the LSP
 | 
			
		||||
// server.
 | 
			
		||||
 | 
			
		||||
import {
 | 
			
		||||
  Parser,
 | 
			
		||||
  Input,
 | 
			
		||||
  TreeFragment,
 | 
			
		||||
  PartialParse,
 | 
			
		||||
  Tree,
 | 
			
		||||
  NodeType,
 | 
			
		||||
} from '@lezer/common'
 | 
			
		||||
import { DocInput } from '@codemirror/language'
 | 
			
		||||
 | 
			
		||||
export default class KclParser extends Parser {
 | 
			
		||||
  createParse(
 | 
			
		||||
    input: Input,
 | 
			
		||||
    fragments: readonly TreeFragment[],
 | 
			
		||||
    ranges: readonly { from: number; to: number }[]
 | 
			
		||||
  ): PartialParse {
 | 
			
		||||
    let parse: PartialParse = new Context(input)
 | 
			
		||||
    return parse
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class Context implements PartialParse {
 | 
			
		||||
  private input: DocInput
 | 
			
		||||
 | 
			
		||||
  stoppedAt: number = 0
 | 
			
		||||
 | 
			
		||||
  constructor(input: Input) {
 | 
			
		||||
    this.input = input as DocInput
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  get parsedPos(): number {
 | 
			
		||||
    return 0
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  advance(): Tree | null {
 | 
			
		||||
    this.stoppedAt = this.input.doc.length
 | 
			
		||||
    return new Tree(NodeType.none, [], [], this.input.doc.length)
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  stopAt(pos: number) {
 | 
			
		||||
    this.stoppedAt = pos
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -12,7 +12,8 @@
 | 
			
		||||
      "@types/wicg-file-system-access",
 | 
			
		||||
      "node",
 | 
			
		||||
      "@wdio/globals/types",
 | 
			
		||||
      "mocha"
 | 
			
		||||
      "mocha",
 | 
			
		||||
      "@lezer/generator"
 | 
			
		||||
    ],
 | 
			
		||||
    "target": "esnext",
 | 
			
		||||
    "lib": ["dom", "dom.iterable", "esnext"],
 | 
			
		||||
@ -32,6 +33,6 @@
 | 
			
		||||
    "jsx": "react-jsx"
 | 
			
		||||
  },
 | 
			
		||||
  "include": ["src", "e2e", "packages", "./*.ts"],
 | 
			
		||||
  "exclude": ["node_modules"],
 | 
			
		||||
  "exclude": ["node_modules", "./*.grammar"],
 | 
			
		||||
  "references": [{ "path": "./tsconfig.node.json" }]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,8 @@ import viteTsconfigPaths from 'vite-tsconfig-paths'
 | 
			
		||||
import eslint from 'vite-plugin-eslint'
 | 
			
		||||
import { defineConfig, configDefaults } from 'vitest/config'
 | 
			
		||||
import version from 'vite-plugin-package-version'
 | 
			
		||||
// @ts-ignore: No types available
 | 
			
		||||
import { lezer } from '@lezer/generator/rollup'
 | 
			
		||||
 | 
			
		||||
const config = defineConfig({
 | 
			
		||||
  server: {
 | 
			
		||||
@ -58,7 +60,7 @@ const config = defineConfig({
 | 
			
		||||
      '@kittycad/codemirror-lsp-client': '/packages/codemirror-lsp-client/src',
 | 
			
		||||
    },
 | 
			
		||||
  },
 | 
			
		||||
  plugins: [react(), viteTsconfigPaths(), eslint(), version()],
 | 
			
		||||
  plugins: [react(), viteTsconfigPaths(), eslint(), version(), lezer()],
 | 
			
		||||
  worker: {
 | 
			
		||||
    plugins: () => [viteTsconfigPaths()],
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										12
									
								
								yarn.lock
									
									
									
									
									
								
							
							
						
						@ -1643,14 +1643,22 @@
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@lezer/common/-/common-1.2.1.tgz#198b278b7869668e1bebbe687586e12a42731049"
 | 
			
		||||
  integrity sha512-yemX0ZD2xS/73llMZIK6KplkjIjf2EvAHcinDi/TfJ9hS25G0388+ClHt6/3but0oOxinTcQHJLDXh6w1crzFQ==
 | 
			
		||||
 | 
			
		||||
"@lezer/highlight@^1.0.0":
 | 
			
		||||
"@lezer/generator@^1.7.1":
 | 
			
		||||
  version "1.7.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@lezer/generator/-/generator-1.7.1.tgz#90c1a9de2fb4d5a714216fa659058c7859accaab"
 | 
			
		||||
  integrity sha512-MgPJN9Si+ccxzXl3OAmCeZuUKw4XiPl4y664FX/hnnyG9CTqUPq65N3/VGPA2jD23D7QgMTtNqflta+cPN+5mQ==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@lezer/common" "^1.1.0"
 | 
			
		||||
    "@lezer/lr" "^1.3.0"
 | 
			
		||||
 | 
			
		||||
"@lezer/highlight@^1.0.0", "@lezer/highlight@^1.2.0":
 | 
			
		||||
  version "1.2.0"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@lezer/highlight/-/highlight-1.2.0.tgz#e5898c3644208b4b589084089dceeea2966f7780"
 | 
			
		||||
  integrity sha512-WrS5Mw51sGrpqjlh3d4/fOwpEV2Hd3YOkp9DBt4k8XZQcoTHZFB7sx030A6OcahF4J1nDQAa3jXlTVVYH50IFA==
 | 
			
		||||
  dependencies:
 | 
			
		||||
    "@lezer/common" "^1.0.0"
 | 
			
		||||
 | 
			
		||||
"@lezer/lr@^1.0.0":
 | 
			
		||||
"@lezer/lr@^1.0.0", "@lezer/lr@^1.3.0", "@lezer/lr@^1.4.1":
 | 
			
		||||
  version "1.4.1"
 | 
			
		||||
  resolved "https://registry.yarnpkg.com/@lezer/lr/-/lr-1.4.1.tgz#fe25f051880a754e820b28148d90aa2a96b8bdd2"
 | 
			
		||||
  integrity sha512-CHsKq8DMKBf9b3yXPDIU4DbH+ZJd/sJdYOW2llbW/HudP5u0VS6Bfq1hLYfgU7uAYGFIyGGQIsSOXGPEErZiJw==
 | 
			
		||||
 | 
			
		||||