Merge pull request #2316 from zed-industries/copilot

🚨 WIP 🚨 Copilot
This commit is contained in:
Mikayla Maki 2023-03-30 18:27:14 -07:00 committed by Joseph Lyons
parent 017b16dc7b
commit b8397a36c1
113 changed files with 3414 additions and 697 deletions

View file

@ -21,7 +21,7 @@ use sqlez::{
use std::{collections::HashMap, num::NonZeroU32, str, sync::Arc};
use theme::{Theme, ThemeRegistry};
use tree_sitter::Query;
use util::ResultExt as _;
use util::{RangeExt, ResultExt as _};
pub use keymap_file::{keymap_file_json_schema, KeymapFileContent};
pub use watched_json::watch_files;
@ -32,6 +32,7 @@ pub struct Settings {
pub buffer_font_features: fonts::Features,
pub buffer_font_family: FamilyId,
pub default_buffer_font_size: f32,
pub enable_copilot_integration: bool,
pub buffer_font_size: f32,
pub active_pane_magnification: f32,
pub cursor_blink: bool,
@ -60,6 +61,29 @@ pub struct Settings {
pub base_keymap: BaseKeymap,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)]
#[serde(rename_all = "snake_case")]
pub enum CopilotSettings {
#[default]
On,
Off,
}
impl From<CopilotSettings> for bool {
fn from(value: CopilotSettings) -> Self {
match value {
CopilotSettings::On => true,
CopilotSettings::Off => false,
}
}
}
impl CopilotSettings {
pub fn is_on(&self) -> bool {
<CopilotSettings as Into<bool>>::into(*self)
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq, Default)]
pub enum BaseKeymap {
#[default]
@ -153,6 +177,42 @@ pub struct EditorSettings {
pub ensure_final_newline_on_save: Option<bool>,
pub formatter: Option<Formatter>,
pub enable_language_server: Option<bool>,
pub copilot: Option<OnOff>,
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum OnOff {
On,
Off,
}
impl OnOff {
pub fn as_bool(&self) -> bool {
match self {
OnOff::On => true,
OnOff::Off => false,
}
}
pub fn from_bool(value: bool) -> OnOff {
match value {
true => OnOff::On,
false => OnOff::Off,
}
}
}
impl From<OnOff> for bool {
fn from(value: OnOff) -> bool {
value.as_bool()
}
}
impl From<bool> for OnOff {
fn from(value: bool) -> OnOff {
OnOff::from_bool(value)
}
}
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
@ -375,6 +435,8 @@ pub struct SettingsFileContent {
pub auto_update: Option<bool>,
#[serde(default)]
pub base_keymap: Option<BaseKeymap>,
#[serde(default)]
pub enable_copilot_integration: Option<bool>,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)]
@ -436,6 +498,7 @@ impl Settings {
format_on_save: required(defaults.editor.format_on_save),
formatter: required(defaults.editor.formatter),
enable_language_server: required(defaults.editor.enable_language_server),
copilot: required(defaults.editor.copilot),
},
editor_overrides: Default::default(),
git: defaults.git.unwrap(),
@ -452,6 +515,7 @@ impl Settings {
telemetry_overrides: Default::default(),
auto_update: defaults.auto_update.unwrap(),
base_keymap: Default::default(),
enable_copilot_integration: defaults.enable_copilot_integration.unwrap(),
}
}
@ -503,6 +567,10 @@ impl Settings {
merge(&mut self.autosave, data.autosave);
merge(&mut self.default_dock_anchor, data.default_dock_anchor);
merge(&mut self.base_keymap, data.base_keymap);
merge(
&mut self.enable_copilot_integration,
data.enable_copilot_integration,
);
self.editor_overrides = data.editor;
self.git_overrides = data.git.unwrap_or_default();
@ -526,6 +594,14 @@ impl Settings {
self
}
pub fn copilot_on(&self, language: Option<&str>) -> bool {
if self.enable_copilot_integration {
self.language_setting(language, |settings| settings.copilot.map(Into::into))
} else {
false
}
}
pub fn tab_size(&self, language: Option<&str>) -> NonZeroU32 {
self.language_setting(language, |settings| settings.tab_size)
}
@ -662,6 +738,7 @@ impl Settings {
format_on_save: Some(FormatOnSave::On),
formatter: Some(Formatter::LanguageServer),
enable_language_server: Some(true),
copilot: Some(OnOff::On),
},
editor_overrides: Default::default(),
journal_defaults: Default::default(),
@ -681,6 +758,7 @@ impl Settings {
telemetry_overrides: Default::default(),
auto_update: true,
base_keymap: Default::default(),
enable_copilot_integration: true,
}
}
@ -787,6 +865,7 @@ fn write_settings_key(settings_content: &mut String, key_path: &[&str], new_valu
.unwrap();
let mut depth = 0;
let mut last_value_range = 0..0;
let mut first_key_start = None;
let mut existing_value_range = 0..settings_content.len();
let matches = cursor.matches(&query, tree.root_node(), settings_content.as_bytes());
@ -798,6 +877,14 @@ fn write_settings_key(settings_content: &mut String, key_path: &[&str], new_valu
let key_range = mat.captures[0].node.byte_range();
let value_range = mat.captures[1].node.byte_range();
// Don't enter sub objects until we find an exact
// match for the current keypath
if last_value_range.contains_inclusive(&value_range) {
continue;
}
last_value_range = value_range.clone();
if key_range.start > existing_value_range.end {
break;
}
@ -811,6 +898,8 @@ fn write_settings_key(settings_content: &mut String, key_path: &[&str], new_valu
if found_key {
existing_value_range = value_range;
// Reset last value range when increasing in depth
last_value_range = existing_value_range.start..existing_value_range.start;
depth += 1;
if depth == key_path.len() {
@ -852,7 +941,8 @@ fn write_settings_key(settings_content: &mut String, key_path: &[&str], new_valu
}
if row > 0 {
let new_val = to_pretty_json(&new_value, column, column);
// depth is 0 based, but division needs to be 1 based.
let new_val = to_pretty_json(&new_value, column / (depth + 1), column);
let content = format!(r#""{new_key}": {new_val},"#);
settings_content.insert_str(first_key_start, &content);
@ -912,13 +1002,28 @@ fn to_pretty_json(
pub fn update_settings_file(
mut text: String,
old_file_content: SettingsFileContent,
mut old_file_content: SettingsFileContent,
update: impl FnOnce(&mut SettingsFileContent),
) -> String {
let mut new_file_content = old_file_content.clone();
update(&mut new_file_content);
if new_file_content.languages.len() != old_file_content.languages.len() {
for language in new_file_content.languages.keys() {
old_file_content
.languages
.entry(language.clone())
.or_default();
}
for language in old_file_content.languages.keys() {
new_file_content
.languages
.entry(language.clone())
.or_default();
}
}
let old_object = to_json_object(old_file_content);
let new_object = to_json_object(new_file_content);
@ -931,6 +1036,7 @@ pub fn update_settings_file(
for (key, old_value) in old_object.iter() {
// We know that these two are from the same shape of object, so we can just unwrap
let new_value = new_object.get(key).unwrap();
if old_value != new_value {
match new_value {
Value::Bool(_) | Value::Number(_) | Value::String(_) => {
@ -986,7 +1092,75 @@ mod tests {
let old_json = old_json.into();
let old_content: SettingsFileContent = serde_json::from_str(&old_json).unwrap_or_default();
let new_json = update_settings_file(old_json, old_content, update);
assert_eq!(new_json, expected_new_json.into());
pretty_assertions::assert_eq!(new_json, expected_new_json.into());
}
#[test]
fn test_update_copilot() {
assert_new_settings(
r#"
{
"languages": {
"JSON": {
"copilot": "off"
}
}
}
"#
.unindent(),
|settings| {
settings.editor.copilot = Some(OnOff::On);
},
r#"
{
"copilot": "on",
"languages": {
"JSON": {
"copilot": "off"
}
}
}
"#
.unindent(),
);
}
#[test]
fn test_update_langauge_copilot() {
assert_new_settings(
r#"
{
"languages": {
"JSON": {
"copilot": "off"
}
}
}
"#
.unindent(),
|settings| {
settings.languages.insert(
"Rust".into(),
EditorSettings {
copilot: Some(OnOff::On),
..Default::default()
},
);
},
r#"
{
"languages": {
"Rust": {
"copilot": "on"
},
"JSON": {
"copilot": "off"
}
}
}
"#
.unindent(),
);
}
#[test]