fixes up some playwright tests and adds a test for the ghost text plugin only in dev mode (#2849)

* things

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* things

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix up most tests

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixups

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fixes

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix lints

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* typo

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2024-06-30 18:26:16 -07:00
committed by GitHub
parent 5f5ecc5afe
commit 5fbbe2fa8c
9 changed files with 332 additions and 50 deletions

View File

@ -482,19 +482,19 @@ test.describe('Testing Camera Movement', () => {
await page.waitForTimeout(100)
// hover over horizontal line
await page.mouse.move(858, y, { steps: 5 })
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await hoverOverNothing()
// hover over vertical line
await page.mouse.move(x, 325)
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await hoverOverNothing()
// hover over vertical line
await page.mouse.move(857, y)
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
// now click it
await page.mouse.click(857, y)
@ -511,7 +511,7 @@ test.describe('Testing Camera Movement', () => {
await page.waitForTimeout(100)
await page.mouse.move(x, 419, { steps: 5 })
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await hoverOverNothing()
@ -526,7 +526,7 @@ test.describe('Testing Camera Movement', () => {
await hoverOverNothing()
await page.mouse.move(x, 419)
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await hoverOverNothing()
@ -834,7 +834,7 @@ test('if you write invalid kcl you get inlined errors', async ({ page }) => {
// error text on hover
await page.hover('.cm-lint-marker-error')
await expect(page.getByText('Unexpected token')).toBeVisible()
await expect(page.getByText('Unexpected token').first()).toBeVisible()
// select the line that's causing the error and delete it
await page.getByText('$ error').click()
@ -1177,16 +1177,194 @@ shell({ faces: ['end'], thickness: 0.25 }, exampleSketch)`
// Okay execution finished, let's start editing text below the error.
await u.codeLocator.click()
// Go to the end of the editor
// This bug happens when there is a diagnostic in the editor and you try to
// edit text below it.
// Or delete a huge chunk of text and then try to edit below it.
await page.keyboard.press('End')
await page.keyboard.down('Shift')
await page.keyboard.press('ArrowUp')
await page.keyboard.press('ArrowUp')
await page.keyboard.press('ArrowUp')
await page.keyboard.press('ArrowUp')
await page.keyboard.up('Shift')
await page.keyboard.press('Backspace')
await expect(page.locator('.cm-lint-marker-error')).not.toBeVisible()
// Get to the area where we want to type.
for (let i = 0; i < 20; i++) {
await page.keyboard.press('ArrowLeft')
}
await page.keyboard.press('Enter')
await page.keyboard.press('Enter')
await page.keyboard.type('thing: "blah"', { delay: 100 })
await page.keyboard.press('Enter')
await expect(page.locator('.cm-content'))
.toHaveText(`const exampleSketch = startSketchOn("XZ")
|> startProfileAt([0, 0], %)
|> angledLine({ angle: 50, length: 45 }, %)
|> yLineTo(0, %)
|> close(%)
thing: "blah"`)
await expect(page.locator('.cm-lint-marker-error')).toBeVisible()
})
test.describe('Copilot ghost text', () => {
test('completes code in empty file', async ({ page }) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``)
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter')
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
)
await expect(page.locator('.cm-ghostText').first()).toHaveText(
`fn cube = (pos, scale) => {`
)
// We should be able to hit Tab to accept the completion.
await page.keyboard.press('Tab')
await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
)
// Hit enter a few times.
await page.keyboard.press('Enter')
await page.keyboard.press('Enter')
await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %) `
)
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
})
test('going elsewhere in code rejects the suggestion', async ({ page }) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``)
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter')
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
)
await expect(page.locator('.cm-ghostText').first()).toHaveText(
`fn cube = (pos, scale) => {`
)
// Going elsewhere in the code should hide the ghost text.
await page.keyboard.press('ArrowUp')
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(``)
})
test('delete in code rejects the suggestion', async ({ page }) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``)
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter')
await page.keyboard.press('Enter')
await page.keyboard.press('Enter')
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
)
await expect(page.locator('.cm-ghostText').first()).toHaveText(
`fn cube = (pos, scale) => {`
)
// Going elsewhere in the code should hide the ghost text.
await page.keyboard.press('Delete')
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(``)
})
test('backspace in code rejects the suggestion', async ({ page }) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``)
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter')
await page.keyboard.press('Enter')
await page.keyboard.press('Enter')
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
)
await expect(page.locator('.cm-ghostText').first()).toHaveText(
`fn cube = (pos, scale) => {`
)
// Going elsewhere in the code should hide the ghost text.
await page.keyboard.press('Backspace')
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(``)
})
test('focus outside code pane rejects the suggestion', async ({ page }) => {
const u = await getUtils(page)
// const PUR = 400 / 37.5 //pixeltoUnitRatio
await page.setViewportSize({ width: 1200, height: 500 })
await u.waitForAuthSkipAppStart()
await u.codeLocator.click()
await expect(page.locator('.cm-content')).toHaveText(``)
await expect(page.locator('.cm-ghostText')).not.toBeVisible()
await page.waitForTimeout(500)
await page.keyboard.press('Enter')
await expect(page.locator('.cm-ghostText').first()).toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(
`fn cube = (pos, scale) => { const sg = startSketchOn('XY') |> startProfileAt(pos, %) |> line([0, scale], %) |> line([scale, 0], %) |> line([0, -scale], %) return sg}const part001 = cube([0,0], 20) |> close(%) |> extrude(20, %)`
)
await expect(page.locator('.cm-ghostText').first()).toHaveText(
`fn cube = (pos, scale) => {`
)
// Going outside the editor should hide the ghost text.
await page.mouse.move(0, 0)
await page
.getByRole('button', { name: 'Start Sketch' })
.waitFor({ state: 'visible' })
await page.getByRole('button', { name: 'Start Sketch' }).click()
await expect(page.locator('.cm-ghostText').first()).not.toBeVisible()
await expect(page.locator('.cm-content')).toHaveText(``)
})
})
test.describe('Autocomplete works', () => {
@ -1869,10 +2047,10 @@ test.describe('Testing selections', () => {
await page.waitForTimeout(100)
await page.mouse.move(startXPx + PUR * 15, 500 - PUR * 10)
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
// bg-yellow-200 is more brittle than hover-highlight, but is closer to the user experience
// and will be an easy fix if it breaks because we change the colour
await expect(page.locator('.bg-yellow-200')).toBeVisible()
await expect(page.locator('.bg-yellow-200').first()).toBeVisible()
// check mousing off, than mousing onto another line
await page.mouse.move(startXPx + PUR * 10, 500 - PUR * 15) // mouse off
@ -2293,6 +2471,7 @@ const sketch002 = startSketchOn(launderExtrudeThroughVar, seg02)
},
})
await page.waitForTimeout(100)
await u.closeDebugPanel()
const extrusionTop: Coords2d = [800, 240]
const flatExtrusionFace: Coords2d = [960, 160]
@ -2307,25 +2486,25 @@ const sketch002 = startSketchOn(launderExtrudeThroughVar, seg02)
await page.waitForTimeout(200)
await page.mouse.move(extrusionTop[0], extrusionTop[1])
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await page.mouse.move(nothing[0], nothing[1])
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).not.toBeVisible()
await page.mouse.move(arc[0], arc[1])
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await page.mouse.move(nothing[0], nothing[1])
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).not.toBeVisible()
await page.mouse.move(close[0], close[1])
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await page.mouse.move(nothing[0], nothing[1])
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).not.toBeVisible()
await page.mouse.move(flatExtrusionFace[0], flatExtrusionFace[1])
await expect(page.getByTestId('hover-highlight')).toHaveCount(5) // multiple lines
await expect(page.getByTestId('hover-highlight')).toHaveCount(19) // multiple lines
await page.mouse.move(nothing[0], nothing[1])
await page.waitForTimeout(100)
await expect(page.getByTestId('hover-highlight')).not.toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).not.toBeVisible()
})
test("Extrude button should be disabled if there's no extrudable geometry when nothing is selected", async ({
page,
@ -2454,7 +2633,7 @@ const part001 = startSketchOn('XZ')
await page.mouse.move(pos[0], pos[1], { steps: 5 })
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toHaveText(
expectedCode
removeAfterFirstParenthesis(expectedCode)
)
// hover over segment, click it and check the cursor has move to the right place
await page.mouse.click(pos[0], pos[1])
@ -2520,8 +2699,10 @@ const extrude001 = extrude(50, sketch001)
await page.mouse.move(nothing.x, nothing.y)
await page.waitForTimeout(100)
await page.mouse.move(extrudeWall.x, extrudeWall.y)
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight')).toContainText(extrudeText)
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toContainText(
removeAfterFirstParenthesis(extrudeText)
)
await page.waitForTimeout(200)
await expect(
await u.getGreatestPixDiff(extrudeWall, hoverColor)
@ -2549,8 +2730,10 @@ const extrude001 = extrude(50, sketch001)
await expect(await u.getGreatestPixDiff(cap, noHoverColor)).toBeLessThan(5)
await page.mouse.move(cap.x, cap.y)
await expect(page.getByTestId('hover-highlight')).toBeVisible()
await expect(page.getByTestId('hover-highlight')).toContainText(capText)
await expect(page.getByTestId('hover-highlight').first()).toBeVisible()
await expect(page.getByTestId('hover-highlight').first()).toContainText(
removeAfterFirstParenthesis(capText)
)
await page.waitForTimeout(200)
await expect(await u.getGreatestPixDiff(cap, hoverColor)).toBeLessThan(5)
await page.mouse.click(cap.x, cap.y)
@ -6707,3 +6890,11 @@ test('Paste should not work unless an input is focused', async ({
)
).toContain(pasteContent)
})
function removeAfterFirstParenthesis(inputString: string) {
const index = inputString.indexOf('(')
if (index !== -1) {
return inputString.substring(0, index)
}
return inputString // return the original string if '(' is not found
}

View File

@ -1,8 +1,6 @@
import { Extension } from '@codemirror/state'
import { linter, forEachDiagnostic, Diagnostic } from '@codemirror/lint'
import { LanguageServerPlugin } from './lsp'
export default function lspLintExt(): Extension {
return linter((view) => {
let diagnostics: Diagnostic[] = []

View File

@ -12,7 +12,6 @@ import type {
ViewPlugin,
} from '@codemirror/view'
import { EditorView, Tooltip } from '@codemirror/view'
import { setDiagnosticsEffect } from '@codemirror/lint'
import type { PublishDiagnosticsParams } from 'vscode-languageserver-protocol'
import type * as LSP from 'vscode-languageserver-protocol'
@ -26,7 +25,6 @@ import { LanguageServerClient } from '../client'
import {
lspSemanticTokensEvent,
lspFormatCodeEvent,
lspDiagnosticsEvent,
relevantUpdate,
} from './annotations'
import { CompletionItemKindMap } from './autocomplete'

View File

@ -1,16 +1,25 @@
import { StateField, StateEffect } from '@codemirror/state'
import { StateField, StateEffect, Annotation } from '@codemirror/state'
import { EditorView, Decoration } from '@codemirror/view'
export { EditorView }
export const addLineHighlight = StateEffect.define<[number, number]>()
const addLineHighlightAnnotation = Annotation.define<null>()
export const addLineHighlightEvent = addLineHighlightAnnotation.of(null)
export const lineHighlightField = StateField.define({
create() {
return Decoration.none
},
update(lines, tr) {
lines = lines.map(tr.changes)
const isLineHighlightEvent = tr.annotation(addLineHighlightEvent.type)
if (isLineHighlightEvent === undefined) {
return lines
}
const deco = []
for (let e of tr.effects) {
if (e.is(addLineHighlight)) {

View File

@ -5,7 +5,7 @@ import { ModelingMachineEvent } from 'machines/modelingMachine'
import { Selections, processCodeMirrorRanges, Selection } from 'lib/selections'
import { undo, redo } from '@codemirror/commands'
import { CommandBarMachineEvent } from 'machines/commandBarMachine'
import { addLineHighlight } from './highlightextension'
import { addLineHighlight, addLineHighlightEvent } from './highlightextension'
import {
forEachDiagnostic,
Diagnostic,
@ -98,6 +98,7 @@ export default class EditorManager {
effects: addLineHighlight.of([selection[0], safeEnd]),
annotations: [
updateOutsideEditorEvent,
addLineHighlightEvent,
Transaction.addToHistory.of(false),
],
})

View File

@ -1,17 +1,22 @@
/// Thanks to the Cursor folks for their heavy lifting here.
/// This has been heavily modified from their original implementation but we are
/// still grateful.
import { indentUnit } from '@codemirror/language'
import {
Decoration,
DecorationSet,
EditorView,
KeyBinding,
PluginValue,
ViewPlugin,
ViewUpdate,
keymap,
} from '@codemirror/view'
import {
Annotation,
EditorState,
Extension,
Prec,
StateEffect,
StateField,
Transaction,
@ -39,6 +44,9 @@ import { CopilotRejectCompletionParams } from 'wasm-lib/kcl/bindings/CopilotReje
const copilotPluginAnnotation = Annotation.define<null>()
export const copilotPluginEvent = copilotPluginAnnotation.of(null)
const rejectSuggestionAnnotation = Annotation.define<null>()
export const rejectSuggestionCommand = rejectSuggestionAnnotation.of(null)
// Effects to tell StateEffect what to do with GhostText
const addSuggestion = StateEffect.define<Suggestion>()
const acceptSuggestion = StateEffect.define<null>()
@ -76,13 +84,16 @@ interface GhostText {
uuid: string
}
export const completionDecoration = StateField.define<CompletionState>({
const completionDecoration = StateField.define<CompletionState>({
create(_state: EditorState) {
return { ghostText: null }
},
update(state: CompletionState, transaction: Transaction) {
// We only care about events from this plugin.
if (transaction.annotation(copilotPluginEvent.type) === undefined) {
if (
transaction.annotation(copilotPluginEvent.type) === undefined &&
transaction.annotation(rejectSuggestionCommand.type) === undefined
) {
return state
}
@ -201,7 +212,6 @@ export const relevantUpdate = (update: ViewUpdate): RelevantUpdate => {
return {
overall: infos.some(
(info: TransactionInfo) =>
update.focusChanged ||
info.transaction.annotation(copilotPluginEvent.type) !== undefined ||
info.annotations.includes(TransactionAnnotation.UserSelect) ||
info.annotations.includes(TransactionAnnotation.UserInput) ||
@ -259,15 +269,6 @@ export class CompletionRequester implements PluginValue {
return
}
if (viewUpdate.focusChanged) {
this.rejectSuggestionCommand()
return
}
if (!viewUpdate.docChanged) {
return
}
this.lastPos = this.viewUpdate.state.selection.main.head
this._deffererCodeUpdate(true)
}
@ -503,7 +504,10 @@ export class CompletionRequester implements PluginValue {
insert: '',
},
effects: clearSuggestion.of(null),
annotations: [copilotPluginEvent, Transaction.addToHistory.of(false)],
annotations: [
rejectSuggestionCommand,
Transaction.addToHistory.of(false),
],
})
this.reject()
@ -586,9 +590,10 @@ export class CompletionRequester implements PluginValue {
}
export const copilotPlugin = (options: LanguageServerOptions): Extension => {
const completionPlugin = ViewPlugin.define((view) => {
return new CompletionRequester(options.client)
})
let plugin: CompletionRequester | null = null
const completionPlugin = ViewPlugin.define(
(view) => (plugin = new CompletionRequester(options.client))
)
const domHandlers = EditorView.domEventHandlers({
keydown(event, view) {
@ -596,6 +601,8 @@ export const copilotPlugin = (options: LanguageServerOptions): Extension => {
event.key !== 'Shift' &&
event.key !== 'Control' &&
event.key !== 'Alt' &&
event.key !== 'Backspace' &&
event.key !== 'Delete' &&
event.key !== 'Meta'
) {
if (view.plugin === null) return false
@ -611,10 +618,61 @@ export const copilotPlugin = (options: LanguageServerOptions): Extension => {
},
})
const copilotAutocompleteKeymap: readonly KeyBinding[] = [
{
key: 'Tab',
run: (view: EditorView): boolean => {
if (view.plugin === null) return false
// Get the current plugin from the map.
const p = view.plugin(completionPlugin)
if (p === null) return false
return p.sameKeyCommand('Tab')
},
},
{
key: 'Backspace',
run: (view: EditorView): boolean => {
if (view.plugin === null) return false
// Get the current plugin from the map.
const p = view.plugin(completionPlugin)
if (p === null) return false
return p.rejectSuggestionCommand()
},
},
{
key: 'Delete',
run: (view: EditorView): boolean => {
if (view.plugin === null) return false
// Get the current plugin from the map.
const p = view.plugin(completionPlugin)
if (p === null) return false
return p.rejectSuggestionCommand()
},
},
]
const copilotAutocompleteKeymapExt = Prec.highest(
keymap.computeN([], () => [copilotAutocompleteKeymap])
)
return [
lspPlugin(options),
completionPlugin,
copilotAutocompleteKeymapExt,
domHandlers,
completionDecoration,
EditorView.focusChangeEffect.of((_, focusing) => {
if (plugin === null) return null
plugin.rejectSuggestionCommand()
return null
}),
]
}

View File

@ -64,6 +64,9 @@ pub struct Backend {
pub diagnostics_map: DashMap<String, Vec<Diagnostic>>,
pub is_initialized: Arc<tokio::sync::RwLock<bool>>,
/// Are we running in dev mode.
pub dev_mode: bool,
}
// Implement the shared backend trait for the language server.
@ -209,7 +212,7 @@ impl Backend {
// Let's not call it yet since it's not our model.
// We will need to wrap in spawn_local like we do in kcl/mod.rs for wasm only.
#[cfg(test)]
let completion_list = self
let mut completion_list = self
.get_completions(doc_params.language, doc_params.prefix, doc_params.suffix)
.await
.map_err(|err| Error {
@ -218,7 +221,25 @@ impl Backend {
message: Cow::from(format!("Failed to get completions: {}", err)),
})?;
#[cfg(not(test))]
let completion_list = vec![];
let mut completion_list = vec![];
if self.dev_mode {
completion_list.push(
r#"fn cube = (pos, scale) => {
const sg = startSketchOn('XY')
|> startProfileAt(pos, %)
|> line([0, scale], %)
|> line([scale, 0], %)
|> line([0, -scale], %)
return sg
}
const part001 = cube([0,0], 20)
|> close(%)
|> extrude(20, %)"#
.to_string(),
);
}
let response = CopilotCompletionResponse::from_str_vec(completion_list, line_before, doc_params.pos);
// Set the telemetry data for each completion.

View File

@ -99,6 +99,7 @@ pub async fn copilot_lsp_server() -> Result<crate::lsp::copilot::Backend> {
telemetry: Default::default(),
is_initialized: Default::default(),
diagnostics_map: Default::default(),
dev_mode: Default::default(),
});
let server = service.inner();

View File

@ -356,6 +356,11 @@ pub async fn copilot_lsp_run(config: ServerConfig, token: String, baseurl: Strin
is_initialized: Default::default(),
diagnostics_map: Default::default(),
dev_mode: if baseurl == "https://api.dev.zoo.dev" {
true
} else {
false
},
})
.custom_method("copilot/setEditorInfo", kcl_lib::lsp::copilot::Backend::set_editor_info)
.custom_method(