Co-Authored-By: Mikayla Maki <mikayla.c.maki@gmail.com>
This commit is contained in:
Joseph T. Lyons 2023-08-25 15:06:31 -04:00
parent 0801e5e437
commit 507a5db09c
7 changed files with 213 additions and 168 deletions

View File

@ -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": {

View File

@ -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::<TerminalSettings>(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<Project>,
settings: &VenvSettingsContent,
working_directory: Option<PathBuf>,
) -> Option<PathBuf> {
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);
}
}

View File

@ -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::<TerminalSettings>(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<f32>,
pub font_family: Option<String>,
pub line_height: TerminalLineHeight,
pub font_features: Option<fonts::Features>,
pub env: HashMap<String, String>,
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<Shell>,
pub working_directory: Option<WorkingDirectory>,
pub font_size: Option<f32>,
pub font_family: Option<String>,
pub line_height: Option<TerminalLineHeight>,
pub font_features: Option<fonts::Features>,
pub env: Option<HashMap<String, String>>,
pub blinking: Option<TerminalBlink>,
pub alternate_scroll: Option<AlternateScroll>,
pub option_as_meta: Option<bool>,
pub copy_on_select: Option<bool>,
pub dock: Option<TerminalDockPosition>,
pub default_width: Option<f32>,
pub default_height: Option<f32>,
pub activate_python_virtual_environment: Option<bool>,
}
impl TerminalSettings {
pub fn font_size(&self, cx: &AppContext) -> Option<f32> {
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> {
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<String> },
}
#[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,

View File

@ -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<f32>,
pub font_family: Option<String>,
pub line_height: TerminalLineHeight,
pub font_features: Option<fonts::Features>,
pub env: HashMap<String, String>,
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<ActivateScript>,
directories: Option<Vec<PathBuf>>,
},
}
pub struct VenvSettingsContent<'a> {
pub activate_script: ActivateScript,
pub directories: &'a [PathBuf],
}
impl VenvSettings {
pub fn as_option(&self) -> Option<VenvSettingsContent> {
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<Shell>,
pub working_directory: Option<WorkingDirectory>,
pub font_size: Option<f32>,
pub font_family: Option<String>,
pub line_height: Option<TerminalLineHeight>,
pub font_features: Option<fonts::Features>,
pub env: Option<HashMap<String, String>>,
pub blinking: Option<TerminalBlink>,
pub alternate_scroll: Option<AlternateScroll>,
pub option_as_meta: Option<bool>,
pub copy_on_select: Option<bool>,
pub dock: Option<TerminalDockPosition>,
pub default_width: Option<f32>,
pub default_height: Option<f32>,
pub detect_venv: Option<VenvSettings>,
}
impl TerminalSettings {
pub fn font_size(&self, cx: &AppContext) -> Option<f32> {
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> {
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<String> },
}
#[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 },
}

View File

@ -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;

View File

@ -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},

View File

@ -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