Skip to content

Commit

Permalink
Add copilot settings
Browse files Browse the repository at this point in the history
Add copilot pause / resume
Add copilot statusbar item stub
  • Loading branch information
mikayla-maki committed Mar 29, 2023
1 parent f812796 commit ebd06b4
Show file tree
Hide file tree
Showing 9 changed files with 368 additions and 51 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion assets/keymaps/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,9 @@
"focus": false
}
],
"alt-]": "copilot::NextSuggestion"
"alt-]": "copilot::NextSuggestion",
"alt-[": "copilot::PreviousSuggestion",
"alt-\\": "copilot::Toggle"
}
},
{
Expand Down
18 changes: 15 additions & 3 deletions assets/settings/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
// The factor to grow the active pane by. Defaults to 1.0
// which gives the same size as all other panes.
"active_pane_magnification": 1.0,
// Enable / disable copilot integration.
"enable_copilot_integration": true,
// Controls whether copilot provides suggestion immediately
// or waits for a `copilot::Toggle`
"copilot": "on",
// Whether to enable vim modes and key bindings
"vim_mode": false,
// Whether to show the informational hover box when moving the mouse
Expand Down Expand Up @@ -120,7 +125,7 @@
// Settings specific to the terminal
"terminal": {
// What shell to use when opening a terminal. May take 3 values:
// 1. Use the system's default terminal configuration (e.g. $TERM).
// 1. Use the system's default terminal configuration in /etc/passwd
// "shell": "system"
// 2. A program:
// "shell": {
Expand Down Expand Up @@ -200,7 +205,9 @@
// Different settings for specific languages.
"languages": {
"Plain Text": {
"soft_wrap": "preferred_line_length"
"soft_wrap": "preferred_line_length",
// Copilot can be a little strange on non-code files
"copilot": "off"
},
"Elixir": {
"tab_size": 2
Expand All @@ -210,7 +217,9 @@
"hard_tabs": true
},
"Markdown": {
"soft_wrap": "preferred_line_length"
"soft_wrap": "preferred_line_length",
// Copilot can be a little strange on non-code files
"copilot": "off"
},
"JavaScript": {
"tab_size": 2
Expand All @@ -223,6 +232,9 @@
},
"YAML": {
"tab_size": 2
},
"JSON": {
"copilot": "off"
}
},
// LSP Specific settings.
Expand Down
1 change: 1 addition & 0 deletions crates/copilot/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ doctest = false

[dependencies]
collections = { path = "../collections" }
context_menu = { path = "../context_menu" }
gpui = { path = "../gpui" }
language = { path = "../language" }
settings = { path = "../settings" }
Expand Down
76 changes: 41 additions & 35 deletions crates/copilot/src/copilot.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod copilot_button;
mod request;
mod sign_in;

Expand All @@ -24,7 +25,7 @@ const COPILOT_AUTH_NAMESPACE: &'static str = "copilot_auth";
actions!(copilot_auth, [SignIn, SignOut]);

const COPILOT_NAMESPACE: &'static str = "copilot";
actions!(copilot, [NextSuggestion]);
actions!(copilot, [NextSuggestion, PreviousSuggestion, Toggle]);

pub fn init(client: Arc<Client>, node_runtime: Arc<NodeRuntime>, cx: &mut MutableAppContext) {
let copilot = cx.add_model(|cx| Copilot::start(client.http_client(), node_runtime, cx));
Expand Down Expand Up @@ -67,9 +68,11 @@ pub fn init(client: Arc<Client>, node_runtime: Arc<NodeRuntime>, cx: &mut Mutabl
}

enum CopilotServer {
Downloading,
Error(Arc<str>),
Disabled,
Starting {
_task: Shared<Task<()>>,
},
Error(Arc<str>),
Started {
server: Arc<LanguageServer>,
status: SignInStatus,
Expand All @@ -93,7 +96,7 @@ enum SignInStatus {

#[derive(Debug, PartialEq, Eq)]
pub enum Status {
Downloading,
Starting,
Error(Arc<str>),
Disabled,
SignedOut,
Expand Down Expand Up @@ -138,45 +141,46 @@ impl Copilot {
node_runtime: Arc<NodeRuntime>,
cx: &mut ModelContext<Self>,
) -> Self {
// TODO: Make this task resilient to users thrashing the copilot setting
cx.observe_global::<Settings, _>({
let http = http.clone();
let node_runtime = node_runtime.clone();
move |this, cx| {
if cx.global::<Settings>().copilot.as_bool() {
if cx.global::<Settings>().enable_copilot_integration {
if matches!(this.server, CopilotServer::Disabled) {
cx.spawn({
let http = http.clone();
let node_runtime = node_runtime.clone();
move |this, cx| {
Self::start_language_server(http, node_runtime, this, cx)
}
})
.detach();
let start_task = cx
.spawn({
let http = http.clone();
let node_runtime = node_runtime.clone();
move |this, cx| {
Self::start_language_server(http, node_runtime, this, cx)
}
})
.shared();
this.server = CopilotServer::Starting { _task: start_task }
}
} else {
// TODO: What else needs to be turned off here?
this.server = CopilotServer::Disabled
}
}
})
.detach();

if !cx.global::<Settings>().copilot.as_bool() {
return Self {
if cx.global::<Settings>().enable_copilot_integration {
let start_task = cx
.spawn({
let http = http.clone();
let node_runtime = node_runtime.clone();
move |this, cx| Self::start_language_server(http, node_runtime, this, cx)
})
.shared();

Self {
server: CopilotServer::Starting { _task: start_task },
}
} else {
Self {
server: CopilotServer::Disabled,
};
}

cx.spawn({
let http = http.clone();
let node_runtime = node_runtime.clone();
move |this, cx| Self::start_language_server(http, node_runtime, this, cx)
})
.detach();

Self {
server: CopilotServer::Downloading,
}
}
}

Expand Down Expand Up @@ -216,6 +220,7 @@ impl Copilot {
}
Err(error) => {
this.server = CopilotServer::Error(error.to_string().into());
cx.notify()
}
}
})
Expand All @@ -226,11 +231,10 @@ impl Copilot {
if let CopilotServer::Started { server, status } = &mut self.server {
let task = match status {
SignInStatus::Authorized { .. } | SignInStatus::Unauthorized { .. } => {
cx.notify();
Task::ready(Ok(())).shared()
}
SignInStatus::SigningIn { task, .. } => {
cx.notify(); // To re-show the prompt, just in case.
cx.notify();
task.clone()
}
SignInStatus::SignedOut => {
Expand Down Expand Up @@ -382,7 +386,7 @@ impl Copilot {

pub fn status(&self) -> Status {
match &self.server {
CopilotServer::Downloading => Status::Downloading,
CopilotServer::Starting { .. } => Status::Starting,
CopilotServer::Disabled => Status::Disabled,
CopilotServer::Error(error) => Status::Error(error.clone()),
CopilotServer::Started { status, .. } => match status {
Expand All @@ -403,21 +407,23 @@ impl Copilot {
) {
if let CopilotServer::Started { status, .. } = &mut self.server {
*status = match lsp_status {
request::SignInStatus::Ok { user } | request::SignInStatus::MaybeOk { user } => {
request::SignInStatus::Ok { user }
| request::SignInStatus::MaybeOk { user }
| request::SignInStatus::AlreadySignedIn { user } => {
SignInStatus::Authorized { _user: user }
}
request::SignInStatus::NotAuthorized { user } => {
SignInStatus::Unauthorized { _user: user }
}
_ => SignInStatus::SignedOut,
request::SignInStatus::NotSignedIn => SignInStatus::SignedOut,
};
cx.notify();
}
}

fn authorized_server(&self) -> Result<Arc<LanguageServer>> {
match &self.server {
CopilotServer::Downloading => Err(anyhow!("copilot is still downloading")),
CopilotServer::Starting { .. } => Err(anyhow!("copilot is still starting")),
CopilotServer::Disabled => Err(anyhow!("copilot is disabled")),
CopilotServer::Error(error) => Err(anyhow!(
"copilot was not started because of an error: {}",
Expand Down
Loading

0 comments on commit ebd06b4

Please sign in to comment.