Skip to content
This repository was archived by the owner on Feb 18, 2025. It is now read-only.

Commit 85f6a74

Browse files
committed
WIP: add processing of generated project API response
1 parent 98b137f commit 85f6a74

9 files changed

Lines changed: 134 additions & 13 deletions

File tree

crates/cursor-core/src/auth/mod.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,11 @@ use wasm_bindgen_futures::{future_to_promise, spawn_local};
1818
const AUTH_TOKEN_KEY: &str = "auth_token";
1919

2020
use crate::{
21-
bindings::{progress_location::ProgressLocation, progress_options::ProgressOptions},
21+
bindings::{
22+
progress::Progress, progress_location::ProgressLocation, progress_options::ProgressOptions,
23+
},
2224
context::get_extension_context,
2325
request::make_request,
24-
storage::GlobalStorage,
2526
};
2627

2728
use self::token::Token;
@@ -85,10 +86,7 @@ pub async fn sign_in() {
8586
title: Some("Waiting for sign in / sign up...".to_owned()),
8687
cancellable: true,
8788
},
88-
closure!(|abort_signal: AbortSignal| {
89-
let uuid = uuid.clone();
90-
let verifier = verifier.clone();
91-
let storage: GlobalStorage = storage.clone().into();
89+
closure_once!(|_progress: Progress, abort_signal: AbortSignal| {
9290
future_to_promise(async move {
9391
Ok(
9492
if let Some(token) = polling(&uuid, &verifier, abort_signal).await? {
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
1+
pub mod progress;
12
pub mod progress_location;
23
pub mod progress_options;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use wasm_bindgen::prelude::*;
2+
3+
#[wasm_bindgen(typescript_custom_section)]
4+
const IPROGRESS: &'static str = r#"
5+
interface IProgress {
6+
report(message?: string): void;
7+
}
8+
"#;
9+
10+
#[wasm_bindgen]
11+
extern "C" {
12+
#[wasm_bindgen(typescript_type = "IProgress")]
13+
pub type Progress;
14+
15+
#[wasm_bindgen(method, structural)]
16+
pub fn report(this: &Progress, message: &str);
17+
}

crates/cursor-core/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ pub mod auth;
22
mod bindings;
33
pub mod context;
44
mod conversation;
5+
mod project;
56
mod request;
67
pub mod storage;
78

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
use futures::StreamExt;
2+
use node_bridge::{bindings::AbortSignal, prelude::*};
3+
use serde_json::json;
4+
use wasm_bindgen::prelude::*;
5+
use wasm_bindgen_futures::future_to_promise;
6+
7+
use crate::{
8+
bindings::{
9+
progress::Progress, progress_location::ProgressLocation, progress_options::ProgressOptions,
10+
},
11+
context::get_extension_context,
12+
request::stream::{make_stream_request, StreamResponseState},
13+
};
14+
15+
const STEP_MESSAGE: &str = "cursor-step";
16+
const CREATE_MESSAGE: &str = "cursor-create";
17+
const APPEND_MESSAGE: &str = "cursor-append";
18+
const END_MESSAGE: &str = "cursor-end";
19+
const FINISHED_MESSAGE: &str = "cursor-finished";
20+
21+
enum Task {
22+
Step(String),
23+
Create(String),
24+
Append(String),
25+
}
26+
27+
#[wasm_bindgen(js_name = generateProject)]
28+
pub async fn generate_project(prompt: &str) -> Result<JsValue, JsValue> {
29+
let prompt = prompt.to_owned();
30+
Ok(get_extension_context()
31+
.with_progress(
32+
ProgressOptions {
33+
location: ProgressLocation::Notification,
34+
title: Some("Generating project...".to_owned()),
35+
cancellable: true,
36+
},
37+
closure_once!(|progress: Progress, abort_signal: AbortSignal| {
38+
future_to_promise(async move {
39+
let mut state: StreamResponseState =
40+
make_stream_request("/gen_project", &json!({ "description": prompt }))
41+
.send()
42+
.await?
43+
.into();
44+
let mut data_stream = state.data_stream();
45+
let mut current_task = None;
46+
while let Some(data) = data_stream.next().await {
47+
#[cfg(debug_assertions)]
48+
console::log_str(&data);
49+
50+
// The start identifier of the task is in the form of: `identifier task`.
51+
// First, match the prefix of the identifier,
52+
// and then extract the specific task following it.
53+
if data.starts_with(STEP_MESSAGE) {
54+
let task = data[STEP_MESSAGE.len() + 1..].trim();
55+
current_task = Some(Task::Step(task.to_owned()));
56+
} else if data.starts_with(CREATE_MESSAGE) {
57+
let task = data[CREATE_MESSAGE.len() + 1..].trim();
58+
current_task = Some(Task::Create(task.to_owned()));
59+
} else if data.starts_with(APPEND_MESSAGE) {
60+
let task = data[APPEND_MESSAGE.len() + 1..].trim();
61+
current_task = Some(Task::Append(task.to_owned()));
62+
} else if data.starts_with(END_MESSAGE) {
63+
current_task = None;
64+
} else if data.starts_with(FINISHED_MESSAGE) {
65+
break;
66+
}
67+
68+
// The message sent by the report will automatically disappear after a short period of time.
69+
// In order to keep the text displayed on the dialog box, report the title every time data is returned.
70+
match &current_task {
71+
Some(Task::Step(title) | Task::Create(title) | Task::Append(title)) => {
72+
progress.report(&title);
73+
}
74+
_ => {}
75+
}
76+
}
77+
drop(data_stream);
78+
state.complete().await.map(|_| JsValue::null())
79+
})
80+
})
81+
.into_js_value()
82+
.into(),
83+
)
84+
.await)
85+
}

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "aicursor",
33
"displayName": "CodeCursor (Cursor for VS Code)",
44
"description": "Cursor integration for Visual Studio Code",
5-
"version": "0.4.1",
5+
"version": "0.5.0",
66
"publisher": "ktiays",
77
"repository": {
88
"type": "git",
@@ -80,6 +80,11 @@
8080
"command": "aicursor.configureApiKey",
8181
"title": "Configure API Key",
8282
"category": "CodeCursor"
83+
},
84+
{
85+
"command": "aicursor.generateProject",
86+
"title": "Generate Project",
87+
"category": "CodeCursor"
8388
}
8489
],
8590
"viewsContainers": {

src/extension/context.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as vscode from "vscode";
22
import {
33
IExtensionContext,
44
IGlobalStorage,
5+
IProgress,
56
RustProgressOptions,
67
} from "@crates/cursor-core";
78
import { getGlobalState } from "./globalState";
@@ -30,14 +31,19 @@ export class ExtensionContext implements IExtensionContext {
3031

3132
withProgress(
3233
options: RustProgressOptions,
33-
callback: (signal: AbortSignal) => Thenable<any>
34+
callback: (progress: IProgress, signal: AbortSignal) => Thenable<any>
3435
): Thenable<any> {
35-
return vscode.window.withProgress(options, async (_, token) => {
36+
return vscode.window.withProgress(options, async (progress, token) => {
3637
const abortController = new AbortController();
3738
token.onCancellationRequested(() => {
3839
abortController.abort();
3940
});
40-
await callback(abortController.signal);
41+
const wrappedProgress = {
42+
report(message?: string) {
43+
progress.report({ message });
44+
},
45+
} as IProgress;
46+
await callback(wrappedProgress, abortController.signal);
4147
});
4248
}
4349

src/extension/index.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ import { GenerateSession, getScratchpadManager } from "./generate";
55
import { getGlobalState } from "./globalState";
66
import { ChatPanelProvider } from "./chat/chatPanelProvider";
77
import { sharedChatServiceImpl } from "./chat/chatServiceImpl";
8-
import { setExtensionContext, signIn, signOut } from "@crates/cursor-core";
8+
import {
9+
generateProject,
10+
setExtensionContext,
11+
signIn,
12+
signOut,
13+
} from "@crates/cursor-core";
914
import { ExtensionContext } from "./context";
1015

1116
function setHasActiveGenerateSessionContext(value: boolean) {
@@ -89,6 +94,9 @@ export function activate(context: vscode.ExtensionContext) {
8994
"aicursor.openaiApiKey"
9095
);
9196
}),
97+
vscode.commands.registerCommand("aicursor.generateProject", () => {
98+
generateProject("a new Unity project");
99+
}),
92100
getScratchpadManager().registerTextDocumentContentProvider(),
93101
vscode.window.registerWebviewViewProvider(
94102
ChatPanelProvider.viewType,

0 commit comments

Comments
 (0)