From 471810a3c2ce1ebf2b4ebdbaaa5e94e43e52ac5b Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Tue, 22 Aug 2023 15:27:44 -0400 Subject: [PATCH 1/5] WIP Co-Authored-By: Julia <30666851+ForLoveOfCats@users.noreply.github.com> --- assets/settings/default.json | 18 ++++++++---- crates/project/src/terminals.rs | 49 +++++++++++++++++++++++++++++++++ crates/terminal/src/terminal.rs | 14 ++++++++++ 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index 24412b883b..f4d77f02cf 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -284,8 +284,6 @@ // "directory": "~/zed/projects/" // } // } - // - // "working_directory": "current_project_directory", // Set the cursor blinking behavior in the terminal. // May take 4 values: @@ -334,13 +332,23 @@ // "line_height": { // "custom": 2 // }, - "line_height": "comfortable" + "line_height": "comfortable", // Set the terminal's font size. If this option is not included, // the terminal will default to matching the buffer's font size. - // "font_size": "15" + // "font_size": "15", // Set the terminal's font family. If this option is not included, // the terminal will default to matching the buffer's font family. - // "font_family": "Zed Mono" + // "font_family": "Zed Mono", + // --- + // Whether or not to automatically search for, and activate, Python virtual + // environments. + // Current limitations: + // - Only ".env", "env", ".venv", and "venv" are searched for at the + // root of the project + // - Only works with Posix-complaint shells + // - Only activates the first virtual environment it finds, regardless + // of the nunber of projects in the workspace. + "automatically_activate_python_virtual_environment": false }, // Difference settings for semantic_index "semantic_index": { diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index db5996829f..e585b659ee 100644 --- a/crates/project/src/terminals.rs +++ b/crates/project/src/terminals.rs @@ -3,6 +3,9 @@ use gpui::{AnyWindowHandle, ModelContext, ModelHandle, WeakModelHandle}; use std::path::PathBuf; use terminal::{Terminal, TerminalBuilder, TerminalSettings}; +#[cfg(target_os = "macos")] +use std::os::unix::ffi::OsStrExt; + pub struct Terminals { pub(crate) local_handles: Vec>, } @@ -47,6 +50,12 @@ impl Project { }) .detach(); + let setting = settings::get::(cx); + + if setting.automatically_activate_python_virtual_environment { + self.set_up_python_virtual_environment(&terminal_handle, cx); + } + terminal_handle }); @@ -54,6 +63,46 @@ impl Project { } } + fn set_up_python_virtual_environment( + &mut self, + terminal_handle: &ModelHandle, + cx: &mut ModelContext, + ) { + let virtual_environment = self.find_python_virtual_environment(cx); + if let Some(virtual_environment) = virtual_environment { + // Paths are not strings so we need to jump through some hoops to format the command without `format!` + let mut command = Vec::from("source ".as_bytes()); + command.extend_from_slice(virtual_environment.as_os_str().as_bytes()); + command.push(b'\n'); + + terminal_handle.update(cx, |this, _| this.input_bytes(command)); + } + } + + pub fn find_python_virtual_environment( + &mut self, + cx: &mut ModelContext, + ) -> Option { + const VIRTUAL_ENVIRONMENT_NAMES: [&str; 4] = [".env", "env", ".venv", "venv"]; + + let worktree_paths = self + .worktrees(cx) + .map(|worktree| worktree.read(cx).abs_path()); + + for worktree_path in worktree_paths { + for virtual_environment_name in VIRTUAL_ENVIRONMENT_NAMES { + let mut path = worktree_path.join(virtual_environment_name); + path.push("bin/activate"); + + if path.exists() { + return Some(path); + } + } + } + + None + } + pub fn local_terminal_handles(&self) -> &Vec> { &self.terminals.local_handles } diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 3bae06a86d..9b0f0bbc86 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -158,6 +158,7 @@ pub struct TerminalSettings { pub dock: TerminalDockPosition, pub default_width: f32, pub default_height: f32, + pub automatically_activate_python_virtual_environment: bool, } #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] @@ -176,6 +177,7 @@ pub struct TerminalSettingsContent { pub dock: Option, pub default_width: Option, pub default_height: Option, + pub automatically_activate_python_virtual_environment: Option, } impl TerminalSettings { @@ -1018,6 +1020,10 @@ impl Terminal { self.pty_tx.notify(input.into_bytes()); } + fn write_bytes_to_pty(&self, input: Vec) { + self.pty_tx.notify(input); + } + pub fn input(&mut self, input: String) { self.events .push_back(InternalEvent::Scroll(AlacScroll::Bottom)); @@ -1026,6 +1032,14 @@ impl Terminal { self.write_to_pty(input); } + pub fn input_bytes(&mut self, input: Vec) { + self.events + .push_back(InternalEvent::Scroll(AlacScroll::Bottom)); + self.events.push_back(InternalEvent::SetSelection(None)); + + self.write_bytes_to_pty(input); + } + pub fn try_keystroke(&mut self, keystroke: &Keystroke, alt_is_meta: bool) -> bool { let esc = to_esc_str(keystroke, &self.last_content.mode, alt_is_meta); if let Some(esc) = esc { From 711f156308322edeeb195978e5773e020ecdf918 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Wed, 23 Aug 2023 04:04:36 -0400 Subject: [PATCH 2/5] WIP --- crates/project/src/terminals.rs | 72 +++++++++++++++++++++------------ 1 file changed, 47 insertions(+), 25 deletions(-) diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index e585b659ee..0fa525a82c 100644 --- a/crates/project/src/terminals.rs +++ b/crates/project/src/terminals.rs @@ -1,7 +1,7 @@ use crate::Project; use gpui::{AnyWindowHandle, ModelContext, ModelHandle, WeakModelHandle}; use std::path::PathBuf; -use terminal::{Terminal, TerminalBuilder, TerminalSettings}; +use terminal::{Shell, Terminal, TerminalBuilder, TerminalSettings}; #[cfg(target_os = "macos")] use std::os::unix::ffi::OsStrExt; @@ -23,10 +23,14 @@ impl Project { )); } else { let settings = settings::get::(cx); + let automatically_activate_python_virtual_environment = settings + .automatically_activate_python_virtual_environment + .clone(); + let shell = settings.shell.clone(); let terminal = TerminalBuilder::new( working_directory.clone(), - settings.shell.clone(), + shell.clone(), settings.env.clone(), Some(settings.blinking.clone()), settings.alternate_scroll, @@ -50,10 +54,13 @@ impl Project { }) .detach(); - let setting = settings::get::(cx); - - if setting.automatically_activate_python_virtual_environment { - self.set_up_python_virtual_environment(&terminal_handle, cx); + if automatically_activate_python_virtual_environment { + let activate_script_path = self.find_activate_script_path(&shell, cx); + self.activate_python_virtual_environment( + activate_script_path, + &terminal_handle, + cx, + ); } terminal_handle @@ -63,36 +70,35 @@ impl Project { } } - fn set_up_python_virtual_environment( - &mut self, - terminal_handle: &ModelHandle, - cx: &mut ModelContext, - ) { - let virtual_environment = self.find_python_virtual_environment(cx); - if let Some(virtual_environment) = virtual_environment { - // Paths are not strings so we need to jump through some hoops to format the command without `format!` - let mut command = Vec::from("source ".as_bytes()); - command.extend_from_slice(virtual_environment.as_os_str().as_bytes()); - command.push(b'\n'); - - terminal_handle.update(cx, |this, _| this.input_bytes(command)); - } - } - - pub fn find_python_virtual_environment( + pub fn find_activate_script_path( &mut self, + shell: &Shell, cx: &mut ModelContext, ) -> Option { - const VIRTUAL_ENVIRONMENT_NAMES: [&str; 4] = [".env", "env", ".venv", "venv"]; + let program = match shell { + terminal::Shell::System => "Figure this out", + terminal::Shell::Program(program) => program, + terminal::Shell::WithArguments { program, args } => program, + }; + + // This is so hacky - find a better way to do this + let script_name = if program.contains("fish") { + "activate.fish" + } else { + "activate" + }; let worktree_paths = self .worktrees(cx) .map(|worktree| worktree.read(cx).abs_path()); + const VIRTUAL_ENVIRONMENT_NAMES: [&str; 4] = [".env", "env", ".venv", "venv"]; + for worktree_path in worktree_paths { for virtual_environment_name in VIRTUAL_ENVIRONMENT_NAMES { let mut path = worktree_path.join(virtual_environment_name); - path.push("bin/activate"); + path.push("bin/"); + path.push(script_name); if path.exists() { return Some(path); @@ -103,6 +109,22 @@ impl Project { None } + fn activate_python_virtual_environment( + &mut self, + activate_script: Option, + terminal_handle: &ModelHandle, + cx: &mut ModelContext, + ) { + if let Some(activate_script) = activate_script { + // Paths are not strings so we need to jump through some hoops to format the command without `format!` + let mut command = Vec::from("source ".as_bytes()); + command.extend_from_slice(activate_script.as_os_str().as_bytes()); + command.push(b'\n'); + + terminal_handle.update(cx, |this, _| this.input_bytes(command)); + } + } + pub fn local_terminal_handles(&self) -> &Vec> { &self.terminals.local_handles } From 7b170304dfe1ece11ba193867c43a90050026d10 Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Wed, 23 Aug 2023 04:07:10 -0400 Subject: [PATCH 3/5] Shorten setting name --- assets/settings/default.json | 2 +- crates/project/src/terminals.rs | 7 +++---- crates/terminal/src/terminal.rs | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/assets/settings/default.json b/assets/settings/default.json index f4d77f02cf..27be6ae5d2 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -348,7 +348,7 @@ // - Only works with Posix-complaint shells // - Only activates the first virtual environment it finds, regardless // of the nunber of projects in the workspace. - "automatically_activate_python_virtual_environment": false + "activate_python_virtual_environment": false }, // Difference settings for semantic_index "semantic_index": { diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index 0fa525a82c..539d120e97 100644 --- a/crates/project/src/terminals.rs +++ b/crates/project/src/terminals.rs @@ -23,9 +23,8 @@ impl Project { )); } else { let settings = settings::get::(cx); - let automatically_activate_python_virtual_environment = settings - .automatically_activate_python_virtual_environment - .clone(); + let activate_python_virtual_environment = + settings.activate_python_virtual_environment.clone(); let shell = settings.shell.clone(); let terminal = TerminalBuilder::new( @@ -54,7 +53,7 @@ impl Project { }) .detach(); - if automatically_activate_python_virtual_environment { + if activate_python_virtual_environment { let activate_script_path = self.find_activate_script_path(&shell, cx); self.activate_python_virtual_environment( activate_script_path, diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 9b0f0bbc86..73ff09225f 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -158,7 +158,7 @@ pub struct TerminalSettings { pub dock: TerminalDockPosition, pub default_width: f32, pub default_height: f32, - pub automatically_activate_python_virtual_environment: bool, + pub activate_python_virtual_environment: bool, } #[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] @@ -177,7 +177,7 @@ pub struct TerminalSettingsContent { pub dock: Option, pub default_width: Option, pub default_height: Option, - pub automatically_activate_python_virtual_environment: Option, + pub activate_python_virtual_environment: Option, } impl TerminalSettings { From 9fe580acb675e573588e9451617310e26be8e9ea Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Fri, 25 Aug 2023 01:50:54 -0400 Subject: [PATCH 4/5] WIP --- crates/project/src/terminals.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index 539d120e97..2fb66a6c4c 100644 --- a/crates/project/src/terminals.rs +++ b/crates/project/src/terminals.rs @@ -77,7 +77,7 @@ impl Project { let program = match shell { terminal::Shell::System => "Figure this out", terminal::Shell::Program(program) => program, - terminal::Shell::WithArguments { program, args } => program, + terminal::Shell::WithArguments { program, args: _ } => program, }; // This is so hacky - find a better way to do this From 507a5db09c53014e8e45c00fe39c71e992f978ab Mon Sep 17 00:00:00 2001 From: "Joseph T. Lyons" Date: Fri, 25 Aug 2023 15:06:31 -0400 Subject: [PATCH 5/5] WIP Co-Authored-By: Mikayla Maki --- assets/settings/default.json | 27 ++- crates/project/src/terminals.rs | 59 +++---- crates/terminal/src/terminal.rs | 122 +------------- crates/terminal/src/terminal_settings.rs | 163 +++++++++++++++++++ crates/terminal_view/src/terminal_element.rs | 3 +- crates/terminal_view/src/terminal_panel.rs | 2 +- crates/terminal_view/src/terminal_view.rs | 5 +- 7 files changed, 213 insertions(+), 168 deletions(-) create mode 100644 crates/terminal/src/terminal_settings.rs diff --git a/assets/settings/default.json b/assets/settings/default.json index 27be6ae5d2..b1d36c938f 100644 --- a/assets/settings/default.json +++ b/assets/settings/default.json @@ -333,6 +333,24 @@ // "custom": 2 // }, "line_height": "comfortable", + // Activate the python virtual environment, if one is found, in the + // terminal's working directory (as resolved by the working_directory + // setting). Set this to "off" to disable this behavior. + "detect_venv": { + "on": { + // Default directories to search for virtual environments, relative + // to the current working directory. We recommend overriding this + // in your project's settings, rather than globally. + "directories": [ + ".env", + "env", + ".venv", + "venv" + ], + // Can also be 'csh' and 'fish' + "activate_script": "default" + } + } // Set the terminal's font size. If this option is not included, // the terminal will default to matching the buffer's font size. // "font_size": "15", @@ -340,15 +358,6 @@ // the terminal will default to matching the buffer's font family. // "font_family": "Zed Mono", // --- - // Whether or not to automatically search for, and activate, Python virtual - // environments. - // Current limitations: - // - Only ".env", "env", ".venv", and "venv" are searched for at the - // root of the project - // - Only works with Posix-complaint shells - // - Only activates the first virtual environment it finds, regardless - // of the nunber of projects in the workspace. - "activate_python_virtual_environment": false }, // Difference settings for semantic_index "semantic_index": { diff --git a/crates/project/src/terminals.rs b/crates/project/src/terminals.rs index 2fb66a6c4c..68a0431316 100644 --- a/crates/project/src/terminals.rs +++ b/crates/project/src/terminals.rs @@ -1,7 +1,10 @@ use crate::Project; use gpui::{AnyWindowHandle, ModelContext, ModelHandle, WeakModelHandle}; -use std::path::PathBuf; -use terminal::{Shell, Terminal, TerminalBuilder, TerminalSettings}; +use std::path::{Path, PathBuf}; +use terminal::{ + terminal_settings::{self, TerminalSettings, VenvSettingsContent}, + Terminal, TerminalBuilder, +}; #[cfg(target_os = "macos")] use std::os::unix::ffi::OsStrExt; @@ -23,8 +26,7 @@ impl Project { )); } else { let settings = settings::get::(cx); - let activate_python_virtual_environment = - settings.activate_python_virtual_environment.clone(); + let python_settings = settings.detect_venv.clone(); let shell = settings.shell.clone(); let terminal = TerminalBuilder::new( @@ -53,15 +55,15 @@ impl Project { }) .detach(); - if activate_python_virtual_environment { - let activate_script_path = self.find_activate_script_path(&shell, cx); + if let Some(python_settings) = &python_settings.as_option() { + let activate_script_path = + self.find_activate_script_path(&python_settings, working_directory); self.activate_python_virtual_environment( activate_script_path, &terminal_handle, cx, ); } - terminal_handle }); @@ -71,37 +73,26 @@ impl Project { pub fn find_activate_script_path( &mut self, - shell: &Shell, - cx: &mut ModelContext, + settings: &VenvSettingsContent, + working_directory: Option, ) -> Option { - let program = match shell { - terminal::Shell::System => "Figure this out", - terminal::Shell::Program(program) => program, - terminal::Shell::WithArguments { program, args: _ } => program, + // When we are unable to resolve the working directory, the terminal builder + // defaults to '/'. We should probably encode this directly somewhere, but for + // now, let's just hard code it here. + let working_directory = working_directory.unwrap_or_else(|| Path::new("/").to_path_buf()); + let activate_script_name = match settings.activate_script { + terminal_settings::ActivateScript::Default => "activate", + terminal_settings::ActivateScript::Csh => "activate.csh", + terminal_settings::ActivateScript::Fish => "activate.fish", }; - // This is so hacky - find a better way to do this - let script_name = if program.contains("fish") { - "activate.fish" - } else { - "activate" - }; + for virtual_environment_name in settings.directories { + let mut path = working_directory.join(virtual_environment_name); + path.push("bin/"); + path.push(activate_script_name); - let worktree_paths = self - .worktrees(cx) - .map(|worktree| worktree.read(cx).abs_path()); - - const VIRTUAL_ENVIRONMENT_NAMES: [&str; 4] = [".env", "env", ".venv", "venv"]; - - for worktree_path in worktree_paths { - for virtual_environment_name in VIRTUAL_ENVIRONMENT_NAMES { - let mut path = worktree_path.join(virtual_environment_name); - path.push("bin/"); - path.push(script_name); - - if path.exists() { - return Some(path); - } + if path.exists() { + return Some(path); } } diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 73ff09225f..e28e0ca5c1 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -1,5 +1,6 @@ pub mod mappings; pub use alacritty_terminal; +pub mod terminal_settings; use alacritty_terminal::{ ansi::{ClearMode, Handler}, @@ -31,8 +32,8 @@ use mappings::mouse::{ }; use procinfo::LocalProcessInfo; -use schemars::JsonSchema; use serde::{Deserialize, Serialize}; +use terminal_settings::{AlternateScroll, Shell, TerminalBlink, TerminalSettings}; use util::truncate_and_trailoff; use std::{ @@ -48,7 +49,6 @@ use std::{ use thiserror::Error; use gpui::{ - fonts, geometry::vector::{vec2f, Vector2F}, keymap_matcher::Keystroke, platform::{Modifiers, MouseButton, MouseMovedEvent, TouchPhase}, @@ -134,124 +134,6 @@ pub fn init(cx: &mut AppContext) { settings::register::(cx); } -#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] -#[serde(rename_all = "snake_case")] -pub enum TerminalDockPosition { - Left, - Bottom, - Right, -} - -#[derive(Deserialize)] -pub struct TerminalSettings { - pub shell: Shell, - pub working_directory: WorkingDirectory, - font_size: Option, - pub font_family: Option, - pub line_height: TerminalLineHeight, - pub font_features: Option, - pub env: HashMap, - pub blinking: TerminalBlink, - pub alternate_scroll: AlternateScroll, - pub option_as_meta: bool, - pub copy_on_select: bool, - pub dock: TerminalDockPosition, - pub default_width: f32, - pub default_height: f32, - pub activate_python_virtual_environment: bool, -} - -#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] -pub struct TerminalSettingsContent { - pub shell: Option, - pub working_directory: Option, - pub font_size: Option, - pub font_family: Option, - pub line_height: Option, - pub font_features: Option, - pub env: Option>, - pub blinking: Option, - pub alternate_scroll: Option, - pub option_as_meta: Option, - pub copy_on_select: Option, - pub dock: Option, - pub default_width: Option, - pub default_height: Option, - pub activate_python_virtual_environment: Option, -} - -impl TerminalSettings { - pub fn font_size(&self, cx: &AppContext) -> Option { - self.font_size - .map(|size| theme::adjusted_font_size(size, cx)) - } -} - -impl settings::Setting for TerminalSettings { - const KEY: Option<&'static str> = Some("terminal"); - - type FileContent = TerminalSettingsContent; - - fn load( - default_value: &Self::FileContent, - user_values: &[&Self::FileContent], - _: &AppContext, - ) -> Result { - Self::load_via_json_merge(default_value, user_values) - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, Default)] -#[serde(rename_all = "snake_case")] -pub enum TerminalLineHeight { - #[default] - Comfortable, - Standard, - Custom(f32), -} - -impl TerminalLineHeight { - pub fn value(&self) -> f32 { - match self { - TerminalLineHeight::Comfortable => 1.618, - TerminalLineHeight::Standard => 1.3, - TerminalLineHeight::Custom(line_height) => f32::max(*line_height, 1.), - } - } -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum TerminalBlink { - Off, - TerminalControlled, - On, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum Shell { - System, - Program(String), - WithArguments { program: String, args: Vec }, -} - -#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum AlternateScroll { - On, - Off, -} - -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum WorkingDirectory { - CurrentProjectDirectory, - FirstProjectDirectory, - AlwaysHome, - Always { directory: String }, -} - #[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct TerminalSize { pub cell_width: f32, diff --git a/crates/terminal/src/terminal_settings.rs b/crates/terminal/src/terminal_settings.rs new file mode 100644 index 0000000000..e0649ebf65 --- /dev/null +++ b/crates/terminal/src/terminal_settings.rs @@ -0,0 +1,163 @@ +use std::{collections::HashMap, path::PathBuf}; + +use gpui::{fonts, AppContext}; +use schemars::JsonSchema; +use serde_derive::{Deserialize, Serialize}; + +#[derive(Copy, Clone, Debug, Serialize, Deserialize, JsonSchema, PartialEq, Eq)] +#[serde(rename_all = "snake_case")] +pub enum TerminalDockPosition { + Left, + Bottom, + Right, +} + +#[derive(Deserialize)] +pub struct TerminalSettings { + pub shell: Shell, + pub working_directory: WorkingDirectory, + font_size: Option, + pub font_family: Option, + pub line_height: TerminalLineHeight, + pub font_features: Option, + pub env: HashMap, + pub blinking: TerminalBlink, + pub alternate_scroll: AlternateScroll, + pub option_as_meta: bool, + pub copy_on_select: bool, + pub dock: TerminalDockPosition, + pub default_width: f32, + pub default_height: f32, + pub detect_venv: VenvSettings, +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum VenvSettings { + #[default] + Off, + On { + activate_script: Option, + directories: Option>, + }, +} + +pub struct VenvSettingsContent<'a> { + pub activate_script: ActivateScript, + pub directories: &'a [PathBuf], +} + +impl VenvSettings { + pub fn as_option(&self) -> Option { + match self { + VenvSettings::Off => None, + VenvSettings::On { + activate_script, + directories, + } => Some(VenvSettingsContent { + activate_script: activate_script.unwrap_or(ActivateScript::Default), + directories: directories.as_deref().unwrap_or(&[]), + }), + } + } +} + +#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum ActivateScript { + #[default] + Default, + Csh, + Fish, +} + +#[derive(Clone, Debug, Default, Serialize, Deserialize, JsonSchema)] +pub struct TerminalSettingsContent { + pub shell: Option, + pub working_directory: Option, + pub font_size: Option, + pub font_family: Option, + pub line_height: Option, + pub font_features: Option, + pub env: Option>, + pub blinking: Option, + pub alternate_scroll: Option, + pub option_as_meta: Option, + pub copy_on_select: Option, + pub dock: Option, + pub default_width: Option, + pub default_height: Option, + pub detect_venv: Option, +} + +impl TerminalSettings { + pub fn font_size(&self, cx: &AppContext) -> Option { + self.font_size + .map(|size| theme::adjusted_font_size(size, cx)) + } +} + +impl settings::Setting for TerminalSettings { + const KEY: Option<&'static str> = Some("terminal"); + + type FileContent = TerminalSettingsContent; + + fn load( + default_value: &Self::FileContent, + user_values: &[&Self::FileContent], + _: &AppContext, + ) -> anyhow::Result { + Self::load_via_json_merge(default_value, user_values) + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema, Default)] +#[serde(rename_all = "snake_case")] +pub enum TerminalLineHeight { + #[default] + Comfortable, + Standard, + Custom(f32), +} + +impl TerminalLineHeight { + pub fn value(&self) -> f32 { + match self { + TerminalLineHeight::Comfortable => 1.618, + TerminalLineHeight::Standard => 1.3, + TerminalLineHeight::Custom(line_height) => f32::max(*line_height, 1.), + } + } +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum TerminalBlink { + Off, + TerminalControlled, + On, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum Shell { + System, + Program(String), + WithArguments { program: String, args: Vec }, +} + +#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum AlternateScroll { + On, + Off, +} + +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, JsonSchema)] +#[serde(rename_all = "snake_case")] +pub enum WorkingDirectory { + CurrentProjectDirectory, + FirstProjectDirectory, + AlwaysHome, + Always { directory: String }, +} diff --git a/crates/terminal_view/src/terminal_element.rs b/crates/terminal_view/src/terminal_element.rs index 1d12b83c5c..b3d87f531a 100644 --- a/crates/terminal_view/src/terminal_element.rs +++ b/crates/terminal_view/src/terminal_element.rs @@ -25,7 +25,8 @@ use terminal::{ term::{cell::Flags, TermMode}, }, mappings::colors::convert_color, - IndexedCell, Terminal, TerminalContent, TerminalSettings, TerminalSize, + terminal_settings::TerminalSettings, + IndexedCell, Terminal, TerminalContent, TerminalSize, }; use theme::{TerminalStyle, ThemeSettings}; use util::ResultExt; diff --git a/crates/terminal_view/src/terminal_panel.rs b/crates/terminal_view/src/terminal_panel.rs index 472e748359..9fb3939e1f 100644 --- a/crates/terminal_view/src/terminal_panel.rs +++ b/crates/terminal_view/src/terminal_panel.rs @@ -9,7 +9,7 @@ use gpui::{ use project::Fs; use serde::{Deserialize, Serialize}; use settings::SettingsStore; -use terminal::{TerminalDockPosition, TerminalSettings}; +use terminal::terminal_settings::{TerminalDockPosition, TerminalSettings}; use util::{ResultExt, TryFutureExt}; use workspace::{ dock::{DockPosition, Panel}, diff --git a/crates/terminal_view/src/terminal_view.rs b/crates/terminal_view/src/terminal_view.rs index 92465d6b32..104d181a7b 100644 --- a/crates/terminal_view/src/terminal_view.rs +++ b/crates/terminal_view/src/terminal_view.rs @@ -33,7 +33,8 @@ use terminal::{ index::Point, term::{search::RegexSearch, TermMode}, }, - Event, MaybeNavigationTarget, Terminal, TerminalBlink, WorkingDirectory, + terminal_settings::{TerminalBlink, TerminalSettings, WorkingDirectory}, + Event, MaybeNavigationTarget, Terminal, }; use util::{paths::PathLikeWithPosition, ResultExt}; use workspace::{ @@ -44,8 +45,6 @@ use workspace::{ NewCenterTerminal, Pane, ToolbarItemLocation, Workspace, WorkspaceId, }; -pub use terminal::TerminalSettings; - const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500); ///Event to transmit the scroll from the element to the view